10 Replies Latest reply on Apr 23, 2009 10:46 PM by beve

    ESB4.x/AS 5 classloading

    beve

      In the ESB a .esb archive may contain action classes that the ESB needs to have access to and load. The same goes for resources in these archives.

      There is also the case were there are services that provide services to other esb services. For example, there is a smooks.esb that provides a SmooksAction which provides data transformation. To use the SmooksAction, a user creates an .esb archive and referenses the SmooksAction from the ESB configuration. They will also need to specify that their .esb archive depends on smooks.esb which they specify in the file deployment.xml.
      This worked well with JBoss AS 4.x but with AS 5 this does not work and I think some sort of classloading configuration will be needed simliar to OSGI where a .esb archive might need to contain a META-INF/jboss-classloading.xml file and declare what packages/modules it imports/exports.

      Without any configuration this is what happens upon deployment :

      java.lang.RuntimeException: java.lang.RuntimeException: Failed to find action class 'org.jboss.soa.esb.smooks.SmooksAction'.
       at org.jboss.soa.esb.listeners.config.Configuration.create(Configuration.java:138)
       at org.jboss.soa.esb.listeners.deployers.mc.EsbDeployment.start(EsbDeployment.java:112)
       ... // Cut out some of the stacktrace to make it more readable /Daniel
       ...
      Caused by: java.lang.RuntimeException: Failed to find action class 'org.jboss.soa.esb.smooks.SmooksAction'.
       at org.jboss.soa.esb.listeners.config.mappers.XMLBeansModel.getContractPublisher(XMLBeansModel.java:378)
       at org.jboss.soa.esb.listeners.config.mappers.XMLBeansModel.getServicePublishers(XMLBeansModel.java:351)
       at org.jboss.soa.esb.listeners.config.model.Model101SchemaParser$Model101Adapter.getServicePublishers(Model101SchemaParser.java:116)
       at org.jboss.soa.esb.listeners.config.Configuration.create(Configuration.java:117)
       ... 53 more
      Caused by: java.lang.ClassNotFoundException: org.jboss.soa.esb.smooks.SmooksAction
       at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
       at java.security.AccessController.doPrivileged(Native Method)
       at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
       at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
       at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:268)
       at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
       at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
       at java.lang.Class.forName0(Native Method)
       at java.lang.Class.forName(Class.java:242)
       at org.jboss.soa.esb.util.ClassUtil.forName(ClassUtil.java:93)
       at org.jboss.soa.esb.listeners.config.mappers.XMLBeansModel.getContractPublisher(XMLBeansModel.java:376)
       ... 56 more
      08:46:16,523 INFO [EsbDeployment] Destroying ESB Deployment 'transformation-pojo-quickstart'
      08:46:16,586 ERROR [ProfileServiceBootstrap] Failed to load profile: Summary of incomplete deployments (SEE PREVIOUS ERRORS FOR DETAILS):
      
      DEPLOYMENTS IN ERROR:
       Deployment "jboss.esb.vfszip:/opt/jboss/as/jboss-5.0.1.GA/server/default/deploy/transformation-pojo-quickstart.esb/" is in error due to the following reason(s): java.lang.ClassNotFoundException: org.jboss.soa.esb.smooks.SmooksAction
      


      The org.jboss.soa.esb.smooks.SmooksAction class lives in smooks.esb. Now the transformation-pojo-quickstart.esb does state that it depends on smooks.esb but this does not give it access to the classes from smooks.esb as far as I can tell (from server.log):
      2009-04-16 10:59:14,468 DEBUG [org.jboss.soa.esb.listeners.deployers.mc.EsbConfigParser] (main)
      Parsed ESB configuration'EsbMetaData [archiveName='transformation-pojo-quickstart.esb/META-INF/jboss-esb.xml', deploymentName='transformation-pojo-quickstart',
      dependencies='[
      jboss.esb.quickstart.destination:service=Queue,name=quickstart_simple_transformation_Response,
      jboss.esb.quickstart.destination:service=Queue,name=quickstart_transform_pojo_gw,
      jboss.esb:deployment=smooks.esb,
      jboss.esb.quickstart.destination:service=Queue,name=quickstart_transform_pojo_esb]']'
      


      Now, if smooks.esb contains a META-INF/jboss-classloading.xml that exports the org.jboss.soa.esb.smooks.SmooksAction will that mean that this deployment, the transformation-pojo-quickstart.esb, will have access to that class?
      I'm thinking no, as the quickstart does to say that it requires access to the package. Just becasue smooks.esb exports a class does not mean that other deployment will see it.
      So if .esb archives are to be able to get deployed as is, we may need to inquire the services that it depends on and add the equivalent ClassLoadingMetaData during deployment.

      I'll start by trying to manually add a jboss-classloading.xml to the quickstart and see if that works.

      If anyone has comments or suggestions they are always welcome.







        • 1. Re: ESB4.x/AS 5 classloading
          kconner

          The AS 4 deployer has a mechanism whereby it automatically injects the dependency based on the name of the actions, just in case the user has not defined this dependency within their deployment.xml.

          We should be able to create a similar mechanism for all the standard actions then specify, as with AS 4, that they handle their own by themselves.

          Kev

          • 2. Re: ESB4.x/AS 5 classloading
            beve

             

            The AS 4 deployer has a mechanism whereby it automatically injects the dependency based on the name of the actions, just in case the user has not defined this dependency within their deployment.xml.

            Ah, do you mean the actionArtifactMap.properties? I've actually got that implemented but that might not be working correctly. I'll double check that.

            Thanks

            • 3. Re: ESB4.x/AS 5 classloading
              kconner

              Yeah, that's the one although the requirements for MC are likely to be very different to AS 4.

              Kev

              • 4. Re: ESB4.x/AS 5 classloading
                alesj

                What you need is this:
                - http://www.jboss.org/community/docs/DOC-13178
                See jboss-dependency.xml.

                But jboss-classloading.xml should work as well.
                If you do it properly. ;-)

                • 5. Re: ESB4.x/AS 5 classloading
                  beve

                   

                  See jboss-dependency.xml.

                  I believe that we are using this but doing it programatically since we have a different configuration file (deployment.xml) for specifying dependencies in ESB 4.x.
                  This is how it we are doing it at the moment:
                  http://anonsvn.jboss.org/repos/labs/labs/jbossesb/workspace/dbevenius/jbossas5/product/rosetta/src/org/jboss/soa/esb/listeners/deployers/mc/EsbDeployer.java
                  // Add the dependencies for this deployment.
                  Set<ObjectName> dependencies = esbMetaData.getDependencies();
                  for (ObjectName objectName : dependencies)
                  {
                   // The dependencies are added as demands. If we add them as dependencies
                   // they will get undeployed when this unit is undeployed.
                   bmdBuilder.addDemand(objectName.toString());
                  }

                  The dependencies are added by the EsbConfigParser deployer by extracting the dependency information from deployment.xml.
                  If one deployment has a dependency on another does that imply that the one defining the dependency has access to the other deployments classes?

                  Thanks,

                  /Daniel






                  • 6. Re: ESB4.x/AS 5 classloading
                    alesj

                     

                    "beve" wrote:

                    The dependencies are added by the EsbConfigParser deployer by extracting the dependency information from deployment.xml.

                    Your dependency kicks in too late, hence the CNFE.

                    And you are just describing a module (transitively for class/package)
                    dependency for a single bean (EsbDeployment) which might not be enough.

                    You can still use your mechanism,
                    but then the demand must have whenRequired before or equal PreInstall.

                    "beve" wrote:

                    If one deployment has a dependency on another does that imply that the one defining the dependency has access to the other deployments classes?

                    If there is no explicit ClassLoadingMetaData (e.g. jboss-classloading.xml),
                    then you have the same behavior as 4.x - flat "big ball of mud". ;-)

                    If CLMD is present, then we follow "OSGI-ish" rules.

                    • 7. Re: ESB4.x/AS 5 classloading
                      kconner

                      Unfortunately, at present, we need the "big ball of mud".

                      There would be a lot of work involved in tidying up ESB 4.x to use cleaner classloader dependencies.

                      • 8. Re: ESB4.x/AS 5 classloading
                        beve

                         

                        You can still use your mechanism,
                        but then the demand must have whenRequired before or equal PreInstall.

                        I've modified the EsbDeployer and we now set the demands like this:
                        bmdBuilder.addDemand(objectName.toString(), ControllerState.PRE_INSTALL, ControllerState.INSTALLED, null);
                        

                        What I think I'm saying here is that this deployment demands objectName.toString(), and it requires that when this deploment is at the PRE_INSTALL stage, that objectName().toString() is INSTALLED. Have I understood that correctly?
                        I'm getting the same error with the above code but it might not be correct.

                        If I look at the classloader used in ClassUtil.forName, the thread context classloader is first used to try to locate the resource:
                        final ClassLoader threadClassLoader = Thread.currentThread().getContextClassLoader() ;
                        

                        The classloader returned is :
                        BaseClassLoader@215548{vfszip:/opt/jboss/as/jboss-5.0.1.GA/server/default/deploy/transformation-pojo-quickstart.esb/}


                        Since this is the deployment units classloader and the deployment has a demands on smooks.esb should it not be able to access and load the SmooksAction in smooks.esb/jbossesb-smooks.jar, which is in smook.esb. I'm not using any explicit classloading configuration here going with the "big ball of mud" option :)




                        • 9. Re: ESB4.x/AS 5 classloading
                          alesj

                          When do you actually try to load that "missing" class?

                          As I thought that was one of the beans,
                          but looking at the exception that's probably not the case.

                          • 10. Re: ESB4.x/AS 5 classloading
                            beve

                            Since the forums have been down I've made some progress on this.

                            The classloading issue that I reported previously was a configuration error on my part. I had created jboss-structure.xml files for our services.

                            <structure>
                             <context>
                             <path name=""/>
                             <metaDataPath>
                             <path name="META-INF"/>
                             </metaDataPath>
                             <classpath>
                             <path name=""/>
                             </classpath>
                             </context>
                            </structure>

                            I was assuming that this would include all files in the root of the the deployment archive but it seems that I need to specify that jars are to be included. Adding
                            <path name="" suffixes=".jar"/>

                            to the classpath worked.

                            The complete jboss-structure.xml now looks like this:

                            <structure>
                             <context>
                             <path name=""/>
                             <metaDataPath>
                             <path name="META-INF"/>
                             </metaDataPath>
                             <classpath>
                             <path name=""/>
                             <path name="" suffixes=".jar"/>
                             </classpath>
                             </context>
                            </structure>