Thursday, November 11, 2010

creating layout in ext environment in liferay

Hi today I want to share how to create layout in ext environment in liferay. Though it should not be used as ext environment is hard to manage but some times we don't want to maintain seperate development environment (plugin) in that case it can be used.
Here are the steps:
Step 1:
In ext-web\docroot\WEB-INF create a file name liferay-layout-templates-ext.xml

Step 2:
Open file liferay-layout-templates-ext.xml and put code

<?xml version="1.0"?>
<!DOCTYPE layout-templates PUBLIC "-//Liferay//DTD Layout Templates 5.2.0//EN" "http://www.liferay.com/dtd/liferay-layout-templates_5_2_0.dtd">

<layout-templates>
<custom>
<layout-template id="4_2_columns" name="custom(4-2)">
<template-path>
/layouttpl/customlayout/4_2_columns.tpl
</template-path>
<wap-template-path>
/layouttpl/customlayout/4_2_columns.wap.tpl
</wap-template-path>
<thumbnail-path>
/layouttpl/customlayout/4_2_columns.png
</thumbnail-path>
</layout-template>
</custom>
</layout-templates>

This is file where your mapping goes regarding .tpl files used to create your layout.

Step 3:Make a layouttpl folder at same level as html folder in ext-web. Inside this folder make customlayout folder.

Step 4:Now in customlayout folder you need to keep your .png and .tpl files related to layout as per the mapping .Now create a files with name 4_2_columns.tpl and 4_2_columns.wap.tpl in customlayout folder and put below code.


<div class="columns-2" id="content-wrapper">
<table class="lfr-grid" id="layout-grid">
<tr>
<td class="lfr-column thirty" id="column-1" width="25%" valign="top">
$processor.processColumn("column-1")
</td>
<td class="lfr-column thirty" id="column-2" width="25%" valign="top">
$processor.processColumn("column-2")
</td>
<td class="lfr-column thirty" id="column-3" width="25%" valign="top">
$processor.processColumn("column-3")
</td>
<td class="lfr-column thirty" id="column-4" width="25%" valign="top">
$processor.processColumn("column-4")
</td>
</tr>
<tr>
<td colspan="4"><div style="border-bottom: 3px dotted #405DD5;"></div></td>
</tr>
<tr>
<td colspan="4">
<table class="lfr-grid" id="layout-grid">
<tr>
<td class="lfr-column thirty" id="column-5" valign="top">
$processor.processColumn("column-5")
</td>
<td class="lfr-column seventy" id="column-6" valign="top">
$processor.processColumn("column-6")
</td>
</tr>
</table>
</td>
</tr>
</table>
</div>


and in 4_2_columns.wap.tpl put below code

<table>
<tr>
<td>
$processor.processColumn("column-1")
</td>
<td>
$processor.processColumn("column-2")
</td>
<td>
$processor.processColumn("column-3")
</td>
<td>
$processor.processColumn("column-4")
</td>
<td>
$processor.processColumn("column-5")
</td>
<td>
$processor.processColumn("column-6")
</td>
</tr>
</table>

Now do ant deploy from ext-web and start the server after successful deployment. In dock in Layout Template you will get new layout. add it and see.
That's all.

Thursday, October 7, 2010

getting url parameter value in liferay

Hi All,
If we set url parameter value in normal jsp page like $some_url$?abc=ok. Then normally we can get value using request.getParameter("abc"); very simple.But in liferay I tried it was not working, then how to do in liferay?? not as simple as
request.getParameter("abc"); but little more code. Taking above example
HttpServletRequest httpReq = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(renderRequest));
String abc = httpReq.getParameter("abc");

So we will get desired result.
Hope this helps others.

Thursday, September 23, 2010

popup on popup in liferay

To implement popup on popup in liferay is quite simple. We need to have 2 pages one parent page on which 1st popup is already opened and 2nd page which will be opened in 2nd popup.

For 1st page call:
function parentPage(url) {
var popup = Liferay.Popup(
{
stack: true,
draggable:false,
title: 'Parent Page',
position:[110,50],
modal:true,
width:450,
height:365,
url:url
}
);
}
here stack:true property is important which is responsible for pop on popup.url is which page we want to load . It can be portlet url. Other parameters are self explanatory.

In child page you can simply write another popup.

function childPage(url) {
var popup = Liferay.Popup(
{

title: 'Child Page',
position:[110,50],
modal:true,
width:450,
height:365,
url:url
}
);
}

Thanks and Hope this help few people.

Wednesday, August 4, 2010

orderable search container in liferay by example

