javax.faces.application.ViewExpiredException: View could not be restored - jsf

I have written simple application with container-managed security. The problem is when I log in and open another page on which I logout, then I come back to first page and I click on any link etc or refresh page I get this exception. I guess it's normal (or maybe not:)) because I logged out and session is destroyed. What should I do to redirect user to for example index.xhtml or login.xhtml and save him from seeing that error page/message?
In other words how can I automatically redirect other pages to index/login page after I log out?
Here it is:
javax.faces.application.ViewExpiredException: viewId:/index.xhtml - View /index.xhtml could not be restored.
at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:212)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:110)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:312)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at filter.HttpHttpsFilter.doFilter(HttpHttpsFilter.java:66)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:277)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
at java.lang.Thread.run(Thread.java:619)

Introduction
The ViewExpiredException will be thrown whenever the javax.faces.STATE_SAVING_METHOD is set to server (default) and the enduser sends a HTTP POST request on a view via <h:form> with <h:commandLink>, <h:commandButton> or <f:ajax>, while the associated view state isn't available in the session anymore.
The view state is identified as value of a hidden input field javax.faces.ViewState of the <h:form>. With the state saving method set to server, this contains only the view state ID which references a serialized view state in the session. So, when the session is expired or absent for one of the following reasons ...
session object is timed out in server
session cookie is timed out in client
session cookie is deleted in client
HttpSession#invalidate() is called in server
SameSite=None is missing on session cookie (and thus e.g. Chrome won't send them along when a 3rd party site (e.g. payment) navigates back to your site via a callback URL)
... then the serialized view state is not available anymore in the session and the enduser will get this exception. To understand the working of the session, see also How do servlets work? Instantiation, sessions, shared variables and multithreading.
There is also a limit on the amount of views JSF will store in the session. When the limit is hit, then the least recently used view will be expired. See also com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews.
With the state saving method set to client, the javax.faces.ViewState hidden input field contains instead the whole serialized view state, so the enduser won't get a ViewExpiredException when the session expires. It can however still happen on a cluster environment ("ERROR: MAC did not verify" is symptomatic) and/or when there's a implementation-specific timeout on the client side state configured and/or when server re-generates the AES key during restart, see also Getting ViewExpiredException in clustered environment while state saving method is set to client and user session is valid how to solve it.
Regardless of the solution, make sure you do not use enableRestoreView11Compatibility. it does not at all restore the original view state. It basically recreates the view and all associated view scoped beans from scratch and hereby thus losing all of original data (state). As the application will behave in a confusing way ("Hey, where are my input values..??"), this is very bad for user experience. Better use stateless views or <o:enableRestorableView> instead so you can manage it on a specific view only instead of on all views.
As to the why JSF needs to save view state, head to this answer: Why JSF saves the state of UI components on server?
Avoiding ViewExpiredException on page navigation
In order to avoid ViewExpiredException when e.g. navigating back after logout when the state saving is set to server, only redirecting the POST request after logout is not sufficient. You also need to instruct the browser to not cache the dynamic JSF pages, otherwise the browser may show them from the cache instead of requesting a fresh one from the server when you send a GET request on it (e.g. by back button).
The javax.faces.ViewState hidden field of the cached page may contain a view state ID value which is not valid anymore in the current session. If you're (ab)using POST (command links/buttons) instead of GET (regular links/buttons) for page-to-page navigation, and click such a command link/button on the cached page, then this will in turn fail with a ViewExpiredException.
To fire a redirect after logout in JSF 2.0, either add <redirect /> to the <navigation-case> in question (if any), or add ?faces-redirect=true to the outcome value.
<h:commandButton value="Logout" action="logout?faces-redirect=true" />
or
public String logout() {
// ...
return "index?faces-redirect=true";
}
To instruct the browser to not cache the dynamic JSF pages, create a Filter which is mapped on the servlet name of the FacesServlet and adds the needed response headers to disable the browser cache. E.g.
#WebFilter(servletNames={"Faces Servlet"}) // Must match <servlet-name> of your FacesServlet.
public class NoCacheFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (!req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
res.setHeader("Pragma", "no-cache"); // HTTP 1.0.
res.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(request, response);
}
// ...
}
Avoiding ViewExpiredException on page refresh
In order to avoid ViewExpiredException when refreshing the current page when the state saving is set to server, you not only need to make sure you are performing page-to-page navigation exclusively by GET (regular links/buttons), but you also need to make sure that you are exclusively using ajax to submit the forms. If you're submitting the form synchronously (non-ajax) anyway, then you'd best either make the view stateless (see later section), or to send a redirect after POST (see previous section).
Having a ViewExpiredException on page refresh is in default configuration a very rare case. It can only happen when the limit on the amount of views JSF will store in the session is hit. So, it will only happen when you've manually set that limit way too low, or that you're continuously creating new views in the "background" (e.g. by a badly implemented ajax poll in the same page or by a badly implemented 404 error page on broken images of the same page). See also com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews for detail on that limit. Another cause is having duplicate JSF libraries in runtime classpath conflicting each other. The correct procedure to install JSF is outlined in our JSF wiki page.
Handling ViewExpiredException
When you want to handle an unavoidable ViewExpiredException after a POST action on an arbitrary page which was already opened in some browser tab/window while you're logged out in another tab/window, then you'd like to specify an error-page for that in web.xml which goes to a "Your session is timed out" page. E.g.
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/WEB-INF/errorpages/expired.xhtml</location>
</error-page>
Use if necessary a meta refresh header in the error page in case you intend to actually redirect further to home or login page.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Session expired</title>
<meta http-equiv="refresh" content="0;url=#{request.contextPath}/login.xhtml" />
</head>
<body>
<h1>Session expired</h1>
<h3>You will be redirected to login page</h3>
<p>Click here if redirect didn't work or when you're impatient.</p>
</body>
</html>
(the 0 in content represents the amount of seconds before redirect, 0 thus means "redirect immediately", you can use e.g. 3 to let the browser wait 3 seconds with the redirect)
Note that handling exceptions during ajax requests requires a special ExceptionHandler. See also Session timeout and ViewExpiredException handling on JSF/PrimeFaces ajax request. You can find a live example at OmniFaces FullAjaxExceptionHandler showcase page (this also covers non-ajax requests).
Also note that your "general" error page should be mapped on <error-code> of 500 instead of an <exception-type> of e.g. java.lang.Exception or java.lang.Throwable, otherwise all exceptions wrapped in ServletException such as ViewExpiredException would still end up in the general error page. See also ViewExpiredException shown in java.lang.Throwable error-page in web.xml.
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/errorpages/general.xhtml</location>
</error-page>
Stateless views
A completely different alternative is to run JSF views in stateless mode. This way nothing of JSF state will be saved and the views will never expire, but just be rebuilt from scratch on every request. You can turn on stateless views by setting the transient attribute of <f:view> to true:
<f:view transient="true">
</f:view>
This way the javax.faces.ViewState hidden field will get a fixed value of "stateless" in Mojarra (have not checked MyFaces at this point). Note that this feature was introduced in Mojarra 2.1.19 and 2.2.0 and is not available in older versions.
The consequence is that you cannot use view scoped beans anymore. They will now behave like request scoped beans. One of the disadvantages is that you have to track the state yourself by fiddling with hidden inputs and/or loose request parameters. Mainly those forms with input fields with rendered, readonly or disabled attributes which are controlled by ajax events will be affected.
Note that the <f:view> does not necessarily need to be unique throughout the view and/or reside in the master template only. It's also completely legit to redeclare and nest it in a template client. It basically "extends" the parent <f:view> then. E.g. in master template:
<f:view contentType="text/html">
<ui:insert name="content" />
</f:view>
and in template client:
<ui:define name="content">
<f:view transient="true">
<h:form>...</h:form>
</f:view>
</f:view>
You can even wrap the <f:view> in a <c:if> to make it conditional. Note that it would apply on the entire view, not only on the nested contents, such as the <h:form> in above example.
See also
ViewExpiredException shown in java.lang.Throwable error-page in web.xml
Check if session exists JSF
Session timeout and ViewExpiredException handling on JSF/PrimeFaces ajax request
Unrelated to the concrete problem, using HTTP POST for pure page-to-page navigation isn't very user/SEO friendly. In JSF 2.0 you should really prefer <h:link> or <h:button> over the <h:commandXxx> ones for plain vanilla page-to-page navigation.
So instead of e.g.
<h:form id="menu">
<h:commandLink value="Foo" action="foo?faces-redirect=true" />
<h:commandLink value="Bar" action="bar?faces-redirect=true" />
<h:commandLink value="Baz" action="baz?faces-redirect=true" />
</h:form>
better do
<h:link value="Foo" outcome="foo" />
<h:link value="Bar" outcome="bar" />
<h:link value="Baz" outcome="baz" />
See also
When should I use h:outputLink instead of h:commandLink?
Difference between h:button and h:commandButton
How to navigate in JSF? How to make URL reflect current page (and not previous one)

