« | Main| Installing brl-cad on a Debian system »

Running Java programs as services


Some Java code is packaged to run easily as a long running service (Tomcat for instance), but if you are writing your own code or are using code that has not been set up to run in this way it be problematic.

Fortunately TunakiSoftware have provided a solution, a wrapper that takes care of all the problems and even runs with the same config files on Windows and Linux.  It can be found at http://wrapper.tanukisoftware.org/doc/english/introduction.html.

The particular software that I was trying to use was JRadius.  We had a need to resolve authentication requests (which also allocated IP addresses) to a Radius client, reading data from an existing Tomcat and XML based web server.  So we installed FreeRadius and JRadius, and wrote a piece of code that built the request to the Tomcat/XML system and parsed the responhse in order to be able to handle the authentication requests for FreeRadius.

I installed the wrapper software (it was version 3.2.3 at the time this was written) in /usr/local/share as I am running in a Debian environment and there is no Debian package for wrapper.  I put all the config file for the various wrapper packages in /etc/wrapper/.

There were two files I needed to create, or rather copy and tailor.  These are the shell script to be added to /etc/init.d, and the config file to be put in /etc/wrapper.

The sample shell script can be found in the wrapper directory /src/bin/sh.script.in.  This file can be copied into the init.d directory, and you should only touch the first few lines where the various variables are set.  For JRadius these read:-

#
# Copyright (c) 1999, 2006 Tanuki Software Inc.
#
# Java Service Wrapper sh script.  Suitable for starting and stopping
#  wrapped Java applications on UNIX platforms.
#

#-----------------------------------------------------------------------------
# These settings can be modified to fit the needs of your application
export WRAPPER_HOME=/usr/local/share/wrapper-linux-x86-32-3.2.3
export JRADIUS_HOME=/usr/local/share/jradius
export JAVA_HOME=/usr/lib/j2sdk1.5-sun

# Application
APP_NAME="jradius"
APP_LONG_NAME="JRadius Server"

# Wrapper
WRAPPER_CMD="$WRAPPER_HOME/bin/wrapper"
WRAPPER_CONF="/etc/wrapper/jradius.conf"

# Priority at which to run the wrapper.  See "man nice" for valid priorities.
#  nice is only used if a priority is specified.
PRIORITY=

# Location of the pid file.
PIDDIR="$WRAPPER_HOME/pids/"

# If uncommented, causes the Wrapper to be shutdown using an anchor file.
#  When launched with the 'start' command, it will also ignore all INT and
#  TERM signals.
#IGNORE_SIGNALS=true

# If specified, the Wrapper will be run as the specified user.
# IMPORTANT - Make sure that the user has the required privileges to write
#  the PID file and wrapper.log files.  Failure to be able to write the log
#  file will cause the Wrapper to exit without any way to write out an error
#  message.
# NOTE - This will set the user which is used to run the Wrapper as well as
#  the JVM and is not useful in situations where a privileged resource or
#  port needs to be allocated prior to the user being changed.
RUN_AS_USER=jradius

# The following two lines are used by the chkconfig command. Change as is
#  appropriate for your application.  They should remain commented.
# chkconfig: 2345 20 80
# description: JRadius Server

# Do not modify anything beyond this point
#-----------------------------------------------------------------------------

I created a user "jradius" so that it was running as a normal user rather than a superuser, and it is necessary to make sure that you put any such users into a group who have write access to the $WRAPPER_HOME/logs and $WRAPPER_HOME/pids directories.  I keep all the PID files in $WRAPPER_HOME rather than the default (.) so that they are all in one place.

Next we need a config file, which can be copied from $WRAPPER_HOME/src/conf/wrapper.conf.in, in this case /etc/wrapper/jradius.conf:-

#********************************************************************
# Wrapper Properties
#********************************************************************
# Java Application
wrapper.java.command=%JAVA_HOME%/bin/java

# Java Main class.  This class must implement the WrapperListener interface
#  or guarantee that the WrapperManager class is initialized.  Helper
#  classes are provided to do this for you.  See the Integration section
#  of the documentation for details.
wrapper.java.mainclass=org.tanukisoftware.wrapper.WrapperSimpleApp

