Esse é um post de utilidade pública para quem usa JSF 1.2: finalmente encontrei uma solução mais completa para o problema de ViewExpiredException.
O problema no projeto
Em um projeto novo, estamos usando JSF 1.2, Facelets 1.1.14 e RichFaces 3.3.3. No primeiro momento, tínhamos uma tela que colocava um dado na sessão e, depois que a sessão expirava, aparecia o erro ViewExpiredException.
Até aí, nada tão estranho. Esse comportamento é conhecido. A primeira solução foi implementar um PhaseListener com base no artigo JSF Session Timeout Handling. Isso resolveu o problema de sessão expirada.
Quando a sessão ainda está ativa
Depois veio outro caso: ViewExpiredException mesmo com a sessão ativa. Pesquisando bastante, encontrei o parâmetro facelets.BUILD_BEFORE_RESTORE. Configurar esse parâmetro como true elimina o problema, mas cria efeitos colaterais com RichFaces.
A saída foi abrir a classe FaceletViewHandler para entender o comportamento e criar uma classe própria, herdando de FaceletViewHandler, sobrescrevendo o método createView.
/**
* ViewHandler que previne o problema de ViewExpiredException
* para os casos em que a sessão ainda está ativa.
*
* Usa o ViewHandler pai para restaurar a view. Caso ele não consiga
* restaurar (UIViewRoot == null), recria a view.
*
* @author Rômulo Augusto
*/
public class PreventViewExpiredViewHandler extends FaceletViewHandler {
private ViewHandler parent;
public PreventViewExpiredViewHandler(ViewHandler parent) {
super(parent);
this.parent = parent;
}
@Override
public UIViewRoot createView(FacesContext context, String viewId) {
UIViewRoot viewRoot = this.parent.restoreView(context, viewId);
if (viewRoot == null) {
viewRoot = super.createView(context, viewId);
}
return viewRoot;
}
}
Resumo da solução
- Coloque o parâmetro facelets.BUILD_BEFORE_RESTORE no web.xml como true apenas se ele não quebrar o comportamento esperado do RichFaces.
- Use um PhaseListener para tratar session timeout.
- Use a classe PreventViewExpiredViewHandler para recriar a view quando a restauração não for possível.
No caso de session timeout, é possível redirecionar para uma página específica ou permanecer na mesma página e mostrar uma mensagem. A classe PreventViewExpiredViewHandler apenas recria a view quando a restauração falha, usando o mesmo método da superclasse FaceletViewHandler.
Fiquem à vontade para copiar, só lembrem de deixar os créditos. Valeu!