Tuesday, May 12, 2015

Working with Free Marker Templates in Liferay ADT

ADT is great way in Liferay to change the Portlet Display  and we can develop our custom view to the Portlet so that we can change entire look and feel of Portlets without changing the JSP pages.

Go through the Article for More about Liferay ADT


When we are working with ADT we can use Free Marker Templates to change view of Portlet.
This article will give all basics of how to use Free Marker Templates in Liferay ADT.

Some time each Portlet ADT will contain default variables which we can see in the FTL Editor which you can see left side section.




FTL Code Snippets when we work with Liferay ADT

Statement


<#        />


Comment


<#--  This is comment -->


Variable Declaration and Assignment


<#assign name ="meera"/>

<#assign categoryId =100/>


Array Declaration



<#assign cat = [100,101,102] />
 
<#assign selectVocab = ["Department", "Client Scope"] />


Global Variable and Assignment


<#global categoryId =100/>


Print or Output Data


${ name }


IF Statement


<#if categoryId != 0>

<#--  Do something -->

</#if>


If and Else


<#if categoryId != 0>

<#--  Do something -->

<#else>

<#--  Do something -->

</#if>


For Loop


<#assign categoryIds ={13,39,45,10}/>

<#list categoryIds as categoryId>

</#list>


Find something in the object or list


<#if categoryIds?has_content>
           
</#if>


Example loop


<#assign categoryIds ={13,39,45,10}/>
<#if categoryIds?has_content>   
<#list categoryIds as categoryId>
${ categoryId }
</#list>
</#if>


Liferay Tag libraries Import


<#assign aui = taglibLiferayHash["/WEB-INF/tld/aui.tld"] />
<#assign liferay_portlet = taglibLiferayHash["/WEB-INF/tld/liferay-portlet.tld"] />
<#assign liferay_ui = taglibLiferayHash["/WEB-INF/tld/liferay-ui.tld"] />


Create URLs using Tag Libraries


<@liferay_portlet.renderURL var="filterByCategory" windowState="normal">
<@liferay_portlet.param name="mycategoryId" value="100" />
</@liferay_portlet.renderURL>

OR

<@liferay_portlet["renderURL"] var="filterByCategory" windowState="normal">
<@liferay_portlet["param"] name="mycategoryId" value="100" />
</@liferay_portlet["renderURL"]>


Form Elements and From


<@aui.form action="${filterByCategory}" method="post" name="filterForm">
<@aui.input name="categoryName" id="categoryName" type="text" value="" label="Category Name" placeholder="/>
<@aui.select name="mycategoryId" id="mycategoryId" label="Category">
<@aui.option label="Sports" value="100" first="true" />
<@aui.option label="Games" value="101"/>
</@aui.select>
<@aui.button type="submit" value="Submit"></@aui.button>
</@aui.form>

OR

<@aui["form"] action="${filterByCategory}" method="post" name="filterForm">
<@aui["input"] name="categoryName" id="categoryName" type="text" value="" label="Category Name" placeholder="/>
<@aui["select"] name="mycategoryId" id="mycategoryId" label="Category">
<@aui["option"] label="Sports" value="100" first="true" />
<@aui["option"] label="Games" value="101"/>
</@aui["select"]>
<@aui["button"] type="submit" value="Submit"></@aui["button"]>
</@aui["form"]>


Load Static OR Util Class


<#assign ParamUtil = staticUtil["com.liferay.portal.kernel.util.ParamUtil"]/>
<#assign categoryId =ParamUtil.getLong(request,"mycategoryId")/>
${ categoryId }


Load non Static Classes


<#assign assetEntryQuery = objectUtil("com.liferay.portlet.asset.service.persistence.AssetEntryQuery") />
<#assign assignedCategoryIdsNew=assetEntryQuery.getAllCategoryIds()/>


Find the Index of Element in The array


<#assign selectVocab = ["Department", "Client Scope"] />
<#if selectVocab?seq_index_of("Department") gt -1>
<#--  Do something -->
</#if>


Access Liferay Services in FTL


<#assign AssetCategoryLocalService = serviceLocator.findService("com.liferay.portlet.asset.service.AssetCategoryLocalService")>


Note:

To access Liferay Services in FTL we need to use following properties in portal-ext.properties file then only services will be available to the FTL


freemarker.engine.restricted.classes=
freemarker.engine.restricted.variables=


Try Following Code in the Asset Publisher ADT


