2010-06-05 27 views
8

Estoy desarrollando una aplicación JSF 2.0 en Glassfish v3 y estoy tratando de manejar la ViewExpiredException. Pero haga lo que haga, siempre obtengo un informe de error de Glassfish en lugar de mi propia página de error.JSF: No se puede detectar ViewExpiredException

Para simular la aparición del VEE, inserté la siguiente función en mi bean de respaldo, que dispara el VEE. Estoy activando esta función desde mi página JSF a través de un commandLink. El Código:

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

Al principio lo intenté simplemente añadiendo una página de error, a mi web.xml:

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

Pero esto no funciona, no estoy redirigido a error pero yo estoy mostró el ErrorPage Glassfish, que muestra un estado HTTP 500 página con el siguiente contenido:

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 

siguiente que probé era escribir ExceptionHandlerFactory y una CustomExceptionHandler, como se des cibed en JavaServerFaces 2.0 - La referencia completa. Así que me inserta la siguiente etiqueta en faces-config.xml:

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

y ha añadido estas clases: La fábrica:

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; 
    } 

} 

El manejador de excepción personalizada:

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(); 
    } 
} 

pero todavía NO se me redirige a mi página de error; recibo el mismo error de HTTP 500 que el anterior. ¿Qué estoy haciendo mal, qué podría faltar en mi implementación que la excepción no se maneja correctamente? Cualquier ayuda muy apreciada!

EDITAR

Ok, soy honesto. De hecho, mi código está escrito en Scala, pero esa es una historia larga. pensé que era un problema de Java todo el tiempo. El error REAL en este caso fue mi propia estupidez. En mi código (Scala), en CustomExceptionHandler, olvidé agregar la línea con "i.remove();" Entonces ViewExpiredException se mantuvo en UnhandledExceptionsQueue después de manejarlo, y se "borró". Y cuando se enciende, se convierte en una ServletException.

¡Realmente lo siento por confundirlos a los dos!

+0

* "para que pueda lanzar una ViewExpiredException en CUALQUIER JSF-fase" *: de forma predeterminada, cuando se hace esto dentro de un grano como en su primera ejemplo, este será envuelto en una 'FacesException' y lo hará no terminará en la página de error esperado. – BalusC

+0

Gracias. Tienes razón, eliminé la declaración any-jsf-phase de mi última edición. – ifischer

+0

¿Su última publicación editada lo hace funcionar? Necesito establecer la misma redirección en el error ViewExpired también –

Respuesta

14

Este caso de prueba es falso.El ViewExpiredException generalmente solo se lanza durante la restauración de la vista (porque falta en la sesión), no durante la representación de la respuesta ni al crear instancias del bean. En su caso, esta excepción se produce al crear instancias del bean y esta excepción se envuelve en un ServletException.

realViewExpiredException generalmente solo se lanza cuando envía una solicitud HTTP POST al servidor mientras la sesión HTTP ha caducado. Así que hay básicamente dos maneras de reproducir esta manera confiable:

  1. abrir una página JSF con un formulario de envío (h:form es por defecto ya POST) en un navegador web, apagar el servidor y limpiar su directorio de trabajo (esto es importante, porque la mayoría de los servidores serializarán las sesiones abiertas en el disco al apagarlas y las deserializarán al iniciarse), reiniciar el servidor y enviar el formulario ya abierto. Se lanzará un ViewExpiredException.

  2. Establecer la <session-timeout> en web.xml-1 minuto y envíe el formulario más de 1 minuto después de la apertura de la página JSF con el formulario POST. Esto lanzará el ViewExpiredException también.

+0

Gracias BalusC. ¿Pero por qué esto no se redirige correctamente a la página de error? – gekrish

+2

Porque se ha lanzado una 'ServletException'. – BalusC

2

No soy un experto. Estas son simples conjeturas o sugerencias.

1) Trate de volver a dirigir a una página HTML estándar para ver si funciona 2) Based on this, se debe trabajar con el primer enfoque en sí, intentar escribir un JSF PhaseListener y la misma excepción en el restaurar la vista de Phase.Right ahora , está lanzando ya sea en la APLICACIÓN DE INVOCACIÓN o en la FASE DE MODO ACTUALIZACIÓN. 3) Por un sysout, asegúrese de que la página de error esté configurada - utilizando el contexto del servlet (no lo he probado pero debería ser posible)

¡¡¡Tengo curiosidad por saber cuál podría ser el problema !!!

+0

¡gracias por tus pensamientos! Nunca utilicé PhaseListeners antes, es bueno conocerlos. Acabo de implementar uno, que arroja la excepción en la fase RESTORE_VIEW, ¡y ahora realmente redirige correctamente! Mi excepción se produce en la fase InvokeApplication. Me pregunto por qué las excepciones lanzadas en esta fase no están atrapadas correctamente. – ifischer

+0

Hmm no, no es la fase por la que no funcionó, también obtengo el Status-500 cuando lanzo la excepción en la fase RESTORE_VIEW (una vez funcionó, pero ya no) Tengo que investigar más ... – ifischer

Cuestiones relacionadas