8 Replies Latest reply on Mar 10, 2009 4:24 AM by jaikiran pai

    EAR and classloader in JBoss 5

    J-C jc Apprentice

      Hi,

      I have two ears deploy in my JBoss 5.0.1.GA application server. It is deploy as follow.
      ear1.ear/META-INF/application.xml
      ear1.ear/myEJB3.jar
      ear1.ear/lib/myJar.jar

      ear2.ear/META-INF/application.xml
      ear2.ear/myEJB3.jar
      ear2.ear/lib/myJar.jar

      The dependencies myJar is in both ear but with a different release. Consequently I need that each ear has its own classloader.

      I have updated file ear-deployer-jboss-beans.xml

      <bean name="EARClassLoaderDeployer" class="org.jboss.deployment.EarClassLoaderDeployer">
       <!-- A flag indicating if ear deployments should have their own scoped
       class loader to isolate their classes from other deployments.
       -->
       <property name="isolated">true</property>
       </bean>


      Unfortunatelly with that configuration I still have the same issue. oth ear uses the same myJay.jar file and not the jar include in the ear.

      What should I do to have have one classloader per ear ?

      Thanks

        • 1. Re: EAR and classloader in JBoss 5
          Ales Justin Master

           

          "jc7442" wrote:

          What should I do to have have one classloader per ear ?

          You already have one cl per .ear.
          It's strange that your isolated change didn't fix that.

          • 2. Re: EAR and classloader in JBoss 5
            jaikiran pai Master

             

            "jc7442" wrote:

            Unfortunatelly with that configuration I still have the same issue. oth ear uses the same myJay.jar file and not the jar include in the ear.


            Are you sure that's happening? I might sound silly - but did you change the ear-deployer-jboss-beans.xml in the correct server configuration? :)

            To debug, here's what you can do - in the jboss-log4j.xml in %JBOSS_HOME%/server/< serverName>/conf folder, enable org.jboss.classloading TRACE logs. Something like this:

            ...
            <appender name="CLASSLOADING" class="org.jboss.logging.appender.RollingFileAppender">
             <errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
             <param name="File" value="${jboss.server.log.dir}/classloading.log"/>
             <param name="Append" value="false"/>
             <param name="MaxFileSize" value="5000KB"/>
             <param name="MaxBackupIndex" value="10"/>
            
             <layout class="org.apache.log4j.PatternLayout">
             <param name="ConversionPattern" value="%d %-5p [%c] %m%n"/>
             </layout>
            </appender>
            
            ...
            
            <category name="org.jboss.classloading">
             <priority value="TRACE"/>
             <appender-ref ref="CLASSLOADING"/>
             </category>


            This will redirect the classloading logs to %JBOSS_HOME%/server/< serverName>/log/classloading.log files. In those logs you will find information about which class is being loaded from which jar file. See if that helps.


            • 3. Re: EAR and classloader in JBoss 5
              J-C jc Apprentice

              Yes I use the right configuration :-).

              I have added logs ... and only one one my jar is loaded. Unfortunattely, I can not attached my ears to this post ... so I will try to explain the issue with some more details.
              Ear delployer is configured with isoloated set to true.

              I have two ear with one EJB in each.
              ear 1:

              @Stateless()
              @Remote(Hello.class)
              public class HelloBean implements Hello {
              
               @Override
               public String sayHello() {
               System.out.println("111111111111");
               System.out.println(this.getClass().getClassLoader());
               System.out.println(this.getClass().getClassLoader().getClass());
               Stub stub = new Stub();
               return stub.sayHello();
               }


              ear2
              @Stateless()
              @Remote(Hello2.class)
              public class HelloBean2 implements Hello2 {
              
               @Override
               public String sayHello() {
               System.out.println("22222222");
               System.out.println(this.getClass().getClassLoader());
               System.out.println(this.getClass().getClassLoader().getClass());
               Stub stub = new Stub();
               return stub.sayHello();
               }


              Both EJBs uses the same class Stub. This class is in the lib directory of each ear with different release. It lloks like
              public class Stub {
              
               public String sayHello() {
               String s = "sayHello 2";
               System.out.println(s);
               displayClassloader();
               return s;
               }
               public void displayClassloader() {
               System.out.println(this.getClass().getClassLoader());
               System.out.println(this.getClass().getClassLoader().getClass());
               }


              I have added in each class a printl to display the classloader instance.

              When I invoked the first ejb in the first ear, I have
              12:14:36,686 INFO [STDOUT] BaseClassLoader@15d8ef1{vfsfile:/D:/jboss/essai/server/default/nextgen/titi.ear/}
              12:14:36,686 INFO [STDOUT] class org.jboss.classloader.spi.base.BaseClassLoader
              12:14:36,686 INFO [STDOUT] sayHello 2
              12:14:36,686 INFO [STDOUT] BaseClassLoader@15d8ef1{vfsfile:/D:/jboss/essai/server/default/nextgen/titi.ear/}
              12:14:36,686 INFO [STDOUT] class org.jboss.classloader.spi.base.BaseClassLoader


              With the second ear I have
              12:14:36,733 INFO [STDOUT] 111111111111
              12:14:36,733 INFO [STDOUT] BaseClassLoader@1738a7c{vfsfile:/D:/jboss/essai/server/default/nextgen/toto.ear/}
              12:14:36,733 INFO [STDOUT] class org.jboss.classloader.spi.base.BaseClassLoader
              12:14:36,733 INFO [STDOUT] sayHello 2
              12:14:36,733 INFO [STDOUT] BaseClassLoader@15d8ef1{vfsfile:/D:/jboss/essai/server/default/nextgen/titi.ear/}
              12:14:36,733 INFO [STDOUT] class org.jboss.classloader.spi.base.BaseClassLoader


              Its clear that each ejb is invoked in different classloader. But both ejbs invoke the class Stub from the same classloader. It looks like the jar conatains in ear1/lib is loaded at the first invokation and when the second ejb is invoked, class contains in ear2/lib is not loaded.

              I thought that class contains in ear/lib was only available for this ear !

              • 4. Re: EAR and classloader in JBoss 5
                jaikiran pai Master

                Strange. Let me see if i can reproduce this.

                In the meantime, please try the jboss-app.xml approach of configuring a classloader. In each of the ear, add a jboss-app.xml in the META-INF of the ear with the following contents:

                ear1:

                <jboss-app>
                 <loader-repository>
                 somename:someothername=UltimatelyAnUniqueObjectNameOne
                 <loader-repository-config>
                 java2ParentDelegation=false
                 </loader-repository-config>
                 </loader-repository>
                
                
                </jboss-app>


                ear2:

                <jboss-app>
                 <loader-repository>
                 somename:someothername=UltimatelyAnUniqueObjectNameTwo
                 <loader-repository-config>
                 java2ParentDelegation=false
                 </loader-repository-config>
                 </loader-repository>
                
                
                </jboss-app>


                See if that works.


                • 5. Re: EAR and classloader in JBoss 5
                  J-C jc Apprentice

                  OK with jboss-app in both ear it works fine !

                  Not sure to understand the issue ! Do you know if there is some documentation about that ?

                  Thks

                  • 6. Re: EAR and classloader in JBoss 5
                    jaikiran pai Master

                     

                    "jc7442" wrote:


                    Not sure to understand the issue !



                    I could reproduce this issue on my system. I removed the EJB deployment from the equation and created two plain ears with just a jsp and a simple class file in each deployment.

                    Looks like a bug in org.jboss.deployment.EarClassLoaderDeployer. This deployer is responsible handling/creating a classloader in a unique domain for each deployment when "isolated" is set to true. However, there appears to be a bug in that:


                    @Override
                     public void deploy(DeploymentUnit unit, JBossAppMetaData metaData) throws DeploymentException
                     {
                     ClassLoadingMetaData classLoadingMetaData = unit.getAttachment(ClassLoadingMetaData.class);
                     if (classLoadingMetaData != null)
                     return;
                    
                     LoaderRepositoryMetaData lrmd = metaData.getLoaderRepository();
                     if (lrmd != null)
                     {
                     ClassLoadingMetaData clmd = LoaderRepositoryMetaDataHelper.create(unit, lrmd);
                     // For isolated automatically create the classloader in a new domain
                     if (clmd == null && isolated)
                     {
                     String domain = EARDeployment.getJMXName(metaData, unit) + ",extension=LoaderRepository";
                     classLoadingMetaData = new ClassLoadingMetaData();
                     classLoadingMetaData.setName(unit.getName());
                     classLoadingMetaData.setDomain(domain);
                     classLoadingMetaData.setExportAll(ExportAll.NON_EMPTY);
                     classLoadingMetaData.setImportAll(true);
                     classLoadingMetaData.setVersion(Version.DEFAULT_VERSION);
                     classLoadingMetaData.setJ2seClassLoadingCompliance(false);
                     }
                     }
                    
                    
                    


                    As can be seen, this deployer expects a LoaderRepositoryMetaData to be present for the deployment unit and only then it goes and checks the "isolated" flag. Effectively, this mandates the presence of jboss-app.xml (with appropriate classloader configuration) through which the LoaderRepositoryMetaData is generated.

                    The deployment unit need not necessarily have a jboss-app.xml (with the classloader configurations), especially when the "isolated" flag is set to true at the server level. The patch is pretty simple:

                    1) See if LoaderRepositoryMetaData exists (for deployments which specifically provide this maybe through jboss-app.xml). If exists, then just use it and a create a ClassLoadingMetaData out of it.
                    2) If LoaderRepositoryMetaData does not exist then check whether "isolated" is true. If yes, then create a ClassLoadingMetaData in a new (unique) domain for the deployment:

                    Index: src/main/org/jboss/deployment/EarClassLoaderDeployer.java
                    ===================================================================
                    --- src/main/org/jboss/deployment/EarClassLoaderDeployer.java (revision 85377)
                    +++ src/main/org/jboss/deployment/EarClassLoaderDeployer.java (working copy)
                    @@ -79,21 +79,25 @@
                     return;
                    
                     LoaderRepositoryMetaData lrmd = metaData.getLoaderRepository();
                    + ClassLoadingMetaData clmd = null;
                    + // If the unit has a loader repository configured, then lets use that
                    + // and create a classloader metadata out of it
                     if (lrmd != null)
                     {
                    - ClassLoadingMetaData clmd = LoaderRepositoryMetaDataHelper.create(unit, lrmd);
                    - // For isolated automatically create the classloader in a new domain
                    - if (clmd == null && isolated)
                    - {
                    - String domain = EARDeployment.getJMXName(metaData, unit) + ",extension=LoaderRepository";
                    - classLoadingMetaData = new ClassLoadingMetaData();
                    - classLoadingMetaData.setName(unit.getName());
                    - classLoadingMetaData.setDomain(domain);
                    - classLoadingMetaData.setExportAll(ExportAll.NON_EMPTY);
                    - classLoadingMetaData.setImportAll(true);
                    - classLoadingMetaData.setVersion(Version.DEFAULT_VERSION);
                    - classLoadingMetaData.setJ2seClassLoadingCompliance(false);
                    - }
                    + clmd = LoaderRepositoryMetaDataHelper.create(unit, lrmd);
                     }
                    + // For isolated automatically create the classloader in a new domain
                    + if (clmd == null && isolated)
                    + {
                    + String domain = EARDeployment.getJMXName(metaData, unit) + ",extension=LoaderRepository";
                    + classLoadingMetaData = new ClassLoadingMetaData();
                    + classLoadingMetaData.setName(unit.getName());
                    + classLoadingMetaData.setDomain(domain);
                    + classLoadingMetaData.setExportAll(ExportAll.NON_EMPTY);
                    + classLoadingMetaData.setImportAll(true);
                    + classLoadingMetaData.setVersion(Version.DEFAULT_VERSION);
                    + classLoadingMetaData.setJ2seClassLoadingCompliance(false);
                    + unit.addAttachment(ClassLoadingMetaData.class, classLoadingMetaData);
                    + }
                     }
                     }
                    


                    • 7. Re: EAR and classloader in JBoss 5
                      J-C jc Apprentice

                      Do you think I should open a bug in JBossAS JIRA for that ?

                      • 8. Re: EAR and classloader in JBoss 5
                        jaikiran pai Master

                        I'm sorry, i was planning to create a JIRA yesterday, but completely forgot about it. Just created one https://jira.jboss.org/jira/browse/JBAS-6600