6 Replies Latest reply on Jul 21, 2005 1:47 PM by umeshs79

    Classloading: Using isolation and accessing global libraries

    karink

      Hello

      I have the following requirements regarding class loading in JBoss/Tomcat

      Firstly, all the deployment units should be isolated from each other, and
      have the possibility to override classes of the parent classloader
      (as described in the "Isolation with Overriding" feature in
      http://www.jboss.org/wiki/Wiki.jsp?page=ClassLoadingConfiguration)).

      Secondly, some libraries should be globally accessible. This means they
      are installed on the machine in one directory and all applications can
      use them.

      I constructed the following test application:

      In my example I would like to have an EAR file which contains two WAR-files.
      The classes from the WAR-file should be first loaded from the classes directory
      of the WAR-file then from the lib and last from the parent class loader.
      For the sake of this example the two war files contain exactly the same
      servlet which invoke a class that can determine its own codesource.
      This class is deployed in a jar file the WEB-INF/lib file of each War-file.
      The jar file is called jpi-jboss-iv-classloadertest.jar.
      The servlet than just reports a string from where the jar file is loaded.
      for example
      [STDOUT] CodeSource = (file:/C:/jboss/4.0/server/test/tmp/deploy/tmp52670my.sar-contents/first.war/WEB-INF/lib/jpi-jboss-iv-classloadertest.jar <no certificates>)
      This way I can see from which Jar file the class is loaded.

      My first approach was following the solution described in the WIKI mentioned
      above. So each WAR-file does contain a jboss-web.xml file which configure
      a loader-repository in this way

      jboss-web.xml of first.war

       <class-loading java2ClassLoadingCompliance="false">
       <loader-repository>
       com.winterthur.jackpot.karin:loader=first.war
       <loader-repository-config>java2ParentDelegation=false</loader-repository-config>
       </loader-repository>
       </class-loading>
      

      jboss-web.xml of second.war
      <class-loading java2ClassLoadingCompliance="false">
       <loader-repository>
       com.winterthur.jackpot.karin2:loader=second.war
       <loader-repository-config>java2ParentDelegation=false</loader-repository-config>
       </loader-repository>
       </class-loading>
      

      Because I'd like to access those global libraries I build up a SAR-file
      that contains a jboss-service.xml where I defined a classpath including
      my global accessible libraries. The SAR-file does contain the EAR-file
      mentioned above.
      (which contains the two WAR-files).

      The jboss-service.xml file looks like this:
      <server>
      
       <classpath
       codebase="file:/C:/common/lib/"
       archives="mycommon.jar"/>
      </server>
      

      The flag "UseJBossWebLoader" and the flag "Java2ClassLoadingCompliance"
      in the file jboss-service.xml of Tomcat are set to true.

      To test the isolation between the JBoss and th application I also deployed
      the jpi-jboss-iv-classloadertest.jar to the server/lib directory of Jboss.

      The effect of this configuration was that the class was not loaded from the
      War file but from the server/lib directory of JBoss.

      In my next trial I set the flag "Java2ClassLoadingCompliance"
      in the file jboss-service.xml of Tomcat to false, but this has the same effect.

      Now I defined the loader-repository in the jboss-service.xml file, then the
      class was loaded from always the same WAR-file (this was what I expected, but not
      the effect I wish to have, because I'd like to isolate the different
      WAR-files from each other).

      At the end I came up with a configuration that seems to work fine,
      but as it does not correspond to the recommendation in the WIKI,
      I would ask you to review this. Possibly there is another better solution,
      than this.

      Ok, here is the configuration:

      I did not define any loader repositories (not in the jboss-service.xml
      file and not in the jboss-web.xml file), but I set the flag "UseJBossWebLoader" and the flag "Java2ClassLoadingCompliance"
      in the file jboss-service.xml of Tomcat are set to false.
      This way the jpi-jboss-iv-classloadertest.jar is loaded from the WAR file in use (so separation of the
      WARs from each other is reached), also the mycommon.jar was found.


      Regards Karin

      P.S.:
      I use JBoss 4.0.1 (build: CVSTag=JBoss_4_0_1 date=200412230944

        • 1. Re: Classloading: Using isolation and accessing global libra
          karink

          sorry,
          the link to wiki is wrong above
          here is the correct link
          http://www.jboss.org/wiki/Wiki.jsp?page=ClassLoadingConfiguration
          Regards Karin

          • 2. Re: Classloading: Using isolation and accessing global libra
            karink

            Hello,
            at the moment I enhance the example explained above and put some
            EJBs as well in the EAR. The EJB should also use a class from
            the jar file called jpi-jboss-iv-classloadertest.jar. This jar file I
            deployed in the EAR-File and the Classpath variable of the Manifest
            file of the ejb jar file list the jpi-jboss-iv-classloadertest.jar.
            The jpi-jboss-iv-classloadertest.jar is also deployed in the server/lib directory of JBoss (as I'd like to test, that it is loaded from the EAR
            and not from the server/lib directory of JBoss).

            Here is a short overview how the SAR-file now looks

            jpi-iv-jboss.sar
             - meta-inf/jboss-service.xml
             - myear.ear
             - application.xml
             - first.war
             - second.war
             - jpi-jboss-iv-classloadertest.jar
             - myejb.jar
             - meta-inf/Manifest
             - meta-inf/jboss.xml
             - meta-inf/ejb-jar.xml
             ...the ejbs and other classes
            



            The jboss-service.xml file of the sar file looks like this:


            <server>
             <classpath
             codebase="file:/C:/common/lib/"
             archives="mycommon.jar"/>
            
             <loader-repository>dot.com:loader=jpi-jboss-iv-ejbs.ear
             <loader-repository-config>java2ParentDelegation=false
             </loader-repository-config> </loader-repository>
            </server>


            When the ejb accesses the class (which is contained in the jpi-jboss-iv-classloadertest.jar file) it is not loaded from the ear file, but from
            the server/lib directory of jboss.
            Removing the jboss-iv-classloadertest.jar from the server/lib directory
            has the effect, that it is now loaded from the EAR file. I did this
            test just to ensure that the EAR file really contains the jboss-iv-classloadertest.jar file.
            What is wrong with this configuration?. By the way in the JBoss
            JmxConsole I cannot see the loader-repository configured above.

            Thanks for your help
            Regards Karin




            • 3. Re: Classloading: Using isolation and accessing global libra
              ssilvert

              You've mostly got it right.

              jars that you want to be seen globally by all deployments go in server//lib, Where is usually "default", "all", or "minimal".

              You should not put jar files in jboss-4.0.1/lib.

              I suspect that the reason you don't see the dot.com:loader=jpi-jboss-iv-ejbs.ear repository in the JMX console is that the XML for your jboss-service.xml looks backwards. According to the DTD, loader-repository goes before classpath. Try adding this to jboss-service.xml so the xml will be validated:

              <!DOCTYPE server
               PUBLIC "-//JBoss//DTD MBean Service 4.0//EN"
               "http://www.jboss.org/j2ee/dtd/jboss-service_4_0.dtd">
              


              For what you want to do with the WAR files, you need to have useJBossWebLoader=false. This will make your web apps use the Tomcat class loader which doesn't know anything about loader repositories. It will look at the web app first and then ask its parent to load the class if it is not inside the WAR.

              Loader repository settings only take effect on the root context class loader. That means that if you have an ear inside a sar then only the class loader repository settings for the sar have any effect. The same is true for a war or ejb.jar inside an ear. useJBossWebLoader=false, however, does have an effect because it is outside the realm of loader repositories. When you put a loader-repository setting in a non-root deployment, you will get a warning message in the server.log.

              Stan Silvert
              JBoss, Inc.

              • 4. Re: Classloading: Using isolation and accessing global libra
                karink

                Hi Stan,
                thanx for your answer.
                In meantime there is coming another question up.
                Is it also possible to configure it without using a SAR.
                "It" means, again I would like to isolate the EAR file from
                the application server and I would also like to access some
                global libraries.


                My directory structure would then look like this:

                mydeploy
                 -jboss-service.xml
                 -myear.ear
                 -META-INF
                 -jboss-app.xml
                 ...
                


                Deployment is done by adding the directory mydeploy to the DeploymentScanner.

                The content of jboss-service.xml file looks like that:
                <!DOCTYPE server PUBLIC "-//JBoss//DTD MBean Service 4.0//EN"
                 "http://www.jboss.org/j2ee/dtd/jboss-service_4_0.dtd">
                <server>
                 <loader-repository>dot.com:loader=jpi-jboss-iv-ejbs.ear
                 <loader-repository-config>java2ParentDelegation=false
                 </loader-repository-config>
                 </loader-repository>
                 <!-- this is just an example do not care that which library it is -->
                 <classpath
                 codebase="file:/C:/common/lib/"
                 archives="mycommon.jar"/>
                
                </server>


                The content of the file jboss-app.xml looks like this:
                <!DOCTYPE jboss-app PUBLIC "-//JBoss//DTD J2EE Application 1.4//EN"
                 "http://www.jboss.org/j2ee/dtd/jboss-app_4_0.dtd">
                <jboss-app>
                 <loader-repository>dot.com:loader=jpi-jboss-iv-ejbs.ear
                 <loader-repository-config>java2ParentDelegation=false
                 </loader-repository-config>
                 </loader-repository>
                </jboss-app>
                


                This time I checked if the xml files are valid ;-))

                Ok, during deployment I receive the following log messages
                14:24:07,203 WARN [DeploymentInfo] Only the root deployment can set the loader repository, ignoring config=LoaderRepositoryConfig(repositoryName: dot.com:loader=jpi-jboss-iv-ejbs.earimjboss-service.xml, repositoryClassName: org.jboss.mx.loading.HeirarchicalLoaderRepository3, configParserClassName: org.jboss.mx.loading.HeirarchicalLoaderRepository3ConfigParser, repositoryConfig: java2ParentDelegation=false)
                14:24:07,243 INFO [EARDeployer] Init J2EE application: file:/C:/eplatform/ews/R_3.0/jboss-4.0/jpi-jboss-iv/deploy/mydeploy/jpi-jboss-iv.ear/
                14:24:07,263 WARN [DeploymentInfo] Only the root deployment can set the loader repository, ignoring config=LoaderRepositoryConfig(repositoryName: dot.com:loader=jpi-jboss-iv-ejbs.ear, repositoryClassName: org.jboss.mx.loading.HeirarchicalLoaderRepository3, configParserClassName: org.jboss.mx.loading.HeirarchicalLoaderRepository3ConfigParser, repositoryConfig: java2ParentDelegation=false)
                14:24:07,634 INFO [EjbModule] Deploying PropagatorTest
                14:24:08,535 INFO [EARDeployer] Started J2EE application: file:/C:/eplatform/ews/R_3.0/jboss-4.0/jpi-jboss-iv/deploy/mydeploy/jpi-jboss-iv.ear/


                So it seems that it was not possible to declare the loader-repository
                by means of the jboss-service.xml. How can I declare it.
                Or is there another possibility of declaring a loader-repository for my ear
                file and in parallel accessing global libraries that do not have to be part
                of the ear.

                Regards Karin

                • 5. Re: Classloading: Using isolation and accessing global libra
                  karink

                  Hi,
                  I found my mistake
                  The url I deployed was not correct.
                  I forgot the final /.
                  So now everything works correct.
                  Regards
                  Karin

                  • 6. Re: Classloading: Using isolation and accessing global libra

                    Hi karink,

                    I am facing the same issue. I want to configure log4j for my ear file, which contains 1 ejb jar file and one war file. I am able to configure for war file but not for EJB. the EJB always uses the JBoss logger.

                    Can you please help me and if possible send your sample containing ejb and war file


                    Many Thanks,
                    Umesh