Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Session timeout and ViewExpiredException handling on JSF/PrimeFaces ajax request

I find this article to be useful for non-ajax request How to handle session expiration and ViewExpiredException in JSF 2? but I can't make use of this when I am submitting using an AJAX call.

Suppose in a primefaces dialog, I am making a post request using AJAX and session has already timed out. I see my page getting stuck.

How to fix this kind of scenario such that when I post using AJAX, I could redirect him to my view expired page and then forward him to the login page similar to the solution in the link above?

JSF2/Primefaces/Glassfish

like image 261
Mark Estrada Avatar asked Jun 26 '12 08:06

Mark Estrada


People also ask

How does JSF handle session timeout?

To handle the exception whenever the user invokes a synchronous POST request on a page while the HTTP session has been expired and the JSF view state saving method is set to server , add an <error-page> to the web. xml which catches the JSF ViewExpiredException and shows the home page.

What is Ajax in Primefaces?

Ajax Attributes It is used to process in partial request. Immediate. false. boolean. It returns a boolean value that determines the phaseId, when true actions are processed at apply_request_values, when false at invoke_application phase.


2 Answers

Exceptions which are thrown during ajax requests have by default totally no feedback in the client side. Only when you run Mojarra with project stage set to Development and use <f:ajax>, then you will get a bare JavaScript alert with the exception type and message. But other than that, and in PrimeFaces, there's by default no feedback at all. You can however see the exception in the server log and in the ajax response (in the webbrowser's developer toolset's "Network" section).

You need to implement a custom ExceptionHandler which does basically the following job when there's a ViewExpiredException in the queue:

String errorPageLocation = "/WEB-INF/errorpages/expired.xhtml"; context.setViewRoot(context.getApplication().getViewHandler().createView(context, errorPageLocation)); context.getPartialViewContext().setRenderAll(true); context.renderResponse(); 

Alternatively, you could use the JSF utility library OmniFaces. It has a FullAjaxExceptionHandler for exactly this purpose (source code here, showcase demo here).

See also:

  • Why use a JSF ExceptionHandlerFactory instead of <error-page> redirection?
  • What is the correct way to deal with JSF 2.0 exceptions for AJAXified components?
like image 178
BalusC Avatar answered Sep 20 '22 12:09

BalusC


A merge between the answer of @BalusC and this post, I solved my problem!

My ExceptionHandlerWrapper:

public class CustomExceptionHandler extends ExceptionHandlerWrapper {      private ExceptionHandler wrapped;      CustomExceptionHandler(ExceptionHandler exception) {         this.wrapped = exception;     }      @Override     public ExceptionHandler getWrapped() {         return wrapped;     }      @Override     public void handle() throws FacesException {         final Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();         while (i.hasNext()) {             ExceptionQueuedEvent event = i.next();             ExceptionQueuedEventContext context                     = (ExceptionQueuedEventContext) event.getSource();              // get the exception from context             Throwable t = context.getException();              final FacesContext fc = FacesContext.getCurrentInstance();             final Map<String, Object> requestMap = fc.getExternalContext().getRequestMap();             final NavigationHandler nav = fc.getApplication().getNavigationHandler();              //here you do what ever you want with exception             try {                  //log error ?                 //log.log(Level.SEVERE, "Critical Exception!", t);                 if (t instanceof ViewExpiredException) {                     requestMap.put("javax.servlet.error.message", "Session expired, try again!");                     String errorPageLocation = "/erro.xhtml";                     fc.setViewRoot(fc.getApplication().getViewHandler().createView(fc, errorPageLocation));                     fc.getPartialViewContext().setRenderAll(true);                     fc.renderResponse();                 } else {                     //redirect error page                     requestMap.put("javax.servlet.error.message", t.getMessage());                     nav.handleNavigation(fc, null, "/erro.xhtml");                 }                  fc.renderResponse();                 // remove the comment below if you want to report the error in a jsf error message                 //JsfUtil.addErrorMessage(t.getMessage());             } finally {                 //remove it from queue                 i.remove();             }         }         //parent hanle         getWrapped().handle();     } } 

My ExceptionHandlerFactory:

public class CustomExceptionHandlerFactory extends ExceptionHandlerFactory {      private ExceptionHandlerFactory parent;      // this injection handles jsf     public CustomExceptionHandlerFactory(ExceptionHandlerFactory parent) {         this.parent = parent;     }      @Override     public ExceptionHandler getExceptionHandler() {         ExceptionHandler handler = new CustomExceptionHandler(parent.getExceptionHandler());         return handler;     }  } 

My faces-config.xml

<?xml version='1.0' encoding='UTF-8'?> <faces-config version="2.2"               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_2.xsd">      <factory>         <exception-handler-factory>             your.package.here.CustomExceptionHandlerFactory         </exception-handler-factory>     </factory> </faces-config> 
like image 32
Douglas Nassif Roma Junior Avatar answered Sep 19 '22 12:09

Douglas Nassif Roma Junior