Esse é um post de utilidade pública! Finalmente, uma solução definitiva para o problema do ViewExpiredException pra quem usa  JSF 1.2.

Vou contar o que aconteceu comigo esses dias… Num projeto novo que estou fazendo com uns colegas, 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, após a sessão expirar… adivinha: ViewExpiredException!!!

Normal até aí, todo mundo já sabe que isso ocorre mesmo. A solução foi implementar um PhaseListener com base no post desse cara: JSF Session Timeout Handling.

Resolvido o problema da sessão! Porém, me deparo com outro problema, esse agora ainda com a sessão ativa, e adivinhem novamente… ViewExpiredException!!!

Depois de pesquisar o Google inteiro sobre o ocorrido, me deparei com o um parâmetro mágico do Facelets: facelets.BUILD_BEFORE_RESTORE. Simples, configura pra “true” e tá tudo certo, o problema desaparece.

Realmente desaparece, mas outros aparecem, agora com o RichFaces (Build Before Restore Will Eat Your RichFaces).

Resumindo, tive que abrir a classe FaceletViewHandler pra saber o que tava havendo, até que cheguei à solução:

Criei uma nova classe, herdando de FaceletViewHandler, que sobrescreve o método createView. Confiram abaixo:

 

/**
  *
  * ViewHandler que previne o problema de 
  * ViewExpiredException para os casos onde a sessão 
  * ainda está ativa. 
  *
  * Basicamente utiliza o ViewHandler "pai" 
  * para restaurar a view. Caso ele não consiga 
  * (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;
	}
}

 

Resumão pra concluir:

  1. Coloque o parâmetro facelets.BUILD_BEFORE_RESTORE no web.xml como true;
  2. Use um PhaseListener para o caso de session timeout;
  3. Use a classe PreventViewExpiredViewHandler para os outros casos.

No caso do session timeout, é possível redirecionar para uma página específica ou atém mesmo se manter na mesma página e mostrar uma mensagem (e foi assim que eu fiz).

A classe PreventViewExpiredViewHandler  apenas recria a view caso sua restauração não tenha sido possível. Usa o mesmo método da superclasse, FaceletViewHandler.

*Fiquem à vontade pra copiar, só lembrem de deixar os créditos! Valeu!