• Writing your first OSGI Service in Liferay 7

    Posted on November 21, 2016 by Hamidul Islam in liferay 7.

    writing-your-first-osgi-service-in-liferay-7


    aimIn this article we will try to understand about OSI Service and its usage. In Liferay 7, OSGI plays a vital role. So its very important to understand the basics of OSGI Service. In this article we will create a basic OSGI service and in the next article we will create a portlet to consume this service.


    Note

    Whats OSGI Service???

    1. An OSGI Service is simply a instance of Java Object registered in OSGI Framework with some properties. At the time of registering OSGI Service we can set properties to it. However setting properties is optional.

    2. OSGI Service class must have to implement interface.

    3. In OSGI everything is deployed as bundle. So when we create an OSGI Service, the final artifact is simply an OSGI Bundle.

    4. An OSGI Bundle can register zero or multiple services in the OSGI Framework. Its not mandatory that an OSGI Bundle should register service. Its fully optional.

     5. The way an OSGI Bundle can Register services (or expose service ), similarly it can also consume one or many services.

     6. We can unregister a service at any point of time.   


    Creating OSGI Service:

     Use the bellow maven command to create OSGI Service

     mvn archetype:generate
    -DarchetypeGroupId=com.liferay
    -DarchetypeArtifactId=com.liferay.project.templates.service
    -DgroupId=com.proliferay
    -DartifactId=com.proliferay.sample.osgi.service
    -DserviceClass=SampleService
    -DclassName=SampleServiceImpl
    -DinteractiveMode=false 
    

    Service Interface:

    package com.proliferay.service;
    
    public interface SampleService {
    
    	public int add(int number1, int number2);
    }
    
    

    Service Implementation:

    package com.proliferay.service.impl;
    
    import com.proliferay.service.SampleService;
    
    import org.osgi.service.component.annotations.Component;
    
    @Component(
    	immediate = true,
    	property = {
    		// TODO enter required service properties
    	},
    	service = SampleService.class
    )
    public class SampleServiceImpl implements SampleService {
    
    	@Override
    	public int add(int number1, int number2) {
    		System.err.println("###########Calling add() method##################");
    		return number1 + number2;
    	}
    }
    

    Bundle Activator: 

    Now we have service implementation in place. The OSGI framework has to understand that its a service. To make OSGI to understand that its a service, we have to register the service in the framework. We can use bundle activator to register our service. Remember that an activator class must implement BundleActivator interface. Below is the code for registering the service.

    package com.proliferay.activator;
    
    import com.proliferay.service.SampleService;
    import com.proliferay.service.impl.SampleServiceImpl;
    
    import org.osgi.framework.BundleActivator;
    import org.osgi.framework.BundleContext;
    import org.osgi.framework.ServiceRegistration;
    
    public class ServiceActivator implements BundleActivator {
    
    	private ServiceRegistration registration;
    	
    	@Override
    	public void start(BundleContext context) throws Exception {
    
    		registration = context.registerService(SampleService.class.getName(), new SampleServiceImpl(), null);
    		System.out.println("###########Service Registered Successfully##############");
    	}
    
    	@Override
    	public void stop(BundleContext context) throws Exception {
    		registration.unregister();
    		System.out.println("###########Service Unregistered##############");
    		
    	}
    
    }
    
    

    NoteBundleActivator???

    A bundle activator is simply a class which is notified when a bundle starts and stops. Therefore to register our service BundleActivator is the right choice. Just write the registration code inside the start method so that when the bundle start the service is also registered as well.


    Very Important!!!!

    The final artifact of the project is OSGI bundle and its not same as traditional JAR file. The MANIFEST file must have BundleActivator entry so that when the bundle is deployed in OSGI container, it reads the MANIFEST file at first. Look into bnd.bnd file in the source code. Give attention to the Export-Package entry also. We need to expose our service so that from other bundle it can be discovered.

    Bundle-Name: com.proliferay.sample.osgi.service
    Bundle-SymbolicName: com.proliferay
    Bundle-Version: 1.0-SNAPSHOT
    Bundle-Activator: com.proliferay.activator.ServiceActivator
    Export-Package: com.proliferay.service
    

    When the bundle is packaged at the end, look inside the JAR(which is nothing but bundle) and open the MANIFEST file. It should look like

    Manifest-Version: 1.0
    Bundle-SymbolicName: com.proliferay
    Archiver-Version: Plexus Archiver
    Built-By: hamidul.islam
    Bnd-LastModified: 1479719348003
    Bundle-ManifestVersion: 2
    Import-Package: com.proliferay.service,org.osgi.framework;version="[1.
     8,2)"
    Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))"
    Service-Component: OSGI-INF/com.proliferay.service.impl.SampleServiceI
     mpl.xml
    Tool: Bnd-3.2.0.201605172007
    Provide-Capability: osgi.service;objectClass:List<String>="com.prolife
     ray.service.SampleService"
    Export-Package: com.proliferay.service;version="1.0.0"
    Bundle-Name: com.proliferay.sample.osgi.service
    Bundle-Version: 1.0.0.201611210909
    Bundle-Activator: com.proliferay.activator.ServiceActivator
    Private-Package: com.proliferay.activator,com.proliferay.service.impl
    Created-By: 1.8.0_111 (Oracle Corporation)
    Build-Jdk: 1.8.0_111
    

    Packaging and deploying the Bundle:

    Navigate to the project directory and execute mvn clean install. The generated bundle will be available in the target folder of the project directory. Now copy the bundle and deploy in the deploy folder of Liferay. After few seconds the service will be registered in the OSGI Container.

    Checkpoint:

    We have deployed the service. How would we know whether the service is registered or not. For a quick check open the Gogo Shell. We will find the bundle id of deployed bundle. The Active status of a bundle indicates that the bundle is active inside the container. 

    g! lb proliferay 
    START LEVEL 20
       ID|State      |Level|Name
      513|Active     |    1|com.proliferay.demo (1.0.0.201611210957)
      514|Active     |   10|com.proliferay.sample.osgi.service (1.0.0.201611210909)
    g! 
    

    As displayed in the above 514 is the ID of the bundle. Now we can check the service associated with the bundle ID

    g! inspect cap service 514
    com.proliferay_1.0.0.201611210909 [514] provides:
    -------------------------------------------------
    service; com.proliferay.service.SampleService with properties:
       service.id = 6749
       service.bundleid = 514
       service.scope = singleton
       Used by:
          com.proliferay_1.0.0.201611210957 [513]
    service; com.proliferay.service.SampleService with properties:
       component.name = com.proliferay.service.impl.SampleServiceImpl
       component.id = 2414
       service.id = 6763
       service.bundleid = 514
       service.scope = bundle
    g! 
    

    Summery:
    In this article we have shown how to create a sample service. In the next article we will explain how to use this service inside another bundle/portlet.

    Download Source Code:

    com-proliferay-sample-osgi-service

3 Responses so far.

  1. […] Writing your first OSGI Service in Liferay 7 […]

  2. Chris J says:

    Great tutorial, thanks! I was able to modify it to work using Eclipse with Gradle.

  3. Sravani Reddy says:

    this tutorial is helpful for me..as a beginner

Top
%d bloggers like this: