quarta-feira, 27 de novembro de 2013

Primefaces: atualizar componentes JSF nos clientes usando p:socket


Em uma série de posts anterior, mostrei como usar o componente poll do Primefaces para atualizar periodicamente os clientes de uma aplicação. Desta vez vou mostrar como disparar uma atualização imediata para todos os clientes usando o componente socket do Primefaces. Este componente monitora um canal de mensagens, e quando colocado em uma página, cria uma comunicação em tempo real com todos os navegadores dos clientes da aplicação. São cinco passos muito simples:

I - Incluir no projeto a biblioteca atmosphere-runtime-2.0.4.jar

Eu estou usando JBoss versão 6.1.0-Final, mas acredito que não haja problemas com outras versões.

II - Configurar o arquivo web.xml, acrescentando o seguinte trecho:

1.     <servlet>
2.         <servlet-name>Push Servlet</servlet-name>
3.         <servlet-class>org.primefaces.push.PushServlet</servlet-class>
4.     </servlet>
5.     <servlet-mapping>
6.         <servlet-name>Push Servlet</servlet-name>
7.         <url-pattern>/primepush/*</url-pattern>
8.     </servlet-mapping>

Este trecho é fixo, pode ser usado em qualquer outro projeto, sem necessidade de fazer modificações.

III - Na página que deve ser atualizada, criar um socket, pode ser no final da página, antes da tag </html>:

1.         <p:socket channel="/atualizar">
2.             <p:ajax event="message"
3.                          update=":frmPrincipal:pnlTabela"
4.                          oncomplete="wTabela.filter()" />
5.         </p:socket>

Neste exemplo, o canal de mensagens foi chamado de atualizar, o componente que será atualizado com um update é :frmPrincipal:pnlTabela (que é um p:outputPanel, no meu caso) e ainda será executado o método filter() do widget wTabela (que no meu caso é um p:dataTable).

IV - Criar um método para mandar uma mensagem por um canal:

1.     public synchronized void atualizarClientes(String canal) {
2.         PushContext pushContext =
3.                PushContextFactory.getDefault().getPushContext();
4.         pushContext.push("/"+canal, "Enviando mensagem");
5.     }

Este método pode ser colocado em alguma classe estratégica, de preferência com escopo de aplicação. Se o seu projeto tiver um façade para distribuir os serviços, lá é um bom lugar.

V - Mandar uma mensagem pelo canal desejado sempre que for necessária uma atualização:

1. atualizarClientes("atualizar");


Sempre que a chamada acima for feita, será enviada uma mensagem pelo canal atualizar. No momento, o conteúdo da mensagem não é importante, e sim o efeito causado, já que qualquer cliente da aplicação que estiver em uma página com um socket monitorando o canal atualizar, será comunicado e uma requisição ajax do evento message poderá ser disparada para qualquer fim desejado..

Observação: consulte a classe aplicacao da série anterior de posts e o método atualizarLista da mesma. A chamada atualizarClientes("atualizar") poderia ser a última linha daquele método, garantindo que sempre que houver uma operação de CRUD, será enviada uma mensagem para o canal atualizar. Lembrando que se for usada esta tecnologia com socket, o componente poll colocado nas páginas da série não será mais necessário.