2010-06-05 6 views
8

Sto sviluppando un'applicazione JSF 2.0 su Glassfish v3 e sto cercando di gestire ViewExpiredException. Ma qualunque cosa faccia, ottengo sempre un rapporto di errore Glassfish al posto della mia pagina di errore.JSF: impossibile catturare ViewExpiredException

Per simulare l'occorrenza del VEE, ho inserito la seguente funzione nel mio backing bean, che attiva il VEE. Sto attivando questa funzione dalla mia pagina JSF tramite un comando link. Il Codice:

@Named 
public class PersonHome { 
    (...) 
    public void throwVEE() { 
    throw new ViewExpiredException(); 
    } 
} 

In un primo momento ho provato semplicemente aggiungendo un errore-pagina al mio web.xml:

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

Ma questo non funziona, non sto reindirizzato ad errore ma sto mostrato l'ErrorPage Glassfish, che mostra un HTTP stato di 500 pagine con il seguente contenuto:

description:The server encountered an internal error() that prevented it from fulfilling this request. 
exception: javax.servlet.ServletException: javax.faces.application.ViewExpiredException 
root cause: javax.faces.el.EvaluationException:javax.faces.application.ViewExpiredException 
root cause:javax.faces.application.ViewExpiredException 

prossima cosa che ho provato è stato di scrivere ExceptionHandlerFactory e CustomExceptionHandler, come des citato in JavaServerFaces 2.0 - Il riferimento completo. Così ho inserito il seguente tag in faces-config.xml:

<factory> 
    <exception-handler-factory> 
    exceptions.ExceptionHandlerFactory 
    </exception-handler-factory> 
</factory> 

e ha aggiunto queste classi: La fabbrica:

package exceptions; 

import javax.faces.context.ExceptionHandler; 

public class ExceptionHandlerFactory extends javax.faces.context.ExceptionHandlerFactory { 

    private javax.faces.context.ExceptionHandlerFactory parent; 

    public ExceptionHandlerFactory(javax.faces.context.ExceptionHandlerFactory parent) { 
     this.parent = parent; 
    } 

    @Override 
    public ExceptionHandler getExceptionHandler() { 
     ExceptionHandler result = parent.getExceptionHandler(); 
     result = new CustomExceptionHandler(result); 
     return result; 
    } 

} 

Il gestore di eccezioni personalizzato:

package exceptions; 

import java.util.Iterator; 

import javax.faces.FacesException; 
import javax.faces.application.NavigationHandler; 
import javax.faces.application.ViewExpiredException; 
import javax.faces.context.ExceptionHandler; 
import javax.faces.context.ExceptionHandlerWrapper; 
import javax.faces.context.FacesContext; 
import javax.faces.event.ExceptionQueuedEvent; 
import javax.faces.event.ExceptionQueuedEventContext; 

class CustomExceptionHandler extends ExceptionHandlerWrapper { 

    private ExceptionHandler parent; 

    public CustomExceptionHandler(ExceptionHandler parent) { 
     this.parent = parent; 
    } 

    @Override 
    public ExceptionHandler getWrapped() { 
     return this.parent; 
    } 

    @Override 
    public void handle() throws FacesException { 
     for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();) { 
      ExceptionQueuedEvent event = i.next(); 
      System.out.println("Iterating over ExceptionQueuedEvents. Current:" + event.toString()); 
      ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource(); 
      Throwable t = context.getException(); 
      if (t instanceof ViewExpiredException) { 
       ViewExpiredException vee = (ViewExpiredException) t; 
       FacesContext fc = FacesContext.getCurrentInstance(); 

       NavigationHandler nav = 
         fc.getApplication().getNavigationHandler(); 
       try { 
        // Push some useful stuff to the flash scope for 
        // use in the page 
        fc.getExternalContext().getFlash().put("expiredViewId", vee.getViewId()); 

        nav.handleNavigation(fc, null, "/login?faces-redirect=true"); 
        fc.renderResponse(); 

       } finally { 
        i.remove(); 
       } 
      } 
     } 
     // At this point, the queue will not contain any ViewExpiredEvents. 
     // Therefore, let the parent handle them. 
     getWrapped().handle(); 
    } 
} 

