5 Replies Latest reply on Sep 16, 2009 9:54 AM by thomas.diesler

    Autostart bundles when deployed in JBossAS

    thomas.diesler

      https://jira.jboss.org/jira/browse/JBOSGI-148

      The basic issue is that a bundle deployment when put in

      requiredStage = DeploymentStages.DESCRIBE

      it will only progress to Bundle.INSTALLED, hence the bundle with not get RESOLVED nor STARTED.

      When requiredStage = DeploymentStages.CLASSLOADER or above, the bundle can start when all its dependencies are resolved. The bundle deployment will however fail, if it has unresolved dependencies.

      The desired behaviour is:

      Bundles with unresolved dependencies get INSTALLED without error.
      Bundles with resolved dependencies get STARTED without error.
      A bundle that could only get INSTALLED (but not RESOLVED) gets STARTED when it's dependencies can be RESOLVED.

        • 1. Re: Autostart bundles when deployed in JBossAS
          thomas.diesler

          There is an approach from Ales, which introduces a new state 'Reset' and resets the context to Described when it cannot get resolved.

          http://anonsvn.jboss.org/repos/jbossas/projects/demos/microcontainer/trunk/igloo/src/main/java/org/jboss/demos/bootstrap/igloo/deployers/

          This approach fails however for bundles with self dependencies.

          I also have made an attempt which involves a LifecycleCallbackItem and uses the PackageAdmin in a seperate Thread to resolve and progress bundles

          http://anonsvn.jboss.org/repos/jbossas/projects/jboss-osgi/projects/runtime/microcontainer/trunk/src/main/java/org/jboss/osgi/plugins/deployers/bundle/OSGiBundleResolverDeployer.java

           public void deploy(DeploymentUnit unit, OSGiBundleState bundleState) throws DeploymentException
           {
           bundleState.getBundleManager();
          
           ControllerContext context = unit.getAttachment(ControllerContext.class);
           DependencyInfo di = context.getDependencyInfo();
          
           LifecycleCallbackItem lifecycleCallbackItem = new LifecycleCallback(unit);
           di.addLifecycleCallback(lifecycleCallbackItem);
           }
          
           private class LifecycleCallback implements LifecycleCallbackItem
           {
           private DeploymentUnit unit;
           private PackageAdmin packageAdmin;
           private DeployerClient deployerClient;
          
           public LifecycleCallback(DeploymentUnit unit)
           {
           this.unit = unit;
          
           OSGiBundleState bundleState = unit.getAttachment(OSGiBundleState.class);
           BundleContext sysContext = bundleState.getBundleManager().getSystemContext();
           ServiceReference sref = sysContext.getServiceReference(PackageAdmin.class.getName());
           packageAdmin = (PackageAdmin)sysContext.getService(sref);
          
           deployerClient = unit.getAttachment(MainDeployer.class);
           }
          
           public void uninstall(ControllerContext ctx)
           {
           OSGiBundleState bundleState = unit.getAttachment(OSGiBundleState.class);
           unresolvedBundles.remove(bundleState);
           }
          
           public void install(ControllerContext ctx) throws Exception
           {
           Runnable runnable = new Runnable()
           {
           public void run()
           {
           try
           {
           // [TODO] remove this hack and find a way to trigger
           // PackageAdmin after the context has been deployed
           Thread.sleep(100);
           }
           catch (InterruptedException e)
           {
           // ignore
           }
          
           OSGiBundleState bundleState = unit.getAttachment(OSGiBundleState.class);
          
           // Add the new bundle to the list of unresolved
           unresolvedBundles.add(0, bundleState);
           OSGiBundleState[] unresolved = new OSGiBundleState[unresolvedBundles.size()];
           unresolvedBundles.toArray(unresolved);
          
           // Try to resolve all unresolved bundles
           packageAdmin.resolveBundles(unresolved);
           if (bundleState.getState() != Bundle.RESOLVED)
           log.info("Unresolved: " + bundleState);
          
           for (OSGiBundleState aux : unresolved)
           {
           if (aux.getState() == Bundle.RESOLVED)
           {
           unresolvedBundles.remove(aux);
          
           try
           {
           // When resolved progress to INSTALLED
           String name = aux.getDeploymentUnit().getName();
           deployerClient.change(name, DeploymentStages.INSTALLED);
           }
           catch (DeploymentException ex)
           {
           log.error(ex);
           }
           }
           }
           }
           };
           new Thread(runnable).start();
           }
          
           public ControllerState getWhenRequired()
           {
           return new ControllerState(getStage().getName());
           }
          
           public ControllerState getDependentState()
           {
           return null;
           }
          
           public Object getBean()
           {
           return null;
           }
           }
          


          The separate Thread was necessary because the context is still installing when the PackageAdmin tries to progress to stage CLASSLOADER.

          Conceptually, there are two passes needed for bundle deployment.

          Phase #1: Install bundles (reqstage == DESCRIBE )

          Phase #2: Resolve & Start bundles (reqstage == INSTALLED)

          Perhaps a callback for when the Phase #1 is needed or is there any other way to get rid of that Thread that starts Phase #2?

          Please advise.

          • 2. Re: Autostart bundles when deployed in JBossAS
            thomas.diesler

            To reproduce

            #1 Build the installer

            mvn -Pdistro clean install

            #2 Install MC Framework in jboss-5.2.0 minimal

            #3 Delete default bundles

            rm -rf server/minimal/deploy/osgi

            #4 Start the server

            12:12:55,287 INFO [OSGiBundleManager] JBossOSGi Runtime - Microcontainer
            12:12:55,288 INFO [OSGiBundleManager] 1.0.2-SNAPSHOT
            12:12:55,293 INFO [FrameworkEventsPluginImpl] Bundle STARTING: Bundle{system.bundle:0.0.0}
            12:12:55,335 INFO [FrameworkEventsPluginImpl] Service REGISTERED: Service{id=1 bundle=system.bundle:0.0.0 classes=[org.jboss.osgi.spi.service.MicrocontainerService]}
            12:12:55,400 INFO [FrameworkEventsPluginImpl] Service REGISTERED: Service{id=2 bundle=system.bundle:0.0.0 classes=[org.osgi.service.packageadmin.PackageAdmin]}
            12:12:55,404 INFO [FrameworkEventsPluginImpl] Service REGISTERED: Service{id=3 bundle=system.bundle:0.0.0 classes=[org.osgi.service.startlevel.StartLevel]}
            12:12:55,407 INFO [FrameworkEventsPluginImpl] Bundle STARTED: Bundle{system.bundle:0.0.0}
            12:12:55,409 INFO [FrameworkEventsPluginImpl] Framwork STARTED
            12:12:55,664 INFO [ProfileServiceBootstrap] Loading profile: ProfileKey@3c4c33[domain=default, server=default, name=minimal]
            12:12:55,666 INFO [AbstractServer] Started: JBoss Server[5.2.0.Beta1 (build: SVNTag=JBoss_5_2_0_Beta1 date=200909022330)] in 14s:470ms
            


            #5 Deploy Bundle jbosgi142-bundleA.jar

            12:16:15,779 INFO [FrameworkEventsPluginImpl] Bundle INSTALLED: Bundle{jbosgi142-bundleA:0.0.0}
            12:16:15,938 INFO [OSGiBundleResolverDeployer] Unresolved: Bundle{jbosgi142-bundleA:0.0.0}
            


            #6 Deploy Bundle jbosgi142-bundleX.jar

            12:16:50,849 INFO [FrameworkEventsPluginImpl] Bundle INSTALLED: Bundle{jbosgi142-bundleX:0.0.0}
            12:16:50,968 INFO [FrameworkEventsPluginImpl] Bundle RESOLVED: Bundle{jbosgi142-bundleX:0.0.0}
            12:16:50,973 INFO [FrameworkEventsPluginImpl] Bundle RESOLVED: Bundle{jbosgi142-bundleA:0.0.0}
            12:16:50,975 INFO [FrameworkEventsPluginImpl] Bundle STARTING: Bundle{jbosgi142-bundleX:0.0.0}
            12:16:50,975 INFO [FrameworkEventsPluginImpl] Bundle STARTED: Bundle{jbosgi142-bundleX:0.0.0}
            12:16:50,977 INFO [FrameworkEventsPluginImpl] Bundle STARTING: Bundle{jbosgi142-bundleA:0.0.0}
            12:16:50,988 INFO [FrameworkEventsPluginImpl] Bundle STARTED: Bundle{jbosgi142-bundleA:0.0.0}
            



            This shows the behaviour with the LifecycleCallbackItem approach.

            • 3. Re: Autostart bundles when deployed in JBossAS
              thomas.diesler

              Here is an update to the issue

              I removed the LifecycleCallbackItem and its associated Thread

              Instead I use a wrapper around the Deployers that are associated with the MainDeployer

              http://anonsvn.jboss.org/repos/jbossas/projects/jboss-osgi/projects/runtime/microcontainer/trunk/src/main/java/org/jboss/osgi/plugins/deployers/bundle/OSGiDeployersWrapper.java

              This still relies on implementation detail and I'd like to replace the wrapper with some kind of listener that I can associate with the MainDeployer.

               public OSGiDeployersWrapper(MainDeployer mainDeployer, OSGiBundleManager bundleManager)
               {
               if (bundleManager == null)
               throw new IllegalArgumentException("Null bundleManager");
               if (mainDeployer instanceof MainDeployerImpl == false)
               throw new IllegalStateException("Cannot instrument: " + mainDeployer);
              
               this.mainDeployer = mainDeployer;
               this.bundleManager = bundleManager;
              
               // Swap the deployers implementation
               MainDeployerImpl mainDeployerImpl = (MainDeployerImpl)mainDeployer;
               this.deployers = mainDeployerImpl.getDeployers();
               mainDeployerImpl.setDeployers(this);
               }
              
               public void process(List<DeploymentContext> deploy, List<DeploymentContext> undeploy)
               {
               // Delegate to the original deployers
               deployers.process(deploy, undeploy);
              
               // OSGi bundles resolve phase
               afterDeployersProcess(deploy, undeploy);
               }
              


              • 4. Re: Autostart bundles when deployed in JBossAS

                I'm not really following what this is all about?

                I don't think you should wrap and replace the DeployersImpl, that is very hacky.
                You should just extend it and configure your version as the impl to use.

                But even then, it doesn't look very good.
                e.g. This certainly looks very wrong.
                http://anonsvn.jboss.org/repos/jbossas/projects/demos/microcontainer/trunk/igloo/src/main/java/org/jboss/demos/bootstrap/igloo/deployers/BundleStartStopDeployer.java

                It says anything that has an OSGiBundleState (which is everything -
                an OSGiMetaData attachment is what determines an OSGi deployment)
                should instantly move to INSTALLED at some unknown point in the CLASSLOADER
                stage of deployment - you don't even order after the java.lang.ClassLoader attachment?

                This completely breaks the "width first" behaviour of the deployers.

                If you just want all the bundles started then why not just set the required stage to INSTALLED in the first place? But this is actually not what it is says in the spec.

                If there are missing dependencies for something you want started,
                then you don't want to "after the fact" change the required state to DESCRIBED because then it won't appear in the IncompleteDeploymentException.

                • 5. Re: Autostart bundles when deployed in JBossAS
                  thomas.diesler

                   


                  I don't think you should wrap and replace the DeployersImpl, that is very hacky.
                  You should just extend it and configure your version as the impl to use.


                  In that case I would have to maintain copies of the supported AS configurations

                  http://jbmuc.dyndns.org:8280/hudson/job/jbossosgi-matrix-jbossmc/7/

                  in the installer. The installer would overwrite the AS config, which I like to avoid because it would not work with another project installer that uses that same approach.

                  Could you please comment on this


                  Conceptually, there are two passes needed for bundle deployment.

                  Phase #1: Install bundles (reqstage == DESCRIBE )

                  Phase #2: Resolve & Start bundles (reqstage == INSTALLED)

                  Perhaps a callback for when the Phase #1 is done is needed


                  Here is the issue: https://jira.jboss.org/jira/browse/JBDEPLOY-214