Boa tarde srs,
Tenho um sistema JSF + Richfaces que não permite sessões duplicadas de um usuário, este controle é feito por um número randômico que é gerado a cada acesso do usuário, tenho um servlet inicial que além de autenticar o usuário, ele verifica se o id deste já está em uma lista em um bean de aplicação, se já estiver por meio do out do servlet coloco uma mensagem para o usuário. Porém se o id do usuário ainda não está nesta lista ele pode acessar normalmente. E criei um sessionlistener para que ao encerrar a sessão o id do usuário seja removido da lista.
Meu problema é que em algumas situações quando o usuário acessa está dando “duplicate Id” nos componentes da minha tela jsf. Por meio de um phase listener eu vi que em algumas situações o faces está recuperando a view e renderizando-a (pulando da fase 1 para a 6). Tentei criar uma nova viewroot, porém quando passa pela 1ª fase do JSF ele recupera os componentes antigos e lasca tudo de novo!
Alguém sabe como forçar o JSF a “zerar o cache” (se é este o termo), ou forçá-lo a reconstruir a view, passando por todas as fases normalmente?
O código que utilizo para limpar a viewroot está abaixo, acesso ele pelo meu servlet de login.
[code]protected FacesContext getFacesContext(HttpServletRequest request, HttpServletResponse response) {
FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext == null) {
FacesContextFactory contextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
facesContext = contextFactory.getFacesContext(request.getSession().getServletContext(), request, response, lifecycle);
}
if(facesContext.getViewRoot() != null){
// set a new viewRoot, otherwise context.getViewRoot returns null
UIViewRoot view = facesContext.getApplication().getViewHandler().createView(facesContext,
"/inicio.xhtml");
facesContext.setViewRoot(view);
}
return facesContext;
}[/code]
Galera consegui!
Após muita batalha, descubri algo interessante. Estou utilizando o RichFaces, sendo assim o estado dos componentes da view ficam armazenados na sessão do usuário.
Primeiro vamos a solução pouco efetiva:
Reiniciei a instância do FacesContext conforme trecho de código abaixo:
protected void limparFacesContext(HttpServletRequest request, HttpServletResponse response) {
FacesContext facesContext = FacesContext.getCurrentInstance();
if (facesContext == null) {
FacesContextFactory contextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
facesContext = contextFactory.getFacesContext(request.getSession().getServletContext(), request, response, lifecycle);
}
facesContext.release();
InnerFacesContext.setFacesContextAsCurrentInstance(null);
}
private abstract static class InnerFacesContext extends FacesContext{
protected static void setFacesContextAsCurrentInstance(final FacesContext facesContext){
FacesContext.setCurrentInstance(facesContext);
}
}
Isso não foi muito efetivo visto que novamente ao passar pela RESTORE_VIEW a VIEWROOT era criada e "pegava" os componentes antigos.
A solução foi a seguinte:
/**
* Método utilizado para remover as referências dos objetos que estão na sessão
* tomando cuidado para não remover os objetos de segurança do Spring
* @param session - sessão ativa do usuário
*/
@SuppressWarnings("unchecked")
public void limpaSessaoParaInicio(HttpSession session) {
try{
if(session != null){
Enumeration atributeNames = session.getAttributeNames();
StringBuilder strBuilder = new StringBuilder();
while(atributeNames.hasMoreElements()){
String keyObjeto = (String) atributeNames.nextElement();
if(!keyObjeto.contains("SPRING")){
strBuilder.append(keyObjeto + "\n\t");
session.removeAttribute(keyObjeto);
}
}
if(strBuilder.length() > 1){
LOGGER.info("Objetos excluídos da sessão("+session.getId()+") para início da aplicação: \n\t"+strBuilder.toString());
}
}
}catch (Exception e) {
e.printStackTrace();
}
}
Ao acessar o servlet de login os objetos da sessão são limpos.
Apenas tomo cuidado para não limpar os objetos de segurança e autenticação do Spring, por isso o if:
if(!keyObjeto.contains("SPRING"))
Descubri que o RichFaces mantém os estados dos componentes atrelados a sessão do usuário por meio de 2 objetos (org.ajax4jsf.application.AjaxStateManager.view_sequence e org.ajax4jsf.application.AjaxStateHolder). Com a limpeza da sessão estes objetos não existem mais e a árvore de componentes é recriada (pelo que percebi).
Assim, não tomei mais o "duplicate Id" e de fato a VIEWROOT criou novos componentes.
Obrigado a todos!