<#assign aui = taglibLiferayHash["/WEB-INF/tld/aui.tld"] />
<#assign liferay_portlet = taglibLiferayHash["/WEB-INF/tld/liferay-portlet.tld"] />
<#assign liferay_ui = taglibLiferayHash["/WEB-INF/tld/liferay-ui.tld"] />
<#assign queryUtil = staticUtil["com.liferay.portal.kernel.dao.orm.QueryUtil"]/>
<#assign AssetCategoryLocalService = serviceLocator.findService("com.liferay.portlet.asset.service.AssetCategoryLocalService")>
<#assign AssetVocabularyLocalService = serviceLocator.findService("com.liferay.portlet.asset.service.AssetVocabularyLocalService")>
<#assign listVecoblaries = AssetVocabularyLocalService.getGroupVocabularies(themeDisplay.getSiteGroupId())>
<#assign AssetVocabularyLocalService = serviceLocator.findService("com.liferay.portlet.asset.service.AssetVocabularyLocalService")>
<@liferay_portlet.renderURL var="filterByCategory" windowState="normal">
</@liferay_portlet.renderURL>
<@aui.form action="${filterByCategory}" method="post" name="filterForm">
<#if listVecoblaries?has_content>
<#list listVecoblaries as vecobulary>
<@aui.select name="mycategoryId" id="categoryId" label="">
<@aui["option"] label="${vecobulary.getName()}" value="0"/>
<#assign listVecoblaryCategories = AssetCategoryLocalService.getVocabularyRootCategories(vecobulary.getVocabularyId(), queryUtil.ALL_POS, queryUtil.ALL_POS, null)>
<#if listVecoblaryCategories?has_content>
<#list listVecoblaryCategories as category>
<@aui["option"] label="${category.getName()}" value="${category.getCategoryId()}"/>
</#list>
</#if>
</@aui.select>
</#list>
</#if>
<@aui.button type="submit" value="Submit"></@aui.button>
</@aui.form>


When we use above FTL code in Asset Publisher then we can see all vocabularies as Select Box and its categories will become as options in the drop down box.

The following is result view for above FTL



 Author

Friday, April 17, 2015

Liferay Inter Portlet Communication (IPC)

Liferay Inter Portlet Communication (IPC) is mechanism to communicating one Portlet to other Portlet.

JSR 168/ Portlet 1.0 have very limited capability to provide Liferay Inter Portlet Communication (IPC) and its used Portlet Session to share data among Portlets.

JSR 286/Portlet 2.0 has added many ways to support Liferay Inter Portlet Communication (IPC) and it provides better approaches than what JSR 168 is already provided.



Liferay Portal will support all types of Inter Portlet Communication (IPC) that JSR 168 and JSR 286 provided.

When IPC comes into picture we can have two types of Portlets that is Sender Portlets and Receiver Portlets another way we can say Producer Portlets and Consumer Portlets.

Sender/Producer Portlet will send some data that is sharable to other Portlets and 
Consumer/Receiver/Listener Portlets are will receive data which already shared by producer/Sender Portlets. IPC can made with in the page or across the portal

Some of IPC mechanism only possible with in the page means all Portlets should be in the same and some other can support IPC among all Portlets which are in different pages or we can say across portal Portlets.

We have following Types of IPC Mechanisms which Liferay portal can support.

  1. Portlet Sessions IPC
  2. Public Render Parameters IPC
  3. IPC Events
  4. Client Side IPC with AJAX
  5. Client Side IPC with Cookies


From JSR 168/Portlet 1.0 we have feature of Inter Portlet Communication with Portlet Sessions.
Each Portlet have its own session that is called Portlet Session and session data won’t be shared with other Portlets.

To make Inter Portlet Communication with help of Portlet session we will make Portlet session as public so that data will be shared in other Portlets.


Available from JSR 168 and carried to JSR 286

Communication can be possible with in the page and across the portal


Public Render Parameters are the one of the way to make Inter Portlet Communication among the Portlets and these Portlets may be in same page or different pages in the portal.

Public Render Parameters we will define specific parameter in the Portlet with help of that data will be carried from one Portlet to other Portlet and these Public Render Parameters accessible by specific Portlet where we already defined these parameters.

IPC we have two categories of Portlets Sender Portlet and Receiver Portlets. Sender Portlet will send some data or push some data then receiver Portlet will receive the data and will process subsequent steps.

Available from JSR 286

Communication can be possible with in the page and across the portal



IPC Events is one of the ways to make Inter Portlet Communication among the Portlets and these Portlets may be in same page or different pages in the portal.

