Friday, 20 February 2015

Migrating JSF 1.2 - JSF2 and RichFaces 3 to 4

The motive of this blog post is to share my experience of migrating an application from JSF 1.2 to JSF 2.1  and RichFaces 3.3 to 4.5.

To start with , following is the custom facelet component designed to implement sorting in rich:dataTable

Sorting In RichDataTable : 

Since built in sorting has been removed for rich:dataTable , the sorting has to be achieved programmatically.  After referring rich faces showcase in point 3 ,  I have designed a new facelet custom component with supporting java class as shown below :

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="http://java.sun.com/jsf/facelets"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns:a4j="http://richfaces.org/a4j"
                xmlns:c="http://java.sun.com/jsp/jstl/core"
                xmlns:fn="http://java.sun.com/jsp/jstl/functions">
             
<ui:composition>

<h:panelGrid columns="1" styleClass="table_center">
<a4j:commandLink value="#{name}" styleClass="dataTableSortLink" actionListener="#{bean[actionListenerMethod]}" render="#{render}">
              <f:param name="columnKey" value="#{columnKey}"/>
              <span style="padding:1px;"/>
              <h:graphicImage value="/images/icons/arrow-unsorted.jpg" alt="unsorted" styleClass="sortingArrows" rendered="#{sortOrder eq 'unsorted'}"/>
  <h:graphicImage value="/images/icons/arrow-ascending.jpg" alt="ascending" styleClass="sortingArrows" rendered="#{sortOrder eq 'ascending'}"/>
  <h:graphicImage value="/images/icons/arrow-descending.jpg" alt="descending" styleClass="sortingArrows" rendered="#{sortOrder eq 'descending'}"/>              
</a4j:commandLink>
</h:panelGrid>                
</ui:composition>
</html>

and it will be invoked from rich:dataTable as shown below :

<rich:dataTable id="userList" rows="#{bean.rowsPerPage}" value="#{bean.userList}" var="user">

<rich:column sortBy="#{user.name}" sortOrder="#{bean.dataSorterHelper.sortOrderMap['name']}">
<f:facet name="header">
<custom:commandLinkwithSort name="User Name" bean="#{bean.dataSorterHelper}"
                actionListenerMethod="processSortOrder" render="userList" columnKey="name"
                sortOrder="#{bean.dataSorterHelper.sortOrderMap['name']}"/>
</f:facet>
<h:outputText value="#{user.name}"/>
</rich:column>

<rich:column sortBy="#{user.lastname}" sortOrder="#{bean.dataSorterHelper.sortOrderMap['lastname']}">
<f:facet name="header">
<custom:commandLinkwithSort name="User Last Name" bean="#{bean.dataSorterHelper}"
                actionListenerMethod="processSortOrder" render="userList" columnKey="lastname"
                sortOrder="#{bean.dataSorterHelper.sortOrderMap['lastname']}"/>
</f:facet>
<h:outputText value="#{user.lastname}"/>
</rich:column>

</rich:dataTable>


The class used to handle sorting is shown below :
/**
 * Class to help in sorting rich:dataTable.
 * It contains sort keys for columns to sort and processes sort order according to user selected column for sort.
 *
 */

public class DataSorterHelper {

//map to store sort order for columns , this map contains column key and rich faces sort order
private Map<String,SortOrder> sortOrderMap;

public Map<String, SortOrder> getSortOrderMap() {
return sortOrderMap;
}
/**
* Constructor to initialise sortOrderMap with all columns sort order - unsorted
*
*/
public DataSorterHelper(List<String> sortKeys) {

sortOrderMap = new HashMap<String, SortOrder>();
for(String sortKey : sortKeys){
sortOrderMap.put(sortKey,SortOrder.unsorted);
}
}

public DataSorterHelper() {
sortOrderMap = new HashMap<String, SortOrder>();
}
/**
* Method to set user defined sort order for particular column.Some tables require to set default sort order for a column
*
*/
public void init(List<String> sortKeys,String columnKey,SortOrder sortOrder) {

for(String sortKey : sortKeys){

if(sortKey.equalsIgnoreCase(columnKey)){
sortOrderMap.put(sortKey,sortOrder);
}else{
sortOrderMap.put(sortKey,SortOrder.unsorted);
}
}
}

private void setOtherColumnsUnsorted(String sortKey){

if(sortOrderMap != null){
for(Entry<String,SortOrder> sortInfo : sortOrderMap.entrySet()){
if(!sortKey.equals(sortInfo.getKey())){
sortInfo.setValue(SortOrder.unsorted);
}
}
}
}

/**ActionListener to set sorting order of a column under sorting
* It also sets sorting order of other columns to "unsorted"
* @param event
*/
public void processSortOrder(ActionEvent event){
//get colun key and set sort order
String columnKey = VariableStore.getRequestParameter("columnKey");

/*set sort order of other columns to unsoted .Otherwise sorting doesn't work */
setOtherColumnsUnsorted(columnKey);
if(sortOrderMap != null){
if(sortOrderMap.get(columnKey).equals(SortOrder.ascending)){
sortOrderMap.put(columnKey, SortOrder.descending);
}else{
sortOrderMap.put(columnKey, SortOrder.ascending);
}
}

}

public void resetSortOrderMap(){

if(sortOrderMap != null){
for(Entry<String,SortOrder> sortInfo : sortOrderMap.entrySet()){
sortInfo.setValue(SortOrder.unsorted);
}
}
}


}

It is important to note that , is is necessary to set sort order of other columns to "unsorted" when applying sorting to a prticular column.