Liferay provide us with many good taglib out of them search container is one of them.It is widely used taglib. For simple understanding of search container please check Wiki here is the link Wiki Search Container. One thing that article is missing how to implement ordering using. For that we will follow few step and will do a simple example.
Step 1: Read the wiki article Search Container.
Step 2:Now write the below code in your jsp.

<%
PortalPreferences portalPrefs = PortletPreferencesFactoryUtil.getPortalPreferences(request);
String orderByCol = ParamUtil.getString(request, "orderByCol");

String orderByType = ParamUtil.getString(request, "orderByType");

if (Validator.isNotNull(orderByCol) && Validator.isNotNull(orderByType)) {
portalPrefs.setValue("KK_3", "kk-order-by-col", orderByCol);
portalPrefs.setValue("KK_3", "kk-order-by-type", orderByType);

} else {

orderByCol = portalPrefs.getValue("KK_3", "kk-order-by-col", "name");
orderByType = portalPrefs.getValue("KK_3", "kk-order-by-type", "asc");

}

OrderByComparator orderByComparator = AddressBookUtil.getAddressBookOrderByComparator(orderByCol, orderByType);
%>


Now I will explain what is happening we are getting the column on which we have to do ordering in orderByCol and order asc or desc in orderByType.
In line portalPrefs.setValue("KK_3", "kk-order-by-col", orderByCol);
here "KK_3" is namespace , "kk-order-by-col" is key and orderByCol is value.
In last line OrderByComparator orderByComparator = AddressBookUtil.getAddressBookOrderByComparator(orderByCol, orderByType);
For this you need to write a comparator , I have written it in com.ext.portlet.addressBook.util.AddressBookUtil and write this code


public class AddressBookUtil {

/**
*
* @param orderByCol
* @param orderByType
* @return
*/

public static OrderByComparator getAddressBookOrderByComparator(
String orderByCol, String orderByType) {

boolean orderByAsc = false;

if (orderByType.equals("asc")) {
orderByAsc = true;
}

OrderByComparator orderByComparator = null;

if (orderByCol.equals("name")) {
orderByComparator = new AddressBookNameComparator(orderByAsc);
} else if (orderByCol.equals("status")) {
orderByComparator = new AddressBookStatusComparator(orderByAsc);
}

return orderByComparator;
}

}

Now in same package write AddressBookNameComparator and AddressBookStatusComparator if you want you can write any where else and do the required imports. Below is the code for AddressBookNameComparator

public class AddressBookNameComparator extends OrderByComparator {

public static String ORDER_BY_ASC = "name ASC";

public static String ORDER_BY_DESC = "name DESC";

public AddressBookNameComparator() {
this(false);
}

public AddressBookNameComparator(boolean asc) {
_asc = asc;
}

public int compare(Object obj1, Object obj2) {
AddressBook project1 = (AddressBook) obj1;
AddressBook project2 = (AddressBook) obj2;

int value = project1.getName().toLowerCase().compareTo(
project2.getName().toLowerCase());

if (_asc) {
return value;
} else {
return -value;
}
}

public String getOrderBy() {
if (_asc) {
return ORDER_BY_ASC;
} else {
return ORDER_BY_DESC;
}
}

private boolean _asc;

}

Do the required imports .Same way you can do for other columns.
Step 3: Use the SearchContainer taglib.

<liferay-ui:search-container
emptyResultsMessage="No Result Found"
orderByCol="<%= orderByCol %>"
orderByType="<%= orderByType %>"
>
<liferay-ui:search-container-results results="<%= AddressBookLocalServiceUtil.getAddressBookList(searchContainer.getStart(), searchContainer.getEnd(),orderByComparator)%>">
total="<%= AddressBookLocalServiceUtil.getAddressBookCount() %>"
/>
<liferay-ui:search-container-row classname="com.ext.portlet.addressBook.model.AddressBook" escapedmodel="<%= true %>">
keyProperty="bookId"
modelVar="addressBook"
>


<liferay-ui:search-container-column-text name="name" orderable="<%= true %>" orderableproperty="name">
>

<%= addressBook.getName() %>

</liferay-ui:search-container-column-text>

<liferay-ui:search-container-column-text name="status" orderable="<%= true %>" orderableproperty="status" property="status">
/>

</liferay-ui:search-container-column-text>


<liferay-ui:search-iterator />
</liferay-ui:search-container-row></liferay-ui:search-container-results>
That is all about orderable search container.If you have read the wiki article then you will easily understand this.

HTH

Monday, March 8, 2010

Hiding portlet in liferay

Requirement: Hide the portlet for which user is not having permission to view.