IPC Events we have two categories of Portlets Event Producer Portlet and Event Listener Portlets. Producer Portlet will send some data or push some data then Listener Portlet will receive the data and will process subsequent steps.

We can have one Producer and Multiple Consumer Portlet will listen the event and process subsequent steps.

Available from JSR 286

Communication can be possible with in the page and across the portal



Client Side Inter Portlet Communication is one of the ways in IPC this can apply the Portlet which reside in same page. Because Client side IPC will uses java script to communicate that’s why all Portlet which participated in IPC need to be in same page.

Liferay already have some java script library to implement client side IPC in Portlet Development.
Available from JSR 286

Communication can be possible with in the page only


Client Side IPC with Cookies

Same Like Client Side IPC with AJAX we can also achieve IPC through browser cookies and data will be stored in cookies and this will be accessed by other portlets and this have some limitation with respect data storage and security wise means I can store very limited data and sometime browsers may disable cookies then communication will be failed among Portlets.

Available from JSR 286

Communication can be possible with in the page only

Suggestible priority order as per my knowledge

  1. IPC Events
  2. Public Render Parameters IPC
  3. Portlet Sessions IPC 
  4. Client Side IPC with AJAX
  5. Client Side IPC with Cookies

Thursday, April 16, 2015

Liferay Inter Portlet Communication with Events

Inter Portlet Communication shortly we can call IPC is the way of making communication among different Portlets which are in same page or reside in other pages.

In the IPC mechanism Portlet will share data among the Portlets and Portlet will work based on the other Portlet.

JSR 168/Portlet 1.0 there is no better Inter Portlet Communication  later in JSR 286/ Portlet 2.0 have added capability of better Inter Portlet Communication with different ways.

IPC Events is one of the ways to make Inter Portlet Communication among the Portlets and these Portlets may be in same page or different pages in the portal.

IPC Events we have two categories of Portlets Event Producer Portlet and Event Listener Portlets. Producer Portlet will send some data or push some data then Listener Portlet will receive the data and will process subsequent steps.

We can have one Producer and Multiple Consumer Portlet will listen the event and process subsequent steps.

Producer Portlet is responsible for generate event when action is performed in it and what are respective Listener Portlets will listen the events that generated by producer Portlet and all these will be configured in the Portlets development that is who is producer and who are the consumers to listen the producer events.

Implement IPC Events

Assume we have Producer Portlet and Listener Portlets from Producer Portlet we will send user email address and send it to Listener Portlet once receiver Portlet get email address then it will show full details of user in the receiver Portlet.

The following are implementation steps

Step: 1

To make Inter Portlet Communication among all Portlets which are reside in same page or across the all the pages we need to update following portal property in portal-ext.properties file.


portlet.event.distribution=layout-set


Default value for portlet.event.distribution is layout and if we not updated this property then IPC will work among Portlets and which are in the same page

Previous versions of Liferay you may use following property


portlet.event.distribution=ALL_PORTLETS


Note:

As we know that portal-ext.properties file was in Liferay Home directory or we can Application Server Parent Directory.

Step: 2

We need to define event definition in the event producer Portlet of portlet.xml file. Portlet container will identify the event producers from this configuration.

Assume we have two Portlets Event Producer and Event Listener and assume Producer is responsible to generate event so we need to define Event publishing configuration in Event Producer Portlet of Portlet.xml file.

The following is configuration should be in portlet.xml file


<portlet-app>
------
<portlet>
<supported-publishing-event xmlns:event="http://www.liferaysavvy.com">
<qname>event:userEmailAddress</qname>
</supported-publishing-event>
</portlet>
-------
<event-definition xmlns:event="http://www.liferaysavvy.com">
<qname>event:userEmailAddress</qname>
<value-type>java.lang.String</value-type>
</event-definition>
-----
</portlet-app>


Note:

Please place the xml tags in right position

Step: 3

Now we need to generate event from Event producer Portlet so we need to generate it from processAction(--) method or our Custom Action Method and this value will be received by the Listener Portlet.

The following is sample code snippet in the “Custom Action Method”


public void getData(ActionRequest actionRequest,
ActionResponse actionResponse) throws IOException, PortletException, SystemException {
String userEmailAddress = ParamUtil.getString(actionRequest,"userEmailAddress");
javax.xml.namespace.QName qName = new javax.xml.namespace.QName("http://www.liferaysavvy.com", "userEmailAddress", "event");
actionResponse.setEvent(qName,userEmailAddress);
}


