4 Life Cycle Layer - OSGi Core 8 (original) (raw)
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
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:
- Service Provider Configuration model, see Java Service Provider Configuration Support,
- Get it from some configuration and use
Class.forName
, or - Hardcode the 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 becomesACTIVE
.
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 becomeACTIVE
, 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
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 thenewFramework
method provides the configuration properties to the framework. This parameter may benull
, 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, seeBundle 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 theorg.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}"The 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.2A 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 theorg.osgi.framework.executionenvironment property. This property is deprecated; its function is replaced withorg.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 bySystem.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, butSystem.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 = onFirstInitIt 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 theorg.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 | |
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 theINSTALLED
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 theSTARTING
state.start
- Ensure that the framework is in theACTIVE
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 thewaitForStop
method and then restarts the framework to its previous state. The launcher should then take the appropriate action and then call thewaitForStop
method again or reboot the VM. Theupdate
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 theRESOLVED
state via theSTOPPING
state. This will return a Framework STOPPED event from thewaitForStop
method. The Framework's Bundle Context is no longer valid. The framework must be initialized again to get a new, valid Bundle Context. Thestop
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
4.2.4 Initializing the Framework
Before the framework can be used, it must be_initialized_. Initialization is caused by one of theinit
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
orRESOLVED
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 theFramework
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 theBundle.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 aBundleException
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. SeeStart 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 theFramework
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 Activatorstop
method must be wrapped in aBundleException
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 itsstop
method when the framework is shutdown. After calling the stop
method, that particularBundleActivator
object must never be used again. An Extension Bundle Activators that threw an exception duringstart
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. Theorg.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 thestart
method returns, the framework has moved to theACTIVE
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, eitherACTIVE
orSTARTING
. - 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 [14] 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[13] 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 pathMETA-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 [13] 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 methodgetBundleId()
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 BundlegetVersion()
method returns the version. Though the pair is unique, it is possible to install the same bundle multiple times if theorg.osgi.framework.bsnversion
framework launching property is set tomanaged
ormultiple
, 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 theSTARTING
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 thestop
method has not yet returned. - UNINSTALLED - The bundle has been uninstalled. It cannot move into another state.
Figure 4.4 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 agetState()
method for returning a bundle's state.
If this specification uses the term active to describe a state, then this includes the STARTING
andSTOPPING
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:
- installBundle(String) - Installs a bundle from the specified location string (which should be a URL).
- installBundle(String,InputStream) - Installs a bundle from the specified
InputStream
object.
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 theorg.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, theinstallBundle
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 thestart
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 thestart(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 unlessSTART_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 aBundleActivator
instance. It must then call theBundleActivator.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 theBundleActivator
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 thestart(BundleContext)
method throws an exception, the Framework must mark the bundle as stopped and send outSTOPPING
andSTOPPED
events but it must not call the Bundle Activatorstop(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 theACTIVE
state. That is, when the start method has thrown exception, thestop
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 Activatorstart
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
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 FrameworkERROR
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
orSTARTING
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 thestop(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 astop(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 andBundleContext
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 thestop
method.
The Framework must guarantee that if aBundleActivator
. 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:
- update() - This method updates a bundle.
- update(InputStream) - This method updates a bundle from the specified
InputStream
object.
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 haveAdminPermission[<bundle>,LIFECYCLE]
for both the installed bundle as well as the new bundle. The parameters ofAdminPermission
are explained in Admin Permission.
4.4.10 Uninstalling Bundles
The Bundle
interface defines theuninstall()
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 toUNINSTALLED
. 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()
andgetHeaders(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 byjava.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 byjava.util.Locale.getDefault
is used. This makes this method identical to thegetHeaders()
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 byBundle.getHeaders
will return the raw values as specified in the manifest header values without the leading '%' character.
These methods require AdminPermission[<bundle>,
[METADATA](framework.api.html#org.osgi.framework.AdminPermission.METADATA "10.1.3.7 public static final String METADATA = "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)
andgetResources(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), thegetResource
andgetResources
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)
andgetEntryPaths(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
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 returnstrue
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 ofjava.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 }
, thennull
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
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 privateBundleContext
object for the following purposes:
- Installing new bundles into the OSGi environment. See Installing Bundles.
- Interrogating other bundles installed in the OSGi environment. See Getting Bundle Information.
- Obtaining a persistent storage area. See Persistent Storage.
- Retrieving service objects of registered services. See Service References.
- Registering services in the Framework service. See Registering Services.
- Subscribing or unsubscribing to events broadcast by the Framework. See Listeners.
When a bundle is started, the Framework creates aBundleContext
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 theBundleContext
object is related to the security and resource allocation aspects of a bundle.
After the stop(BundleContext)
method has returned, theBundleContext
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 afterstop(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 theBundleContext
object. - getBundles() - Returns an array of the bundles currently installed in the Framework.
- getBundle(long) - Returns the
Bundle
object specified by the unique identifier, ornull
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 haveAdminPermission[<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 aFile
object. This method returns null
if there is no support for persistent storage.
The Framework must automatically provide the bundle withFilePermission[<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 theConstants
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, seeosgi.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 propertyorg.osgi.framework.system.packages ororg.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 thegetType
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 anyBundleListener
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. TheUNRESOLVED
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
andUNRESOLVED
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 aFrameworkEvent.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 ownBundleEvent.INSTALLED
event.
The following three scenarios illustrate this concept.
- 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.
- 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.
- 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
, andFrameworkListener
- 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 qualifyingServiceListener
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 usedoPrivileged
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 adoPrivileged
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 adoPrivileged
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 theEXECUTE
action during a loadClass
method call.
Normal class loading caused by executing Java class code must not require AdminPermission[*,EXECUTE ]
.
4.9 References
4.10 Changes
- References to deprecated launching property
org.osgi.supports.bootclasspath.extension
removed. - References to deprecated FrameworkEvent type
STOPPED_BOOTCLASSPATH_MODIFIED
removed.