The Open Services Gateway Initiative OSGi is an independent, non-profit corporation working to define and promote open specifications for the delivery of managed services to networked environments, such as homes and automobiles. These specifications define the OSGi Service Platform, which consists of two pieces: the OSGi framework and a set of standard service definitions. The OSGi framework, which sits on top of a Java virtual machine, is the execution environment for services. The OSGi framework was originally conceived to be used inside restricted environments, such as the set-top box.
The OSGi framework
The framework can be divided in two main elements:
a. A services platform: It involves interaction between three main actors, service providers, service requesters and a service registry. A service is described as a Java class or interface, the service interface, along with a variable number of attributes, the service properties. The service registry allows service providers to be discovered through queries formulated in an LDAP syntax. Service providers and requesters are part of an entity called a bundle that is both a logical as well as physical entity.
b. A deployment infrastructure: Physically, a bundle correspond to a delivery and deployment unit that is materialized by a JAR file along with a file that contains information about the bundle, the manifest file. The OSGi framework provides mechanisms to support continuous deployment activities. These deployment activities include installation, removal, update, starting (activation) and stopping (de-activation) of a physical bundle. Once a bundle is installed in the platform, it can be activated if deployment dependencies that are associated to the bundle are fulfilled.
Deployment activities are realized according to a well defined series of states corresponding to the physical bundle life-cycle. The activation or de-activation of a physical bundle results in the creation or destruction of a unique logical bundle, materialized by an instance from a class inside the bundle called a bundle activator. When the instance is created, the execution environment calls an activation method that signals the logical bundle that it is active. When the physical bundle is de-activated, the execution environment calls a de-activation method. When the logical bundle is active, it can publish or discover services and bind with other bundles by accessing the framework's services registry. It can also be notified from changes that occur in the framework by subscribing as an event listener.
We will demonstrate OSGi programming based on the open source Knopflerfish OSGi framework which is easy to install and provides a great desktop GUI. Download the framework from http://www.knopflerfish.org. To start the Knopflerfish Framework, you can now simply double-click on the framework.jar.
Creating your First Bundle in 5 easy steps
1. In Eclipse, create a new Java Project and import framework.jar in the classpath.
2. Create a manifest.mf file in META-INF folder and add the bundle properties like
Bundle-Name, Bundle-SymbolicName, Bundle-Version, Bundle-Description, Bundle-Vendor, Bundle-Activator, Bundle-Category and Import-Package.
Bundle-Activator tells the framework which class is your Activator class, this is a kind of “main”
class for your bundle.
The Import-Package property tells the framework that our bundle needs to have access to all classes contained in the org.osgi.framework package.
3. Create an Ant build file.
4. Create the Activator class by implementing two methods, start(BundleContext bc) and stop(BundleContext bc) of the BundleActivator interface in the implementation package. Next, we create a Thread subclass. Finally, we have to create a new thread while the bundle is started (in the start() method) and we have to stop the thread once the bundle is stopped.
5. Build and install your First Bundle using Knopflerfish. The bundle is automatically activated and you should see a new icon in the upper left window.
Creating your First Service in 5 easy steps
Repeat the above steps for creating a new bundle and then follow the steps below:
1. Update the manifest.mf file by adding an Export-Package property so that later other services will be able to retrieve the service interface and use it.
2. Create the Service Interface in the interface package.
3. Create the Service Implementation in the implementation package.
4. Create an Activator that registers the Service by using registerService() of the BundleContext object in the start(). All registering operations are done via methods in the BundleContext object. This object is the glue between our bundle and the framework.
5. Build and Install the Service Bundle
Using other Services in 4 easy steps
Repeat the above steps for creating a new service and then follow the steps below:
1. Update the manifest.mf File by adding a comma and a new package name to the Import-Package header. We now declare, that our bundle needs to have access to the new package. A framework will always check that this package is available to the bundle before the Activator is started.
2. Retrieve a Service with the help of ServiceReference object from the BundleContext's getServiceReference() method passing the name of the service interface as argument. Once we have a ServiceReference object, we use the getService() method to acquire the service implementation object, cast it to Service and use it.
3. Using a ServiceListener to Dynamically Bind Services by performing the following steps
a. Create a object name filter
b. Using this filter add a ServiceListener by using BundleContext's addServiceListener().
c. Get service references as given in step 2 by using this filter.
d. Loop through all the references to check the ServiceEvent state
if ServiceEventType is Registered then create a new thread of the Service
if ServiceEventType is Modified then stop this thread and create a new thread of the Service
if ServiceEventType is unregistered then stop the thread of the Service
4. Using a ServiceTracker to track Services with the help of ServiceTracker class which monitors services. It is done by creating a implementation class of ServiceTrackerCustomizer consisting of methods addingService(), modifiedService() and removedService() and passing this class object to create an object of ServiceTracker class.