OSGI Concepts and Tutorial

OSGI is Open Service Gateway Initiative  provides a modular architecture  distributed systems and mostly widely used. This tutorial is intended of OSGI beginners and will drive you through OSGI components.

OSGI Building blocks:

  1. Bundles
  2. Components
  3. Services

1.OSGI Bundles

OSGI Bundle is one or more components/service are made as a jar file. In nutshell, its a plain jar file that contains components/services.

  • Bundle is a JAR file packaging classes and resources.Each bundle is having metadata that is added in manifest file in META- INF/MANIFEST.MF.
  • One OSGI bundle can not refer other OSGI bundle directly in the OSGI container.
  • Each OSGI Bundle should have the activator  that will be invoked  when then bundle is starts. In this case, HelloWorldActivator is activator that implements BundleActivator interface will be called. (add org.eclipse.osgi.jar as dependency)
  • Each bundle should also requires MANIFEST.MF file that defines meta data of bundle such – bundle activaor,policty, list of exported packages,services etc
  • Bundles in OSGi can be installed,updated and uninstalled without taking down the entire application.
  • One Bundle with differant versions can be installed in OSGI container.
  • Each OSGI bundle has lifecycle in OSGI container with below  six states:
    • UNINSTALLED: The bundle is uninstalled and may not be used in the OSGI container
    • INSTALLED  :A bundle is installed in the Framework but is not resolved.
    • RESOLVED: The bundle is resolved and is able to be started, which means  bundle is not active. you can start the bundle at any time using start {bundle-id} command in OSGI console.
    • STARTING: The bundle is in the process of starting.
    • STOPPING: The bundle is in the process of stopping.
    • ACTIVE:The bundle is now running.A bundle is in the ACTIVE state when it has been successfully started and activated.

OSGI Tutorial

Lets look into sample OSGI project.OSGI

  • Create a java project
  • add org.eclipse.osgi.jar as dependency
  • create HelloWorldActivator.java file that implements BundleActivator interface
  • create MANIFEST.MF file and add bundle activator entry and symbolic name in that
  • that’s it.. the above two steps makes Java Project as OSGI Bundle
  • Activator:
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class HelloWorldActivator implements BundleActivator {

      @Override
        public void start(BundleContext arg0) throws Exception {
                      System.out.println("_------ - Bundle is starting------");
        }
       @Override
       public void stop(BundleContext arg0) throws Exception {
            System.out.println("---- Stopping Bundle -----");
       }
}

 MANIFEST.MF file: Activator will be referred in MANIFESH.MF file

Manifest-Version: 1.0
Bundle-Name: Hello Service
Bundle-SymbolicName: com.demo.osgi.bundle.helloworld
Bundle-Version: 1.0.0
Bundle-Activator:com.demo.osgi.bundle.HelloWorldActivator
Bundle-Vendor: jay
Require-Bundle: org.eclipse.osgi
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Bundle-ActivationPolicy: lazy

What is MANIFEST.MF file in OSGI?

  • MANIFEST.MF contains meta data about bundle and holds below information:
    • bundle Name
    •  a  symbolic name  to determine  bundle’s unique identity by OSGI Container
    • bundle Name  – decription of bundle
    • bundle Version
    • supported  java version of the bundle
    • bundle activation policy (lazy means bundle is installed but not active)
    • import-packge
    • export-Package
      • Sample Manifest file 
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Hellow Service
Bundle-Version: 1.0.0
Bundle-SymbolicName: org.demo.osgi.bundle.hello-service
Created-By: Jayaram
Import-Package: com.liferay.portal.kernel.exception;version="[7.0,8)",com.liferay.portal.kernel.log;version="[7.0,8)",
com.liferay.portal.kernel.service;version="[1.0,2)" 
Private-Package: org.demo.liferay.service 
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
Bundle-ActivationPolicy: lazy;

How to Run OSGI applications?

