Have you ever heard of OSGi? Do you know what’s its purpose?
If you haven’t, I’ll do my best to introduce you to this wonderful piece of software.
Let’s see what Wikipedia has to say:
The OSGi Alliance, formerly known as the Open Services Gateway initiative, is an open standards organization founded in March 1999 that originally specified and continues to maintain the OSGi standard.
OSGi is a Java specification, or simply put, just a set of interfaces.
It aims 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.
This architecture consists of two primary components:
- System core — the minimal set of functionalities that are considered to build up the heart of a software system.
- Plug-in modules — also called bundles in OSGi, they represent independent and stand-alone pieces of software which are meant to bring additional features to the core system, thus expanding its functionalities.
We can imagine bundles as separate mini-programs that operate over an OSGi core system.
Bundles can be plugged into the core system at runtime, and they can start working immediately without the need for a system restart which makes the software very flexible and extendable.
Bundles can also be easily reused in other applications. And hey, it’s better to reuse whole components rather than just objects, right?
Furthermore, the plug-in architecture offers strong loose coupling between modules which makes them easy to test and the software easy to develop since different modules can be developed in parallel because they’re independent from each other.
Now let’s take a look at Figure 2.
It demonstrates an embedded system that can read or write commands to multiple sensors through the serial port with the help of the Serial Port Library module, it can also persist each sensor’s data using the SQL Database module and can send data to a cloud service through the HTTP Client module.
Here the cool part is that If we want the system to support a new sensor, e.g. a temperature sensor, we just develop a temperature sensor bundle and introduce it to the system. Additionally, If there’s a need for more functionalities like data compression, for an example, we’ll again develop a data compression bundle then install it to the system and use it.
An OSGi bundle, or as we earlier said — plug-in module, is an ordinary JAR file containing a manifest file with some additional OSGi-specific headers. Its idea is to be an extension to an OSGi system.
Bundles can export functionality and import functionality from other bundles in the system.
Every bundle should introduce abstractions to its business logic through interfaces and export only those interfaces to other bundles, thus allowing its business logic to vary independently. This strategy ensures loose coupling between bundles.
Bundles have their independent life-cycle. When they’re installed to a system they start running if their dependencies are met, otherwise they just stay inactive, on stand-by. Additionally, while running if some dependencies drop, the bundle is stopped until the dependencies are met again.
Services are the concept which bundles use to import and export functionality from and to other bundles.
In OSGi, any Java object can be registered as a service.
To illustrate the service concept, let’s consider the following example: Let the Earth be the OSGi core system while people are plug-in modules. Now let’s consider one exact person. We know that he has multiple friends —also plug-in modules. He can request favors from his friends who are computer scientists, lawyers, doctors, etc. Every ask for a favor is basically a use of service. Moreover, he doesn’t necessarily need to know how exactly will his friends do his favor, he just needs the results. This way his friends’ plan for how to do the favor can vary independently, because this won’t affect the final result. This shows how bundles don’t export their inner logic, instead they export only an interface to it.
Why do we need OSGi?
OSGi makes complex software look like a Python “Hello world” example.
It offers a nice development flow which works towards a loosely-coupled, nicely divided into modules application with reduced complexity.
The modularity which OSGi provides eases not only development complexity and development speed but also maintenance and testing of an application.
Furthermore, we can
- Add or remove functionality during runtime.
- Reuse whole components instead of just objects.
- Efficiently encapsulate business logic and export only interfaces to it.
- Resolve the Jar Hell problem via bundle versioning.
Here’s a note from the OSGi Alliance showing what kind of software is built with OSGi.
The OSGi component system is actually used to build highly complex applications like IDEs (Eclipse), application servers (GlassFish, IBM Websphere, Oracle/BEA Weblogic, Jonas, JBoss), application frameworks (Spring, Guice), industrial automation, residential gateways, phones, and so much more.
What’s the “Hello world” of OSGi?
Let’s create a simple calculator usage example which demonstrates core OSGi principles.
We’ll create a calculator provider and a calculator consumer.
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.
First, we’ll describe what functionality will our calculator support.
Then we’ll start implementing the functionality straight ahead.
Note that we’ve used the OSGi @Component annotation to mark our calculator’s implementation as a service component. This way we register it to a place called SCR or Service Component Runtime which will manage our component and ensure that it can be accessed through its interface by other components later in the future.
That’s all from the provider module’s part.
Now let’s inject our calculator provider module’s interface via the @Reference annotation.
We also used the @Activate annotation to mark a method as a first-to-run when the component is instantiated.
In this example, we clearly see that the calculator’s implementation has the freedom to vary independently. For instance, we can change the calculator’s multiplication operation to use multiple addition operations instead of direct multiplication, and we won’t break anything in the system. All bundles will continue to use the calculator but with the updated implementation instead.
Sources and guides
You can find the complete source code and further setup details in the GitHub repository below.
Relatively old and proven to be stable, OSGi makes complex software manageable, flexible, extensible and robust.
It’s basically a standardized ‘go-to’ solution for enterprise Internet of Things solutions.