Monday, July 8, 2013

Sorting (Case insensitive) using Custom Comparator in Liferay

Search Container is widely used taglib in Liferay.
We will follow few steps to implement ordering on container columns
 
1) Write below code in your jsp .
<%
 
String orderByCol = ParamUtil.getString(renderRequest, "orderByCol");
String orderByType = ParamUtil.getString(renderRequest, "orderByType"); 
 
/* Code to set default arrow on particular column while landing on this page */
 
PortalPreferences portalPrefs = PortletPreferencesFactoryUtil.getPortalPreferences(request);
 
if (Validator.isNotNull(orderByCol) && Validator.isNotNull(orderByType)) {
portalPrefs.setValue("DemoName", "DemoName-order-by-col", orderByCol);
portalPrefs.setValue("DemoName", "DemoName-order-by-type", orderByType);
 
} else {
 
orderByCol = portalPrefs.getValue("DemoName", "DemoName-order-by-col", "keyProperty");
orderByType = portalPrefs.getValue("DemoName", "DemoName-order-by-type", "desc");
}
 
/* Code to convert asc in desc after clicking on cloumn */
 
if(orderByCol==null || orderByCol.equals(StringPool.BLANK)) {
renderRequest.setAttribute("orderByCol","keyProperty");
}
if(orderByType==null || orderByType.equals(StringPool.BLANK)) {
orderByType="desc";
renderRequest.setAttribute("orderByType",orderByType);
}
%>
 
2) Pass Custom comparator to your search container results.
 
<liferay-ui:search-container orderByCol="<%=orderByCol %>" orderByType="<%=orderByType %>"  iteratorURL="<%=iteratorURL %>"  delta='10'>
<liferay-ui:search-container-results>
<%
 
List<YourModel> lst = lst; //Fetch List for sorting purpose;
if(lst!=null){
Collections.sort(lst,DemoComparatorUtil.getDemoComparator(orderByType, orderByCol)); //Pass custom comparator for sorting
total = lst.size();
results = ListUtil.subList(lst, searchContainer.getStart(), searchContainer.getEnd());
pageContext.setAttribute("results", results);
pageContext.setAttribute("total", total);
 
}
 
%>
 
</liferay-ui:search-container-results>
.
.
.
</liferay-ui:search-container>
 
3) Now create custom comparator mentioned above "DemoComparator" :
 
public class DemoComparatorUtil {


    public static DemoComparator getDemoComparator(String orderByType,String orderByCol){
        DemoComparator demoComparator;    
        
        if (orderByType.equals("desc")) {
            demoComparator = new DemoComparator(false, false);
        } else {
            demoComparator = new DemoComparator(true, false);
        }
        
        if (orderByCol != null) {
            demoComparator.addOrderBy(orderByCol);
        }        
            return demoComparator;    
    }
}
class DemoComparator implements Comparator<YourModel>, Serializable{


        private boolean asc;
        private boolean caseSensitive;
        private List<DocumentComparatorOrderBy> columns = new ArrayList<DocumentComparatorOrderBy>();


    public DemoComparator(){
        this(true,false);
    }

    public DemoComparator(boolean asc, boolean caseSensitive) {
        this.asc = asc;
        this.caseSensitive = caseSensitive;
    }
    
    public void addOrderBy(String name) {
        addOrderBy(name, asc, caseSensitive);
    }

    public void addOrderBy(String name, boolean asc, boolean caseSensitive) {
    DocumentComparatorOrderBy orderBy = new DocumentComparatorOrderBy(name, asc, caseSensitive);
        columns.add(orderBy);
    }
    
    public int compare(YourModel arg0, YourModel arg1) {
    
        int result=0;
        for (DocumentComparatorOrderBy orderBy : columns) {
            String value1 = "";
            String value2 = "";
            
            if (orderBy.getName().equals("keyProperty")) {
                if (!orderBy.isAsc()) {
                    String temp = value1;
                    value1 = value2;
                    value2 = temp;        
                }
            
                if ((value1 != null) && (value2 != null)) {
                    if (orderBy.isCaseSensitive()) {
                        result = value1.compareTo(value2);
                    } else {
                        result = value1.compareToIgnoreCase(value2);
                    }
                }    
            
            }
        
        
            if (result != 0) {
                return result;
            }
        }
        return 0;
    }

}