# Java Classpath (include wrapper.jar)  Add class path elements as
#  needed starting from 1
wrapper.java.classpath.1=%WRAPPER_HOME%/lib/wrapper.jar
wrapper.java.classpath.2=%JRADIUS_HOME%/jradius.jar:%JRADIUS_HOME%jradius-dictionary.jar
wrapper.java.classpath.3=%JRADIUS_HOME%/lib/commons-configuration-1.0.jar
wrapper.java.classpath.4=%JRADIUS_HOME%/lib/commons-lang-2.0.jar
wrapper.java.classpath.5=%JRADIUS_HOME%/lib/commons-chain-1.0.jar
wrapper.java.classpath.6=%JRADIUS_HOME%/lib/commons-digester-1.7.jar
wrapper.java.classpath.7=%JRADIUS_HOME%/lib/commons-logging.jar
wrapper.java.classpath.8=%JRADIUS_HOME%/lib/commons-beanutils.jar
wrapper.java.classpath.9=%JRADIUS_HOME%/lib/commons-collections-3.1.jar
wrapper.java.classpath.10=%JRADIUS_HOME%/lib/java-getopt-1.0.10.jar
wrapper.java.classpath.11=%JRADIUS_HOME%/lib/gnu-crypto.jar
wrapper.java.classpath.12=%JRADIUS_HOME%/lib/log4j-1.2.9.jar
wrapper.java.classpath.13=%JRADIUS_HOME%/lib/ehcache-1.2beta4.jar
wrapper.java.classpath.14=%JRADIUS_HOME%/lib/
wrapper.java.classpath.15=%JRADIUS_HOME%/localcode.jar

# Java Library Path (location of Wrapper.DLL or libwrapper.so)
wrapper.java.library.path.1=%WRAPPER_HOME%/lib

# Java Additional Parameters

# Initial Java Heap Size (in MB)
#wrapper.java.initmemory=20

# Maximum Java Heap Size (in MB)
#wrapper.java.maxmemory=150

# Application parameters.  Add parameters as needed starting from 1
wrapper.app.parameter.1=net.sf.jradius.server.Main
wrapper.app.parameter.2=jradius-config.xml

wrapper.working.dir=%JRADIUS_HOME%

#********************************************************************
# Wrapper Logging Properties
#********************************************************************

# Enable or disable debugging
wrapper.debug=FALSE

# Format of output for the console.  (See docs for formats)
wrapper.console.format=PM

# Log Level for console output.  (See docs for log levels)
wrapper.console.loglevel=INFO

# Log file to use for wrapper output logging.
wrapper.logfile=%WRAPPER_HOME%/logs/jradius.log

# Format of output for the log file.  (See docs for formats)
wrapper.logfile.format=LPTM

# Log Level for log file output.  (See docs for log levels)
wrapper.logfile.loglevel=INFO

# Maximum size that the log file will be allowed to grow to before
#  the log is rolled. Size is specified in bytes.  The default value
#  of 0, disables log rolling.  May abbreviate with the 'k' (kb) or
#  'm' (mb) suffix.  For example: 10m = 10 megabytes.
wrapper.logfile.maxsize=0

# Maximum number of rolled log files which will be allowed before old
#  files are deleted.  The default value of 0 implies no limit.
wrapper.logfile.maxfiles=0

# Log Level for sys/event log output.  (See docs for log levels)
wrapper.syslog.loglevel=NONE

NOTE 1,  I have removed the Windows only bits at the end of this file as I did not need them.
NOTE 2,  The variables in this file are marked in the Windows manner (%var%) not the Linux manner ($var).  Now also that all directory paths should be specified in Linux format (/ not \).

Now we are ready to start the server.  To start this manually issue:-

sudo /etc/init.d/jradius start

(assuming you are authorised to use sudo), to run it every time you start the machine, add a link in /etc/rc2.d to the /etc/init.d/jradius file.

One additional option that this script has over normal /etc/init.d scripts is the console option.  If you say sudo /etc/init.d/jradius console it will tail -f the current log file, so you get a running log.

Post A Comment

Monthly Archives

Tag Cloud