4 Life Cycle Layer

4.1 Introduction

The Life Cycle Layer provides an API to control the security and life cycle operations of bundles. The layer is based on the module and security layer.

4.1.1 Essentials

  • Complete - The Life Cycle layer must implement an API that fully covers the installation, starting, stopping, updating, uninstallation, and monitoring of bundles.

  • Reflective - The API must provide full insight into the actual state of the Framework.

  • Secure - It must be possible to use the API in a secure environment using fine-grained permissions. However, security must be optional.

  • Manageable - It must be possible to manage a OSGi framework remotely.

  • Launching - It must be able to launch an implementation of a framework in a standardized way.

4.1.2 Entities

  • Bundle - Represents an installed bundle in the Framework.

  • Bundle Context - A bundle's execution context within the Framework. The Framework passes this to a Bundle Activator when a bundle is started or stopped.

  • Bundle Activator - An interface implemented by a class in a bundle that is used to start and stop that bundle.

  • Bundle Event - An event that signals a life cycle operation on a bundle. This event is received via a (Synchronous) Bundle Listener.

  • Framework Event - An event that signals an error or Framework state change. The event is received via a Framework Listener.

  • Bundle Listener - A listener to Bundle Events.

  • Synchronous Bundle Listener - A listener to synchronously delivered Bundle Events.

  • Framework Listener - A listener to Framework events.

  • Bundle Exception - An Exception thrown when Framework operations fail.

  • System Bundle - A bundle that represents the Framework.

  • Framework - An interface implemented by an object that represents the actual framework. It allows external management of a Framework.

  • Framework Factory - An interface implemented by Framework providers that allows the creation of a framework object.

Figure 4.1 Class diagram org.osgi.framework Life Cycle Layer

Class diagram org.osgi.framework Life Cycle Layer

4.2 Frameworks

This section outlines how a launcher can launch a framework implementation and then manage it, regardless of the implementation type of the framework. This allows a launcher to embed an OSGi framework without having to provide code that differs between different implementations.

4.2.1 Launching and Controlling a Framework

Code that wants to use one of the OSGi Framework implementations must provide the chosen framework implementation on the class path, or create a special class loader that loads the code and resources from that implementation. How this is achieved, is outside this specification.

A framework implementation must provide a factory class. A factory class is an indirection to create a framework implementation object. The implementation factory class must implement the FrameworkFactory interface. The launcher can use the following ways to get this class name:

The FrameworkFactory interface has a single method: newFramework(Map). The map provides the sole configuration properties for the framework object. The result of this method is a framework object, this object implements the Framework interface. The Framework interface extends the Bundle interface and adds methods to handle the issues unique to launching a framework. The framework object can be seen as the system bundle, though the framework object and the system bundle do not have to be identical, implementations are allowed to implement them in different objects.

Before the framework object can be used, the launcher must first initialize it by calling the init method. After initialization, the framework object can provide a valid Bundle Context and has registered any framework services, but any installed bundles must be in the INSTALLED state. The launcher can then configure the framework object by installing bundles, interacting with the framework services, or registering launcher services. The launcher can also start bundles, but these bundles will not be started until the framework object becomes ACTIVE.

After the framework object is properly configured, the launcher can start it by calling the start method. The framework object will become ACTIVE, and it will move the startlevel (if present) to the configured start level. This can then resolve and start any installed bundle. After a framework has become ACTIVE, it can be stopped from the framework object, or through the system bundle.

The launcher can wait for a framework object to be stopped with the waitForStop method. This method will block until the framework is completely stopped and return a Framework event indicating the cause of the stop. After the framework object has been shutdown, and the waitForStop method has returned, all installed bundles will be in the INSTALLED state. The same framework object can be re-initialized, and started again, any number of times.

The action diagram in Figure 4.2 shows a typical session. A new framework is created and initialized. The launcher then gets the Bundle Context, installs a bundle and starts the framework. It then gets a service, calls a method and then waits for the framework to stop. The service waits some time and calls stop on the System Bundle. The dotted lines indicate some non-specified interactions that are implementation dependent.

Figure 4.2 Action Diagram for Framework Launching

Action Diagram for Framework Launching

If security is enabled, then the launcher and the framework require All Permission. If All Permission is not available, then the framework must throw a Security Exception.

The following code shows how a framework can be launched.

void launch( String factoryName, File[] bundles) 
            throws Exception {
    Map p = new HashMap();
    p.put( "org.osgi.framework.storage",    
            System.getProperty("user.home")
        +   File.separator+"osgi");

    FrameworkFactory factory = 
        (FrameworkFactory) Class.forName( factoryName )
                                            .newInstance();
    Framework framework = factory.newFramework(p);
    framework.init();

    BundleContext context = framework.getBundleContext();

    for ( File bundle : bundles )
        context.installBundle( bundle.toURL().toString() );
    
    framework.start();
    framework.waitForStop(0);
}

4.2.2 Launching Properties

The Map object given as a parameter to the newFramework method provides the configuration properties to the framework. This parameter may be null, in that case the framework must be started with reasonable defaults for the environment it is started in. For example, the framework should export the JRE packages as system packages and it should store its bundles in an appropriate place. The framework must not look in the System properties for configuration properties, the specified configuration properties are complete.

The configuration properties may contain any implementation specific properties. The properties in Table 4.1 must be supported by all conformant frameworks.

The configuration properties plus any defaults set by the framework and the fixed properties set by the framework all together form the launching properties for the framework.

Table 4.1 Framework Launching Properties

Property Name Description

org.osgi.framework.«

 bootdelegation

Set the boot delegation mask, see Parent Delegation.

org.osgi.framework.«

 bsnversion

Allow installation of multiple bundles with the same bundle symbolic name or restrict this. The property can have the following values:

  • single - A combination of equal bundle symbolic name and equal version is unique in the framework. Installing a second bundle with the same bundle symbolic name and version is an error.

  • multiple - The combination of bundle symbolic name and version is not unique in the framework.

  • managed - (Default) Using a Bundle Collision Hook to filter any non-colliding bundles, see Bundle Hook Service Specification.

org.osgi.framework.«

 bundle.parent

This property is used to specify what class loader is used for boot delegation. That is, java.* and the packages specified on the org.osgi.framework.bootdelegation. All other packages must be accessed through a wire.

This property can have the following values:

  • boot - The boot class loader of the VM. This is the default.

  • app - The application class loader

  • ext - The extension class loader

  • framework - The class loader of the framework

org.osgi.framework.«

 command.execpermission

Specifies an optional OS specific command to set file permissions on a bundle's native code. This is required on some operating systems to use native libraries. For example, on a UNIX style OS you could have the following value:

org.osgi.framework.command.execpermission=«
   "chmod +rx ${abspath}"

The ${abspath} macro will be substituted for the actual file path.

org.osgi.framework.«

 executionenvironment

A comma-separated list of provided execution environments (EE). All methods of each listed EE must be present on the OSGi framework. For example, this property could contain:

CDC-1.1/Foundation-1.1,OSGi/Minimum-1.2

A OSGi framework implementation must provide all the signatures that are defined in the mentioned EEs. Thus, the execution environment for a specific OSGi framework Server must be the combined set of all signatures of all EEs in the org.osgi.framework.executionenvironment property.

This property is deprecated; its function is replaced with org.osgi.framework.system.capabilities[.extra].

org.osgi.framework.language

The language used by the framework for the selection of native code. If not set, the framework must provide a value. See [7] Codes for the Representation of Names of Languages for valid values.

org.osgi.framework.library.«

 extensions

A comma separated list of additional library file extensions that must be used when searching for native code. If not set, then only the library name returned by System.mapLibraryName(String) will be used. This list of extensions is needed for certain operating systems which allow more than one extension for native libraries. For example, the AIX operating system allows library extensions of .a and .so, but System.mapLibraryName(String) will only return names with the .a extension. For example:

org.osgi.framework.library.extensions= a,so,dll
org.osgi.framework.os.name

The name of the operating system as used in the native code clause. If not set, then the framework must provide a default value. Table 4.3 defines a list of operating system names. New operating system names are made available on the OSGi web site, see [11] OSGi Reference Names. Names should be matched case insensitive.

org.osgi.framework.os.version

The version of the operating system as used in the native code clause. If not set, then the framework must provide a default value. If the operating system reported version does not fit the standard version syntax (e.g. 2.4.32-kwt), then the launcher should define this launching property with a valid version value.

org.osgi.framework.processor

The name of the processor as used in the native code clause. If not set, then the framework must provide a value. Table 4.2 defines a list of processor names. New processors are made available on the OSGi web site, see [11] OSGi Reference Names. Names should be matched case insensitive.

