1 2 Previous Next 17 Replies Latest reply on Jan 27, 2009 6:00 AM by Adrian Brock

    Module.getModuleForClassLoader()

    Kabir Khan Master

      Similar to the getModuleForClass() from JBCL-78
      discussed here http://www.jboss.com/index.html?module=bb&op=viewtopic&t=143639&postdays=0&postorder=asc&start=30

      I would like to add an additional method to Module:

       public Module getModuleForClassLoader(ClassLoader cl) throws ClassNotFoundException
       {
       SecurityManager sm = System.getSecurityManager();
       if (sm != null)
       sm.checkPermission(new RuntimePermission("getClassLoader"));
      
       // Determine the module (if any) for the classloader
       if (cl != null)
       return modulesByClassLoader.get(cl);
       // Unknown
       return null;
       }
      

      I need this to initialise my classpool domains with the bootstrap classloaders, since they are not getting picked up by the AOPClassLoaderDeployer in AS.

        • 1. Re: Module.getModuleForClassLoader()
          Kabir Khan Master

          I have created an org.jboss.bootstrap.spi.Bootstrap implementation to pick up the classloaders created by the bootstrap deployments.

          Next I need a method to get the Module for each classloader so I can push that into the AOP registry. I am not sure if Module is the right place for it, since I have no initiating Module at this stage.

          • 2. Re: Module.getModuleForClassLoader()
            Kabir Khan Master

            I've worked around it for now in my AOPBootstrap

             public void start(Server server) throws Exception
             {
             log.debug("Registering bootstrap classloaders with AOP");
             if(server instanceof MCServer)
             {
             MCServer mcserver = MCServer.class.cast(server);
             Map<String, KernelDeployment> serverDeployments = mcserver.getDeployments();
             KernelController controller = mcserver.getKernel().getController();
            
             for(KernelDeployment kd : serverDeployments.values())
             {
             Object loaderName = getClassLoaderName(kd);
             if (loaderName == null)
             {
             continue;
             }
             registerClassLoader(controller, loaderName);
             }
             }
             else
             {
             log.warn("Server is not an instance of MCServer. Ignoring bootstrap loaders");
             }
             }
            
             private Object getClassLoaderName(KernelDeployment kd)
             {
             ClassLoaderMetaData clmd = kd.getClassLoader();
             if (clmd == null)
             {
             log.debug("No ClassLoaderMetaData for " + kd);
             return null;
             }
             ValueMetaData vmd = clmd.getClassLoader();
             if (vmd == null)
             {
             log.debug("No ValueMetaData for " + clmd + " from " + kd);
             return null;
             }
             Object ldr = vmd.getUnderlyingValue();
             if (ldr == null)
             {
             log.debug("No loader in " + vmd + " for " + clmd + " for " + kd);
             return null;
             }
             return ldr;
             }
            
             private void registerClassLoader(KernelController controller, Object name)
             {
             ControllerContext loaderCtx = controller.getContext(name, ControllerState.INSTALLED);
             if (loaderCtx == null)
             {
             throw new IllegalStateException("No classloader found with name " + name);
             }
             ClassLoader loader = (ClassLoader)loaderCtx.getTarget();
             if (loader == null)
             {
             throw new IllegalStateException("Classloader was null " + name);
             }
            
             registerLoaderWithAOP(loader, findModule(controller, loaderCtx));
             }
            
             private Module findModule(KernelController controller, ControllerContext loaderCtx)
             {
             //Figure out the Module from the dependencies
             DependencyInfo info = loaderCtx.getDependencyInfo();
             Set<DependencyItem> loaderDependencies = info.getIDependOn(null);
             Module module = null;
             for (DependencyItem dep : loaderDependencies)
             {
             Object name = dep.getIDependOn();
             ControllerContext candidateCtx = controller.getContext(name, ControllerState.INSTALLED);
             if (candidateCtx.getTarget() instanceof Module)
             {
             if (module != null)
             {
             throw new IllegalStateException("Found more than one Module in the dependencies of " +
             loaderCtx.getName() + ":" + module.getContextName() + " and " + name);
             }
             module = (Module)candidateCtx.getTarget();
             }
             }
            
             if (module == null)
             {
             throw new IllegalStateException("No Module found for loader " + loaderCtx.getName());
             }
            
             return module;
             }
            


            • 3. Re: Module.getModuleForClassLoader()
              Adrian Brock Master

               

              "kabir.khan@jboss.com" wrote:
              Similar to the getModuleForClass() from JBCL-78
              discussed here http://www.jboss.com/index.html?module=bb&op=viewtopic&t=143639&postdays=0&postorder=asc&start=30

              I would like to add an additional method to Module:
               public Module getModuleForClassLoader(ClassLoader cl) throws ClassNotFoundException
               {
               SecurityManager sm = System.getSecurityManager();
               if (sm != null)
               sm.checkPermission(new RuntimePermission("getClassLoader"));
              
               // Determine the module (if any) for the classloader
               if (cl != null)
               return modulesByClassLoader.get(cl);
               // Unknown
               return null;
               }
              

              I need this to initialise my classpool domains with the bootstrap classloaders, since they are not getting picked up by the AOPClassLoaderDeployer in AS.


              Ok with me. Your "workaround" looks horrible. :-)
              The use of the MC to implement the classloading dependencies is an implemention detail,
              it could change without notice.


              I have created an org.jboss.bootstrap.spi.Bootstrap implementation to pick up the classloaders created by the bootstrap deployments.

              Next I need a method to get the Module for each classloader so I can push that into the AOP registry. I am not sure if Module is the right place for it, since I have no initiating Module at this stage.


              I don't mind you adding static query methods to the Module class as long as
              they have permissions checks.
              In fact, I think the first part of your post would be better implemented by listing
              all existing modules at aop initialization?
              That way you don't depend upon the specific bootstrap implementation.

              • 4. Re: Module.getModuleForClassLoader()
                Adrian Brock Master

                 

                "adrian@jboss.org" wrote:
                Your "workaround" looks horrible. :-)
                The use of the MC to implement the classloading dependencies is an implemention detail,
                it could change without notice.


                If you do it correctly, your integration with the classloading shouldn't make any reference
                to the MC. The ClassLoading/Module classes should give you enough information.


                I don't mind you adding static query methods to the Module class as long as
                they have permissions checks.


                Well actually this should be on the ClassLoading class rather than
                static methods on the Module?

                • 5. Re: Module.getModuleForClassLoader()
                  Ales Justin Master

                   

                  "adrian@jboss.org" wrote:

                   public Module getModuleForClassLoader(ClassLoader cl) throws ClassNotFoundException
                   {
                   SecurityManager sm = System.getSecurityManager();
                   if (sm != null)
                   sm.checkPermission(new RuntimePermission("getClassLoader"));
                  
                   // Determine the module (if any) for the classloader
                   if (cl != null)
                   return modulesByClassLoader.get(cl);
                   // Unknown
                   return null;
                   }
                  


                  I don't mind you adding static query methods to the Module class as long as
                  they have permissions checks.

                  Yeah, Kabir, this one could be made static.
                  I guess we don't expect it to be overridden somewhere?

                  • 6. Re: Module.getModuleForClassLoader()
                    Kabir Khan Master

                     

                    "adrian@jboss.org" wrote:

                    Ok with me. Your "workaround" looks horrible. :-)

                    I know, just needed something to get me going without having to update too many snapshots.
                    "adrian@jboss.org" wrote:

                    In fact, I think the first part of your post would be better implemented by listing
                    all existing modules at aop initialization?
                    That way you don't depend upon the specific bootstrap implementation.

                    I'm not sure what you mean here? If you mean adding a method returning a map of all loaders and modules, then I think that means AOP will need to come last in the bootstrap? Otherwise as now, it will not pick up the loaders for bootstrap deployments deployed after aop.




                    • 7. Re: Module.getModuleForClassLoader()
                      Kabir Khan Master

                       

                      "adrian@jboss.org" wrote:

                      Well actually this should be on the ClassLoading class rather than
                      static methods on the Module?

                      I made the Module method shown in my original post package-protected and static + added a public static method to ClassLoading.
                      https://jira.jboss.org/jira/browse/JBCL-79
                      http://fisheye.jboss.com/changelog/JBossAS/projects/jboss-cl/trunk?cs=83347



                      • 8. Re: Module.getModuleForClassLoader()
                        Adrian Brock Master

                         

                        "kabir.khan@jboss.com" wrote:

                        "adrian@jboss.org" wrote:

                        In fact, I think the first part of your post would be better implemented by listing
                        all existing modules at aop initialization?
                        That way you don't depend upon the specific bootstrap implementation.

                        I'm not sure what you mean here? If you mean adding a method returning a map of all loaders and modules, then I think that means AOP will need to come last in the bootstrap? Otherwise as now, it will not pick up the loaders for bootstrap deployments deployed after aop.


                        What is different between that and using the bootstrap if you are asking the question
                        part way through the bootstrap process?

                        Maybe a better mechanism would be to use the in/uncallback to be notified of the Modules
                        as they are constructed/destroyed. That is in fact how they get registered with
                        the ClassLoading anyway.

                        from bootstrap/classloader.xml
                         <bean name="ClassLoading" class="org.jboss.classloading.spi.dependency.ClassLoading">
                         <classloader><null/></classloader>
                         <incallback method="addModule" state="Configured"/>
                         <uncallback method="removeModule" state="Configured"/>
                         </bean>
                        


                        Although you would want them at "Installed" when they are actually usuable
                        rather than "Configured".

                        • 9. Re: Module.getModuleForClassLoader()
                          Kabir Khan Master

                           

                          "adrian@jboss.org" wrote:

                          What is different between that and using the bootstrap if you are asking the question
                          part way through the bootstrap process?

                          The Bootstrap implementations are invoked AFTER the bootstrap deployments are deployed, so all the classloaders have been created. AbstractServerImpl:
                           public void start() throws IllegalStateException, Exception
                           {
                           ...
                           // deploys conf/bootstrap.xml and conf/bootstrap/*.xml
                           doStart(watch);
                          
                           // TODO Fix the TCL hack used here!
                           ClassLoader cl = Thread.currentThread().getContextClassLoader();
                           try
                           {
                           // Run the bootstraps
                           for (Bootstrap bootstrap : bootstraps)
                           {
                           Thread.currentThread().setContextClassLoader(bootstrap.getClass().getClassLoader());
                           startedBootstraps.add(0, bootstrap);
                           bootstrap.start(this);
                           }
                           }
                           finally
                           {
                           Thread.currentThread().setContextClassLoader(cl);
                           }
                           ...
                           }
                          

                          "adrian@jboss.org" wrote:

                          Maybe a better mechanism would be to use the in/uncallback to be notified of the Modules
                          as they are constructed/destroyed.

                          Why is that better? I'm happy with using bootstrap, as long as the following is ok:
                          - use KernelDeployment.getClassLoader() to get classloader name and look that up in MC
                          - use ClassLoading.getModuleForClassLoader() to get the module corresponding to the classloader rather than the findModule() stuff from my workaround example

                          If I have understood correctly, using a bootstrap I only need to modify aop.xml, making it easy to upgrade older versions of AS. Otherwise I need to modify classloader.xml to add the in/uncallback stuff. Will that work when the classes I need are in the aop classloader that has not been deployed yet? If I add the un/incallback in aop.xml, is that retroactive, i.e. will classloaders added previously in the bootstrap process (from classloader.xml) be added?

                          • 10. Re: Module.getModuleForClassLoader()
                            Kabir Khan Master

                             

                            "kabir.khan@jboss.com" wrote:
                            Will that work when the classes I need are in the aop classloader that has not been deployed yet?

                            An solution for that would be to add the in/uncallback class to jboss.jar.

                            Anyway, I would be happy to continue with Bootstrap, unless there are good reasons not to

                            • 11. Re: Module.getModuleForClassLoader()
                              Ales Justin Master

                               

                              "kabir.khan@jboss.com" wrote:
                              If I add the un/incallback in aop.xml, is that retroactive, i.e. will classloaders added previously in the bootstrap process (from classloader.xml) be added?

                              Yes.

                              See
                              - AbstractController::resolveCallbacks
                              - CallbackItem::ownerCallback
                              - ClassSingleCallbackItem::ownerCallback


                              • 12. Re: Module.getModuleForClassLoader()
                                Adrian Brock Master

                                 

                                "kabir.khan@jboss.com" wrote:
                                "adrian@jboss.org" wrote:

                                What is different between that and using the bootstrap if you are asking the question
                                part way through the bootstrap process?

                                The Bootstrap implementations are invoked AFTER the bootstrap deployments are deployed, so all the classloaders have been created. AbstractServerImpl:
                                 public void start() throws IllegalStateException, Exception
                                 {
                                 ...
                                 // deploys conf/bootstrap.xml and conf/bootstrap/*.xml
                                 doStart(watch);
                                
                                 // TODO Fix the TCL hack used here!
                                 ClassLoader cl = Thread.currentThread().getContextClassLoader();
                                 try
                                 {
                                 // Run the bootstraps
                                 for (Bootstrap bootstrap : bootstraps)
                                 {
                                 Thread.currentThread().setContextClassLoader(bootstrap.getClass().getClassLoader());
                                 startedBootstraps.add(0, bootstrap);
                                 bootstrap.start(this);
                                 }
                                 }
                                 finally
                                 {
                                 Thread.currentThread().setContextClassLoader(cl);
                                 }
                                 ...
                                 }
                                



                                Isn't that actually a bit late? I assume if the one of the bootstraps
                                wants to use aop you would need to know about the Module once it is installed
                                rather than the end of the bootstrap process?
                                i.e. the pojo deployment will try to load a class that needs to be weaved.

                                In practice, once all the boostraps have run, the server is fully deployed,
                                see for example ProfileServiceBootstrap.start()
                                so you would actually be looking at the end of the full server boot wouldn't you?


                                "adrian@jboss.org" wrote:

                                Maybe a better mechanism would be to use the in/uncallback to be notified of the Modules
                                as they are constructed/destroyed.

                                Why is that better? I'm happy with using bootstrap, as long as the following is ok:
                                - use KernelDeployment.getClassLoader() to get classloader name and look that up in MC
                                - use ClassLoading.getModuleForClassLoader() to get the module corresponding to the classloader rather than the findModule() stuff from my workaround example


                                It's better because you are not mixing policy and implementation.

                                But I'm what I'm really saying is that you are relying on one particular
                                configuration/implementation of the bootstrap.

                                Even the fact that the bootstrap is based on pojo deployments could change.
                                I know this is not likely but you are making integration assumptions around
                                implementation details which is always a bad plan.

                                Futher, there could be other pojo deployments that are not part of the bootstrap
                                but still create their own classloader/module.


                                If I have understood correctly, using a bootstrap I only need to modify aop.xml, making it easy to upgrade older versions of AS. Otherwise I need to modify classloader.xml to add the in/uncallback stuff. Will that work when the classes I need are in the aop classloader that has not been deployed yet? If I add the un/incallback in aop.xml, is that retroactive, i.e. will classloaders added previously in the bootstrap process (from classloader.xml) be added?


                                No, you modify your pojo to have add/removeModule() methods
                                and then define the in/uncallback methods in your aop.xml for that bean.

                                You are then using the same mechanism as the ClassLoading uses to be notified
                                of what Modules are created "manually" (rather than through the deployers).
                                So you are unlikely to have an inconsistent view. ;-)

                                This also makes your integration cleaner.
                                You have some bean that just has add/removeModule() as your api.

                                You then tell the MC to make the necessary calls.

                                If somebody really needs to do extra work in certain specifc cases,
                                (e.g. they create a Module programmatically outside either the jboss-beans.xml or the deployers) it is possible for them to tell you about it using that simple api.

                                • 13. Re: Module.getModuleForClassLoader()
                                  Kabir Khan Master

                                  OK, since the in/uncallbacks are retroactive I will experiment with using those. Since I will now have a Module and need the loader, I need an additional static method on ClassLoading/Module:
                                  ClassLoader getClassLoaderForModule()

                                  I'll try to add that a bit later today

                                  1 2 Previous Next