Lazy Start

Please send any comments on this page to osgi-dev.

Overview

This design defines a mechanism for activating bundles upon the first class load from them. This allows a system to activate bundles lazily the first time they are needed. Using this model, the Framework can be started with as few active bundles as possible and only activate other bundles on demand as classes are loaded from them.

Terminology

The following terms are defined:

Lazy Activation

Lazy activation is a life cycle policy that mandates a bundle MUST be activated upon the first successful request to load a class from that bundle. Sometimes this is referred to as auto starting because the bundle is automatically activated upon first class load. This design will always use the term lazy instead of auto because auto starting can imply that a bundle is always automatically started every time the framework is launched.

Lazy Activation Bundle

lazy activation bundle is a bundle that has declared the lazy activation life cycle policy.

Local Class Space

local class space is all classes contained in a bundle�s classpath, including classes contained in the classpaths of attached fragment bundles.

Trigger Class

For the purpose of this design, a trigger class is the first class load request that initiates a set of lazy activations. No bundle will be lazily activated until after the trigger class has been successfully defined by its bundle’s classloader.

Problem Description

The Life Cycle Layer provides an API to control the life cycle operations on bundles. This layer gives management agents the ability to install, uninstall, update, start and stop a bundle. In a typical environment a management agent will start every bundle in the framework that it thinks will be needed while the framework is running. Most bundles need to be activated for the following reasons.

  • Run some initialization code (open a port, start a thread etc.)
  • Obtain the BundleContext to participate in the service layer or register listeners with the Framework.
  • To load native code

In a Framework where 1000s of bundles are installed it is not reasonable to activate every bundle upon framework launch. In a user driven application it is not possible for a management agent to know what bundles should be activated ahead of time. For example, when a user selects a menu item in a GUI, it could start a feature of the application. This feature could be implemented by a bundle that should be activated once the menu item is selected by the user.

Requirements

  1. Bundles MUST be allowed to specify a lazy activation life cycle policy.
  2. Backwards compatibility MUST be maintained.
  3. There SHOULD NOT be any undesirable side-effects of lazy activating a bundle.
  4. All bundles must be explicitly started via the Bundle.start methods.
  5. The framework must allow the declared activation policy to be overridden.
  6. During the Framework shutdown process; bundles which were activated with the lazy activation policy must not be reactivated as other bundles are stopping.
  7. When a bundle fails to activate using the lazy activation policy then a Framework event of type ERROR should be published and the class load request must succeed.
  8. Once a bundle fails to activate using the lazy activation policy then no further attempts to activate the bundle with the lazy activation policy are made until the framework is restarted.
  9. During the Framework shutdown process; bundles which were activated with the lazy activation policy SHOULD be shutdown in reverse dependency order. This SHOULD help prevent bundles from loading classes from already stopped lazy activation bundles. In the case of bundle cycles the stop order is unspecified.
  10. Lazy activation bundles MUST be able to participate in the service layer before the first class is loaded from the bundle. This requires that the BundleContext for a lazy activation bundle be available to component systems (e.g. Declarative Services, Spring-OSGi, etc.) before the bundle enters the ACTIVE state.
  11. The design of the lazy activation policy MUST consider secure operations with respect to activating a bundle.

Technical Solution

The Lazy Activation Policy

The lazy activation policy activates bundles when the first successful class load is made from a bundle�s local class space. This policy is implemented by the Framework instead of in a management agent because only the Framework knows when the first class load request is being made.

Trigger Class

A trigger class is the first class load which initiates a set of lazy activations. In order to prevent ClassCircularityErrors while loading classes it is important that the trigger class is fully defined before activating any bundle in the set of lazy activations. A bundle must not be activated by a thread while that thread is calling the bundle classloader defineClass method.

Defining a trigger class may cause a set of class loads that spans across multiple bundles some of which have a lazy activation policy. A set of lazy activations must be created to contain of all the lazy activation bundles which defined a class as a result of defining the trigger class.

After the trigger class has been successfully defined then all the bundles in the set must be activated. The activations occur on LIFO order: that is, the last bundle added to the set is activated first, the bundle of the trigger class is activated last.

For example, a system contains three Bundles: X, Y and Z. Bundle X has an interface x.X. Bundle Y has a class y.Y which implements x.X. Bundle Z has a class z.Z which extends y.Y. In this example, a request is made to load class z.Z. Class z.Z is thus the trigger class.

When loading class z.Z the Framework notes that Bundle Z has a lazy activation policy and adds it to the set of bundles that must be activated after the trigger class (z.Z) is defined. When defining z.Z the class y.Y is loaded from Bundle Y. The Framework notes that Bundle Y has a lazy activation policy and adds it to the set of bundles that must be activated after the trigger class (z.Z) is defined. When defining y.Y the class x.X is loaded from Bundle X. The Framework notes that Bundle X has a lazy activation policy and adds it to the set of bundles that must be activated after the trigger class (z.Z) is defined. Finally the class z.Z is successfully defined. Now each bundle on the set is activated in LIFO order. In this case the activation order would be X, Y, Z.

Lazy Activation Bundle Life Cycle

The following table lists the state/action/events in time order for various start and stop scenarios for a bundle. * indicates a change in behavior from R4. In particular, in the normal start failure case, the STOPPING state is entered and the STOPPING and STOPPED events are fired for symmetry with the lazy activation failure case. Also with the new Bundle.getBundleContextmethod, the STOPPING event will advise SynchronousBundleListeners that the context is about to be destroyed.

