4 Replies Latest reply on Aug 20, 2007 7:01 AM by Kabir Khan

    AOP ClassLoader/Scoping for the VFSClassLoader

    Adrian Brock Master

      Now that I've done my "brain dump" on where I really want to get to
      for the AOP scoping, here' s another one on some more immediate changes I need
      to make for the VFSClassLoader integration.

      The problem with the AOPScopedClassLoaderHelper and the
      ScopedClass[Pool/Factory/Repository]
      is that is assuming a simple hierarchical model.

      That works for typical J2SE usage (with hierarchical classloaders)
      or the JBoss UnifiedClassLoader (with hierarchical loader repositories)
      but it doesn't work with the new classloader that has OSGi classloading rules.

      With the OSGI style classloading rules a class can be deployed multiple times
      (at different versions or as a private class to a deployment that is not shared).

      The classloaders are also peers of each other and delegate to each other
      (in a consistent way). This is similar to the JBoss UnifiedClassLoader
      but it is not a delegate to everybody, there's no equivalent of a global repository
      that defines the classloading space.

      NOTE: In fact, the VFSClassLoader can emulate the old UnifiedClassLoader
      rules with export/importAll policies but that is beside the point here.

      So, as far as I can tell there needs to be the following changes in
      the AOPSharedClassLoaderHelper abstraction.

      1) All policy decisions need to be done inside the abstraction.
      Currently the abstraction is too low level with some decisions being made
      inside the AOP classes themselves.

      2) The ScopedClassPool needs replacing with something that
      doesn't assume that all classes are visible from the caller classloader.

      I'm thinking that this can probably be done with the already existing
      javassist ClassPath api, if we make an implement of this that hooks into
      the ClassLoaderPolicy abstraction of the new classloader (the apis
      are pretty similar at least in the concept of resource location).

      3) I'm not sure the idea of "repository", at least at is it used by AOP, is rich enough.
      I do have a notion of "ClassLoadingSpace"
      (which is all classloaders that interact with each other consistently)
      so maybe that is what could be used?

      But it still doesn't really encapsulate the idea that classes can be deployed twice
      inside a "space" if they are only used privately.
      e.g. think two deployments that interact but they each have their own
      version (possibly different version) of commons logging that isn't part of
      their interaction api.

      I'm going to try to implement it this way and see what problems I find.

        • 1. Re: AOP ClassLoader/Scoping for the VFSClassLoader
          Adrian Brock Master

          Linking related thread:
          http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4051453#4051453

          I've started the work on JBAOP-107 mentioned on the other thread.
          The AOPScopedClassLoaderHelper is replaced with a higher level abstraction
          AOPClassLoaderScopingPolicy that is implemented using the older class with a bridge.

          The isScoped(ClassLoader) is still not very useful for the OSGi style classloading
          so this needs more work.

          https://svn.jboss.org/repos/jbossas/projects/aop/trunk/aop/src/main/org/jboss/aop/classpool/AOPClassLoaderScopingPolicy.java

          NOTE: This is only a temporary solution to get a better abstraction for different
          classloader implementations/policies. The real solution is for AOP not to "guess"
          based on the classloader :-)

          • 2. Re: AOP ClassLoader/Scoping for the VFSClassLoader
            Adrian Brock Master

            Looks like there is lot more work to this.

            The original refactoring just dealt with the aop project (AspectManager).
            There's also a lot of deep integration in the asintegration project (AspectManagerService).

            I've manged to come up with an alternate integration interface that encapsulates all this:

            package org.jboss.aop.deployment;
            
            import java.io.File;
            
            import javassist.scopedpool.ScopedClassPoolFactory;
            
            import org.jboss.aop.ClassLoaderValidation;
            import org.jboss.aop.classpool.AOPClassLoaderScopingPolicy;
            
            /**
             * AOPIntegration.<p>
             *
             * This class is intended to identify all the integration
             * points AOP is making with the JBoss appserver.
             *
             * @author <a href="adrian@jboss.com">Adrian Brock</a>
             * @version $Revision: 1.1 $
             */
            public interface JBossIntegration extends ClassLoaderValidation, ScopedClassPoolFactory
            {
             /**
             * Create the AOPClassLoaderScopingPolicy
             *
             * @return the policy
             */
             AOPClassLoaderScopingPolicy createAOPClassLoaderScopingPolicy();
            
             /**
             * Create a scoped classpool factory
             *
             * TODO JBAOP-??? need to review whether ScopedClassPool should also be replaced with
             * some other policy, e.g. javassist ClassPath notion is closer to new classloader?
             * @param tmpDir the temporary directory for classes
             * @return the factory
             * @throws Exception for any error
             */
             ScopedClassPoolFactory createScopedClassPoolFactory(File tmpDir) throws Exception;
            
             /**
             * Attach the depreacted translator
             */
             void attachDeprecatedTranslator();
            
             /**
             * Detach the deprecated translator
             */
             void detachDeprecatedTranslator();
            }
            


            And an implementation for the old stuff
            package org.jboss.aop.deployment;
            
            import java.io.File;
            
            import javax.management.Attribute;
            import javax.management.AttributeNotFoundException;
            import javax.management.InstanceNotFoundException;
            import javax.management.InvalidAttributeValueException;
            import javax.management.MBeanException;
            import javax.management.MBeanServer;
            import javax.management.ReflectionException;
            
            import javassist.ClassPool;
            import javassist.scopedpool.ScopedClassPool;
            import javassist.scopedpool.ScopedClassPoolFactory;
            import javassist.scopedpool.ScopedClassPoolRepository;
            
            import org.jboss.aop.AspectManager;
            import org.jboss.aop.classpool.AOPClassLoaderScopingPolicy;
            import org.jboss.aop.classpool.AOPScopedClassLoaderHelper;
            import org.jboss.aop.classpool.AOPScopedClassLoaderHelperBridge;
            import org.jboss.mx.loading.RepositoryClassLoader;
            import org.jboss.mx.util.MBeanServerLocator;
            
            /**
             * JBoss4Integration.<p>
             *
             * This class and its associated classes are
             * for the old JBoss4 integration with the LoaderRepository<p>
             *
             * <ul>Related Classes:
             * <li> {@link JBossClassPool}
             * <li> {@link JBossClassPoolFactory}
             * <li> {@link JBossScopedClassLoaderHelper}
             * <li> {@link LoaderRepositoryUrlUtil}
             * <li> {@link ScopedClassLoaderDomain}
             * <li> {@link ScopedJBossClassPool}
             * </ul>
             *
             * @deprecated TODO JBAOP-??? need to write a JBoss5 version
             * @author <a href="adrian@jboss.com">Adrian Brock</a>
             * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
             * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
             * @version $Revision: 1.1 $
             */
            @Deprecated
            public class JBoss4Integration implements JBossIntegration
            {
             /** The delegate classpool factory */
             private ScopedClassPoolFactory delegateClassPoolFactory;
            
             public boolean isValidClassLoader(ClassLoader loader)
             {
             if (!(loader instanceof RepositoryClassLoader)) return false;
             return ((RepositoryClassLoader) loader).getLoaderRepository() != null;
             }
            
             public AOPClassLoaderScopingPolicy createAOPClassLoaderScopingPolicy()
             {
             AOPScopedClassLoaderHelper helper = new JBossScopedClassLoaderHelper();
             return new AOPScopedClassLoaderHelperBridge(helper);
             }
            
             public ScopedClassPoolFactory createScopedClassPoolFactory(File tmpDir) throws Exception
             {
             delegateClassPoolFactory = new JBossClassPoolFactory(tmpDir);
             return this;
             }
            
             public ScopedClassPool create(ClassLoader cl, ClassPool src, ScopedClassPoolRepository repository)
             {
             return delegateClassPoolFactory.create(cl, src, repository);
             }
            
             public ScopedClassPool create(ClassPool src, ScopedClassPoolRepository repository)
             {
             return delegateClassPoolFactory.create(src, repository);
             }
            
             public void attachDeprecatedTranslator()
             {
             AspectManager mgr = AspectManager.instance();
             MBeanServer server = MBeanServerLocator.locateJBoss();
             try
             {
             server.setAttribute(AspectManagerService.DEFAULT_LOADER_REPOSITORY, new Attribute("Translator", mgr));
             }
             catch (InstanceNotFoundException e)
             {
             throw new RuntimeException(e);
             }
             catch (AttributeNotFoundException e)
             {
             throw new RuntimeException(e);
             }
             catch (InvalidAttributeValueException e)
             {
             throw new RuntimeException(e);
             }
             catch (MBeanException e)
             {
             throw new RuntimeException(e);
             }
             catch (ReflectionException e)
             {
             throw new RuntimeException(e);
             }
             }
            
             public void detachDeprecatedTranslator()
             {
             MBeanServer server = MBeanServerLocator.locateJBoss();
             try
             {
             server.setAttribute(AspectManagerService.DEFAULT_LOADER_REPOSITORY, new Attribute("Translator", null));
             }
             catch (InstanceNotFoundException e)
             {
             throw new RuntimeException(e);
             }
             catch (AttributeNotFoundException e)
             {
             throw new RuntimeException(e);
             }
             catch (InvalidAttributeValueException e)
             {
             throw new RuntimeException(e);
             }
             catch (MBeanException e)
             {
             throw new RuntimeException(e);
             }
             catch (ReflectionException e)
             {
             throw new RuntimeException(e);
             }
             }
            


            This is just an FYI warning, since I've NOT committed it yet (not tested it).

            The main work will be in writing a JBoss5 version that uses the new
            jboss-classloading-spi instead so it can work with both the
            RepositoryClassLoader and the VFSClassLoader.

            • 3. Re: AOP ClassLoader/Scoping for the VFSClassLoader
              Adrian Brock Master

              I've committed this since I haven't broken any tests that weren't already broken. :-)

              NOTE: I haven't updated the temp deployer in jboss's system project
              since that would require releasing a jboss-aop snapshot which
              I don't want to do yet.

              P.S. There seems to be a problem with the way the pluggable instrumentor is
              being used by the testsuite bootstrapping ant tasks (path problem?).

              I keep seeing "random" errors like this:

              Caused by: java.lang.NoClassDefFoundError: org/jboss/aop/standalone/PluggableInstrumentor
               at org.jboss.aop.deployment.AspectManagerServiceJDK5.attachTranslator(AspectManagerServiceJDK5.java:46)
               at org.jboss.aop.deployment.AspectManagerService.setEnableLoadtimeWeaving(AspectManagerService.java:537)
               at org.jboss.mx.interceptor.AttributeDispatcher.invoke(AttributeDispatcher.java:136)
              

              which I haven't seen when I start the appserver manually?

              I'll also see if I can figure out why the other tests were already failing before I started this work. e.g. the ScopedEarWithClassesInWebInfTestCase test

              • 4. Re: AOP ClassLoader/Scoping for the VFSClassLoader
                Kabir Khan Master

                AspectManager.enableTransformer = use the the old Transformer/UCL integration

                AspectManager.enableLoadtimeWeaving = use the JDK 5 pluggable instrumentor, so to use this you need to set up the server for loadtime weaving. i.e. specify -javaagent. This is done by the tests-aop-scoped target