Have you tried adding lines below to your web.xml?
<context-param>
<param-name>com.sun.faces.enableRestoreView11Compatibility</param-name>
<param-value>true</param-value>
</context-param>
I found this to be very effective when I encountered this issue.

First what you have to do, before changing web.xml is to make sure your ManagedBean implements Serializable:
#ManagedBean
#ViewScoped
public class Login implements Serializable {
}
Especially if you use MyFaces

Avoid multipart forms in Richfaces:
<h:form enctype="multipart/form-data">
<a4j:poll id="poll" interval="10000"/>
</h:form>
If you are using Richfaces, i have found that ajax requests inside of multipart forms return a new View ID on each request.
How to debug:
On each ajax request a View ID is returned, that is fine as long as the View ID is always the same. If you get a new View ID on each request, then there is a problem and must be fixed.

I resolved this problem in JAVA EE 8 using AjaxExceptionHandler tag of Primefaces this is available from Primefaces 7 or higher (i am using and test in 11 version). Is so easy and you can combine this with a custom ExceptionHandlerWrapper as BalusC suggests. Use onShow event like this if you need that the page reload are auto.
<p:ajaxExceptionHandler type="javax.faces.application.ViewExpiredException"
update="viewExpiredDialog"
onexception="PF('viewExpiredDialog').show();" />
<p:dialog id="viewExpiredDialog" header="Session expired"
widgetVar="viewExpiredDialog" height="250px"
onShow="document.location.href = document.location.href;">
<h3>Reloading page</h3>
<p>Message...</p>
<!--Here, you decide that you need-->
<h:commandButton value="Reload" action="index?faces-redirect=true" />
Reload.
</p:dialog>
Add this configuration to faces-config.xml file. See ExceptionHandler and Error Handling
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.3" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd">
<application>
<el-resolver>
org.primefaces.application.exceptionhandler.PrimeExceptionHandlerELResolver
</el-resolver>
</application>
<factory>
<exception-handler-factory>
org.primefaces.application.exceptionhandler.PrimeExceptionHandlerFactory
</exception-handler-factory>
</factory>
</faces-config>
And VoilĂ  this works like clockwork. Regards.

