Saturday, May 30, 2009

Java Program as a Daemon

After my pursuit for a source on the web that would help me accomplish this, I realized that I should share it and it might save you some time.
So this is exactly what we are trying to do. Make a Java Program run as a Daemon in the UNIX Environment and do a few checks and ensure that we are in control of the Daemon that we have started. We would also avoid dependencies, such that our approach works across all flavors of Unix. So let’s get started.







  • We will start with a simple Java class ‘JavaDaemonTest’ that runs a recursive loop in the main method to log the Time Stamp after every three seconds to a text file.


public class JavaDaemonTest {
public static void main (String[] args) {
try {
while (true) {
Thread.sleep (3000);
log ("running"); }}
//The log method is defined below
catch (Throwable t) {
log ("Exception: "+t.toString()); }}




private static void log (String msg) {
BufferedWriter out=null;
FileWriter fstream =null;
try{
fstream = new FileWriter("out.txt",true);
//the message is written to the text file out.txt
out = new BufferedWriter(fstream);
out.write('\n'+getTimeStamp()+""+msg);
//the getTimeStamp() method is defined below
}catch(Exception e){
e.printStackTrace();
}
finally{
//Close the output stream
try{
out.close();
}catch(Exception e){
}
}
}



private static String getTimeStamp() {
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return f.format(new Date()); }
} // end class JavaDaemonTest





  • Now if we want to have this Java Class run as a daemon it is recommended to have a Shut Down Hook attached to the main method which would ensure that the Daemon terminates properly and we can associate some events to this Daemon to be triggered when the thread is shutdown.Our shell script that starts this Daemon would create a plain text file with the process ID(PID) of the Daemon. And now we add a few lines to our Java Code.


import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

public class JavaDaemonTest {

private static final int shutdownTime = 2;
// Initialize a variable to add a delay after the Daemon ShutDown //is invoked

public static void main (String[] args) {

log ("JavaDaemonTest started");

//We create a new thread object which calls the
//shutdownHook
() method defined below
Thread runtimeHookThread = new Thread() {
public void run() {
shutdownHook(); }};
//Pass the above defined thread object reference
//to the addShutdownHook() method which is a predefined method
// to watch the shutdown of the main method.
Runtime.getRuntime().addShutdownHook (runtimeHookThread);
try {
while (true) {
Thread.sleep (3000);
log ("running"); }}
catch (Throwable t) {
log ("Exception: "+t.toString()); }}
//This method is called when the Daemon is shutdown



private static void shutdownHook() {
log ("ShutdownHook started");
long t0 = System.currentTimeMillis();
while (true) {
try {
Thread.sleep (500); }
catch (Exception e) {
log ("Exception: "+e.toString());
break; }
//we wait for 2 seconds before we break from the loop.
if (System.currentTimeMillis() - t0 > shutdownTime*1000) break;
log ("shutdown"); }
log ("ShutdownHook completed");
//Check for the existence of the text file
//<> created to hold the PID
//by the shell script and delete it on Daemon shutdown.
if(new File("ActiveDaemonPID.pid").exists())
if(new File("ActiveDaemonPID.pid").delete())
log ("ActiveDaemonPID.pid file deleted");
}

private static void log (String msg) {
BufferedWriter out=null;
FileWriter fstream =null;
try{
fstream = new FileWriter("out.txt",true);
out = new BufferedWriter(fstream);
out.write('\n'+getTimeStamp()+""+msg);
}catch(Exception e){
e.printStackTrace();
}
finally{
//Close the output stream
try{
out.close();
}catch(Exception e){
}
}
}

private static String getTimeStamp() {
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return f.format(new Date()); }
} // end class JavaDaemonTest





  • And now the final step is creating a shell script which would run the Daemon. Our shell script would check for the existence of a file called ‘ActiveDaemonPID.pid’ and if not found it starts our java code as a Daemon and writes the PID to the file ‘ActiveDaemonPID.pid’. If you can recollect the shutdownHook()method of our Java Code we delete the file ‘ActiveDaemonPID.pid’ when the Daemon stops. And here is our shell script



if [ -f /home/wajidmehraj/ServiceDaemon/ActiveDaemonPID.pid ]
then
echo "Daemon already in progress"
else
java JavaDaemonTest <&- & pid=\$! if ps -p "\${pid}" >/dev/null 2>&1
then
echo \${pid} > ActiveDaemonPID.pid
else
echo \daemon failed to start. >DaemonFailiureStatusFile
fi
fi


EOF


In case the Daemon fails to start and no PID is associate to it we write the text ‘daemon failed to start’ to the DaemonFailiureStatusFile file.

So that is all you need to have the Daemon working.




1 comment:

  1. Hi Wajid,

    Do you think you can send me the example source code for this? rg@snpp.com.ar

    Also, I'm not sure how to stop the daemon from the console. Do you end up with a script to start, stop and restart?

    Thanks.

    ReplyDelete