OSGI is a framework used in building complex Java applications that contain multiple components. With OSGI, you can build Java application that can load dynamically. When you are building a basic Java application, you might create a jar file for each module and load it with the class path. But, with the OSGI framework, you can load OSGI jar file dynamically whenever you needed.
Lets discuss some of the terminologies and concepts that you should know about OSGI framework:
Bundle
Bundle is the OSGI module that contain all your logics. Bundle is a jar file that contain your business logic that provide some service. Other than a regular jar file, it also contain information about how it supposed to work in OSGI runtime in MANIFEST.MF file. These information include a bundle name, version, exported and imported libraries.
Following is a sample definition of OSGI bundle definition:
Bundle-Name: Hello World
Bundle-SymbolicName: org.dhanushka.helloworld
Bundle-Description: A Hello World bundle
Bundle-ManifestVersion: 2
Bundle-Version: 1.0.0
Bundle-Activator: org.dhanushka.Activator
Export-Package: org.dhanushka.helloworld;version="1.0.0"
Import-Package: org.osgi.framework;version="1.3.0"
- Bundle-name is used to identify the bundle. This is just a optional string value.
- Bundle-SymbolicName is a unique identifier for the bundle. This follows the common java package naming standard.
- Bundle-Description is a description about what this bundle does.
- Bundle-ManifestVersion is versioning used by OSGI framework to read bundle manifest.
- Bundle-Version is the version number you allocated for the OSGI bundle.
- Bundle-Activator is the starting point of your module. You bundle can have multiple class implementations. OSGI use this property to mark what is the class that used as starting point of the bundle. We will discuss about bundle activator more later.
- Export-Package is a set of packages that you need to expose to other OSGI bundles. If you didn't specify export packages, then other OSGI bundles unable to access classes in your OSGI bundle.
- Import-Package is a set of packages that required to your OSGI bundle. You should import packages in here if you need to refer any other OSGI bundles.
Bundle is simply a module that contain all of your programming logics. You can import another bundle functionality into it and expose your own functionality to other bundles.
Services
Services are the way how each of the bundles are connected together. As I have already explained, multiple bundles can be connected together to provide some service.
Check the following sample bundle implementation that has activation method on it:
public class Activator implements BundleActivator {
private BundleContext context;
@Override
public void start(BundleContext context) throws Exception {
System.out.println("Starting");
this.context = context;
}
@Override
public void stop(BundleContext context) throws Exception {
System.out.println("Stopping");
this.context = null;
}
}
In this source code, the bundle activator is the Activator
class. When the OSGI starting up it start executing the start
method. This is much similar to the main
method. When the OSGI framework stopping, it trigger the stop
method. Whenever you add this bundle into the OSGI runtime, it will start execution by calling the start
method and end its execution by calling the stop
method.
As you can see, this bundle does not have any dependency with other OSGI bundles. It can start its execution independently. In some scenarios, you might need to start this bundle when some conditions are met. Until condition satisfy, OSGI runtime does not call the start
method.
This can be achieved with references. References let you to call start
method once given conditions are met. Check the following modification done to the Activator
class:
public class Activator implements BundleActivator {
private BundleContext context;
@Override
public void start(BundleContext context) throws Exception {
System.out.println("Starting");
this.context = context;
}
@Reference(
name = "activator.service",
service = ActivatorService.class,
cardinality = ReferenceCardinality.MANDATORY,
policy = ReferencePolicy.DYNAMIC,
unbind = "unsetActivatorService")
protected void setActivatorService(ActivatorService activatorService) {
// Set values
}
protected void unsetActivatorService(ActivatorService activatorService) {
// Unset values
}
@Override
public void stop(BundleContext context) throws Exception {
System.out.println("Stopping");
this.context = null;
}
}
In this code, other than previous start
and stop
method, there are another two methods. @Reference
annotation used here to mark these dependencies. Here, we have given a service name and service class. Under the reference annotation, we defined the cardinality
as mandatory. Since the cardinality marked as mandatory, to trigger start
function, setActivatorService
should be satisfied. If the cardinality is optional, then it is not mandatory to call setActivatorService
to start this bundle. This method can be triggered from another bundle. Following is a sample code, how to trigger setActivatorService
method.
context.getBundleContext().registerService(ActivatorService.class.getName(), activatorService, null);
Here, the activatorService
is the object that contain details that need to send to the setActivatorService
. Once this method get called, OSGI bundle will start the ActivatorService
start
method.
You can build more advanced applications by using the OSGI framework. You build dynamically pluggable components with dependency injection design pattern.
Top comments (0)