Liferay Development

Liferay Consulting

Liferay Training

Your Trusted Liferay Solutions Partner

Tuesday, September 5, 2017

OSGi Dependency Management Example

OSGi dependency management explain, how components or bundles share code between bundles. OSGi is dynamic component development so each application composed of components. Dependency Management define how code can be shared between bundles or we can say how we can access one bundle classes/interfaces in other bundles.

When we develop OSGi bundles any class or interfaces which we developed in the bundles accessible to within the bundle and not outside the bundle. Dependency management will explain how we can access one bundle resources in other bundles.

The following articles will give the introduction about OSGi dependency management


Usually to understand example we have two bundles and one bundles will have interface with set of service and its implementation. Other bundle will access the services which are developed by other bundle

The following are the steps

Bundle A Creation

  • Create New Bundle A
  • Define Service in the Interface
  • Implements Service defined in the Interface
  • Export Service Package
  • Register Service Implementation Object with Bundle Context


Bundle B Creation

  • Create New Bundle B
  • Import Service Provider Bundle Services Package
  • Access Service Provider Bundle Service Implementation Object in Consumer Bundle

Prerequisites

Install Java 8
Latest Eclipse IDE (Oxygen Release (4.7.0))

Create New Bundle A

Create New Bundle A

Create new bundle using eclipse with activator class. This bundle will have one interface and its service implementation.

Start Eclipse

File à New Project à New Plugin Project


Bundle Name: com.ls.de.LSServiceProvider

Target Platform à OSGi Framework à standard





Click on next

Click on Check Box Generate Activator Class and provide name


Example:

com.ls.de.lsserviceprovider.ServiceActivator





Click on Finish then new bundle will be created. Bundle can be visible in the project explorer with generated activator class and MANIFEST file



Define Services in the Interface

We already created bundle and now create Service Interface and define the service.
Create new package and create new java interface

Right Click on Project Src à New Interface à Provide Details à Click On Finish

Package :           com.ls.de.lsserviceprovider.services
Interface Name: HelloService





Now define service method in the Interface finally it looks like as follows

HelloService.java


package com.ls.de.lsserviceprovider.services;

public interface HelloService {
      public String greetHello();
}


Implements Service defined in the Interface

We already define the service interface with method. Now we have to implements the service method in the implementation class. Create new package and new implementation class.

Right Click on Project Src à New Class à Provide Details à Click on Finish

Package :           com.ls.de.lsserviceprovider.services.impl
Interface Name: HelloServiceImpl




Implement interface method in the implementation class, finally implementations class as follows.

HelloServiceImpl.java


package com.ls.de.lsserviceprovider.services.impl;

import com.ls.de.lsserviceprovider.services.HelloService;

public class HelloServiceImpl implements HelloService {
    
     @Override
      public String greetHello() {
          
           System.out.println("=====Inside HelloServiceImpl.greetHello()=====");
        return "Hello Greeting from Liferay Savvy World..";
     }

}

Export Services Package

Now we have to Export Services package from services bundles so that these interfaces or resources can be accessible in the other bundles. Remember here only we are exporting services package not implementation package.

MANIFEST have OSGi header called “Export-Package” and we need to add package names with comma separate value, so that we can access these resources in other bundles.

Add “com.ls.de.lsserviceprovider.services” package name under “Export-Package” in the Bundle MANIFEST file

Finally MANIFEST looks as follows

MANIFEST.MF


Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: LSServiceProvider
Bundle-SymbolicName: com.ls.de.LSServiceProvider
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.ls.de.lsserviceprovider.ServiceActivator
Bundle-Vendor: LS
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Export-Package: com.ls.de.lsserviceprovider.services
Import-Package: org.osgi.framework;version="1.3.0"


Register Service Implementation Object with Bundle Context

Now we need to register service implantation in OSGi Bundle Context so that it will be accessible to other bundles.

