daemon is a computer program that runs as a background process, executing tasks on a predefined schedule or in response to particular events, or in response to requests for information or services from other programs.

To start up a Java program as a daemon using Jsvc, we’ll need to do a few things:

a) Implement the Apache Commons Daemon interface.

b) Install Jsvc by downloading and compiling the source (C) or via the command line with the sudo apt-get install jsvc command.

c) Create a bash shell script to launch the daemon and manage the basic set of daemon controls, namely: startstop restart. Others include reload status.

Implementing the Java Daemon Interface

Implementing the Daemon interface is a fairly simple undertaking. Once you have downloaded the library from the Apache Commons project site and referenced it in your Java project, you can go about creating your implementation as follows:

package za.co.neilson;

import org.apache.commons.daemon.Daemon;
import org.apache.commons.daemon.DaemonContext;
import org.apache.commons.daemon.DaemonInitException;

public class MyDaemon implements Daemon {

private Thread myThread;
private boolean stopped = false;
private boolean lastOneWasATick = false;

@Override
public void init(DaemonContext daemonContext) throws DaemonInitException, Exception {
/*
* Construct objects and initialize variables here.
* You can access the command line arguments that would normally be passed to your main()
* method as follows:
*/

String[] args = daemonContext.getArguments();

myThread = new Thread(){
private long lastTick = 0;

@Override
public synchronized void start() {
MyDaemon.this.stopped = false;
super.start();
}

@Override
public void run() {
while(!stopped){
long now = System.currentTimeMillis();
if(now - lastTick >= 1000){
System.out.println(!lastOneWasATick ? "tick" : "tock");
lastOneWasATick = !lastOneWasATick;
lastTick = now;
}
}
}
};
}

@Override
public void start() throws Exception {
myThread.start();
}

@Override
public void stop() throws Exception {
stopped = true;
try{
myThread.join(1000);
}catch(InterruptedException e){
System.err.println(e.getMessage());
throw e;
}
}

@Override
public void destroy() {
myThread = null;
}
}

Jsvc seems to require that our program is exported to a jar, which in this instance I have stored at /usr/local/mydaemon/MyDaemon.jar and the Apache Commons Daemon library has been stored at /usr/local/mydaemon/lib/commons-daemon-1.0.15.jar.

Creating a bash shell script to launch the daemon and manage the basic set of daemon controls

Debian daemon init scripts are stored in /etc/init.d/. A skeleton init script, (/etc/init.d/skeleton) is available to copy and modify according to your needs and generally would provide a good starting point for your services’ init script, however, writing an init script for Jsvc is a little different.

So assuming that that your Daemon implementation’s jar file and the Apache Commons Daemon library are stored at the above locations A basic example of a bash init script for our MyDaemon service could look like this:

#! /bin/sh
# /etc/init.d/mydaemon

### BEGIN INIT INFO
# Provides: mydaemon
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Short-Description: Starts the MyDaemon service
# Description: This file is used to start the daemon
# and should be placed in /etc/init.d
### END INIT INFO

# Author: Sheldon Neilson <sheldon[AT]neilson.co.za>
# Url: www.neilson.co.za
# Date: 25/04/2013

NAME="mydaemon"
DESC="MyDaemon service"

# The path to Jsvc
EXEC="/usr/bin/jsvc"

# The path to the folder containing MyDaemon.jar
FILE_PATH="/usr/local/$NAME"

# The path to the folder containing the java runtime
JAVA_HOME="/usr/lib/jvm/default-java"

# Our classpath including our jar file and the Apache Commons Daemon library
CLASS_PATH="$FILE_PATH/MyDaemon.jar:$FILE_PATH/lib/commons-daemon-1.0.15.jar"

# The fully qualified name of the class to execute
CLASS="za.co.neilson.MyDaemon"

# Any command line arguments to be passed to the our Java Daemon implementations init() method
ARGS="myArg1 myArg2 myArg3"