org.osgi.framework.security

Specifies the type of security manager the framework must use. If not specified then the framework will not set the VM security manager. The following type is architected:

  • osgi - Enables a security manager that supports all security aspects of the OSGi Core specifications (including postponed conditions).

If specified, and there is a security manager already installed, then a SecurityException must be thrown when the Framework is initialized.

For example:

org.osgi.framework.security = osgi

org.osgi.framework.startlevel.«

 beginning

Specifies the beginning start level of the framework. See Start Level API Specification for more information.

org.osgi.framework.startlevel.beginning = 3
org.osgi.framework.storage

A valid file path in the file system to a directory. If the specified directory does not exist then the framework must create the directory. If the specified path exists, but is not a directory, or if the framework fails to create the storage directory, then the framework initialization must fail with an exception being thrown. The framework is free to use this directory as it sees fit, for example, completely erase all files and directories in it. If this property is not set, the framework must set this property to a reasonable platform default.

org.osgi.framework.storage.«

 clean

Specifies if and when the storage area for the framework should be cleaned. If no value is specified, the framework storage area will not be cleaned. The possible values is:

  • onFirstInit - The framework storage area will be cleaned before the Framework bundle is initialized for the first time. Subsequent inits, starts or updates of the Framework bundle will not result in cleaning the framework storage area.

For example:

org.osgi.framework.storage.clean = onFirstInit

It could seem logical to provide delete on exit and clean at initialization. However, restrictions in common Java VM implementations make it impossible to provide this functionality reliably.

org.osgi.framework.system.«

 capabilities

Specifies the capabilities of the environment in the grammar specified for the Provide-Capability header, see Dependencies. These capabilities must be provided from the system bundle. If this property is not set, the framework must calculate this header based on the environment. It should at least set the following namespaces:

  • osgi.ee

  • osgi.native

Deployers should use the org.osgi.framework.system.capabilities.extra property.

org.osgi.framework.system.«

 capabilities.extra

Capabilities defined in this property are added to the org.osgi.framework.system.capabilities property. The purpose of the extra property is to be set by the deployer. The grammar for this property is identical to the other capabilities property.

org.osgi.framework.system.«

 packages

The packages that must be exported from the System Bundle. If not set, the framework must provide a reasonable default for the current execution environment. See Execution Environment.

org.osgi.framework.system.«

 packages.extra

Packages specified in this property are added to the org.osgi.framework.system.packages property and therefore have the same syntax. This allows the configurator to only define the additional packages and leave the standard execution environment packages to be defined by the framework. For example:

org.osgi.framework.system.packages.extra=«
   org.acme.foo; version=1.2, org.acme.foo.impl

org.osgi.framework.trust.«

 repositories

This property is used to configure trust repositories for the framework. The value is path of files. The file paths are separated by the pathSeparator defined in the File class. Each file path should point to a key store. The Framework must support the JKS type but can support other key store types. The framework will use the key stores as trust repositories to authenticate certificates of trusted signers. The key stores must only be used as read-only trust repositories to access public keys. The keystore must not have a password. For example:

org.osgi.framework.trust.repositories = «
   /var/trust/keystore.jks:~/.cert/certs.jks

org.osgi.framework.«

 windowsystem

Provide the name of the current window system. This can be used by the native code clause, Native Code Algorithm. If not set, the framework should provide a value that depends on the current environment.


Table 4.2 Processor Names

Name Aliases Description
68k   Motorola 68000
AArch64 ARM64 64-bit extension of the ARM architecture
ARM  

Intel Strong ARM. Deprecated because it does not specify the endianness. See the following two rows.

arm_le   Intel Strong ARM Little Endian mode
arm_be   Intel String ARM Big Endian mode
Alpha   Compaq (ex DEC)
ia64n   Hewlett Packard 32 bit
ia64w   Hewlett Packard 64 bit mode
Ignite psc1k PTSC
Mips   SGI
PArisc   Hewlett Packard
PowerPC power ppc Motorola/IBM Power PC
PowerPC-64 ppc64 IBM Power PC 64-bit Big Endian mode
PowerPC-64-LE ppc64le IBM Power PC 64-bit Little Endian mode
Sh4   Hitachi
Sparc   Sun Microsystems
Sparcv9   Sun Microsystems
S390   IBM Mainframe 31 bit
S390x   IBM Mainframe 64-bit
V850E   NEC V850E
x86 pentium i386 i486 i586 i686 Intel & AMD 32 bit
x86-64 amd64 em64t x86_64 AMD/Intel 64 bit x86 architecture

Table 4.3 Operating System Names

Name Aliases Description
AIX  

IBM

DigitalUnix  

Compaq

Embos  

Segger Embedded Software Solutions

Epoc32 SymbianOS

Symbian OS

FreeBSD  

Free BSD

HPUX hp-ux

Hewlett Packard

IRIX  

Silicon Graphics

Linux  

Open source

MacOS "Mac OS"

Apple

MacOSX "Mac OS X"

Apple

NetBSD  

Open source

Netware  

Novell

OpenBSD  

Open source

OS2 OS/2

IBM

QNX procnto

QNX

Solaris SunOS

Sun Microsystems

VxWorks  

WindRiver Systems

Windows95 Win95 "Windows 95" Win32

Microsoft

Windows98 Win98 "Windows 98" Win32

Microsoft

WindowsNT WinNT "Windows NT" "Windows NT (unknown)" Win32

Microsoft

WindowsCE WinCE "Windows CE"

Microsoft

Windows2000 Win2000 "Windows 2000" Win32

Microsoft

Windows2003 Win2003 "Windows 2003" Win32 "Windows Server 2003"

Microsoft

WindowsXP WinXP "Windows XP" Win32

Microsoft

WindowsVista WinVista "Windows Vista" Win32

Microsoft

Windows7 Win7 "Windows 7" Win32

Microsoft

Windows8 Win8 "Windows 8" "Windows 8.1" "Windows 8.2" "Windows 8.3" Win32

Microsoft

Windows10 Win10 "Windows 10" Win32

Microsoft

WindowsServer2008 "Windows Server 2008" "Windows 2008" Windows2008 Win2008 Win32

Microsoft

WindowsServer2008R2 "Windows Server 2008 R2" "Windows 2008 R2" Windows2008R2 Win2008R2 Win32

Microsoft

WindowsServer2012 "Windows Server 2012" "Windows 2012" Windows2012 Win2012 Win32

Microsoft

WindowsServer2012R2 "Windows Server 2012 R2" "Windows 2012 R2" Windows2012R2 Win2012R2 Win32

Microsoft

WindowsServer2015 "Windows Server 2015" "Windows 2015" Windows2015 Win2015 Win32

Microsoft

WindowsServer2015R2 "Windows Server 2015 R2" "Windows 2015 R2" Windows2015R2 Win2015R2 Win32

Microsoft

WindowsServer2016 "Windows Server 2016" "Windows 2016" Windows2016 Win2016 Win32

Microsoft

z/OS

IBM


The properties in the following table are the fixed properties of the framework. The values of these properties are established by the framework implementation and added to the launching properties. If these properties are set in the configuration properties, the framework must ignore them.

Table 4.4 Fixed Framework Launching Properties

Property name Description
org.osgi.framework.version

The specification version number implemented by the Framework implementation. The specification version number of this specification is 1.10.

org.osgi.framework.vendor

The vendor of the Framework implementation.

org.osgi.framework.uuid

Unique id for the framework instance, see Framework UUID.

org.osgi.supports.«

 framework.extension

Support for framework extensions is mandatory, must therefore be set to true, see Extension Bundles.

org.osgi.supports.«

 framework.fragment

Support for fragment bundles is mandatory, must therefore be set to true, see Fragment Bundles.

org.osgi.supports.«

 framework.requirebundle

Support for Require Bundle is mandatory, must therefore be set to true, see Requiring Bundles.


All launching properties are available through the getProperty(String) method. See Environment Properties.

4.2.3 Life Cycle of a Framework

Once the frameworks is created, it must be in the INSTALLED state. In this state, the framework is not active and there is no valid Bundle Context. From this point on, the framework object can go through its life cycle with the following methods.

  • init - If the framework object is not active, then this method moves the framework object into the STARTING state.

  • start - Ensure that the framework is in the ACTIVE state. This method can be called only on the framework because there are no bundles running yet.

  • update - Stop the framework. This returns the Framework event STOPPED_UPDATE to the waitForStop method and then restarts the framework to its previous state. The launcher should then take the appropriate action and then call the waitForStop method again or reboot the VM. The update method can be called on the framework or on the system bundle. If the framework is not active, this has no effect.

  • stop - Move the framework into the RESOLVED state via the STOPPING state. This will return a Framework STOPPED event from the waitForStop method. The Framework's Bundle Context is no longer valid. The framework must be initialized again to get a new, valid Bundle Context. The stop method can be called on the framework or on the system bundle.

  • uninstall - Must not be called, will throw an Exception when called.