The services registration and unregister information will managed by Service Registration object. When we register Service Implementation object with Bundle Context it will return Service Registration Object.

Usually when bundle is started then we register the services with bundle context. We will use Bundle Activator start (--) method to register service objects
Bundle Context have methods registerService(--) and unregister(--) methods to register and unregister service objects.

registerService(--) method will take three arguments

Argument: 1

Service object unique identification to identify the service, usually we will use fully qualified service interface class name

Argument: 2

Service Implementation Object to register with bundle context

Argument: 3

Its Java MAP object to filter the service objects. Sometime same interface have multiple implementation then we will use some filter properties to identify the service implementation object. Service Identification is same for all implementation so we will additional properties to get service objects. In this example we have only one implementation so we have passed null.

unregister(--) method will unregister service object from Bundle Context. Usually we unregister service when bundle is removed from the container then it will call stop(--) lifecycle method. We will unregister service when it execute stop(--) method.

Now go to Bundle Activator class add following code parts in the start (--) and stop (--) methods.  
  
ServiceActivator.java

package com.ls.de.lsserviceprovider;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

import com.ls.de.lsserviceprovider.services.HelloService;
import com.ls.de.lsserviceprovider.services.impl.HelloServiceImpl;

public class ServiceActivator implements BundleActivator {

     private static BundleContext context;
     ServiceRegistration serviceRegistration;

     static BundleContext getContext() {
           return context;
     }

     /*
      * (non-Javadoc)
      * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
      */
     public void start(BundleContext bundleContext) throws Exception {
           ServiceActivator.context = bundleContext;
           System.out.println("Liferay Savvy Hello World Service Provider Bundle Activator Start");
           HelloService helloService = new HelloServiceImpl();
           serviceRegistration =context.registerService(HelloService.class.getName(), helloService, null);
     }

     /*
      * (non-Javadoc)
      * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
      */
     public void stop(BundleContext bundleContext) throws Exception {
           ServiceActivator.context = null;
           System.out.println("Liferay Savvy Hello World Service Provider Bundle Activator Stop");
           serviceRegistration.unregister();
     }

}


Create New Bundle B

Create new bundle using eclipse with activator class.
Start Eclipse

File à New Project à New Plugin Project


Bundle Name: com.ls.de.LSServiceConsumer
Target Platform à OSGi Framework à standard





Click on next

Click on Check Box Generate Activator Class and provide name


Example:

com.ls.de.serviceconsumer.ServiceConsumerActivator



Click on Finish then new bundle will be created. Bundle can be visible in the project explorer with generated activator class and MANIFEST file




Import Service Provider Bundle Services Package

We have to Import Services package from services bundle so that these interfaces or resources can be accessible in the consumer bundle.

MANIFEST have OSGi header called “Import-Package” and we need to add package names with comma separate value, so that we can access these resources in current bundle.

Add “com.ls.de.lsserviceprovider.services” package name under “Import-Package” in the Bundle MANIFEST file

Finally MANIFEST looks as follows

MANIFEST.MF


Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: LSServiceConsumer
Bundle-SymbolicName: com.ls.de.LSServiceConsumer
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.ls.de.serviceconsumer.ServiceConsumerActivator
Bundle-Vendor: LS
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: com.ls.de.lsserviceprovider.services,
 org.osgi.framework;version="1.3.0"


When we use import header then the listed java classes and interfaces are available in the current working bundles.

Access Service Provider Bundle Service Implementation Object in Consumer Bundle

We already register services object and exported package in the consumer bundle. Now we can user service implementation in the consumer bundle. Now we can access service implementation object from consumer bundle context.

We have Bundle Context getService(--) method and it will return the service implementation object. We need to pass service reference object for this method.

We will identify the Service Implementation Object by service interface name. We already register the service with same name. So we will use same name to identify the service implementation Object.

We will use consumer Activator Class to get implementation object and call the required services.