You can use this single comparator for all columns in your search container by checking key property in if-else condition only.
Enjoy..!!

IPC (Inter Portlet Communication) - in Liferay.

Hi Liferay Developers,

Liferay have so many good feature. IPC is one of them. let me give basic idea about IPC. Basically
IPC is use for Inter Portlet Communication between portlets.

IPC can be achieved in two ways:

1) Public-render-parameter
2) Event-definition




1) Public Render Parameter - IPC

Adding below property in portlet-ext, we can enable portlets to share render states with other portlets that are on different pages:

Changes in portal-ext.properties:

portlet.public.render.parameter.distribution=ALL_PORTLETS



Changes in Pitcher Portlet

Step 1:

Add below attribute in Pitcher Portlet in portlet.xml

<portlet-app>
   <portlet>
         <supported-public-render-parameter>
          name
          </supported-public-render-parameter>
   </portlet>
   <public-render-parameter>
           <identifier>name</identifier>
           <qname xmlns:x="http://ktn.com/anything">x:param1</qname>
    </public-render-parameter>
</portlet-app>

Note: http://ktn.com/anything is userdefine url which you like. i.e. http://testorganizationcom/name


Step 2:
Set render parameter in the processAction() method from the Pitcher Portlet.

public void processAction(
    ActionRequest request, ActionResponse response)
             throws IOException, PortletException {
        response.setRenderParameter("name", "value");
}



Step 3:
Changes Catcher Portlet in portlet.xml, defines which render parameter is shared in portlet section.

<portlet-app>
     <portlet>
              <supported-public-render-parameter>
              name
                </supported-public-render-parameter>
     </portlet>
     <public-render-parameter>
                <identifier>name</identifier>
                <qname xmlns:x="http://ktn.com/anything">x:param1</qname>
     </public-render-parameter>
</portlet-app>


Step 4:
Portlet can read public render parameter using from the Catcher Portlet:

request.getPublicParameterMap()

or can also be read using

request.getParameter(“name”);



2) Event : IPC

Adding below property in portlet-ext, we can enable portlets to share Even states with other portlets.

Changes in portal-ext.properties:

portlet.event.distribution=ALL_PORTLETS



Changes in Pitcher Portlet

Step 1:

Adding attribute in Pitcher Portlet in portlet.xml

This is defines supported-publishing from the pitcher portlet.

<portlet-app>
     <portlet>
                  <supported-publishing-event>
                           <qname xmlns:t="http://liferay.com/events">t:name</qname>
                  </supported-publishing-event>
      </portlet>
       <event-definition>
                  <qname xmlns:t="http://liferay.com/events">t:name</qname>
                  <value-type>java.lang.String</value-type>
      </event-definition>
</portlet-app>

 
Step 2:


Changes in jsp page to

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

<a href="<%=actionURL.toString()%>"> Click here </a>

this code is generate event from jsp to controller class of Pitcher portlet.


Step 3:
By using below code line we can communicate between Pitcher and Catcher Portlet.
This is to how we sending event from Pitcher to Catcher portlet.


public void myAction(ActionRequest actionRequest,ActionResponse actionResponse) {
       QName qname = new QName("http://liferay.com/events","name");
       actionResponse.setEvent(qname,"Hello World");
       return;
}


Changes in Catcher Portlet

Step 4:
Adding below entry in Catcher portlet. This is defines supported-processing from the Catcher portlet.

<portlet-app>
       <portlet>          
          <supported-processing-event>
                        <qname xmlns:t="http://liferay.com/events">t:name</qname>
                </supported-processing-event>
       </portlet>

       <event-definition>
                 <qname xmlns:t="http://liferay.com/events">t:name</qname>
                 <value-type>java.lang.String</value-type>
       </event-definition>
</portlet-app>



 Step 5:

By below code line  capture the event in Catcher Portlet.

@Override

public void processEvent(EventRequest request, EventResponse response)
{
         Event event = request.getEvent();
         String name = (String) event.getValue();
         response.setRenderParameter("name", name);  
}



Step 6:
Now, we get this attribute value in jsp page of Catcher portlet.
In view page of Catcher Portlet, by this line we can get value of parameter from Pitcher Portlet.

<% String name = (String)renderRequest.getParameter("name"); %>



That's It for IPC. Enjoy the feature to communicate between portlet to portlet!!!