OSGI bundles requires OSGI container to run the OSGI bundles. A bundle must be OSGI compliant which would be having BundleActivator to enable the bundle. The below are popular OSGI container Providers:

  • Equinox  –  eclipse comes with equinox as default OSGI container
  • Apache Felix

Its always recommended to use BndTools which provides OSGI workspace and runtime also. Just install the install the bnd eclipse plugin  from : https://dl.bintray.com/bndtools/bndtools/latest/

 2. OSGI Components:

The above example is native implementation of OSGI bundle where all things such as bundle activation,service registration,dependency injection are need to manage manually via BundleActivator.

How to make OSGI implementation easy? Answer Declarative Services

Declarative services are OSGI annotations  are used to create OSGI components.   Declarative Services provides annotations to create OSGI bundle, injects required dependencies, bundle activation and deactivation etc. All the annotations specifications are provided by org.osgi.compendium.jar file.

  1. OSGI Framework will have list of components and services.
  2. OSGI component can be exposed as service
  3. OSGI component can inject Other service from OSGI runtime
  4. OSGI component can not refer other OSGI components directly. OSGI component can only reuse services exposed by other OSGI component

@Component – Define Component
@Service  –  Defines Service I
@Reference – Injects external service
@Activate
@Deactivate
@Modified
@Property

In the below example:

  • @Component need to at top level of each class difines this as a OSGI component
  • @Activate method will be called when the bundle start
  • @Deactivate method will be called when the bundle deactivated
  • immediate = true means bundle will starts immediatly
  • service/provide – This defines what service it is consuming. An OSGI component can be Service Provider or Consumer.
@Component(
   configurationPid={"org.javasavvy.demo.impl",Component.NAME},
    enabled=true,
   immediate=true
   service = Portlet.class //(or Servlet.class or Listner.class)
)
public class HelloWorldPortlet {
 
     @Activate
     protected void activate() {
     }
    @Deactivate
     protected void deactivate() {
     }
}

3. OSGI Services

OSGI Services are follows Service Registry Modal to connects bundles in OSGI framework via Publish-Find-Bind Modal.

Lets take below use case:

1. org.demo.student.api – provides interface(StudentService.java) methods for entire project
2. org.demo.student.impl – provides implementation layer(StudentServiceImpl.java) of Interfaces
3. org.demo.student.web – this is client bundle that consumers student services

Service Registration:

    • public class StudentServiceActivator implements BundleActivator {
      
       private StudentService studentService;
       @Override
       public void start(BundleContext context) throws Exception {
        studentService = new StudentServiceImpl();
       context.registerService(StudentService.class.getName(), studentService, null);
       }
       @Override
       public void stop(BundleContext context) throws Exception {
         System.out.println("[Student Activator] Stopping Module...");
       }
       
      }

      “org.demo.student.impl” bundle will register  register StudentService as Service to OSGI framework with below code execution.

      •  studentService = new StudentServiceImpl();
         context.registerService(StudentService.class.getName(), studentService, null);
  • “org.demo.student.web” bundle will get the StudentService at runtime via @Reference or ServiceTracker as per below:

    How “org.demo.student.web” bundle got  StudentService  object?

  •   OSGI Framework looks up in Service Registry for implementation object for StudentService and returns the implementation object that  “org.demo.student.impl” registered  to the OSGI framework

    What if there are multiple StudentService implementation providers are registered to the framework?

  • OSGI framework offers filters such as bind,servcie,cardinality to identify the exact service.
public class StudentClient {

 private StudentService studentService;

 public void getName(){
 System.out.println("Calling command getName:"+studentService.getStudentName());
 }

 @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL)
 protected void setStudentService(StudentService studentService) {
 System.out.println("[Student Service Client]: setting student service");
 this.studentService = studentService;
 }
 protected void unsetStudentService(StudentService studentService) {
 System.out.println("[Student Service Client]: remove student service");
 this.studentService = null;
 }

 

Let looks into the tutorial : OSGI Bundle Tutorial