Figure 4.3 on page shows how the previous methods traverse the state diagram.

Figure 4.3 State diagram Framework

State diagram Framework

4.2.4 Initializing the Framework

Before the framework can be used, it must be initialized. Initialization is caused by one of the init methods or implicitly by the start method. An initialized framework is operational, but none of its bundles are active. This is reflected in the STARTING state. As long as the framework is in this state, new bundles can be installed without any installed code interfering. Existing bundles must all be in the INSTALLED or RESOLVED state. In this state, the framework will run at start level 0.

A framework object can be initialized multiple times. After initialization:

  • Event handling is enabled

  • The security manager is configured

  • Start level is set to 0

  • The framework object has a valid Bundle Context

  • Any installed bundle is in the INSTALLED or RESOLVED state

  • Framework services are available

  • The framework state is STARTING

  • Has a valid UUID

  • The system bundle can adapt to any of its defined types

  • All resolved extension bundle activators start methods have been called

4.2.4.1 Start Extension Activators

The Extension Bundle Activator start method is called to inform the framework extension that the Framework is initializing, see Extension Bundle Activator.

During the initialization process a framework must attempt to resolve all installed Framework Extensions. All resolve operations that occur during initialization must be scoped to only include the system bundle and the extension bundles. This is necessary to avoid resolution operations which change the wiring of normal bundles before all of the Extension Bundle Activators have been called.

The last step during Framework initialization is to call the start method of each Extension Bundle Activator declared by resolved framework extensions. While calling Extension Bundle Activator start methods the framework must be in the STARTING state and have a valid bundle context. Any exception thrown by an Extension Bundle Activator start method must be wrapped in a BundleException and broadcast as an ERROR.

4.2.4.2 Init Framework Listeners

The Framework init(FrameworkListener...) method may be called with a list of framework listeners. Any framework events broadcast during the initialization process must be delivered to the specified framework listeners in the order they are specified before returning from the init method. After returning from init, the specified listeners are no longer notified of framework events. This allows a launcher to initialize a Framework with an init framework listener in order to detect errors from framework extension activators.

4.2.5 Starting the Framework

After the framework has been initialized, it can be started with the start method. This start method must be called on the framework object. The start method moves the framework into the ACTIVE state. If the framework was not initialized, it must be initialized first.

In the active state, all installed bundles previously recorded as being started must be started as described in the Bundle.start method. Any exceptions that occur during startup must be wrapped in a BundleException and then published as a Framework ERROR event. Bundles, and their different states, are discussed in The Bundle Object. If the Framework implements the optional Start Level specification, this behavior can be different. See Start Level API Specification. Any bundles that specify an activation policy must be treated according to their activation policy, see Activation Policies.

After the system bundle enters the ACTIVE state, a Framework STARTED event is broadcast.

4.2.6 Stopping a Framework

Shutdown can be initiated by stopping the system bundle, covered in The System Bundle or calling the stop method on the framework object. When the framework is shut down, it first enters the STOPPING state. All ACTIVE bundles are stopped as described in the Bundle.stop method, except that their persistently recorded start state is kept unchanged. Any exceptions that occur during shutdown must be wrapped in a BundleException and then published as a Framework event of type FrameworkEvent.ERROR. If the Framework implements the optional Start Level specification, this behavior can be different. See Start Level API Specification. During the shutdown, bundles with a lazy policy must not be activated even when classes are loaded from them and they are not yet activated.

The framework then moves to start level 0, calls stop on the Extension Bundle Activators (see Stop Extension Activators), stops event handling and releases any resources (like threads, class loaders, etc.) it held. The framework then enters the RESOLVED state and destroys the Bundle Context. The last action is to notify any threads that are waiting in the waitForStop method. The Framework must be re-initialized if it needs to be used again.

After a framework object is stopped and in the resolved state, it can be initialized and started again. Framework implementations must ensure that holding on to a framework object does not consume significant resources.

4.2.6.1 Stop Extension Activators

The Extension Bundle Activator stop method is called to inform the framework extension that the Framework is shutting down, see Extension Bundle Activator. Before disabling event handling during the Framework shutdown process, the framework must call the stop method for each Extension Bundle Activator that was started successfully. While calling Extension Bundle Activator stop methods, the framework must be in the STOPPING state and have a valid bundle context. Any exception thrown by an Extension Bundle Activator stop method must be wrapped in a BundleException and broadcast as an ERROR.

The framework must guarantee that if the start method has executed successfully for an Extension Bundle Activator, that same BundleActivator object must be called on its stop method when the framework is shutdown. After calling the stop method, that particular BundleActivator object must never be used again. An Extension Bundle Activators that threw an exception during start must not be called on shutdown.

4.2.7 Embedding a Framework

The launcher is not running as an OSGi bundle, it is a plain Java application. However, often this launcher needs to communicate with the bundles inside the framework. The launcher can use the Bundle Context of the framework object to get and register services. However, it must ensure that there is class compatibility between its objects and objects from the bundle. A framework will not automatically share packages between the launcher code and the bundles. Packages must be explicitly exported from the parent class loader. The org.osgi.framework.system.packages.extra is specifically designed to hold any application packages that needs to be shared between the OSGi bundles and the application. Packages in that property are added to the system packages of the framework, which are packages exported by the system bundle from its parent loader. Care should be taken to ensure that all these system packages are visible to the class loader that loaded the framework.

The OSGi Framework is running in a multi-threaded environment. After the framework is started, it will start bundles and these bundles will be activated. Activated bundles normally start background threads or react on events from other bundles. That is, after the start method returns, the framework has moved to the ACTIVE state and many bundles can be busy on different threads. At this point, the framework object can be stopped by the launcher through the framework object, or by a bundle through the System Bundle's stop method.

The waitForStop(long) method on the framework object is included to handle any launcher cleanup that is required after the framework has completely stopped. It blocks until the framework has been completely shutdown. It returns one of the following Framework events to indicate the reason for stopping:

  • STOPPED - This framework object has been shutdown. It can be restarted.

  • STOPPED_UPDATE - This Framework object has been updated. The framework will begin to restart. The framework will return to its state before it was updated, either ACTIVE or STARTING.

  • STOPPED_SYSTEM_REFRESHED - This Framework object has been stopped because of a refresh operation on the system bundle and the framework requires a new class loader to be used to restart.

  • ERROR - The Framework encountered an error while shutting down or an error has occurred that forced the framework to shutdown.

  • WAIT_TIMEDOUT - This method has timed out and returned before this Framework has stopped.

4.2.8 Framework UUID

Each framework must have a unique identity every time before the framework is started. This identity is reflected in the framework property:

org.osgi.framework.uuid

The value of this property must reflect a string defined in [13] IETF RFC 1422 A Universally Unique IDentifier (UUID) URN Namespace with the urn:uuid: prefix. For example:

f81d4fae-7dec-11d0-a765-00a0c91e6bf6

The Java UUID class is capable of generating such a UUID. However, as long as the external representation is maintained frameworks are free to create a unique global id in another way.

Setting this property in the configuration properties has no effect, the framework must override it.

4.2.9 Daemon Threads

A Java VM will automatically exit when there are only daemon threads running. This can create the situation where the VM exits when the Framework uses only daemon threads and all threads created by bundles are also daemon threads. A Framework must therefore ensure that the VM does not exit when there are still active bundles. One way to achieve this, is to keep at least one non-daemon thread alive at all times.

4.2.10 Java Service Provider Configuration Support

The Java Service Provider Configuration model, as described in [12] Java Service Provider Configuration, provides a way to obtain the name of the framework factory by reading a resource in the JAR. In this specification, it is assumed that the framework implementation is on the class path. The name is obtained by reading the content of the configuration resource with the path META-INF/services/org.osgi.framework.launch.FrameworkFactory.

For example, if the com.acme.osgi framework has a factory class com.acme.osgi.Factory, then it should have the following resource:

META-INF/services/org.osgi.framework.launch.FrameworkFactory

And the contents should be:

# ACME Impl. for OSGi framework
com.acme.osgi.Factory

In contrast with the [12] Java Service Provider Configuration, there must only be one class name listed in the resource. However, launchers should be aware that the class path could contain multiple resources with the same name.