STATE	                ACTION	                EVENT
----------------------- ----------------------- ---------------------

<Normal start>
RESOLVED		
	                =>Bundle.start()	
                        context created
STARTING		
		                                STARTING
	                =>BundleActivator.start()	
                        <=BundleActivator.start()	
ACTIVE		
		                                STARTED
	                <=Bundle.start()	


<Normal stop>		
ACTIVE		
	                =>Bundle.stop()	
STOPPING		
		                                STOPPING
	                =>BundleActivator.stop()	
	                <=BundleActivator.stop()	
                        context destroyed
RESOLVED		
		                                STOPPED
	                <=Bundle.stop()	


<Normal start fails>
RESOLVED		
	                =>Bundle.start()
                        context created
STARTING		
		                                STARTING
	                =>BundleActivator.start()	
                	<=BundleActivator.start() throws exception	
STOPPING [*]
		                                STOPPING [*]
                        context destroyed
RESOLVED		
		                                STOPPED [*]
	                <=Bundle.start() throws BundleException	


<Normal stop fails>
ACTIVE		
	                =>Bundle.stop()	
STOPPING		
		                                STOPPING
	                =>BundleActivator.stop()	
	                <=BundleActivator.stop() throws exception
                        context destroyed
RESOLVED		
		                                STOPPED
	                <=Bundle.stop()	throws BundleException



<Lazy activation [*]>
RESOLVED		
	                =>Bundle.start(START_ACTIVATION_POLICY) 	
                        context created
STARTING		
		                                LAZY_ACTIVATION [*]
	                <=Bundle.start(START_ACTIVATION_POLICY)	
	                =>Bundle.loadClass	
		                                STARTING
	                =>BundleActivator.start()	
	                <=BudnleActivator.start()	
ACTIVE		
		                                STARTED
	                <=Bundle.loadClass	


<Lazy activation fails [*]>
RESOLVED		
	                =>Bundle.start(START_ACTIVATION_POLICY)
                        context created
STARTING		
		                                LAZY_ACTIVATION [*]
	                <=Bundle.start(START_ACTIVATION_POLICY)	
	                =>Bundle.loadClass	
		                                STARTING
	                =>BundleActivator.start()	
	                <= BundleActivator.start() throws exception
STOPPING [*]
		                                STOPPING [*]
                        context destroyed
RESOLVED		
		                                STOPPED [*]
                                                FrameworkEvent.ERROR [*]
	                <=Bundle.loadClass	

Framework Launching

When the Framework launches, the Framework�s start-level is incremented to the initial start-level. For each intermediate start-level, if a bundle to be started declares a lazy activation policy and the bundle was previously started with the start option which indicates the bundle’s declared activation policy should be honored, then the bundle transitions to the STARTING state. Otherwise, the bundle is eagerly activated and transitions to the ACTIVE state.

Framework Shutdown

When the Framework is shutdown the Framework�s start-level is decremented to zero. For each start-level the framework implementation can select an appropriate ordering for stopping the bundles in the start-level. This may include stopping bundles in reverse dependency order such that all bundles which depend on a given bundle are shutdown before the given bundle. In case of dependency cycles, the bundles shutdown order would be unspecified. This helps prevent class load requests from lazy activation bundles that have been stopped during the shutdown process.

Bundle Start Option

A new start option is defined which must be specified to tell the framework that the bundle’s declared activation policy must be used.

	/**
	 * The bundle start operation must activate the bundle according to the
	 * bundle's declared
	 * {@link Constants#BUNDLE_ACTIVATIONPOLICY activation policy}.
	 * 
	 * <p>
	 * This bit may be set when calling {@link #start(int)} to notify the
	 * framework that the bundle must be activated using the bundle's declared
	 * activation policy.
	 * 
	 * @since 1.4
	 * @see Constants#BUNDLE_ACTIVATIONPOLICY
	 * @see #start(int)
	 */
	public static final int	START_ACTIVATION_POLICY	= 0x00000002;

If the bundle is started without the START_TRANSIENT start option, then the presence of the START_ACTIVATION_POLICY option is persistently recorded so that when the bundle is restarted during a framework launch or start level change, the value of the option will be used.

A bundle started without the START_ACTIVATION_POLICY option will always be eagerly activated.

The Bundle-ActivationPolicy Header

The Bundle-ActivationPolicy header is introduced to allow a bundle to specify a bundle start policy.

Bundle-ActivationPolicy ::= policy-type (';' directive)*
policy-type ::= token

The only defined policy type is lazy.

The lazy activation policy has the following defined directives:

  • include � A comma-separated list of package names that require the lazy activation policy. Note that the use of a comma in the value requires it to be enclosed in double quotes. If not specified then all packages require the lazy activation policy.
  • exclude � A comma-separated list of package names that do not use the lazy activation policy. Note that the use of a comma in the value requires it to be enclosed in double quotes. If not specified then all packages require the lazy activation policy.

Security

No additional security support is required. However, the following is noted.

Bundle.loadClass

The Bundle.loadClass method may result in activating a bundle. The action AdminPermission.CLASS will allow the activation of lazy activation bundles when Bundle.loadClass is called.

Bundle ClassLoaders

During the execution of java code additional classes get loaded, this will result in bundles being activated. Loading classes while executing java code must not require a bundle to have the AdminPermission.EXECUTE action.