Liferay Development

Liferay Consulting

Liferay Training

Your Trusted Liferay Solutions Partner

Friday, October 20, 2017

OSGi Declarative Services (DS) Annotations

Annotation are the replacement for traditional XML configuration in the application development. Usually any application we can see many xml configurations, which will have set of predefined tags. Server containers or other application execution engines will use these XML configurations. Example Spring Web Applications, we have many spring configuration files, which will be used by Spring Containers to make the Dependency Injection among the beans.  Similarly, Liferay have many xml configuration files while developing portlets.  To manage the many XML files in the project is little tedious so experts come up with Annotations so that we can avoid most of the XML configurations while developing applications.

OSGi Declarative Services (DS) uses the XML configurations to manage component dependency injection in the OSGi Environment. To avoid old XML configuration, we have OSGi Declarative Services Annotations. Usage of annotation are very simple and simply define in the java classes wherever it requires.  All Annotation configurations finally turn into XML configuration and this kind of action will be taking care by the annotation implementation libraries. Developer do not need to worry about that part.

Follow Liferay DXP/7 Tutorial to get more information.

Previous Articles have given more details about XML configuration for the OSGi Components.


OSGi Declarative Service (DS) have following are the important annotations  to develop OSGi components.


@Component
@Reference
@Activate
@Deactivate
@Modified



Note:

All components are available in “org.osgi.service.component.annotations” package.

@Component

@Component is very important annotation in Declarative Services and it will make any simple java class into OSGi component. Its class level annotation so the java class turn into OSGi component.

Usually the component have service implementation so we will use @Component annotation to make the services implementation java class as Component to deliver services.

We can use @Component to any simple Java class in the OSGi component development and all the components need not to have service implementation. We can use @Component for any java class in the OSGi bundle development.

When we declare java class as component then the component registered in the Service Component Runtime registry so that the component will be available to other component when it needed.

The @Component have following attributes and all the attributes enclosed by braces. Each attributes separated by comma.

The following are the important attributes


name
immediate
service
property


Name:

Name uses to define the Component name. Usually its fully qualified class name. This name will be uses as the reference point for the other component.

Immediate:

Immediate is Boolean type value, which tell the OSGi container to activate component immediately when OSGi bundle deployed.

Service

Service attribute is java service interface. Which tells that, for which service interface the component is proving the implementation.

Property

If component, needed any other configuration information we will provided as properties and this will take list of key value pair values.

Note:

All the attributes are optional. As we know, each component not necessary to provide the service implementation. Some of them are service components and some of them are simple component, which does not have any service implementation.

Case: 1

Simple Component

When we use @Component it will turn into as OSGi component.

Example Component Java Class with @Component


package com.ls.ds.component;
import org.osgi.service.component.annotations.Component;
@Component
public class HelloComponent {
    public HelloComponent() {
        System.out.println("Hey I am Simple OSGi Component");
    }
}


Case: 2

Service Component

As we know that usually component will provide implementation for the services. Assume we have service interface and have implementation class. Now we can make services implementation as component with @Component annotation.

Example:

HelloService.java


package com.ls.ds.lsserviceprovider.services;

public interface HelloService {
      public String greetHello();
}


HelloServiceImpl Service Component

We will use @Component to service implementation class so that java class became service component and these services will be available to other components when it needed.

 
package com.ls.ds.lsserviceprovider.services.impl;
import com.ls.de.lsserviceprovider.services.HelloService;
@Component(
        name=com.ls.ds.lsserviceprovider.services.impl.HelloServiceImpl,
        immediate = true,
        service = HelloService.class
)
public class HelloServiceImpl implements HelloService {
    @Override
    public String greetHello() {
        System.out.println("=====Inside HelloServiceImpl.greetHello()=====");
        return "Hello Greeting from Liferay Savvy World..";
    }
}


@Component equivalent configuration for the above example as follows.


<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
     name="com.ls.ds.lsserviceprovider.services.impl.HelloServiceImpl">
     <implementation class="com.ls.ds.lsserviceprovider.services.impl.HelloServiceImpl" />
     <service>
           <provide interface="com.ls.ds.lsserviceprovider.services.HelloService" />
     </service>
</scr:component>


Case: 3

Service Component with Properties

HelloService.java


package com.ls.ds.lsserviceprovider.services;

public interface HelloService {
      public String greetHello();
}


HelloServiceImpl Service Component

 

package com.ls.ds.lsserviceprovider.services.impl;
import com.ls.de.lsserviceprovider.services.HelloService;
@Component(
        name=com.ls.ds.lsserviceprovider.services.impl.HelloServiceImpl,
        immediate = true,
        property = {
                "service.vendore=Liferay Savvy",
                "service.description=Sample Hello Service",
        },
        service = HelloService.class
)
public class HelloServiceImpl implements HelloService {
    @Override
    public String greetHello() {
        System.out.println("=====Inside HelloServiceImpl.greetHello()=====");
        return "Hello Greeting from Liferay Savvy World..";
    }
}
 