Java 6 has introduced the java.util.ServiceLoader class that simplifies creating objects through these types of factories. The following code assumes there is a framework implementation JAR on the class path:

ServiceLoader<FrameworkFactory> sl =
    ServiceLoader.load(FrameworkFactory.class);

Iterator<FrameworkFactory> it = sl.iterator();
if ( it.hasNext() ) {
    Framework fw = it.next().newFramework(null);
    ...
}

4.3 Bundles

A bundle represents a JAR file that is executed in an OSGi Framework. The class loading aspects of this concept were specified in the Module Layer. However, the Module Layer does not define how a bundle is installed, updated, and uninstalled. These life cycle operations are defined here.

The installation of a bundle can only be performed by another bundle or through implementation specific means (for example as a command line parameter of the Framework implementation).

A Bundle is started through its Bundle Activator. Its Bundle Activator is identified by the Bundle-Activator manifest header. The given class must implement the BundleActivator interface. This interface has a start and stop method that is used by the bundle programmer to register itself as listener and start any necessary threads. The stop method must clean up and stop any running threads.

Upon the activation of a bundle, it receives a Bundle Context. The Bundle Context interface's methods can roughly be divided in the following categories:

  • Information - Access to information about the rest of the Framework.

  • Life Cycle - The possibility to install other bundles.

  • Service Registry - The service registry is discussed in Service Layer.

4.4 The Bundle Object

For each bundle installed in the OSGi framework, there is an associated Bundle object. The Bundle object for a bundle can be used to manage the bundle's life cycle. This is usually done with a Management Agent, which is also a Bundle.

4.4.1 Bundle Identifiers

A bundle is identified by a number of names that vary in their scope:

  • Bundle identifier - A long that is a Framework assigned unique identifier for the full lifetime of a bundle, even if it is updated or the Framework is restarted. Its purpose is to distinguish bundles in a Framework. Bundle identifiers are assigned in ascending order to bundles when they are installed. The method getBundleId() returns a bundle's identifier.

  • Bundle location - A name assigned by the management agent (Operator) to a bundle during the installation. This string is normally interpreted as a URL to the JAR file but this is not mandatory. Within a particular Framework, a location must be unique. A location string uniquely identifies a bundle and must not change when a bundle is updated. The getLocation() method retrieves the location of a bundle.

  • Bundle Symbolic Name and Bundle Version - A name and version assigned by the developer. The combination of Bundle Version and Bundle Symbolic Name is a globally unique identifier for a bundle. The getSymbolicName() method returns the assigned bundle name. The Bundle getVersion() method returns the version. Though the pair is unique, it is possible to install the same bundle multiple times if the org.osgi.framework.bsnversion framework launching property is set to managed or multiple, see also Bundle Collision Hook.

4.4.2 Bundle State

A bundle can be in one of the following states:

  • INSTALLED - The bundle has been successfully installed.

  • RESOLVED - All Java classes that the bundle needs are available. This state indicates that the bundle is either ready to be started or has stopped.

  • STARTING - The bundle is being started, the BundleActivator.start method will be called, and this method has not yet returned. When the bundle has a lazy activation policy, the bundle will remain in the STARTING state until the bundle is activated. See Activation Policies for more information.

  • ACTIVE - The bundle has been successfully activated and is running; its Bundle Activator start method has been called and returned.

  • STOPPING - The bundle is being stopped. The BundleActivator.stop method has been called but the stop method has not yet returned.

  • UNINSTALLED - The bundle has been uninstalled. It cannot move into another state.

Figure 4.4 State diagram Bundle

State diagram Bundle

When a bundle is installed, it is stored in the persistent storage of the Framework and remains there until it is explicitly uninstalled. Whether a bundle has been started or stopped must be recorded in the persistent storage of the Framework. A bundle that has been persistently recorded as started must be started whenever the Framework starts until the bundle is explicitly stopped. The Start Level API influences the actual starting and stopping of bundles. See Start Level API Specification.

The Bundle interface defines a getState() method for returning a bundle's state.

If this specification uses the term active to describe a state, then this includes the STARTING and STOPPING states.

Bundle states are expressed as a bit-mask though a bundle can only be in one state at any time. The following code sample can be used to determine if a bundle is in the STARTING, ACTIVE, or STOPPING state:

if ((b.getState() & (STARTING | ACTIVE| STOPPING)) != 0)
    doActive()

4.4.3 Installing Bundles

The BundleContext interface, which is given to the Bundle Activator of a bundle, defines the following methods for installing a bundle:

A bundle must be valid before it is installed, otherwise the install must fail. The validity of a bundle is discussed in Bundle Validity.

If the to be installed bundle has a bundle symbolic name and version pair that is already installed in the framework then the installation is only valid when the org.osgi.framework.bsnversion framework launching property is set to multiple or managed. See Bundle Collision Hook for more information.

Every bundle is uniquely identified by its location string. If an installed bundle is using the specified location, the installBundle methods must return the Bundle object for that installed bundle and not install a new bundle.

The Framework must assign a unique bundle identifier that is higher than any previous bundle identifier.

The installation of a bundle in the Framework must be:

  • Persistent - The bundle must remain installed across Framework and Java VM invocations until it is explicitly uninstalled.

  • Atomic - The install method must completely install the bundle or, if the installation fails, the OSGi framework must be left in the same state as it was in before the method was called.

Once a bundle has been installed, a Bundle object is created and all remaining life cycle operations must be performed upon this object. The returned Bundle object can be used to start, stop, update, and uninstall the bundle.

4.4.4 Resolving Bundles

A bundle can enter the RESOLVED state when the Framework has successfully resolved the bundle's dependencies as described in the manifest. These dependencies are described in Resolving Process.

4.4.5 Starting Bundles

A bundle can be started by calling one of the start methods on its Bundle object or the Framework can automatically start the bundle if the bundle is ready and the autostart setting of the bundle indicates that it must be started.

A bundle is ready if following conditions are all met:

  • The bundle can be resolved

  • If the optional Start Level API is used, then the bundle's start level is met.

Once a bundle is started, a bundle must be activated, see Activation, to give control to the bundle so that it can initialize. This activation can take place immediately (eager activation), or upon the first class load from the bundle (lazy activation). A started bundle may need to be automatically started again by the framework after a restart or changes in the start level. The framework therefore maintains a persistent autostart setting for each bundle. This autostart setting can have the following values:

  • Stopped - The bundle should not be started.

  • Started with eager activation - The bundle must be started once it is ready and it must then be eagerly activated.

  • Started with declared activation - The bundle must be started once it is ready and it must then be activated according to its declared activation policy. See Activation Policies.

The Bundle interface defines the start(int) method for starting a bundle and controlling the autostart setting. The start(int) method takes an integer option, the following values have been defined for this option:

  • 0 - Start the bundle with eager activation and set the autostart setting to Started with eager activation. If the bundle was already started with the lazy activation policy and is awaiting activation, then it must be activated immediately.

  • START_TRANSIENT - Identical to 0 in behavior, however, the autostart setting must not be altered. If the bundle can not be started, for example, the bundle is not ready, then a Bundle Exception must be thrown.

  • START_ACTIVATION_POLICY - Start the bundle using the activation policy declared in the manifest's Bundle-ActivationPolicy header and set the autostart setting to Started with declared activation.

  • START_ACTIVATION_POLICY | START_TRANSIENT - Start the bundle with the bundle's declared activation policy but do not alter the autostart setting.

The Framework must attempt to resolve the bundle, if not already resolved, when trying to start the bundle. If the bundle fails to resolve, the start method must throw a BundleException. In this case, the bundle's autostart setting must still be set unless START_TRANSIENT is used.

When the start method returns without an exception, the state of the bundle will either be ACTIVE or STARTING, depending on the declared activation policy and whether it was used. If the start method throws an exception, then the bundle will not be in either of these states and the stop method will not be called for this Bundle Activator instance.

The start() method calls start(0).

The optional Start Level API influences the actual order of starting and stopping of bundles. See Start Level API Specification. Fragment bundles can not be started and must cause a Bundle Exception when there is an attempt to start them.

4.4.6 Activation

A bundle is activated by calling its Bundle Activator object, if one exists. The BundleActivator interface defines methods that the Framework invokes when it starts and stops the bundle.

To inform the OSGi environment of the fully qualified class name serving as its Bundle Activator, a bundle developer must declare a Bundle-Activator manifest header in the bundle's manifest file. The Framework must instantiate a new object of this class and cast it to a BundleActivator instance. It must then call the BundleActivator.start method to start the bundle.

The following is an example of a Bundle-Activator manifest header:

Bundle-Activator: com.acme.Activator