Step: 4

We also need to define Event Processing configuration in Event Listener Portlet. The Definition we already done in the Event Producer Portlet same configurations need to be replicate in the Event Listener Portlet of portlet.xml file. All listener Portlets should have Event Processing configuration to listen events from event producer.

The following is configuration should be in portlet.xml file


<portlet-app>
------
<portlet>
<supported-processing-event xmlns:event="http://www.liferaysavvy.com">
<qname>event:userEmailAddress</qname>
</supported-processing-event>
</portlet>
-------
<event-definition xmlns:event="http://www.liferaysavvy.com">
<qname>event:userEmailAddress</qname>
<value-type>java.lang.String</value-type>
</event-definition>
</event-definition>
-----
</portlet-app>


Note:

 Please place the xml tags in right position

Step: 5

Finally we need to listen the event in the Event Listener Portlet and here we will receive the values that were set in the Event Producer Portlet.

JSR 286 added new lifecycle method in the Portlet lifecycle that is processEvent(--) method which is used in IPC events implementation and this will  invoke only when IPC implemented among Portlets. We will use simple annotation to process event in the Portlet action class. We can use custom method name for process Event by simply use the @javax.portlet.ProcessEvent annotation.

The following is sample code to listen event in  Event Listent Portlet Action Class


@javax.portlet.ProcessEvent(qname = "{http://www.liferaysavvy.com}userEmailAddress")
public void handleProcesseuserEmailAddressEvent(javax.portlet.EventRequest request, javax.portlet.EventResponse response)
throws javax.portlet.PortletException, java.io.IOException {
javax.portlet.Event event = request.getEvent();
String userEmailAddress = (String)event.getValue();
response.setRenderParameter("userEmailAddress",userEmailAddress);

}


Finally we will render the value in the Portlet JSP page to display data .

Download IPC Event Portlets


Sender Portlet Screen


Receiver Portlet Screen


Inter Portlet Communication between Portlets in the page


Complete Code Example

Event Producer Portlet

Portlet.xml file (/IPCEventProducer-portlet/docroot/WEB-INF/portlet.xml)


<?xml version="1.0"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
version="2.0">

<portlet>
<portlet-name>IPCEventProducerPortlet</portlet-name>
<display-name>IPCEventProducerPortlet</display-name>
<portlet-class>
com.meera.liferay.ipc.events.IPCEventProducerPortletAction
</portlet-class>
<init-param>
<name>view-template</name>
<value>/html/ipcevents/view.jsp</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<portlet-info>
<title>IPCEventProducerPortlet</title>
<short-title>IPCEventProducerPortlet</short-title>
<keywords></keywords>
</portlet-info>
<security-role-ref>
<role-name>administrator</role-name>
</security-role-ref>
<security-role-ref>
<role-name>guest</role-name>
</security-role-ref>
<security-role-ref>
<role-name>power-user</role-name>
</security-role-ref>
<security-role-ref>
<role-name>user</role-name>
</security-role-ref>
<supported-publishing-event xmlns:event="http://www.liferaysavvy.com">
<qname>event:userEmailAddress</qname>
</supported-publishing-event>
</portlet>
<event-definition xmlns:event="http://www.liferaysavvy.com">
<qname>event:userEmailAddress</qname>
<value-type>java.lang.String</value-type>
</event-definition>
</portlet-app>


View.jsp (/IPCEventProducer-portlet/docroot/html/ipcevents/view.jsp)


<%@ taglib uri="http://liferay.com/tld/portlet" prefix="liferay-portlet"%>
<%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme"%>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui"%>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui"%>
<portlet:defineObjects />
<liferay-theme:defineObjects />
<portlet:actionURL var="sendDataActionURL" windowState="normal"
     name="getData">
</portlet:actionURL>
<h1>IPC Events Producer Portlet</h1>
<aui:form action="<%=sendDataActionURL%>" method="post" name="smsForm">
<aui:input name="userEmailAddress" id="userEmailAddress" label="User Email Address">
     <aui:validator name="required" />
     <aui:validator name="email"></aui:validator>
</aui:input>
<aui:button type="submit" value="Submit"></aui:button>
</aui:form>


Portlet Action Class (IPCEventProducerPortletAction.java)