You coud use your own custom AjaxExceptionHandler or primefaces-extensions
Update your faces-config.xml
...
<factory>
<exception-handler-factory>org.primefaces.extensions.component.ajaxerrorhandler.AjaxExceptionHandlerFactory</exception-handler-factory>
</factory>
...
Add following code in your jsf page
...
<pe:ajaxErrorHandler />
...

I was getting this error : javax.faces.application.ViewExpiredException.When I using different requests, I found those having same JsessionId, even after restarting the server.
So this is due to the browser cache. Just close the browser and try, it will work.

When our page is idle for x amount of time the view will expire and throw javax.faces.application.ViewExpiredException to prevent this from happening
one solution is to create CustomViewHandler that extends ViewHandler
and override restoreView method all the other methods are being delegated to the Parent
import java.io.IOException;
import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
public class CustomViewHandler extends ViewHandler {
private ViewHandler parent;
public CustomViewHandler(ViewHandler parent) {
//System.out.println("CustomViewHandler.CustomViewHandler():Parent View Handler:"+parent.getClass());
this.parent = parent;
}
#Override
public UIViewRoot restoreView(FacesContext facesContext, String viewId) {
/**
* {#link javax.faces.application.ViewExpiredException}. This happens only when we try to logout from timed out pages.
*/
UIViewRoot root = null;
root = parent.restoreView(facesContext, viewId);
if(root == null) {
root = createView(facesContext, viewId);
}
return root;
}
#Override
public Locale calculateLocale(FacesContext facesContext) {
return parent.calculateLocale(facesContext);
}
#Override
public String calculateRenderKitId(FacesContext facesContext) {
String renderKitId = parent.calculateRenderKitId(facesContext);
//System.out.println("CustomViewHandler.calculateRenderKitId():RenderKitId: "+renderKitId);
return renderKitId;
}
#Override
public UIViewRoot createView(FacesContext facesContext, String viewId) {
return parent.createView(facesContext, viewId);
}
#Override
public String getActionURL(FacesContext facesContext, String actionId) {
return parent.getActionURL(facesContext, actionId);
}
#Override
public String getResourceURL(FacesContext facesContext, String resId) {
return parent.getResourceURL(facesContext, resId);
}
#Override
public void renderView(FacesContext facesContext, UIViewRoot viewId) throws IOException, FacesException {
parent.renderView(facesContext, viewId);
}
#Override
public void writeState(FacesContext facesContext) throws IOException {
parent.writeState(facesContext);
}
public ViewHandler getParent() {
return parent;
}
}
Then you need to add it to your faces-config.xml
<application>
<view-handler>com.demo.CustomViewHandler</view-handler>
</application>
Thanks for the original answer on the below link:
http://www.gregbugaj.com/?p=164

Please add this line in your web.xml
It works for me
<context-param>
<param-name>org.ajax4jsf.handleViewExpiredOnClient</param-name>
<param-value>true</param-value>
</context-param>

I ran into this problem myself and realized that it was because of a side-effect of a Filter that I created which was filtering all requests on the appliation. As soon as I modified the filter to pick only certain requests, this problem did not occur. It maybe good to check for such filters in your application and see how they behave.

I add the following configuration to web.xml and it got resolved.
<context-param>
<param-name>com.sun.faces.numberOfViewsInSession</param-name>
<param-value>500</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.numberOfLogicalViews</param-name>
<param-value>500</param-value>
</context-param>

Related

Value change listner not working in jsf [duplicate]

