Monday, May 25, 2015

Liferay ADT Implementation for Custom Portlet

Liferay Application Display Templates (ADT) is great way to change Portlet view dynamically without changing JSP pages code.

Liferay ADT use the Free Marker/Velocity Templates to change Portlet view dynamically and this can be done by Liferay administrator from Site Administration.

By Default Liferay have given ADT capability for few Portlets which are in Liferay portal and we can change Portlets views dynamically by using velocity/free marker templates.

Follow below Article Know about ADT



Liferay have given ADT API to implement ADT support for Out of Box Portlet that is Custom Portlets.

Generally what are the variables or elements which required in view logic we will group it and will be stored in template engine and whenever we need in views we simply use reference names to access the variables or elements from template engine and all these mechanism was implemented in Liferay ADT API so that we can implement ADT Support to custom Portlets.

Liferay Have Template Handler which will take care of the groping variables and store into template engine and at the time of render we will use reference variable to access data from template engine and these template engine are velocity or free marker that is why we will use velocity/free marker templates in the ADT to change Portlet display dynamically.

Implementation ADT Support to Custom Portlet
  1. Create Liferay MVC Portlet
  2. Implement Portlet Display Template Handler Java Class
  3. Register Portlet Display Template Handler Java Class
  4. Implement ADD_PORTLET_DISPLAY_TEMPLATE Permission to Custom Portlet
  5. Implement Configuration View to Portlet
  6. Implement View Logic to Read Configured Templates

Create Liferay MVC Portlet

Creating Liferay MVC Portlet is very straight forward step and you can use Liferay IDE to create Liferay MVC Portlet.


Implement Portlet Display Template Handler Java Class

To handle template variables we will use Portlet Display Template Handler java class from ADT API and it will take care the template variables which are required in the portlet display and these variables we will defined in the Portlet Display Template Handler class.

We need to implement Custom Portlet Display Template Handler class that should extend the BasePortletDisplayTemplateHandler.

BasePortletDisplayTemplateHandler java class consist many methods so we will override some of the methods in the Custom Portlet Display Template Handler class

The following are methods

getClassName(): This will defined what type of entries you are rendering  and typically its model class name(Student.class, Employee.class)

getName(): Declares the name of your ADT type (typically, the name of the portlet).

getResourceName(): Specifies which resource is using the ADT (e.g. a portlet) for permission checking.

 getTemplateVariableGroups(): Defines the variables exposed in the template editor.

The following is Example Implementation


public class ADTPOCPortletDisplayTemplateHandler extends
BasePortletDisplayTemplateHandler {

@Override
public String getClassName() {
// TODO Auto-generated method stub
return Student.class.getName();
}

@Override
public String getName(Locale arg0) {
// TODO Auto-generated method stub
return "ADTPOC Template";
}

@Override
public String getResourceName() {
// TODO Auto-generated method stub
return "ADTPOC_WAR_ADTPOCportlet";
}

public Map<String, TemplateVariableGroup> getTemplateVariableGroups(
long classPK, String language, Locale locale)
throws Exception {

Map<String, TemplateVariableGroup> templateVariableGroups =
super.getTemplateVariableGroups(classPK, language, locale);

TemplateVariableGroup templateVariableGroup =
templateVariableGroups.get("fields");

templateVariableGroup.empty();

templateVariableGroup.addCollectionVariable(
"students", List.class, PortletDisplayTemplateConstants.ENTRIES,
"student", Student.class, "curStudent", "name");
return templateVariableGroups;
}
}


Register Portlet Display Template Handler Java Class

We already implemented Custom Register Portlet Display Template Handler Java ClassAnd now we need to register this class name so that Portlet will get ADT Capability to do this we will use Liferay-portlet.xml file configuration file where we need to configure Custom Portlet Display Template Handler Java Class and <template-handler/> is tag which should be enclosed by <portlet/>

The following is example Configuration


<portlet>
<portlet-name>ADTPOC</portlet-name>
<icon>/icon.png</icon>
<configuration-action-class>com.adt.poc.config.ADTPOCConfigImpl</configuration-action-class>
<template-handler>com.adt.poc.template.ADTPOCPortletDisplayTemplateHandler
</template-handler>

<header-portlet-css>/css/main.css</header-portlet-css>
<footer-portlet-javascript>/js/main.js</footer-portlet-javascript>
<css-class-wrapper>ADTPOC-portlet</css-class-wrapper>
</portlet>

Implement “ADD_PORTLET_DISPLAY_TEMPLATE” Permission to Custom Portlet

Since the ability to add ADTs is new to your portlet, we need to configure permissions so that administrative users can grant permissions to the roles that will be allowed to create and manage display templates. Just add the action key ADD_PORTLET_DISPLAY_TEMPLATE to your portlet’s docroot/WEB-INF/src/resource-actions/default.xml file