A class acting as a Bundle Activator must implement the BundleActivator interface, be declared public, and have a public default constructor so an instance of it may be created with Class.newInstance.

Supplying a Bundle Activator is optional. For example, a library bundle that only exports a number of packages does not need to define a Bundle Activator. In addition, other mechanism exists to obtain control and get a Bundle Context, like for example the Service Component Runtime.

The BundleActivator interface defines these methods for starting and stopping a bundle:

  • start(BundleContext) - This method can allocate resources that a bundle needs, start threads, register services, and more. If this method does not register any services, the bundle can register services it needs later: for example, in a callback or an external event, as long as it is in the ACTIVE state. If the start(BundleContext) method throws an exception, the Framework must mark the bundle as stopped and send out STOPPING and STOPPED events but it must not call the Bundle Activator stop(BundleContext) method. The start method must therefore be careful to clean up any resources it creates in the start method when it throws an exception.

  • stop(BundleContext) - This method must undo all the actions of the BundleActivator.start(BundleContext) method. However, it is unnecessary to unregister services or Framework listeners, because they must be cleaned up by the Framework anyway. This method is only called when the bundle has reached the ACTIVE state. That is, when the start method has thrown exception, the stop method is never called for the same instance.

A Bundle Activator must be created when a Bundle is started, implying the creation of a class loader. For larger systems, this greedy strategy can significantly increase startup times and unnecessarily increase the memory footprint. Mechanisms such as the Service Component Runtime and activation policies can mitigate these problems.

Fragment bundles must not have a Bundle Activator specified.

4.4.6.1 Activation Policies

The activation of a bundle can also be deferred to a later time from its start using an activation policy. This policy is specified in the Bundle-ActivationPolicy header with the following syntax:

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

The only policy defined is the lazy activation policy. If no Bundle-ActivationPolicy header is specified, the bundle will use eager activation.

4.4.6.2 Lazy Activation Policy

A lazy activation policy indicates that the bundle, once started, must not be activated until it receives the first request to load a class. This request can originate either during normal class loading or via the Bundle loadClass method. Resource loading and a request for a class that is re-directed to another bundle must not trigger the activation. The first request is relative to the bundle class loader, a bundle will not be lazily started if it is stopped and then started again without being refreshed in the mean time.

This change from the default eager activation policy is reflected in the state of the bundle and its events. When a bundle is started using a lazy activation policy, the following steps must be taken:

  • A Bundle Context is created for the bundle.

  • The bundle state is moved to the STARTING state.

  • The LAZY_ACTIVATION event is fired.

  • The system waits for a class load from the bundle to occur.

  • The normal STARTING event is fired.

  • The bundle is activated.

  • The bundle state is moved to ACTIVE.

  • The STARTED event is fired.

If the activation fails because the Bundle Activator start method has thrown an exception, the bundle must be stopped without calling the Bundle Activator stop method. These steps are pictured in a flow chart in Figure 4.5. This flow chart also shows the difference in activation policy of the normal eager activation and the lazy activation.

Figure 4.5 Starting with eager activation versus lazy activation

Starting with eager activation versus lazy activation

The lazy activation policy allows a Framework implementation to defer the creation of the bundle class loader and activation of the bundle until the bundle is first used; potentially saving resources and initialization time during startup.

By default, any class loaded from the bundle can trigger the lazy activation, however, resource loads must not trigger the activation. The lazy activation policy can define which classes cause the activation with the following directives:

  • include - A list of package names that must trigger the activation when a class is loaded from any of these packages. The default is all package names present in the bundle.

  • exclude - A list of package names that must not trigger the activation of the bundle when a class is loaded from any of these packages. The default is no package names.

For example:

Bundle-ActivationPolicy: lazy; «
    include:="com.acme.service.base,com.acme.service.help"

When a class load triggers the lazy activation, the Framework must first define the triggering class. This definition can trigger additional lazy activations. These activations must be deferred until all transitive class loads and defines have finished. Thereafter, the activations must be executed in the reverse order of detection. That is, the last detected activation must be executed first. Only after all deferred activations are finished must the class load that triggered the activation return with the loaded class. If an error occurs during this process, it should be reported as a Framework ERROR event. However, the class load must succeed normally. A bundle that fails its lazy activation should not be activated again until the framework is restarted or the bundle is explicitly started by calling the Bundle start method.

4.4.6.3 Restoring State After Refresh or Update

The refresh operation, see Refreshing, and the update methods can cause other bundles to be stopped. Started bundles can be in the ACTIVE state or waiting to be activated, depending on their activation policy. The following rules must be applied when restoring the state after an update or refresh:

  • An ACTIVE or STARTING bundle must be started transiently after an update or refresh operation to not change its persistent autostart state.

  • If the bundle was in the STARTING state due to lazy activation, the bundle's activation policy should be used when starting the bundle.

4.4.7 Stopping Bundles

The Bundle interface defines the stop(int) method for stopping a bundle. This calls the stop method when the bundle is in the ACTIVE state and sets the bundle's state to RESOLVED. The stop(int) takes an integer option. The following value has been defined for this option:

  • 0 - If the bundle was activated, then deactivate the bundle and sets the autostart setting for this bundle to Stopped.

  • STOP_TRANSIENT - If the bundle was activated, then deactivate the bundle. Does not alter the autostart setting for this bundle.

The stop() method calls stop(0).

The optional Start Level API influences the actual order of starting and stopping of bundles. See Start Level API Specification.

Attempting to stop a Fragment bundle must result in a Bundle Exception.

4.4.8 Deactivation

The BundleActivator interface defines a stop(BundleContext) method, which is invoked by the Framework to stop a bundle. This method must release any resources allocated since activation. All threads associated with the stopping bundle should be stopped immediately. The threaded code may no longer use Framework-related objects (such as services and BundleContext objects) once the stop method returns.

If the stopping bundle had registered any services or Framework listeners during its lifetime, then the Framework must automatically unregister all registered services and Framework listeners when the bundle is stopped. It is therefore unnecessary from the Framework's point of view to unregister any services or Framework listeners in the stop method.

The Framework must guarantee that if a BundleActivator. start method has executed successfully, that same BundleActivator object must be called with its BundleActivator.stop method when the bundle is deactivated. After calling the stop method, that particular BundleActivator object must never be used again.

Packages exported by a stopped bundle continue to be available to other bundles. This continued export implies that other bundles can execute code from a stopped bundle, and the designer of a bundle should assure that this is not harmful. Exporting interfaces only is one way to prevent such unwanted execution when the bundle is not started. Generally, to ensure they cannot be executed, interfaces should not contain executable code.

4.4.9 Updating Bundles

The Bundle interface defines two methods for updating a bundle:

The update process supports migration from one revision of a bundle to a newer revision of the same bundle. The capabilities provided by the new revision must be immediately available to the Framework. If the old bundle revision has an isInUse() bundle wiring then all capabilities provided by the old bundle wiring must remain available for existing bundles and future resolves until the bundle is refreshed, see Refreshing, or the Framework is restarted. Otherwise the capabilities provided by the old revision must be removed.

After the update operation is complete, the framework must attempt to move the bundle to the same state as it was before the operation taking the activation policy into account, without changing the autostart setting. This is described in more detail in Restoring State After Refresh or Update.

An updater of a bundle must have AdminPermission[<bundle>,LIFECYCLE] for both the installed bundle as well as the new bundle. The parameters of AdminPermission are explained in Admin Permission.

4.4.10 Uninstalling Bundles

The Bundle interface defines the uninstall() method for uninstalling a bundle from the Framework. This method causes the Framework to notify other bundles that the bundle is being uninstalled, and sets the bundle's state to UNINSTALLED. To whatever extent possible, the Framework must remove any resources related to the bundle. This method must always uninstall the bundle from the persistent storage of the Framework.

If the uninstalled bundle has one or more revisions with isInUse() bundle wirings then all capabilities provided by the old in use bundle wirings must remain available for existing bundles and future resolves until the bundle is refreshed, see Refreshing, or the Framework is restarted. Otherwise the capabilities provided by the old revision must be removed.

4.4.11 Detecting Bundle Modifications

The Bundle object provides a convenient way to detect modifications in a bundle. The Framework must keep the time that a bundle is modified by any of the life cycle operations or, in the case of multi-release JARs, by changing the version of Java platform being used. See Multi-release JAR. The getLastModified() method will return the last time the bundle was effectively modified. This last modified time must be stored persistently.

The method must return the number of milliseconds since midnight Jan. 1, 1970 UTC with the condition that a modification must always result in a higher value than the previous last modified time of any bundle.

