This post explains how to track changes in the lifecycle state of OSGi bundles, using two different techniques: an OSGi BundleListener and an Eclipse BundleWatcher.

The OSGi Lifecycle



(source: OSGi Service Platform – Core Specification)

Eclipse runs on top of the OSGi runtime, which manages the bundles (components) that make up an application. At any time, each bundle is has one of these lifecycle states:

INSTALLED: The OSGi runtime knows the bundle is there.

RESOLVED: The bundle is there and all it’s prerequisites (dependencies) are available. The bundle can be started (or has been stopped).

STARTING: The bundle is being started. If it has a BundleActivator class, the BundleActivator.start() method is being executed. When done, the bundle will become ACTIVE. Note: Bundles that can be activated lazily (Bundle-ActivationPolicy: lazy) stay in this state until one of their class files is loaded.

ACTIVE: The bundle is running.

STOPPING: The bundle is being stopped. If it has a BundleActivator class, the BundleActivator.stop() method is being executed. When done, the bundle will become RESOLVED.

UNINSTALLED: The bundle has been removed from the OSGi runtime.

BundleListener

The BundleListener interface provides a convenient way to track lifecycle changes. It provides a bundleChanged(BundleEvent event) method, that is called by the OSGi runtime to communicate lifecycle changes.

To receive notifications, a BundleListener is added a BundleContext object. To stop receiving notifications, a BundleListener is removed from the BundleContent. This is shown in the next code snippet:

You can get this code from my eclipse-examples repository on Github.

To see how this works, we install, start, stop and uninstall a bundle called ‘example.bundle_1.0.0.jar’ using the OSGi Console (-console launch argument). The jar file is located in the example.eclipse.bundlewatcher project. Don’t forget to use three slashes after file:///.

BundleListener restrictions and the BundleWatcher

A BundleListener the can only receive notifications after it has been started. It will miss lifecycle events related to bundles being installed as the OSGi runtime starts. The Equinox OSGi runtime will (typically) install and resolve all bundles that are initially available, before starting any of them. This happens before our BundleListener is started.

To monitor the lifecycle changes that happen during the startup of the OSGi runtime we have to hook our code into the runtime itself. The details depend on the OSGi implementation.

Eclipse Equinox has a BundleWatcher interface, that provides a watchBundle(Bundle bundle, int type) method. The framework will call this method to communicate lifecycle changes.

To install the the BundleWatcher into the startup process, we need to ‘hook’ into the runtime, using an Equinox Adaptor Hook. This requires the following steps:

You will need org.eclipse.osgi as source code in your workspace (this is already part of my git repository). In the same parent directory, create a fragment to org.eclipse.osgi (the example.eclipse.bundlewatcher project). Create a file ‘hookconfigurator.properties’ pointing to your hook configurator class(es).

The hook configurator class must implement the HookConfigurator interface and have a no-argument constructor. The framework will call the addHooks(HookRegistry method), to allow you to install your BundleWatcher (in my example the BundleWatcher and HookConfigurator are implemented in the same class). In your launch configuration, make sure to include the ‘org.eclipse.osgi’ bundle from your workspace (not the Target Platform!).

Your launch configuration must have the following command line argument (when running outside the workspace, you could put this into the eclipse.ini or config.ini files):-Dosgi.framework.extensions=example.eclipse.bundlewatcher Before you deploy, verify your build.properties to make sure hookconfigurator.properties is included in the .jar file.

You can get this code from my eclipse-examples repository on Github.

To see how this works, we again install, start, stop and uninstall a bundle called ‘example.bundle_1.0.0.jar’ using the OSGi Console. The BundleWatcher output is in red. You can see the bundle watcher fragment and bundle listener bundle being installed and started during startup (before the bundle listener receives any events).

If you are curious about the Equinox Adaptor framework, will find the following links useful:

BundleTracker

Since I’ve been asked about it in the comments, I’ve added a BundleTracker example to my github repository.

I think we all agree that, in general, it is better to use a standardized API than a proprietary one. BundleTracker is a great choice for most use cases. However, there are use cases where the additional API is very useful, e.g. when you are provisioning a system. If you are already committed to using Equinox, then BundleWatcher is an interesting alternative.

Have fun,

Elias.