one-jar and commons-daemon

  • Gudbrand Hegge

    Gudbrand Hegge - 2013-11-20


    My goal is to use one-jar to simplify the distribution of a service using commons-daemon.

    Problem, commons-daemon need to be able to call Boot once for start and once to send stop signal to the mainclass. This fails due to exception in com.simontuffs.onejar.Boot:145 "Attempt to set a second Boot loader".

    Start and use of service works but it is not possible to stop the service nicely, commons-daemon kill the service after defined timeout (exit jvm).

    Possible solution is to add a new method stop(args) in Boot that can be a subset of run(args) and forward the args to the mainClass. Implementation should assume that
    1. mainClass is set (changed to a class member?)
    2. loader is set (JarClassLoader)
    3. 1+2 is a result of prior call to run(), if not set exit/throw exception

    Assumptions for this to work for the user of one-jar
    1. The users mainClass handle start and stop argument to the service.
    2. commons-daemon config to start service is --StartMode jvm --StartClass com.simontuffs.onejar.Boot --StartMethod run ++StartParams start
    3. commons-daemon config to stop service is --StopMode jvm --StopClass com.simontuffs.onejar.Boot --StopMethod stop ++StopParams stop


    Last edit: Gudbrand Hegge 2013-11-21
  • Gudbrand Hegge

    Gudbrand Hegge - 2013-11-21


    The following code will do this.

    //change the mainClass to a class member
        private static String mainClass = null;
    //changes at the end of run()
        public static void run(String args[]) throws Exception {
            //... a lot of code not added here
            if (mainClass != null) {
                invokeMainClass(args, true);
    //new method invokeMainClass
        private static void invokeMainClass(String[] args, boolean dumpTime) throws Exception {
            // Guard against the main.jar pointing back to this
            // class, and causing an infinite recursion.
            String bootClass = Boot.class.getName();
            if (bootClass.equals(mainClass))
                throw new Exception(getMyJarName() + " main class (" + mainClass + ") would cause infinite recursion: check main.jar/META-INF/MANIFEST.MF/Main-Class attribute: " + mainClass);
            Class cls = loader.loadClass(mainClass);
            if (dumpTime) {
                endTime = System.currentTimeMillis();
            Method main = cls.getMethod("main", new Class[]{String[].class}); 
            main.invoke(null, new Object[]{args});
    //and finnally the new stop method
         * Reinvokes the mainClass, used for stuff like commons-daemon to signal stop. 
         * The mainClass need to take action on the user defined command in the args or nothing will happen.
         * {@link #run(String[])}
         * @param args with user defined action to stop 
         * @throws Exception 
        public static void stop(String[] args) throws Exception {
            //if called before run we ignore this call
            if (null==loader || null==mainClass){
                throw new Exception("stop() must be called after run() or main()");
            invokeMainClass(args, false);

    The code is tested based on 0.97 RC11 and give the possiblilty to end a service nicely.

    Hopefully you read this forum since your spam system prevent you from notifications (and I do not want to register into an unknown system without privacy statements for you to get the emails).

    Last edit: Gudbrand Hegge 2013-11-21

Log in to post a comment.