terça-feira, 11 de novembro de 2014

JSF 2 - Eventos

O objetivo desse post é ir um pouco além das categorias de eventos mais utilizadas pelo framework: action listeners e value change listeners.

Action e Value Change Listeners

Como todo mundo que desenvolve JSF deve conhecer, utilizamos action listeners quando queremos executar a lógica de aplicação sem que, no entanto, tenhamos que redirecionar o fluxo das páginas retornando um outcome.

A imagem abaixo mostra o exemplo de um listener:


E o componente (action source) que dispara o evento:


Da mesma mesma forma, sem grandes novidades, utilizamos os value change listeners. Primeiro o código Java:


O script JSF:



O que grande parte dos iniciantes JSF desconhece é que existe outra forma de reproduzir este comportamento implementando os listeners de outra forma - estendendo as interfaces javax.faces.event.ActionListener e javax.faces.event.ValueChangeListener respectivamente. O exemplo a seguir mostra a implementação de um action listener usando a interface proposta:

A interface javax.faces.event.ActionListener especifica o método processAction que se comporta de forma parecida que o método myActionListener do primeiro exemplo. A maior diferença está no fato de que cada vez que uma ação for executada uma instância de MyActionListener será criada.

O botão abaixo dispara um evento que é tratado pela implementação MyActionListener. A maior diferença aqui é que, ao invés de usar o atributo actionListener do h:commandButton, utilizamos a tag f:actionListener especificando o nome totalmente qualificado da classe no atributo type:


Uma das grandes vantagens desta última abordagem é que podemos especificar mais de um action listener para o h:commandButton e eles serão executados na ordem em que forem especificados no corpo do componente:


E é o mesmo no que diz respeito aos value change listeners. Primeiro o código Java:


Depois o JSF:


Os System Events

Os action e value change listener vão resolver a maior parte dos seus problemas de eventos enquanto desenvolvedor JSF. Porém, existem aquelas ocasiões em que precisamos de algo mais. O modelo de componentes do JSF permite associar listener aos componentes em momentos distintos da sua existência. Um bom exemplo é um listener que seria executado no momento imediatamente antes do componente ser renderizado na página. No exemplo a seguir, foi especificado um método listener que recebe um ComponentSystemEvent como parâmetro. O método simplesmente faz o cast do componente que disparou o evento para um UIInput e configura a data atual como o seu valor padrão.


A seguir, o trecho JSF do component que dispara o evento:


A novidade aqui é a tag f:event que especifica o tipo (atributo type) de evento que será disparado e seu respectivo listener (método myPreRenderListener, no managed bean). Outros momentos da existência do componente pode ser observado na doc https://docs.oracle.com/javaee/6/javaserverfaces/2.1/docs/vdldocs/facelets/f/event.html .

Ainda quanto aos System Events, você pode aumentar um pouco mais a capacidade da sua aplicação reagir aos momentos da sua execução. A superclasse de ComponentSystemEvent, SystemEvent, permite que você trate eventos de mais baixo baixo nível, como, por exemplo, a inicialização e a finalização da aplicação. O exemplo a seguir mostra exatamente isso:

A classe acima implementa a interface javax.faces.event.SystemEventListener com o intuito de tratar os eventos derivados da interface javax.faces.event.SystemEvent. A interface provê dois métodos: isListenerForSource, usada para determinar se o evento gerado é do tipo apropriado para ser tratado e o processEvent, onde ele deve ser adequadamente tratado. Para exemplificar, eu irresponsavelmente trataei eventos distintos no mesmo método. O trecho do faces-config.xml a seguir diz para o container que a minha implementação é um listener de eventos do sistema. Todo o código abaixo deve ser inserido entre e
.

O conjunto de eventos que podem ser tratados desta forma está descrito em https://docs.oracle.com/cd/E17802_01/j2ee/javaee/javaserverfaces/2.0/docs/api, na seção "direct subclasses".