Programming tips

Programming tips for various technologies.

lunedì 28 settembre 2009

Tomahawk's library and managing tables.

One of the useful thing while working with some technology is trying to use the provided libraries to avoid every time to "reinvent the Hot Water".
I chose to use Myfaces to develop the web interface so i began to look at its related developing libraries. One of the library is TomaHawk.

Anyway i would like to discuss about displaying Tables and how to manage them in the correct way.
So when you work with databases and data, the things that you would like to do are:
  1. Display the data in tabular way
  2. Manage the pagination on the data
  3. Manage the ordering of the data inside the table
  4. Manage the data in the correct way
  5. As usual write quickly maintainable code
Using Tomahawk to cope with this problem was a very nice solution but i had again to fight against the lack of documentation (or outdated documentation as well).
I won't post links to various documentation because there is a lot of documentation and blogs that talk about managing tabular data and the list would be too long.

Displaying data with tables

What do we need to code to solve this problem? As always you will need to write down a back bean, the web interface code and some more needed java code.
First of all we need a class that will store the fields from the database.

public class TableItem {

private String field1;
//List of fields here
public TableItem(String field1) {
this.field1=field1;
}

public Date getField1() {
return field2;
}

public void setField1(String field1) {
this.field1 = field1;
}
}

After that we code our Back Bean that will keep the data loaded from DB or File and will setup our table. We will use this bean in the JSP or Facelets code to display the data in a table. You basically will need to implement one method to achieve the objective.
For the interface we will use a datascroller to manage the pagination and more we will use a commandSortHeader to manage column sort.
Finally a trick i found after about 2 months of searching. We can handle the latest page visited in the pagination so that when returning to the list (the displayed table) we can remeber the latest visited page inside the paginated table. When you have a list of thousands of records this will be very useful (it is a lot annoying to start always from the first record when we reload the table page).

public class TableBackBean {

private Integer latestpageindex;
private transient ListDataModel model = null;
// This field is transient because it cannot be serialized
// and JSF must be aware of it

public TableBackBean() {
// we load data at the creation of the Bean
model=new ListDataModel(getList());
}

public List< TableItem > getList(){
List< YourDBObject > datalistfromdb = null;
List< TableItem > dataitems = new ArrayList<>();
...
...
...
// You can load data from DB or File or whatever into datalistfromdb
// and after that you must create the List to be returned to JSF
// here is the generic code
if(!datalistfromdb.isEmpty()) {
Iterator it = datalistfromdb.iterator();
while(it.hasNext()) {
YourDBObject dbob = (YourDBObject) it.next();
dataitems.add(new TableItem(dbobj.getFirstField()));
}
}
...
...
...
return items;
}

public Integer getLatestpageindex() {
return latestpageindex;
}

public void setLatestpageindex(Integer latestpageindex) {
this.latestpageindex = latestpageindex;
}
}

Now to the interface code. The dataTable has got 2 parameters, first and rowIndexVar; rowIndexVar will save the first index of the record displayed in the paginated table into a property in the session (you must pass the property name as parameter), while first will pass this saved property as the first index to display next time the page is loaded. So we have done each time we leave the table page and reload it, it will remember latest paginated index.
To sort the list by a field of the record we must add defaultSorted="true" sortable="true" to the column that we want to sort with, and remeber to use t:commandSortHeader inside the column code as below.

< t: dataTable id="table1" first="#{TableBackBean.indicepagina}" rowIndexVar="indicepaginastudi" rows="10" value="#{TableBackBean.items}" var="item" >
< t : column defaultsorted="true" sortable="true">
< f : facet name="header">
< t : commandSortHeader arrow="true" propertyName="field1" >
< h: outputText value="Field1" />
< /t: commandSortHeader >
< /f : facet >
< h : outputText value="#{item.field1}" />
< /t : column >
< /t:dataTable >
< t : dataScroller id="scroller" for="table1" paginator="true" paginatormaxpages="10" immediate="true">
< name="first">First< /f:facet>
< name="last">Last< /f:facet>
< name="previous">& lt;< /f:facet >
< name="next">& gt;< /f:facet >
< / t : dataScroller >

