3 Replies Latest reply on Feb 23, 2011 9:28 AM by alesj

    More on BaseClassLoader conflict with Instrumentation....

    ted.hulick

      Maybe would be best to spell out the architecture of my issue:

       

       

      * At runtime, I add a group of jars to sun.misc.Loader$AppLoader containing some instrumentation using the addURL method, the code in these jars make reference to some jms classes.   I also include jms.jar as part of this

       

      * An EAR/WAR is loaded which is instrumented (bytecode modified) and make reference to the code in the jars put in the sun class loader.  This WAR also has a jms.jar file - these classes are loaded into the JBoss "BaseClassLoader".

       

      * The classes in the BaseClassLoader pick up the classes from the sun Class Loader just fine - evidently, the BaseClassLoader IS delegating to the

      sun base Class Loader EVEN THOUGH it shows that it's parent is NOT the base loader (which I normally see), but instead the parent being

      null indicating a native or boot loader.

       

      * The problem comes when code in the sun loader is called by the code in the BaseClassLoader and the javax.jms.Session interface seems to be loaded into the BaseClassLoader from jms.jar in the WAR (self first? as it DID NOT delegate down to the sun Class Loader) and all comes

      apart when a class impl for javax.jms.Session created in the BaseClassLoader is then cast to javax.jms.Session in the sun Class Loader and

      because they were loaded in 2 different class loaders they are not considered the same class and we get a Class Cast Exception.

       

      ***** I want to either at runtime set the Classpath for the BaseClassLoader to my instrumentation classes which would resolve this issue OR

      force ALL class loaders to delegate downstream to the jms.jar that I loaded in the sun AppClassLoader....

       

        • 1. More on BaseClassLoader conflict with Instrumentation....
          alesj
          * The classes in the BaseClassLoader pick up the classes from the sun Class Loader just fine - evidently, the BaseClassLoader IS delegating to the

          sun base Class Loader EVEN THOUGH it shows that it's parent is NOT the base loader (which I normally see), but instead the parent being

          null indicating a native or boot loader.

          System Classloader

           

          * The problem comes when code in the sun loader is called by the code in the BaseClassLoader and the javax.jms.Session interface seems to be loaded into the BaseClassLoader from jms.jar in the WAR (self first? as it DID NOT delegate down to the sun Class Loader) and all comes

          apart when a class impl for javax.jms.Session created in the BaseClassLoader is then cast to javax.jms.Session in the sun Class Loader and

          because they were loaded in 2 different class loaders they are not considered the same class and we get a Class Cast Exception.

          Why exactly do you need that jms.jar in .war?

           

          Self first is per the spec for web/.war deployments.

          ***** I want to either at runtime set the Classpath for the BaseClassLoader to my instrumentation classes which would resolve this issue OR

          force ALL class loaders to delegate downstream to the jms.jar that I loaded in the sun AppClassLoader....

           

          Add jboss-classloading.xml with parent-first=true attribute.

           

          If you want that the rest of classes (non jms.jar) are still looked parent-first=false, you need a bit more work.

          The new jboss-classloading-domain.xml in AS6 helps here, but unfortunately it has a few bugs, which are already fixed,

          and as such will be part of next AS6.1 release.

          • 2. More on BaseClassLoader conflict with Instrumentation....
            ted.hulick

            First, I really appreciate your help...

             

            Ok - I don't control the WAR file...essentially, our product montiors JBoss app server...the WAR in this case was written by QA...and they included jms.jar in their deployment.  So, you are saying that if they DID NOT include it - it would have found the one I attached to the base system classloader?

            And you are saying that by default the WAR will indeed load it's jms.jar and NOT look downstream to my jms.jar?  Is there a way to override this behavior just for that 1 jar?  Maybe via a property that was set?  Can it be done programmatically?  We can't ask the customer to change

            their deployments.

             

            On the jboss-classloading.xml to parent first...would this override the WAR file self-first?  Again, can something be done via property or programmatically so customers don't have to alter their deployment.

             

            Essentially, I'm just added some jars to the classpath using the addURL (and change protection) on the system classloader and then referring

            to those classes in instrumentation....because they make reference to jms classes - I have to make sure jms.jar is in the system classloader

            path as well.   When anything else in the app loader loads jms.jar (which is only interfaces anyhow) classes from their own loader and now

            delegate downstream to mine - then Class Cast issues occur as of course, a class instance in 2 different loaders is not considered to be

            the same class.

             

            Again - any help/suggestions is appreciated....

            • 3. More on BaseClassLoader conflict with Instrumentation....
              alesj

              All deployments are metadata / attachment driven via deployers.

              What this means in more human form? :-)

              btw: did you read any of the DZone article's on Microcontainer topic?

               

              Each configuration file is transfomed into some metadata class / instance.

              And this metadata instance is added / attached to DeploymentUnit instance.

              DeploymentUnit is what is passed between deployer instances -- see Deployer::deploy(DeploymentUnit unit).

              DeploymentUnit's attachments are nothing more then a smarter semi type-safe Map.

              As you can see deployers actually don't care where this metadata instances come from.

              It could be either from parsed configuration or added programatically.

               

              So, to answer your question, yes it can be done programmatically.

              Simply add a new custom deployer to the existing chain of deployers.

              Where you would add or replace or modify an existing ClassLoaderMetaData, which is jboss-classloading.xml is parsed into.