Friday, 22 August 2014

Liferay Grid



View.jsp :
<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

<portlet:defineObjects />

This is the <b>NewPortlet</b> portlet in View mode.

<portlet:actionURL var="actionURL"></portlet:actionURL>

<a href="<%=actionURL %>" >view grid</a>
Grid.jsp:


Description:

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%@ page import="javax.portlet.PortletURL" %>
<%@ page import="org.apache.commons.collections.CollectionUtils" %>
<portlet:defineObjects />


<portlet:renderURL var="renderURL"></portlet:renderURL>

<a href="<%=renderURL %>" >Back to Home</a>

<%@ page import="java.util.*" %>
<%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui"%>



<%
//creating Iterator URL.

PortletURL iteratorURL = renderResponse.createRenderURL();
iteratorURL.setParameter("jspPage", "/html/newportlet/grid.jsp");
%>

<%!
//Creating Global List Object

List list =new ArrayList();
%>
<%
//getting List object from Render Request Object
List originalList = (List)renderRequest.getAttribute("list");

System.out.println("originalList"+originalList);

//copying list into global list object
if(originalList!=null ){
      list= new ArrayList(originalList.size());
      for(Object b: originalList){
            list.add(b);
      }
}



%>


<liferay-ui:search-container delta="3" emptyResultsMessage="No Records" iteratorURL="<%=iteratorURL %>" deltaConfigurable="true" >
<%
//creating Sub list
List displayList= null;
if(list!=null && list.size()>0 ){
      displayList =list.subList(searchContainer.getStart(), list.size());
}

System.out.println(searchContainer.getEnd());
System.out.println(list.size());
if( searchContainer.getEnd() < list.size()){

      displayList=list.subList(searchContainer.getStart(), searchContainer.getEnd());

}

%>


<liferay-ui:search-container-results results="<%=displayList%>" total="<%=list.size()%>" >

</liferay-ui:search-container-results>



<liferay-ui:search-container-row className="com.test.Book" modelVar="book" >

<liferay-ui:search-container-column-text value="<%= book.getBookTitle() %>" name="Book Title" ></liferay-ui:search-container-column-text>
<liferay-ui:search-container-column-text value="<%= book.getAuthor()  %>" name="Author"></liferay-ui:search-container-column-text>



</liferay-ui:search-container-row >

<liferay-ui:search-iterator />


</liferay-ui:search-container>

Description:
1. Create iterator URL for same page. if we want to use pagination, we need this url. Based on this url, the paginator will know where to display further results.
2.  Get the List object from Action class.
3. Copy that list into Global List Object.
Note:
This is not the best way. But while using pagination, we are facing problems. That is we are not getting list object from Action class while click on next.  To fix that problem temporarily we followed this way.
4. Write the tag <liferay-ui:search-container>. It will create the searchContainer Object by supplying tag attributes and values to the SearchContainer class. After writing this tag, we can use searchContainer object in scriptlets.
Attributes:
1. delta: default no. of results per page.
2: emptyResultsMessage: To display default message when the list object is emty.
3. iteratorURL: On which we want to display further results.
4. deltaConfigurable: To select items per page dynamically
5. Create the sublist which will be displayed based on items per page. Write proper logic to create sub list. Because if the remaining object is samller than the items per page we will get errors.
Ex:
<%

List displayList= null;
if(list!=null && list.size()>0 ){
      displayList =list.subList(searchContainer.getStart(), list.size());
}

System.out.println(searchContainer.getEnd());
System.out.println(list.size());
if( searchContainer.getEnd() < list.size()){

      displayList=list.subList(searchContainer.getStart(), searchContainer.getEnd());

}

%>

6. Write the <liferay-ui:search-container-results> tag and supply subList and Total list size.
Ex:
<liferay-ui:search-container-results results="<%=displayList%>" total="<%=list.size()%>" >

</liferay-ui:search-container-results>

7. Write the Tag <liferay-ui:search-container-row> and Supply the model object name  and give it variable name. We can access property values by using this variable.  This tag will create a row of search container.
Ex: <liferay-ui:search-container-row className="com.test.Book" modelVar="book"
<liferay-ui:search-container-column-text/>
</liferay-ui:search-container->
className is the class name of the objects which are stored in the list object
8. Set the name and value attribute values for <liferay-ui:search-container-column-text/>.
Where name is column name of the Grid and value is result of that attribute.
For Ex:

<liferay-ui:search-container-column-text value="<%= book.getBookTitle() %>" name="Book Title" ></liferay-ui:search-container-column-text>
<liferay-ui:search-container-column-text value="<%= book.getAuthor()  %>" name="Author"></liferay-ui:search-container-column-text>

The above code displays two Columns in a row.
We are calling the methods of Model class using modelVar attribute values we set in the <liferay-ui:search-container-row> tag
Note:
If you want to display any datatype other than String in the column, Please use toString() method. Otherwise you will get Error
9. The Tag <liferay-ui:search-iterator /> takes care of iterating the list object until all the objects are displayed.