Simple Approach:
It is very difficult to hide or show portlet at user level. To get rid of these type of problem liferay provide us Roles. So we can create roles and on those roles we can easily assign permission on each portlet.
Creating role in liferay is very simple.
Just login as Admin and using dock navigate to control panel , click on Role from left panel and then click Add...for more details refer portal administration guide from liferay.
Once this is done click on define permission and select portlet permission.
e.g. Suppose you want to remove view permission from portlet A then uncheck view.

When you will login as user with that role then you will get message something like this.
"you don't have required permission to access this portlet"
Finally to make this portlet invisible for that role user who is not having required permission to view the portlet.In portal-ext.properties add this line
layout.show.portlet.access.denied=false

IPC-using public render parameter

In last post we have learned how to do coordination between 2 portlet commonly known as Inter Portlet Communication. In post I am going to describe IPC using public render parameter.

This is the simplest method for IPC given by JSR-286.

Description:

In JSR 168 (Portlet 1.0), the render parameters set in the processAction() method are available only in the render phase of the same portlet.

By using the public render parameters feature, the render parameters set in the processAction() method of one portlet are available in render parameters of the other portlets. Using public render parameters instead of events avoids the additional process event call. The public render parameters can also be set on the render URL.

To enable coordination of render parameters with other portlets within the same portlet application or across portlet applications, the portlet can declare public render parameters in its deployment descriptor using the public-render-parameter element in the portlet application section. Public render parameters can be viewed and changed by other portlets or components.

In the portlet section, each portlet can specify the public render parameters to be shared through the supported-public-render-parameter element. The supported-public-render-parameter element must reference the identifier of a public render parameter defined in the portlet application section in a public-render-parameter element.

Example: If we carry same old portlets which we have build in last example i.e for Event model IPC namely test1-portlet and test2-portlet.

Step 1:

Declare the render parameters to be shared in the portlet.xml file by setting the public render parameters at the portlet application level.

e.g:

<portlet-app ...>

<portlet> ... </portlet>

<public-render-parameter>

<identifier>user-id</identifier> <qname xmlns:x="http://abc.com/userId">x:userId</qname>

</public-render-parameter>

</portlet-app>

Note:

1.A developer can declare a list of public paramters for a portlet application in portlet.xml.

2.Parameter names are namespaced to avoid naming conflict.

Step 2:

Portlet must declare which public param they want to use.

e.g.

After adding declaration portlet.xml will look something like this.

<portlet-app ......>

<portlet>

<portlet-name>test1</portlet-name> <display-name>test1</display-name>

........ ........

<supported-public-render-parameter>

user-id

</supported-public-render-parameter>

</portlet>

<public-render-parameter>

<identifier>user-id</identifier> <qname xmlns:x="http://abc.com/userId">x:userId</qname>

</public-render-parameter>

</portlet-app>

Note: Public params are available in all lifecycle method like processAction , processEvent, render and serveResource.

Step 3: We can set render parameter in the processAction() method by using the defined public render parameter identifier as the key.

e.g.

public void processAction(ActionRequest request, ActionResponse response)

throws IOException, PortletException { ........ response.setRenderParameter("user-id", userId); ........

}

Step 4: A portlet can read public render parameter using follwing method

request.getPublicParameterMap()

Note: Public render parameters are merged with regular parameters so can also be read using

request.getParameter(name) or request.getParameterMap()

Step 5: A portlet can remove a public render parameter by invoking following methods.

response.removePublicRenderParameter(name)

or

portletURL.removePublicRenderParameter(name)

Thursday, February 25, 2010

Coordination between portlets in JSR-286

To provide coordination JSR-286 provides 2 mechanism
1.Event: Portlet event that portlet can recieve and send.
2.Public Render Parameter : Render states that can be shared between portlets.

Event :

In JSR-168 :
The only way to achive eventing was through portlet session.
Limitation : Portlet has to be in the same web application.

In JSR-286 :
JSR 286 (Portlet 2.0) defines a lifecycle for events, so that eventing is possible between portlets that are in different web applications.

Definition Of Event in JSR -286 :
An event is lifecycle operation occuring before rendering phase. It is a loosely coupled , acting as a agent for communication between portlets.
Events allow portlets to respond on actions or state changes not directly related to an interaction of the user with the portlet.

A portlet can declare events in its deployment descriptor by using the event-definition element in the portlet application section.
In the portlet section, each portlet specifies the events it would like to publish through the supported-publishing-event element and
the events it would like to process through the supported-processing-event element.

The supported-publishing-event and supported-processing-event elements must reference the event name defined in the portlet application section in an event-definition element.

The portlet creates events using the setEvent() method during action processing. The events are processed by the portlet container after the action processing has finished.
Portlets can also create events during the event phase by calling the setEvent() method on EventResponse.