package com.meera.liferay.ipc.events;
import java.io.IOException;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletSession;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.util.bridges.mvc.MVCPortlet;
public class IPCEventProducerPortletAction extends MVCPortlet {

public void getData(ActionRequest actionRequest,
ActionResponse actionResponse) throws IOException, PortletException, SystemException {
String userEmailAddress = ParamUtil.getString(actionRequest,"userEmailAddress");
javax.xml.namespace.QName qName = new javax.xml.namespace.QName("http://www.liferaysavvy.com", "userEmailAddress", "event");
actionResponse.setEvent(qName,userEmailAddress);
}
}


Event Listener Portlet

Portlet.xml (/IPCEventListener-portlet/docroot/WEB-INF/portlet.xml)


<?xml version="1.0"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
version="2.0">
<portlet>
<portlet-name>IPCEventListenerPortlet</portlet-name>
<display-name>IPCEventListenerPortlet</display-name>
<portlet-class>
com.meera.liferay.ipc.events.IPCEventListenerPortletAction</portlet-class>
<init-param>
<name>view-template</name>
<value>/html/ipcevents/view.jsp</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>view</portlet-mode>
</supports>
<portlet-info>
<title>IPCEventListenerPortlet</title>
<short-title>IPCEventListenerPortlet</short-title>
<keywords></keywords>
</portlet-info>
<security-role-ref>
<role-name>administrator</role-name>
</security-role-ref>
<security-role-ref>
<role-name>guest</role-name>
</security-role-ref>
<security-role-ref>
<role-name>power-user</role-name>
</security-role-ref>
<security-role-ref>
<role-name>user</role-name>
</security-role-ref>
<supported-processing-event xmlns:event="http://www.liferaysavvy.com">
<qname>event:userEmailAddress</qname>
</supported-processing-event>
</portlet>
<event-definition xmlns:event="http://www.liferaysavvy.com">
<qname>event:userEmailAddress</qname>
<value-type>java.lang.String</value-type>
</event-definition>
</portlet-app>


View.jsp (/IPCEventListener-portlet/docroot/html/ipcevents/view.jsp)


<%@page import="javax.portlet.PortletSession"%>
<%@page import="com.liferay.portal.NoSuchUserException"%>
<%@page import="com.liferay.portal.service.UserLocalServiceUtil"%>
<%@page import="com.liferay.portal.model.User"%>
<%@page import="com.liferay.portal.kernel.util.ParamUtil"%>
<%@ taglib uri="http://liferay.com/tld/portlet" prefix="liferay-portlet"%>
<%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme"%>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui"%>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui"%>
<portlet:defineObjects />
<liferay-theme:defineObjects />
<h1>Receive User Data from Events Producer in Listener Portlet</h1>

<%
String message=null;
String userEmailAddress=ParamUtil.getString(renderRequest,
"userEmailAddress",null);
User senderPortletUserOject=null;
try{
if(userEmailAddress!=null){
senderPortletUserOject=
UserLocalServiceUtil.getUserByEmailAddress(themeDisplay.getCompanyId(), userEmailAddress);
}
}catch(NoSuchUserException e){
message="No User exists with the given Email Address.";
}catch(Exception e){
message="There is problem in view the user details.";
}

if(senderPortletUserOject!=null){
%>
<table border="1">
<tr>
<td>User Id</td>
<td><%=senderPortletUserOject.getUserId()%></td>
</tr>
<tr>
<td>First Name</td>
<td><%=senderPortletUserOject.getFirstName()%></td>
</tr>
<tr>
<td>Last Name</td>
<td><%=senderPortletUserOject.getLastName()%></td>
</tr>
<tr>
<td>Email Address</td>
<td><%=senderPortletUserOject.getEmailAddress()%></td>
</tr>
<tr>
<td>Screen Name</td>
<td><%=senderPortletUserOject.getScreenName()%></td>
</tr>
</table>

<%}else{%>
<%=message%>
<%}%>


Portlet Action Class (IPCEventListenerPortletAction.java)


package com.meera.liferay.ipc.events;
import com.liferay.util.bridges.mvc.MVCPortlet;
public class IPCEventListenerPortletAction extends MVCPortlet {
@javax.portlet.ProcessEvent(qname = "{http://www.liferaysavvy.com}userEmailAddress")
public void handleProcesseuserEmailAddressEvent(javax.portlet.EventRequest request, javax.portlet.EventResponse response)
throws javax.portlet.PortletException, java.io.IOException {
javax.portlet.Event event = request.getEvent();
String userEmailAddress = (String)event.getValue();
response.setRenderParameter("userEmailAddress",userEmailAddress);

}
}



Popular Posts

Recent Posts

Recent Posts Widget