#The user to run the daemon as
USER="root"

# The file that will contain our process identification number (pid) for other scripts/programs that need to access it.
PID="/var/run/$NAME.pid"

# System.out writes to this file...
LOG_OUT="$FILE_PATH/log/$NAME.out"

# System.err writes to this file...
LOG_ERR="$FILE_PATH/err/$NAME.err"

jsvc_exec()
{
cd $FILE_PATH
$EXEC -home $JAVA_HOME -cp $CLASS_PATH -user $USER -outfile $LOG_OUT -errfile $LOG_ERR -pidfile $PID $1 $CLASS $ARGS
}

case "$1" in
start)
echo "Starting the $DESC..."

# Start the service
jsvc_exec

echo "The $DESC has started."
;;
stop)
echo "Stopping the $DESC..."

# Stop the service
jsvc_exec "-stop"

echo "The $DESC has stopped."
;;
restart)
if [ -f "$PID" ]; then

echo "Restarting the $DESC..."

# Stop the service
jsvc_exec "-stop"

# Start the service
jsvc_exec

echo "The $DESC has restarted."
else
echo "Daemon not running, no action taken"
exit 1
fi
;;
*)
echo "Usage: /etc/init.d/$NAME {start|stop|restart}" >&2
exit 3
;;
esac

The init script above should be stored in /etc/init.d/ along with the system’s other start-up scripts.

Automatically Starting the Daemon at System Boot

With our init script done, we need to change it’s permissions to make it executable using chmod. chmod 755 /etc/init.d/mydaemon. And register it for execution as the system’s run level changes.

“Debian uses a Sys-V like system for executing commands when the system runlevel changes, for example at boot and shutdown time.” – Source: Making scripts run at boot time with Debian

As the system’s runlevel changes, any scripts within corresponding /etc/rc*.d/ directory will be executed, where * is the number of the runlevel.

The easiest way to have our script executed appropriately is to use the Debian command update-rc.d to add the appropriate symlinks for us.

To enable our daemon at boot use update-rc.d mydaemon defaults:

root@sheldon-pc:/etc/init.d# update-rc.d mydaemon defaults
 Adding system startup for /etc/init.d/mydaemon...
   /etc/rc0.d/K20mydaemon -> ../init.d/mydaemon
   /etc/rc1.d/K20mydaemon -> ../init.d/mydaemon
   /etc/rc6.d/K20mydaemon -> ../init.d/mydaemon
   /etc/rc2.d/S20mydaemon -> ../init.d/mydaemon
   /etc/rc3.d/S20mydaemon-> ../init.d/mydaemon
   /etc/rc4.d/S20mydaemon -> ../init.d/mydaemon
   /etc/rc5.d/S20mydaemon-> ../init.d/mydaemon

If you should ever wish to disable it, run update-rc.d -f mydaemon remove:

root@sheldon-pc:/etc/init.d# update-rc.d -f mydaemon remove
update-rc.d: /etc/init.d/mydaemon exists during rc.d purge (continuing)
 Removing any system startup links for /etc/init.d/blah ...
   /etc/rc0.d/K20mydaemon
   /etc/rc1.d/K20mydaemon
   /etc/rc2.d/S20mydaemon
   /etc/rc3.d/S20mydaemon
   /etc/rc4.d/S20mydaemon
   /etc/rc5.d/S20mydaemon
   /etc/rc6.d/S20mydaemon

Our daemon should now start when the system boots. To view it’s output, first we should stop it to prevent any concurrent access issues when we open the log file: /etc/init.d/mydaemon stop.

As we know that our log file is being created at /usr/local/mydaemon/log/mydaemon.out, we can view it using the command vi /usr/local/mydaemon/log/mydaemon.out

root@sheldon-pc:/etc/init.d# vi /usr/local/mydaemon/log/mydaemon.out
tick
tock
tick
tock
tick
tock...