<?xml version="1.0"?>
<!DOCTYPE resource-action-mapping
PUBLIC "-//Liferay//DTD Resource Action Mapping 6.2.0//EN" "http://www.liferay.com/dtd/liferay-resource-action-mapping_6_2_0.dtd">
<resource-action-mapping>
<portlet-resource>
<portlet-name>ADTPOC</portlet-name>
<permissions>
<supports>
<action-key>ADD_PORTLET_DISPLAY_TEMPLATE</action-key>
<action-key>ADD_TO_PAGE</action-key>
<action-key>CONFIGURATION</action-key>
<action-key>VIEW</action-key>
</supports>
<site-member-defaults>
<action-key>VIEW</action-key>
</site-member-defaults>
<guest-defaults>
<action-key>VIEW</action-key>
</guest-defaults>
<guest-unsupported>
<action-key>CONFIGURATION</action-key>
</guest-unsupported>
</permissions>
</portlet-resource>
</resource-action-mapping>


Implement Configuration View to Portlet

To provide ADT Templet editor to create new ADT templates will use Liferay Configuration page where we will provide template editor code so that when we add new templates to Portlet, where you can  see all  defined variables.

Follow the Article to Implement Portlet Configuration


Now Portlet configuration page(config.jsp) we need to add following code so that it will provide template editor while design templates and these can be accessed through Portlet configuration option by administrator.< liferay-ui:ddm-template-selector/>  is tag which will take care all.

The following is example code in config.jsp page


<%@page import="com.liferay.portal.kernel.util.Constants"%>
<%@page import="com.liferay.portal.util.PortalUtil"%>
<%@ include file="init.jsp" %>
<%@page import="com.adt.poc.model.Student"%>
<%@page import="com.liferay.portal.kernel.template.TemplateHandlerRegistryUtil"%>
<%@page import="com.liferay.portal.kernel.template.TemplateHandler"%>
<liferay-portlet:actionURL portletConfiguration="true" var="configurationURL" />
<aui:form action="<%= configurationURL %>" method="post" name="fm">
<aui:input name="<%= Constants.CMD %>" type="hidden" value="<%= Constants.UPDATE %>" />
<aui:fieldset>
<div class="display-template">
<%
TemplateHandler templateHandler = TemplateHandlerRegistryUtil.getTemplateHandler(Student.class.getName());
%>
<liferay-ui:ddm-template-selector
classNameId="<%= PortalUtil.getClassNameId(templateHandler.getClassName()) %>"
displayStyle="<%= displayStyle %>"
displayStyleGroupId="<%= displayStyleGroupId %>"
refreshURL="<%= PortalUtil.getCurrentURL(request) %>"
showEmptyOption="<%= true %>"
/>
</div>
</aui:fieldset>
<aui:button type="submit" name="submit"></aui:button>
</aui:form>


Implement View Logic to Render Configured Templates

Now we need to provide logic that will render configure templates to change Portlet view and this we will write in default view page of Portlet.

When the ADT template is configures to Portlet then it will render the configured template otherwise it will render default view.

The following is sample code.


<%@page import="java.util.ArrayList"%>
<%@page import="com.adt.poc.model.Student"%>
<%@page import="java.util.List"%>
<%@ include file="init.jsp" %>

This is the <b>Location Listing Portlet</b> in View mode.
<%
List<Student> students = new ArrayList<Student>();
for(int i=1; i<10; i++){
Student student = new Student();
student.setId(i);
student.setName("name"+i);
student.setCity("city"+i);
students.add(student);
}
%>
<%=portletDisplayDDMTemplateId%>
<c:choose>
<c:when test="<%= portletDisplayDDMTemplateId > 0 %>">
<%= PortletDisplayTemplateUtil.renderDDMTemplate(pageContext, portletDisplayDDMTemplateId, students) %>
</c:when>
<c:otherwise>
<table border="1">
<tr><th>Name</th><th>city</th></tr>

<%
for(Student student:students){%>
<tr><td><%=student.getName()%></td>
<td><%=student.getCity()%></td></tr>
<%} %>
</table>
</c:otherwise>
</c:choose>


Download ADT Implemented Custom Portlet


ADT Implementation in Custom Portlet Complete Example

In the example used Dummy Model class Student.java and while create Student object simply use for loop to create student object and these will be available as entries in the templates at the time of create new templates for Portlet display.

ADTPOCPortletDisplayTemplateHandler.java


