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

Tuesday, October 17, 2017

Liferay DXP/7 BLADE CLI Installation

BLADE CLI is Liferay DXP/7 Application Development Tool to create and deploy Liferay 7 Modules.

As we know that Liferay 7 introduces modularity to develop Liferay applications and BLADE is providing command line interface to create and deploy the application modules into Liferay Portal Module Framework.

BLADE have set of predefined commands to create different types of module to customize or create new features in Liferay Portal Environment.

It is really a different king of experience to develop Liferay OSGi bundles than regular web application development.

Please follow the below articles to know more about BLADE CLI and its commands.


Liferay have provided Liferay Workspace Installer to install BLADE CLI in our local machines. Installer is available for all kinds of OS environments like Windows, Linux and Mac. BLADE CLI is available as part of Liferay Workspace Installer. Liferay Workspace is manage the Liferay Modules and It configuration. We will more details of Liferay Workspace in the future articles.

Note:

Before Liferay Workspace Installer BLADE CLI used the Java Package Manager (JPM) to install BLADE CLI and we have other option as well that is directly download BLADE CLI java JAR file then simply execute using Java JAR command. Liferay Workspace Installer is way to install BLADE CLI and it is recommended.

Java Package Manager(JPM)


Step: 1

Go to following link to download Liferay Workspace Installer.


We can also go to Liferay IDE Download page and Select Liferay Workspace Installer in the Others Download dropdown.


Based on your Operating System download appropriate Installer and run in your machine.
The following screen shows you the Liferay Workspace Installer Download page.




Step: 2

In this example, I am showing for the Windows Operating System. Once you downloaded the Liferay Workspace Installer, double click in file then it open dialog. Click on Next


Step: 3

Here we have option to select directory for initialize the Liferay Workspace. However, here we would like to install only BLDE CLI so just select “Don’t Install Liferay Workspace Directory” then click on next.


Note:

Sometimes you can see the option to select Liferay portal Server. Either we can chose Liferay 7 Community Server bundle Or Liferay DXP server bundle.Select “Liferay Community Server Bundle” as we are using Liferay 7 Community Edition and it is free to use. If you already have Liferay DXP license then select Liferay DXP bundle.

Step: 4

Once you click on Next it will show dialog that “Setup is now to being install” then click on next.



Step: 5

Finally it installed all required thing and it shows finish dialog then click on finish. Now BLADE CLI installation is completed.



Step: 6

Once installation is completed then open Windows Command Prompt and type “blade” then you can list of commands. If you see all these commands, it means BLADE CLI successfully installed otherwise you can see 'blade' is not recognized as an internal or external command.



Now you can play with BLADE CLI commands. You can create and deploy the Liferay DXP/7 modules. Here you can find all available commands.


Note:

In this installation, we only installed BLADE CLI. It is recommended to initializing the Liferay Workspace through installer option. Liferay Workspace has provided the way to manage modules and deploy into different types of run time environment like DEV, UAT and PROD.

BLADE CLI also have command “blade init” to initialize the Liferay Workspace. We can create multiple Liferay Workspace based on our needs.

The following are the list of BLADE CLI commands.


blade convert
blade create
blade deploy
blade gw
blade help.
blade init
blade install
blade open
blade samples
blade server
blade sh
blade update.
blade version



Author

Recent Posts

Recent Posts Widget

Popular Posts