blob: 99d42f9f5d0b044f4366dd6865b7ae945959c7ba [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Trabalhando com Eventos no CDI: Tutorial do NetBeans IDE</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="description" content="This tutorial demonstrates how to integrate Java EE events into an application with CDI using NetBeans IDE">
<meta name="keywords" content="NetBeans, IDE, integrated development environment,
Contexts and Dependency Injection, CDI, Web Beans, injection, qualifier">
<link rel="stylesheet" type="text/css" href="../../../netbeans.css">
</head>
<body>
<!--
Copyright (c) 2009, 2010, 2011, Oracle and/or its affiliates. All rights reserved.
-->
<h1>Trabalhando com Eventos no CDI</h1>
<p><em>Contribuição de Andy Gibson</em></p>
<div class="margin-around">
<div class="feedback-box margin-around float-left" style="margin-right:15px">
<h3>Injeção de Dependência e Contextos</h3>
<ol>
<li><a href="cdi-intro.html">Introdução ao CDI e ao JSF 2.0</a></li>
<li><a href="cdi-inject.html">Trabalhando com Injeção e Qualificadores no CDI</a></li>
<li><a href="cdi-validate.html">Aplicando Anotações @Alternative Beans e de Ciclo de Vida</a>
<li><strong>Trabalhando com Eventos no CDI</strong>
<ul style="margin: 5px 0 0 -2em">
<li><a href="#event">Utilizando Eventos</a></li>
<li><a href="#scopes">Tratando Escopos</a></li>
<li><a href="#seealso">Consulte Também</a></li>
</ul></li>
</ol>
</div>
</div>
<img alt="O conteúdo desta página se aplica ao NetBeans IDE 7.2, 7.3, 7.4 e 8.0" class="stamp" src="../../../images_www/articles/73/netbeans-stamp-80-74-73.png" title="O conteúdo desta página se aplica ao NetBeans IDE 7.2, 7.3, 7.4 e 8.0">
<p>A Injeção de Dependência e Contextos (CDI), especificada por <a href="http://jcp.org/en/jsr/detail?id=299">JSR-299</a>, é parte integrante do Java EE 6 e fornece uma arquitetura que permite aos componentes do Java EE, como os servlets, enterprise beans e JavaBeans, existirem dentro do ciclo de vida de uma aplicação com escopos bem definidos. Além disso, os serviços CDI permitem que os componentes do Java EE, como beans de sessão EJB e beans gerenciados do JavaServer Faces (JSF), sejam injetados e interajam de maneira acoplada flexível, disparando e observando eventos.</p>
<p>Este tutorial tem base no post do blog de Andy Gibson, intitulado <a href="http://www.andygibson.net/blog/index.php/2010/01/11/getting-started-with-jsf-2-0-and-cdi-part-3/">Getting Started with CDI part 3 – Events</a> (Introdução ao CDI parte 3 - Eventos). Ele demonstra como aproveitar o conceito do Java EE de <em>eventos</em>, em que você produz e se inscreve em (isto é, <em>observa</em>) eventos que ocorrem na sua aplicação, de maneira que o permite manter o código desacoplado entre produtores e observadores. A classe <code>javax.enterprise.event.Event</code> é utilizada para criar eventos e anotação <code>@Observes</code> de CDI para se inscrever em eventos.</p>
<p>O NetBeans IDE fornece um suporte incorporado para a Injeção de Dependência e Contextos, incluindo a opção de geração do arquivo de configuração de CDI <code>beans.xml</code> durante a criação do projeto, do editor e do suporte de navegação para anotações, assim como vários assistentes para a criação de artefatos CDI comumente utilizados.</p>
<br style="clear:left;">
<div class="indent">
<p>Para concluir este tutorial, você precisa dos seguintes recursos e softwares.</p>
<table id="requiredSoftware">
<tbody>
<tr>
<th class="tblheader" scope="col">Software ou Recurso</th>
<th class="tblheader" scope="col">Versão Necessária</th>
</tr>
<tr>
<td class="tbltd1"><a href="https://netbeans.org/downloads/index.html">NetBeans IDE</a></td>
<td class="tbltd1">Versão Java EE 7.2, 7.3, 7.4, 8.0</td>
</tr>
<tr>
<td class="tbltd1"><a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">JDK (Java Development Kit)</a></td>
<td class="tbltd1">versão 7 ou 8</td>
</tr>
<tr>
<td class="tbltd1"><a href="http://glassfish.dev.java.net/">GlassFish Server</a></td>
<td class="tbltd1">Open Source Edition 3.x ou 4.x</td>
</tr>
<tr>
<td class="tbltd1"><a href="https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252FcdiDemo3.zip">cdiDemo3.zip</a></td>
<td class="tbltd1">n/d</td>
</tr>
</tbody>
</table>
<p class="notes"><strong>Observações:</strong></p>
</div>
<ul>
<li>O pacote Java EE do NetBeans IDE inclui também o GlassFish Server Open Source Edition, que é um contêiner compatível com Java EE.</li>
<li>É possível fazer download do projeto de amostra de solução para este tutorial em: <a href="https://netbeans.org/projects/samples/downloads/download/Samples%252FJavaEE%252FcdiDemoComplete.zip">cdiDemoComplete.zip</a></li>
</ul>
<br>
<h2 id="event">Utilizando Eventos</h2>
<p>No tutorial anterior, <a href="cdi-validate.html">Aplicando Anotações de Ciclo de Vida e de Beans @Alternative</a>, tínhamos uma aplicação que obtinha uma lista de itens, validava-os e agia, de maneira específica, quando um item inválido era encontrado. Vamos dizer que no futuro queremos expandir nosso sistema para tratar todos os tipos de coisas que ocorrem quando encontramos um item inválido. Isso pode variar de um e-mail sendo enviado, alterações feitas a outros dados, como um pedido sendo cancelado ou o armazenamento de uma lista de rejeições em um arquivo ou tabela de banco de dados. Para desacoplar completamente a implementação, podemos utilizar <em>eventos</em> no Java EE. Eventos são gerados pelo <em>produtor</em> de eventos e a inscrição feita pelos <em>observadores</em> de eventos. Como a maior parte do CDI, a produção e inscrição de eventos é segura para tipo e permite que os qualificadores determinem quais eventos os observadores irão observar.</p>
<p>Utilizando a aplicação que estamos construindo desde os tutoriais anteriores da série, não precisamos de muitas alterações para implementar isso. Podemos fornecer apenas outra implementação de <code>ItemErrorHandler</code> (criado no <a href="cdi-validate.html">tutorial anterior</a>), que gera um evento toda vez que trata um item. Nomearemos essa classe <code>EventItemHandler</code>, a injetaremos no <code>ItemProcessor</code> e utilizaremos um qualificador <code>Notify</code>para selecioná-la para injeção.</p>
<div class="indent">
<img alt="Diagrama de CDI que mostra os objetos criados neste exercício" class="margin-around" src="../../../images_www/articles/73/javaee/cdi-events/cdi-diagram-events.png" title="Use a injeção de CDI para acoplar, livremente, as classes na sua aplicação">
</div>
<ol>
<li>Comece extraindo o projeto de início de amostra do arquivo <code>cdiDemo3.zip</code> (Consulte a <a href="#requiredSoftware">tabela que lista os recursos necessários</a> acima.) Abra o projeto no IDE escolhendo Arquivo > Abrir Projeto (Ctrl-Shift-O; ⌘-Shift-O no Mac) e, em seguida, selecionando o projeto no seu local no computador.</li>
<li>Crie uma classe denominada <code>EventItemHandler</code>. Clique no botão Novo Arquivo (<img alt="Botão Novo Arquivo" src="../../../images_www/articles/73/javaee/cdi-common/new-file-btn.png">) ou pressione CTRL-N (⌘-N no Mac) para abrir o assistente de Arquivo.</li>
<li>Selecione a categoria Java e, em seguida, a Classe Java. Clique em Próximo.</li>
<li>Digite <strong>EventItemHandler</strong> como o nome da classe e, em seguida, digite <strong>exercise4</strong> como o pacote.</li>
<li>Clique em Finalizar. A nova classe e o novo pacote são gerados e a classe é aberta no editor.</li>
<li>Implemente <strong>EventItemHandler</strong> como se segue.
<pre class="examplecode">
public class EventItemHandler <strong>implements ItemErrorHandler</strong> {
<strong>@Inject
private Event&lt;Item&gt; itemEvent;
@Override
public void handleItem(Item item) {
System.out.println("Firing Event");
itemEvent.fire(item);
}</strong>
}</pre>
Injetamos uma instância de um <code>Event</code> em que a carga do evento será um <code>Item</code>. A carga do evento são os dados de estado passados do produtor de evento para o observador de evento que, nesse caso, passa o item rejeitado. Quando o item inválido é tratado, nós acionamos o evento e passamos no item inválido que recebemos. Esse handler de item com base em evento é injetado da mesma maneira que qualquer outro handler de item seria e, portanto, podemos colocá-lo ou tirá-lo sempre que precisarmos e também podemos substituí-lo durante os testes.</li>
<li>Corrigir todas as importações. Clique com o botão direito do mouse no editor e selecione Corrigir importações ou pressione Ctrl-Shift-I (⌘-Shift-I no Mac). Certifique-se de selecionar <code>javax.enterprise.event.Event</code> como o nome completamente qualificado para a classe <code>Event</code>. <br> <img alt="Caixa de diálogo Corrigir Importações" class="margin-around b-all" src="../../../images_www/articles/73/javaee/cdi-events/fix-all-imports.png" title="Clique com o botão direito do mouse no Editor e escolha corrigir importa para chamar a caixa de diálogo Importações de Correção"> <br><br> <span class="tips">Pressione Ctrl-Espaço em <code>Event</code> para exibir a definição Javadoc da classe. O método <code>fire()</code>, utilizado acima, também será definido.</span> <br> <img alt="Pop - up de Javadoc no editor" class="margin-around b-all" src="../../../images_www/articles/73/javaee/cdi-events/event-javadoc.png" title="Pressione CTRL-Espaço para exibir documentação de Javadoc em classes na API"></li>
<li>Crie um nome qualificador <code>Notify</code>. (Qualificadores foram discutidos em <a href="cdi-inject.html">Trabalhando com Injeção e Qualificadores no CDI</a>.)</li>
<li>Clique no botão Novo Arquivo (<img alt="Botão Novo Arquivo" src="../../../images_www/articles/73/javaee/cdi-common/new-file-btn.png">) ou pressione CTRL-N (⌘-N no Mac) para abrir o assistente de Arquivo.</li>
<li>Selecione a categoria Injeção de Dependência e Contexto e, em seguida, selecione Tipo de Qualificador. Clique em Próximo.</li>
<li>Digite <strong>Notify</strong> como o nome da classe e, em seguida, digite <strong>exercise4</strong> como o pacote.</li>
<li>Clique em Finalizar. O novo qualificador <code>Notify</code> será aberto no editor.
<pre class="examplecode">
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface Notify {
}</pre></li>
<li>Adicione a anotação <code>@Notify</code> a <code>EventItemHandler</code>.
<pre class="examplecode">
<strong>@Notify</strong>
public class EventItemHandler implements ItemErrorHandler {
...
}</pre>
Criamos uma anotação de qualificador <code>@Notify</code> para identificar esse handler de erros para injeção e podemos utilizá-lo em nosso <code>ItemProcessor</code> adicionando-o ao ponto de injeção.</li>
<li>Adicione a anotação <code>@Notify</code> ao ponto de injeção do <code>EventItemHandler</code> no <code>exercise2.ItemProcessor</code>.
<pre class="examplecode">
@Named
@RequestScoped
public class ItemProcessor {
@Inject @Demo
private ItemDao itemDao;
@Inject
private ItemValidator itemValidator;
@Inject <strong>@Notify</strong>
private ItemErrorHandler itemErrorHandler;
public void execute() {
List&lt;Item&gt; items = itemDao.fetchItems();
for (Item item : items) {
if (!itemValidator.isValid(item)) {
itemErrorHandler.handleItem(item);
}
}
}
}</pre>
(Utilize a dica do editor para adicionar a instrução de importação para <code>exercise4.Notify</code>.)</li>
<li>Clique no botão Executar Projeto (<img alt="Botão Executar Projeto" src="../../../images_www/articles/73/javaee/cdi-common/run-project-btn.png">) para executar o projeto.</li>
<li>No browser, clique no botão "<code>Execute</code>" e, em seguida, retorne para o IDE e examine o log do servidor na janela Saída (Ctrl-4; ⌘-4 no Mac). Como a aplicação que você tem construído atualmente utiliza o <code>DefaultItemDao</code> para configurar quatro <code>Item</code>s, e, em seguida, aplica o <code>RelaxedItemValidator</code> nos <code>Iten</code>s, é esperado ver o acionamento de <code>itemErrorHandler</code> duas vezes. <br> <img alt="Janela Saída - log do GlassFish Server" class="margin-around b-all" src="../../../images_www/articles/73/javaee/cdi-events/output-window.png" title="Exibir o log do GlassFish Server exibido na janela Saída"> <br> Atualmente, no entanto, não temos nada observando o evento. Podemos corrigir isso criando um método <em>observador</em> utilizando a anotação <code>@Observes</code>. Essa é a única coisa necessária para observar um evento. Para demonstrar, podemos modificar o <code>FileErrorReporter</code> (criado no <a href="cdi-validate.html">tutorial anterior</a>) para responder a eventos acionados adicionando um método observador que chama seu método <code>handleItem()</code>.</li>
<li>Para fazer nosso <code>FileErrorReporter</code> responder ao evento, adicione o seguinte método à classe.
<pre class="examplecode">
public class FileErrorReporter implements ItemErrorHandler {
<strong>public void eventFired(@Observes Item item) {
handleItem(item);
}</strong>
...
}</pre>
(Utilize a dica do editor para adicionar uma instrução de importação para <code>javax.enterprise.event.Observes</code>.)</li>
<li>Execute o projeto (F6; fn-F6 no Mac) novamente, clique no botão "<code>Execute</code>" e, em seguida, retorne para o IDE e examine o log do servidor na janela Saída. <br> <img alt="Janela Saída - log do GlassFish Server" class="margin-around b-all" src="../../../images_www/articles/73/javaee/cdi-events/output-window2.png" title="Exibir o log do GlassFish Server exibido na janela Saída"> <br> Você verá que os eventos são acionados nos objetos inválidos como eram anteriormente, mas agora as informações do item estão sendo salvas quando cada evento é acionado. Também é possível notar que os eventos de ciclo de vida estão sendo observados, já que um bean <code>FileErrorReporter</code> é criado e fechado para cada evento acionado. (Consulte <a href="cdi-validate.html">Aplicando Anotações de Ciclo de Vida e de Beans @Alternative</a> para obter uma discussão de anotações de ciclo de vida, como <code>@PostConstruct</code> e <code>@PreDestroy</code>.)</li>
</ol>
<p>Conforme mostrado nas etapas acima, a anotação <code>@Observes</code> fornece uma maneira fácil de observar um evento.</p>
<p class="tips">Eventos e observadores também podem ser anotados com qualificadores para permitir que os observadores observem apenas eventos específicos de um item. Consulte <a href="http://www.andygibson.net/blog/index.php/2010/01/11/getting-started-with-jsf-2-0-and-cdi-part-3/">Introdução ao CDI parte 3 – Eventos</a> para uma demonstração.</p>
<br>
<h2 id="scopes">Tratando Escopos</h2>
<p>No estado atual da aplicação, um bean <code>FileErrorReporter</code> é criado toda vez que o evento é criado. Nesse caso, não queremos criar um novo bean toda vez, já que não queremos abrir e fechar o arquivo para cada item. Ainda queremos abrir o arquivo no início do processo e, em seguida, fechá-lo depois que o processo tiver sido concluído. Portanto, precisamos considerar o <em>escopo</em> do bean <code>FileErrorReporter</code>.</p>
<p>Atualmente, o bean <code>FileErrorReporter</code> não tem um escopo definido. Quando nenhum escopo é definido, o CDI utiliza o escopo pseudodependente default. Na prática, isso significa que o bean é criado e destruído em um espaço muito pequeno de tempo, normalmente em uma chamada de método. No nosso cenário atual, o bean é criado e destruído pela duração do evento sendo acionado. Para corrigir isso, podemos aumentar o escopo do bean adicionando manualmente uma anotação de escopo. Tornaremos esse bean <code>@RequestScoped</code>, de modo que quando o bean for criado com o primeiro evento sendo acionado, ele continuará a existir pela duração da solicitação. Isso também significa que para todos os pontos de injeção em que esse bean é qualificado para ser injetado, a mesma instância do bean será injetada.</p>
<ol>
<li>Adicione a anotação <code>@RequestScope</code> e a instrução de importação correspondente para <code>javax.enterprise.context.RequestScoped</code> à classe <code>FileErrorReporter</code>.
<pre class="examplecode">
<strong>import javax.enterprise.context.RequestScoped;</strong>
...
<strong>@RequestScoped</strong>
public class FileErrorReporter implements ItemErrorHandler { ... }</pre>
<span class="tips">Pressione Ctrl-Espaço enquanto digita para chamar o suporte da funcionalidade autocompletar código do editor. Quando você escolhe um item por meio da funcionalidade autocompletar código, todas as instruções de importação associadas serão automaticamente adicionadas à classe.</span> <br> <img alt="Pop-up de autocompletar código no editor" class="margin-around b-all" src="../../../images_www/articles/73/javaee/cdi-events/code-completion.png" title="Pressione Ctrl-Espaço ao digitar para chamar sugestões de autocompletar código"></li>
<li>Execute o projeto (F6; fn-F6 no Mac) novamente, clique no botão "<code>Execute</code>" e, em seguida, retorne para o IDE e examine o log do servidor na janela Saída. <br> <img alt="Janela Saída - log do GlassFish Server" class="margin-around b-all" src="../../../images_www/articles/73/javaee/cdi-events/output-window3.png" title="Exibir o log do GlassFish Server exibido na janela Saída"> <br> Note que o bean <code>FileErrorReporter</code> é criado apenas quando o primeiro evento é acionado e fechado depois de o evento final ter sido acionado.
<pre class="examplecode">
INFO: Firing Event
<strong>INFO: Creating file error reporter</strong>
INFO: Saving exercise2.Item@48ce88f6 [Value=34, Limit=7] to file
INFO: Firing Event
INFO: Saving exercise2.Item@3cae5788 [Value=89, Limit=32] to file
<strong>INFO: Closing file error reporter</strong>
</pre></li>
</ol>
<p>Os eventos são uma ótima maneira de desacoplar partes do sistema de maneira modular, já que os observadores e produtores de eventos não sabem nada um sobre o outro, nem exigem alguma configuração para isso. Você pode adicionar partes de códigos que se inscrevem a eventos, com o produtor de evento desconhecendo o observador. (Sem utilizar eventos, normalmente seria necessário fazer com que o produtor de eventos chamasse o observador manualmente.) Por exemplo, se alguém atualizar o status de um pedido, seria possível adicionar eventos por e-mail para o representante de vendas ou notificar um gerente de conta se um problema de suporte técnico estiver aberto há mais de uma semana. Esses tipos de regras podem ser implementados sem eventos, mas os eventos facilitam o desacoplamento da lógica de negócios. Além disso, não há nenhuma dependência de compilação ou de tempo de construção. Você pode apenas adicionar módulos à sua aplicação e eles começarão, automaticamente, a observar e produzir eventos.</p>
<div class="feedback-box">
<a href="/about/contact_form.html?to=3&amp;subject=Feedback:%20Working%20with%20Events%20in%20CDI">Enviar Feedback neste Tutorial</a>
</div>
<br style="clear:both;">
<h2 id="seealso">Consulte Também</h2>
<p>Para obter mais informações sobre o CDI e o Java EE, consulte os recursos a seguir.</p>
<h3>Recursos do NetBeans</h3>
<ul>
<li><a href="cdi-intro.html">Introdução à Injeção de Dependência e Contextos e JSF 2.0</a></li>
<li><a href="cdi-inject.html">Trabalhando com Injeção e Qualificadores no CDI</a></li>
<li><a href="cdi-validate.html">Aplicando Anotações @Alternative Beans e de Ciclo de Vida</a></li>
<li><a href="javaee-gettingstarted.html">Conceitos Básicos sobre Aplicações do Java EE</a></li>
<li><a href="../web/jsf20-intro.html">Introdução ao JavaServer Faces 2.0</a></li>
</ul>
<h3>Recursos Externos</h3>
<ul>
<li><a href="http://blogs.oracle.com/enterprisetechtips/entry/using_cdi_and_dependency_injection">Dica Técnica do Enterprise: Utilizando Injeção de Dependência e de CDI para Java em uma Aplicação JSF 2.0</a></li>
<li><a href="http://download.oracle.com/javaee/6/tutorial/doc/gjbnr.html">O Tutorial do Java EE 6, Parte V: Injeção de Dependência e Contextos para a Plataforma Java EE</a></li>
<li><a href="http://jcp.org/en/jsr/detail?id=299">JSR 299: Especificação para Injeção de Dependência e Contextos</a></li>
<li><a href="http://jcp.org/en/jsr/detail?id=316">JSR 316: Plataforma Java, Especificação do Enterprise Edition 6</a></li>
</ul>
</body>
</html>