[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 744
  • Last Modified:

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.
0
garry_m
Asked:
garry_m
  • 3
  • 2
2 Solutions
 
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
 
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
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
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

Featured Post

Vote for the Most Valuable Expert

It’s time to recognize experts that go above and beyond with helpful solutions and engagement on site. Choose from the top experts in the Hall of Fame or on the right rail of your favorite topic page. Look for the blue “Nominate” button on their profile to vote.

  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now