9 Replies Latest reply on Mar 4, 2010 9:07 AM by Adrian Brock

    ClassLoadingAdmin

    Adrian Brock Master
      To mirror what is available in OSGi's PackageAdmin class, I've created a ClassLoadingAdmin interface

      that is implemented by both ClassLoading and Domain.

      https://svn.jboss.org/repos/jbossas/projects/jboss-cl/trunk/classloading/src/main/java/org/jboss/classloading/spi/dependency/ClassLoadingAdmin.java

      along with some supporting classes.

       

      This required tidying up the way dependencies were stored for Modules for a number of reasons.

       

      1) The cleanup of dependsOnMe() had some problems, there was a TODO in the code about it.

      2) When using ShutdownPolicy=GARBAGE_COLLECTION (GC) the dependsOnMe() no longer gets updated on the DependencyInfo

      so it needs to be maintained on the Module.

      3) We need to keep track of dependencies after undeployment for the GC shutdown policy so we can handle

      refreshModules(null) to re-resolve all deployments that have dependencies that are out-of-date.

      4) Some of the queries need to be look at specific types of dependencies, e.g. those exporting a package or importing a module.

       

      The major changes in this are;

      * the remembering of the "resolvedModule" in the RequirementsDependencyItem and maintaining it

      properly, including the dependsOnMe processing.

      * holding a set of "lazyShutdownModules" in the Module class that get cleaned up after calls to refreshModules().

       

      There's probably some other stuff that can get added ClassLoadingAdmin? e.g. those importing a package.

      For now I've just been guided by what is available in OSGi, although I have generalized some of that api.

        • 1. Re: ClassLoadingAdmin
          Ales Justin Master

          Found a potential NPE -- see Module class:

           

             public static boolean resolveModules(Module... modules) throws Exception
             {
                if (modules == null || modules.length == 0)
                   return true;
          
                LifeCycle[] lifeCycles = new LifeCycle[modules.length]; 
                for (int i = 0; i < modules.length; ++i)
                {
                   Module module = modules[i];
                   if (module == null)
                      throw new IllegalArgumentException("Null module");
                   LifeCycle lifeCycle = module.getLifeCycle();
                   if (lifeCycle == null)
                      log.warn(module + " has no lifecycle, don't know how to resolve it.");
                   lifeCycles[i] = lifeCycle; // HERE -- we allow null
                }
          
                lifeCycles[0].resolve(lifeCycles); // NPE #1
                
                for (LifeCycle lifeCycle : lifeCycles)
                {
                   if (lifeCycle.isResolved() == false) // NPE#2
                      return false;
                }
                return true;
             }
          

           

          And the code in #1 and #2 looks a lot the same -- could be made into one?

          • 2. Re: ClassLoadingAdmin
            Adrian Brock Master

            I fixed the NPE by throwing an error.

             

            I could maybe change the LifeCycle.resolve() methods to return a boolean saying whether the resolve actually worked or not?

            • 3. Re: ClassLoadingAdmin
              Thomas Diesler Master

              Eventually we will need a notion of try run for module resolution. The concept of application also needs to be supported - not sure if this can aleady be done by the Module abstraction.

               

              The use case is:

               

              From a gui select the application located at some repository to download/install into the framework.

              An application consists of potentially very many bundles.

              Try run the resolver using the application metadata.

              Only when the application can be resolved in the running framework, do the install.

               

              The worst case, which must be avoided is a partial install that fails and leaves the framework in a state where random bits are installed/resolved that cannot easily been uninstalled. Essentially, the resolve step for a set of bundles must be atomic.

              • 4. Re: ClassLoadingAdmin
                Ales Justin Master

                I could maybe change the LifeCycle.resolve() methods to return a boolean saying whether the resolve actually worked or not?

                If this changes the need to do resolving check twice, sure.

                 

                btw, I find it a bit strange to see lifeCycles[0].resolve(lifeCycles). :-)

                • 5. Re: ClassLoadingAdmin
                  Ales Justin Master

                  From a gui select the application located at some repository to download/install into the framework.

                  An application consists of potentially very many bundles.

                  Try run the resolver using the application metadata.

                  Only when the application can be resolved in the running framework, do the install.

                   

                  The worst case, which must be avoided is a partial install that fails and leaves the framework in a state where random bits are installed/resolved that cannot easily been uninstalled. Essentially, the resolve step for a set of bundles must be atomic.

                  This sounds more like a job for ProfileService.

                  As it's the only one that knows which deployments/repositories exist that could potentially resolve this -- aka dry resolve.

                  MC's mechanism should only know to say true or false if a particular set of ControllerContexts can be resolved.

                   

                  Although I don't see how we could do dry resolve atm != deploy+undeploy if not complete.

                  • 6. Re: ClassLoadingAdmin
                    Adrian Brock Master

                    alesj wrote:

                    btw, I find it a bit strange to see lifeCycles[0].resolve(lifeCycles). :-)

                    That's what gives it the chance to do width first resolution.

                     

                    If you look at the DeploymentLifecycle implementation,

                    it will fallback to doing it one at a time if the lifecycles have mixed implementations

                    since it can't handle that case width first.

                    • 7. Re: ClassLoadingAdmin
                      Adrian Brock Master

                      thomas.diesler@jboss.com wrote:


                      The use case is:

                       

                      From a gui select the application located at some repository to download/install into the framework.

                      An application consists of potentially very many bundles.

                      Try run the resolver using the application metadata.

                      Only when the application can be resolved in the running framework, do the install.

                       

                      The worst case, which must be avoided is a partial install that fails and leaves the framework in a state where random bits are installed/resolved that cannot easily been uninstalled. Essentially, the resolve step for a set of bundles must be atomic.

                      You can already do that.

                       

                      deploy/change(deploymentNames);

                      try

                      {

                         checkComplete(deploymentNames);

                      }

                      catch (IncompleteDeploymentException e)

                      {

                         undeploy/change[back](deploymentNames);

                      }

                       

                      One of the features I added (different to what happens in 4.2.x) is that if a subdeployment ends

                      up in the error state then so does the rest of the application (i.e. top level deployment, subdeployments and components).

                       

                      NOTE: It is still an unimplemented feature in the profile service to be able to "dry run" an install.

                      i.e. you can validate the metadata can be parsed and is complete and check all the dependencies

                      without creating the actual runtime objects.

                      Of course there might still be runtime errors thrown from the objects themselves, which this wouldn't catch.

                      • 8. Re: ClassLoadingAdmin
                        Emanuel Muckenhuber Master

                        adrian@jboss.org wrote:

                         

                        NOTE: It is still an unimplemented feature in the profile service to be able to "dry run" an install.

                        i.e. you can validate the metadata can be parsed and is complete and check all the dependencies

                        without creating the actual runtime objects.

                        Of course there might still be runtime errors thrown from the objects themselves, which this wouldn't catch.

                        You mean doing mainDeployer.change(deployment, PRE_REAL) ?

                        • 9. Re: ClassLoadingAdmin
                          Adrian Brock Master

                          emuckenhuber wrote:

                           


                          adrian@jboss.org wrote:

                           

                          NOTE: It is still an unimplemented feature in the profile service to be able to "dry run" an install.

                          i.e. you can validate the metadata can be parsed and is complete and check all the dependencies

                          without creating the actual runtime objects.

                          Of course there might still be runtime errors thrown from the objects themselves, which this wouldn't catch.

                          You mean doing mainDeployer.change(deployment, PRE_REAL) ?

                          No. I mean having a special copy of the kernel/deployers in the management client that doesn't do any of the callbacks for the real deployments.

                          So it will go through the dependency resolution, but won't invoke constructors, set properties, etc.