I have written simple application with container-managed security. The problem is when I log in and open another page on which I logout, then I come back to first page and I click on any link etc or refresh page I get this exception. I guess it's normal (or maybe not:)) because I logged out and session is destroyed. What should I do to redirect user to for example index.xhtml or login.xhtml and save him from seeing that error page/message?
In other words how can I automatically redirect other pages to index/login page after I log out?
Here it is:
javax.faces.application.ViewExpiredException: viewId:/index.xhtml - View /index.xhtml could not be restored.
at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:212)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:110)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:312)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at filter.HttpHttpsFilter.doFilter(HttpHttpsFilter.java:66)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:277)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
at java.lang.Thread.run(Thread.java:619)
Introduction
The ViewExpiredException will be thrown whenever the javax.faces.STATE_SAVING_METHOD is set to server (default) and the enduser sends a HTTP POST request on a view via <h:form> with <h:commandLink>, <h:commandButton> or <f:ajax>, while the associated view state isn't available in the session anymore.
The view state is identified as value of a hidden input field javax.faces.ViewState of the <h:form>. With the state saving method set to server, this contains only the view state ID which references a serialized view state in the session. So, when the session is expired or absent for one of the following reasons ...
session object is timed out in server
session cookie is timed out in client
session cookie is deleted in client
HttpSession#invalidate() is called in server
SameSite=None is missing on session cookie (and thus e.g. Chrome won't send them along when a 3rd party site (e.g. payment) navigates back to your site via a callback URL)
... then the serialized view state is not available anymore in the session and the enduser will get this exception. To understand the working of the session, see also How do servlets work? Instantiation, sessions, shared variables and multithreading.
There is also a limit on the amount of views JSF will store in the session. When the limit is hit, then the least recently used view will be expired. See also com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews.
With the state saving method set to client, the javax.faces.ViewState hidden input field contains instead the whole serialized view state, so the enduser won't get a ViewExpiredException when the session expires. It can however still happen on a cluster environment ("ERROR: MAC did not verify" is symptomatic) and/or when there's a implementation-specific timeout on the client side state configured and/or when server re-generates the AES key during restart, see also Getting ViewExpiredException in clustered environment while state saving method is set to client and user session is valid how to solve it.
Regardless of the solution, make sure you do not use enableRestoreView11Compatibility. it does not at all restore the original view state. It basically recreates the view and all associated view scoped beans from scratch and hereby thus losing all of original data (state). As the application will behave in a confusing way ("Hey, where are my input values..??"), this is very bad for user experience. Better use stateless views or <o:enableRestorableView> instead so you can manage it on a specific view only instead of on all views.
As to the why JSF needs to save view state, head to this answer: Why JSF saves the state of UI components on server?
Avoiding ViewExpiredException on page navigation
In order to avoid ViewExpiredException when e.g. navigating back after logout when the state saving is set to server, only redirecting the POST request after logout is not sufficient. You also need to instruct the browser to not cache the dynamic JSF pages, otherwise the browser may show them from the cache instead of requesting a fresh one from the server when you send a GET request on it (e.g. by back button).
The javax.faces.ViewState hidden field of the cached page may contain a view state ID value which is not valid anymore in the current session. If you're (ab)using POST (command links/buttons) instead of GET (regular links/buttons) for page-to-page navigation, and click such a command link/button on the cached page, then this will in turn fail with a ViewExpiredException.
To fire a redirect after logout in JSF 2.0, either add <redirect /> to the <navigation-case> in question (if any), or add ?faces-redirect=true to the outcome value.
<h:commandButton value="Logout" action="logout?faces-redirect=true" />
or
public String logout() {
// ...
return "index?faces-redirect=true";
}
To instruct the browser to not cache the dynamic JSF pages, create a Filter which is mapped on the servlet name of the FacesServlet and adds the needed response headers to disable the browser cache. E.g.
#WebFilter(servletNames={"Faces Servlet"}) // Must match <servlet-name> of your FacesServlet.
public class NoCacheFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (!req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
res.setHeader("Pragma", "no-cache"); // HTTP 1.0.
res.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(request, response);
}
// ...
}
Avoiding ViewExpiredException on page refresh
In order to avoid ViewExpiredException when refreshing the current page when the state saving is set to server, you not only need to make sure you are performing page-to-page navigation exclusively by GET (regular links/buttons), but you also need to make sure that you are exclusively using ajax to submit the forms. If you're submitting the form synchronously (non-ajax) anyway, then you'd best either make the view stateless (see later section), or to send a redirect after POST (see previous section).
Having a ViewExpiredException on page refresh is in default configuration a very rare case. It can only happen when the limit on the amount of views JSF will store in the session is hit. So, it will only happen when you've manually set that limit way too low, or that you're continuously creating new views in the "background" (e.g. by a badly implemented ajax poll in the same page or by a badly implemented 404 error page on broken images of the same page). See also com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews for detail on that limit. Another cause is having duplicate JSF libraries in runtime classpath conflicting each other. The correct procedure to install JSF is outlined in our JSF wiki page.
Handling ViewExpiredException
When you want to handle an unavoidable ViewExpiredException after a POST action on an arbitrary page which was already opened in some browser tab/window while you're logged out in another tab/window, then you'd like to specify an error-page for that in web.xml which goes to a "Your session is timed out" page. E.g.
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/WEB-INF/errorpages/expired.xhtml</location>
</error-page>
Use if necessary a meta refresh header in the error page in case you intend to actually redirect further to home or login page.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Session expired</title>
<meta http-equiv="refresh" content="0;url=#{request.contextPath}/login.xhtml" />
</head>
<body>
<h1>Session expired</h1>
<h3>You will be redirected to login page</h3>
<p>Click here if redirect didn't work or when you're impatient.</p>
</body>
</html>
(the 0 in content represents the amount of seconds before redirect, 0 thus means "redirect immediately", you can use e.g. 3 to let the browser wait 3 seconds with the redirect)
Note that handling exceptions during ajax requests requires a special ExceptionHandler. See also Session timeout and ViewExpiredException handling on JSF/PrimeFaces ajax request. You can find a live example at OmniFaces FullAjaxExceptionHandler showcase page (this also covers non-ajax requests).
Also note that your "general" error page should be mapped on <error-code> of 500 instead of an <exception-type> of e.g. java.lang.Exception or java.lang.Throwable, otherwise all exceptions wrapped in ServletException such as ViewExpiredException would still end up in the general error page. See also ViewExpiredException shown in java.lang.Throwable error-page in web.xml.
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/errorpages/general.xhtml</location>
</error-page>
Stateless views
A completely different alternative is to run JSF views in stateless mode. This way nothing of JSF state will be saved and the views will never expire, but just be rebuilt from scratch on every request. You can turn on stateless views by setting the transient attribute of <f:view> to true:
<f:view transient="true">
</f:view>
This way the javax.faces.ViewState hidden field will get a fixed value of "stateless" in Mojarra (have not checked MyFaces at this point). Note that this feature was introduced in Mojarra 2.1.19 and 2.2.0 and is not available in older versions.
The consequence is that you cannot use view scoped beans anymore. They will now behave like request scoped beans. One of the disadvantages is that you have to track the state yourself by fiddling with hidden inputs and/or loose request parameters. Mainly those forms with input fields with rendered, readonly or disabled attributes which are controlled by ajax events will be affected.
Note that the <f:view> does not necessarily need to be unique throughout the view and/or reside in the master template only. It's also completely legit to redeclare and nest it in a template client. It basically "extends" the parent <f:view> then. E.g. in master template:
<f:view contentType="text/html">
<ui:insert name="content" />
</f:view>
and in template client:
<ui:define name="content">
<f:view transient="true">
<h:form>...</h:form>
</f:view>
</f:view>
You can even wrap the <f:view> in a <c:if> to make it conditional. Note that it would apply on the entire view, not only on the nested contents, such as the <h:form> in above example.
See also
ViewExpiredException shown in java.lang.Throwable error-page in web.xml
Check if session exists JSF
Session timeout and ViewExpiredException handling on JSF/PrimeFaces ajax request
Unrelated to the concrete problem, using HTTP POST for pure page-to-page navigation isn't very user/SEO friendly. In JSF 2.0 you should really prefer <h:link> or <h:button> over the <h:commandXxx> ones for plain vanilla page-to-page navigation.
So instead of e.g.
<h:form id="menu">
<h:commandLink value="Foo" action="foo?faces-redirect=true" />
<h:commandLink value="Bar" action="bar?faces-redirect=true" />
<h:commandLink value="Baz" action="baz?faces-redirect=true" />
</h:form>
better do
<h:link value="Foo" outcome="foo" />
<h:link value="Bar" outcome="bar" />
<h:link value="Baz" outcome="baz" />
See also
When should I use h:outputLink instead of h:commandLink?
Difference between h:button and h:commandButton
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Have you tried adding lines below to your web.xml?
<context-param>
<param-name>com.sun.faces.enableRestoreView11Compatibility</param-name>
<param-value>true</param-value>
</context-param>
I found this to be very effective when I encountered this issue.
First what you have to do, before changing web.xml is to make sure your ManagedBean implements Serializable:
#ManagedBean
#ViewScoped
public class Login implements Serializable {
}
Especially if you use MyFaces
Avoid multipart forms in Richfaces:
<h:form enctype="multipart/form-data">
<a4j:poll id="poll" interval="10000"/>
</h:form>
If you are using Richfaces, i have found that ajax requests inside of multipart forms return a new View ID on each request.
How to debug:
On each ajax request a View ID is returned, that is fine as long as the View ID is always the same. If you get a new View ID on each request, then there is a problem and must be fixed.
I resolved this problem in JAVA EE 8 using AjaxExceptionHandler tag of Primefaces this is available from Primefaces 7 or higher (i am using and test in 11 version). Is so easy and you can combine this with a custom ExceptionHandlerWrapper as BalusC suggests. Use onShow event like this if you need that the page reload are auto.
<p:ajaxExceptionHandler type="javax.faces.application.ViewExpiredException"
update="viewExpiredDialog"
onexception="PF('viewExpiredDialog').show();" />
<p:dialog id="viewExpiredDialog" header="Session expired"
widgetVar="viewExpiredDialog" height="250px"
onShow="document.location.href = document.location.href;">
<h3>Reloading page</h3>
<p>Message...</p>
<!--Here, you decide that you need-->
<h:commandButton value="Reload" action="index?faces-redirect=true" />
Reload.
</p:dialog>
Add this configuration to faces-config.xml file. See ExceptionHandler and Error Handling
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.3" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd">
<application>
<el-resolver>
org.primefaces.application.exceptionhandler.PrimeExceptionHandlerELResolver
</el-resolver>
</application>
<factory>
<exception-handler-factory>
org.primefaces.application.exceptionhandler.PrimeExceptionHandlerFactory
</exception-handler-factory>
</factory>
</faces-config>
And VoilĂ  this works like clockwork. Regards.
You coud use your own custom AjaxExceptionHandler or primefaces-extensions
Update your faces-config.xml
...
<factory>
<exception-handler-factory>org.primefaces.extensions.component.ajaxerrorhandler.AjaxExceptionHandlerFactory</exception-handler-factory>
</factory>
...
Add following code in your jsf page
...
<pe:ajaxErrorHandler />
...
I was getting this error : javax.faces.application.ViewExpiredException.When I using different requests, I found those having same JsessionId, even after restarting the server.
So this is due to the browser cache. Just close the browser and try, it will work.
When our page is idle for x amount of time the view will expire and throw javax.faces.application.ViewExpiredException to prevent this from happening
one solution is to create CustomViewHandler that extends ViewHandler
and override restoreView method all the other methods are being delegated to the Parent
import java.io.IOException;
import javax.faces.FacesException;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
public class CustomViewHandler extends ViewHandler {
private ViewHandler parent;
public CustomViewHandler(ViewHandler parent) {
//System.out.println("CustomViewHandler.CustomViewHandler():Parent View Handler:"+parent.getClass());
this.parent = parent;
}
#Override
public UIViewRoot restoreView(FacesContext facesContext, String viewId) {
/**
* {#link javax.faces.application.ViewExpiredException}. This happens only when we try to logout from timed out pages.
*/
UIViewRoot root = null;
root = parent.restoreView(facesContext, viewId);
if(root == null) {
root = createView(facesContext, viewId);
}
return root;
}
#Override
public Locale calculateLocale(FacesContext facesContext) {
return parent.calculateLocale(facesContext);
}
#Override
public String calculateRenderKitId(FacesContext facesContext) {
String renderKitId = parent.calculateRenderKitId(facesContext);
//System.out.println("CustomViewHandler.calculateRenderKitId():RenderKitId: "+renderKitId);
return renderKitId;
}
#Override
public UIViewRoot createView(FacesContext facesContext, String viewId) {
return parent.createView(facesContext, viewId);
}
#Override
public String getActionURL(FacesContext facesContext, String actionId) {
return parent.getActionURL(facesContext, actionId);
}
#Override
public String getResourceURL(FacesContext facesContext, String resId) {
return parent.getResourceURL(facesContext, resId);
}
#Override
public void renderView(FacesContext facesContext, UIViewRoot viewId) throws IOException, FacesException {
parent.renderView(facesContext, viewId);
}
#Override
public void writeState(FacesContext facesContext) throws IOException {
parent.writeState(facesContext);
}
public ViewHandler getParent() {
return parent;
}
}
Then you need to add it to your faces-config.xml
<application>
<view-handler>com.demo.CustomViewHandler</view-handler>
</application>
Thanks for the original answer on the below link:
http://www.gregbugaj.com/?p=164
Please add this line in your web.xml
It works for me
<context-param>
<param-name>org.ajax4jsf.handleViewExpiredOnClient</param-name>
<param-value>true</param-value>
</context-param>
I ran into this problem myself and realized that it was because of a side-effect of a Filter that I created which was filtering all requests on the appliation. As soon as I modified the filter to pick only certain requests, this problem did not occur. It maybe good to check for such filters in your application and see how they behave.
I add the following configuration to web.xml and it got resolved.
<context-param>
<param-name>com.sun.faces.numberOfViewsInSession</param-name>
<param-value>500</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.numberOfLogicalViews</param-name>
<param-value>500</param-value>
</context-param>