@Component equivalent configuration for the above example as follows.


<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
     name="com.ls.ds.lsserviceprovider.services.impl.HelloServiceImpl">
     <implementation
          class="com.ls.ds.lsserviceprovider.services.impl.HelloServiceImpl" />
     <property name="service.description" value="Sample Hello Service" />
     <property name="service.vendor" value="Liferay Savvy" />
     <service>
           <provide interface="com.ls.ds.lsserviceprovider.services.HelloService" />
     </service>
</scr:component>


Liferay DXP/7 used the Declarative Services annotations to develop Liferay Application modules such as portlets and hooks.

Liferay Portlet Component

The following is simple example code for the portlet component with @Component Annotation


package com.liferay.polls.web.internal.portlet;

import com.liferay.polls.constants.PollsPortletKeys;
import com.liferay.portal.kernel.portlet.bridges.mvc.MVCPortlet;
import javax.portlet.Portlet;
import org.osgi.service.component.annotations.Component;

@Component(
     immediate = true,
     property = {
           "com.liferay.portlet.add-default-resource=true",
           "com.liferay.portlet.css-class-wrapper=portlet-polls-display",
           "com.liferay.portlet.display-category=category.cms",
           "com.liferay.portlet.header-portlet-css=/css/main_polls_display.css",
           "com.liferay.portlet.icon=/icons/polls_display.png",
           "com.liferay.portlet.instanceable=true",
           "com.liferay.portlet.preferences-owned-by-group=true",
           "com.liferay.portlet.private-request-attributes=false",
           "com.liferay.portlet.private-session-attributes=false",
           "com.liferay.portlet.render-weight=50",
           "com.liferay.portlet.scopeable=true",
           "com.liferay.portlet.struts-path=polls_display",
           "com.liferay.portlet.use-default-template=true",
           "javax.portlet.display-name=Polls Display",
           "javax.portlet.expiration-cache=0",
             "javax.portlet.info.keywords=Polls",
           "javax.portlet.info.short-title=Polls Display",
           "javax.portlet.info.title=Polls Display",
           "javax.portlet.init-param.template-path=/",
           "javax.portlet.init-param.view-template=/polls_display/view.jsp",
           "javax.portlet.name=" + PollsPortletKeys.POLLS_DISPLAY,
           "javax.portlet.resource-bundle=content.Language",
           "javax.portlet.security-role-ref=power-user,user",
           "javax.portlet.supports.mime-type=text/html"
     },
     service = Portlet.class
)
public class PollsDisplayPortlet extends MVCPortlet {

}


@Reference

@Reference is opposite to @Component. @Component is will used to declare java class as service component and @Reference used to find the Service Component from the Service Component Runtime Registry.

To identify the required service component from the Service Registry we will use @Reference. @Reference will identify the dependent component and inject into the current component.

@Component is responsible to register the component in the OSGi Service Registry and make it available to other components.

@Reference used to identify the right dependent component and inject into the current component.

Example @Reference


package com.ls.ds.consumer.component;
import com.ls.ds.lsserviceprovider.services.HelloService;

@Component(
name=com.ls.ds.ConsumerComponent
)
public class ConsumerComponent {
      @Reference
      public void setHelloService(HelloService helloService) {
           System.out.println("=====Inside Consumer Component setService()=====");
           System.out.println(helloService.greetHello());   
      }
}


@Reference equivalent configuration for the above example as follows.


<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="com.ls.ds.ConsumerComponent">
     <implementation class="com.ls.ds.ConsumerComponent" />
     <reference bind="setHelloService" cardinality="1..1"
     interface="com.ls.ds.lsserviceprovider.services.HelloService" name="HelloService" policy="static" />
</scr:component>


The following are the important attributes for the @Reference


target
unbind


target

Target attribute will used to filter the reference components. Sometime we may have multiple implementation for service. It means we have many Service Components with different implementation. To identify the right Component instance, we will use target attribute. Usually we use set of properties for Component declaration so same properties will be used @Reference target to filter the reference components.

unbind

Unbind is used to declare setter method when the component is unbind or dissociated with the component. When the attribute with “-” it means there is no setter method is called after component unbind.

Example:


@Reference(
  target = "(javax.portlet.name=" + NotificationsPortletKeys.NOTIFICATIONS + ")",
  unbind = "-"
)
protected void setPanelApp(PanelApp panelApp) {
  _panelApp = panelApp;
}


Liferay DXP/7 used the Declarative Services annotations to develop Liferay Application modules such as portlets, hooks.

Liferay Portlet Component with @Reference

The following is simple example code for the portlet component with @Reference Annotation


