OSGi, a walkthrough
This post will briefly explain about what is OSGi, basic concepts in OSGi and its major application areas.
What is OSGi?
OSGi (Open Service Gateway Initiative) technology is a set of specifications and a reference implementation for each specification that define a dynamic component system for Java. OSGi is a Java framework for developing and deploying modular software programs and libraries. It specifies how to build larger applications from very loosely-coupled components.
The OSGi specifications enable components to hide their implementations from other components while communicating through services. Purpose of OSGi specification is to define a way to develop modular Java applications and to utilize the concepts of a microkernel architecture, also known as a plug-in architecture.
What is Modularity?
We can define modularity in simple terms as independent small components or programs which communicate with each other in a loosely coupled manner to solve a complex problem. Modularity is a way of writing and implementing a program or a system, rather than implementing it as a single monolithic design, we can implement it as different independent unique modules. This will help in optimizing application development, and reduce system complexity by minimizing coupling.
OSGi defines a dynamic component system in Java. The OSGi specification focuses on modular development with a component based deployment model. The application consists of several decoupled deployable units or components packaged in bundles. These components communicate through services, where the communication can be done locally or across the network.
The components are designed in such a way that they form a reusable building block of the application. The service based communication allows the components to hide the implementation details from other components.
The layered model of OSGi is depicted in the following figure.
A complete reference guild of the OSGi layered architecture can be found in the official documentation https://www.osgi.org/developer/architecture/
OSGi bundle is nothing but JAR of java classes made by the developers. The OSGi components which are packaged with manifest (bundle metadata), code (classes in packages) and resources (other files in the JAR file) to form a deployable bundle.
Bundles are the development unit of OSGi which defines the modular concept. Bundles can hide and share packages with the help of manifest. A bundle can carry descriptive information about itself in the manifest file that is contained in its JAR file under the name of META-INF/MANIFEST.MF.
Here is an example bundle manifest file, META-INF/MANIFEST.MF:
Bundle-Name: My Service Bundle
Bundle-Description: Sample OSGi bundle.
- Manifest-Version: Version number of the manifest file.
- Bundle-ManifestVersion: The Bundle-ManifestVersion header determines whether the bundle follows the rules of this specification. It is 1 (the default) for Release 3 Bundles, 2 for Release 4 and later.
- Bundle-Name: Bundle-Name header defines a readable name for this bundle. This should be a short, human-readable name that can contain spaces.
- Bundle-SymbolicName: A name that identifies the bundle uniquely and is a mandatory field, it is generally defined as the base package name of the bundle by convention.
- Bundle-Version: This header describes the version of the bundle, and enables multiple versions of a bundle to be active concurrently in the same framework instance.
- Bundle-Activator: This header notifies the bundle of lifecycle changes.
- Import-Package: This header declares the external dependencies of the bundle that the OSGi Framework uses to resolve the bundle. Specific versions or version ranges for each package can be declared.
- Export-Package: This header declares the packages that are visible outside the bundle. If a package is not declared in this header, it is visible only within the bundle.
OSGi bundles communicate with each other using service. A bundle can create an object and register it with the OSGi service registry under one or more interfaces. The consuming bundles can go to the registry and list all objects that are registered under a specific interface or class.
Any number of bundles can register the same service type, and any number of bundles can get the same service. We can generally refer to this as broker pattern.
The Life Cycle Layer provides an API to control the security and life cycle operations of bundles.
INSTALLED — This state indicates that the installation step has been successfully completed. In this case, neither dependency analysis nor the class loading is made. Only required steps are performed, such as defining bundle properties analyzing its Manifest file.
RESOLVED — This is the state that comes before starting and after stopping. Bundle is found in this state when OSGi resolves and satisfies all of its dependencies and makes class loading operations.
STARTING — This is the state that bundle will be when the “start” method of the Activator of the bundle is called, but not yet as successfully or unsuccessfully finished.
ACTIVE — The bundle is successfully started and running meaning the “start” method of the Activator resulted in success.
STOPPING — This is the state that bundle will be when the “stop” method of the Activator of the bundle is called, but not yet as successfully or unsuccessfully finished.
UNINSTALLED — This is the state when the bundle is removed from the system. In this situation, there is no transition to another state. The component must be installed again.
The OSGi Framework provides a generic and standardized solution for Java modularization. The Framework defines a unit of modularization, called a bundle. A bundle is composed of Java classes and other resources, which together can provide functions to end users. The modularization layer has strict rules for sharing Java packages between bundles or hiding packages from other bundles. The Module Layer can be used without the life cycle and Service Layer. The Life Cycle Layer provides an API to manage the bundles in the Module Layer, while the Service Layer provides a communication model for the bundles.
OSGi Security Layer is an optional layer that underlies in the OSGi framework. This layer is based on the Java specification. It defines a secure packaging format as well as the runtime interaction with the Java security layer.
OSGi allows bundles to be marked with minimum execution environment they require. Good practice is to have a bundle with minimal dependencies.
The OSGi framework is dynamic. It can update bundles on the fly and services can come and go. Bundles can be installed, started, stopped, updated, and uninstalled without bringing down the whole system. This behavior influenced almost all the areas of software industry ranging from small scale systems to Enterprise applications.
OSGi is widely adopted in a broad range of open source and commercial applications. Application ranges from enterprise business to life critical application. Industry is adopting OSGi framework for products and solutions involving IoT, Smart Home, Healthcare, Smart Meters, Telecommunications, Automotive, Media, Control Systems, Enterprise Software Platforms, Robotics etc.
The above figure represents a schematic diagram in which OSGi framework is leveraged to support IoT platform. Here we can deploy OSGi bundle to Raspberry Pi which can poll temperature or data from any kind of sensory device attached to it and sends data to the external data center.
We can also extend the application to have a OSGi middleware server which communicates to internal bundles, which serve specific tasks. The middleware bundle contains the application server that enables communi‐cation with the installed bundles via the registered service interfaces. The dynamic middleware is realized as an OSGi bundle, which utilizes the benefits of the OSGi specification for enabling the modularity and scalability of the system.
One major benefit of this system is we can update with a new software bundle on the fly. We can realize the application to have bundles running in a OSGi framework like Eclipse Kura integrated with Apache Camel. The common reason to deploy Camel routes into the Eclipse Kura is to provide enterprise integration patterns and Camel components to the messaging M2M gateway. For example you might want to install Kura on Raspberry PI, then read temperature from the sensor attached to that Raspberry PI using Kura services and finally forward the current temperature value to your data center using Camel EIP and components.
Let’s create a simple Random number generation example which demonstrates core OSGi principles.
For this demonstration we will use Apache Karaf as the OSGi container.
In order to prevent cluttering, only the key parts of the code samples will be shown here and a link to the complete source code will be left below.
This project will act as a provider and it will have a random number generator interface ‘RandomNumberGenerator’ as below.
Then we’ll start implementing the functionality straight ahead.
The project random-number-generator will have an Activator class which will implement the BundleActivator of OSGi framework and register ‘RandomNumberGenerator’ as a service.
This project will consume the random number generated by the previous project and write to the standard output. The bundles communicate through the OSGi service registry.
The Activator class in this project will look up for the registered ‘RandomNumberGenerator’ service. If the service is found RandomNumberReader will use the service to fetch the randomly generated data.
Download the OSGi container to deploy and test the service, for this example we will choose Apache Karaf. Follow the below steps to run the bundles in OSGi container:
- Download the last Stable Version of Karaf from https://karaf.apache.org/download.html
- Extract the Zip to the location of your choice.
- Start Karaf by typing ./karaf in your KARAF/bin Folder.
- Build the two projects using maven install, bundle jar files will be generated at the target folder. Copy the generated jar files to KARAF/deploy folder for auto deployment or install using mvn.
- Use list command to see the installed bundles.
- Start bundle of project random-number-generator followed by random-number-reader, the order is important since the later depends on the former.
Sources and guides
You can find the complete source code in the GitHub repository below.
- OSGi in Action: Creating Modular Applications in Java- Book by David Savage, Karl Pauls, Richard S. Hall, and Stuart McCulloch