How do I get JSF to redirect to the default 401 page from within a managed bean? [duplicate]

In a JSF managed bean constructor, I load a entity from database usint a request parameter. Some times, the entity is not in database and I want to show other JSF (.xhtml) page with 404 message.
This is a sample of managed bean:
#ManagedBean(name = "someBean")
#RequestScoped
public class SomeBean implements Serializable {
private static final long serialVersionUID = 1L;
private SomeData someData;
public SomeBean() throws IOException {
someData = ... loads from database using JPA features
if(someData == null){
HttpServletResponse response = (HttpServletResponse) FacesContext
.getCurrentInstance().getExternalContext().getResponse();
response.sendError(404);
}
}
public SomeData getSomeData(){
return someData;
}
}
I configured the web.xml file something like that:
<error-page>
<error-code>404</error-code>
<location>/404.xhtml</location>
</error-page>
I have a JSF page to handle the entity loaded by managed bean. When the entity exists, I will use it in the page. Like that:
<h1>#{someBean.someEntity.name}</h1>
<h2>#{someBean.someEntity.description}</h2>
<ui:repeat value="#{someBean.someEntity.books}" var="book">
// ..........
</ui:repeat>
The page above works when the managed loads the data successfully.
The Problem
When the entity not exists and I send a 404 ERROR CODE, the JSF still process methods defined in the expression language of the first page.
This behavior makes the managed bean throws a NullPointerException, and a HTTP 500 ERRO CODE.
My 404 error page is not called. I do not know why.
I try send the 404 error even when the entity is found in database and the 404 error page works.
Enyone can explain this JSF behavior to this happiness? Or offer some kind to show the 404 error page without URL change ?
You're basically trying to perform front controller logic while rendering the view. You should do it before rendering the view. Because, once you start rendering the view, it's already too late to change the view to a different destination, e.g. an error page as in your case. You namely cannot take the already sent response back from the client.
In JSF 2.2 you can use <f:viewAction> for this.
<f:metadata>
<f:viewAction action="#{bean.init}" />
</f:metadata>
public void init() {
// ...
if (someCondition) {
context.getExternalContext().responseSendError(404, "some message");
context.responseComplete();
}
}
(note that whenever you need to import javax.servlet.* classes into your JSF backing bean, you should absolutely stop and look if the functionality isn't already available in ExternalContext or otherwise think twice if you're doing things the right way, e.g. perhaps you needed a servlet filter; also note that you need to explicitly tell JSF that you've completed the response, otherwise it will still attempt to render the view)
In JSF 2.0/2.1 you can use <f:event type="preRenderView"> for this. See also among others What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
In case you're actually trying to validate a HTTP request parameter and you also happen to use OmniFaces, you may consider using <f:viewParam> with a true JSF validator and control the sendError with OmniFaces <o:viewParamValidationFailed>.

JSF calls methods when managed bean constructor sends 404 ERROR CODE

In a JSF managed bean constructor, I load a entity from database usint a request parameter. Some times, the entity is not in database and I want to show other JSF (.xhtml) page with 404 message.
This is a sample of managed bean:
#ManagedBean(name = "someBean")
#RequestScoped
public class SomeBean implements Serializable {
private static final long serialVersionUID = 1L;
private SomeData someData;
public SomeBean() throws IOException {
someData = ... loads from database using JPA features
if(someData == null){
HttpServletResponse response = (HttpServletResponse) FacesContext
.getCurrentInstance().getExternalContext().getResponse();
response.sendError(404);
}
}
public SomeData getSomeData(){
return someData;
}
}
I configured the web.xml file something like that:
<error-page>
<error-code>404</error-code>
<location>/404.xhtml</location>
</error-page>
I have a JSF page to handle the entity loaded by managed bean. When the entity exists, I will use it in the page. Like that:
<h1>#{someBean.someEntity.name}</h1>
<h2>#{someBean.someEntity.description}</h2>
<ui:repeat value="#{someBean.someEntity.books}" var="book">
// ..........
</ui:repeat>
The page above works when the managed loads the data successfully.
The Problem
When the entity not exists and I send a 404 ERROR CODE, the JSF still process methods defined in the expression language of the first page.
This behavior makes the managed bean throws a NullPointerException, and a HTTP 500 ERRO CODE.
My 404 error page is not called. I do not know why.
I try send the 404 error even when the entity is found in database and the 404 error page works.
Enyone can explain this JSF behavior to this happiness? Or offer some kind to show the 404 error page without URL change ?
You're basically trying to perform front controller logic while rendering the view. You should do it before rendering the view. Because, once you start rendering the view, it's already too late to change the view to a different destination, e.g. an error page as in your case. You namely cannot take the already sent response back from the client.
In JSF 2.2 you can use <f:viewAction> for this.
<f:metadata>
<f:viewAction action="#{bean.init}" />
</f:metadata>
public void init() {
// ...
if (someCondition) {
context.getExternalContext().responseSendError(404, "some message");
context.responseComplete();
}
}
(note that whenever you need to import javax.servlet.* classes into your JSF backing bean, you should absolutely stop and look if the functionality isn't already available in ExternalContext or otherwise think twice if you're doing things the right way, e.g. perhaps you needed a servlet filter; also note that you need to explicitly tell JSF that you've completed the response, otherwise it will still attempt to render the view)
In JSF 2.0/2.1 you can use <f:event type="preRenderView"> for this. See also among others What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
In case you're actually trying to validate a HTTP request parameter and you also happen to use OmniFaces, you may consider using <f:viewParam> with a true JSF validator and control the sendError with OmniFaces <o:viewParamValidationFailed>.

Why jsf life cycle skips render response after Invoke application when redirect the page?

I have two scenario
I have two actions which have logic in bean like
My buttons
<h:commandButton value="Submit" action="#{bean.test}" />
<h:commandButton value="Submit" action="#{bean.testOne}" />
This are the two commnadButtons and there logic in bean
public void test() {
log.info("I m in test");
}
public void testOne() {
log.info("I m in testOne");
try {
FacesContext.getCurrentInstance()
.addMessage("", new FacesMessage("Record Saved successfully."));
FacesContext
.getCurrentInstance()
.getExternalContext()
.redirect(
FacesContext.getCurrentInstance()
.getExternalContext().getRequestContextPath()
+ "/cycle/page");
} catch (IOException e) {
log.error(e.getMessage());
}
}
When I am going to click on 1st button (test action) that time jsf life cycle goes to every phase like restore view Apply request valuesProcess validationupdate modelsinvoke applicationrender response
But when I click on testOne button that time jsf life cycle skip render response after invoke application like restore view Apply request valuesProcess validationupdate modelsinvoke applicationrestore viewrender response
In simple language When I am navigate the page through facesContext that time jsf skips that phase.
But why this happens? I am not getting the problem.
According to the JSF docs, that's what the INVOKE_APPLICATION phase does:
During this phase, the JavaServer Faces implementation handles any application-level events, such as submitting a form or linking to another page.
At this point, if the application needs to redirect to a different web application resource or generate a response that does not contain any JavaServer Faces components, it can call the FacesContext.responseComplete method.
If the view being processed was reconstructed from state information from a previous request and if a component has fired an event, these events are broadcast to interested listeners.
Finally, the JavaServer Faces implementation transfers control to the Render Response phase.
What you're doing is calling FacesContext#getCurrentInstance#getExternalContext#redirect in this phase, which performs your redirection. This method triggers FacesContext#getCurrentInstance#responseComplete, which ends the JSF lifecycle. The redirection is performed to a JSF view, so a new cycle starts after that.
Apart from that and unrelated to the concrete issue, do not perform redirections like that if you want to redirect to an internal JSF view. Just return the navigation case + ?faces-redirect=true in your action method (i.e. /cycle/page?faces-redirect=true). Use the external context only if you want to access external urls.
See also:
JSF INVOKE_APPLICATION
Redirection in JSF

JSF1.2 to JSF2.1 migration: Using a4j:ajax / f:ajax on First page causes: "ReferenceError: RichFaces / jsf is not defined"

I am migrating JSF1.2 application to JSF 2.1. It has a Login page, which uses facelets template. And the template page has h:head tag. Login page has a tag h:selectBooleanCheckbox inside ui:composition/ui:define/h:form/a4j:outputPanel/h:panelGrid/h:panelGroup tags.
<h:selectBooleanCheckbox value="#{bean.alogin}" >
<a4j:ajax event="click" execute="#form" render="loginPanel" />
</h:selectBooleanCheckbox>
On click of check box, I am getting 'ReferenceError: RichFaces is not defined' in Browser Error Console.
The issue is same even with using f:ajax tag, and having
<h:outputScript name="jsf.js" library="javax.faces" target="head"/>
in template page/login page.
This issue (of not finding/loading js libs) is coming only on the First load of Login page. That means if I login to my application and logout and then use the above check box, there is no issue.
Please direct with any pointers and that will be very helpful.
Thanks very much in advance.
And following is the html generated in head tag:
<script src="/myapp/javax.faces.resource/jsf.js.faces?ln=javax.faces" type="text/javascript"><!--
//--></script>
I have the two *.faces mappings in web.xml. One is CustomFilter (implementing javax.servlet.Filter) and the other is CustomServlet (extending org.apache.myfaces.webapp.MyFacesServlet).
ReferenceError: RichFaces / jsf is not defined
This is a JavaScript error. This means that neither var RichFaces = ...; nor var jsf = ...; is anywhere been defined in JavaScript context. This in turn means that auto-including the JSF and RichFaces-provided JavaScript files jsf.js and richfaces.js has failed. This can in turn be caused by not having used the <h:head> component to declare the HTML head which is a mandatory hook for JSF to auto-include JavaScript files.
Apparently you forgot to replace the
<head>
...
</head>
in your templates by
<h:head>
...
</h:head>
Fix it accordingly.
Using <h:outputScript name="jsf.js" library="javax.faces" target="head"/> only fixes the JSF part of the error, not the RichFaces part and is actually a workaround, not a solution.
Update: as per your question update, you confirmed that you've mapped sort of a login Filter on the exact URL pattern of those resources (at least, the filter name "session filter" in combination with the problem symptoms described so far indicates that you're blocking requests whereby the user is not logged-in). JSF resources are served by *.faces URL pattern through the FacesServlet as well and thus they are checked by that filter as well (if you have studied the generated <script src> URL closely, you'd have realized that).
You likely need to alter your Filter to skip the logged-in check on those resources so that those resources won't be redirected to the login page as well. You could do that by checking if the request URI does not concern the ResourceHandeler.RESOURCE_IDENTIFIER URLs.
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) {
chain.doFilter(request, response); // Skip JSF resources (CSS/JS/Images/etc)
return;
}
// ... Continue your login check here.
}

Resources