Overview
Commons Daemon http://jakarta.apache.org/commons/daemon/index.html can be used to run executables or java applications as windows service or UNIX daemon.
To build it from source you need GNU autoconf and m4 in addition to the requirements listed in the presentation page.
FAQ
Is it possible to use the commons daemon to run a executable as Windows service?
Yes, not only java applications can be installed as windows service. Similar to the Srvany.exe tool any other exe can be used.
Sample: Proxomitron (http://www.proxomitron.info/) as windows service
Installation: prunsrv //IS//PROXO --DisplayName="Proxomitron Proxy" --Description="Proxomitron Web Proxy" --StartImage=c:\proxomitron\proxomitron.exe --StartPath=c:\proxomitron --Type=interactive --LogLevel=DEBUG --LogPath=c:\proxomitron\logs --LogPrefix=procrun.log --Startup=manual --StdOutput=c:\proxomitron\logs\stdout.log --StdError=c:\proxomitron\logs\stderr.log
Uninstallation: prunsrv //DS//PROXO
Can I use the commons daemon to install (register) a Windows service?
Yes a Windows service can be installed/uninstalled using prunsrv. See the following example to install the a Windows Service called SCNService: prunsrv //IS//SCNService --Install=%CD%\SCNService.exe --Startup=manual --DisplayName=SCNService
Hint: prunsrv will add "//RS//SCNService" to the ImagePath, which will be passed to SCNService.exe when the Windows SCM (Service Control Manager) is staring the service. Most Services will ignore such command line arguments, but you should check this with your service just to make sure.
I get "prunsrv.c Failed creating java" errors when commons daemon launches Tomcat
These errors occur when JVM used by Tomcat is unable to locate msvcr71.dll runtime library.
Possible solutions:
- Copy msvcr71.dll from java’s bin directory to tomcat’s bin folder
- Add java’s bin directory to windows environment variable
- Copy msvcr71.dll from java’s bin directory to windows\system32 folder
- Make sure your tomcat’s pointing to correct jvm.dll folder
Can I use the common daemon to start a Windows service?
I can stop a windows service with //SS//ServiceName. As I tried to start it again with //RS// nothing happend?
UNIX Return codes
- 0 = Successful operation
- 1 = ? (When used for starting tomcat it starts but returns this...?)
...
Error 109: The pipe has been ended.
When halting a Windows service with net stop, this error may appear if
The java app uses System.exit(0) when asked to stop
or if the Windows start method returns without waiting (see example below)
Examples
Combined java class for Windows and Linux
The following Java code works when called from both a Windows service (using prunsrv) and Linux (using jsvc). The Windows start and stop taken from Christopher Pierce's blog at http://blog.platinumsolutions.com/node/234
/** * Launch the Engine from a variety of sources, either through a main() or invoked through * Apache Daemon. */ public class EngineLauncher implements Daemon { private static final Log4J log = Log4J.getLog(); private static Engine engine = null; private static EngineLauncher engineLauncherInstance = new EngineLauncher(); /** * The Java entry point. * @param args Command line arguments, all ignored. */ public static void main(String[] args) { // the main routine is only here so I can also run the app from the command line engineLauncherInstance.initialize(); Scanner sc = new Scanner(System.in); // wait until receive stop command from keyboard System.out.printf("Enter 'stop' to halt: "); while(!sc.nextLine().toLowerCase().equals("stop")); if (!engine.isStopped()) { engineLauncherInstance.terminate(); } } /** * Static methods called by prunsrv to start/stop * the Windows service. Pass the argument "start" * to start the service, and pass "stop" to * stop the service. * * Taken lock, stock and barrel from Christopher Pierce's blog at http://blog.platinumsolutions.com/node/234 * * @param args Arguments from prunsrv command line **/ public static void windowsService(String args[]) { String cmd = "start"; if (args.length > 0) { cmd = args[0]; } if ("start".equals(cmd)) { engineLauncherInstance.windowsStart(); } else { engineLauncherInstance.windowsStop(); } } public void windowsStart() { log.debug("windowsStart called"); initialize(); while (!engine.isStopped()) { // don't return until stopped synchronized(this) { try { this.wait(60000); // wait 1 minute and check if stopped } catch(InterruptedException ie){} } } } public void windowsStop() { log.debug("windowsStop called"); terminate(); synchronized(this) { // stop the start loop this.notify(); } } // Implementing the Daemon interface is not required for Windows but is for Linux @Override public void init(DaemonContext arg0) throws Exception { log.debug("Daemon init"); } @Override public void start() { log.debug("Daemon start"); initialize(); } @Override public void stop() { log.debug("Daemon stop"); terminate(); } @Override public void destroy() { log.debug("Daemon destroy"); } /** * Do the work of starting the engine */ private void initialize() { if (engine == null) { log.info("Starting the Engine"); ... spawn threads etc } } /** * Cleanly stop the engine. */ public void terminate() { if (engine != null) { log.info("Stopping the Engine"); engine.stop(); log.info("Engine stopped"); } } }