Inter Portlet Communication



Introduction


The first version of the portlet specification, JSR-168/Portlet 1.0, did not include any support for Inter Portlet Communication. The second version, JSR-286/Portlet 2.0, has supported for IPC Mechanism.
JSR-286 makes it easy to share the data between two portlets. Using IPC mechanisms, we can share the data from ACTION to VIEW phase and VIEW-VIEW Phase.
Definition :
Intert Portlet Communication means that to share data between the portlets”.
There are 3 ways to share the data between 2 portlets.
1.    Portlet session
2.    IPC Mechanisms
1.    Public Render Parameters
2.    Events
3.    Client-Side IPC
3.    Cookies

1. Portlet Session

By default, Each WAR has its own session and will not be shared with other WARs. Liferay provides a mechanism by which Portlets can share session attributes across WARs.
A PortletSession is created for each user per portlet application. This makes the PortletSession useful for communicating all user related information among different portlets in the same portal application.

Step 1: Set below attributes in Portlet1

liferay-portlet.xml :
 Note: Place below tag after  <instanceble/> tag
    <portlet>
        <private-session-attributes>false</private-session-attributes>
    </portlet>

Step 2: To set the Session

    PortletSession session = renderRequest.getPortletSession();
    session.setAttribute("sessionValue", some-value ,PortletSession.APPLICATION_SCOPE);

Step 3: Get the Session Value in Portlet2

    PortletSession ps = renderRequest.getPortletSession();
    String tabNames = (String)ps.getAttribute("sessionValue ",PortletSession.APPLICATION_SCOPE);

 2. Inter Portlet Communication (IPC) Mechanism

               

2.1 Public-render-parameter Inter-portlet Communication

 
In JSR 168, the render parameters set in processAction is only available in the render of the same portlet. With the Public Render Parameters feature, the render parameters set in the processAction of one portlet will be available in render of other portlets also.
By adding the following property in portlet-ext, we can enable portlets to share render states with other portlets that are on different pages:
    portlet.public.render.parameter.distribution=ALL_PORTLETS

Step 1: Add below attribute in "Sender-Portlet"  In portlet.xml

    <portlet-app>
        <portlet>
           Note :Place below tag after <security-role-ref>user</security-role-ref>
            <supported-public-render-parameter>id1</supported-public-render-parameter>
        </portlet>
        
           Note : place below tag  after end tag of </portlet>
        <public-render-parameter>
            <identifier>id1</identifier>
            <qname xmlns:x="http://abc.com/userId">x:param1</qname>
        </public-render-parameter>
    </portlet-app>
Note:We can declare a list of public paramters for a portlet application.

Step 2  Set Parameter value  inside processAction()

We can set render parameter in the processAction() method by using the defined public render parameter identifier as the key.
    response.setRenderParameter("id1", "someIdValue");




E.g.
    public void processAction(ActionRequest  request, ActionResponse response) throws IOException, PortletException  {
        ........
        response.setRenderParameter("id1", “someIdValue”); ........
    }

Step 3: Receiver Portlet Portlet "portlet.xml"

Specify the render parameter the portlet would like to share in the portlet section.
    <portlet-app>
        <portlet>
            <portlet-name >PortletB< /portlet-name>
            Note :Place below tag after the <security-role-ref>user</security-role-ref>
            <supported-public-render-parameter>id1</supported-public-render-parameter>
        </portlet >

        Note :Place the below tag after the end tag of </portlet>
        <public-render-parameter>
            <identifier>id1</identifier>
            <qname xmlns:x="http://abc.com/userId">x:param1</qname>
        </public-render-parameter>
    </portlet-app>

Step 4  :Get the Parameter

A portlet can read public render parameter using following method request.getPublicParameterMap()
Note:Public render parameters are merged with regular parameters so can also be read using
    request.getParameter(“id1”);

Step 5:  Remove the Render Parameter

A portlet can remove a public render parameter by invoking following methods.
    response.removePublicRenderParameter("id1")
               



   2.2 Event Inter-portlet Communication

 
Portlet events that a portlet can receive and send.
In JSR-168 The only way to achieve eventing was through portlet session. The limitation of this approach was that the Portlets 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.
By adding the following property in portal-ext.properties, we can enable portlets to send and receive events from other portlets that are on different pages
    portlet.event.distribution=ALL_PORTLETS

Step 1: Sender Portlet

portlet.xml
The portlet standard defines a way of telling the portlet container which portlet is responsible for sending an event.
Add this inside <portlet> tag:
    <portlet-app>
        <portlet>
           
         Note :place below tag after the end tag of <security-role-ref>user</security-role-ref>
            <supported-publishing-event xmlns:x='http://liferay.com'>
                <qname>x:empinfo</qname>
            </supported-publishing-event>>
        </portlet>
 
        Note :place the below tag after end tag of </portlet>
        <event-definition xmlns:x='http://liferay.com'>
            <qname>x:empinfo</qname>
            <value-type>java.lang.String</value-type>
        </event-definition>
    </portlet-app>

 

