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.
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/web-facesconfig_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>
<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</ managed-bean-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-bean-class>
<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>
</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 5
package br.com.human.web; import java.util.ArrayList; import java.util.List;
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(); }
} }
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
import java.util.ArrayList; import java.util.List; import javax.ejb.EJB; import javax.faces.bean.ManagedBean; import javax.faces.bean.ManagedProperty; import javax.faces.bean.SessionScoped; import 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(); }
}
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.
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.