4 Replies Latest reply on Feb 20, 2006 11:02 AM by randahl

    Deployment isolation and loader repositories have no effect

    randahl

      INTRODUCTION
      ------------------

      On a JBoss 4.0.3sp1 I am deplying two instances of the same application as two ear files

      ApplicationA.ear
      ApplicationB.ear

      Inside each ear I have a jar containing some EJBs, and this jar actually contains several other jars containing the EJB classes. Like this for ApplicationA:

      ApplicationA.ear/my-ejbs.jar/module1.jar
      ApplicationA.ear/my-ejbs.jar/module2.jar

      and similarly for ApplicationB:

      ApplicationB.ear/my-ejbs.jar/module1.jar
      ApplicatoinB.ear/my-ejbs.jar/module2.jar

      The reason why I have module1 and module2 in both applications is that each application may be using different versions of the modules.


      THE PROBLEM
      ----------------
      The module1.jar contains both some classes and some configuration xml files. I use Hibernate, so for instance the module1.jar contains a hibernate.cfg.xml configuration file. This means that on my class path I have the following:

      ApplicationA.ear/my-ejbs.jar/module1.jar/hibernate.cfg.xml
      ApplicationB.ear/my-ejbs.jar/module1.jar/hibernate.cfg.xml

      Now since ApplicationA and ApplicationB are different applications their hibernate.cfg.xml files are different. The hibernate.cfg.xml file nested inside ApplicationA.ear tells ApplicationA to use DatabaseA, and the file nested inside ApplicationB.ear tells ApplicationB to use DatabaseB.

      However, my tests have shown that the way I have configured JBoss does not allow this to work. When I restart JBoss and start interacting with ApplicationA the code inside it requests the hibernate.cfg.xml file like this

      getClass().getResource("/hibernate.cfg.xml");


      This makes JBoss load the hibernate.cfg.xml file nested inside the ApplicationA.ear which says ApplicationA should use DatabaseA.

      Then when I start interacting with ApplicationB and its code also makes a getResource(...) call that application is served the wrong hibernate.cfg.xml file from ApplicationA - the one that has already been loaded.

      Informally speaking it looks as if JBoss thinks that because both hibernate.cfg.xml files share the same name and reside the same place on the classpath, they must be similar, and thus JBoss asumes it is safe to use the hibernate.cfg.xml file already loaded (which is wrong, of course).


      MY CONFIGURATION
      ------------------------
      Yes, I have already enabled application isolation like this (from ear-deployer.xml):
      <attribute name="Isolated">true</attribute>
       <attribute name="CallByValue">true</attribute>


      Yes, I have already assigned a unique class loader repository for each ear file like this for ApplicationA (from jboss-app.xml):

      <loader-repository>
       ApplicationA:loader=ApplicationA.ear
       <loader-repository-config>
       java2ParentDelegation=false
       </loader-repository-config>
       </loader-repository>


      This information is stored int the jboss-app.xml file inside the META-INF folder of each ear file and the folder also contains an application.xml file which says that the ear contains module1 and module2. Like this:

      <application>
       <module>
       <ejb>module1.jar</ejb>
       <ejb>module2.jar</ejb>
       </module>
      </application>


      So what I am trying to tell JBoss here is that each application ear contains its own module1.jar which should be loaded using a class loader which is unique for the ear.


      ROUND UP
      ------------
      Throughout the last weeks I have tried a huge number of possible configuration options but for unknown reasons I simply cannot make JBoss separate the application's resources from each other. I thought about simply renaming my hibernate.cfg.xml files so that the class path would look like

      ApplicationA.ear/my-ejbs.jar/module1.jar/ApplicationA-hibernate.cfg.xml
      ApplicationB.ear/my-ejbs.jar/module1.jar/ApplicationB-hibernate.cfg.xml

      but I feel this is an impossible solution because I have lots of other xml files in each module and managing unique names for each and every xml file simply is not practical.

      I think there must be a silver bullet configuration option that I have simply overlooked. If anyone have any suggestions I will be grateful for hearing from you.


      Yours

      Randahl


        • 1. Re: Deployment isolation and loader repositories have no eff
          randahl

          Can anyone please confirm that they have succesfully run a setup where two different instances of the same application are able to get their own hibernate.cfg.xml file from their own jar on jboss?

          Could you please give me some hints about what you did to get around the problem I have described above.

          Thanks


          Randahl

          • 2. Re: Deployment isolation and loader repositories have no eff
            starksm64

            You have multiple configuration errors, the jboss-app.xml should be:

            <jboss-app>
             <loader-repository>
             ApplicationA:loader=ApplicationA.ear
             </loader-repository>
            </jboss-app>
            


            as there is no need for anything but scoping, and the root element is jboss-app.

            The application.xml is also incorrect. There can only be one ejb element under a module element. Try using the dtd for these descriptors to validate their contents.


            • 3. Re: Deployment isolation and loader repositories have no eff
              randahl

              Thank you for your response.

              I looked into it, and it turns out that I actually only have a single ejb module element - sorry my description was a bit wrong there.

              That aside I turned to your suggestion about changing the loader-repository config to not include the java2ParentDelegation setting. Removing it had no effect, but I now have two interesting findings:


              Possible problem 1
              ----------------------
              When ApplicationA and ApplicationB are deployed jboss states that their loader-configuration settings are ignored:

              2006-02-20 15:02:36,156 WARN [org.jboss.deployment.DeploymentInfo] Only the root deployment can set the loader repository, ignoring config=LoaderRepositoryConfig(repositoryName: ApplicationA:loader=ApplicationA.ear, repositoryClassName: org.jboss.mx.loading.HeirarchicalLoaderRepository3, configParserClassName: null, repositoryConfig: null)
              


              (the same is logged for ApplicationB)

              This surprises me since the loader repository configuration is located in

              ApplicationA.ear/META-INF/jboss-app.xml

              I believe the ApplicationA.ear is what jboss calls a root deployment since it is not nested inside another archive. So why is it ignored?


              Possible Problem 2
              ----------------------
              Once I have configured a Hibernate session factory I store this session factory in a static singleton class which I have called SessionManager.
              The problem is that when staring ApplicationA I get the hibernate.cfg.xml file from ApplicationA and then store its corresponding hibernate session factory it in my SessionManager. Then when starting ApplicationB the session manager checks to see if it has been configured and (surprise!) it has indeed already been configured, so it wrongly uses the session factory from ApplicationA.

              My session manager looks like this:
              public class SessionManager {
              ...
               private static SessionFactory sessionFactory;
               public static Session openSession(Object opener) {
               try {
               if(sessionFactory == null)
               initialize(opener);
              ...
              }


              I believe this would work like it should had it not been for my class loader problems. What I am trying to achieve is to make ApplicationA and ApplicationB have each their own SessionManager, which they also would have if the SessionManager class inside ApplicationA was considered to be another class than the SessionManager class inside ApplicationB.

              But what happens is in fact that the SessionManager class is actually shared between the two applications and thus both applications get access to the same database.


              QUESTIONS
              --------------

              I am a bit puzzled. If the logging shown under "Problem 1" is indeed correct, and my class loader configuration is in fact ignored, then "Problem 2" is just a direct consequence of "Problem 1". So my questions are

              1. Is it indeed possible that my loader-repository configuration is ignored in spite of the fact that it is placed in the META-INF folder of an ear?

              2. Am I correct in my asumption that if the loader-repository configuration was correct, then ApplicationA and ApplicationB would have completely different sets of classes, meaning they would get their own SessionManager class (and consequently their own static sessionFactory variable giving them access to their own database)?


              All thoughts and hints will be highly appreciated - if you have a setup where you are able to make two different applications have their own separate set of classes, I would very much like to hear from your. Thank you.

              Yours
              Randahl



              • 4. Re: Deployment isolation and loader repositories have no eff
                randahl

                PROBLEM SOLVED

                Auchhh that was a tough one, but I finally solved it thanks to Adrian Block's comments at

                http://jira.jboss.com/jira/browse/JBAS-947

                When deploying ApplicationA and ApplicationB I thought I had pointed JBoss to the ApplicationA.ear and ApplicationB.ear but that was not so. In my jboss-service.xml file which lists the deployed applications I had


                deploy/,
                file:/server/solution/ApplicationA/deploy,
                file:/server/solution/ApplicationB/deploy,


                Which is in fact wrong. I was trying to make jboss deploy all ears of the deploy folders but notice that the end of the folder names are missing their final slashes. What I should have written was


                deploy/,
                file:/server/solution/ApplicationA/deploy/,
                file:/server/solution/ApplicationB/deploy/,


                Consequently I actually made jboss deploy an application called "deploy" which contained my my ear, and the loader-repository configuration was rightly ignored. After inserting the final slashes after "deploy" I am now telling jboss to deploy all ears in the deploy FOLDER.

                That was one hard to find needle in a hay stack.

                Gotcha ;-)
                Randahl