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.
-
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.
-
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.
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.
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 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.
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);
}
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 |
---|---|
|
Set the boot delegation mask, see Parent Delegation. |
|
Allow installation of multiple bundles with the same bundle symbolic name or restrict this. The property can have the following values:
|
|
This property is used to specify what class loader
is used for boot delegation. That is, This property can have the following values:
|
|
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:
The |
|
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:
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
This property is deprecated; its function
is replaced with
|
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. |
|
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
|
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.
|
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:
If specified, and there is a security manager already installed, then a SecurityException must be thrown when the Framework is initialized. For example:
|
|
Specifies the beginning start level of the framework. See Start Level API Specification for more information.
|
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. |
|
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:
For example:
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. |
|
Specifies the capabilities of the environment in
the grammar specified for the
Deployers should use the
|
|
Capabilities defined in this property are added to
the |
|
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. |
|
Packages specified in this property are added to
the
|
|
This property is used to configure trust
repositories for the framework. The value is path of files. The
file paths are separated by the
|
|
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. |
|
Support for framework extensions is mandatory, must
therefore be set to |
|
Support for fragment bundles is mandatory, must
therefore be set to |
|
Support for Require Bundle is mandatory, must
therefore be set to |
All launching properties are available through the getProperty(String) method. See Environment Properties.
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 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.
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
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
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.
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.
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.
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.
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.
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, 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.
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.
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.
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);
...
}
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.
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.
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.
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.
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()
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 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.
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.
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.
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 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.
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.
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.
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.
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.
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.
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.
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 have
AdminPermission[<bundle>,LIFECYCLE]
for both the
installed bundle as well as the new bundle. The parameters of
AdminPermission
are explained in Admin Permission.
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.
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.
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 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 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.
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.
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), the
getResource
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.
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 |
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.
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]
.
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 |
---|---|
|
The Access Control Context for this bundle according to Permissions of a Bundle. |
The Bundle Context for this bundle. |
|
The current Bundle Revision for this bundle, see Bundle Wiring API Specification. |
|
All existing Bundle Revision objects for this bundle, see Bundle Wiring API Specification. |
|
The Bundle Start Level for this bundle, see Start Level API Specification. |
|
The Bundle Wiring for the current Bundle Revision, see Bundle Wiring API Specification. |
|
The Framework object from the launching API if this bundle is the System Bundle, see Frameworks. |
|
The Framework Start Level if this is the System Bundle, see Start Level API Specification. |
|
The Framework Wiring if this bundle is the System Bundle. See Bundle Wiring API Specification. |
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:
-
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 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.
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 have
AdminPermission[<bundle>,METADATA]
.
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.
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.
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.
-
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. |
|
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 |
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.
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 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.
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.
-
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.
-
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.
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.
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 |
|
RESOURCE |
Bundle resource/entry URL creation |
CLASS |
|
LIFECYCLE |
|
EXECUTE |
|
LISTENER |
|
EXTENSIONLIFECYLE |
|
RESOLVE |
|
STARTLEVEL |
|
CONTEXT |
|
WEAVE |
|
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.
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 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.
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 ]
.
[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
[5]Java Security Architecturehttps://docs.oracle.com/javase/8/docs/technotes/guides/security/spec/security-spec.doc.html
[6]Java Package Versioning Specificationhttps://docs.oracle.com/javase/8/docs/technotes/guides/versioning/index.html
[7]Codes for the Representation of
Names of LanguagesISO 639, International Standards
Organization
https://lcweb.loc.gov/standards/iso639-2/langhome.html
[9]W3C EBNFhttps://www.w3c.org/TR/REC-xml#sec-notation
[10]Interval Notationhttps://en.wikipedia.org/wiki/Interval_(mathematics)#Notations_for_intervals
[11]OSGi Reference Nameshttps://docs.osgi.org/reference/
[12]Java Service Provider Configurationhttps://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html#Service_Provider
[13]IETF RFC 1422 A Universally Unique IDentifier (UUID) URN Namespacehttps://www.ietf.org/rfc/rfc4122.txt