Smart Sophisticated Data grids using Jmesa.

Published:
I had a project requirement for a displaying a user workbench .This workbench would consist multiple data grids .In each grid the user will be able to see a large number of data.

These data grids should allow the user to
1. Sort
2. Export the data to Excel, CSV as well as PDF format
3. User customizable Pagination
4. Filter
5. All the grid activities (i.e. 1, 2, 3 and 4) should be Ajax enabled.

My project was a J2EE project using Struts 1.3.8 as the web framework.  Struts itself does not have a direct support for such features.  I used Jmesa. It is an open source Dynamic HTML Table Rendering API that allows to filter, sort, paginate, export and inline editing of data (if required).  I have configured this API according to my project needs.

The requirements that I have mentioned above (i.e. 1 to 5) are not solved by any single library or API apart from Jmesa.  I have gone through the following solutions below, but none of them have the support for all mentioned features like Jmesa has.

I used JMesa extensively in my recent  project. I am benefited heavily from this API . So I want to give something back to this wonderful API by contributing some code/tips/techniques related to the usage of JMesa.  Complete source code is attached at the end of theis article.

Following are few topics on which I going to focus on.

1.  Complete example of using Jmesa with Struts (Specifically the Ajax enabled version).
2.  Practical example /recipe on the row rendering ( i.e. proper usage of HtmlRowRendererImpl )
3.  Proper usage of ColumnSort with examples .
4.  I have a generic comparator (I am working on this currently ), which deals with some real life data type problems in terms of sorting (for example a String containing a date or number, so the sorting becomes weird).  This comparator is capable enough to handle such frequently required real life problem scenarios.

1. Complete example of using Jmesa with Struts (With Ajax )

Brief Summary of what I want to do:
First, setup an application configuration so that Struts 1.x and Jmesa works together.  Then I will have an action class JmesaDispatchAction.java (I am using DispatchAction here so that if wants same action to works for multiple jmesa table less struts mapping and code is required ) which will have a method load().   This load() method is everything .

Setup
Create the structure for any standard struts project. Noww place Jmesalibrariess in side WEB-INF/lib folder.  Place jmesa.properties inside  WEB-INF. Inside web.xml create its entry like the following:
<context-param>
                          <param-name>jmesaPreferencesLocation</param-name>
                          <param-value>WEB-INF/jmesa.properties</param-value>
                       </context-param>

Open in new window

Place Jmesa related css,js and image files inside css,js and images folders respectively, all these folders are under WebContent.  Please see the set up image below:
Image for showing the set up for Jmesa
Code the Action class and the JSP:
The action class will have two basic block inside the load() method one for normal flow another for Ajax request from the JSP page (with request parametre ajax=true).  In the JSP page named pay attention to the JavaScript method onInvokeAction, the main ajaxifying trick is present there .

2. Row Rendering Recipe

Suppose I want to highlight a particular row with a specific color for a specific value... How would I do that?
This is an ideal case for using a Custom HtmlRowRenderer which will extend HtmlRowRendererImpl.

Now we need to override the default public Object render(Object item, int rowcount) method to our specific requirement.

In this case the data list contains a DTO object which has a boolean field named ok. If this field value is true we need to highlight the row with green color.

Here is the code for that
public class CustomHtmlRowRenderer extends HtmlRowRendererImpl 
                      {
                      	public Object render(Object item, int rowcount) 
                      	{
                            	HtmlBuilder html = new HtmlBuilder();
                              html.tr(1);
                              html.id(getCoreContext().getLimit().getId() + "_row" + rowcount);
                              
                              //Get the actual value of ok field
                              Object okValueObj = ItemUtils.getItemValue(item, "ok");
                              String valueStr = String.valueOf(okValueObj).toLowerCase();
                              if (valueStr.contains("true")) 
                              {
                                  html.style("background-color:green");
                              } 
                              else 
                              {
                                  html.style(getStyle());
                              } 
                      
                              html.styleClass(getStyleClass(rowcount));
                              html.append(getRowEvents(item, rowcount));
                              html.close();
                              return html.toString(); 
                      	}   
                      
                      }

Open in new window

Now we need to inform the Tablefacade object about this renederer .Inside getHtml we do this by the following lines of code
         /*
                               * Override and customize the sorting of the table facade 
                               */
                              ColumnSort customColumnSort = new CustomColumnSort();
                              tableFacade.setColumnSort(customColumnSort);

Open in new window

Before row rendering customization, the grid was like :
Grid before row rendering code added
After row rendering customization, the grid is  like :
Grid after row rendering code added

3. Custom Sorting Recipe

How to sort a table according to my own choice using Jmesa?
Jmesa comes with its own nice way of sorting.  But for custom sorting of your own you need to write your own  Custom Sorting class   which will implement ColumnSort interface and implement the sortItems method of the said interface to customize the sorting.

