Thursday, October 30, 2008

[JSF] How to get rid of "JSF1054: (Phase ID: RESTORE_VIEW 1, View ID: )" on session timeout

While upgrading JSF from 1.1 to 1.2 (1.2_09) I found a lot of the following exceptions in tomcats catalina.out and localhost.log.

com.sun.faces.lifecycle.Phase doPhase SEVERE: JSF1054: (Phase ID: RESTORE_VIEW 1, View ID: ) Exception thrown during phase execution: javax.faces.event.PhaseEvent[source=com.sun.faces.lifecycle.LifecycleImpl@55d7b]

SEVERE: Servlet.service() for servlet Faces Servlet threw exception
javax.faces.application.ViewExpiredException: viewId:/xxxx.jsf - View /xxxx.jsf could not be restored.
        at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:186)
        at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)

Turns out that this usually happens if you have a request that refers to JSF ViewIds (the structure of the jsf page) that doesn't exist in the session on the server. For example, a users session could be timed out on the server, so when the user makes a request to the server with the ViewId, it no longer exist and you will most likely receive the above exception.
The reason why this suddenly shows up is that JSF 1.1 and 1.2 handles the session timeout differently. Now you actually have a chance to react upon the thrown exception whereas previously it was just ignored and the view tree was just regenerated from scratch.

Anyways... What you can do to avoid this is two things:
  • Handle the exception, for example by adding a filter that shows a nice page to the user
  • Insert the following in your web.xml:
      
        com.sun.faces.enableRestoreView11Compatibility    true
      
    
    This will cause JSF to behave as it did in 1.1

10 comments:

jainparv said...

can you help me by elaborating how to add the filter to redirect user at desired page.

Jakob Maaløe said...

Sure,

To add a filter you can in JSF add the following to your web.xml:
<filter>
<display-name>Auth Filter</display-name>
<filter-name>authfilter</filter-name>
<filter-class>com.maaloe.filters.MyAuthorizationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>authfilter</filter-name>
<servlet-name>FacesServlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
<servlet>
<servlet-name>FacesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>FacesServlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>

and then in the doFilter() method of your com.maaloe.filters.MyAuthorizationFilter class, you can catch the exception like this:

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
try {
// Validate the user
} catch (Exception exception) {
// catch the exception and forward to the page
request.getRequestDispatcher("/pagetoforwardto.jsp").forward(request,response);
}
}

Let me know if you need further elaboration. The above was just an example... I hope you see what i mean and that you can read it even with this miserable layout that i have chosen for the page. ;)

freemarket said...

Hi Jakob,

Can you kindly elaborate a bit further with respect to the second option, your filter extension class? I have an richfaces based application so the current web.xml already has a filter for richfaces for the facesservlet. How does one composite this with this filter?


Thanks,
Henry

Jakob Maaløe said...

Hi,

Sorry for the late response, I've been on vacation.
You can add more than one filter to your web.xml, so in case you need to have a filter running before your Richfaces filter, you should be able to do this by adding the filter-mapping for richfaces AFTER the filter-mapping for your own customized filtering.

Does this answer your question?

nohacks said...

Hi Jakob,

I have been running into this issue and posted on Richfaces board several times. They seem to think it my code...

http://www.jboss.org/index.html?module=bb&op=viewtopic&t=150803&postdays=0&postorder=asc&start=0

http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4212379#4212379

could you review the posts and let me know if we are having the same issue?

Thanks for your time.

Phil

freemarket said...

Thanks, Jakob. I shall try combining the filters in the order you've suggested.

Regards,
Henry

Jakob Maaløe said...

Nohacks:
From what i can see without digging really deep in your application, the problem is that you get a NullPointerException in the
com.myAppName.java.beansTable.EmailReceivedBeanTest
class. Do you have a constructor where you do some kind of operation that causes the NullPointerException? If you do, it would probably make sense to move this logic out of the constructor.

Please try this and post whatever you find...

- Jakob

Phil said...

Do you know why I am getting this error??

Nov 29, 2009 11:07:07 PM org.apache.catalina.core.StandardContext filterStart
SEVERE: Exception starting filter authfilter
java.lang.ClassCastException: com.testApp.java.MyAuthorizationFilter cannot be cast to javax.servlet.Filter
at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:255)
at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:397)
at org.apache.catalina.core.ApplicationFilterConfig.< init >(ApplicationFilterConfig.java:108)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:3709)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4356)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:626)
at org.apache.catalina.startup.HostConfig.deployDescriptors(HostConfig.java:553)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:488)
at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1147)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
at org.apache.catalina.core.StandardService.start(StandardService.java:516)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
at org.apache.catalina.startup.Catalina.start(Catalina.java:578)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)

Michael Phoenix said...

You might be intereste4d to know that I came across this problem in a JSF 1.2 installation and was able to resolve it by adding the context parameter you suggested to my web.xml file.

Jakob Maaløe said...

Thanks Michael, hopefully others will benifit from your experience.