Friday, August 26, 2011

Daemons in Java

In Spanish the translation of daemon is "demonio" that means also devil, I know now why.
I will put the method to create one from zero, for any SO with J2SE 1.6. If you think that is easy, that could be done with tools like Java Service Wrapper, etc, etc, ok do it, you'll find that have to deal with other world of troubles.
Ok, the idea is, use a main to begin the program, and add a DaemonShutdownHook, what is that? This capture the shutdown signal (normal shutdown/kill) of the runnig JVM.
The main class will look like this
static public void main(String[] args)
{
Appender startupAppender = new ConsoleAppender(new SimpleLayout());
try
{
logger.addAppender(startupAppender);
// do sanity checks and startup actions
daemonize();
addDaemonShutdownHook();
}
catch (Throwable e)
{
logger.fatal("Startup failed.",e);
}
finally
{
logger.removeAppender(startupAppender);
}

while(!isShutdownRequested())
{
// wait for stimuli
// process stimulus
}

// do shutdown actions
//end thread shutdown hook
}
The methods used:

static public void shutdown()
{
shutdownRequested = true;
}

static protected void addDaemonShutdownHook()
{
Runtime.getRuntime().addShutdownHook( new Thread() { public void run() { MainClass.shutdown(); }});
}

An issue I've found is, that the DaemonShutdownHook doesn't hold the app to finalize, you must not finalize the shutdown method till you end the main thread. Why? Because after the shutdown method the Signal continues with System.exit, that means that if you didn't end your tasks before that, you're going to leave lines without execution. My way to fix it was, waiting the main method to end, and then end the shutdown, avoiding the forced System.Exit of the JVM.

static public void shutdown()
{
shutdownRequested = true;
while (!MainClass.endFlag){//put some wait if u want}
}

static protected void addDaemonShutdownHook()
{
Runtime.getRuntime().addShutdownHook( new Thread() { public void run() { MainClass.shutdown(); }});
}

static public void main(String[] args)
{
endFlag=false;
Appender startupAppender = new ConsoleAppender(new SimpleLayout());
try
{
logger.addAppender(startupAppender);
// do sanity checks and startup actions
daemonize();
addDaemonShutdownHook();
}
catch (Throwable e)
{
logger.fatal(“Startup failed.”,e);
}
finally
{
logger.removeAppender(startupAppender);
}

while(!isShutdownRequested())
{
// wait for stimuli
// process stimulus
}

// do shutdown actions
//end thread shutdown hook
endFlag=true;
}

I hope this helps
BR

Sources:
http://barelyenough.org/blog/2005/03/java-daemon/