domenica 8 giugno 2014

Gestire sessione non valida con JSF 2.0

Quando in JSF la sessione scade si incappa nella tipica eccezione di tipo

javax.faces.application.ViewExpiredException

Questo errore si verifica quando l'utente richiede una pagina ma la sessione è ormai scaduta, per cui non si riesce a ricostruire l'alberatura degli oggetti propria di JSF.

Un modo molto semplice per ovviare a questa eccezione è quello di dichiararla nel web.xml in questo modo:

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


Il problema di questo approccio è che non gestisce i casi di chiamate ajax, ed essendo ormai il supporto di ajax il comportamento base di tutti i componenti di JSF 2.0 la dichiarazione nel web.xml non basta.

E' necessario quindi creare una classe che estenda

javax.faces.context.ExceptionHandlerWrapper

in questo modo


package it.exceptionHandler;
import it.util.Costanti;
import it.util.Utility;
import java.io.IOException;
import java.util.Iterator;
import javax.faces.FacesException;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ExceptionQueuedEvent;
import org.apache.log4j.Logger;
public class ViexExpiredExceptionHandler extends ExceptionHandlerWrapper {
 private static final Logger log=Logger.getLogger(Costanti.LOGGER);
 private ExceptionHandler parent;
 public ViexExpiredExceptionHandler(ExceptionHandler parent){
  this.parent=parent;
 }

 @Override
 public ExceptionHandler getWrapped() {
  return this.parent;
 }
 @Override
 public void handle() throws FacesException{
   FacesContext facesContext = FacesContext.getCurrentInstance();
         for (Iterator<ExceptionQueuedEvent> iter = getUnhandledExceptionQueuedEvents().iterator(); iter.hasNext();) {
           Throwable exception = iter.next().getContext().getException();

if (exception instanceof ViewExpiredException) {


    final ExternalContext externalContext = facesContext
            .getExternalContext();

    try {


        facesContext.setViewRoot(facesContext.getApplication()
                .getViewHandler()
                .createView(facesContext, "/viewExpired.jsf"));     
        externalContext.redirect("viewExpired.jsf");             
        facesContext.getPartialViewContext().setRenderAll(true);
        facesContext.renderResponse();

    } 
    catch(IOException ioex){
     log.error(Utility.stackToString(ioex));
    }
    finally {
        iter.remove();
    }
}

}

getWrapped().handle();
 }

}


Quindi occorre creare una classe che estenda

javax.faces.context.ExceptionHandlerFactory e che faccia l'override del metodo getExceptionHandler tornando il nostro Handler personalizzato che gestisce la ViewExpiredException.


package it.exceptionHandler;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerFactory;
public class MyExceptionHandlerFactory extends ExceptionHandlerFactory {
    private ExceptionHandlerFactory parent;
    public MyExceptionHandlerFactory(ExceptionHandlerFactory parent){
     this.parent=parent;
    }
 @Override
 public ExceptionHandler getExceptionHandler() {
  ExceptionHandler result=parent.getExceptionHandler();
  result=new ViexExpiredExceptionHandler(result);
  return result;
 }

}


Quindi nel faces-config.xml dobbiamo dichiarare questa factory in questo modo:


<factory>
<exception-handler-factory>it.exceptionHandler.MyExceptionHandlerFactory</exception-handler-factory>
</factory>


Nessun commento:

Posta un commento