@Component(
     immediate = true,
     property = {
           "com.liferay.portlet.add-default-resource=true",
           "com.liferay.portlet.css-class-wrapper=portlet-journal-content",
           "com.liferay.portlet.display-category=category.cms",
           "com.liferay.portlet.display-category=category.highlighted",
           "com.liferay.portlet.header-portlet-css=/css/main.css",
           "com.liferay.portlet.icon=/icons/journal_content.png",
           "com.liferay.portlet.instanceable=true",
           "com.liferay.portlet.layout-cacheable=true",
           "com.liferay.portlet.preferences-owned-by-group=true",
           "com.liferay.portlet.private-request-attributes=false",
           "com.liferay.portlet.private-session-attributes=false",
           "com.liferay.portlet.render-weight=50",
           "com.liferay.portlet.scopeable=true",
           "com.liferay.portlet.use-default-template=true",
           "javax.portlet.display-name=Web Content Display",
           "javax.portlet.expiration-cache=0",
           "javax.portlet.init-param.template-path=/",
           "javax.portlet.init-param.view-template=/view.jsp",
           "javax.portlet.name=" + JournalContentPortletKeys.JOURNAL_CONTENT,
           "javax.portlet.resource-bundle=content.Language",
           "javax.portlet.security-role-ref=guest,power-user,user",
           "javax.portlet.supports.mime-type=application/vnd.wap.xhtml+xml",
           "javax.portlet.supports.mime-type=text/html"
     },
     service = Portlet.class
)
public class JournalContentPortlet extends MVCPortlet {

     private ExportArticleUtil _exportArticleUtil;
     private JournalArticleLocalService _journalArticleLocalService;
     private JournalContent _journalContent;
     private TrashEntryService _trashEntryService;
    
     @Reference(unbind = "-")
     protected void setExportArticleUtil(ExportArticleUtil exportArticleUtil) {
           _exportArticleUtil = exportArticleUtil;
     }

     @Reference(unbind = "-")
     protected void setJournalContent(JournalContent journalContent) {
           _journalContent = journalContent;
     }

     @Reference(unbind = "-")
     protected void setJournalContentSearchLocal(
           JournalArticleLocalService journalArticleLocalService) {

           _journalArticleLocalService = journalArticleLocalService;
     }

     @Reference(unbind = "-")
     protected void setTrashEntryService(TrashEntryService trashEntryService) {
           _trashEntryService = trashEntryService;
     }

     protected void unsetExportArticleUtil(ExportArticleUtil exportArticleUtil) {
           _exportArticleUtil = exportArticleUtil;
     }

     protected void unsetJournalContent(JournalContent journalContent) {
           _journalContent = null;
     }

     protected void unsetJournalContentSearchLocal(
           JournalArticleLocalService journalArticleLocalService) {

           _journalArticleLocalService = null;
     }

     @Override
     public void doView(
                RenderRequest renderRequest, RenderResponse renderResponse)
           throws IOException, PortletException {

           ..........
     }

     @Override
     public void render(
                RenderRequest renderRequest, RenderResponse renderResponse)
           throws IOException, PortletException {

           ............
     }

     public void restoreJournalArticle(
                ActionRequest actionRequest, ActionResponse actionResponse)
           throws Exception {
         .................
     }

     @Override
     public void serveResource(
                ResourceRequest resourceRequest, ResourceResponse resourceResponse)
           throws IOException, PortletException {

           ................
     }   

}



Component Lifecycle Annotations

Each component have its own lifecycle and each life cycle stage will call life cycle methods. To define these life cycle methods we will use following annotation


@Activate
@Deactivate
@Modified


@Activate

@Activate will define the method that will be called when the component is activated. When we deploy the bundle then all the components will be activated.

The activate method have 3 types of method signatures


@Activate
protected void activate() {
  
}

@Activate
protected void activate(Map<String, Object> properties) {
  
}

@Activate
protected void activate(BundleContext bundleContext, Map<String, Object> properties) {
  
}



@Deactivate

@Deactivate will define the method that will be called when the component is deactivated. Usually when un-deploy or stop the bundle then the all component will be deactivated.

@Modified

@Modified will define the method that will be called when the component is modified.

Component with Lifecycle Annotations


package com.ls.ds.consumer.component;
import com.ls.ds.lsserviceprovider.services.HelloService;
@Component(
name=com.ls.ds.ConsumerComponent
)
public class ConsumerComponent {
      
      @Activate
      public void activate() {
           System.out.println("=====Service Component is Activated=====");   
      }
      @Deactivate
      public void @deactivate() {
           System.out.println("=====Service Component is Deactivated=====");   
      }
      @Modified
      public void modified() {
           System.out.println("=====Service Component is Modified=====");  
      }
      @Reference
      public void setHelloService(HelloService helloService) {
           System.out.println("=====Inside Consumer Component setService()=====");
           System.out.println(helloService.greetHello());   
      }
}



Author

Recent Posts

Recent Posts Widget

Popular Posts