An open foundation for widespread environments
The OSGi (Open Services Gateway Initiative) R4 alliance has come a long way since its inception in March 1999. The objective of the alliance is to provide open specifications in the form of a horizontal platform for the managed delivery of multiple services over wide-area networks to local networks and devices.
The OSGi platform envisions supporting a diverse family of devices and industries, such as consumer electronics, automotive systems, security products, mobile phones, set top boxes and cable/DSL modems, among many others. OSGi concepts come into play when requirements warrant diverse qualities of service in network infrastructures, lifecycle management, long uptimes, high resiliency, and remote management of platforms and services. The OSGi platform would cater to diverse set of stakeholders, such as telecommunications, cable, and utility providers, software developers and vendors, ISPs, gateway operators, and a multitude of other players.
The OSGi framework is executed on a Java™ Runtime Environment (JRE). Together, JRE and OSGi make up the overall OSGi environment. OSGi applications known as bundles extend the OSGi environment by running on top of it (Figure 1).
Figure 1. The OSGi environment
This overview article presents a subset of key OSGi framework concepts that are relevant when developing OSGi platform solutions for IBM WebSphere Application Server V8 using the IBM Rational Application Developer V8.0.3 workbench. An example application is included for your reference to help lay a foundation for understanding these concepts.
Parts and features of the OSGi environment
The OSGi Service Platform features the OSGi framework as its foundation. The OSGi framework provides a general purpose, secure, managed Java framework to host Java service applications, known as bundles. The framework facilitates downloading, installing, deploying, updating, and un-installing OSGi bundles in a dynamic, extensible, and scalable manner. The OSGi framework manages dependencies between bundles and services, registration, and controlled sharing of services between bundles.
The OSGi framework provides a concise and consistent programming model, separates service specification (interface) from service implementation, and helps address scalability challenges. The framework features a service registry into which bundles:
- Register new services.
- Lookup existing services.
- Receive notifications about the state of services.
The service registry capability of the OSGi framework enables bundles to extend their capabilities after deployment and without having to restart the environment, affording bundles with new levels of dynamicity and extensibility.
OSGi bundles are Java applications deployed to the OSGi environment, and can feature services, Java classes, and other resources. Bundles are packaged as JAR files with an associated manifest file to describe the JAR file contents. System bundles represent the framework itself and contain different features than other application bundles.
Management bundles encapsulate the implementation of polices. A management bundle manages the lifecycle of bundles using associated bundle objects. Bundles have unique and persistent identifiers, a bundle location string that uniquely identifies the bundle, and a bundle state that represents the bundle in its lifecycle journey.
A bundle can be in one of these bundle states: INSTALLED, RESOLVED, STARTING, STOPPING, ACTIVE and UNINSTALLED. Bundle context objects encapsulate the relationship between the OSGi framework and installed bundles. Information about bundles can be obtained using bundle context objects.
Manifest files and manifest headers
Manifest files, which are contained in bundle JAR files, describe the contents of JAR files using manifest headers.
The bundle namespace contains fully qualified classes, including the classloader that created the class. The bundle namespace can contain a class created by different classloaders, potentially resulting in multiple instances of the same class. Sharing bundles will result in the sharing object instances of a class or interface loaded by the same mutually agreed upon classloader. Additionally, the classloader sets the ProtectionDomain object for classes (for security definition) loaded from the bundle, and facilitates loading of native class libraries
Bundles can offer to share classes and resources in a package by exporting the package. Bundles can choose not to offer sharing or to import packages exported by other bundles. The OSGi framework ensures visibility of the proper version of a package in order for a bundle to access package resources. A bundle needs to have appropriate permissions to access resources of an imported package.
An OSGi managed environment hosts bundles, which contain service interfaces defining a service's public methods, service objects that implement service interfaces, and a shared service registry. Bundles register and unregister services with the OSGi framework. The framework provides an event mechanism for bundles to receive events of service objects that are registered, unregistered, modified, exported, imported, configured, or released. Services are typically accessed using service reference objects. Services can have properties specified as key/value pairs. Properties can be used by filter objects for querying, comparing, and searching.
The OSGi framework runtime is a very dynamic programming environment into which bundles can be installed, started, stopped, updated, and uninstalled without the framework being recycled. The OSGi framework provides a service registry into which service objects are registered, modified, and unregistered frequently. This makes the contents of the service registry very dynamic. Bundles need to be aware of service registry dynamism in order not to risk using unregistered service objects. The OSGi framework provides a ServiceTracker utility class to make it simple and easy to tracking service registration, modification, and unregistration.
ServiceReference objects are used to access actual services from the OSGi framework. ServiceReference objects can be stored and passed between bundles. These objects help avoid creating dynamic service dependencies between bundles.
This is a special class that implements the Bundle Activator interface by implementing Start and Stop methods to start and stop the bundle. The Start method helps initialize the bundle by registering the services, acquiring and allocating the resources, and so on. The Stop method helps unregister services, de-allocate and finalize resources, and so on.
An activation policy can be eager or lazy. A lazy activation policy makes the bundle move to activated state from a started state only when a class is loaded from the bundle. A normal classloading or loadClass method call on the bundle causes the trigger to transition the state of the bundle from started to activated state. Bundle resource loading does not trigger the state transition. Eager policy activation does not make use of the trigger mechanism. The default policy is to activate the bundle in an eager manner.
Properties are key/value pairs, with keys being String types and values being any type. A key can have multiple values, handled as arrays or vectors. If the value types are types that are recognized by Filter objects, then comparisons and searches can be performed on the value types. Properties are widely used in the context of Service, ServiceReference, and other objects in the OSGi environment.
Blueprint, Blueprint properties, and Blueprint container
Achieving maximum software reuse requires minimal coupling. Minimal coupling can be achieved by separating implementation details from the interface definition. However, implementation logic is still needed through concrete classes for creating and working with actual class object instances, which leads to some necessary coupling. A dependency injection framework solves the problem of creating objects, defining collaborators that the objects need to work with, and wiring the dependencies. In the process, the dependency injection framework facilitates significant improvements to reuse and flexibility. The Blueprint container, derived from the Spring Dynamic Modules project, provides a dependency injection framework for OSGi bundles when OSGi APIs are being used. Specifically, the Blueprint container makes use of annotations specified in OSGi bundles to wire the OSGi application together. You can see this capability in action in the sample OSGi application.
OSGi application example
In the spirit of celebrating the IBM’s centennial anniversary, the sample OSGi application is called IBMCentennialOSGIApp. This simple application proudly returns a celebratory greeting message when invoked from an OSGi client bundle in plain English (or in the (IBM) computer machine friendly languages of binary, octal, and hexadecimal formats). The remainder of this article will describe how to use IBM Rational Application Developer V8.0.3 to complete development of the application and and how to deploy it on IBM WebSphere Application Server V8.0.
The basic packaging of the sample application summarized below:
- CentennialMessageBundle: Celebratory greeting, English format, server side main
- CentennialBinaryBundle: Celebratory greeting, binary format, server side
- CentennialOctalBundle: Celebratory greeting, octal format, server side
- CentennialHexadecimalBundle: Celebratory greeting, hexadecimal format, server side
- CentennialWebBundle: OSGi client bundle
- IBMCentennialOSGIApp: OSGi composite application, client and server side
The OSGi application is structured as described below, with the detailed structure and annotated salient implementation explanations provided.
This bundle contains three Java sources. Activator.java and InitializeCentennialMessageImpl.java sources capture implementation logic, while InitializeCentennialMessage.java source captures interface definition.
Activator.java source implements a ServiceListener interface by implementing serviceChanged(ServiceEvent):void method.
Bundle logic returns a celebratory greeting in plain English format, implementing server side main logic. The client bundle logic connects to this server side bundle first, in a client to server interaction, to retrieve the plain English message using getCentennialMessage():String method. This bundle defines three privately visible, instance variables to keep track of references to StringToBinary, StringToOctal and StringToOctal interface types. The bundle features some setter and getter methods. In addition, the bundle provides one native service with native bean implementation, and three remote references consisting of StringToBinary, StringToOctal and StringToOctal interface types captured in the Blueprint definition. The Blueprint container provides the dependency injection to wire the application together.
The bundle logic connects to each of server side bundles one at a time, in a server to server interaction, to retrieve the binary, octal, and hexadecimal equivalents of the plain English celebratory greeting message using getAllCentennialMessage():void method.
The bundle logic in Listing 1 demonstrates how to invoke server side bundle-to-bundle interactions.
CentennialMessageBundle Activator.java serviceChanged(ServiceEvent):void start(BundleContext):void stop(BundleContext):void InitializeCentennialMessage.java getAllCentennialMessage():void getCentennialMessage():String InitializeCentennialMessageImpl.java private String astrVal StringToBinary s2bBean; StringToOctal s2oBean; StringToHexadecimal s2hBean; getAllCentennialMessage():void getAstrVal():String getCentennialMessage():String getS 2bBean():StringToBinary getS 2hBean():StringToHexadecimal getS 2oBean():StringToOctal init():void setAstrVal(String):void setS2bBean(StringToBinary):void setS2hBean(StringToHexadecimal):void setS2oBean(StringToOctal):void
This bundle contains two Java sources. Activator.java and CentennialServlet.java sources capture implementation logic. This bundle contains Web container support components.
The bundle logic contains a client side invocation logic flow structure with references to remote interfaces, naming lookup, and remote provider invocation calls. The client bundle logic connects to the CentennialMessageBundle server side bundle first, in a client to server interaction, to retrieve the plain English message using getCentennialMessage():String method. The bundle logic connects to each of the server side bundles one at a time, in a client to server interaction, to retrieve the binary, octal, and hexadecimal equivalents of the plain English celebratory greeting message using getBinaryFormat(String):String, getOctalFormat(String):String and getHexadecimalFormat(String):String methods.
The bundle logic in Listing 2 demonstrates how to invoke client to server side bundle-to-bundle interactions.
CentennialWebBundle Activator.java start(BundleContext):void stop(BundleContext):void CentennialServlet.java CentennialServlet() doGet(HttpServletRequest,HttpServletResponse):void doPost(HttpServletRequest,HttpServletResponse):void
CentennialBinaryBundle, CentennialHexadecimalBundle, CentennialOctalBundle
These bundles contains three Java sources each. Activator.java and StringTo<type>Impl.java sources with <type> token taking values of binary, octal, or hexadecimal (as appropriate) to capture implementation logic. StringTo<type>.java sources with <type> token taking values of binary, octal, or hexadecimal (as appropriate) to capture interface definitions.
The bundle logic returns a celebratory greeting in <type> format with <type> token taking values of binary, octal, or hexadecimal, implementing server side logic. Client and server side bundles connect to these bundles to invoke the server side implementation logic. These bundles provide one native service with one native bean implementation for each <type> with <type> token taking values of binary, octal, and hexadecimal formats, respectively.
The bundle logic in Listing 3 demonstrates how to implement provider side implementation logic.
CentennialBinaryBundle Activator.java start(BundleContext):void stop(BundleContext):void StringToBinary.java getBinaryFormat(String):String StringToBinaryImpl.java getBinaryFormat(String):String init():void CentennialOctalBundle Activator.java start(BundleContext):void stop(BundleContext):void StringToOctal.java getOctalFormat(String):String StringToOctalImpl.java getOctalFormat(String):String init():void CentennialHexadecimalBundle Activator.java start(BundleContext):void stop(BundleContext):void StringToHexadecimal.java getHexadecimalFormat(String):String StringToHexadecimalImpl.java getHexadecimalFormat(String):String init():void
This is a composite OSGi application that contains all five of the bundles described above (Listing 4).
IBMCentennialOSGIApp CentennialBinaryBundle 1.0.0 CentennialHexadecimalBundle 1.0.0 CentennialMessageBundle 1.0.0 CentennialOctalBundle 1.0.0 CentennialWebBundle 1.0.0
Figure 2 shows the Enterprise Explorer tab view project contents in Rational Application Developer.
Figure 2. IBMCentennialOSGIApp Enterprise Explorer Tab, Java EE perspective
Figure 3 shows the Rational Application Developer Servers view when your OSGi application is successfully deployed and running.
Figure 3. IBMCentennialOSGIApp Servers view
Figure 4 shows the Services tab view contents under the OSGi category in Rational Application Developer.
Figure 4. IBMCentennialOSGIApp Services Tab, Java EE perspective
Figure 5 shows your OSGi application successfully deployed and running in the WebSphere Application Server V8 runtime.
Figure 5. WebSphere Application Server, Business-level applications
Figure 6 shows your OSGi application assets, as seen when deployed and running successfully in WebSphere Application Server V8.
Figure 6. WebSphere Application Server OSGi assets
To run the sample client application, point your web browser to
(You might need to modify the host name and port number values when you install and deploy the sample application in your environment.)
Figure 7 shows the response flow when the browser client invokes the sample OSGi application successfully.
Figure 7. Browser client, invocation response
Figure 8 shows the response flow when the browser client invokes the application successfully; the Console view is shown for a server to server side bundle logic invocation. This output is not visible to the browser, as this logic is exercised invisible to client (to demonstrate how to perform bundle to bundle server side method invocation).
Figure 8. Browser client, invocation response, console view
Figure 9 shows the output from the ServiceListener interface’s serviceChanged implementation to track service status changes.
Figure 9. Browser client, invocation response, SystemOut.log
This brief overview, guide, and sample application highlighted the exciting and emerging OSGi programming model, supported in WebSphere Application Server V8 and by the Rational Application Developer V8.0.3 workbench tooling. Hopefully this information will inspire you to investigate further how OSGi can enhance your existing solutions and foster innovations in new development.
|Sample application||dw-OSGi-sample.zip||26 KB|
- Comment lines: What makes for good modularity and why OSGi is awesome
- WebSphere Application Server Network Deployment V8 Information Center
- Rational Application Developer V8.0.3 Information Center
- OSGi Alliance Specifications
- IBM developerWorks WebSphere