Remember  sortItems() method is the place where you whatever customization.  The code is written below to sort the data on two properties age and displaydate.

public class CustomColumnSort implements ColumnSort 
                      {
                          public Collection<?> sortItems(Collection<?> items, Limit limit) 
                          {
                              ComparatorChain chain = new ComparatorChain();
                              SortSet sortSet = limit.getSortSet();
                              Iterator sortItr= sortSet.getSorts().iterator();
                              while(sortItr.hasNext())
                              {
                                  Sort sort =(Sort)sortItr.next();
                                  GenericComparator genericComparator = null;
                      			
                                  if (sort.getOrder() == Order.ASC) 
                                  {
                                      if(sort.getProperty().equalsIgnoreCase("age"))
                                      {
                                          genericComparator= new GenericComparator(sort.getProperty(),true,GenericComparator.NUMERIC_STRING);
                                      }
                                      if(sort.getProperty().equalsIgnoreCase("displayDate"))
                                      {
                                          genericComparator= new GenericComparator(sort.getProperty(),true,GenericComparator.DATE_STRING);
                                      }
                                  } 
                                  else if (sort.getOrder() == Order.DESC) 
                                  {
                                      /*
                                       * For descending sort one extra parameter sorting mode (value false)
                                       * is passed to the GenericComparator.
                                       * By default its value is true.
                                       * 
                                       */
                                      if(sort.getProperty().equalsIgnoreCase("age"))
                                      {
                                          genericComparator= new GenericComparator(sort.getProperty(),true,GenericComparator.NUMERIC_STRING,false);
                                      }
                                      if(sort.getProperty().equalsIgnoreCase("displayDate"))
                                      {
                                          genericComparator= new GenericComparator(sort.getProperty(),true,GenericComparator.DATE_STRING,false);
                                      }
                                  }
                      			
                                  /*
                                   * This is the main place where the Generic comparator is added to the
                                   * ComparatorChain for sorting
                                   * 
                                   */
                                  chain.addComparator(genericComparator);
                      
                              }
                      		
                              if (chain.size() > 0) 
                              {
                                  Collection((List<?>) items, chain);
                              }
                              return items;
                          }
                      }

Open in new window

Now we need to inform the HtmlTable object about this custom sort object .Inside getHtml we do this by the following lines of code:
        HtmlTable table = (HtmlTable) tableFacade.getTable();
                              HtmlRow row = table.getRow();
                              
                              /*
                               * Override and customize the rendering of the table facade 
                               */
                              CustomHtmlRowRenderer customHtmlRowRenderer = new CustomHtmlRowRenderer();
                              row.setRowRenderer(customHtmlRowRenderer) ;

Open in new window


4. Handle real life sorting issues with GenericComparator

I want to write one and only comparator which will handle all types of sorting.
Even if you have that there are some situations where the comparator will fail.  For e.g. you have some DTO objects within a list which you want to sort. Now the DTO has a displaydate field which is of type String but displays a Date.

Now when the sorting takes place the comparator will try to sort it as a String but the user will be expecting a sort on date !

I mention these particular field types as hybrid data type. We can say displaydate had a Date String hybrid datatype.  Similarly, we may face problems with Numeric String, Boolean String etc etc.

Here comes my brain child custom Generic Comparator. Just inform the comparator about the hybrid data type and let it do its sorting job.

Inside sorItems method of CustomColumnSort I have used generic comparator .

For proper java data type you just need to create the comparator like
GenericComparator comparator= new GenericComparator(<String fieldNameToBeSorted>)

Open in new window

For hybrid  java data type you need to create the comparator like
public GenericComparator(<String fieldNameToBeSorted>,<boolean hybridDataType>,<String hybridDataTypeName>)

Open in new window

     
Inside CustomColumnSort I have shown how to deal with hybrid data type like the following
GenericComparator genericComparator= new GenericComparator(sort.getProperty(),true,GenericComparator.NUMERIC_STRING);

Open in new window

If it was a normal data type the code would have been like:
GenericComparator  genericComparator= new GenericComparator(sort.getProperty());

Open in new window


Please note:
I've attached the complete example source code in the form of a war file.  Please have a look.  In case you need any reference you may go to the URL:
     http://code.google.com/p/jmesa/  
and have a look.  I have written an article about Jmesa usage with Struts over there and my sample code is also uploaded there.
Warfile.doc
1
8,553 Views

Comments (1)

Author

Commented:
Hi ,
First of all I apologize to mwvisa1 as I could not respond on time .I am very sorry that I could not help the the editor mwvisa1 and myself to make the article a better one .

Many thanks to the experts exchange team for publishing my article .
Regards,
Ayan

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.