Go to Consumer Bundle Activator class add the following code part in the Start (--) method and invoke service method using service implementation object.

ServiceConsumerActivator.java

package com.ls.de.serviceconsumer;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

import com.ls.de.lsserviceprovider.services.HelloService;

public class ServiceConsumerActivator implements BundleActivator {

     private static BundleContext context;
     ServiceReference helloServiceReference;

     static BundleContext getContext() {
           return context;
     }

     /*
      * (non-Javadoc)
      * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
      */
     public void start(BundleContext bundleContext) throws Exception {
            ServiceConsumerActivator.context = bundleContext;
            System.out.println("Hello World Consumer Bundle Activator Start");
          helloServiceReference= context.getServiceReference(HelloService.class.getName());
          HelloService helloService =(HelloService)context.getService(helloServiceReference);
          System.out.println(helloService.greetHello());

     }

     /*
      * (non-Javadoc)
      * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
      */
     public void stop(BundleContext bundleContext) throws Exception {
           ServiceConsumerActivator.context = null;
           System.out.println("Hello World Consumer Bundle Activator Stop");
           context.ungetService(helloServiceReference);
     }

}



Execute Bundles

We have two bundles Service Provider Bundle and Service Consumer bundle.
Service Consumer bundle dependence on Service Provider Bundle. So we have to activate Service Provider bundler before access services in the consumer bundle.


Service Provider Bundle Name:
 com.ls.de.LSServiceProvider

Service Consumer Bundle Name:
com.ls.de.LSServiceConsumer



Start com.ls.de.LSServiceProvider

Go to com.ls.de.LSServiceProvider Activator Class and Right click on class you can see Run

Right Click à Run à Run Configuration

Run configuration window check the required bundles then click on run
Basically we need OSGi implementation bundles that equinox and we can also use other implementation as well like apache Felix. Other two bundles are that we developed. Select only service provider bundle so that only provider bundle will be executed.



Once you run then bundle will activated you can see messages in the console.
In the console just type OSGi gogo shell command to list the bundles then you can see Service Provider Bundle in the list and we can see status that is activated.

Type following command in the gogo shell then we can see all bundles list

lb



Now you can see Service Provider bundle in the list with active state and bundle number.


Now use following stop and start commands then you can see console messages. It will invoke Bundle Activator class


osgi> stop 1003
Liferay Savvy Hello World Service Provider Bundle Activator Stop
osgi> start 1003
Liferay Savvy Hello World Service Provider Bundle Activator Start
osgi>


Note:

We will use bundle number to start or stop bundle in the OSGi container.

The following console shows Invoking Service Provider Bundle Life cycle methods.


Start com.ls.de.LSServiceConsumer

Service Provide Bundle is activated and Now execute Service Consumer bundles so that it will invoke the greetHello(--) method which is implemented in the Service Provider bundle.
Go to com.ls.de.LSServiceConsumer Activator Class and Right click on class you can see Run

Right Click à Run à Run Configuration

Run configuration window check the required bundles then click on run
Basically we need OSGi implementation bundles that equinox and we can also use other implementation as well like apache Felix. Other two bundles are that we developed. Select both bundle and click on run.


Go to Console and list bundles using lb command then you can see both bundles are in active state

Now use stop and start shell commands for service consumer bundle then we can see the console message that make sure that is invoking greetHell(--) method from service provider bundle from consumer bundle

osgi> stop 1003
Liferay Savvy Hello World Service Provider Bundle Activator Stop

osgi> stop 1004

osgi> start 1003
Liferay Savvy Hello World Service Provider Bundle Activator Start

osgi> start 1004
Liferay Savvy Hello World Consumer Bundle Activator Start
=====Inside HelloServiceImpl.greetHello()=====
Hello Greeting from Liferay Savvy World..

osgi>

The following is console which shows its invoked greetHello(--) method




Author

Popular Posts

Recent Posts

Recent Posts Widget