ma ancora NON sono reindirizzato alla mia pagina di errore - sto ricevendo lo stesso errore HTTP 500 come sopra. Cosa sto facendo male, cosa potrebbe mancare nella mia implementazione che l'eccezione non venga gestita correttamente? Qualsiasi aiuto altamente apprezzato!

EDIT

Ok, io sono onesto. In effetti, il mio codice è in realtà scritto in Scala, ma questa è una lunga storia. ho pensato che fosse un problema di Java tutto il tempo. L'errore REALE in questo caso era la mia stessa stupidità. Nel mio codice (Scala), in CustomExceptionHandler, ho dimenticato di aggiungere la riga con "i.remove();" Pertanto, ViewExpiredException è rimasto in UnhandledExceptionsQueue dopo averlo gestito, e ha "ribollito". E quando bolle, diventa un ServletException.

Sono davvero dispiaciuto per aver confuso entrambi!

+0

* "in modo da poter lanciare una ViewExpiredException in QUALSIASI JSF-fase" *: per impostazione predefinita, quando si esegue questa operazione all'interno di un fagiolo come nel tuo primo esempio, questo sarà avvolto in un 'FacesException' e sarà non finire nella pagina di errore prevista. – BalusC

+0

Grazie. Hai ragione, ho rimosso la frase any-jsf-phase dalla mia ultima modifica. – ifischer

+0

Il tuo ultimo post modificato lo ha reso funzionante? Ho bisogno di impostare lo stesso reindirizzamento sull'errore ViewExpired pure –

risposta

14

Questo test case è fasullo.Il ViewExpiredException viene solitamente lanciato solo durante il ripristino della vista (perché manca nella sessione), non durante il rendering della risposta né l'istanziazione del bean. Nel tuo caso questa eccezione viene generata durante l'istanziazione del bean e questa eccezione è stata incapsulata in un ServletException.

Il realeViewExpiredException viene solitamente generato solo quando si invia una richiesta POST HTTP al server mentre la sessione HTTP è scaduta. Quindi, ci sono fondamentalmente due modi per riprodurre questo modo affidabile:

  1. aprire una pagina JSF con un modulo POST (h:form è per default già POST) in un web browser, spegnere il server e pulire la sua directory di lavoro (importante, perché la maggior parte dei server serializza le sessioni aperte su disco all'arresto e le unserializza all'avvio), riavvia il server e invia il modulo già aperto. Verrà lanciato un ViewExpiredException.

  2. Impostare il <session-timeout> in web.xml-1 minuto, inviate il formulario più di 1 minuto dopo l'apertura della pagina JSF con la forma POST. Questo lancerà anche il ViewExpiredException.

+0

Grazie BalusC. Ma perché questo non viene reindirizzato correttamente alla pagina di errore? – gekrish

+2

Poiché è stata generata una 'ServletException'. – BalusC

2

Non sono un esperto. Queste sono solo supposizioni o suggerimenti selvaggi.

1) Prova il reindirizzamento ad una pagina HTML standard per vedere se funziona 2) Based on this, dovrebbe funzionare con il primo approccio per sé, provare a scrivere un JSF PhaseListener e gettare la stessa eccezione nel ripristinare la visualizzazione Phase.Right ora , stai lanciando o nella fase INVOKE APPLICATION o UPDATE MODEL. 3) Da un sysout, assicurati che la pagina di errore sia configurata - usando Servlet Context (non l'ho provato ma dovrebbe essere possibile)

Anche io sono curioso di sapere quale potrebbe essere il problema !!!

+0

grazie per i vostri pensieri! Non ho mai usato PhaseListeners prima, buono a conoscerli. Ne ho appena implementato uno, che lancia l'eccezione nella fase RESTORE_VIEW - e ora effettivamente reindirizza correttamente! La mia eccezione viene generata nella fase InvokeApplication. Mi chiedo perché le eccezioni lanciate in questa fase non vengono catturate correttamente? – ifischer

+0

Hmm no, non è la fase per cui non ha funzionato, ho anche ricevuto lo Status-500 quando lancio l'eccezione nella fase RESTORE_VIEW (una volta ha funzionato, ma non più) Devo investigare ulteriormente ... – ifischer