1 2 3 Previous Next 32 Replies Latest reply on Feb 8, 2008 10:28 AM by Scott Stark

    Classloader problem with NamingRestartUnitTestCase

    Brian Stansberry Master

      Looking at why the o.j.t.naming.test.NamingRestartUnitTestCase started failing, looks like there is some classloader problem when a sar is redeployed.

      This test deploys a sar with a -beans.xml and a couple classes. It then redeploys it to simulate a restart of the naming service. This redeploy is failing:

      2008-02-01 10:09:41,700 ERROR [org.jboss.kernel.plugins.dependency.AbstractKernelController] Error installing to Described: name=RestartNamingService state=PreInstall
      java.lang.RuntimeException: java.lang.IllegalStateException: BaseClassLoader@1345af1{vfsfile:/home/bes/dev/jboss/trunk/testsuite/output/lib/naming-restart.sar} classLoader is not connected to a domain (probably undeployed?) for class org.jboss.aspects.jmx.MBean
       at org.jboss.aop.pointcut.Util.matchesClassExpr(Util.java:137)
       at org.jboss.aop.pointcut.TypeMatcher.visit(TypeMatcher.java:153)
       at org.jboss.aop.pointcut.ast.ASTClass.jjtAccept(ASTClass.java:43)
       at org.jboss.aop.pointcut.TypeMatcher.visit(TypeMatcher.java:73)
       at org.jboss.aop.pointcut.ast.ASTStart.jjtAccept(ASTStart.java:42)
       at org.jboss.aop.introduction.InterfaceIntroduction.matches(InterfaceIntroduction.java:274)
       at org.jboss.aop.AspectManager.applyInterfaceIntroductions(AspectManager.java:1735)
       at org.jboss.aop.Advisor.initializeInterfaceIntroductions(Advisor.java:318)
       at org.jboss.aop.proxy.container.ClassProxyContainer.initialise(ClassProxyContainer.java:171)
       at org.jboss.aop.proxy.container.InstanceProxyContainer.<init>(InstanceProxyContainer.java:56)
       at org.jboss.aop.proxy.container.InstanceProxyContainer.createInstanceProxyContainer(InstanceProxyContainer.java:68)
       at org.jboss.aop.proxy.container.ContainerCache.initInstanceContainer(ContainerCache.java:277)
       at org.jboss.aop.proxy.container.ContainerCache.initialise(ContainerCache.java:93)
       at org.jboss.aop.proxy.container.ContainerCache.initialise(ContainerCache.java:72)
       at org.jboss.aop.microcontainer.integration.AOPDependencyBuilder.getDependencies(AOPDependencyBuilder.java:97)
       at org.jboss.classadapter.plugins.BasicClassAdapter.getDependencies(BasicClassAdapter.java:80)
       at org.jboss.beans.info.plugins.AbstractBeanInfo.getDependencies(AbstractBeanInfo.java:211)
       at org.jboss.kernel.plugins.dependency.DescribeAction.installActionInternal(DescribeAction.java:53)
       at org.jboss.kernel.plugins.dependency.KernelControllerContextAction.installAction(KernelControllerContextAction.java:135)
       at org.jboss.kernel.plugins.dependency.KernelControllerContextAction.installAction(KernelControllerContextAction.java:46)
       at org.jboss.dependency.plugins.action.SimpleControllerContextAction.simpleInstallAction(SimpleControllerContextAction.java:62)
       at org.jboss.dependency.plugins.action.AccessControllerContextAction.install(AccessControllerContextAction.java:71)
       at org.jboss.dependency.plugins.AbstractControllerContextActions.install(AbstractControllerContextActions.java:51)
       at org.jboss.dependency.plugins.AbstractControllerContext.install(AbstractControllerContext.java:327)
       at org.jboss.dependency.plugins.AbstractController.install(AbstractController.java:1309)
       at org.jboss.dependency.plugins.AbstractController.incrementState(AbstractController.java:734)
       at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:862)
       at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:784)
       at org.jboss.dependency.plugins.AbstractController.install(AbstractController.java:574)
       at org.jboss.dependency.plugins.AbstractController.install(AbstractController.java:398)
       at org.jboss.deployers.vfs.deployer.kernel.BeanMetaDataDeployer.deploy(BeanMetaDataDeployer.java:69)
       at org.jboss.deployers.vfs.deployer.kernel.BeanMetaDataDeployer.deploy(BeanMetaDataDeployer.java:42)
       at org.jboss.deployers.spi.deployer.helpers.AbstractSimpleRealDeployer.internalDeploy(AbstractSimpleRealDeployer.java:65)
       at org.jboss.deployers.spi.deployer.helpers.AbstractRealDeployer.deploy(AbstractRealDeployer.java:50)
       at org.jboss.deployers.plugins.deployers.DeployerWrapper.deploy(DeployerWrapper.java:169)
       at org.jboss.deployers.plugins.deployers.DeployersImpl.doInstallParentFirst(DeployersImpl.java:853)
       at org.jboss.deployers.plugins.deployers.DeployersImpl.doInstallParentFirst(DeployersImpl.java:874)
       at org.jboss.deployers.plugins.deployers.DeployersImpl.install(DeployersImpl.java:794)
       at org.jboss.dependency.plugins.AbstractControllerContext.install(AbstractControllerContext.java:327)
       at org.jboss.dependency.plugins.AbstractController.install(AbstractController.java:1309)
       at org.jboss.dependency.plugins.AbstractController.incrementState(AbstractController.java:734)
       at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:862)
       at org.jboss.dependency.plugins.AbstractController.resolveContexts(AbstractController.java:784)
       at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:622)
       at org.jboss.dependency.plugins.AbstractController.change(AbstractController.java:411)
       at org.jboss.deployers.plugins.deployers.DeployersImpl.process(DeployersImpl.java:498)
       at org.jboss.deployers.plugins.main.MainDeployerImpl.process(MainDeployerImpl.java:506)
       at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:812)
       at org.jboss.deployment.MainDeployer.redeploy(MainDeployer.java:587)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:157)
       at org.jboss.mx.server.Invocation.dispatch(Invocation.java:96)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
       at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
       at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:668)
       at sun.reflect.GeneratedMethodAccessor190.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.jmx.connector.invoker.InvokerAdaptorService.invoke(InvokerAdaptorService.java:270)
       at sun.reflect.GeneratedMethodAccessor187.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:157)
       at org.jboss.mx.server.Invocation.dispatch(Invocation.java:96)
       at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:138)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:90)
       at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:140)
       at org.jboss.jmx.connector.invoker.SerializableInterceptor.invoke(SerializableInterceptor.java:74)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:90)
       at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
       at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:668)
       at org.jboss.invocation.jrmp.server.JRMPProxyFactory.invoke(JRMPProxyFactory.java:179)
       at sun.reflect.GeneratedMethodAccessor186.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:157)
       at org.jboss.mx.server.Invocation.dispatch(Invocation.java:96)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
       at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
       at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:668)
       at org.jboss.invocation.jrmp.server.JRMPInvoker$MBeanServerAction.invoke(JRMPInvoker.java:815)
       at org.jboss.invocation.jrmp.server.JRMPInvoker.invoke(JRMPInvoker.java:416)
       at sun.reflect.GeneratedMethodAccessor185.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:294)
       at sun.rmi.transport.Transport$1.run(Transport.java:153)
       at java.security.AccessController.doPrivileged(Native Method)
       at sun.rmi.transport.Transport.serviceCall(Transport.java:149)
       at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:466)
       at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:707)
       at java.lang.Thread.run(Thread.java:595)
      Caused by: java.lang.IllegalStateException: BaseClassLoader@1345af1{vfsfile:/home/bes/dev/jboss/trunk/testsuite/output/lib/naming-restart.sar} classLoader is not connected to a domain (probably undeployed?) for class org.jboss.aspects.jmx.MBean
       at org.jboss.classloader.spi.base.BaseClassLoader.loadClassFromDomain(BaseClassLoader.java:579)
       at org.jboss.classloader.spi.base.BaseClassLoader.loadClass(BaseClassLoader.java:234)
       at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
       at org.jboss.aop.Advisor.hasAnnotation(Advisor.java:396)
       at org.jboss.aop.Advisor.hasAnnotation(Advisor.java:370)
       at org.jboss.aop.pointcut.Util.matchesClassExpr(Util.java:115)
       ... 94 more
      


        • 1. Re: Classloader problem with NamingRestartUnitTestCase
          Brian Stansberry Master

          JIRA for this is http://jira.jboss.com/jira/browse/JBAS-5208 . I let it auto-assign to Scott Stark but I'll go ahead and poke further into it today.

          • 2. Re: Classloader problem with NamingRestartUnitTestCase
            Adrian Brock Master

            My guess is that AOP is caching the classloader somewhere?

            The most obvious candidate is this code in AOPDependencyBuilder:

             AspectManager manager = AspectManagerFactory.getAspectManager(metaData);
            


            which eventually boils down to a lookup by a String based on the deployment name

            AspectManagerFactory
             public static AspectManager getAspectManager(MetaData md)
             {
             AspectManager manager = AspectManager.instance();
             if (md != null)
             {
             ApplicationScope app = md.getMetaData(ApplicationScope.class);
             DeploymentScope dep = md.getMetaData(DeploymentScope.class);
             if (app != null && dep != null)
             {
             JBossStringBuilder fqn = new JBossStringBuilder("/");
             AspectManager sub = null;
             if (app != null)
             {
             String name="APPLICATION=" + app.value();
             fqn.append(name);
             fqn.append("/");
             sub = manager.findManagerByName(fqn.toString());
             if (sub == null)
             {
             sub = createNewDomain(manager, name);
             }
             }
            
             if (dep != null)
             {
             String name="DEPLOYMENT=" + dep.value();
             fqn.append(name);
             fqn.append("/");
             AspectManager parent = sub;
             sub = manager.findManagerByName(fqn.toString());
             if (sub == null)
             {
             sub = createNewDomain(parent, name);
             }
             }
             return sub;
             }
             }
             return manager;
             }
            


            AspectManager:
             /** A map of domains by name */
             protected volatile WeakValueHashMap subDomainsByName = UnmodifiableEmptyCollections.EMPTY_WEAK_VALUE_HASHMAP;
            


            Although this is a WeakValueHashMap, there's no guarantee that
            it will be reaped (depends when the GC runs) between redeployments
            and there is no "remove" at undeployment.

            So if something in the sub Domain created for the deployment name
            references the old classloader, it is going to leak across redeployment.

            • 3. Re: Classloader problem with NamingRestartUnitTestCase
              Adrian Brock Master

              Additionally, what this code is doing with the annotations looks wrong to me.

              The annotations are only a potential source of the scope,
              the scope could be determined in a different way.
              e.g. The deployers generate a scope for each deployment
              which comes from the deployment names not annotations.

              • 5. Re: Classloader problem with NamingRestartUnitTestCase
                Brian Stansberry Master

                Quick report as I poke around in this as well.

                Looking more into what AOPDependencyBuild.getDependencies does, following from the AspectManagerFactory.getAspectManager() call you highlighted:

                AspectManager manager = AspectManagerFactory.getAspectManager(metaData);
                 try
                 {
                 ClassInfo classInfo = classAdapter.getClassInfo();
                 String className = classInfo.getName();
                 if (className != null)
                 {
                 ClassLoader loader = classAdapter.getClassLoader();
                 if (loader == null)
                 {
                 loader = Thread.currentThread().getContextClassLoader();
                 }
                 Class clazz = loader.loadClass(className);
                


                The classAdapter.getClassLoader() call is returning the BaseClassLoader from the previous deployment. That happens before any usage is made of the AspectManager.

                Looking more into that, I see a chain of AbstractBeanInfo.classAdapter.classInfo.getType().getClassLoader(). Looking at classInfo.getType() I see it's actually ClassInfoImpl.annotatedElement.

                I'm going to poke a bit more and see if I can figure out where the AbstractBeanInfo and the ClassInfoImpl.annotatedElement are coming from.

                • 6. Re: Classloader problem with NamingRestartUnitTestCase
                  Adrian Brock Master

                  The ClassAdapter is retrieved during this processing in AbstractKernelConfigurator

                   public BeanInfo getBeanInfo(BeanMetaData metaData) throws Throwable
                   {
                   ClassLoader cl = Configurator.getClassLoader(metaData);
                   String className = metaData.getBean();
                   if (className == null)
                   return null;
                   return getBeanInfo(className, cl);
                   }
                  


                  The links are:
                  BeanInfo -> ClassAdapter -> ClassInfo -> Class

                  The AnnotatedElement is just the real Class.

                  The Configurator.getClassLoader(...) uses the thread context classloader
                  to load the class if there isn't a specific one configured (which in your case
                  there isn't - that comes with the next gen of the MC :-).

                  So it looks like there are three options for why it fails.

                  1) The TCL is wrong. e.g. something is setting the TCL on the RMI thread
                  and not resetting it.
                  2) Somehow it is able to lookup the old class in the old classloader
                  without getting an error
                  3) There is some bad caching going on somewhere
                  (the BeanInfo/ClassInfo caches are based on classloader so (1) would
                  also appear as this problem).

                  • 7. Re: Classloader problem with NamingRestartUnitTestCase
                    Adrian Brock Master

                     

                    "adrian@jboss.org" wrote:
                    The ClassAdapter is retrieved during this processing in AbstractKernelConfigurator


                    I should have also mentioned that is invoked from
                    org.jboss.kernel.plugins.dependency.PreInstallAction
                     protected void installActionInternal(KernelControllerContext context) throws Throwable
                     {
                     KernelController controller = (KernelController)context.getController();
                     Kernel kernel = controller.getKernel();
                     KernelConfigurator configurator = kernel.getConfigurator();
                    
                     BeanMetaData metaData = context.getBeanMetaData();
                     if (metaData.getBean() != null)
                     {
                     BeanInfo info = configurator.getBeanInfo(metaData);
                     context.setBeanInfo(info);
                    


                    • 8. Re: Classloader problem with NamingRestartUnitTestCase
                      Adrian Brock Master

                       

                      "adrian@jboss.org" wrote:

                      3) There is some bad caching going on somewhere
                      (the BeanInfo/ClassInfo caches are based on classloader so (1) would
                      also appear as this problem).


                      Yep. This is the problem and it's in the JDK.
                      It's due to my lack of understanding of ClassLoader.findLoadedClass() actually works.

                      I thought this was just a cache of classes defined by this classloader
                      but the javadoc says it is something else

                      Returns the class with the given binary name if this loader has been recorded by the Java virtual machine as an initiating loader of a class with that binary name. Otherwise null is returned.


                      I think this is actually related to the change we made to use Class.forName()
                      to resolve the array class name problem in JDK6
                      Class.forName() does some additional caching inside the JDK.

                      This is what I'm seeing. The bootstrap classloader
                      created by conf/jboss-service.xml is remembering that it already the class
                      even though the classloader it loaded it from is dead:
                      2008-02-05 20:43:25,554 TRACE [org.jboss.classloader.spi.base.BaseClassLoader] BaseClassLoader@8be9ef{vfsfile:/home/ejort/jboss-head/build/output/jboss-5.0.0.Beta4/ser
                      ver/all/conf/jboss-service.xml} loadClass org.jboss.test.naming.restart.RestartNamingService resolve=false
                      2008-02-05 20:43:25,554 TRACE [org.jboss.classloader.spi.base.BaseClassLoader] BaseClassLoader@8be9ef{vfsfile:/home/ejort/jboss-head/build/output/jboss-5.0.0.Beta4/ser
                      ver/all/conf/jboss-service.xml} already loaded class org.jboss.test.naming.restart.RestartNamingService class org.jboss.test.naming.restart.RestartNamingService{cl=Bas
                      eClassLoader@f834c8{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar} codeSource=(vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-rest
                      art.sar <no signer certificates>)}
                      


                      This in this code in BaseClassLoader which is supposed to be an optimization :-)
                       protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
                       {
                       boolean trace = log.isTraceEnabled();
                       if (trace)
                       log.trace(this + " loadClass " + name + " resolve=" + resolve);
                      
                       // Validate the class name makes sense
                       ClassLoaderUtils.checkClassName(name);
                      
                       // Did we already load this class?
                       Class<?> result = findLoadedClass(name);
                       if (result != null && trace)
                       log.trace(this + " already loaded class " + name + " " + ClassLoaderUtils.classToString(result));
                      


                      So the obvious fix is to replace findLoadedClass() with a real cache
                      of just those classes we already loaded (like it already does for resources).

                      The findLoadedClass() still needs to be invoked as a last resort
                      because of things like IBM's proxy class handling, which is actually
                      kind of bad because it means it will still erronously continue to return
                      undeployed classes until the garbage collector runs.

                      Or alternatively, I could just hack the problem to ignore
                      classes the JVM caches that have gone away. e.g.
                       Class<?> result = findLoadedClass(name);
                       if (result != null)
                       {
                       ClassLoader cl = result.getClassLoader();
                       // Not us, make sure the JDK isn't caching undeployed classes
                       if (cl != null && cl != this && cl instanceof RealClassLoader)
                       {
                       RealClassLoader rcl = (RealClassLoader) cl;
                       // Ignore when undeployed
                       if (rcl.isValid() == false)
                       result = null;
                       }
                       }
                      


                      • 9. Re: Classloader problem with NamingRestartUnitTestCase
                        Brian Stansberry Master

                        Thanks. :)

                        Traced the problem so far to here in IntrospectionTypeInfoFactoryImpl:

                         protected TypeInfo resolveComplexTypeInfo(ClassLoader cl, String name)
                         throws ClassNotFoundException
                         {
                         if (cl == null)
                         cl = Thread.currentThread().getContextClassLoader();
                        
                         Class clazz = Class.forName(name, false, cl);
                         return getTypeInfo(clazz);
                         }
                        


                        Class.forName(name, false, cl) is returning a Class whose getClassLoader() returns the old classloader. The classloader passed as the 'cl' param to Class.forName() is the correct one. Class.forName(String, boolean, ClassLoader) just calls into native method forName0(String, boolean, ClassLoader)

                        Poking around continues...

                        • 10. Re: Classloader problem with NamingRestartUnitTestCase
                          Brian Stansberry Master

                          Ah, I'd missed your last post when I posted mine. Sounds like you've nailed it.

                          • 11. Re: Classloader problem with NamingRestartUnitTestCase
                            Adrian Brock Master

                             

                            "bstansberry@jboss.com" wrote:
                            Ah, I'd missed your last post when I posted mine. Sounds like you've nailed it.


                            Actually, I haven't. The hack I mentioned above solves the problem
                            for ClassLoader.loadClass() but there is some internal caching going on with
                            Class.forName() where I can't intercept the behaviour fix the problem.

                            I added some debug to the BeanMetaDataDeployer

                             public void deploy(DeploymentUnit unit, BeanMetaData deployment) throws DeploymentException
                             {
                             try
                             {
                             String bean = deployment.getBean();
                             ClassLoader tcl = Thread.currentThread().getContextClassLoader();
                             Class<?> fromClassLoader = tcl.loadClass(bean);
                             Class<?> fromClassForName = Class.forName(bean, false, tcl);
                             BeanInfo beanInfo = configurator.getBeanInfo(deployment);
                             Class<?> fromBeanInfo = beanInfo.getClassInfo().getType();
                            
                             System.out.println("========> tcl=" + tcl + " fromClassLoader=" + printClass(fromClassLoader) + " fromClassForName=" + printClass(fromClassForName)+ " fromBeanInfo=" + printClass(fromBeanInfo)
                            


                            which produces the following output on a redeploy

                            2008-02-05 21:27:25,189 INFO [STDOUT] ========> tcl=BaseClassLoader@73a5d3{vfsfile:/home/ejort/jboss-head/build/output/jboss-5.0.0.Beta4/server/all/conf/jboss-service
                            .xml} fromClassLoader=org.jboss.test.naming.restart.RestartNamingService.BaseClassLoader@26f7af{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar}
                             fromClassForName=org.jboss.test.naming.restart.RestartNamingService.BaseClassLoader@50567b{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar} fro
                            mBeanInfo=org.jboss.test.naming.restart.RestartNamingService.BaseClassLoader@50567b{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar}
                            2008-02-05 21:27:25,191 TRACE [org.jboss.classloader.spi.base.BaseClassLoader] BaseClassLoader@50567b{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-
                            


                            @26f7af is the correct version of the classloader
                            @50567b is the old (undeployed) version of the classloader

                            The Class.forName() invocation aboves never hits the classloader
                            (I've checked this by looking at the TRACE logging)
                            so it is obviously using some cache inside the JDK.

                            This problem will obviously be fixed when the TCL and BeanMetaData classloader
                            is set to the deployment classloader with the new code.
                            e.g. I can simulate this with

                             public void deploy(DeploymentUnit unit, BeanMetaData deployment) throws DeploymentException
                             {
                             ClassLoader old = Thread.currentThread().getContextClassLoader();
                             Thread.currentThread().setContextClassLoader(unit.getClassLoader());
                             try
                             {
                             try
                             {
                             String bean = deployment.getBean();
                             ClassLoader tcl = Thread.currentThread().getContextClassLoader();
                             Class<?> fromClassLoader = tcl.loadClass(bean);
                             Class<?> fromClassForName = Class.forName(bean, false, tcl);
                             BeanInfo beanInfo = configurator.getBeanInfo(deployment);
                             Class<?> fromBeanInfo = beanInfo.getClassInfo().getType();
                            
                             System.out.println("========> tcl=" + tcl + " fromClassLoader=" + printClass(fromClassLoader) + " fromClassForName=" + printClass(fromClassForName)+ " fromBeanInfo=" + printClass(fromBeanInfo));
                             }
                             catch (Throwable t)
                             {
                             throw DeploymentException.rethrowAsDeploymentException("Unexpected error", t);
                             }
                            ...
                             }
                             finally
                             {
                             Thread.currentThread().setContextClassLoader(old);
                             }
                             }
                            


                            And the test passes with the following output on redeploy

                            21:40:29,591 INFO [STDOUT] ========> tcl=BaseClassLoader@f800e1{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar} fromClassLoader=org.jboss.test.naming.restart.RestartNamingService.BaseClassLoader@f800e1{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar} fromClassForName=org.jboss.test.naming.restart.RestartNamingService.BaseClassLoader@f800e1{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar} fromBeanInfo=org.jboss.test.naming.restart.RestartNamingService.BaseClassLoader@f800e1{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar}
                            


                            This is because the initiating classloader has changed so it avoids the
                            Class.forName() caching problem.

                            But this is still going to be an issue for usage of Class.forName() from
                            classloaders that don't get redeployed but have initiated classloading from
                            redeployed classloaders.

                            This must also have been issue with the old UnifiedClassLoader as well?

                            • 12. Re: Classloader problem with NamingRestartUnitTestCase
                              Adrian Brock Master

                              JIRA issue: http://jira.jboss.com/jira/browse/JBMICROCONT-234

                              I'll apply the "hack" to fix the problem. The test will pass when the latest MC stuff
                              is applied to JBossAS trunk.

                              I don't know what to do about the Class.forName() caching?

                              Maybe we could add a System.gc() - even though it is only a hint - whenever somebody
                              undeploys something to try to speed the cleanup of the JDK internal cache.

                              Or maybe there is a JDK specific api we could call from undeploy to flush the cache?
                              i.e. users could configure the call if they are experiencing the problem.

                              • 13. Re: Classloader problem with NamingRestartUnitTestCase
                                Adrian Brock Master

                                 

                                "adrian@jboss.org" wrote:

                                And the test passes with the following output on redeploy


                                Just for clarification purposes, JBMICROCONT-234 is not required to fix the problem.
                                The fix is to use the deployment classloader as the initiating classloader.

                                But I've applied it anyway since it will resolve some other problems.

                                So a temporary workaround without updating the MC code in trunk would be
                                to replace the BeanMetaDataDeployer (configured in bootstrap-beans.xml)
                                with something like:

                                package org.jboss.system.deployers;
                                
                                import org.jboss.beans.metadata.spi.BeanMetaData;
                                import org.jboss.deployers.spi.DeploymentException;
                                import org.jboss.deployers.structure.spi.DeploymentUnit;
                                import org.jboss.deployers.vfs.deployer.kernel.BeanMetaDataDeployer;
                                import org.jboss.kernel.Kernel;
                                
                                /**
                                 * A version of the POJO deployer that sets the context classloader to the deployment classloader
                                 *
                                 * @author <a href="adrian@jboss.com">Adrian Brock</a>
                                 * @version $Revision: 1.1 $
                                 */
                                public class TempBeanMetaDataDeployer extends BeanMetaDataDeployer
                                {
                                 public TempBeanMetaDataDeployer(Kernel kernel)
                                 {
                                 super(kernel);
                                 }
                                
                                 public void deploy(DeploymentUnit unit, BeanMetaData deployment) throws DeploymentException
                                 {
                                 ClassLoader old = Thread.currentThread().getContextClassLoader();
                                 Thread.currentThread().setContextClassLoader(unit.getClassLoader());
                                 try
                                 {
                                 super.deploy(unit, deployment);
                                 }
                                 finally
                                 {
                                 Thread.currentThread().setContextClassLoader(old);
                                 }
                                 }
                                }
                                


                                • 14. Re: Classloader problem with NamingRestartUnitTestCase
                                  Brian Stansberry Master

                                  Is this something we want to do for Beta4?

                                  1 2 3 Previous Next