To receive events, the portlet must implement the javax.Portlet.EventPortlet interface. The portlet container calls the processEvent() method
for each event targeted to the portlet with an EventRequest and EventResponse object. The portlet can access the event that triggered the current
process event call by using the EventRequest.getEvent() method. This method returns an object of type Event encapsulating the current event name and value.

Event names are represented as QNames to identify them uniquely. The event name can be retrieved by using the getQName() method that returns the complete
QName of the event, or by using the getName() method that returns only the local part of the event name. The value of the event must be based on the type
defined in the deployment descriptor.

So this all about theory time for some practical.

For this simple example I am going to use plugin sdk liferay version 5.2.3

Step 1:
create 2 portlets in plugins environment.Creating portlet in plugin is very simple just execute below command
Go to {your_work_space}\plugins\portlets> and execute command
create hello "Hello World" this will create portlet with portlet display name = "Hello World" and portlet name = hello

I am creating here 2 portlets with name test1 and test2

Step 2: Go to your 1st portlet below location in our present case it is test1 i.e

{your_work_space}\plugins\portlets\test1-portlet\docroot\WEB-INF

open porlet.xml file. In that add first Event definition as below

e.g.
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0" 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">
<portlet>

<..>
</portlet>
<!-- Event Definition-starts -->
<event-definition>
<qname xmlns:x="http:kamal.com/events">x:Name
<value-type>java.lang.String
<!-- Event Definition-ends -->
</event-definition>
</portlet-app>

Step 3: Now we need to publish event
We will make test1-portlet as Event Publishing portlet as well. So open again portlet.xml file same as step 2
Add supported-publishing-event tag like below.

<supported-publishing-event>
x:Name
</supported-publishing-event>

Now your portlet.xml file structure will be like this.

<?xml version="1.0"?>

<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0" 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">
<portlet>

<..>
<!-- supported-publishing-event- starts -->
<supported-publishing-event>
x:Name
</supported-publishing-event>
<!-- supported-publishing-event- ends -->
</portlet>
<event-definition>
<qname xmlns:x="http:kamal.com/events">x:Name
<value-type>java.lang.String
</event-definition>
</portlet-app>


Step 4: Now our Event publishing portlet is ready with required configuration , now we need to do same configuration for
Event Processing portlet. Now open portlet.xml for test2-portlet and modify it as above with minor change in place of
<supported-publishing-event> use <supported-processing-event> thats it. Now structure will look like this.

<?xml version="1.0"?>

<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0" 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">
<portlet>
<!-- here other portlet related content will come like portlet-name , diaply-name etc-->
<..>
<supported-processing-event>
x:Name
</supported-processing-event>
</portlet>
<event-definition>
<qname xmlns:x="http:kamal.com/events">x:Name
<value-type>java.lang.String
</event-definition>
</portlet-app>


Step 5: Now all configuration part is over , now we will modify java files
Go to test1-portlet's JSPPortlet.java at location {your_work_space}\plugins\portlets\test1-portlet\docroot\WEB-INF\src\com\sample\jsp\portlet
In processAction method add below code
QName qname = new QName("http:kamal.com/events" , "Name");
String value = "Hurray we have done it";
actionResponse.setEvent(qname, value);

and add needful imports
import javax.xml.namespace.QName;

Step 6: Now Go to test2-portlet's JSPPortlet.java at location {your_work_space}\plugins\portlets\test2-portlet\docroot\WEB-INF\src\com\sample\jsp\portlet
Add new method to process event

public void processEvent(EventRequest request, EventResponse response) {
_log.info("I m in process event");
Event event = request.getEvent();
if(event.getName().equals("Name")) {
String displayText = (String)event.getValue();
response.setRenderParameter(
"displayText", displayText);
}
}

and do needful imports
import javax.portlet.Event;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;

Step 7: Now we are done java part as well need to do minor coding in jsp to see our hard work live.
Open view.jsp of test1-portlet to provide a link to invoke event
e.g.
<%
PortletURL actionURL = renderResponse.createActionURL();
%>
<a href="<%= actionURL.toString() %>">click here to invoke event</a>
do needful imports if required
<%@ page import="javax.portlet.PortletURL" %>

Step 8: Open view.jsp of test2-portlet to show output
just add following line
<%= renderRequest.getParameter("displayText") %>
I have not done any thing extra , I tried to focus on concept and its implementation.

Start the server and if everything is working fine add both portlet test1 and test2 on a page and click the link
provided on test1 portlet you will see the output on portlet test2.

Pls do post your feedbacks.