5 Replies Latest reply on Sep 3, 2004 6:07 AM by Darran Lofthouse

    Private constructors not allowed for singletons

    James Adams Novice

      It appears that it is impossible to deploy a singleton with a private constructor in a clustered environment. I get the following error when launching the first node of a cluster in which I have a singleton with a private constructor:

      15:43:23,917 ERROR [MainDeployer] could not create deployment: file:/C:/jboss-3.2.5/server/all/farm/1000ClusterMBeans.sar
      org.jboss.deployment.DeploymentException: create operation failed for package file:/C:/jboss-3.2.5/server/all/farm/1000ClusterMBeans.sar; -
      nested throwable: (org.jboss.deployment.DeploymentException: com.harborsideplus.grover.mbean.AllUserMessagesSingleton.<init>(); -
      nested throwable: (java.lang.NoSuchMethodException: com.harborsideplus.grover.mbean.AllUserMessagesSingleton.<init>()))
       at org.jboss.deployment.SARDeployer.create(SARDeployer.java:227)
       at org.jboss.deployment.MainDeployer.create(MainDeployer.java:790)
       at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:644)
      etc. etc.
      


      This is unfortunate because (as far as I know) you should have a private constructor in a true singleton since users should go through a getReference() method instead of instantiating the singleton directly. So if I want to use clustering then I assume that I must make the singleton's constructor public and depend on the cluster to insure that it will only be called once. My preference would be to keep the private constructor, so that there is no modification of the code needed if I run in a non-clustered environment (since having a public constructor makes a singleton not really singleton), but this doesn't appear to be supported. I assume that the reason is that the server needs to be able to call the singleton's constructor, instead of a getReference() method, so a public, no argument constructor must be provided. Can anyone confirm this ?

      Having this information available anywhere in the docs would have saved me weeks of frustration. I suggest that this information should be added to the Wiki and clustering docs.

      Thanks in advance for any feedback.


      --James

        • 1. Re: Private constructors not allowed for singletons
          Darran Lofthouse Master

          The use of singletons should only be used if it does not matter if you have mutliple instances within the same JBoss instance and definately each server will instantiate its own instance.

          If you think it should be added to the WIKI add it yourself.

          • 2. Re: Private constructors not allowed for singletons
            James Adams Novice

            An off topic reply, but interesting nevertheless.

            I think you misunderstand singletons and how they're used, or I do. My understanding is that a singleton is a class which should never be instantiated more than once in an application. This is the opposite of what you suggest -- it absolutely does matter if there are multiple instances, otherwise you wouldn't be using a singleton. For a singleton to be a true singleton in a clustered environment then it must be instantiated on only one node of the cluster, and this is accommodated in JBoss with the HASingletonDeployer (see http://www.jboss.org/wiki/Wiki.jsp?page=HASingletonDeployer). So each node server will not instantiate its own instance.

            As far as directly posting information into the JBoss Wiki -- is there no quality control or oversight ? If not then what keeps any yahoo from adding erroneous or dubious information ? Does anybody from JBoss confirm the validity of Wiki entries ?


            --James

            • 3. Re: Private constructors not allowed for singletons
              Darran Lofthouse Master

              James,

              I do understand singletons and how they work, and yes you probably do as well but I don't think you can see how they would fit into a J2EE application server.

              It is quite possible that an application server may actually be made up of multiple JVM instances, each of these will have its own instance of the singleton. It is also possible that multiple classloaders will be used, again depending on the organisation of these each classloader could instantiate the singleton. For this reason singletons should not be used in J2EE applications unless having multiple instances does not matter.

              Also I do not think that my post is off-topic, after all it is you that started confusing pure Java singletons with the functionalty provided by the HASingletonDeployer.

              You are not writing a singleton you are writing a service, the service is then only deployed on one node, this is managed by the application server. You must provide a default public constructor otherwise the server will not be able to instantiate your class.

              All changes to the WIKI are logged and can be rolled back as required, the comunity as a whole keeps the information up to date and valid.

              • 4. Re: Private constructors not allowed for singletons
                James Adams Novice

                You're right, I had no understanding of how this actually works under the hood.

                You make a very good point that when using the HASingletonDeployer you create a service and not a true singleton -- I wasn't thinking of it that way. Things are clearer in that light.

                Another point you make which comes as a surprise to me is that there may be several JVMs running for a single application server instance, and hence you will have an instance of your singleton in each JVM. I assume that this means that each instance could have different data (no replication) between JVMs. It appears that it's impossible to have a true singleton in a J2EE application without some form of replication/synchronization of singletons between the component JVMs of the server instance. If this is the case then how can you get true singleton behavior in a J2EE application ? There must be some way to do it, right ? I certainly hope so, as the design of my application depends on it.

                In my code, which was developed originally for a non-clustered environment, I'm getting a reference to the singleton instance using a getReference() method, which returns a reference to the singleton if it already exists, or, if it doesn't already exist, first calls the private constructor and then returns the reference. If I understand you correctly I don't need to do this any longer (and it may not even work anyway) but I should instead get the reference to the singleton/service by doing a JNDI lookup using the singleton/service's name. Is this the correct approach ?

                My remark about the initial reply being off-topic alludes to the lack of any mention of public vs. private constructors, and the other information just confused me since I had no idea that there could be multiple JVMs or classloaders per server instance. In any event I do appreciate the feedback and education.

                It's fortunate that I didn't post anything to the Wiki on this topic because I was confused as to how all of this works (and I'm still not crystal clear). This is a good example of why I'm hesitant to put anything in the Wiki before getting some confirmation of the info from others on this forum. Maybe once I get a little past the novice level...


                --James

                • 5. Re: Private constructors not allowed for singletons
                  Darran Lofthouse Master

                  If you visit www.TheServerSide.com you should be able to find a book called 'EJB Design Patterns' for free download.

                  The book has a couple of pages that give a summary of singletons and how they fit into J2EE. Unfortunately depending on your current implementation you may need to do some work to move away from the traditional singleton approach.