O que aconteceria se o código a baixo estivesse rodando e tivéssemos que fazer um novo deploy no servidor?
xhtml
<h:outputLabel value="#{contadorController.numero}" id="numero"> <p:poll interval="3" listener="#{contadorController.contar}" update="numero" />
Controller
@ManagedBean @ViewScoped public class ContadorController implements Serializable { private int numero; public ContadorController() { numero = 0; } public void contar() { numero++; } public int getNumero() { return numero; } }
Se o servidor não for reiniciado, vai ocorrer tudo bem e o contador será chamado a cada 3 segundos.
Agora se o servidor for reiniciado com a página aberta o que aconteceria ? Assim que o servidor voltar o p:poll para uma nova requisição para o controller e receberá uma javax.faces.application.ViewExpiredException: viewId:contador/contador.xhtml – A exibição de contador/contador.xhtml não pôde ser restaurada; porque o contexto do controller foi perdido quando o servidor foi desligado/reiniciado e o que fazer ? Sempre que reiniciar o servidor ir na página e apertar F5 ? Não….é possível criar um filtro para monitorar esse caso e um ViewHandlerWrapper para restaurar o contexto que estava na tela, segue a baixo a implementação:
Criar um filtro que que set um atributo(contadorFilter) na request quando passar pela página contador.xhtml
import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import java.io.IOException; public class ContadorFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { final HttpServletRequest httpRequest = (HttpServletRequest) request; // seta o atributo contadorFilter na request //apenas para marcar que é uma request na página contador.xhtml httpRequest.setAttribute("contadorFilter", Boolean.TRUE); chain.doFilter(request, response); } @Override public void destroy() { } }
Mapear o filtro para apenar ser aplicado em /contador/*, pois as outras páginas da aplicação não precisam estar sendo monitoras;
<filter> <filter-name>ContadorFilter</filter-name> <filter-class>br.com.emmanuelneri.blog.filtros.ContadorFilter</filter-class> </filter> <filter-mapping> <filter-name>ContadorFilter</filter-name> <url-pattern>/contador/*</url-pattern> </filter-mapping> </filter>
As requisições na página contador já estão sendo monitoras, agora é preciso recuperar o contexto quando não houver, que será feito na classe ContadorRestoreViewHandler
import javax.faces.application.ViewHandler; import javax.faces.application.ViewHandlerWrapper; import javax.faces.component.UIViewRoot; import javax.faces.context.FacesContext; import javax.servlet.http.HttpServletRequest; public class ContadorRestoreViewHandler extends ViewHandlerWrapper { private final ViewHandler parent; public ContadorRestoreViewHandler(ViewHandler parent) { this.parent = parent; } @Override public ViewHandler getWrapped() { return parent; } @Override public UIViewRoot restoreView(FacesContext context, String viewId) { // restaura a View com o contexto e viewId atual UIViewRoot root = super.restoreView(context, viewId); // caso a restauração for nula e tenha o atributo // contadorFilter na request // cria uma nova View para o context e viewId atual if (root == null && ((HttpServletRequest) context.getExternalContext().getRequest()).getAttribute("contadorFilter") != null) { root = createView(context, viewId); } return root; } }
Declara o ContadorRestoreViewHandler no faces.config
<application> <view-handler>br.com.emmanuelneri.blog.filtros.ContadorRestoreViewHandler</view-handle> </application>