The getLastModified() method is very useful when a bundle is caching resources from another bundle and needs to refresh the cache when the other bundle is effectively modified. A modification in the other bundle can happen while the caching bundle is not active. The last modified time is therefore a convenient way to track modifications in bundles.

4.4.12 Retrieving Manifest Headers

The Bundle interface defines two methods to return manifest header information: getHeaders() and getHeaders(String).

  • getHeaders() - Returns a Dictionary object that contains the bundle's manifest headers and values as key/value pairs. The values returned are localized according to the default locale returned by java.util.Locale.getDefault.

  • getHeaders(String) - Returns a Dictionary object that contains the bundle's manifest headers and values as key/value pairs. The returned values are localized using the specified locale. The locale may take the following values:

    • null - The default locale returned by java.util.Locale.getDefault is used. This makes this method identical to the getHeaders() method.

    • Empty string - The dictionary will contain the raw (unlocalized) manifest headers including any leading '%'.

    • A Specific Locale - The given locale is used to localize the manifest headers.

If the bundle is a multi-release JAR, see Multi-release JAR, then the returned manifest header information must be the supplemented manifest information. That is, the main manifest with the replacement values from a supplemental manifest, if any, for the current Java platform version.

Localization is performed according to the description in Localization. If no translation is found for a specific key, the Dictionary returned by Bundle.getHeaders will return the raw values as specified in the manifest header values without the leading '%' character.

These methods require AdminPermission[<bundle>, METADATA] because some of the manifest header information may be sensitive, such as the packages listed in the Export-Package header. Bundles always have permission to read their own headers.

The getHeaders methods must continue to provide the manifest header information after the bundle enters the UNINSTALLED state. After the bundle has been uninstalled, this method will only return manifest headers that are raw or localized for the default locale at the time the bundle was uninstalled.

A framework implementation must use only the raw (unlocalized) manifest headers when processing manifest headers. Localizations must not influence the operations of the Framework.

4.4.13 Loading Classes

In certain cases, it is necessary to load classes as if they were loaded from inside the bundle. The loadClass(String) method gives access to the bundle class loader. This method can be used to:

  • Load plugins from another bundle

  • Start an application model activator

  • Interact with legacy code

For example, an application model could use this feature to load the initial class from the bundle and start it according to the rules of the application model.

void appStart() {
    Class initializer =  bundle.loadClass(activator);
    if ( initializer != null ) {
      App app = (App) initializer.newInstance();
      app.activate();
   }
}

Loading a class from a bundle can cause it to be activated if the bundle uses a lazy activation policy.

4.4.14 Access to Resources

The resources from a bundle can come from different sources. They can come from the raw JAR file, Fragment bundles, imported packages, or the bundle class path. Different use cases require a different resource search strategy. The Bundle interface provides a number of methods that access resources but use different strategies. The following search strategies are supported:

  • Class Space - The getResource(String) and getResources(String) provide access to resources that is consistent with the class space as described in Overall Search Order. Following the search order can make certain parts of the JAR files inaccessible. These methods require that the bundle is resolved. If the bundle is not resolved, the Framework must attempt to resolve it.

    The search order can hide certain directories of the JAR file. Split packages are taken into account; therefore, resources with the same package names can come from different JARs. If the bundle is unresolved (or cannot be resolved), the getResource and getResources methods must only load resources from the bundle class path. This search strategy should be used by code that wants to access its own resources. Calling either method can cause the creation of a class loader and force the bundle to become resolved.

  • JAR File - The getEntry(String) and getEntryPaths(String) methods provide access to the resources in the bundle's JAR file. No searching is involved, only the raw JAR file is taken into account. The purpose of these methods is to provide low-level access without requiring that the bundle is resolved.

  • Bundle Space - The findEntries(String,String,boolean) is an intermediate form. Useful when configuration or setup information is needed from another bundle. It considers Fragment bundles but it must never create a class loader or use the bundle class path. The method provides access to all directories in the associated JAR files.

For example, consider the following setup:

A: Require-Bundle: D
   Import-Package: q,t
   Export-Package: t
B: Export-Package: q,t
C: Fragment-Host: A
D: Export-Package: s

This setup is depicted in Figure 4.6.

Figure 4.6 Setup for showing the difference between getResource and getEntry

Setup for showing the difference between getResource and getEntry

The following table shows the effect of getting a resource from this setup when bundle A is resolved.

Table 4.5 Differences between getResource, getEntry, and findEntries for resolved bundle A

Resource getResource getEntry findEntries
q B.q null null
p A.p > C.p A.p A.p > C.p
r C.r null C.r
s D.s null null
t B.t A.t A.t

The following table shows the same cases as the previous table but now for an unresolved bundle A.

Table 4.6 Differences between getResource, getEntry, and findEntries for an unresolved bundle A

Resource getResource getEntry findEntries
q null null null
p A.p A.p A.p
r null null null
s null null null
t A.t A.t A.t

4.4.15 Permissions of a Bundle

The Bundle interface defines a method for returning information pertaining to a bundle's permissions: hasPermission(Object). This method returns true if the bundle's Protection Domain has the specified permission, and false if it does not, or if the object specified by the argument is not an instance of java.security.Permission. Fragments also have their own Protection Domain.

The parameter type is Object so that the Framework can be implemented on Java platforms that do not support Java based security.

See The Permission Check for more information about the permission checks.

4.4.16 Access to a Bundle's Bundle Context

Bundles that have been started have a Bundle Context. This object is a capability; it is intended to be used only by the bundle. However, there are a number of cases where bundles must act on behalf of other bundles. For example, the Service Component Runtime registers services on behalf of other bundles. The framework therefore provides access to another bundle's context via the getBundleContext() method. If there is no Bundle Context for that Bundle because the bundle is a fragment bundle or the bundle state is not in { STARTING, ACTIVE, STOPPING }, then null must be returned.

This method is potentially harmful because it allows any bundle to act as any other bundle. In a secure system, the method is protected by requiring AdminPermission[*,CONTEXT].

4.4.17 Adaptations

The adapt(Class) method allows the Bundle to be adapted to different types. The purpose of this method is to provide more specialized access to the Bundle object, access that is not always needed by most clients of the interface. For example, the adapt method can be used to adapt a Bundle object to the current BundleWiring object (if resolved). The adapt method is used as follows:

BundleWiring bw = aBundle.adapt(BundleWiring.class);

The following table shows the minimum list of types that can be used in the adapt method. However, implementations and specifications can extend this list.

Table 4.7 Minimum set of classes that can be adapted from Bundle

Class Description

AccessControlContext

The Access Control Context for this bundle according to Permissions of a Bundle.

BundleContext

The Bundle Context for this bundle.

BundleRevision

The current Bundle Revision for this bundle, see Bundle Wiring API Specification.

BundleRevisions

All existing Bundle Revision objects for this bundle, see Bundle Wiring API Specification.

BundleStartLevel

The Bundle Start Level for this bundle, see Start Level API Specification.

BundleWiring

The Bundle Wiring for the current Bundle Revision, see Bundle Wiring API Specification.

Framework

The Framework object from the launching API if this bundle is the System Bundle, see Frameworks.

FrameworkStartLevel

The Framework Start Level if this is the System Bundle, see Start Level API Specification.

FrameworkWiring

The Framework Wiring if this bundle is the System Bundle. See Bundle Wiring API Specification.


4.5 The Bundle Context

The relationship between the Framework and its installed bundles is realized by the use of BundleContext objects. A BundleContext object represents the execution context of a single bundle within the OSGi framework, and acts as a proxy to the underlying Framework.

A BundleContext object is created by the Framework when a bundle is started. The bundle can use this private BundleContext object for the following purposes:

When a bundle is started, the Framework creates a BundleContext object and provides this object as an argument to the start(BundleContext) method of the bundle's Bundle Activator. Each bundle is provided with its own BundleContext object; these objects should not be passed between bundles, since the BundleContext object is related to the security and resource allocation aspects of a bundle.

After the stop(BundleContext) method has returned, the BundleContext object must no longer be used. Framework implementations must throw an exception if the BundleContext object is used after a bundle is stopped.

The BundleContext object is only valid during the { STARTING, ACTIVE, STOPPING } states of a bundle. However, the BundleContext object becomes invalid after stop(BundleContext) returns (if the bundle has a Bundle Activator). The BundleContext object becomes invalid before disposing of any remaining registered services and releasing any remaining services in use. Since those activities can result in other bundles being called (for example, Service Listeners for UNREGISTERING events and Service Factories for unget operations), those other bundles can observe the stopping bundle in the STOPPING state but with an invalid BundleContext object.

