OSGi subsystem activation process

Version 3

    This article describes the non-trivial process of starting up the OSGi subsystem in AS7

    Activation Triggers

     

    There are currently four activation triggers

     

    1. Eager activation on server start
    2. Explicit activation through management operation
    3. Activation through Bundle deployment
    4. Activation through BundleContext injection point
    Eager activation on server start

     

    By default the OSGi system is not activated - all services are installed with initial mode ON_DEMAND.

     

    To activation attribute can be set to eagerly activate the subsystem.

     

    <subsystem xmlns="urn:jboss:domain:osgi:1.2" activation="eager">
        <properties>
            <property name="org.osgi.framework.startlevel.beginning">1</property>
        </properties>
        <capabilities>
        ...
        </capabilities>
    </subsystem>
    

     

    As with all other activation triggers, the Framework starts up a few internal services until the system BundleContext, the core services (i.e. PackageAdmin, StartLevel) and the Framework.CREATE service become available. The hirarchy of internal framework services is documented in FrameworkActive service.

     

    Framework startup then progresses to Framework.INIT and further to Framework.ACTIVE. These services correspond to the framework states reached by API mathods Framework.init() and Framework.start() respectively.

     

    Having reified Bundle objects for all installed bundles

     

    A requirement for the Framework to reach INIT is that all persistent bundles must be installed and have reached their respective persistent state.

     

    In the context of AS7 we have two sets of persistent bundles:

     

    1. Configured subsystem capabilites
    2. Bundle deployments from a previous run

     

    These bundles are known as "bootstrap bundles" and "persistent bundles" respectively. We first install, resolve, activate the bootstrap bundles. Then do the same with the persistent bundles. In terms of services it corresponds to this dependency chain (a.k.a. BootstrapPhase services)

     

    Framework.INIT
    +- PersistentBundles.COMPLETE
       +- PersistentBundles.ACTIVATE
          +- PersistentBundles.RESOLVE
             +- PersistentBundles.INSTALL
                +- BootstrapBundles.COMPLETE
                   +- BootstrapBundles.ACTIVATE
                      +- BootstrapBundles.RESOLVE
                         +- BootstrapBundles.INSTALL
    

     

    We model Bundle states with a corresponding services

     

    • INSTALLED
    • RESOLVED
    • ACTIVE

     

    The whole Framework activation process would be easy and straight forward if we could model the bootstrap phase services with dependencies on their respective Bundle services. This however cannot be done because once the Framework is active it is perfectly valid to uninstall any Bundle - this should not cause the Framework to go down. Instead we use service listeners that install the next bootstrap phase service when the respective Bundle services have reached their target state.

     

    In other words the BootstrapBundlesInstall service creates a listener for bootstrap bundle INSTALL services and creates the BootstrapBundlesResolve service when all bootstrap bundles are installed. This process is reapeated for each phase. In the context of AS7, this would first install all capability bundles, then resolve the capabilities, then activate the capabilities. For persistent bundles the process is equivalent and starts once the bootstrap bundles complete.

     

    In case of eager activation on server startup we install the BootstrapBundles.INSTALL and the PersistentBundles.INSTALL service eagerly

     

    if (activation == Activation.EAGER) {
       // Install the bootstrap bundle services
       builder.installIntegrationService(serviceContainer, serviceTarget, new BootstrapBundlesIntegration());
       builder.installIntegrationService(serviceContainer, serviceTarget, new PersistentBundlesIntegration());
       builder.setInitialMode(Mode.ACTIVE);
    } else {
       // Exclude the bootstrap bundle services - see {@link FrameworkActivator}
       builder.addExcludedService(IntegrationService.BOOTSTRAP_BUNDLES_INSTALL);
       builder.addExcludedService(IntegrationService.PERSISTENT_BUNDLES_INSTALL);
       builder.setInitialMode(Mode.LAZY);
    }
    

     

    Explicit activation through management operation

     

    There is a FrameworkActivator singleton that deals with this and all following cases. The ActivateOperationHandler calls FrameworkActivator.activateEagerly() which installs the BootstrapBundles.INSTALL, PersistentBundles.INSTALL services and a service with a dependency on Framework.ACTIVE - all with the same verification handler.

    The intended behaviour is that this operation does not return until the Framework reaches the ACTIVE state.

     

    There is currently no operation to shut down the framework - so this is only done once.

     

    Activation through Bundle deployment

     

    This is the activation method that happens most and also during our test runs.

     

    When a deployment goes through the FrameworkActivateProcessor we first check if it is a valid Bundle deployment. If so we call FrameworkActivator.activate() which also installs the BootstrapBundles.INSTALL and PersistentBundles.INSTALL services, but instead of creating a hard dependency on Framework.ACTIVE we explicitly activate this service by setting its mode. The verification handler is the one attached to the deployment unit.

     

    ServiceContainer serviceContainer = context.getController().getServiceContainer();
    serviceContainer.getRequiredService(Services.FRAMEWORK_ACTIVE).setMode(Mode.ACTIVE);
    

     

    The reason is that in the context of AS7 persistent bundles are handles like any other deployment. At startup the server deploys its persistent deployments which is the super set of the persistent bundles. Therefore in FrameworkActivateProcessor we must also treat the dependencies on the next phase differently

     

    // Setup a dependency on the the next phase. Persistent bundles have a dependency on the bootstrap bundles
    if (deploymentTracker.isComplete()) {
       phaseContext.addDeploymentDependency(Services.FRAMEWORK_ACTIVE, AttachmentKey.create(Object.class));
    } else {
       phaseContext.addDeploymentDependency(MODULE_REGISTRATION_COMPLETE, AttachmentKey.create(Object.class));
       phaseContext.addDeploymentDependency(Services.FRAMEWORK_CREATE, OSGiConstants.SYSTEM_CONTEXT_KEY);
    }
    

     

    Activation through BundleContext injection point

     

    JavaEE deployments may have an injection point like this

     

    @Resource
    BundleContext context;
    

     

    this is detected by the FrameworkActivateProcessor and subsystem activation proceeds equivalent to a bundle deployment.

     

    Known issues

     

    The approach with the service listeners in the bootstrap phase services is inherently problematic because the verification handler may report missing services in between the bootstrap phases. On explicit subsystem actiuvation you may see missing/unsatisfied dependencies which shortly after become available.

     

    16:42:37,763 INFO  [org.jboss.osgi.framework] (MSC service thread 1-3) JBOSGI011006: OSGi Framework - 2.0.0.CR19
    16:42:38,139 INFO  [org.jboss.osgi.framework] (MSC service thread 1-3) JBOSGI011001: Bundle installed: org.apache.felix.log:1.0.0
    16:42:38,140 INFO  [org.jboss.osgi.framework] (MSC service thread 1-4) JBOSGI011001: Bundle installed: jboss-as-osgi-configadmin:7.2.0.Alpha1-SNAPSHOT
    16:42:38,146 INFO  [org.jboss.osgi.framework] (MSC service thread 1-1) JBOSGI011001: Bundle installed: jboss-osgi-logging:1.0.0
    16:42:38,194 INFO  [org.jboss.osgi.framework] (MSC service thread 1-2) JBOSGI011001: Bundle installed: org.apache.felix.configadmin:1.2.8
    16:42:38,421 INFO  [org.jboss.as.controller] (MSC service thread 1-3) JBAS014774: Service status report
    JBAS014775:    New missing/unsatisfied dependencies:
          service jbosgi.integration.BootstrapBundles.COMPLETE (missing) dependents: [service jbosgi.internal.framework.INIT, service jbosgi.integration.PersistentBundles.INSTALL, service jboss.osgi.as.module.registration] 
          service jbosgi.integration.PersistentBundles.COMPLETE (missing) dependents: [service jbosgi.internal.framework.INIT] 
    
    16:42:38,430 INFO  [org.jboss.osgi.framework] (MSC service thread 1-4) JBOSGI011011: Starting bundles for start level: 1
    16:42:38,446 INFO  [org.jboss.osgi.framework] (MSC service thread 1-4) JBOSGI011002: Bundle started: org.apache.felix.log:1.0.0
    16:42:38,488 INFO  [org.jboss.osgi.framework] (MSC service thread 1-4) JBOSGI011002: Bundle started: org.apache.felix.configadmin:1.2.8
    16:42:38,497 INFO  [org.jboss.osgi.framework] (MSC service thread 1-4) JBOSGI011002: Bundle started: jboss-as-osgi-configadmin:7.2.0.Alpha1-SNAPSHOT
    16:42:38,517 INFO  [org.jboss.osgi.framework] (MSC service thread 1-4) JBOSGI011002: Bundle started: jboss-osgi-logging:1.0.0
    16:42:38,529 INFO  [org.jboss.osgi.framework] (MSC service thread 1-4) JBOSGI011000: OSGi Framework started
    16:42:38,539 INFO  [org.jboss.web] (MSC service thread 1-1) JBAS018210: Register web context: /httpservice
    16:42:38,552 INFO  [org.jboss.as.controller] (MSC service thread 1-1) JBAS014774: Service status report
    JBAS014776:    Newly corrected services:
          service jbosgi.integration.BootstrapBundles.COMPLETE (no longer required)
          service jbosgi.integration.PersistentBundles.COMPLETE (no longer required)
    

     

    The web console reports an "unknown error".

     

    More critically, this may also happen on activation through Bundle deployment. In whcih case you may see

     

    JBAS015870: Deploy of deployment "jaxrs-osgi-target" was rolled back with failure message {"
    JBAS014771: Services with missing/unavailable dependencies" => ["jboss.deployment.unit.jaxrs-osgi-target.REGISTER Missing[
    JBAS014861: <one or more transitive dependencies>]","jbosgi.integration.PersistentBundles.INSTALL Missing[JBAS014861: <one or more transitive dependencies>]
    

     

    This issue is tracked by

     

    • [AS7-5320] Intermittent failure in RestEasyIntegrationTestCase

     

    It's a critical issue because it is not limited to a single test case, but may happen with any deployment that activates the OSGi subsytem.

    Ideas for Possible Solutions

     

    One idea is to introduce the notion of a weak service dependency with the following semantic

     

    • serviceA depends on serviceB with DependencyType.WEAK
    • serviceA starts when serviceB has started
    • serviceA stays UP when serviceB gets removed

     

    With such a dependency type we could remove the service listeners from the bootstrap phase services and replace them with weak dependencies on the respective Bundle services.

     

    Another idea would be to modify the ServiceVerificationHandler and/or ContainerStateMonitor such that they can handle the case in which services get installed late from a listener. I have tried an approach where I installed all bootstrap phase services with initial mode NEVER and explicitly activated them from the listerners. As far as I could see it made no difference to this issue. Perhaps an initial mode that indicates the the service will start eventually would help too.