Getting Java Application to run as a service using Jakarta Commons Library

Hi,

I want to run a Java application as a daemon/service on a Linux machine and someone suggested using the Jakarta commons library.  I downloaded the commons-daemon-1.0.tar.gz from http://jakarta.apache.org/commons/daemon/ and installed it on the target machine.  I followed the instructions to create the jsvc file, moved it into my application directory and created the script:

JAVA_HOME=/opt/java/j2sdk
export JAVA_HOME

./jsvc -debug -verbose -outfile logs/myDaemon.log -errfile '&1' -pidfile myDaemon.pid -cp lib/commons-daemon.jar:lib/myDaemon.jar myDaemon.GCIGlobal

This all appears to work correctly until the following error is displayed:

[Loaded java.lang.IllegalAccessException from /opt/java/j2sdk1.4.1_01/jre/lib/rt.jar]
java.lang.IllegalAccessException: Class org.apache.commons.daemon.support.DaemonLoader can not access a member of class myDaemon.GCIGlobal with modifiers "protected"
[Loaded java.lang.StackTraceElement from /opt/java/j2sdk1.4.1_01/jre/lib/rt.jar]
        at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:57)
        at java.lang.Class.newInstance0(Class.java:300)
        at java.lang.Class.newInstance(Class.java:259)
        at org.apache.commons.daemon.support.DaemonLoader.check(DaemonLoader.java:115)
jsvc.exec error: An error was detected checking the myDaemon.GCIGlobal daemon
jsvc.exec error: Service exit with a return value of 2

I am new to Java but I understand that the JSVC can not access a method in the class because it is protected and only available to other methods and sub-methods of that class.  However, according to the daemon instructions it only needs to employ the following methods:

void init(String[ ] arguments)
void start()
void stop()
void destroy()

Which it does and they are all public.  It is the constructor that is protected in order to maintain only one instance of the application.

I know this is quite vague, but if anyone could provide me with more information or explain how I need to modify the application to run I would be grateful.  Thanks.
garry_mAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

MogalManicCommented:
You probably HAVE to use a public constructor so that the jsvc can instanciate the class object.

You can enforce the singleton pattern another way like this;
public class GCIGlobal
{
    private static int instanceCount=0;
    private static GCIGlobal instance=null;

    public GCIGlobal()
    {
         if (++instanceCount>1) {
               throw new RuntimeException("Attempt to allocate more than one instance of this class.  Use getInstance() method");
         }
         ...Rest of init logic...
    }

    public static syncronized CGIGlobal getInstance()
    {
         if (instance==null)
             instance=new GCIGlobal();
         return instance;
    }
}
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
garry_mAuthor Commented:
Brilliant, that sounds like exactly the thing I need, although there is one minor problem... Now when I start the service I recieve the following error:

java.lang.RuntimeException: Attempt to allocate more than one instance of this class.  Use getInstance() method
[Loaded java.lang.StackTraceElement from /opt/java/j2sdk1.4.1_01/jre/lib/rt.jar]
        at myDaemon.GCIGlobal.<init>(GCIGlobal.java:100)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:274)
        at java.lang.Class.newInstance0(Class.java:306)
        at java.lang.Class.newInstance(Class.java:259)
        at org.apache.commons.daemon.support.DaemonLoader.check(DaemonLoader.java:115)
jsvc.exec error: An error was detected checking the gcidaemon.GCIGlobal daemon
jsvc.exec error: Service exit with a return value of 2

Now I understand that the program is trying to create another instance of the same GCIGlobal object and the new conditional logic is not allowing it, but what could be causing the application to instantiate another object?

I looked inside the init method and the only thing I could find that I thought might maybe cause problems was the reference to "this."

Is there some code somewhere which is badly referring to the object instead of using GCIGlobal.getInstance()... if so, can you tell me what am I looking for?

Thanks for your help!
0
MogalManicCommented:
Change the code to be the following:
        if (++instanceCount>1) {
               System.stderr.println("Attempt to allocate more than one instance of this class.  InstanceCount:"+instanceCount);
         }

You may not be able to use a singleton pattern with the jsvc program.  It may internally create multiple instances for load balancing and/or just for fun.  You would have to look at the source for DaemonLoader.java to find out why it is loading multiple instances.
0
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

MogalManicCommented:
Another change you COULD make is to make the constructor initialize the singleton so that the getInstance() intialization would not be called.

like this:
    public GCIGlobal()
    {
         if (++instanceCount>1) {
               throw new RuntimeException("Attempt to allocate more than one instance of this class.  Use getInstance() method");
         }
         ...Rest of init logic...
        instance=this;  //NOTE: this part of the code is NOT thread safe!  If multiple threads called the constructor at the same time, then ????
    }
0
garry_mAuthor Commented:
Ok thanks, looking at the code for the GCIGlobal class there is also another entry:

    static {
        AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                    if (m__this == null) {
                        m__this = new GCIGlobal();
                    }
                    return null;
                }
            }
        );
    }

Which appears to be using a similar method to your single instance constructor.
0
Oliver_DornaufCommented:
garry_m your problem is quite mor complicated.
1) Use the singelton pattern as MogalManic explains
2) use a private member init (boolean)
2) move to initialization code from the ctor to init
3) at init:
       first call getInstance
       check if init == false (the object you got from initInstance)
                init your object
                set init = true
       

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.