package com.adt.poc.template;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import com.adt.poc.model.Student;
import com.liferay.portal.kernel.language.LanguageUtil;
import com.liferay.portal.kernel.portletdisplaytemplate.
BasePortletDisplayTemplateHandler;
import com.liferay.portal.kernel.template.TemplateVariableGroup;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portlet.portletdisplaytemplate.util.
PortletDisplayTemplateConstants;
public class ADTPOCPortletDisplayTemplateHandler extends
BasePortletDisplayTemplateHandler {

@Override
public String getClassName() {
// TODO Auto-generated method stub
return Student.class.getName();
}

@Override
public String getName(Locale arg0) {
// TODO Auto-generated method stub
return "ADTPOC Template";
}

@Override
public String getResourceName() {
// TODO Auto-generated method stub
return "ADTPOC_WAR_ADTPOCportlet";
}

public Map<String, TemplateVariableGroup> getTemplateVariableGroups(
long classPK, String language, Locale locale)
throws Exception {

Map<String, TemplateVariableGroup> templateVariableGroups =
super.getTemplateVariableGroups(classPK, language, locale);

TemplateVariableGroup templateVariableGroup =
templateVariableGroups.get("fields");

templateVariableGroup.empty();

templateVariableGroup.addCollectionVariable(
"students", List.class, PortletDisplayTemplateConstants.ENTRIES,
"student", Student.class, "curStudent", "name");
return templateVariableGroups;
}
}


liferay-portlet.xml (/ADTPOC-portlet/docroot/WEB-INF/liferay-portlet.xml)


<?xml version="1.0"?>
<!DOCTYPE liferay-portlet-app
PUBLIC "-//Liferay//DTD Portlet Application 6.2.0//EN" "http://www.liferay.com/dtd/liferay-portlet-app_6_2_0.dtd">

<liferay-portlet-app>
<portlet>
<portlet-name>ADTPOC</portlet-name>
<icon>/icon.png</icon>
<configuration-action-class>com.adt.poc.config.ADTPOCConfigImpl</configuration-action-class>
<template-handler>com.adt.poc.template.ADTPOCPortletDisplayTemplateHandler
</template-handler>

<header-portlet-css>/css/main.css</header-portlet-css>
<footer-portlet-javascript>/js/main.js</footer-portlet-javascript>
<css-class-wrapper>ADTPOC-portlet</css-class-wrapper>
</portlet>
<role-mapper>
<role-name>administrator</role-name>
<role-link>Administrator</role-link>
</role-mapper>
<role-mapper>
<role-name>guest</role-name>
<role-link>Guest</role-link>
</role-mapper>
<role-mapper>
<role-name>power-user</role-name>
<role-link>Power User</role-link>
</role-mapper>
<role-mapper>
<role-name>user</role-name>
<role-link>User</role-link>
</role-mapper>
</liferay-portlet-app>


default.xml (docroot/WEB-INF/src/resource-actions/default.xml)


<?xml version="1.0"?>
<!DOCTYPE resource-action-mapping
PUBLIC "-//Liferay//DTD Resource Action Mapping 6.2.0//EN" "http://www.liferay.com/dtd/liferay-resource-action-mapping_6_2_0.dtd">
<resource-action-mapping>
<portlet-resource>
<portlet-name>ADTPOC</portlet-name>
<permissions>
<supports>
<action-key>ADD_PORTLET_DISPLAY_TEMPLATE</action-key>
<action-key>ADD_TO_PAGE</action-key>
<action-key>CONFIGURATION</action-key>
<action-key>VIEW</action-key>
</supports>
<site-member-defaults>
<action-key>VIEW</action-key>
</site-member-defaults>
<guest-defaults>
<action-key>VIEW</action-key>
</guest-defaults>
<guest-unsupported>
<action-key>CONFIGURATION</action-key>
</guest-unsupported>
</permissions>
</portlet-resource>
</resource-action-mapping>



config.jsp (/docroot/config.jsp)


<%@page import="com.liferay.portal.kernel.util.Constants"%>
<%@page import="com.liferay.portal.util.PortalUtil"%>
<%@ include file="init.jsp" %>
<%@page import="com.adt.poc.model.Student"%>
<%@page import="com.liferay.portal.kernel.template.TemplateHandlerRegistryUtil"%>
<%@page import="com.liferay.portal.kernel.template.TemplateHandler"%>
<liferay-portlet:actionURL portletConfiguration="true" var="configurationURL" />
<aui:form action="<%= configurationURL %>" method="post" name="fm">
<aui:input name="<%= Constants.CMD %>" type="hidden" value="<%= Constants.UPDATE %>" />

<aui:fieldset>
<div class="display-template">

<%
TemplateHandler templateHandler = TemplateHandlerRegistryUtil.getTemplateHandler(Student.class.getName());
%>

