Modelo Java Magazine

Transcrição

Modelo Java Magazine
1/36
De JEE 5 para JEE 6
Como modificar uma aplicação para usar os novos recursos
Descubra como converter uma aplicação que usa JSF, Servlets, EJBs e JPA para a
nova versão e como fica a utilização de cada um desses recursos
MARCELO ELIAS DEL VALLE
Esse artigo ensina como migrar, passo a passo, uma aplicação Java EE 5 para Java EE 6. A
aplicação utilizou JSF para criar a interface gráfica, EJBs para a conversão e JPA para ler dados de
um banco de dados.
Primeiramente é apresentada a parte funcional da aplicação. Em seguida, as diferenças entre as
duas versões da aplicação (Java EE 5 e Java EE 6) são descritas sob várias perspectivas, por meio
de diagramas de classes, de componentes e através da listagem de arquivos de cada versão.
Depois disso é explicado como migrar cada camada. São mostradas as diferenças nos descritores
de arquivo, na implementação dos EJBs e na chamada aos mesmos. Também é mostrado como fica
o layout dos arquivos JSF com o uso de JSPs e com o uso de facelets, como fica o acesso a dados e
o que muda na implementação de um Servlet.
Durante todo esse processo são citadas muitas das novas características da especificação Java EE
6, como templates JSF, Criteria API, novidades no CDI, EJBs sem interface, EJBs instalados dentro
de um WAR ao invés de em um EAR, servlets assíncronos e web-fragments.
A especificação Java EE versão 6 trouxe muitas novidades com relação às versões anteriores e
pode ser considerada uma quebra de paradigma. Finalmente, é possível desenvolver com Java EE
sem uma necessidade tão grande de recorrer a frameworks de terceiros.
Ficou muito mais simples desenvolver e chamar EJBs, nunca foi tão fácil organizar a parte visual
da aplicação graças ao uso de templates, facelets agora é a tecnologia visual padrão, substituindo o
JSP, o acesso a dados ficou menos acoplado ainda com o banco de dados graças à Criteria API e o
uso de servlets assíncronas permite realizar Server Push usando apenas as ferramentas oferecidas
por padrão no Java EE 6. Esse artigo fala sobre tudo isso.
Funcionalmente, nada muda na aplicação da versão Java EE 5 para a versão 6, as únicas diferenças
ficam na implementação.
Ferramentas utilizadas
O exemplo citado no artigo roda no GlassFish, mas com pode rodar em qualquer Application
Server com poucas adaptações. Recomenda-se usar o Glassfish v2 para rodar a aplicação Java EE 5
e o Glassfish v3 para rodar a aplicação Java EE 6.
O GlassFish é a implementação de referência da Sun (agora Oracle) para o Java EE e portanto é
recomendado para o aprendizado, mas vários outros containers implementam a especificação Java
EE da forma como mostrado nesse artigo, como é o caso do JBoss, da Red Hat, e do WebSphere, da
IBM.
As duas versões da aplicação (tanto na versão Java EE 5 quanto na versão Java EE 6), assim como
a versão desse artigo em PDF, estão disponíveis para download NESSE LINK e a mesma utiliza
ANT para o build e contém um arquivo de projeto para o IDE Eclipse. Contudo, é possível rodar a
mesma aplicação em qualquer IDE sem necessidade de modificações no código.
A aplicação faz uso de um banco de dados, acessado em tempo de execução. Nesse banco precisa
existir a tabela “Taxa”, cujos campos são descritos mais abaixo. Os exemplos desse artigo foram
testados no MySQL. Tudo o que você precisa fazer é criar o banco de dados, criar a tabela Taxa no
mesmo e configurar um datasource no seu container.
Um datasource é um recurso do container que permite que as configurações de banco específicas
para o ambiente fiquem configuradas no mesmo e não na aplicação. Para obter uma conexão JDBC
2/36
com o banco basta dizer ao container qual é o JNDI do datasource configurado e o ele se preocupa
em como criar as conexões e fechá-las, conforme necessário.
O conceito de datasource já é bem conhecido pela maioria dos programadores e, como não faz
parte do foco do artigo, não será explicado em detalhes como configurá-lo.
No Glassfish, para criar um data source é necessário configurar um connection pool antes, no
qual são especificados os dados de conexão com o banco de dados. Depois de criado o Connection
Pool especificando tipo de banco e dados de conexão, deve ser cadastrado o DataSource associando
o Pool com o JNDI utilizado pela aplicação: “jdbc/ConversorDS”.
Outro recurso utilizado foi o Realm, para autenticação. Para rodar as aplicações, é necessário
cadastrar um Realm no Container com informações de usuários, grupos e senhas usados para
autenticação. Será mostrado no artigo, sucintamente, como fazer isso em ambas as versões do
Glassfish, mas é um recurso largamente utilizado e programadores não deveriam sentir dificuldade
de realizar essa tarefa.
Para rodar a aplicação, adicione no Glassfish um usuário “admin” com senha “admin” e na
opção “Group List” insira o texto “administrator”, para que o usuário seja adicionado a esse grupo.
Adicione o usuário no “file” realm (Configuration> Security> Realms> file).
Descrevendo a parte funcional da aplicação
A aplicação descrita nesse artigo é bem simples do ponto de vista funcional: uma aplicação que
converte um valor em reais para um valor em dólares através de uma interface gráfica e de dólares
para reais através de um servlet.
A taxa de conversão de cada moeda é obtida a partir do banco de dados e há também interface de
usuário para consultar as taxas no banco, alterar, apagar e adicionar novas taxas. Todas as telas
necessitam de login para serem acessadas, então há também uma tela de login na aplicação.
Na figura 1, é mostrada a tela de login e na figura 2, a tela de conversão de unidades quando a
mesma é iniciada. Na figura 3, vemos a mesma tela, depois de o usuário digitar um valor em reais e
o mesmo ser exibido em dólares.
3/36
Figura 1. Tela de Login
Figura 2. Tela de conversão, ao iniciar
Figura 3. Tela de conversão, após clicar no botão converter
4/36
Ao tentar entrar na aplicação (http://localhost:8080/jee5app ou http://localhost:8080/jee6app, assumindo
que você está usando o glassfish com a porta padrão configurada: 8080), é exibida a tela de login. Uma vez
logado no sistema, o usuário é redirecionado para a tela exibida na figura 2.
A página JSF exibida na figura 2 tem o seguinte comportamento: quando o usuário clica no botão submit, o
JSF chama um ManagedBean, que aciona um EJB do tipo SessionBean. O EJB usa um EntityBean
mapeado via JPA para acessar os dados da tabela.
O mesmo acontece para as telas exibidas nas figuras 4, 5 e 6. Todas elas chamam um ManagedBean, que
por sua vez chama um EJB session que usa JPA para acessar o banco.
A tela mostrada na figura 4 exibe a lista de moedas cadastradas e permite, para cada moeda, editá-la ou
apagá-la. Ao clicar no X, a moeda é simplesmente apagada e a lista é recarregada. Ao clicar no E para
editá-la, é exibida a figura 6, permitindo a alteração da moeda. Clicando no menu “Adicionar Nova Moeda” o
usuário é levado para a figura 5, que permite que o mesmo efetue a adição.
Figura 4. Lista de moedas cadastradas
5/36
Figura 5. Adicionar nova moeda
Figura 6. Alterar moeda
A figura 7 mostra o retorno de um servlet, que quando chamado aciona um EJB para converter um
valor em dólares para Real e retorna um XML com o valor original e o valor em reais.
6/36
Figura 7. XML retornado pela chamada ao servlet
A aplicação lê as taxas de conversão de uma tabela em um banco de dados. A figura 8 mostra dados de
exemplo para a tabela “TAXA”, que deve estar disponível no banco de dados. Essa tabela o valor, em reais,
da unidade de cada moeda. Na figura, vemos que um dólar, por exemplo, custa R$ 1,70 e um Iene (moeda
do Japão, MOEDA = JPY) custa R$ 0,0202631.
Figura 8. Taxas de conversão de outras moedas para Real
Visão de classes
Antes de entrarmos nos detalhes da migração da aplicação, cabe fornecer uma visão geral das
classes em cada aplicação. As figuras 9 e 10 mostram como ficam as classes da aplicação com
JAVA EE 5 e com JAVA EE 6, respectivamente.
Perceba que na versão nova não são usadas interfaces EJB, sendo o bean injetado diretamente nas
classes ConversorMoedaCliente e MoedaCliente, que são managed beans usados pela página JSF
que, assim como o servlet, acessam um EJB para converter uma quantia em reais para uma quantia
em dólares.
Esses ManagedBeans existem nas duas versões da aplicação, o que muda é sua implementação e a
forma de injetar o EJB, como veremos nas próximas seções.
Managed Beans
Managed Beans, ou beans gerenciados pelo container, é um conceito da especificação
JAVA EE usado, sobretudo, em aplicações JSF. O conceito de managed bean é bem
simples, são classes Java acessíveis por facelets que normalmente fazem a ponte entre a
parte visual e a parte de negócio.
O facelet, que no JAVA EE 6 substitui o JSP como tecnologia padrão para a camada
visual, por boa prática deve conter somente a parte visual da aplicação, delegando para
os managed beans a parte de lógica de apresentação. Os managed beans, por sua vez,
devem conter somente a lógica de apresentação, delegando a parte de negócio para
classes específicas de negócio ou, como é o caso dessa aplicação, para EJBs.
Os facelets acessam os managed beans através de expressões EL (Expression
Language), que nada mais são além de expressões misturadas no HTML delimitadas por
#{...}. A listagem 14, por exemplo, exibe um facelet que acessa um managed bean através
da expressão “#{conversorMoedaCliente.valorConvertido}”.
7/36
O conceito de managed beans e EL deve ser bem conhecido também pela maioria nos
leitores, então nesse artigo é feito apenas um comparativo entre as diferenças entre a
versão JAVA EE 5 e JAVA EE 6.
class App Jee 5
Serv let
w eb
JEE5Serv let
home.j sp
ej b
«ManagedBean»
Conv ersorMoedaCliente
lista.j sp
-
«interface»
ConversorMoeda
«EJB»
Conv ersorMoedaBean
moedaDest: String
moedaOri: String
valorConvertido: Double
valorOriginal: Double
+
converter(Double, String, String) : Double
«EJB»
MoedaBean
editar.j sp
«interface»
Moeda
«ManagedBean»
MoedaCliente
adicionar.j sp
-
id: Integer
moeda: String
taxa: Double
+
+
+
+
adicionar(Taxa) : void
alterar(Taxa) : void
apagar(Integer) : void
encontrar(Integer) : void
modelo
«EJB Entity»
Taxa
login.j sp
Figura 9. Classes na aplicação JAVA EE 5
-
id: Integer
moeda: String
taxa: Double
8/36
class App Jee 6
Serv let
w eb
JEE6Serv let
home.xhtml
«ManagedBean»
Conv ersorMoedaCliente
lista.xhtml
-
moedaDest: String
moedaOri: String
valorConvertido: Double
valorOriginal: Double
ej b
«EJB»
Conv ersorMoedaBean
+
editar.xhtml
converter(Double, String, String) : Double
«ManagedBean»
MoedaCliente
-
id: Integer
moeda: String
taxa: Double
adicionar.xhtml
«EJB»
MoedaBean
+
+
+
+
adicionar(Taxa) : void
alterar(Taxa) : void
apagar(Integer) : void
encontrar(Integer) : void
modelo
«EJB Entity»
Taxa
login.xhtml
-
id: Integer
moeda: String
taxa: Double
Figura 10. Classes na aplicação JAVA EE 6
Visão de pacotes
Uma das diferenças entre as especificações JAVA EE 5 e JAVA EE 6 é o fato de que agora é
possível colocar EJBs dentro do WAR diretamente, sem a necessidade de um EAR. A Figura 11
mostra como seria a visão de pacotes nas duas versões da aplicação e ilustra essa diferença do
JAVA EE .
9/36
Figura 11. Diferença entre JAVA EE 5 e JAVA EE 6 com relação a pacotes
Numa aplicação tradicional JAVA EE 5, contendo tanto classes web como EJB, é necessário criar
no mínimo 2 pacotes para fazer deploy da aplicação: um arquivo WAR (Web ARchive) contendo as
classes web, e um jar contendo os EJBs. Além desses dois, é comum empacotarmos ambos os
pacotes dentro de um EAR (Enterprise Application Archive), para não precisarmos fazer o deploy
do WAR e do EJB-JAR separadamente, garantindo que a versão do WAR é sempre compatível com
a versão do EJB-JAR.
Embora esse esquema de empacotamento possa ser interessante para aplicações realmente grandes,
onde queremos fazer deploy de apenas parte da aplicação em um servidor e parte da aplicação em
outro, para a grande maioria das aplicações é um grande transtorno, pelo fato de ser difícil
empacotar a aplicação dessa forma.
A dificuldade se deve principalmente ao fato de existirem classes na aplicação que devem ficar
acessíveis tanto pela camada web quanto pela camada EJB, como é o caso das interfaces dos EJBs,
das classes de domínio ou dos TOs (Transfer Objects).
Como existe uma parte comum tanto para a camada web quanto para a camada de negócio, tornase complicado fazer o deploy de uma aplicação completa com JAVA EE 5. É necessário colocar as
bibliotecas dentro do EAR e referenciar tanto no EJB-JAR quanto no WAR ou, então, colocar as
mesmas classes compiladas tanto no EJB-JAR quando no WAR, como foi feito no exemplo desse
artigo.
Com JAVA EE 6 esse problema não existe, pois todas as classes de todas as camadas ficam no
WEB-INF/classes, tornando tudo acessível para todos. Na figura 7 também não aparece a parte com
as interfaces EJBs, pelo fato delas não existirem mais no JAVA EE 6, como veremos mais adiante.
Visão de arquivos
A listagem 1 mostra o local de cada arquivo da aplicação JAVA EE 5 dentro dos pacotes gerados,
ou seja, qual o caminho de cada arquivo dentro EAR, do WAR e do EJB-JAR. A listagem 2 mostra
10/36
a mesma visão para a aplicação JAVA EE 6, mostrando somente os caminhos dentro do WAR, já
que a aplicação migrada não tem EAR nem EJB-JAR.
Cuidado para não confundir a visão de componentes com a visão dos arquivos dentro do IDE. Independente de como
os arquivos ficam no seu ambiente de desenvolvimento, o que importa para o container JAVA EE quando você faz
deploy é como os arquivos estão dispostos dentro dos pacotes, que é o que é mostrado nas listagens 1 e 2.
Listagem 1. Arquivos em cada componente – JAVA EE 5
EAR (Java EE 5app.ear):
/Java EE 5app-ejb.jar
/Java EE 5app.war
/META-INF/application.xml
/META-INF/MANIFEST.MF
EJB-JAR (Java EE 5app-ejb.jar):
/br/com/human/ejb/ConversorMoeda.class
/br/com/human/ejb/ConversorMoedaBean.class
/br/com/human/ejb/Moeda.class
/br/com/human/ejb/MoedaBean.class
/br/com/human/modelo/Taxa.class
/META-INF/MANIFEST.MF
/META-INF/persistence.xml
WAR (Java EE 5app.war):
/default.css
/style.css
/adicionar.jsp
/editar.jsp
/error.jsp
/footer.jsp
/header.jsp
/home.jsp
/lista.jsp
/login.jsp
/menu.jsp
/META-INF/MANIFEST.MF
/WEB-INF/classes/br/com/human/ejb/ConversorMoeda.class
/WEB-INF/classes/br/com/human/ejb/Moeda.class
/WEB-INF/classes/br/com/human/modelo/Taxa.class
/WEB-INF/classes/br/com/human/servlet/JAVA EE 5Servlet.class
/WEB-INF/classes/br/com/human/web/ApplicationMessages.properties
/WEB-INF/classes/br/com/human/web/ConversorMoedaCliente.class
/WEB-INF/classes/br/com/human/web/MoedaCliente.class
/WEB-INF/faces-config.xml
/WEB-INF/lib
/WEB-INF/web.xml
/WEB-INF/sun-web.xml
Listagem 2. Arquivos em cada componente – JAVA EE 6
WAR (Java EE 5app.war):
/default.css
/style.css
/adicionar.xhtml
/editar.xhtml
/error.xhtml
/home.xhtml
/lista.xhtml
/login.xhtml
/menu.xhtml
/META-INF/MANIFEST.MF
/WEB-INF/classes/br/com/human/ejb/ConversorMoedaBean.class
/WEB-INF/classes/br/com/human/ejb/MoedaBean.class
/WEB-INF/classes/br/com/human/modelo/Taxa.class
/WEB-INF/classes/br/com/human/servlet/JAVA EE 6Servlet.class
/WEB-INF/classes/br/com/human/web/ApplicationMessages.properties
/WEB-INF/classes/br/com/human/web/ConversorMoedaCliente.class
/WEB-INF/classes/br/com/human/web/MoedaCliente.class
/WEB-INF/classes/META-INF/persistence.xml
/WEB-INF/faces-config.xml
/WEB-INF/lib
/WEB-INF/web.xml
11/36
Na listagem 1, percebemos que as interfaces Moeda, ConversorMoeda e a classe Taxa ficam
acessíveis tanto do EJB-JAR quanto do arquivo WAR. Note como fica mais simples na listagem 2,
com JAVA EE 6.
O arquivo persistence.xml, exibido na listagem 4, faz parte da especificação JPA e é usado para
mapear as classes de entidade e para definir o data source usado para acessar o banco que contem a
tabela correspondente à entidade. Em nosso exemplo, mapeamos a classe Taxa, nosso Entity Bean.
Na versão nova (listagem 2) esse arquivo não fica mais em META-INF/persistence.xml, mas sim
em /WEB-INF/classes/META-INF/, que é o local padrão para se colocar esse arquivo agora que é
possível colocar EntityBeans dentro do WAR. Perceba que a classe Taxa também foi movida para
dentro do WAR.
O arquivo web.xml foi utilizado para configurar de forma fácil a servlet do JSF, mas não fosse por
isso poderia ser omitido do WAR (ao menos segundo a especificação, embora alguns containers
ainda exijam), pois a maioria das configurações agora podem ser feitas por anotações, como
veremos.
Migração da aplicação
Teoricamente, existe backward compatibility da versão 6 para a versão 5, ou seja, tudo o que é
possível fazer com JAVA EE 5 fica igual no JAVA EE 6. E então, se você tem uma aplicação
desenvolvida em JAVA EE 5 poderia facilmente fazer deploy do EAR já desenvolvido num
container novo, como o glassfish 3, sem precisar migrar nada.
Por que migrar então? Um dos motivos é que a aplicação ficará muito mais simples de ser
mantida, pois a maioria dos recursos adicionais do JAVA EE 6 facilita muito o dia a dia na hora de
manter o código e diminui consideravelmente o número de arquivos necessários. Além disso,
converter o código de uma aplicação é um excelente modo de se atualizar para a versão nova, já que
vamos focar exatamente nas diferenças de uma versão para a outra do JAVA EE .
Na prática, para projetos reais, pode ou não valer a pena migrar suas aplicações para a versão 6 da
especificação JAVA EE . Espera-se que esse artigo contribua para dar ao leitor uma visão melhor
das vantagens da nova versão, para que ele mesmo possa decidir se é interessante ou não migrar
seus projetos. Se estiver criando aplicações a partir do zero, contudo, com certeza será uma boa
idéia já usar a versão nova, a não ser que existam limitações externas, como impossibilidade de
rodar um container que a suporte, como o glassfish 3.
Nas seções a seguir, vamos migrar cada feature da aplicação JAVA EE 5 para utilizar os novos
recursos da versão 6.
Convertendo os EJBs
O Entity Bean é sem dúvida a parte que menos muda, se você já estiver usando EJB 3. A classe
taxa mostrada na listagem 3 é exatamente a mesma para as duas versões da aplicação. Basicamente
é utilizada a anotação javax.persistence.Entity para definir o bean como uma entidade e
javax.persistence.Id para denotar o campo correspondente ao ID.
Nessa aplicação de exemplo, a camada web chama um EJB session Bean que consulta os dados
utilizando esse EntityBean Taxa e retorna instâncias dessa mesma classe para a web. Embora isso
funcione e esteja correto para esse caso simples, aplicações maiores deveriam transferir dados para
a web através de TOs, usando os EntityBeans somente para realizar consultas no banco. Além disso,
ao invés de realizar consultas diretamente do EJB Session Bean, seria interessante usar um pattern
de acesso a dados, como DAO ou Active Record.
Essas decisões, contudo, fazem parte da definição da arquitetura específica de cada aplicação, não
havendo uma “melhor forma” de fazer universal. Por esse motivo, no artigo a aplicação de exemplo
limitou-se a fazer apenas o necessário.
Listagem 3. EntityBean – Taxa.java
package br.com.human.modelo;
12/36
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Taxa {
@Id
private Integer id;
private String moeda;
private Double taxa;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getMoeda() {
return moeda;
}
public void setMoeda(String moeda) {
this.moeda = moeda;
}
public Double getTaxa() {
return taxa;
}
public void setTaxa(Double taxa) {
this.taxa = taxa;
}
}
A configuração da persistence unit também é bem fácil e não teve mudanças. O XML de
configuração é mostrado na listagem 4. Note que esse arquivo deve ficar em um local diferente
dentro do pacote, conforme mostrado na seção “Visão de Pacotes”.
Listagem 4. Unidade de persistência – persistence.xml
<?xml version='1.0' encoding='UTF-8'?>
<persistence>
<persistence-unit name="ConversorDS">
<description>Unidade de persistência para acessar a tabela de moedas
</description>
<jta-data-source>jdbc/ConversorDS</jta-data-source>
<class>br.com.human.modelo.Taxa</class>
</persistence-unit>
</persistence>
Com relação ao EJB Session Bean, houve uma grande mudança na versão 6 do JAVA EE , que é a
inexistência de interfaces. As listagens 5 e 6 mostram a versão JAVA EE 5 e a listagem 7 mostra a
versão JAVA EE 6.
A listagem 5 mostra a interface do Session Bean, que era incluída pelo ManagedBean
ConversorMoedaCliente, exibido na listagem 18. Essa interface só existe na versão JAVA EE 5.
13/36
Na listagem 6, o EJB ConversorMoedaBean herda de ConversorMoeda, o que não acontece mais na
versão nova, mostrada na listagem 7. Perceba também que na listagem 19, que mostra o
ConversorMoedaCliente na versão JAVA EE 6, o EJB é injetado diretamente, não mais sua
interface.
Essa acabou sendo uma das grandes vantagens da nova versão do JAVA EE , já que o motivo de
existir uma interface seria tornar possível ter várias implementações de um mesmo EJB em seu
código, com o mesmo contrato. Na versão antiga isso nunca era utilizado e pelo fato do Session
Bean ter virado um simples POJO, fica bem mais fácil usar os mecanismos de orientação a objeto
da própria linguagem Java, ao mesmo tempo em que não deixamos de ter todas as vantagens do uso
de EJBs, como capacidade de rodar em cluster e ser gerenciado pelo container.
Comparando as implementações do EJB (listagens 6 e 7), podemos perceber uma diferença na
forma de busca os dados, já que na versão JAVA EE 5 (listagem 6) é utilizado Query Language e
na versão JAVA EE 6 (listagem 7) é utilizada a API de Criteria.
Listagem 5. Interface EJB ConversorMoedaBean - versão JAVA EE 5
package br.com.human.ejb;
import java.util.List;
import javax.ejb.Remote;
import br.com.human.modelo.Taxa;
@Remote
public interface ConversorMoeda {
public Double converter(String moedaOri, String moedaDest, Double
valorOri);
public List<Taxa> getListaTaxas();
}
Listagem 6. Implementação EJB ConversorMoedaBean - versão JAVA EE 5
package br.com.human.ejb;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import br.com.human.modelo.Taxa;
@Stateless
public class ConversorMoedaBean implements ConversorMoeda {
@PersistenceContext
EntityManager em;
public Double converter(String moedaOri, String moedaDest, Double
valorOri) {
Double taxaMoedaOri, taxaMoedaDest;
taxaMoedaOri = getTaxaMoeda(moedaOri);
taxaMoedaDest = getTaxaMoeda(moedaDest);
Double result = valorOri * (taxaMoedaOri / taxaMoedaDest);
return result;
}
14/36
@SuppressWarnings("unchecked")
public Double getTaxaMoeda(String moeda) {
Double taxaMoeda = 1.0;
List<Taxa> resultado = em
.createQuery("SELECT t FROM Taxa t WHERE t.moeda = ?1")
.setParameter(1, moeda).getResultList();
Taxa m = resultado.get(0);
taxaMoeda = m.getTaxa();
return taxaMoeda;
}
}
@SuppressWarnings("unchecked")
public List<Taxa> getListaTaxas() {
return em.createQuery("SELECT t FROM Taxa t").getResultList();
}
Listagem 7. Implementação EJB ConversorMoedaBean - versão JAVA EE 6
package br.com.human.ejb;
import java.util.List;
import
import
import
import
import
import
import
import
javax.ejb.Stateless;
javax.persistence.EntityManager;
javax.persistence.PersistenceContext;
javax.persistence.TypedQuery;
javax.persistence.criteria.CriteriaBuilder;
javax.persistence.criteria.CriteriaQuery;
javax.persistence.criteria.Predicate;
javax.persistence.criteria.Root;
import br.com.human.modelo.Taxa;
@Stateless
public class ConversorMoedaBean {
@PersistenceContext
EntityManager em;
public Double converter(String moedaOri, String moedaDest, Double
valorOri) {
Double taxaMoedaOri, taxaMoedaDest;
taxaMoedaOri = getTaxaMoeda(moedaOri);
taxaMoedaDest = getTaxaMoeda(moedaDest);
Double result = valorOri * (taxaMoedaOri / taxaMoedaDest);
return result;
}
public Double getTaxaMoeda(String moeda) {
Double taxaMoeda = 1.0;
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Taxa> criteriaQuery = criteriaBuilder
.createQuery(Taxa.class);
Root<Taxa> taxa = criteriaQuery.from(Taxa.class);
Predicate condition = criteriaBuilder.equal(taxa.get("moeda"),
moeda);
criteriaQuery.where(condition);
TypedQuery<Taxa> typedQuery = em.createQuery(criteriaQuery);
List<Taxa> resultado = typedQuery.getResultList();
Taxa m = resultado.get(0);
taxaMoeda = m.getTaxa();
15/36
}
return taxaMoeda;
public List<Taxa> getListaTaxas() {
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Taxa> criteriaQuery = criteriaBuilder
.createQuery(Taxa.class);
TypedQuery<Taxa> typedQuery = em.createQuery(criteriaQuery);
List<Taxa> resultado = typedQuery.getResultList();
}
return resultado;
}
Criteria API
Quem está acostumado com o Hibernate deve conhecer de longa sua API de Criteria
Queries. Esse foi um feature tão largamente usado por desenvolvedores que acabou
entrando para a própria especificação JAVA EE nessa versão 6, embora existam rumores
de que será melhorada ainda mais nas novas versões e que não tenha ficado tão boa
quanto a original, do Hibernate.
A vantagem é poder usá-la com qualquer implementação JPA e não só com o Hibernate,
o que pode ser crítico dependendo do container sendo utilizado.
Basicamente, a idéia de uma API desse tipo é poder realizar consultas no banco sem
qualquer uso de uma linguagem de consulta, deixando as regras de negócio todas no
código e eliminando completamente a dependência do banco de dados sendo utilizado.
Uma grande vantagem que esse approach representa é o fato de o compilador lançar erro
caso algo esteja errado na query, coisa que não aconteceria caso fosse usada uma string
com QL.
Utilizando a factory CriteriaBuilder, é possível criar uma query para uma classe
considerada a raiz da busca. Com o objeto de definição de consulta criado, é possível
compor uma série de critérios a partir dessa raiz da busca, tornando-a cada vez mais
específica para aquilo que se deseja encontrar. Por exemplo, poderíamos adicionar para
a raiz da busca definições de predicados (que corresponderiam à cláusula WHERE de um
SQL), ordenações, agrupamentos, subqueries, joins, etc.
Convertendo os descritores de deploy
Um dos principais motivos de se querer converter uma aplicação JAVA EE 5 para a versão 6 é
que na versão nova quase não é necessário escrever XML. Muito do que se configurava através de
arquivos de configuração XML agora é configurado via anotações.
Por exemplo, não é mais necessário declarar os servlets no web.xml. A listagem 8 mostra o
web.xml versão JAVA EE 5 e a listagem 9 mostra a versão 6.
Listagem 8. web.xml da aplicação JAVA EE 5
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<!-- Faces Servlet -->
<servlet>
<servlet-name>FacesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
16/36
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Java EE 5 Servlet -->
<servlet>
<servlet-name>Java EE 5Servlet</servlet-name>
<servlet-class>br.com.human.servlet.JAVA EE 5Servlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>FacesServlet</servlet-name>
<url-pattern>/Java EE 5/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Java EE 5Servlet</servlet-name>
<url-pattern>/Java EE 5servlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>Java EE 5/home.jsp</welcome-file>
</welcome-file-list>
<security-constraint>
<web-resource-collection>
<web-resource-name>Administrativo</web-resource-name>
<!-- The URLs to protect -->
<url-pattern>*.jsp</url-pattern>
</web-resource-collection>
<auth-constraint>
<!-- The authorized users -->
<role-name>administrador</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>file</realm-name>
<form-login-config>
<form-login-page>/Java EE 5/login.jsp</form-login-page>
<form-error-page>/Java EE 5/error.jsp</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>administrador</role-name>
</security-role>
</web-app>
Listagem 9. JAVA EE 6 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
17/36
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/Java EE 6/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>Java EE 6/home.xhtml</welcome-file>
</welcome-file-list>
<security-constraint>
<web-resource-collection>
<web-resource-name>Administrativo</web-resource-name>
<!-- The URLs to protect -->
<url-pattern>*.xhtml</url-pattern>
</web-resource-collection>
<auth-constraint>
<!-- The authorized users -->
<role-name>administrador</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>file</realm-name>
<form-login-config>
<form-login-page>/Java EE 6/login.xhtml</form-login-page>
<form-error-page>/Java EE 6/error.xhtml</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>administrador</role-name>
</security-role>
</web-app>
Como é possível notar, o servlet do faces continua sendo declarado. Em alguns containers existe
como não realizar essa configuração, pois ela é feita no próprio framework, ou seja, não é
necessário declarar o servlet do faces no web.xml pois o próprio jar do framework já contem um
arquivo web-fragment.xml (veja quadro) que especifica o mapeamento de URL da servlet.
Na implementação de referência do JSF ela ainda ficou como necessária e, se não fosse por isso,
não precisaríamos de um web.xml na aplicação. Se você experimentar rodar a aplicação versão
JAVA EE 6 tirando o web.xml, perceberá que o servlet continuará rodando normalmente, só as
páginas JSF que não.
Web Fragments
Embora não tenha sido usado nessa aplicação de exemplo, uma das principais novidades do JAVA
EE 6 é a existência de web fragments. A listagem 10 exemplifica como seria um arquivo webfragment.xml de um framework, embora não seja usado na aplicação.
Esse arquivo ficaria dentro da pasta META-INF de um jar incluído em WEB-INF/lib. Por
exemplo, se você inclui na sua aplicação o framework.jar como uma lib, esse arquivo deveria ter
uma pasta META-INF e dentro dela um arquivo web-fragment.xml como o da listagem 10. Dessa
forma, o container ao carregar sua aplicação já entenderia que você incluiu um módulo web, que
tem servlets a serem carregadas.
18/36
A idéia de web-fragments é tornar a configuração web modularizável, de forma que seja possível
construir vários módulos web independentes, cada um com sua configuração, e integrá-los de forma
fácil quando desejado. Não é mais preciso desenvolver os servlets em vários JARs separados e
colocar a configuração na aplicação que os utiliza, os próprios módulos podem vir com sua
configuração definida.
Esse arquivo poderia definir outras configurações hoje existentes no web.xml, mas no exemplo é
mostrado o mapeamento de um servlet. A tag servlet é semelhante à usada no web.xml, mas no
lugar da servlet-mapping é definida uma classe listener que faz o mesmo papel, programaticamente.
É possível usar tanto arquivos web.xml, quanto anotações e web-fragments, mas existe uma ordem
de processamento, sendo que a configuração do web.xml se sobrepõe às outras, ou seja, se existe
configuração de uma servlet no web.xml, a anotação dessa servlet será ignorada. Se essa servlet foi
incluída a partir de um JAR externo com um web-fragment.xml, a configuração do jar também será
ignorada se a servlet for mapeada pelo web.xml da aplicação. Isso permite sobrescrever as
configurações do módulo incluído.
Listagem 10. web-fragment.xml – novo feature do JAVA EE 6 permite modularizar o web.xml
<web-fragment>
<servlet>
<servlet-name>myFrameworkServlet</servlet-name>
<servlet-class>myFramework.myFrameworkServlet</servlet-class>
</servlet>
<listener>
<listener-class>myFramework.myFrameworkListener</listener-class>
</listener>
</web-fragment>
Observe novamente as listagens 8 e 9. Note que existe uma diferença crucial entre os arquivos de
ambas as listagens que é a designação da versão, no início do arquivo. O arquivo da listagem 8
define a versão 2.3 do servlet, enquanto que o arquivo da listagem 9 define a versão 3 (atente para o
elemento web-app, atributo version).
Se essa versão não estivesse configurada corretamente, o container não leria os EJBs, que não
eram permitidos dentro do war no JAVA EE 5, e ignoraria completamente possíveis arquivos webfragment e anotações de mapeamento dentro de servlets.
Além disso, na listagem 9 não é mapeada a servlet da aplicação, pois ela é mapeada através de
anotações, conforme mostrado na próxima seção.
Convertendo a servlet
As listagens 11 e 12 mostram, respectivamente, as versões da servlet para as plataformas JAVA
EE 5 e 6. A implementação das servlets exibidas nas duas listagens não muda praticamente nada:
ambas as classes servlet recebem um parâmetro dólares vindo da URL (método GET), e retornam
um XML com o valor original em dólares e o valor convertido para reais. O XML é retornado
através de prints para o objeto response.
Verifique, além das duas listagens, o mapeamento da servlet da listagem 11, exibido na listagem 8.
A servlet está mapeada para atender a URLs do tipo: http://localhost:8080/Java EE 5app/Java
EE 5servlet?dolares=23.0, onde Java EE 5app é o contexto da aplicação (o nome do EAR gerado,
se você fizer deploy jogando o arquivo na pasta autodeploy do glassfish) e Java EE 5servlet é o
mapeamento conforme configurado no web.xml.
Uma das coisas que muda de uma versão para outra é o mapeamento. Na classe exibida na
listagem 11, desenvolvida para a versão JAVA EE 5, não há nenhuma configuração de
mapeamento, pois a mesma é realizada no web.xml. Na classe exibida na listagem 12, desenvolvida
19/36
para a versão JAVA EE 6, o mapeamento é feito através de uma anotação: @WebServlet("/Java
EE 6servlet")
Verifique agora a listagem 12. A servlet está mapeada para atender a URLs do tipo:
http://localhost:8080/Java EE 6app/Java EE 6servlet?dolares=23.0, onde Java EE 6app é o
contexto da aplicação (o nome do WAR gerado, se você fizer deploy jogando o arquivo na pasta
autodeploy do glassfish) e Java EE 6servlet é o mapeamento conforme configurado na anotação da
classe.
Outra mudança é a forma de acessar o EJB. Na listagem 11 é necessário criar uma intância do
InitialContext e então obter a referência para o EJB via JNDI, ou seja, é necessário se preocupar no
código da aplicação em quando instanciar a referência para o EJB.
Na listagem 12, versão JAVA EE 6, o EJB é injetado no atributo conversor com a tag @EJB. O
próprio container se preocupa em obter a referência para o EJB através dessa injeção de
dependência, tornando a instanciação completamente transparente para quem está desenvolvendo a
aplicação. Dentro do método service, o atributo conversor é simplesmente usado, sem necessidade
da aplicação instanciá-lo.
Listagem 11. JAVA EE 5Servlet
package br.com.human.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import
import
import
import
import
javax.naming.InitialContext;
javax.servlet.ServletException;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
import br.com.human.ejb.ConversorMoeda;
public class JAVA EE 5Servlet extends HttpServlet {
private static final long serialVersionUID = 5231367249531988910L;
private ConversorMoeda conversor;
public void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
PrintWriter out = res.getWriter();
Double dolares = 100.00;
dolares =
Double.parseDouble(req.getParameter("dolares").toString());
double reais=0.0;
try {
InitialContext ic = new InitialContext();
conversor = (ConversorMoeda) ic.lookup(ConversorMoeda.class
.getName());
reais = conversor.converter("USD", "BRL", dolares);
conversor = null;
} catch (Exception ex) {
ex.printStackTrace();
}
out.println("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
out.println("<Valor>");
out.print("\t<Dolar>");
out.print(dolares);
out.println("</Dolar>");
out.print("\t<Real>");
out.print(reais);
20/36
out.println("</Real>");
out.println("</Valor>");
}
}
Listagem 12. JAVA EE 6Servlet
package br.com.human.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import
import
import
import
import
import
javax.ejb.EJB;
javax.servlet.ServletException;
javax.servlet.annotation.WebServlet;
javax.servlet.http.HttpServlet;
javax.servlet.http.HttpServletRequest;
javax.servlet.http.HttpServletResponse;
import br.com.human.ejb.ConversorMoedaBean;
@WebServlet("/Java EE 6servlet")
public class JAVA EE 6Servlet extends HttpServlet {
private static final long serialVersionUID = 5231367249531988910L;
@EJB
private ConversorMoedaBean conversor;
public void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
PrintWriter out = res.getWriter();
Double dolares = 100.00;
dolares =
Double.parseDouble(req.getParameter("dolares").toString());
double reais = conversor.converter("USD", "BRL", dolares);
out.println("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
out.println("<Valor>");
out.print("\t<Dolar>");
out.print(dolares);
out.println("</Dolar>");
out.print("\t<Real>");
out.print(reais);
out.println("</Real>");
out.println("</Valor>");
}
}
A annotation WebServlet exibida na listagem 12 aceitaria muito mais opções de mapeamento. Um
outro exemplo de possibilidade é mostrado na listagem 13.
Listagem 13. Exemplo fictício do uso da annotation WebServlet
@WebServlet(name="Java EE 6servlet", asyncSupported=true,
urlPatterns={"/jee6servlet", "/getVal"})
O exemplo define mais de uma URL pattern, ou seja, poderíamos chamar essa servlet usando tanto
um
URL
como
http://localhost:8080/jee6app/jee6servlet?dolares=23.0
quanto
http://localhost:8080/jee6app/getVal?dolares=23.0.
21/36
A anotação tamém expõe a servlet como assíncrona. Embora não usado em nossa aplicação de
exemplo, servlet assíncrona é outro feature impactante da especificação servlet 3.0, trazendo
funcionalidades semelhantes às oferecidas por frameworks como cometd, ou seja, server-push para
o client.
Servlets Assíncronas
Um dos grandes problemas enfrentados na vida real por quem desenvolve aplicações
web é que algumas vezes o processamento realizado no lado servidor é muito demorado,
tornando inviável deixar a aplicação no browser esperando a resposta. Por esse motivo, a
solução é usar uma chamada para uma servlet somente para iniciar o processamento, de
forma que a conexão do browser com o servidor web é fechada assim que o
processamento é iniciado e a servlet retorna.
Além de não deixar o cliente (no caso o browser) esperando uma resposta, fechar a
conexão libera aquela instância da servlet para processar outros requests, no lado do
servidor.
Contudo, quando o processamento termina, a conexão com o browser já foi fechada e
não há como devolver um status de resultado do processamento para o cliente. Uma das
soluções mais usadas nesse caso é o pooling, ou seja, o browser faria uma nova
chamada a cada X unidades de tempo (ex.: a cada 30 segundos) perguntando ao servidor
se aquele processamento já terminou.
Pooling também não é a solução ideal pois é um desperdício de recursos, já que
consultar o status do processamento no servidor de tempos em tempos ocupa mais
processamento e possivelmente acesso a banco do que simplesmente esperar o
processamento terminar do lado do servidor para dar a resposta.
O framework cometd foi uma das primeiras implementações de Server push, uma das
melhores soluções para esse tipo de problema, que agora está também na especificação
JAVA EE 6.
No servlet 3.0, que faz parte da especificação JAVA EE 6, você pode especificar a
servlet como assíncrona. Se a servlet é assíncrona, ao invés de realizar todo o
processamento no método service, o desenvolvedor chama um método startAsync(), do
objeto request, que retorna um objeto AsyncContext, responsável por encapsular o
request e o response da chamada. O método service então termina de ser executado
antes do processamento terminar e a servlet é devolvida para o container JAVA EE , mas
a conexão com o cliente não é fechada.
Através de um método complete do AsyncContext e de uma interface AsyncListener, a
aplicação tem a possibilidade de escrever a resposta para o cliente posteriormente,
tornando possível o servidor dar uma resposta para o cliente.
Os detalhes de como usar servlets assíncronas estão fora do escopo desse artigo, mas
é uma das novidades mais impactantes da nova versão e com certeza podem substituir
implementações extremamente complexas de aplicações JAVA EE 5 já desenvolvidas.
Convertendo o JSF
As listagens 14 e 15 mostram respectivamente os arquivos header.jsp e footer.jsp, ambos usados
na aplicação que usa JAVA EE 5. Esses arquivos são incluídos por todos os outros JSPs da
aplicação, como o home.jsp (listagem 16) e o adicionar.jsp (listagem 17).
Listagem 14. header.jsp – cabeçalho comum - camada visual da aplicação na versão JAVA
EE
5
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
22/36
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/Java EE 5/";
%>
<HTML xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Conversor de moeda JAVA EE </title>
<link rel="stylesheet" type="text/css" href="style.css" media="screen" />
<link rel="stylesheet" type="text/css" href="default.css" media="screen" />
<base href="<%=basePath%>">
</head>
<body>
<div id="wrap">
<div id="top"></div>
<div id="content">
<div class="header">
<h1><a href="#">Conversor de moedas JAVA EE </a></h1>
<h2>Human Software</h2>
</div>
<div class="breadcrumbs"><a href="home.jsp"> Home </a> &middot; <%=nomePagina%>
</div>
Listagem 15. footer.jsp – rodapé comum - camada visual da aplicação na versão JAVA EE
5
<div id="clear"></div>
</div>
<div id="bottom"></div>
</div>
</body>
</html>
Listagem 16. home.jsp – página inicial - camada visual da aplicação na versão JAVA EE
5
<%
%>
String nomePagina = "Conversor de Moedas";
<%@ include file="header.jsp"%>
<%@ taglib
<%@ taglib
<f:view>
<div
<div
uri="http://java.sun.com/jsf/html" prefix="h"%>
uri="http://java.sun.com/jsf/core" prefix="f"%>
class="middle">
id="contents"><h:form id="conversorForm">
<h3>Entre com o valor a ser convertido e escolha as moedas de
origem e destino</h3>
<BR>
<div class="valor">Valor original:
<h:inputText
id="valorOriginal" label="Valor original"
23/36
value="#{conversorMoedaCliente.valorOriginal}"
converterMessage="#{ErrMsg.valorOriginalConvert}"
required="true">
<f:validateDoubleRange minimum="0.0" />
<f:convertNumber maxFractionDigits="2" />
</h:inputText>
<h:selectOneListbox size="1" id="moedaOri"
value="#{conversorMoedaCliente.moedaOri}">
<f:selectItems value="#{conversorMoedaCliente.listaMoedas}" />
</h:selectOneListbox></div>
<div class="valor">Valor destino:
<div class="input"><h:outputText lang="pt_BR"
value="#{conversorMoedaCliente.valorConvertido}">
<f:convertNumber groupingUsed="true" type="currency"
currencySymbol="" />
</h:outputText></div>
<h:selectOneListbox size="1" id="moedaDest"
value="#{conversorMoedaCliente.moedaDest}">
<f:selectItems value="#{conversorMoedaCliente.listaMoedas}" />
</h:selectOneListbox></div>
<h:commandButton id="submit" styleClass="submit" value="Converter"
/>
<P><h:message showSummary="true" showDetail="false"
style="color: red;
font-family: 'New Century Schoolbook', serif;
font-style: oblique;
text-decoration: overline"
id="errors1" for="valorOriginal" /></P>
</h:form></div>
</div>
<%@ include file="menu.jsp"%>
</f:view>
<%@ include file="footer.jsp"%>
Listagem 17. adicionar.jsp – página adicionar - camada visual da aplicação na versão
JAVA EE
5
<%
%>
String nomePagina = "Adicionar Moeda";
<%@ include file="header.jsp"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<f:view>
<div class="middle">
<div id="contents">
<h:form id="conversorForm">
<h3>Adicionar moeda</h3>
<BR>
<div class="valor">Moeda:
<h:inputText
id="moeda" label="Moeda"
value="#{moedaCliente.moeda}" required="true">
<f:validateLength minimum="3" maximum="3"/>
</h:inputText>
</div>
<div class="valor">Taxa:
<h:inputText
id="taxa" label="Taxa"
value="#{moedaCliente.taxa}"
24/36
required="true">
converterMessage="#{ErrMsg.valorOriginalConvert}"
<f:validateDoubleRange minimum="0.0" />
<f:convertNumber maxFractionDigits="2" />
</h:inputText>
</div>
<h:commandButton id="submit" styleClass="submit" value="Adicionar"
action="#{moedaCliente.adicionar}" >
<f:param name="id" value="-1" />
</h:commandButton>
<P>
<h:messages showDetail="false" showSummary="true" style="color: red;
font-family: 'New Century Schoolbook', serif;
font-style: oblique;
text-decoration: overline;
list-style-type: none;"/>
</P>
</h:form></div>
</div>
<%@ include file="menu.jsp"%>
</f:view>
<%@ include file="footer.jsp"%>
Listagem 18. menu.jsp – menu - camada visual da aplicação na versão JAVA EE
5
<div class="right">
<h2>Menu</h2>
<ul>
<li><h:outputLink value="home.jsp">
<h:outputText value="Converter Moedas" />
</h:outputLink></li>
<li><h:outputLink value="lista.jsp">
<h:outputText value="Lista de Moedas Cadastradas" />
</h:outputLink></li>
<li><h:outputLink value="adicionar.jsp">
<h:outputText value="Adicionar Nova Moeda" />
</h:outputLink></li>
</ul>
</div>
Perceba como funciona a lógica de reuso da parte comum com JSPs, que são a tecnologia padrão
para JAVA EE 5. Todo arquivo tem que incluir explicitamente a parte comum e fica difícil
reutilizar as partes comuns. Isso fica mais claro quando observamos como foi alterado o nome da
página nesse exemplo. Verifique que a variável nomePagina é exibida por um scriptlet dentro do
header.jsp, mas o valor dessa variável é setado em cada JSP que inclui o mesmo.
Outro ponto importante de ser observado é o número de scriptlets usados. Se a idéia do JSP é
poder dividir o trabalho visual do trabalho de programação, é desejável ter código misturado com o
HTML? Perceba que setar a variável basePath não é uma tarefa tão complicada para se colocar no
JSP, uma vez que é utilizada somente por uma necessidade do próprio HTML, que é setar a pasta
base dos arquivos. Contudo, mesmo para uma tarefa tão simples, o profissional que estiver criando
esse arquivo precisará conhecer Java para criar a expressão.
Na versão JAVA EE 6, ao invés de JSPs são usados facelets, que se tornaram a tecnologia padrão
para a camada visual. O mesmo trabalho realizado com JSPs e JAVA EE 5 nas listagens 14, 15, 16,
17 e 18 é realizado com JAVA EE 6 e facelets nas listagens 19, 20, 21 e 22.
25/36
Listagem 19. template.xhtml – template comum - camada visual da aplicação na versão
JAVA EE
6
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
<title>Conversor de moeda JAVA EE </title>
<link rel="stylesheet" type="text/css" href="style.css" media="screen" />
<link rel="stylesheet" type="text/css" href="default.css" media="screen" />
<base
href="#{request.getScheme()}://#{request.getServerName()}:#{request.getServerPor
t()}#{request.getContextPath()}/Java EE 6/" />
</head>
<body>
<div id="wrap">
<div id="top"></div>
<div id="content">
<div class="header">
<h1><a href="#">Conversor de moedas JAVA EE </a></h1>
<h2>Human Software</h2>
</div>
<div class="breadcrumbs"><h:outputLink value="home.xhtml">
<h:outputText value="Home" />
</h:outputLink> &middot; #{nomePagina}</div>
<f:view>
<div class="middle">
<div id="contents"><ui:insert name="body" /></div>
</div>
<ui:insert name="menu" />
</f:view>
<div id="clear"></div>
</div>
<div id="bottom"></div>
</div>
</body>
</html>
Listagem 20. menu.xhtml – menu - camada visual da aplicação na versão JAVA EE
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
6
26/36
<ui:composition>
<div class="right">
<h2>Menu</h2>
<ul>
<li><h:outputLink value="home.xhtml">
<h:outputText value="Converter Moedas" />
</h:outputLink></li>
<li><h:outputLink value="lista.xhtml">
<h:outputText value="Lista de Moedas Cadastradas" />
</h:outputLink></li>
<li><h:outputLink value="adicionar.xhtml">
<h:outputText value="Adicionar Nova Moeda" />
</h:outputLink></li>
</ul>
</div>
</ui:composition>
</html>
Listagem 21. home.xhtml – página inicial - camada visual da aplicação na versão JAVA
EE
6
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition template="template.xhtml">
<ui:param name="nomePagina" value="Conversor de Moedas" />
<ui:define name="menu">
<ui:include src="menu.xhtml" />
</ui:define>
<ui:define name="body">
<h:form id="conversorForm">
<h3>Entre com o valor a ser convertido e escolha as moedas de
origem e destino</h3>
<BR />
<div class="valor">Valor original: <h:inputText
id="valorOriginal" label="Valor original"
value="#{conversorMoedaCliente.valorOriginal}"
converterMessage="#{ErrMsg.valorOriginalConvert}"
required="true">
<f:validateDoubleRange minimum="0.0" />
<f:convertNumber maxFractionDigits="2" />
</h:inputText> <h:selectOneListbox size="1" id="moedaOri"
value="#{conversorMoedaCliente.moedaOri}">
<f:selectItems
value="#{conversorMoedaCliente.listaMoedas}" />
</h:selectOneListbox></div>
<div class="valor">Valor destino:
<div class="input"><h:outputText lang="pt_BR"
value="#{conversorMoedaCliente.valorConvertido}">
<f:convertNumber groupingUsed="true" type="currency"
currencySymbol="" />
</h:outputText></div>
<h:selectOneListbox size="1" id="moedaDest"
value="#{conversorMoedaCliente.moedaDest}">
27/36
<f:selectItems
value="#{conversorMoedaCliente.listaMoedas}" />
</h:selectOneListbox></div>
<h:commandButton id="submit" styleClass="submit"
value="Converter" />
<P><h:message showSummary="true" showDetail="false"
style="color: red;
font-family: 'New Century Schoolbook', serif;
font-style: oblique;
text-decoration: overline"
id="errors1" for="valorOriginal" /></P>
</h:form>
</ui:define>
</ui:composition>
</html>
Listagem 22. adicionar.xhtml – página adicionar - camada visual da aplicação na
versão JAVA EE
6
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition template="template.xhtml">
<ui:param name="nomePagina" value="Adicionar Moeda" />
<ui:define name="menu">
<ui:include src="menu.xhtml" />
</ui:define>
<ui:define name="body">
<h:form id="conversorForm">
<h3>Adicionar moeda</h3>
<BR/>
<div class="valor">Moeda: <h:inputText id="moeda"
label="Moeda"
value="#{moedaCliente.moeda}" required="true">
<f:validateLength minimum="3" maximum="3" />
</h:inputText></div>
<div class="valor">Taxa: <h:inputText id="taxa" label="Taxa"
value="#{moedaCliente.taxa}"
converterMessage="#{ErrMsg.valorOriginalConvert}"
required="true">
<f:validateDoubleRange minimum="0.0" />
<f:convertNumber maxFractionDigits="2" />
</h:inputText></div>
<h:commandButton id="submit" styleClass="submit"
value="Adicionar"
action="#{moedaCliente.adicionar}">
<f:param name="id" value="-1" />
</h:commandButton>
<P><h:messages showDetail="false" showSummary="true"
style="color: red;
font-family: 'New Century Schoolbook', serif;
font-style: oblique;
text-decoration: overline;
list-style-type: none;" />
</P>
28/36
</h:form>
</ui:define>
</ui:composition>
</html>
Existem várias diferenças entre JAVA EE 5 e JAVA EE 6 no tocante ao uso de facelets. Os
arquivos xhtml mostrados nas listagens 19, 20, 21 e 22 necessariamente tem de ser XMLs bem
formatados, ou seja, tem que seguir as regras de formatação definidas pelo w3c (World Wide Web
Consortion – entidade responsável por padrozinar as especificações para a web). Exemplos de
regras: toda tag aberta ter de ser fechada, todo elemento (tag) ter um namespace, definido de acordo
com os padrões XML do w3c, etc.
O objetivo dessas regras é deixar a especificação do documento o mais formal e estrita o possível,
não deixando margens para ambigüidades, como acontece no HTML, onde cada browser interpreta
o documento de uma forma diferente.
Na versão home.jsp exibida na listagem 16, as taglibs são definidas pelo elemento taglib. No
home.xhtml, versão JAVA EE 6, da exibida na listagem 21, os elementos são definidos no padrão
XML, através do atributo xmlns do elemento html. Os facelets também estão de acordo com o
padrão de páginas XHTML “Transitional Document Type Definition” (veja a referência para o
DTD na listagem), outro padrão do w3c.
Apesar de essas diferenças serem significativas, a maior diferença entre o uso de JSPs ou de
facelets, nesse exemplo é o uso de templates. Perceba que o conteúdo dos arquivos header.jsp
(listagem 14), footer.jsp (listagem 15) e menu.jsp (listagem 18) foi praticamente todo movido para
os arquivos template.xhtml (listagem 19) e menu.xhtml (listagem 20).
Pegando como exemplo os arquivos home.jsp (listagem 16) e adicionar.jsp (listagem 17), vemos
que o arquivo menu.jsp é incluído em cada página, pois fica difícil obter reuso apenas com os
includes do JAVA EE 5. Comparando com o home.xhtml (listagem 21) e o adicionar.xhtml
(listagem 22), vemos que com templates a divisão de conteúdo em arquivos é muito mais lógica,
pois condiz mais com o funcional.
Observe agora como o basePath e o nome da página são setados no template.xhtml da listagem 21.
Compare com a versão JAVA EE 5, o header.jsp da listagem 14. Os scriptlets foram substituídos
por expressões EL, eliminando a necessidade de código no HTML.
O título de cada página também ficou setado de forma muito mais elegante, já que a variável EL
nomePagina é setada de forma explícita como parâmetro (ui:param) para o template, em cada
página.
O uso de templates é um grande benefício dos facelets, padrão no JAVA EE 6, que com certeza
tornarão a parte visual de suas aplicações muito mais organizadas. Veja o quadro “Usando
templates com facelets” para mais informações de como funcionam.
Usando templates com facelets
Usar templates é uma forma excelente de obter reutilização de camada visual, além de
deixar o código muito mais intuitivo e organizado. Um template define um conteúdo HTML
com várias funcionalidades comuns, com inserções em algumas partes de conteúdo
HTML específico, que varia conforme a página sendo renderizada.
Fazendo uma analogia com design patterns, isso se parece muito com o pattern
template method, onde uma classe base define funcionalidade comum e chama métodos
virtuais, a serem implementados diferentemente em cada classe específica.
Quando definimos um template, usamos a tag ui:insert (ui refere-se ao namespace
http://java.sun.com/jsf/facelets) para definirmos as regiões onde deve ser inserido
conteúdo personalizado. Por exemplo, <ui:insert name="menu" /> define um ponto de
inserção de conteúdo HTML referenciado pelo nome menu.
29/36
Para uma página facelet utilizar o template, é necessário definir qual template está sendo
utlizado
pela
tag
ui:composition.
Por
exemplo,
<ui:composition
template="template.xhtml"> define que a página utiliza o template “template.xhtml”.
Uma vez definido o template, podem ser passados parâmetros para o mesmo,
específicos da página em questão, com o uso da tag ui:param e cada região do template
onde foi definido conteúdo personalizável (com ui:insert) deve ter o HTML definido pela
tag ui:define.
Dentro da tag ui:define, que define o conteúdo HTML a ser utilizado na região específica
do template, é possível definir diretamente o HTML ou utilizar a tag ui:include, para
incluir o conteúdo a partir de um arquivo externo.
Conforme já explicado na seção “Visão de classes”, a especificação JSF assume o uso de managed
beans, ou beans gerenciados pelo container, para integrar a camada de apresentação com a camada
de negócio. Os managed beans devem conter a lógica de apresentação da aplicação e são acessados
via expressões EL (Expression Language) pelo JSF. Perceba que tanto no arquivo home.jsp
mostrado na listagem 16 quanto no arquivo home.xhtml mostrado na listagem 21, um managedBean
referenciado com o nome conversorMoedaCliente é acessado por uma expressão EL:
“#{conversorMoedaCliente.valorOriginal}”.
Na versão JAVA EE 5, o managed bean é configurado pelo arquivo faces-config.xml exibido na
listagem
23.
Note
no
início
do
arquivo
a
especificação
de
versão:
xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/webfacesconfig_1_2.xsd”
version="1.2"
Nesse arquivo de configuração é configurado o nome e caminho do arquivo .properties que
guardará as mensagens de erro da aplicação, o locale padrão e também o mapeamento da classe
br.com.human.web.ConversorMoedaCliente para o nome conversorMoedaCliente.
Através desse mapeamento, o container JAVA EE 5 sabe que, quando encontrar no arquivo JSF a
expressão conversorMoedaCliente, deve acessar a classe ConversorMoedaCliente. Para poder
acessar o atributo valorOriginal, o mesmo deve estar configurado também no faces-config.xml. A
listagem 25 mostra a classe ConversorMoedaCliente versão JAVA EE 5.
Já na listagem 24 temos o faces-config.xml da aplicação migrada. Observe que a especificação de
versão
muda:
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" version="2.0". Se a versão estiver
especificada estiver incorreta, o container irá ignorar as anotações do managed bean e as novidades
da versão nova.
Nesse arquivo continuam as configurações de resource bundle e locale, mas as configurações de
mapeamento passam a ser feitas por anotações, conforme mostrado na listagem 26, que mostra a
classe ConversorMoedaCliente de acordo com a especificação JAVA EE 6. O mapeamento da
classe com o nome “conversorMoedaCliente” é feito pela anotação @ManagedBean. O nome
conversorMoedaCliente é o nome default para o qual a classe é mapeada, ou seja, o mesmo nome
da classe com a primeira letra em minúsculo.
Assim como acontece com as servlets, na versão JAVA EE 6 deixa de ser necessário instanciar o
EJB manualmente, como mostrado na listagem 25, que cria o InitialContext para chamar o EJB,
bastando injetar o mesmo com o uso da anotação @EJB (listagem 26).
Listagem 23. faces-config.xml da aplicação JAVA EE
5
<?xml version='1.0' encoding='UTF-8'?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
version="1.2">
<application>
30/36
<resource-bundle>
<base-name>br.com.human.web.ApplicationMessages</base-name>
<var>ErrMsg</var>
</resource-bundle>
<locale-config>
<default-locale>pt</default-locale>
<supported-locale>en</supported-locale>
</locale-config>
</application>
<managed-bean>
<managed-bean-name>conversorMoedaCliente</managed-bean-name>
<managed-bean-class>br.com.human.web.ConversorMoedaCliente</managedbean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>valorOriginal</property-name>
<property-class>java.lang.Double</property-class>
<value>0.0</value>
</managed-property>
<managed-property>
<property-name>valorConvertido</property-name>
<property-class>java.lang.Double</property-class>
<value>0.0</value>
</managed-property>
<managed-property>
<property-name>moedaOri</property-name>
<property-class>java.lang.String</property-class>
<value>USD</value>
</managed-property>
<managed-property>
<property-name>moedaDest</property-name>
<property-class>java.lang.String</property-class>
<value>BRL</value>
</managed-property>
</managed-bean>
<managed-bean>
<managed-bean-name>moedaCliente</managed-bean-name>
<managed-bean-class>br.com.human.web.MoedaCliente</managed-beanclass>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>id</property-name>
<property-class>java.lang.Integer</property-class>
<value>#{param.id}</value>
</managed-property>
<managed-property>
<property-name>moeda</property-name>
<property-class>java.lang.String</property-class>
<null-value />
</managed-property>
<managed-property>
<property-name>taxa</property-name>
<property-class>java.lang.Double</property-class>
<null-value />
</managed-property>
</managed-bean>
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>lista</from-outcome>
<to-view-id>/Java EE 5/lista.jsp</to-view-id>
31/36
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>editar</from-outcome>
<to-view-id>/Java EE 5/editar.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
Listagem 24. faces-config.xml da aplicação JAVA EE
6
<?xml version='1.0' encoding='UTF-8'?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<application>
<resource-bundle>
<base-name>br.com.human.web.ApplicationMessages</base-name>
<var>ErrMsg</var>
</resource-bundle>
<locale-config>
<default-locale>pt</default-locale>
<supported-locale>en</supported-locale>
</locale-config>
</application>
</faces-config>
CDI
Perceba que não é necessário configurar o managed bean por XML na versão 6.
Existem inúmeras novidades na versão 6 da API com relação aos managed beans, como
o CDI – Context Dependency Injection.
O conceito de CDI já foi apresentado em detalhes nas edições 84 e 85 da revista e foge
do escopo desse artigo, portanto não será apresentado em detalhes aqui, mas para ter
uma idéia da flexibilidade trazida, a injeção por contexto permitiria, por exemplo, ter mais
de uma implementação de um bean e injetar uma implementação diferente dependendo
do contexto.
Por exemplo, para nosso caso poderíamos ter duas implementações para o bean
conversorMoedaCliente, uma que convertesse de real para dólar e outra que convertesse
de dólar para real. Poderiamos então definir dois contextos diferentes, como por exemplo
“nativo” ou “estrangeiro”, usando os chamados qualificadores, que fazem parte da
especificação CDI. Para usar a implementação que converte de dólar para real,
usaríamos na
classe
cliente
uma
injeção
do
tipo
@Inject
@Nativo
ConversorMoedaCliente conversorMoedaCliente. Para usar a outra implementação,
usaríamos @Inject @Estrangeiro ConversorMoedaCliente conversorMoedaCliente.
Listagem 25. ConversorMoedaCliente – managed bean da aplicação versão JAVA EE
package br.com.human.web;
import java.util.ArrayList;
import java.util.List;
5
32/36
import javax.faces.model.SelectItem;
import javax.naming.InitialContext;
import br.com.human.ejb.ConversorMoeda;
import br.com.human.modelo.Taxa;
public class ConversorMoedaCliente {
private Double valorConvertido;
private Double valorOriginal;
private String moedaOri;
private String moedaDest;
private ConversorMoeda conversor;
public ConversorMoedaCliente() {
}
public Double getValorConvertido() {
return valorConvertido;
}
public void setValorConvertido(Double valorConvertido) {
this.valorConvertido = valorConvertido;
if (valorConvertido != null) {
try {
InitialContext ic = new InitialContext();
conversor = (ConversorMoeda)
ic.lookup(ConversorMoeda.class
.getName());
this.valorOriginal = conversor.converter(moedaDest,
moedaOri,
valorConvertido);
conversor = null;
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public Double getValorOriginal() {
return valorOriginal;
}
public void setValorOriginal(Double valorOriginal) {
this.valorOriginal = valorOriginal;
if (valorOriginal != null) {
try {
InitialContext ic = new InitialContext();
conversor = (ConversorMoeda)
ic.lookup(ConversorMoeda.class
.getName());
this.valorConvertido = conversor.converter(moedaOri,
moedaDest,
valorOriginal);
conversor = null;
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public List<SelectItem> getListaMoedas() {
33/36
}
List<SelectItem> result = null;
try {
InitialContext ic = new InitialContext();
conversor = (ConversorMoeda) ic.lookup(ConversorMoeda.class
.getName());
result = new ArrayList<SelectItem>();
for (Taxa t : conversor.getListaTaxas()) {
SelectItem i = new SelectItem(t.getMoeda());
result.add(i);
}
conversor = null;
} catch (Exception ex) {
ex.printStackTrace();
}
return result;
public Taxa[] listaTaxas = new Taxa[1];
public List<Taxa> getListaTaxas() {
List<Taxa> result = null;
try {
InitialContext ic = new InitialContext();
conversor = (ConversorMoeda) ic.lookup(ConversorMoeda.class
.getName());
result = conversor.getListaTaxas();
conversor = null;
// return (Taxa[]) result.toArray();
return result;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public String getMoedaOri() {
return moedaOri;
}
public void setMoedaOri(String moedaOri) {
this.moedaOri = moedaOri;
// Faz refresh no valor
setValorOriginal(getValorOriginal());
}
public String getMoedaDest() {
return moedaDest;
}
public void setMoedaDest(String moedaDest) {
this.moedaDest = moedaDest;
// Faz refresh no valor
setValorOriginal(getValorOriginal());
}
}
Listagem 26. ConversorMoedaCliente – managed bean migrado
package br.com.human.web;
34/36
import java.util.ArrayList;
import java.util.List;
import
import
import
import
import
javax.ejb.EJB;
javax.faces.bean.ManagedBean;
javax.faces.bean.ManagedProperty;
javax.faces.bean.SessionScoped;
javax.faces.model.SelectItem;
import br.com.human.ejb.ConversorMoedaBean;
import br.com.human.modelo.Taxa;
@ManagedBean
@SessionScoped
public class ConversorMoedaCliente {
@ManagedProperty(value = "USD")
private String moedaOri;
@ManagedProperty(value = "BRL")
private String moedaDest;
@ManagedProperty(value = "0.0")
private Double valorConvertido;
@ManagedProperty(value = "0.0")
private Double valorOriginal;
@EJB
private ConversorMoedaBean conversor;
public ConversorMoedaCliente() {
}
public Double getValorConvertido() {
return valorConvertido;
}
public void setValorConvertido(Double valorConvertido) {
this.valorConvertido = valorConvertido;
if (valorConvertido != null) {
try {
this.valorOriginal = conversor.converter(moedaDest,
moedaOri,
valorConvertido);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public Double getValorOriginal() {
return valorOriginal;
}
public void setValorOriginal(Double valorOriginal) {
this.valorOriginal = valorOriginal;
if (valorOriginal != null) {
try {
this.valorConvertido = conversor.converter(moedaOri,
moedaDest,
valorOriginal);
} catch (Exception ex) {
ex.printStackTrace();
}
}
35/36
}
public List<SelectItem> getListaMoedas() {
List<SelectItem> result = null;
try {
result = new ArrayList<SelectItem>();
for (Taxa t : conversor.getListaTaxas()) {
SelectItem i = new SelectItem(t.getMoeda());
result.add(i);
}
} catch (Exception ex) {
ex.printStackTrace();
}
return result;
}
public Taxa[] listaTaxas = new Taxa[1];
public List<Taxa> getListaTaxas() {
List<Taxa> result = null;
try {
result = conversor.getListaTaxas();
// return (Taxa[]) result.toArray();
return result;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public String getMoedaOri() {
return moedaOri;
}
public void setMoedaOri(String moedaOri) {
this.moedaOri = moedaOri;
// Faz refresh no valor
setValorOriginal(getValorOriginal());
}
public String getMoedaDest() {
return moedaDest;
}
public void setMoedaDest(String moedaDest) {
this.moedaDest = moedaDest;
// Faz refresh no valor
setValorOriginal(getValorOriginal());
}
}
Conclusões
O que foi mostrado nesse artigo foi apenas uma pequena ponta de um enorme iceberg de
mudanças trazidas pelo JAVA EE 6. Contudo, espera-se que depois de ler esse artigo inteiro o
leitor tenha uma visão muito mais elaborada do que ficou diferente do JAVA EE 5 para o JAVA
EE 6 e de como pensar no estilo da nova versão.
36/36
Depois que ter conhecido na prática como fazer no estilo do JAVA EE 6 aquilo com o que se está
acostumado a fazer no estilo JAVA EE 5, fica mais fácil ter uma visão das diferenças entre cada
especificação e de quais partes da nova especificação são melhores para cada projeto.
Links
http://download.oracle.com/javaee/5/tutorial/doc/
JAVA EE tutorial da Sun/Oracle – versão 5
http://download.oracle.com/javaee/6/tutorial/doc/
JAVA EE tutorial da Sun/Oracle – versão 6
Marcelo Elias Del Valle ([email protected] / http://www.mvalle.com) é arquiteto de TI e trabalha com Java desde 1998 nas
áreas bancária, Telecom e de pesquisa. É nerd por opção e adora desenvolvimento de jogos.

Documentos relacionados