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");
        }
    }
}


  • No labels