Now remember to register properly the backing bean into faces-config.xml as a session bean.

That worked very well to me. Hope you won't have any problem in running this .
Please comment if you have any problems.

martedì 28 ottobre 2008

MyFaces: handling the ViewExpiredException

I am developing some Java Server Faces' technologies related applications from about one year. I have studied for long time this very interesting web framework and i must say i really like it. However even JSF can be very problematic while trying to handle complex things.

The main drawback i had to fight against is the documentation. JSF's specifications had many revisions. We now are at the 1.2 specifications version and browsing the web for fresh documentation is very difficoult. You can find over the network a lot of useful articles and pieces of code but you can also find a lot of old useless things and outdated news.
Usually people tend to help you (if you use Mailing Lists) but sometimes they don't.

Anyway one of the problems I wanted to solve is the ViewExpiredException handling. I studied this problem a lot and tried to document myself the best i could. I also found out some useful articles and blogs related to this problem.

I post these link here for completeness :
  1. JSF dev archive
  2. Sun's forum
  3. Mert Caliskan's weblog (opened my eyes)
  4. Myfaces wiki

Now to My solution.

I am using Apache MyFaces cause it is heavily developed and it has a lot of useful add-on libraries such as Tomahawk, Trinidad and others. Even if Mert Caliskan's articles was really almost the solution it does not work with Myfaces. And honestly i was not able to implement it under Sun's JSF 1.2 as well.

The main problem here is that the JSF 1.2 implementation have somehow a bug (actually i did not understand how come) and the simple solution to this problem does not work at all even on Myfaces and Sun's JSF 1.2.


Simple solution : put into web.xml the following code

<
error-page>
<
exception-type>javax.faces.application.ViewExpiredException< /exception-type>
<
location>/error.jsp< /location>
< /error-page>


The real working solution is a bit tricky. It is based to the fact that Sun's JSF main Servlet does have some code that handles exceptions. So the proposed solution was to use the Servlet in some way. Now JSF's Servlet cannot be subclassed so we must use the Delegation as perfectly described by Mert Caliskan.
I could not anyway figure out how to configure web.xml to let the application deploy without problems (and this is still an open problem to me).

So i decided to try with MyFaces (it works with 1.2.22 and later, I did not test with earlier versions).

Here the job is even simplier cause we have already a delegated Servlet that is MyFacesServlet.java. So i only needed to subclass it. Here is the code:

public class MyFacesServletWrapper extends MyFacesServlet
{

private static final String SYSTEM_ERROR_URI = "/systemerror.jsf";
private static final String VIEWEX_ERROR_URI = "/viewexpiredexception.jsf";

@Override
public void service(ServletRequest request, ServletResponse response) throws IOException,ServletException
{
try {
super.service(request, response);
}
catch(ServletException e) {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
if (e.getCause().getClass().equals(javax.faces.application.ViewExpiredException.class))
{
// here there is the ViewExpiredException
res.sendRedirect(req.getContextPath() +
VIEWEX_ERROR_URI);
}
else {
// any other exception
req.getSession().invalidate();
res.sendRedirect(req.getContextPath() +
SYSTEM_ERROR_URI);
}
}
}
}

However we still haven't finished the job. We must modify in the correct way the web.xml in order to really catch those exceptions. Finally adding the following lines does the job:


< context-param>
< description>Use this to suppress Facelets error page< /description>
< param-name>org.apache.myfaces.ERROR_HANDLING< /param-name>
<
param-value>false< /param-value>
< /
context-param>

< servlet>
< servlet-name>Use this to suppress Facelets error page< /servlet-name>
< servlet-class>MyFacesServletWrapper< /servlet-class>
<
load-on-startup>1< /load-on-startup>
< /
servlet>


That worked to me. Hope you won't have any problem in running this trick.
Please comment if you have any problems.

Lettori fissi