Step 2: Set the event in process action

    javax.xml.namespace.QName qName = new QName("http://liferay.com", "empinfo", "x");
    response.setEvent(qName, "Hi! You have received Event Data sent from Sender Portlet");

Step 3: Listener Portlet

portlet.xml
    <portlet-app>
        <portlet>
         Note :Place below one after end tag of <security-role-ref>user</security-role-ref>
            <supported-processing-event xmlns:x='http://liferay.com'>
                <qname>x:empinfo</qname>
            </supported-processing-event>
        </portlet>
        Note:Place the below one after end tag of </portlet>
        <event-definition xmlns:x='http://liferay.com'>
            <qname>x:empinfo</qname>
            <value-type>java.lang.String</value-type>
        </event-definition>
    </portlet-app>

Step 4: get the EVENT

This Event will be called after processAction as shown in the picture:
Lifecycle for IPC Event
 
    @javax.portlet.ProcessEvent(qname = "{http://liferay.com}empinfo")
    public void handleProcessempinfoEvent(javax.portlet.EventRequest request, javax.portlet.EventResponse response)
                throws javax.portlet.PortletException, java.io.IOException {
               
        javax.portlet.Event event = request.getEvent();
        String value = (String) event.getValue();

        System.out.print("value in process event>>>>>>>>>" + value);
        response.setRenderParameter("empInfo", value);
    }
                                                                               

2.3 Client-Side IPC


There are 2 APIs for client side IPC.
Event generation (call from Portlet-A):
    Liferay.fire(
            '<eventName>', {
            name: value
        }
    );
E.g.
    Liferay.fire(
            'planTravel', {
            origin: 'pune',
            destination : 'mumbai'
        }
    );
Event Listener (call from Portlet-B):
    Liferay.on(
            '<eventName>',
            function(event) {
                // your code
            }
    );
E.g.
    Liferay.on(
            '<eventName>',
            function(event) {
                showNews('', event.origin);
                showNews('', event.destination);
            }
    );
In Portlet A –------view.jsp
ex:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<portlet:defineObjects />
<script type="text/javascript">
    function doSearch() {
        Liferay.fire('searchKeywords', document.getElementById("<portlet:namespace/>search").value);   
    }
</script>
<form>
    <input type="text" name="search" id="<portlet:namespace/>search" />
    <button name="Search" value="Search" onclick="doSearch()" type="button">Search</button>
</form>

In Portlet-B
view.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %>

<portlet:defineObjects />
<portlet:resourceURL var="rurl" />

<script type="text/javascript">
    Liferay.on('searchKeywords', function(event, p_data){
        var A = AUI();
        A.use('aui-io-request', function(aui) {
            A.io.request("<%= rurl %>", {
                method : 'POST',
                data: {search: p_data},
                dataType : 'html',
                on : {
                    success : function() {
                        AUI().one("#<portlet:namespace/>placeholder").html(this.get('responseData'));
                    }
                }
            });
        });
    });
</script>
Search Results:<br />
<div id="<portlet:namespace/>placeholder">
</div>

In Portlet B
 html.jsp
<font color="red"><%= request.getAttribute("result") %></font>
In Portlet B ------>MVCPortlet
public void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws PortletException, IOException {
         //do your search here and put results in 'result'
resourceRequest.setAttribute("result", "results for: " + resourceResponse.getParameter("search"));
getPortletContext().getRequestDispatcher("/html/ipcdemo8portlet/html.jsp").include(resourceRequest, resourceResponse);
}

                                          
 3.Cookies
Other than the IPC mechanism, there is an easiest way to get the data between portlets on different pages through Cookies.
But there are some limitations for cookies:
1.    It will not accept more than 4KB size of data
2.    The biggest limitation is, the 20 cookies per server limit
and so it is not a good idea to use a different cookie for each variable that has to be saved.

Portlet 1

To Set the Cookies through jQuery:
    <script src="/html/js/jquery/cookie.js" type="text/javascript" > </script>
   
    function setCookie(docURL) {
        jQuery.cookie("cookieParam",docURL);
    }
To Set the Cookies through java/jsp:
    HttpServletResponse response = PortalUtil.getHttpServletResponse(actionResponse);
    Cookie cookieParam = new Cookie("cookieParam ", password);
    response.addCookie(cookieParam);

Portlet 2

To get the Cookies through jQuery:
    jQuery.cookie("cookieParam ");
To get the Cookie through java/jsp:
    String sessionid = "";
    Cookie[] cookies = request.getCookies();
    if (cookies != null) {
        for (int i = 0; i < cookies.length; i++) {
            if (cookies[i].getName().equals("cookieParam ")) {
                sessionid = cookies[i].getValue();
                break;
            }
        }
    }