4.5.1 Getting Bundle Information

The BundleContext interface defines methods to retrieve information about bundles installed in the OSGi framework:

  • getBundle() - Returns the single Bundle object associated with the BundleContext object.

  • getBundles() - Returns an array of the bundles currently installed in the Framework.

  • getBundle(long) - Returns the Bundle object specified by the unique identifier, or null if no matching bundle is found.

Bundle access is not restricted; any bundle can enumerate the set of installed bundles. Information that can identify a bundle, however (such as its location, or its header information), is only provided to callers that have AdminPermission[<bundle>,METADATA].

4.5.2 Persistent Storage

The Framework should provide a private persistent storage area for each installed bundle on platforms with some form of file system support.

The BundleContext interface defines access to this storage in terms of the File class, which supports platform-independent definitions of file and directory names.

The BundleContext interface defines a method to access the private persistent storage area: getDataFile(String). This method takes a relative file name as an argument. It translates this file name into an absolute file name in the bundle's persistent storage area. It then returns a File object. This method returns null if there is no support for persistent storage.

The Framework must automatically provide the bundle with FilePermission[<storage area>, READ | WRITE | DELETE] to allow the bundle to read, write, and delete files in that storage area.

If EXECUTE permissions is required, then a relative path name can be used in the File Permission definition. For example, FilePermission[bin/*,EXECUTE] specifies that the sub-directory in the bundle's private data area may contain executables. This only provides execute permission within the Java environment and does not handle the potential underlying operating system issues related to executables.

This special treatment applies only to FilePermission objects assigned to a bundle. Default permissions must not receive this special treatment. A FilePermission for a relative path name assigned via the setDefaultPermission method must be ignored.

4.5.3 Environment Properties

The BundleContext interface defines a method for returning information pertaining to Framework properties: getProperty(String). This method can be used to return the Framework launching properties; see Launching Properties. This method will examine the System properties if the requested property is not available in the launching properties.

4.6 The System Bundle

In addition to normal bundles, the Framework itself is represented as a bundle. The bundle representing the Framework is referred to as the system bundle. Through the system bundle, the Framework may register services that can be used by other bundles. Examples of such a service is the Conditional Permission Admin service.

The system bundle resembles the framework object when a framework is launched, but implementations are not required to use the same object for the framework object and the system bundle. However, both objects must have bundle id 0, same location, and bundle symbolic name.

The system bundle is listed in the set of installed bundles returned by BundleContext.getBundles(), although it differs from other bundles in the following ways:

  • The system bundle is always assigned a bundle identifier of zero (0).

  • The system bundle getLocation method returns the string: "System Bundle", as defined in the Constants interface.

  • The system bundle has a bundle symbolic name that is unique for a specific version. However, the name system.bundle must be recognized as an alias to this implementation-defined name.

  • The system bundle's life cycle cannot be managed like normal bundles. Its life cycle methods must behave as follows:

    • start - Does nothing because the system bundle is already started.

    • stop - Returns immediately and shuts down the Framework on another thread.

    • update - Returns immediately, then stops and restarts the Framework on another thread.

    • uninstall - The Framework must throw a BundleException indicating that the system bundle cannot be uninstalled.

    See Frameworks for more information about the starting and stopping of the Framework.

4.6.1 System Bundle Information

The capabilities of the system bundle are obtained by adapting the system bundle to a BundleWiring as described in Adaptations. This is in preference to parsing the system bundle's headers.

The system bundle's Bundle.getHeaders method returns a Dictionary object with implementation-specific manifest headers. The following headers of this OSGi specification can be returned in this dictionary. Headers not mentioned in this table should not be used.

Table 4.8 Supported headers in the system bundle getHeaders method

Header Type Description
Bundle-ContactAddress optional

Recommended to provide the framework vendor's contact address.

Bundle-Copyright optional

Recommended to provide the framework's copyright information.

Bundle-Description optional

Recommended description of the framework.

Bundle-DocURL optional

Recommended documentation URL pointing to further information about the framework.

Bundle-Icon optional

Recommended pointer to a preferably PNG icon representing this framework.

Bundle-Localization optional

Recommended localization information.

Bundle-License optional

License information about this framework implementation.

Bundle-ManifestVersion mandatory

The maximum version of the manifest version understood by this framework.

Bundle-Name optional

Recommended human readable name of this framework.

Bundle-Required«

 ExecutionEnvironment

mandatory

Mandatory: the list of execution environments supported by this framework. This header is deprecated, see osgi.ee Namespace.

Bundle-SymbolicName mandatory

The implementation name for this framework.

Bundle-Vendor optional

Recommended vendor information

Bundle-Version mandatory

The version of this framework implementation.

Export-Package mandatory

Contains packages that are exported by the Framework like org.osgi.framework but also the packages listed in the framework property org.osgi.framework.system.packages or org.osgi.framework.system.packages.extra.


4.7 Events

The OSGi Framework Life Cycle layer supports the following types of events:

  • BundleEvent - Reports changes in the life cycle of bundles.

  • FrameworkEvent - Reports that the Framework is started, start level has changed, packages have been refreshed, or that an error has been encountered.

The actual event that is reported is available with the getType method. The integer that is returned from this method can be one of the constant names that are described in the class. However, events can, and will be, extended in the future. Unrecognized event types should be ignored.

4.7.1 Listeners

A listener interface is associated with each type of event. The following list describes these listeners.

  • BundleListener and SynchronousBundleListener - Called with an event of type BundleEvent when a bundle's life cycle information has been changed.

    SynchronousBundleListener objects are called synchronously during the processing of the event and must be called before any BundleListener object is called. The following events are sent by the Framework after it has moved to a different state:

    • INSTALLED - Sent after a bundle is installed. The state is now Bundle INSTALLED state.

    • RESOLVED - Sent when the Framework has resolved a bundle. The state is now the Bundle RESOLVED state.

    • LAZY_ACTIVATION - The bundle has specified an activation policy; its activation is deferred to a later point in time. The state is set to the Bundle STARTING state. This is only sent to SynchronousBundleListener objects.

    • STARTING - Sent when the Framework is about to activate a bundle. This is only sent to SynchronousBundleListener objects. The state is now the Bundle STARTING state.

    • STARTED - Sent when the Framework has started a bundle. The state is now the Bundle ACTIVE state.

    • STOPPING - Sent when the Framework is about to stop a bundle or the start method of the Bundle Activator has thrown an exception and the bundle is stopped. This event indicates that the Bundle Context will be destroyed. This event is only sent to SynchronousBundleListener objects.

    • STOPPED - Sent when the Framework has stopped a bundle.

    • UNINSTALLED - Sent when the Framework has uninstalled a bundle

    • UNRESOLVED - Sent when the Framework detects that a bundle becomes unresolved; this could happen when the bundle is refreshed or updated. When a set of bundles are refreshed using the Wiring API then each bundle in the set must have an UNRESOLVED BundleEvent published. The UNRESOLVED BundleEvent must be published after all the bundles in the set have been stopped and, in the case of a synchronous bundle listener, before any of the bundles in the set are re-started. RESOLVED and UNRESOLVED do not have to paired.

    • UPDATED - Sent after a bundle is updated.

  • FrameworkListener - Called with an event of type FrameworkEvent. Framework events are of type:

    • ERROR - Important error that requires the immediate attention of an operator.

    • INFO - General information that is of interest in special situations.

    • PACKAGES_REFRESHED - The Framework has refreshed the packages.

    • STARTED - The Framework has performed all initialization and is running in normal mode.

    • STARTLEVEL_CHANGED - Is sent by the Framework after a new start level has been set and processed.

    • STOPPED - Sent by the Framework because of a stop operation on the system bundle.

    • STOPPED_UPDATE - Sent by the Framework because of an update operation on the system bundle. The Framework will be restarted after this event is fired.

    • WARNING - A warning to the operator that is not crucial but may indicate a potential error situation.

    • WAIT_TIMEDOUT - Returned from the waitForStop method when the Framework did not stop before the given wait time-out expired.

BundleContext interface methods are defined which can be used to add and remove each type of listener.

Events can be asynchronously delivered, unless otherwise stated, meaning that they are not necessarily delivered by the same thread that generated the event. The thread used to call an event listener is not defined.

The Framework must publish a FrameworkEvent.ERROR if a callback to an event listener generates an unchecked exception - except when the callback happens while delivering a FrameworkEvent.ERROR (to prevent an infinite loop).

Synchronous events have the unfortunate effect that, in rare cases, events can be delivered out of order to a listener. For example, a Service Event UNREGISTERING can be delivered before its corresponding Service Event REGISTERED. One pathological case is when a service listener (for example a Service Tracker) unregisters a service that it receives in the REGISTERED event for. If there are listeners queued behind the pathological listener then they see the unregistering before they see the registration.

4.7.2 Delivering Events

If the Framework delivers an event asynchronously, it must:

  • Collect a snapshot of the listener list at the time the event is published (rather than doing so in the future just prior to event delivery), but before the event is delivered, so that listeners do not enter the list after the event happened.

  • Ensure, at the time the snapshot is taken, that listeners on the list still belong to active bundles at the time the event is delivered.

  • It is possible to use more than one thread to deliver events. If this is the case then each handler must receive the events in the same order as the events were posted. This ensures that handlers see events in the expected order.

If the Framework did not capture the current listener list when the event was published, but instead waited until just prior to event delivery, then the following error could occur: a bundle could have started and registered a listener, and then the bundle could see its own BundleEvent.INSTALLED event.

The following three scenarios illustrate this concept.

  1. Scenario one event sequence:

    • Event A is published.

    • Listener 1 is registered.

    • Asynchronous delivery of Event A is attempted.

    Expected Behavior: Listener 1 must not receive Event A, because it was not registered at the time the event was published.

  2. Scenario two event sequence:

    • Listener 2 is registered.

    • Event B is published.

    • Listener 2 is unregistered.

    • Asynchronous delivery of Event B is attempted.

    Expected Behavior: Listener 2 receives Event B, because Listener 2 was registered at the time Event B was published.

  3. Scenario three event sequence:

    • Listener 3 is registered.

    • Event C is published.

    • The bundle that registered Listener 3 is stopped.

    • Asynchronous delivery of Event C is attempted.

    Expected Behavior: Listener 3 must not receive Event C, because its Bundle Context object is invalid.

4.7.3 Synchronization Pitfalls

Generally, a bundle that calls a listener should not hold any Java monitors. This means that neither the Framework nor the originator of a synchronous event should be in a monitor when a callback is initiated.

The purpose of a Java monitor is to protect the update of data structures. This should be a small region of code that does not call any code the effect of which cannot be overseen. Calling the OSGi Framework from synchronized code can cause unexpected side effects. One of these side effects might be deadlock. A deadlock is the situation where two threads are blocked because they are waiting for each other.

Time-outs can be used to break deadlocks, but Java monitors do not have time-outs. Therefore, the code will hang forever until the system is reset (Java has deprecated all methods that can stop a thread). This type of deadlock is prevented by not calling the Framework (or other code that might cause callbacks) in a synchronized block.

If locks are necessary when calling other code, use the Java monitor to create semaphores that can time-out and thus provide an opportunity to escape a deadlocked situation.

4.8 Security

4.8.1 Admin Permission

The Admin Permission is a permission used to grant the right to manage the Framework with the option to restrict this right to a subset of bundles, called targets. For example, an Operator can give a bundle the right to only manage bundles of a signer that has a subject name of ACME:

org.osgi.framework.AdminPermission(
    "(signer=\*, o=ACME, c=us)", ... )

The actions of the Admin Permission are fine-grained. They allow the deployer to assign only the permissions that are necessary for a bundle. For example, an HTTP implementation could be granted access to all resources of all bundles.

org.osgi.framework.AdminPermission("*",
    "resource" )

Code that needs to check Admin Permission must always use the constructor that takes a bundle as parameter: AdminPermission(Bundle,String) with a single action.

For example, the implementation of the loadClass method must check that the caller has access to the class space:

public class BundleImpl implements Bundle{

    Class loadClass(String name) {
        securityManager.checkPermission( 
            new AdminPermission(this,"class") );
            ...
    }
}

The Admin Permission takes a filter as its name. Filter based permissions are described in Filter Based Permissions.

4.8.1.1 Actions

The action parameter of Admin Permission will specify the subset of privileged administrative operations that are allowed by the Framework. The actions that are architected are listed in the following table. Future versions of the specification, as well as additional system services, can add additional actions. The given set should therefore not be assumed to be a closed set.

Table 4.9 Admin Permission actions

Action Used in
METADATA

Bundle.getHeaders

Bundle.getLocation

RESOURCE

Bundle.getResource

Bundle.getResources

Bundle.getEntry

Bundle.getEntryPaths

Bundle.findEntries

Bundle resource/entry URL creation

CLASS

Bundle.loadClass

LIFECYCLE

BundleContext.installBundle

Bundle.update

Bundle.uninstall

EXECUTE

Bundle.start

Bundle.stop

BundleStartLevel.setBundleStartLevel

LISTENER

BundleContext.addBundleListener for SynchronousBundleListener

BundleContext.removeBundleListener for SynchronousBundleListener

EXTENSIONLIFECYLE

BundleContext.installBundle for extension bundles

Bundle.update for extension bundles

Bundle.uninstall for extension bundles

RESOLVE

FrameworkWiring.refreshBundles

FrameworkWiring.resolveBundles

STARTLEVEL

FrameworkStartLevel.setStartLevel

FrameworkStartLevel.setInitialBundleStartLevel

CONTEXT

Bundle.getBundleContext

WEAVE

WovenClass.setBytes

WovenClass.getDynamicImports


The special action "*" will represent all actions.

Each bundle must be given AdminPermission(<bundle identifier>, "resource,metadata,class,context") so that it can access its own resources and context. This is an implicit permission that must be automatically given to all bundles by the Framework.

4.8.2 Privileged Callbacks

The following interfaces define bundle callbacks that are invoked by the Framework:

  • BundleActivator

  • ServiceFactory

  • BundleListener, ServiceListener, and FrameworkListener

  • Framework hook services

When any of these callbacks are invoked by the Framework, the bundle that caused the callback may still be on the stack. For example, when one bundle installs and then starts another bundle, the installer bundle may be on the stack when the BundleActivator.start method of the installed bundle is called. Likewise, when a bundle registers a service object, it may be on the stack when the Framework calls back the serviceChanged method of all qualifying ServiceListener objects.

Whenever any of these bundle callbacks try to access a protected resource or operation, the access control mechanism should consider not only the permissions of the bundle receiving the callback, but also those of the Framework and any other bundles on the stack. This means that in these callbacks, bundle programmers normally would use doPrivileged calls around any methods protected by a permission check (such as getting or registering service objects).

In order to reduce the number of doPrivileged calls by bundle programmers, the Framework must perform a doPrivileged call around any bundle callbacks. The Framework should have java.security.AllPermission. Therefore, a bundle programmer can assume that the bundle is not further restricted except for its own permissions.

Bundle programmers do not need to use doPrivileged calls in their implementations of any callbacks registered with and invoked by the Framework.

For any other callbacks that are registered with a service object and therefore get invoked by the service-providing bundle directly, doPrivileged calls must be used in the callback implementation if the bundle's own privileges are to be exercised. Otherwise, the callback must fail if the bundle that initiated the callback lacks the required permissions.

A framework must never load classes in a doPrivileged region, but must instead use the current stack. This means that static initializers and constructors must not assume that they are privileged. Any privileged code in a static initializer must be guarded with a doPrivileged region in the static initializer. Likewise, a framework must not instantiate a BundleActivator object in a doPrivileged region, but must instead use the current stack. This means that the BundleActivator constructor must not assume that it is privileged.

4.8.3 Lazy Activation

The activation policy, see Activation Policies, can indirectly cause the activation of a bundle. AdminPermission[*,CLASS ] therefore implies the EXECUTE action during a loadClass method call.

Normal class loading caused by executing Java class code must not require AdminPermission[*,EXECUTE ].

4.9 References

[1]The Standard for the Format of ARPA Internet Text MessagesSTD 11, RFC 822, UDEL, August 1982
https://www.ietf.org/rfc/rfc822.txt

[2]The Hypertext Transfer Protocol - HTTP/1.1RFC 2068 DEC, MIT/LCS, UC Irvine, January 1997
https://www.ietf.org/rfc/rfc2068.txt

[3]Java Language Specification: Java SE 8 Editionhttps://docs.oracle.com/javase/specs/jls/se8/html/index.html

[4]A String Representation of LDAP Search FiltersRFC 1960, UMich, 1996
https://www.ietf.org/rfc/rfc1960.txt

[7]Codes for the Representation of Names of LanguagesISO 639, International Standards Organization
https://lcweb.loc.gov/standards/iso639-2/langhome.html

[11]OSGi Reference Nameshttps://docs.osgi.org/reference/

[13]IETF RFC 1422 A Universally Unique IDentifier (UUID) URN Namespacehttps://www.ietf.org/rfc/rfc4122.txt