Programming tips for various technologies.

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