Saturday, October 21, 2017

Differences between Liferay Module and Liferay Plugin

The objective of this article is providing the major differences between Liferay Module and Liferay Plugin.

Before understand difference we must have basic idea of OSGi and Liferay 7 Fundamentals.
Follow Liferay DXP/7 Tutorial to get more information.




Liferay Modules
Liferay Plugins

Introduced in Liferay 7

Introduced since Liferay Started.
From Liferay 4.x to Liferay 7/DXP


Liferay Modules are based on OSGi framework

Liferay Plugins based traditional Java web application framework. Like we use more J2EE web application Frameworks.


Liferay Module will run in OSGi Run Time Environment.


Liferay Plugins run in Traditional Application Servers such as Tomcat, JBoss , Glassfish


Liferay Module we can call it as OSGi bundles and packaged as JAR file.


Liferay Plugins are web applications and packaged as WAR files.

Liferay Module provides the dynamic component injection with help OSGi so that we can make most of the features as independent components and can easily inject into the other components when it required.


Liferay plugins are like independent web applications we cannot share anything between two web applications. It is more coupled. If we want share some classes we have to put these jar files in some global class loaders then only other web application can use that classes.


We can avoid all the problems of class loader issues.


We can see more class loader issues.

No Class Definition Found, Class Not Found Run time errors completely vanished in the runtime.


We frequently experience No Class Definition Found, Class Not Found Run time errors in the runtime.


Liferay Modules have different types like Portlet Modules, Hook Modules.
Themes and Layouts partially support modularity.


Liferay plugins have different types such as portlets, themes, ext, layout and hooks.

Liferay Modules developed based on OSGi Framework and it used the several framework to develop modules such as Declarative Services (DS), Apache Blueprint and OSGi API.


Liferay Plugins uses the J2EE web application frameworks such as Struts, Spring, Liferay MVC, JSF and other web application frameworks.


Liferay Modules followed 3-tier architecture application development such as Persistence, Service and Presentation layered architecture.


Liferay Plugins uses the same 3-tier architecture application development such as Persistence, Service and Presentation layers architecture.


Usually Liferay Module development we separated each Layer as Independent Modules
Persistence Tier Module
Service Tier Module
Web Tier Module


Liferay Plugins Development all 3 tiers packaged as single WAR file.

Liferay Modules support the dynamic deployment feature and we can stop and start module without un-deploy the module.


Liferay Plugins we must un-deploy the war file from server to remove features.


Liferay Modules uses the Apache Gogo shell Command Line Interface (CLI) to manage the Liferay Modules in the OSGi run time environment. Like stop, start, activate and deactivate.

Liferay Portal Admin screen also have to manage these Liferay modules.


Liferay plugins does not have any Command Line Interface to un-deploy the bundles and we have to removed plugin war files from servers.

Some Enterprise Application Servers have administrative feature to do these things.

Liferay Portal Admin screen also have option to manage these Liferay plugins.



Liferay modules are available in Liferay Portal Server Bundle inside OSGI directory once the module is deployed.


All Liferay Plugins are available in Liferay Portal Server webapps directory.

Liferay Module have important configuration file METAINF which is like module deployment configuration file have more information used by OSGi run time environment.


Liferay Plugins have web.xml file and used by Portlet/Servlet containers.


Liferay portlet module all xml configuration files information turn into Declarative Services (DS) Component properties. Like portlet.xml, liferay-portlet.xml and liferay-display.xml files tags and values.



Liferay Plugins used the XML configuration such as portlet.xml, liferay-portlet.xml and liferay-display.xml

If the Liferay Application have more features then we divided into multiple independent modules and these modules can communicate each other very easy in OSGi environment.


Modularity is not that easy in Liferay Plugins development so we have to keep all the files in single WAR file.

Liferay Module introduced new tool called BLADE CLI to develop Liferay Modules.


Liferay Plugins have Plugins SDK to develop Liferay Applications.


Liferay Modules have several tools such as Liferay IDE, Liferay Studio, BLADE CLI


Liferay Plugins have tools such as Liferay IDE, Liferay Studio.


Liferay Module support GRADLE and MAVEN build environment.


Liferay Plugins support ANT and MAVEN build environment.


Liferay Modules used the Liferay Workspace concept to manage the application and its configuration across the platforms.


Liferay Plugins uses the Plugins SDK to develop and manage the plugins.


Liferay Modules used the OSGi API, Declarative Services and Apache Blueprint framework. So we have limited choice to use popular we application framework like Spring. Liferay still not fully supporting Spring Modules, it means we have to use the WAR deployment.



We can use any J2EE popular web application frameworks such as Spring, Struts and JSF.

Liferay Modules provides the Micro services Architecture based applications.


To bring Micro services Architecture we have to depend on other frameworks such as Spring Micro Services.


Liferay Modules have dynamic component development feature so we can easily turn on and off the feature at any point of time with minimal effort.


Liferay Plugins not like Dynamic Component Development so bunch of feature in one plugin application. If we remove one plugin, it can turn off many features.


Liferay Modules can provide easy way deployment process and we can move easily from one environment to other with minimal effort. Liferay Workspace provided this capability.



Liferay Plugin Deployment process and moving from one environment to other tedious. We do not have any special mechanism like Liferay Workspace.

Liferay Modules uses the Bndtools to develop and build the modules. We have BLADE CLI, Liferay IDE, GRADLE and MAVEN are used the Bndtools internally.



Liferay Plugins follow the J2EE web application development so MAVEN Liferay Plugin or Liferay IDE handle the Development and Deployment.



Author

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