<liferay-ui:ddm-template-selector
classNameId="<%= PortalUtil.getClassNameId(templateHandler.getClassName()) %>"
displayStyle="<%= displayStyle %>"
displayStyleGroupId="<%= displayStyleGroupId %>"
refreshURL="<%= PortalUtil.getCurrentURL(request) %>"
showEmptyOption="<%= true %>"
/>
</div>
</aui:fieldset>
<aui:button type="submit" name="submit"></aui:button>
</aui:form>


ADTPOCConfigImpl.java (src/com/adt/poc/config/ADTPOCConfigImpl.java)


package com.adt.poc.config;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletConfig;
import com.liferay.portal.kernel.portlet.DefaultConfigurationAction;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portlet.PortletPreferencesFactoryUtil;

public class ADTPOCConfigImpl extends DefaultConfigurationAction {
@Override
public void processAction(PortletConfig portletConfig,
ActionRequest actionRequest, ActionResponse actionResponse)
throws Exception {
// TODO Auto-generated method stub
String portletResource = ParamUtil.getString(actionRequest, "portletResource");
javax.portlet.PortletPreferences prefs = PortletPreferencesFactoryUtil.getPortletSetup(actionRequest, portletResource);
String displayStyle = ParamUtil.getString(actionRequest, "displayStyle");
prefs.setValue("displayStyle", displayStyle);
prefs.store();
super.processAction(portletConfig, actionRequest, actionResponse);
}
}


view.jsp(docroot/view.jsp)


<%@page import="java.util.ArrayList"%>
<%@page import="com.adt.poc.model.Student"%>
<%@page import="java.util.List"%>
<%@ include file="init.jsp" %>

This is the <b>Location Listing Portlet</b> in View mode.
<%
List<Student> students = new ArrayList<Student>();
for(int i=1; i<10; i++){
Student student = new Student();
student.setId(i);
student.setName("name"+i);
student.setCity("city"+i);
students.add(student);
}
%>
<%=portletDisplayDDMTemplateId%>
<c:choose>
<c:when test="<%= portletDisplayDDMTemplateId > 0 %>">
<%= PortletDisplayTemplateUtil.renderDDMTemplate(pageContext, portletDisplayDDMTemplateId, students) %>
</c:when>
<c:otherwise>
<table border="1">
<tr><th>Name</th><th>city</th></tr>

<%
for(Student student:students){%>
<tr><td><%=student.getName()%></td>
<td><%=student.getCity()%></td></tr>
<%} %>
</table>
</c:otherwise>
</c:choose>


init.jsp (docroot/init.jsp)


<%@page import="com.liferay.portal.kernel.util.StringPool"%>
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %>
<%@taglib uri="http://liferay.com/tld/portlet" prefix="liferay-portlet" %>
<%@taglib uri="http://liferay.com/tld/security" prefix="liferay-security" %>
<%@taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %><%@
taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>
<%@taglib uri="http://liferay.com/tld/util" prefix="liferay-util" %>
<%@page import="com.liferay.portlet.portletdisplaytemplate.util.
PortletDisplayTemplateUtil"%>
<%@page import="com.liferay.portal.kernel.util.GetterUtil"%>

<portlet:defineObjects />

<liferay-theme:defineObjects />
<%
String displayStyle = 
 GetterUtil.getString(portletPreferences.getValue("displayStyle", StringPool.BLANK));
long displayStyleGroupId = GetterUtil.getLong(portletPreferences.getValue("displayStyleGroupId", null), scopeGroupId);

long portletDisplayDDMTemplateId = PortletDisplayTemplateUtil.getPortletDisplayTemplateDDMTemplateId
(displayStyleGroupId, displayStyle);

boolean showLocationAddress_view = GetterUtil.getBoolean(portletPreferences.getValue("showLocationAddress", StringPool.TRUE));
%>


Usage of Portlet

Deploy Portlet into you portal server

After successful deployment you can see the Portlet in sample category

Login as Admin and Drag and Drop Portlet in the page

The following is Default view of Portlet


Now go to Docbar Admin tab and click on Site Configuration


Configuration section you can see Application Display Templates click on it


Now you can Add new ADT for our Custom Portlet by Select Custom Portlet from Add Button Icon and Select Our Custom Portlet


Once we click on Add then it will launch Template Editor there we need to design New Display to Custom Portlet By using Free Marker/Velocity Templates. Once you design view then click on save then new ADT Template will be created for Custom Portlet



 Now go to Portlet Configuration


In Setup tab you can see Display Template Drop down there you can select our newly created Custom Portlet ADT then save it.



Once you apply new ADT then Portlet Display will be changed such way you can create many Displays to custom Portlet using ADT.

Author

Recent Posts

Recent Posts Widget

Popular Posts