Jul 26, 2010

Running a Java program as a daemon.

Sometimes we need a Java program that works as a service starting manually or every time that our OS starts. These services are executing themselves as background processes, constantly waiting for events or executing certain tasks between defined periods of time. These services are known also as daemons. As opposed to a normal application, daemons are controlled by the OS. The OS either starts or stops the deamon. This allows the completion of the task of liberation of resources every time the service is finished or when the machine is turned off.
In order to created an application which works as a daemon we must implement the daemon interface using the package provided by Apache. We can find it in http://commons.apache.org/daemon.com. The interface has the following methods that we must implement:


public interface Daemon {
public void init(DaemonContext context) throws Exception;
public void start() throws Exception;
public void stop() throws Exception;
public void destroy();
}
The method 'init' is executed just once when the class which implements the interface daemon is initiated. In this method it is possible to initialize instant attributes that we need. To initialize sockets but not to initialize threads, like those which listen on ports and neither other threads.

The method 'start' is the point of entry for the daemon. like the method 'main' for conventional application. It is here in this method where we can initialize the threads that are going to do the tasks for which the daemon has been created.

The method 'stop' is used when it is necessary to stop the daemon. Here operations such as disconnections from the database are executed, but not liberation of resources. These must be preserved because the daemon can be required to restart.

The method 'destroy' is executed when we need the daemon to finish all tasks and free up all the resources it is using. It is here where we can liberate any resource that is in use, like sockets, databases, objects, etc.

We can, for example, have two threads, one which works as a server that listens constantly in the port 6000, waiting for a package. The other thread could be a client application which is monitoring a database table. Every time that it finds a new record, it packs it and sends it to a remote server. These two threads should be started in the method 'start' or in any other method that is called from 'start'. Let's do a simple example:

First of all let's define a 'server' class.


public class Server {
private static Server ctrlComm;
public static int PTO_SERVER = 6000;
boolean activeServer = true;
Vector vDaemons = new Vector();
private Server() { }
public static Server getInstance() {
if (ctrlComm == null) {
ctrlComm = new Server();
}
return ctrlComm;
}
public void initServer() throws Exception {
new ThreadServer().start();
}
public void stopServer() {
activeServer = false;
for (Iterator iter = vDaemons.iterator(); iter.hasNext();) {
ThreadProcessInfo item = (ThreadProcessInfo ) iter.next();
item.continuar = false;
}
}
private void serverTCP() throws Exception {
ServerSocket serverSocket = new ServerSocket(PTO_SERVER);
ThreadProcessInfo process = null;
while (activeServer) {
try {
Socket socket = serverSocket.accept();
process= new ThreadProcessInfo(socket);
} catch (Exception ex) {
ex.printStackTrace();
throw new Exception("Error initializing ThreadProcessInfo instance");
}
process.start();
vDaemons.add(process);
}
//Now the thread that initialized the server.
private class ThreadServer extends Thread {
int type = 0;
public ThreadServer() {}
public void run() {
try {
serverTCP();
} catch (Exception ex) {
ex.printStackTrace();
stopServer();
}
}
}
}
Now the client thread.


public class Client extends Thread {
private boolean serverActive = true;
public Client() {}
public void stopServer() {
this.serverActive = false;
}
public void process() throws Exception {
/*Here all the code for manipulate data*/
}
public void run() {
while (serverActive) {
try {
processs();
} catch (Exception e) {
try {
/*close sockets connection*/
} catch (Exception e2) {}
}
}
}
Now the main class that implements the daemon interface.

public class MainDaemons implements Daemon {
private static Server servComm;
private static DaemonClient cliComm;
public static void initService() {
try {
servComm = Server.getInstance();
servComm.initServer();
cliComm = new Client();
cliComm.start();
} catch (Exception ex) {
System.out.println("Server abort: " + ex.getMessage());
System.exit(0);
}
}
public static void stopService() {
if (servComm != null) {
servComm.stopService();
servComm = null;
System.out.println("Service stopped " + new Date());
}
}
public void init(DaemonContext context) throws Exception { }
public void start() throws Exception {
initService();
}
public void stop() throws Exception {
stopService();
}
public void destroy() { }

}
Well that is all. To start the daemon, we use JSVC, but the explanation about its use will be for another post in the blog. Although, the example is missing other things and controls. I hope you can figure out how you can implement and use the daemon interface. I hope this information is useful.

4 comments :

  1. Is the ThreadProccessInfo class encapsulating the protocol to comunicate the request from the client? (that is, by processing the raw data from the the body of packages)
    And this class seems to be extending from Thread and it also seems being implemented by you, because you set a flag 'continuar' to false in order to stop the proccess handling the client request and 'continuar' is a spanish word...lol
    regards!

    ReplyDelete
  2. Yes you are right ThreadProccessInfo class process the packages that the server receive. This class extend from Thread and it was implemented by me and thanks! for remind me that I forgot change that word...

    ReplyDelete
  3. Really cool first post...With this API and code example, anybody can begin to write its own server from scratch as SO service. Anyway this is a big job but interesting field to development.
    congrats again and regards!

    ReplyDelete
  4. We also enhanced this understanding

    ReplyDelete