Escolar Documentos
Profissional Documentos
Cultura Documentos
JGoodies Binding
Ligue componentes gráficos a objetos
de negócio mantendo a abstração OO
JAVA EE 5
JA Explorando a Plataforma
Conheça a fundo todas as novidades,
Javaa Persistence
Jav Persistence API
A nova API de persistência do EJB 3.0
de motivações a efeitos práticos – com que muda as bases do mapeamento
um tutorial no GlassFish objeto-relacional em Java
s
e RECAPITULANDO: DICAS NA WEB
õ
ç
FELIPE LEME
10
e Obtendo as versões suportadas de JSP e servlets, usando forward e redirect,
S manipulando JavaBeans em taglibs e alterando o nome de arquivos para download
JAVA EE 5
OSVALDO PINALI DOEDERLEIN
16
Explorando a nova versão do Java corporativo: anotações, injeção de dependên-
cias, novas JSRs e um exemplo prático usando o servidor open source GlassFish
PERSISTÊNCIA NO JAVA EE 5
AVA
a ANDRÉ DANTAS ROCHA E SÉRGIO OLIVEIRA KUBOTA
28
p
a Aprenda a utilizar a nova Java Persistence API, de conceitos de mapeamento
C objeto-relacional, a um exemplo completo usando Toplink
Toplink Essentials e MySQL
UMA MALA DIRETA COM JAVAMAIL
YARA SENGER E ANA ABRANTES
62
Utilize a API JavaMail para enviar e-mails em HTML com anexos para múltiplos
destinatários, e personalize mensagens usando expressões regulares
RIA COM OPEN LASZLO
b ANDRÉ LUÍS MONTEIRO
70
e Turbine suas interfaces gráficas e maximize a interatividade com o usuário
W utilizando uma plataforma open source baseada em Flash, XML e Java
p
o
t
INTERFACES GRÁFICAS COM QUALIDADE – PARTE 2
k
s
HUGO VIDAL TEIXEIRA
Descubra como aplicar o pattern Presentation Model e a API Binding do
50
e JGoodies para construir GUIs com produtividade, favorecendo os testes unitários
D
jm39.indb 3 15/8/2006 18:12:15
Direção
Ano V • Edição 39 • 2006 • ISSN 1676-8361
C
Ari Dias Neto, Fernando Lozano, Hugo Vidal, Leonardo Galvão, om o Java Enterprise Edition 5.0, entramos em numa nova e importante
Osvaldo Doederlein, Sérgio Kubota, Yara Senger geração do desenvolvimento corporativo. O foco na facilidade de uso, a ab-
Arte sorção de técnicas utilizadas em produtos open source, uma participação sem
Diretor de Arte Tarcísio Bannwart ( phdesign@phdesign.com.br ) precedentes da comunidade e uma implementação de referência que já rivaliza com
Diagramação Jaime Peters Junior, Lais Pancote e Tersis Zonato os melhores servidores de aplicações... Talvez pela primeira vez na história do Java
Ilustrações Felipe Machado e Francisco Peixoto corporativo vemos lançada uma versão que é sucesso entre as mais diversas castas
Capa Felipe Machado de desenvolvedores Java. O Java EE 5.0 faz grandes correções de rumo, criando novas
Produção tecnologias que tornam obsoletas áreas problemáticas da especificação como os tão
Gerência de Marketing Kaline Dolabella polêmicos Entity Beans, incorpora mais do que nunca os web services, e já olha adiante
integrando-se com várias novidades que virão no Java SE 6.0 (Mustang). Quem diria
Distribuição
Fernando Chinaglia Distribuidora S.A.
que uma especificação do JCP, envolvendo gigantes do mercado com visões e perfis
Rua Teodoro da Silva, 907, Grajaú - RJ tão distintos como Sun, IBM, Oracle, BEA, Motorola, Cisco e SAP, chegaria a um con-
CEP 20563-900, (21) 3879-7766 - (21) 2577-6362 senso de tal solidez, criando uma especificação tão eficaz e alin hada às necessidades
do mercado? Mas foi o que aconteceu, em mais uma demonstração da efetividade do
Atendimento ao leitor Java Community Process e da força da comunidade Java.
A DevMedia possui uma Central de Atendimento on-line, onde você pode Nesta edição, o Java EE 5 é tratado em dois artigos aprofundados. Em uma visão
tirar suas dúvidas sobre serviços, enviar críticas e sugestões e falar com um
de nossos atendentes.Através da nossa central t ambém é possível alterar geral da plataforma, você conhece todas as grandes novidades, com diversos exem-
dados cadastrais, consultar o status de assinaturas e conferir a data de envio plos funcionais, e ainda um tutorial mostrando como criar uma aplicação usando
de suas revistas.Acesse www.devmedia.com.br/central, ou se preferir uma seleção dos novos recursos da especificação, além do GlassFish, o servidor que
entre em contato conosco através do telefone 21 2283-9012. é a base da implementação de referência do novo Java EE. Em um segundo artigo, é
Edições anteriores vista em detalhes a API que tem chamado mais atenção no Java EE 5, a Java Persis-
tence API (JPA). Parte da especificação do EJB 3.0, mas planejada como especificação
Adquira as edições anteriores da revista Java Magazine ou de qualquer outra
publicação do Grupo DevMedia de forma prática e segura, em
independente na sua próxima versão, a JPA se inspira fortemente em ferramentas
www.devmedia.com.br/anteriores. de mapeamento objeto-relacional como Hibernate e iBatis, padronizando uma área
fundamental do desenvolvimento corporativo. Você vai conhecer os fundamentos da
Publicidade JPA, e criar um exemplo completo usando vários tipos de associações e herança.
publicidade@javamagazine.com.br , 21 2213-0940 Ainda nesta edição, confira um artigo sobre desenvolvimento AJAX que explora a
Anúncios – Anunciando nas publicações e nos si tes do Grupo DevMedia, API do Google Web Toolkit para criar componentes altamente interativos e integrá-
você divulga sua marca ou produto para mais de 100 mil desenvolvedores los em uma aplicação sofisticada com acesso a dados. Veja também como melhorar
de todo o Brasil, em mais de 200 cidades.Solicite nossos Media Kits, com
detalhes sobre preços e formatos de anúncios.
suas aplicações desktop usando o pattern Presentation Model e a API JGoodies Bin-
ding, que permite vincular os seus modelos OO à interface gráfica de forma eficaz
Reprints Editoriais – Se foi publicado na Java Magazine um artigo que
possa alavancar as suas vendas, multiplique essa oportunidade! Solicite a e organizada.
reimpressão da matéria junto com a capa da edição em que s aiu, e distribua Em outra matéria passo a passo, é mostrado como criar uma mala direta completa
esse reprint personalizado entre seus clientes. usando a API JavaMail e expressões regulares. E mais um artigo voltado à internet
Encarte de CDs – Faça como nossos maiores anunciantes.Encarte um CD mostra como usar o OpenLaszlo para criar Rich Internet Applications, baseadas em
com uma amostra de seus produtos na Java Magazine e atinja um público Flash, XML e Java. Finalmente, nesta edição retomamos a seção “Recapitulando”, dessa
segmentado e formador de opinião. vez trazendo dicas sobre o desenvolvimento com JSP e servlets; também incluímos
Realização
um artigo especial no Cafeína mostrando como fazer sua aplicação
Apoio
SWT se integrar perfeitamente ao visual do Windows XP.
Boa leitura!
Parceiros
Leonardo Galvão
SOA importantes novidades do Java EE 5: a Java simples configuração do container web (no caso
Persistence API. do Tomcat,a ativação da válvula “SingleSignOn”) faz
Sou assinante da Java Magazine e gostaria
com que o login em uma aplicação seja automati-
primeiramente de parabenizá-los pela excelente
camente repassado para todas as outras aplicações
qualidade do material apresentado. Também Ferramentas dentro do mesmo servidor de aplicações, ou do
gostaria de saber de vocês se há possibilidade de
Parabenizo a Java Magazine pelas excelentes mesmo cluster de servidores de aplicações.
publicar na revista um artigo falando sobre SOA e
edições. Sou iniciante em Java e uma das grandes As dificuldades surgem quando o desenvol-
web services, visto que o assunto é cada vez mais
dificuldades para um iniciante é, além de aprender vedor, em vez de adaptar seus programas aos
comentado na comunidade Java.
a linguagem, saber utilizar as ferramentas exis- recursos de segurança previstos pelo Java EE,
Michel Pires da Silva
tentes. E a Java Magazine sabe nos mostrar como cria sua própria solução “personalizada” de
utilizar essas ferramentas de forma muito didática, autenticação. Mas não há motivos para se fugir
Web Services e SOA (Service-Oriented Archi-
o que facilita bastante a vida dos iniciantes. aos recursos padrões do Java EE, pois qualquer
tecture) foi um dos assuntos de capa da Java
Rubens Renato Lima servidor de aplicações com um mínimo de qua-
Magazine 34. O artigo de Osvaldo Doederlein
lidade é capaz de usar senhas armazenadas em
cobriu desde as tecnologias precursoras dos web
vários locais, como bancos de dados, diretórios
services como RPC, até o atual enfoque na criação Autenticação integrada no Java EE LDAP ou mesmo as senhas de rede em Windows,
de arquiteturas orientadas a serviços. Tenho várias aplicações Java EE e preciso que elas Linux e Netware.
trabalhem com um único login. Ou seja, quando
Java EE 5 o usuário efetuar o login em uma das aplicações,
TestNG 5.0 nível de suporte oferecido no IDE para o CVS. construído sobre o Apache Lucene. Recursos
O framework de testes TestNG é o principal polari on.org . enterprise não disponíveis na versão Commu-
concorrente do JUnit, e se posiciona como nity, como Single Sign-On e suporte a clusters
uma alternativa mais capaz e mais moderna LimpidLog estão acessíveis sob uma licença baseada na
(NG é uma abreviação de “New Generation”). A nova API de logging open source idéia de “contribuição ou pagamento”, pela
Primeiro framework de testes a suportar LimpidLog tem uma proposta radical, que qual empresas ou indivíduos podem escolher
anotações (mesmo antes do Java 5), o Tes- pode simplificar o log de informações sobre pagar royalties pelos recursos adicionais, ou
tNG inclui suporte a métodos dependentes classes durante a execução. Em vez de codificar trocá-los por contribuições para o projeto.
e parâmetros, distribuição de testes e testes chamadas à API de logging, você registra a jahia.o rg.
orientados a dados. classe a ser monitorada e o LimpidLog acom-
O TestNG segue um modelo de execução que panha e loga informações importantes sobre Google lança repositório open source
dispensa o uso do tradicional TestSuite e traz o que está sendo feito na classe (isso vale O Google lançou um novo repositório de
o BeanShell embutido. Há também plug-ins para mensagens do tipo TRACE e ERROR; para projetos open source, baseado no sistema de
para várias ferramentas, entre elas o Eclipse e outros casos, ainda será necessário chamar controle de versões Subversion, e subordinado
o Apache Maven. A versão 5.0 tem melhorias uma API de logging comum). A API usa a classe ao portal “Google Code” (que hospeda pro-
importantes nos relatórios de testes gerados, java. lang .ins trume nt.In stru menta tion para instru- jetos como a Go ogle Search API). O cadastro
com uma estrutura mais organizada e mudan- mentar classes e é capaz de logar eventos de de novos projetos é simples e há recursos
ças visuais. Outro destaque é o trabalho com chamada/entrada/saída de métodos, atribui- completos de busca, além de navegação por
stack traces, que agora podem ser mostrados ção de variáveis e levantamento de exceções. palavras-chave. Para registrar um projeto, é
acelet.com/limpidlog. necessário ter uma conta no Google, o que
interativamente nos relatórios HTML, sendo
possível também filtrá-los. testng.org abre a possibilidade de se usar diversos ou-
Jahia Community Edition tros serviços da empresa juntamente com o
Subversive 1.0.0 Mais um produto importante liberado como repositório.
Um dos mais populares plug-ins Eclipse open source, o Jahia Community Edition torna Um detalhe interessante é que apenas algu-
para integração com o sistema de controle de disponível sob uma licença CDDL modificada, mas licenças open source são acei tas. Diz o FAQ
versões Subversion, o Subversive chegou à 80% do código do produto. São mais de 2.200 do Google, “A comunidade open source está
versão 1.0.0. O Subversion é considerado em classes e arquivos. cheia de licenças praticamente iguais. Gostarí-
muitos pontos melhor e mais moderno que o O Jahia é uma “plataforma web unificada”, amos que projetos fossem padronizados com
CVS e hoje é adotado como sistema de controle que integra tecnologias como ECM ( Enterprise as licenças mais populares e maduras”. O repo-
de versões oficial da Fundação Apache, entre Content Management) e portlets, bem como sitório inclui ainda recursos de issue tracking,
outras organizações. O objetivo do plug-in um gerenciador de documentos baseado em um módulo que foi criado inteiramente
Subversive é trazer para o Eclipse o mesmo no Apache Slide e um mecanismo de buscas pelo Google. code.google.com/hosting.
M
Microsoft simplesmente forçava todas as
uito se fala que uma das grandes executável javaw.exe utilizado para rodar as
aplicações a assumirem o novo visual (por
vantagens do SWT sobre o Swing aplicações SWT em seu computador.
exemplo, do Windows 3.1 para o Windows
é a aderência ao visual nativo da
95). Entretanto, isto criava problemas quando
plataforma, obtido graças ao uso dos com- Os programas javaw.exe e java.exe são ambos
a aplicação utilizava componentes customi-
ponentes gráficos nativos. Entretanto, desen- alternativas para a execução de uma máquina
virtual Java (JVM). A única diferença entre eles é
zados que não se adequavam bem ao novo
volvedores de aplicações SWT e usuários do
que o cabeçalho do javaw.exe diz ao Windows que visual. Por isso, no XP, qualquer aplicação
Eclipse em geral devem ter percebido que,
ele é uma aplicação gráfica, e assim sua execução pode ser configurada para o visual “antigo”
no Windows XP, é assumido o visual nativo
não provoca a abertura de uma janela de console ou para o novo.
do Windows 98 e 2000, em vez do visual mais
moderno do Windows XP. ou prompt do MS-DOS.
Veja na Figura 1, por exemplo, o exemplo
EnderecoTerrestre.java publicado original- Uma vez criado (ou copiado) o arquivo, a
mente no artigo da Edição 31 sobre desen- linha de comando a seguir executa o exemplo
volvimento SWT. A Figura 2 ilustra como conforme visto na Figura 2 :
deveria ser a aparência da aplicação com o
javaw EnderecoTerrestre
visual nativo do XP.
A boa notícia é que as duas figuras foram
A criação do arquivo irá afetar todas as apli -
geradas pela mesma aplicação. Não foi ne-
cações SWT executadas neste computador,
cessário modificar uma única linha do código
inclusive o próprio Eclipse. As Figuras 3 e 4
Java, nem recompilar a aplicação contra uma
mostram o próprio Eclipse antes e depois da
versão diferente do SWT.
criação do javaw.exe.manifest .
A solução exige que o arquivo javaw.exe.
Fica a pergunta: por que essa “mágica”
manifest , apresentado na Listagem 1, seja
não é parte da instalação padrão do Eclipse Figura 1. Exemplo EnderecoTerrestre.java como exibido na
copiado para a mesma pasta que contém o instalação padrão do SWT no Windows XP, assumindo a
para Windows? Afinal o arquivo javaw.exe.
manifest seria simplesmente ignorado em aparência padrão do Windows 98 e 2000.
versões mais antigas do Windows, e assim
não causaria prejuízo algum.
A impossibilidade de o arquivo ser instalado
pelo próprio Eclipse decorre da licença do
Java. A redistribuição do Java da Sun deve ser
feita de modo inalterado, assim não é possível
para o Eclipse (ou para qualquer outro forne-
cedor que não tenha adquirido uma licença
especial junto à Sun) acrescentar o javaw.exe.
Dicas na
aplicações web, portanto, é sempre impor-
tante saber as versões das APIs suportadas
nos containers web utilizados. Os métodos
getMajorVersion() e getMinorVersion() da classe
javax.servlet.ServletContext permitem obter a
Web
versão da API de servlets. E sta classe fornece
ainda o método getServerInfo(), que descreve
o nome do servidor e sua versão.
Já para a versão da especificação JSP, é pre-
ciso obter um objeto javax.servlet.jsp.JspEngine e
chamar seu método getSpecificationVersion() . A
Listagem 1 contém uma página JSP que pode
N
este artigo são apresentadas dicas ser usada para obter essas informações.
úteis sobre JSP e servlets, soluções
para problemas recorrentes no de-
senvolvimento web, e esclarecimentos sobre Definindo o nome do
alguns procedimentos comuns. arquivo em downloads
Um uso comum para servlets (e mesmo
para páginas JSP) é a geração dinâmica de
Obtendo as versões de JSP arquivos, tais como planilhas ou documentos
e Servlets PDF. Nessas situações, ao enviar o arquivo
As tecnologias JSP e servlets gerado, é preciso que o servlet especifique
Nesta edição, evoluíram muito desde suas o tipo do conteúdo através do método
recapitulamos um dos primeiras versões. Por exemplo, response.setContentType(String tipo) . O tipo segue
a API de servlets 2.3 introduziu no cabeçalho da resposta HTTP retornada pelo
assuntos mais populares o conceito de filtros (interface servlet e, de acordo com ele, o navegador po-
java x.sevle t.Fi lter ), e com o JSP derá decidir o que fazer com o arquivo.
na Java Magazine: o
2.0, veio o suporte a uso da Ex- Normalmente o arquivo é exibido através
desenvolvimento com JSP e pression Language dentro das de um plug-in, ou é oferecida a opção de
páginas. salvá-lo no disco, mas nos casos onde a in-
servlets. Foram selecionadas
quatro dicas, ainda
Listagem 1. versoes.jsp , obtendo a versão das APIs web suportadas
totalmente atuais, do artigo <%@ page import=”javax.servlet.ServletContext” %>
<%@ page import=”javax.servlet.jsp.JspFactory” %>
“Dicas na Web” publicado
<%
na Edição 12, que resolvem ServletContex t sc = pageContext .getServletCo ntext();
String servidor = sc.getServerInfo();
String versaoServlet = “” + sc.getMajorVersion() + “.”
dúvidas comuns e exploram + sc.getMinorVe rsion();
String versaoJsp = JspFactory.g etDefaultFact ory().
getEngineInfo().getSpecificationVersion();
detalhes importantes da %>
tenção é que o usuário faça o download, esse sejado (como “relatorio.pdf” ou “contador. para outra página. Existem duas formas de s e
procedimento traz alguns problemas: txt”) para o servlet ou página JSP responsável fazer isso – forward (encadeamento) e redirect
•Não é garantido que o usuário tenha a pela geração do arquivo, o que funcionará (redirecionamento). Embora o resultado final
opção de salvar o arquivo em vez de o nave- independente do navegador utilizado. No pareça muitas vezes ser o mesmo, o funciona-
gador abrir automaticamente um plug-in. entanto essa solução não tem a flexibilidade mento é bem diferente sob o ponto de vista
•Mesmo que o navegador web ofereça a de permitir a definição do nome no momento do navegador web.
opção de salvamento, o nome sugerido será de execução do ser vlet/JSP.
o do servlet ou o da página JSP (por exemplo, Forward
“contador.jsp”), sendo que o ideal seria um Forward ou redirect? A primeira forma usa o método forward()
nome mais amigável, ou ao menos com a Uma necessidade muito comum na pro- da classe RequestDispatcher, como mostra o
extensão correta (como "contador-10.txt"). gramação web é passar o fluxo de execução código da Listagem 3.
Para resolver esses problemas, a solução Listagem 2. contador.jsp , exemplo simples para demonstrar mudança de nome do download
é definir a propriedade content-disposition do
<%
cabeçalho da resposta HTTP, com o valor int limite = 10; // valor padrão
attachment;filename= nome. extensão, como no try {
limite = Integer.pars eInt(request .getParameter (“limite”));
trecho de código a seguir: }
catch(Exception exc) {
// ignora exceção (limite=10)
response.setHeader( }
“content-disposition”, String nomeArquivo = “contador-” + limite + “.txt”;
“attachment;filename =” + nomeArquivo response.setContentType(“text/plain”);
); response.setHeader(“content-disposition”,
“attachment;filename=” + nomeArquivo);
for (int i=1; i<=limite; i++) {
A Listagem 2 inclui uma página JSP que out.println(i);
}
imprime um contador, de 1 até 10 (ou até %>
o valor definido no parâmetro limite). Note
que o navegador não exibe o conteúdo da Listagem 3.Forwards em JSPs e servlets
página; em vez disso abre a janela com a op -
ção de salvar o arquivo, com nome sugerido Em páginas JSP:
“contador- XX .txt” (sendo XX o limite). RequestDispatcher dispatcher =
pageContext.getServletContext().getRequestDispatcher(“/novaPagina.jsp”);
A propriedade content-disposition é definida dispatcher.forward(request, response);
no protocolo HTTP (RFC 2183 1), e não na
API de servlets/JSP. Assim o funcionamento Em servlets:
dessa dica depende da compatibilidade do RequestDispatcher dispatcher =
navegador com os padrões W3C, e pode getServletContext().getRequestDispatcher(“/novaPagina.jsp”);
dispatcher.forward(request, response);
não funcionar em navegadores mais antigos
(nesses casos, o nome sugerido continuará
sendo o nome do JSP).
Outra opção é definir no descritor
web.xml um mapeamento com o nome de-
1
RFCs (Requests for Comments) são documentos que
definem protocolos, modelos ou especificações para os
sistemas da internet. De forma ampla, representam para
a internet o que os JSRs (Java Specification Requests) são
para Java. Figura 1. Uso de RequestDispatcher.forward() numa arquitetura simplificada
O método forward() repassa a requisição chamada a out.print() ou out.println(), como 1. O corpo da tag <jsp:useBean> só é exe-
para outro recurso – como um ser vlet, página mostrado nos exemplos. cutado quando o JavaBean é instanciado.
JSP ou página HTML – dentro do mesmo con- Assim, se o escopo do bean for de sessão,
tainer web. Esse recurso pode fornecer uma Cuidados com <jsp:useBean> o código de inicialização só será executado
resposta final ao cliente, ou então repassar e <jsp:setProperty> uma vez. Códigos como o seguinte são causa
novamente a requisição (veja a Figura 1). Uma prática muito comum no desenvol- constante de bugs:
Usar forward() é útil quando o primeiro servlet vimento de páginas JSP é o uso das tags
precisa fazer algum pré-processamento <jsp:useBean id=”beanEntrada” scope= ”session”
<jsp:useBean> e <jsp:setProperty> para, respec- class=”jm.dicas.EntradaDadosBean”
(por exemplo, validar se o usuário atual tem tivamente, instanciar JavaBeans e preencher scope=”session”>
permissões para acessar a URL especificada), suas propriedades com os valores fornecidos <jsp:setProperty name=”beanEntrada” property=”*”/>
antes de passar a requisição para o servlet ou </jsp:useBean>
no formulário da página. Embora a prática
JSP que realizará o processamento final. Em seja correta, é preciso tomar alguns cuidados O problema aqui é que os valores do formulário
particular, é dessa forma que o Struts e outras com o uso dessas duas tags: só são repassados para o bean na primeira vez
implementações da arquitetura MVC realizam
o trabalho do controller (veja a Figura 2).
Redirect
A segunda forma de passar o fluxo de exe-
cução para outra página consiste em usar o
método sendRedirect() da classe HttpResponse ,
enviando com isso um comando HTTP SEND
REDIRECT para o navegador web. Nesse caso
a requisição volta para o navegador, que
automaticamente faz a requisição da página
especificada (que não precisa estar localiza-
da no mesmo servidor). A Figura 3 ilustra o
procedimento.
Figura 2. Uso de RequestDispatcher.forward() na arquitetura MVC
Comparando as técnicas
A Tabela 1 mostra as demais diferenças RequestDispatcher.forward() Response.sendRedirect()
entre cada opção, e a Listagem 4 contém Fl ux o d e e xe cu çã o p er ma ne ce no s er vi do r Fl uxo v ol ta ao cl ie nt e
uma página JSP com exemplos das duas
Atributos definidos no request são acessíveis na O request da nova página não tem nenhum atribu-
técnicas. Note que, em ambos os casos, nova página to definido
se o buffer de resposta já tiver recebido Nova página deve obrigatoriamente estar no Não há restrições quanto à localização da nova
alguma saída, a tentativa de mudar o f luxo mesmo contexto web página
de execução lança uma IllegalStateException . A URL exibida no navegador continua sendo a da
A URL no navegador muda para a da nova página
Assim, é recomendável que chamadas a página que originou a chamada de forward()
forward() ou a sendRedirect() sejam feitas A URL da nova página deve começar com “/”
Endereço da nova página pode ser qualquer URL
no começo do código principal do servlet válida
( doPost() , doGet() etc.), antes de qualquer Tabela 1. Diferenças entre redirecionamento e encadeamento
package jm.dicas;
Listagem 6. usoIncorreto.jsp, uso incorreto das tags <jsp:useBean> e <jsp:setProperty>
public class EntradaDadosBean {
Exemplo do uso incorreto das tags private String nome;
(valores dos textfields nunca mudam):<br> private String email;
<jsp:useBean id=”beanEntrada” //... métodos get/set
}
if (meuBean == null) {
meuBean = new java.util.Date ();
pageContext. setAtt ribute (“meuBean”, meuBean,
PageContext.SESSION_SCOPE);
}
Figura 3. Redirecionamento com Response.sendRedirect()
Ou seja, o código gerado tenta recuperar
que o formulário é submetido. Nas submissões 2. A especificação JSP diz que quando um um bean existente no escopo de sessão e
seguintes, o bean já está presente na sessão e parâmetro da requisição é nulo ou vazio, associá-lo a uma variável da classe Object
não precisa mais ser instanciado; conseqüente- a respectiva propriedade não é “setada” (definida no atributo type). Caso o bean não
mente a tag <jsp:setProperty> não é executada. através da tag <jsp:setProperty>. É muito exista no escopo, uma nova instância da clas-
A solução para o problema é retirar a tag comum, porém, o desenvolvedor criar có- se Date (definida no atributo class) é gerada e
<jsp:setProperty> do corpo de <jsp:useBean> : digo supondo que essa propriedade será atribuída à variável meuBean .
definida com o valor nulo (ou vazio), o que Quando apenas type é usado, o bean precisa
<jsp:useBean id=”beanEntrada”
class=”jm.dicas.EntradaDadosBean”
mais uma vez causa bugs quando o bean obrigatoriamente estar disponível no escopo,
scope=”session”/> está armazenado em escopo de sessão. A senão é lançada uma exceção. Por exemplo,
<jsp:setProperty name=”beanEntrada” property=”*”/> Figura 4 ilustra o comportamento da tag o seguinte trecho de código:
<jsp:setProperty>, passo a passo, sobre o
Ou então mudar o escopo do bean: código da Listagem 6. <jsp:useBean id=”meuBean” scope= ”session”
type=”java.lang.Object”/>
<jsp:useBean id=”beanEntrada” 3. O tipo do bean a ser usado por <jsp:useBean>
class=”jm.dicas.EntradaDadosBean” pode ser definido através dos atributos type e seria equivalente a:
scope=”request” >
class. Embora os significados desses atributos
<jsp:setProperty name=”beanEntrada” property=”*”/> Object meuBean = ( Object) pageContext.getAttribute(
</jsp:useBean> sejam semelhantes, eles representam concei- “meuBean”, PageContext .SESSION );
tos ligeiramente diferentes: class define a classe if (meuBean == null) {
Os exemplos nas Listagens 5 e 6 demons- throw new InstantiationException(
sendo instanciada, enquanto que type define
tram o uso correto e incorreto dessas tags (e “bean meuBean not found within scope”);
o tipo do bean, que, além da classe do bean, }
a Listagem 7 inclui o bean simples utilizado
pode ser uma das suas superclasses ou uma
por estas).
interface implementada por ele. Por exemplo,
2
O código mostrado aqui é parecido com o gerado pelo
o código abaixo: compilador JSP, porém simplificado: além do tratamento
de exceções ter sido omitido, os objetos foram instancia-
<jsp:useBean id=”meuBean” scope= ”session” dos através do operador new, enquanto que o compilador
type=”java.lang.Object” class=”java.util.Date”/> JSP usa java.beans.Beans.instantiate().
Java EE 5
Um Enterprise Edition muito mais fácil
OSVALDO PINALI DOEDERLEIN
do boa parte da burocracia do tradicional (mesma informação em anotações e no destas interfaces de framework, pois isto
J2EE em favor de uma opção preferencial descritor), o container dará preferência ao “queima” a oportunidade única de herança
pela simplicidade. A “programação base- descritor. Preserva-se assim a flexibilidade de implementação2).
ada em POJOs1” é fortemente suportada. dos descritores – e só há o trabalho de Em oposição à rigidez da herança, as
Veja algumas novas características: manipulá-los quando isso for realmente anotações enriquecem uma classe com
•Temos POJOs no lugar de implementa- necessário. comportamentos de forma muito mais
ção de interfaces. Não precisam mais ser Mas note que estes casos são a minoria. granular. Há anotações por tipo, atributo,
escritos centenas de métodos completa- Na prática, as oportunidades de adap- método, e até por parâmetro ou variável
mente vazios, como ejbActivate(), só porque tar aplicações a mudanças no ambiente local. Assim, se o seu bean realmente pre-
uma interface de EJB os exige. externo mexendo apenas no descritor só cisa executar algum código especial após
•É usada a Injeção de Dependências em costumam ocorrer em casos triviais, como a ativação, basta implementar um método
vez de aborrecidos lookups na JNDI. mudanças nos nomes JNDI de DataSources anotado por @PostActivate.
•As anotações assumem o lugar de des- ou filas de JMS, causadas talvez por uma As anotações possuem uma vantagem
critores XML. migração de ambiente (ex.: homologação crucial: são estaticamente tipadas. Podem
•Há muitos comportamentos default que para produção). E mesmo nestes casos, a ser verificadas e validadas de forma
evitam a necessidade de especificar op- indireção proporcionada pelas resource re- offline, o que evita toda uma categoria
ções comuns, seja com descr itores ou com ferences (J2EE 1.3+) já evita a necessidade de de bugs. O javac só verificará a correção
anotações. Por exemplo, um @WebMethod alterações até nos nomes JNDI “internos”, sintática das anotações, por exemplo re-
(método de web service) suporta anotações usados nos descritores e no código. clamando se você usar uma propriedade
@WebParam para os parâmetros, mas estas Observamos que existem algumas ca- inexistente numa anotação; não reportará
são opcionais. Na sua falta, o container racterísticas, consideradas “estruturais”, erros semânticos, ex.: uma propriedade
assumirá defaults bons para a maioria dos que se definidas por anotações não são @EJB.beanInterface com um valor que não
usos (como holder=Mode.IN). redefiníveis por descritores. Por exemplo, seja uma interface local/remota de EJB.
novamente com EJBs, anotações como Mas as ferramentas de validação incluídas
Mas será que este paradigma de progra- @Stateless e @Stateful denotam os diferentes em IDEs com suporte a Java EE e em ser-
mação é sempre melhor? Em relação às tipos de Session Beans. Mas se uma clas se vidores de aplicações poderão fazer estas
anotações, que são o instrumento funda- for anotada com @Stateless , não será possí- validações no momento da implantação
mental do novo modelo, já as questiona- vel, pelo descritor, transformá-la num EJB ou antes, evitando que o bug fique ocu lto
mos em artigos anteriores, em seções com Stateful. O motivo é simples: a diferença e “estoure” somente quando a aplicação já
títulos como “Cuidados com as anotações” entre um bean Stateless e um Statefu l não estiver em operação.
e “Uma crítica às anotações”. O motivo está apenas no descritor – beans Stateful,
de tanta precaução é que uma revisão tão presumivelmente, mantêm algum estado Injeção de Dependências
radical no processo de desenvolvimento interno, enquanto beans Stateless não o A persistência de POJOs, no estilo do
não deve ser abordada sem cuidado e fazem, portanto transformar um tipo no Hibernate, tem chamado atenção como
visão crítica. outro exige alterações de código de qual- a grande novidade que o Java EE 5 pega
Felizmente, com a forma que o Java EE quer maneira. emprestada de outros frameworks. Mas
5 tomou, esses temores não se concretiza- não menos importante é a Injeção de De-
ram. Em especial, os descritores ainda são Anotações versus Orientação a Objetos pendências (ID). Para compreender a idéia
suportados (o que já é bom por motivo de As anotações constituem uma alter- fundamental da ID, podemos classificar as
compatibilidade) e eles têm prioridade so- nativa a técnicas mais tradicionais na
bre informações declaradas por anotações. programação OO, como herança ou 1
Plain Old Java Objects, algo como “bons e velhos obje-
Isso evita que as anotações eliminem a design patterns. O J2EE tradicional, tos Java”. É uma definição por exclusão: objeto s que não
flexibilidade garantida pelos descritores. como sabemos, é fortemente baseado em são obrigados a herdar/implementar nenhuma interface
Por exemplo, numa classe persistente você herança. Um Entity Bean, por exemplo, é imposta por uma API. Também se usa POJI para interfaces
que não precisam herdar nenhuma outra interface. Um
pode usar uma anotação @Table(name=”TAB”) uma classe que implementa a interface framework que suporta POJOs, no lugar de herança, uti-
para determinar que os objetos da classe javax.ejb.EntityBean, o que obriga a definir liza mecanismos mais fracamente acoplados, como ano-
serão persistidos na tabela “TAB”. Isso é sete métodos (como ejbActivate() , ejbLoad() tações ou arquivos de configuração, para interagir com
seus objetos.
muito conveniente, mas o que acontece se etc.), que na sua maioria são desneces- 2
A exceção fica por conta de casos simplistas como os
um dia o nome da tabela t iver que mudar? sários para a maior parte dos beans. Há listeners da AWT/Swing, ex.: MouseListener, acompanhados
No J2EE tradicional (EJB/CMP), bastaria certamente algo errado numa arquitetura por classes “adapter”, como MouseAdapter, que facilitam a
criação de inner classes que implementam somente um
alterar o descritor. No Java EE 5 podería- que obriga as aplicações a definir até sete dos métodos exigidos por listeners que agrupam vários
mos alterar a anotação @Table,mas isto não métodos vazios para cada entidade de eventos. Como tratadores de eventos são simples e rara-
é obrigatório. Podemos também criar um negócio. (Lembrando que em Java, nem mente se beneficiariam de herança de implementação,
nestes casos não faz mal usar a herança única para deri-
descritor e informar nele o nome atuali- sempre é uma boa idéia usar classes-base var do adapter. O mesmo não pode ser dito de EJBs que
zado da tabela. No caso de redundância que forneçam implementações default implementam complexas regras de negócio.
l
GlassFish:
para o GlassFish, utilizando o plug-in disponível
em glassfishplugins.dev.java.net , mas o WTP (e
a
versões anteriores do NetBeans) ainda não possui
i
suporte específico para o Java EE 5.
O NetBeans pode ser baixado numa versão que
r O Java EE 5
já inclui o servido r Java EE, que desta forma é pré-
configurado na instalação, ou se pode instalar o
Glassfish à parte. Neste caso, será preciso ir em
o
Tools > Server Manager > Add Server e criar um novo
t
ver, entrando com seus parâmetros de instalação
(diretório, login de administrador etc.). (Este mes-
uO
Java EE 5 é um padrão formal do JCP, e logo terá muitas implementações mo tipo de servidor funciona com o Java EE SDK
concorrentes. Mas vale a pena dar uma atenção privilegiada para uma 5.0 / SJSAS 9 e com o Glassfish; par a simplificar, nos
destas implementações, o projeto GlassFish. Trata-se do mais novo servidor referiremos ao servidor como apenas “GlassFish”.)
T
Java EE 5 de fonte aberto. Aliás, o único por ora, já que o JBoss, apesar do pioneirismo Agora vá na janela Runtime do NetBeans e, sob
com o EJB 3.0, ainda não parece perto de finalizar o suporte para a Java EE 5 como Servers , encontre o servidor GlassFish e comande
um todo, e o Geronimo provavelmente demorará muito mais. Start in Debug Mode .
O GlassFish foi baseado em código doado pela Sun, sendo a base Em File | New Project , selecione Enterprise / Enter-
do Sun Java System Application Server 9 (também conhecido prise App lication na primeira página, e preencha
como Java EE SDK 5), que é a implementação de referência (RI) a segunda conforme a Figura Q1 (modificando
do Java EE 5. Tanto a versão open source quanto a da Sun são é claro os drives e diretórios), selecionando o
certificadas. O GlassFish vem sendo desenvolvido como um GlassFish e criando um módulo EJB e um módulo
projeto do portal java.net, onde já angariou bastante suporte web. O NetBeans criará três projetos, para os mó-
da comunidade open source. Resta saber se isso se traduzirá em dulos EJB, WAR e EAR.
ganhos significativos de mercado para es te servidor, que até hoje, a No projeto EJB, acione New > Session Bean, e crie
despeito da liderança da Sun no desenvolvimento da tecnologia J2EE / um EJB com nome “Alo”, tipo Stateless e interface
Java EE e fortes resultados recentes de benchmarks SPEC jAppServer apenas Remote. O assistente irá criar os fontes da
2004, tem amargado pouca popularidade, apesar de gratuito para interface AloRemote e da implementação AloBean.
uso comercial (um apelo que se mostrou insuficiente, já que o Após customizarmos estes fontes, eles deverão
JBoss é tanto gratuito quanto open source). ficar como nas Listagens Q1 e Q2 .
Examinando o projeto, você verá que temos
Testando o Java EE 5 com o Glassfish apenas estes dois arquivos .java , e além disso
Para exercitar um pouco os novos recursos do Java dois descritores – sun-ejb-jar.xml e MANIFEST.MF .
EE 5 apresentados neste artigo, veremos uma apli- Mas ambos estão vazios; foram criados apenas
cação “alô mundo” de duas camadas, com uma por conveniência. Apague estes dois arquivos do
interface web JSF que invoca um Session Bean projeto, para comprovar o que dissemos sobre
– executando no GlassFish. serem opcionais.
Para este exercício, utilizare mos o IDE No projeto do EAR, acione Deploy Project . O
NetBeans 5.5. Usuários do Eclipse 3.2 / NetBeans irá executar a compilação dos módulos
WTP 1.5 também podem desenvolver dependentes, o empacotamento do EAR, e sua
Listagem Q2.Implementação do stateless session bean “Alo”. Listagem Q4.Página de teste da JSF.
É para resolver esses problemas que priedades, permitindo escolher a interface ponentizada (neste caso, a ID configura
surgiram design patterns como o Service local ou remota, ou o nome lógico ( java: referências para EJBs ou web services).
Locator, que já comentamos. Estes patterns comp/env ) ou o nome proprietário do con- Já framework s esp ecial izados como o
reduzem o problema – podemos ter todos tainer EJB (mapped name). Spring incentivam e permitem o uso de
os lookups de EJBs numa única classe, e •Há anotações para interagir com o ID intenso, de alta granularidade. Neste
não em dezenas de classes Action – mas ciclo de vida do objeto sujeito à Injeção estilo, praticamente nenhum recurso é
não eliminam o problema totalmente. de Dependências. Por exemplo, poderí- inicializado em código, coisa que para
A solução definitiva é proposta pelo amos criar um método com a anotação alguns desenvolvedores parece ser uma
sistema de Injeção de Dependências, cuja @InjectionComplete , que seria então invocado maravilha e para outros um excesso ou
implementação no Java EE 5 nos permite uma única vez, após a inicialização de abuso da técnica. Assim, podemos arriscar
escrever código como o da Listagem 2, todos os recursos que usam Injeção de que o Java EE 5 satisfará às necessidades de
na qual foram destacadas as mudanças Dependências na sua classe. ID da maioria dos desenvolvedores, mas
em relação à versão anterior. Observe que os adeptos mais radicais da técnica terão
não precisamos mais nos preocupar com A Injeção de Dependências no Java EE 5 que avaliar se preferem continuar usa ndo
JNDI, lookup, exceções, interfaces Home, Quem já conhece a Injeção de Depen- algo como o Spring4, ou se preferem “mo-
conversões de interfaces remotas, ou mes- dências em frameworks como Spring, derar” para ter os benefícios de escrever
mo otimizações para reduzir os lookups. PicoContainer e outros, poderá se pergun- aplicações “puro-Java EE”.
Só precisamos declarar uma variável (local tar se o suporte a ID do Java EE 5 é melhor
ou atributo) que seja do tipo da interface ou pior. As anotações de ID utilizadas Os componentes do Java EE 5
de Session Bean desejada, e complementar pelo Java EE 5, especif icadas pela JSR-250 Nada menos que 21 JSRs separadas, que
esta declaração com a anotação @EJB. Esta (Anotações Comuns para a Plataforma podemos ver na Tabela 1, contribuem
anotação é simples: basta informar o nome Java), são também incluídas no Java SE diretamente para o Java EE 5. Novas fun-
JNDI do bean desejado, e o runtime de ID 6. Isso abre a possibilidade de melhorias cionalidades são poucas, mas importantes:
faz o resto. de APIs fundamentais e até otimizações a Java Persistence API (que sucede os EJB/
O código resultante é muito menor. Até da JVM, para tirar proveito da Injeção de CMP) é a única API totalmente nova. Além
mesmo o método doLogin() foi simplificado. Dependências, ou torná-la mais eficiente disso, temos a incorporação de APIs ante-
O funcionamento básico da ID é simples: e poderosa. riormente independentes, como a StAX e
quando o artefato que contém a dependên- Por outro lado, sistemas de ID mais ma- a JAXB, e atualizações de muitas outras. A
cia (no caso, a LoginAction3) for criado, o con- duros como o Spring são mais poderosos. mudança mais sensível ao programador,
tainer fará o lookup, a invocação do create() Por exemplo, o Spring pode “injetar” ob- que é a introdução de anotações para faci-
etc. Se o lookup falhar, ocorrerá um erro jetos arbitrários com construção complexa litar o uso de muitas APIs, dá uma “cara”
impedindo a inicialização da Action, e este (algo que pode exigir arquivos XML bem de novidade, mas por si só não cria novas
erro será tratado pelo framework web. grandes...), enquanto o mecanismo do Java funcionalidades – só permite fazer com
Existem variantes neste comportamento, EE 5 é mais orientado a objetos publicados anotações as mesmas coisas que podíamos
que recuperam muito da flexibilidade que na JNDI. Entretanto, a nova especificação e continuamos podendo fazer invocando
você poderia imaginar ter perdido na tran- torna obsoletos os sistemas anteriores de as APIs tradicionais.
sição da Listagem 1 para a Listagem 2 : ID, pelo menos para as funcionalidades Versões do Java EE e SE sempre compar-
•Ao invés de anotar com @EJB o atributo em comum. tilham algumas novas APIs, e cada versão
loginServer, poderíamos utilizar esta anota- Uma maneira de ver essa diferença é que do Java EE depende da versão anterior
ção num setter ( setLoginServer(LoginServer)), a JSR-250 oferece um suporte a ID menos mais recente do Java SE, ambas tradicional-
que seria invocado pelo container. Isto nos radical, mais orientado ao desacoplamento mente compartilhando o mesmo número.
daria maior grau de controle sobre sua entre código de aplicação e recursos de O Java EE 5 depende do Java SE 5. Mas as
inicialização. deployment (como DataSources, filas etc.), versões subseqüentes do Java SE sempre
•A anotação @EJB suporta outras pro- e entre módulos numa arquitetura com- incorporam algumas APIs introduzidas
inicialmente no Java EE. O Mustang ( Java
SE 6) é um exemplo disso, integrando as
Listagem 2.Injeção de Dependências no Java EE 5.
de aplicações (ex.: uma mensagem SOAP Aproveite para observar, neste exemplo de um novo projeto que precisa de persistência
chega num Message-Driven Bean, onde é concreto, outras simplificações do EJB objeto-relacional, recomendo pensar bem antes
automaticamente mapeada, verificações 3.0 que já mencionamos: nada de inter- de decidir usar os já obsoletos Entity Beans, seja
de segurança são feitas, uma transação faces Home, nem exceções RemoteException com BMP ou com CMP.
XA é criada etc.). (mesmo ao usar a interface remota), nem
Este artigo não teria espaço para tratar herança de interfaces do framework, e
igualmente todas as funcionalidades do como veremos, um empacotamento mais Qual é a relevância da JPA para os adep-
Java EE 5, mas basta dizer aqui que outros simples. tos de outras soluções (não-EJB) de persis-
recursos do EJB também são “envenena- tência? Nenhum sistema O/R será ideal
dos” por Injeção de Dependências e por As especificações CMP e CMR são agora desa- para todas as aplicações e a concorrência
anotações como @SecurityRoles, @Interceptor , provadas (deprecated); não haverá mais evolução deve continuar existindo, mas creio que a
@MessageDriven etc. destas tecnologias, e implementações futuras (tal- JPA tende a se impor como um forte pa-
vez a partir do Java EE 6) não terão que suportá-las drão, ao unificar o status de API oficial do
A Java Persistence API (JPA) para obter certificação. Note que o pacote javax.ejb Java EE 5 com qualidades de facilidade de
Qual é a nova prática recomendada para define anotações para Session Beans ( @Stateful e uso e compatibilidade com o Java SE (antes
aplicações Java EE que acessam bancos de @Stateless ) e MDBs ( @MessageDriven ), mas nenhuma exclusividades do JDO, Hibernate e outras
dados? A mesma que muita gente, fugin- anotação para Entity Beans. A minha interpreta- soluções). Até mesmo a API do popular
do dos Entity Beans, já vinha praticando ção é que além dos CMPs, os próprios Entity Beans Hibernate deve perder terreno; o projeto já
há anos: usar só Session Beans (para a estão “marcados para morrer” num release futuro oferece uma implementação (hoje em beta)
comunicação remota, controle de transa- do Java EE. Alguns podem ficar confusos, pois a da Persistence API, o Hibernate Entity
ções, segurança etc.), criar uma camada Persistence API possui uma anotação @Entity que Manager (HEM). O HEM é uma “casca”
de POJOs para as entidades, e persisti-los denota entidades persistentes; mas esta anota- que implementa a nova API padronizada
com uma ferramenta como o Hiber nate. A ção não tem qualquer relação com Entity Beans. pela JSR-220, mas que possui no núcleo o
diferença é que agora você pode substituir Resumindo, se você está na fase de prospecção runtime tradicional do Hibernate 5. Pode
a API do Hibernate pela JPA, que funciona
da mesma maneira, mas é um padrão do
Java EE. E pode esquecer dos DAOs, pois Listagem 3.Uma aplicação EJB 3.0 completa, com persistência e Session Bean.
a persistência direta de POJOs dispensa
// Entidade persistente simples
códigos de conversão de/para objetos
exigidos pela persistência, e o código de import
import
java.io.Serializable;
javax.persistence.Entity;
persistência que você terá que escrever é import javax.persistence.GeneratedValue;
tão pouco que não justifica encapsulá-los import javax.persistence.GenerationType;
import javax.persistence.Id;
numa camada de DAOs.
@Entity public class Usuario implements Serializable {
A Listagem 3 apresenta um exemplo private Long id;
completo de EJB 3.0 e da Persistence API. private String nome;
private String senha;
O código é simples, e além disso familiar @Id @GeneratedValue(strategy=GenerationType.AUTO)
para quem já usou o Hibernate. A classe public Long getId () { return id; }
public void setId (Long id) { this.id = id; }
EntityManager faz as vezes da classe Session public String getNome () { return nome; }
do Hibernate, sendo até mais fácil de usar public void setNome (String nome) { this.nome = nome; }
public String getSenha() { return senha; }
– não precisamos implementar uma Fac- public void setSenha (String senha) { this.senha = senha; }
tory para ler a configuração, instanciar a }
Session, garantir que cada thread use sem- // Interface remota do Session Bean
pre a mesma Session etc. São as vantagens import javax.ejb.Remote;
da integração com o container Java EE, e
@Remote public interface LoginServer {
é claro, da Injeção de Dependências. Note Usuario find (Long id);
que o método EntityManager.find() é genérico, }
retornando o objeto já com o tipo correto, o // Session Bean que utiliza a entidade persistente
que dispensa o typecast que precisaríamos
import javax.ejb.Stateless;
com o Session.get() do Hibernate. import javax.persistence.EntityManager;
O código da Listagem 3 só não constitui import javax.persistence.PersistenceContext;
uma aplicação completa porque também @Stateless public class LoginServerBean implements LoginServer {
precisamos de um descritor de “unidade @PersistenceContext EntityManager em;
public Usuario find (Long id) {
de persistência” ( persistence.xml). Bastaria return em.find(Usuario.class, id);
então reunir estas classes e o descritor num }
}
arquivo .ear, e instalá-lo no container.
ser usado em qualquer servidor Java EE JavaServer Faces runtime portável da JAXB 2.0; e é claro,
5 que suporte EJB 3.0 6 e até sem servidor A inclusão da JSF 1.2 é a única grande facilidade de programação com anotações
algum, em aplicações Java SE 5. novidade de funcionalidade do Java EE 5 7. e suporte a POJOs.
Este anúncio de “grande novidade” pode Quanto aos web services, seu principal
Empacotamento parecer uma surpresa para os já adeptos atrativo sobre soluções mais maduras
Uma das melhorias de facilidade de da JSF, comumente utilizada em servidores e eficientes – segundo as más línguas,
uso mais discretas do Java EE 5, mas nem J2EE 1.4. Mas o fato é que até então, nenhu- qualquer outra coisa – sempre foi a inte-
por isso pouco importante, está nos seus ma versão da JSF fez parte, oficialmente, da roperabilidade. Um importante anúncio
padrões de pacotes para deployment, os plataforma J2EE (a JSF 1.0, JSR-127 (março no JavaOne 2006 foi o Projeto Tango 8, um
arquivos EAR, WAR e outros, que tradicio- de 2004) é posterior à J2EE 1.4 (novembro esforço conjunto da Sun e da Microsoft
nalmente exigiam uma estrutura bastante de 2003)). para alinhar as implementações de web
complexa. Mas isto talvez tenha sido bom, pois a services – de um lado, as APIs do Java Web
A estrutura básica continua existindo. JSF é uma tecnologia complexa que teve Services Developer Pack (JWSDP) e do Java
Por exemplo, uma “enterprise application” um período relativamente longo de ama- EE 5; do outro, o Windows Communication
continua sendo empacotada num arquivo durecimento – de reclamações sobre o de- Framework (parte do .NET 3.0). O projeto
EAR, dentro do qual pode-se ter arquivos sempenho das primeiras implementações, Tango foi focado não só na interoperabili-
JAR com os EJBs, um folder META-INF com a trapalhadas como problemas de compati- dade, mas também em eficiência, facilidade
descritores e assim por diante. As melhorias bilidade com as especificações JSP e EL, que de uso, segurança, suporte a transações e
são duas. Primeiro, os descritores tendem a só recentemente foram resolvidos. Assim, outras características.
ser bem menores (e até opcionais), graças pode ser uma boa coisa que somente agora, Pode parecer estranho que uma tecnolo-
ao novo modelo de anotações + POJOs + já na sua terceira revisão e com muitas des- gia criada sob medida para a interopera-
defaults. Segundo, não é mais preciso decla- sas “dores de crescimento” superadas, a JSF bilidade, baixo acoplamento etc., precise
rar obviedades ou informar a mesma coisa tenha sido integrada ao complexo conjunto de esforços contínuos para funcionar
duas vezes – o Java EE aprendeu a seguir o de especificações e tecnologias que forma a corretamente entre as duas principais pla-
princípio DRY (don’t repeat yourself ). plataforma Java EE. taformas de mercado que a implementam.
Um bom exemplo disso é a configuração A JSF é um framework orientado a com- Mas o problema é que as especificações de
de JARs utilitários, que são colocados na ponentes para geração de GUIs web. Isto se web services continuam se multiplicando e
pasta /lib de um EAR, mas antigamente insere melhor na arquitetura geral do Java evoluindo a uma velocidade tão grande que
isso não era suficiente: era preciso declarar EE, que já possui modelos de componentes as implementações estão sempre correndo
todos os JARs no META-INF/MANIFEST. para regras de negócio, serviços, integra- atrás, e tendo que corrigir dificuldades cau-
MF, na diretiva Classpath. Agora nada disso ção com recursos e sistemas externos etc. sadas por bugs de implementação ou por
é necessário – o container irá detectar todos Faltava suportar o mesmo paradigma no especificação insuficiente. Para mais sobre
os arquivos lib/*.jar e incluí-los no classpath lado do cliente, até então servido apenas o assunto, veja meu artigo “Web services e
do módulo EAR. por opções “força-bruta” (Servlets) ou de SOA”, na Edição 34.
Aplicações web (WAR) que usem somente templates (JSP – mesmo com extensões
JSP e tecnologias relacionadas como JSTL, como EL, JSTL, Struts etc.). Por “orientado Conclusões
mas não servlets, não precisam de nenhum a componentes” queremos dizer que a JSF Neste artigo demos as primeiras pince-
descritor (WEB-INF/web.xml). O mesmo permite construir GUIs através da compo- ladas no Java EE 5, a plataforma que todos
vale para WARs expondo web services (não sição de objetos e (em se tratando de GUI) usaremos em algum ponto para aplicações
precisam mais de um webservices.xml , nem do tratamento de eventos gerados por estes
de arquivos da JAX-RPC). objetos. Um benefício desta arquitetura é a 5
A API proprietária do Hibernate possui algumas funcio-
Além disso, os EARs não precisam mais separação entre o comportamento da GUI nalidades que ainda não existem na JPA (como as queries
“Criteria”), mas isso só afeta usuários mais avançados. A
do application.xml. Os application clients e a sua apresentação. Outro é a facilidade maioria pode migrar facilmente para a JPA, ganhando
também dispensam o application-client.xml; para a construção de ferramentas pura- com isso as vantagens de padrões do Java EE, como im-
basta ter no META-INF/MANIFEST.MF o mente visuais. plementações concorrentes, maior suporte de IDEs etc.
6
É o caso do JBoss 4.0, cujos últimos releases (compatí-
Main-Class apontando para a classe princi- veis com o J2EE 1.4) suportam também o EJB 3.0, embora
pal da aplicação. Finalmente, módulos EJB Web services e XML: JAXB 2.0, JAX-WS 2.0, StAX o JBoss ainda não possua (no momento em que escrevo)
também não precisam obrigatoriamente do O Java EE 5 incorpora uma segunda gera- uma versão que suporte a plataforma Java EE como um
todo.
ejb-jar.xml, bastando que o arquivo JAR do ção de APIs para web services, integradas 7
A JPA é uma nova API , mas não uma nova funcionali-
módulo possua anotações como @Stateless. inicialmente ao J2EE 1.4. Não há novidades dade (a não ser qualitativamente), já que as versões an-
Tudo isso não quer dizer que os descrito- revolucionárias, mas temos muitas atuali- teriores do J2EE já suportavam persistência O/R com os
Entity Beans.
res tenham desaparecido completamente. zações no suporte às últimas especificações 8
O codinome “Tango” é específico ao lado da Sun do
Continuam sendo suportados, e às vezes do W3C, WS-I e OASIS. Melhorias de de- projeto, e achei ótimo. Afinal, o Tango é uma dança lenta,
podem ser necessários. A diferença é que sempenho críticas, como o suporte a StAX formal e sombria, e das mais difíceis de executar sem es-
corregar para o ridículo (pelo menos no estereótipo que
agora, só é preciso criar descritores quando e Fast Infoset (codificação binária de XML); aprendi no cinema: ver Quanto Mais Quente Melhor com
são realmente necessários. aperfeiçoamentos de arquitetura, como o Jack Lemmon, e O Baile de Ettore Scola).
jcp.org/en/jsr/detail?id=244
JSR-244, padrão do JCP que define a
plataforma JEE 5.
java.sun.com/javaee
JEESDK 5 / Sun Java System Application Server 9.
glassfish.dev.java.net
Projeto GlassFish.
javamagazine.com.br/downloads/jm39/
jm-jee5.zip
ANDRÉ DANTAS ROCHA E SÉRGIO OLIVEIRA K UBOTA
possuir uma forma distinta de efetuar o mapeamento O/R, os Um conjunto de ferramentas para
•
Para que uma entidade se torne persisten- Grande parte da produtividade trazida uma alternativa ao SQL, que também é
te é necessário associá-la a um persistence pela JPA deve-se à utilização de valores suportado. As consultas suportam poli-
context (contexto de persistência), que default de mapeamento, que facilitam morfismo, o que significa que quando uma
fornece a conexão entre as instâncias e bast ante o trabalho do desenvolvedor. entidade é consultada, todas as entidades
o banco de dados. A manipulação das Assim, o que não é definido explicitamente descendentes que atendam ao critério da
entidades é feita, a partir desse contexto, assume a configuração padrão da API. Por consulta também são retornadas. A criação
por meio do entity manager (gerenciador exemplo, por padrão a JPA considera o de consultas é feita através do EntityManager,
de entidades), que é responsável por nome da entidade o mesmo nome da tabela que fornece métodos específicos para
executar as operações básicas sobre a no banco de dados e o nome da proprie- instanciar consultas estáticas e dinâmicas,
entidade (criação, atualização, exclusão, dade o mesmo nome da coluna. No código além de permitir a execução das operações
localização, consultas etc.). O entity ma- anterior, a entidade Pessoa será salva na CRUD5.
nager na JPA é uma instância da interface tabela PESSOA e a propriedade cpf na coluna As consultas estáticas possuem nomes e
javax.persistence.EntityManager. CPF. Caso seja necessár io alterar a forma de são descritas pela anotação @NamedQuery.
A implementação da JPA é feita por um mapeamento, devem-se utilizar as anota- Elas são definidas nas entidades corres-
persistence provider (provedor de persistên- ções @Table e @Column, por exemplo: pondentes e ficam “pré-compiladas”. Veja
cia). O provedor define “como as coisas um exemplo de consulta estática para
funcionam”, através da implementação de @Entity localizar uma pessoa pelo seu CPF:
@Table(name=”TB_PESSOA”)
todas as interfaces definidas pela especifi- public class Pessoa {
cação da JPA. Dessa forma, cada provedor @Id @NamedQuery(name = “consultarPorCPF”,
decide a maneira e o momento de carre- @Column(name=”DS_CPF)” query = “SELECT p FROM Pessoa p WHERE p.cpf = :cpf”)
private String cpf;
gar, atualizar e armazenar as entidades, }
assim como sincronizar os dados com o O EntityManager utiliza o nome da consul-
banco. As configurações utilizadas pelo Outro padrão utilizado pelo JPA é con- ta para instanciá-la, o que é feito através
provedor em uma determinada aplicação siderar todas as propriedades de uma en- do método createNamedQuery(). Depois que
(conexão com o banco de dados, entidades tidade como persistentes (o mapeamento a consulta é criada, basta setar os parâ-
que serão gerenciadas, tipo de transação segue as regras descritas anteriormente). metros e executá-la. A execução pode
etc.) são descritas em uma persistence unit, Caso seja desejável excluir alguma pro- ser feita pelos métodos getSingleResult()
que é configurada num arquivo especial priedade do mapeamento (ex.: no caso ou getResultList(), a depender do resultado
denominado persistence.xml. de ela poder ser criada a partir de outras esperado. Por exemplo, para localizar uma
propriedades), basta marcá-la com a ano- pessoa pelo CPF (supondo que o retorno
Mapeamento tação @Transient : será único), basta executar a consulta con-
As classes e interfaces da JPA estão forme o exemplo abaixo:
localizadas no pacote javax .persiste nce. A @Entity
public class Pessoa { Query consulta =
API faz uso intensivo de anotações 3; por @Id manager.createNamedQuery(“consultarPorCPF”);
isso não é necessário criar descritores private String cpf; consulta.s etParameter (“cpf”, “111.111.111-11”);
XML para cada uma das entidades da @Transient Pessoa pessoa = consulta.getSingleResult();
private String nomeCompleto;
aplicação4. Uma entidade é uma classe }
Java comum, rotulada através da anota- As consultas dinâmicas não possuem
ção @Entity. Não é preciso implementar Os dados de uma única entidade po- nome, e podem ser construídas em tem-
interfaces ou estender outras classes dem estar distribuídos em mais de uma po de execução. A criação desse tipo
para tornar uma classe “persistível”; a tabela, e diversos tipos de relacionamen- de consulta é feito através do método
única exigência é que a classe da entidade tos entre entidades são possíveis. Os createQuery() :
possua um construtor sem parâmetros, mais comuns são os de agregação (ano-
pois a instanciação da classe é feita por tações @OneToOne, @OneToMany, @ManyToOne, Query consulta = manager.createQuery(
“SELECT p FROM Pessoa p WHERE p.cpf = :cpf”);
reflexão. @ManyToMany, etc.) e herança (anotação
No código a seguir a classe Pessoa re- @Inheritance ), que serão vistos mais adiante.
presenta uma entidade. O atributo cpf é o 3
As anotações surgiram da versão 5.0 do Java e estão
presentes na maioria das APIs do novo JEE.
identificador da entidade (chave primária), Consultas 4
Mesmo não sendo obrigatório o uso de XML para
especificado através da anotação @Id : A JPA oferece suporte a consultas es- descrever o mapeamento, ainda é possível utilizar essa
táticas e dinâmicas. A API fornece uma opção. Um exemplo típico é o arquivo persistence.xml ,
@Entity linguagem própria de consulta, que é que guarda as configurações da unidade de persistência
public class Pessoa { e é utilizado neste artigo.
uma extensão bastante poderosa da EJB
@Id 5
As principais operações executadas sobre dados são
private String cpf; QL (a linguagem de consultas do EJB). conhecidas através da sigla CRUD ( Create, Read, Update,
} Essa linguagem pode ser usada como e Delete).
O mapeamento das propriedades nome que define se a propriedade em questão A propriedade reservas é um pouco mais
e endereco é muito simples. Ambas as pro- pode ser nula: complexa, pois ela determina um rela-
priedades possuem a anotação @Column, cionamento um-para-muitos. No nosso
contendo dois atributos: name, que define a @Column(name = “DS_NOME”, nullable = false) modelo, um cliente pode estar relacionado
coluna correspondente no banco; e nullable, private String nome; a diversas reservas, sendo que cada reserva
relaciona-se a um único cliente.
A anotação @OneToMany é usada para
indicar o relacionamento entre as enti-
Veiculo
{ From model } Reserva Cliente
dades (um cliente para muitas reservas).
Attributes
{ From model } { From locadora } As reservas do cliente são armazenadas
private String placa veiculo Attributes
cliente Attributes na propriedade reservas (uma lista de
private String modelo
private Integer ano
private String codigo
private Date inicio
private String codigo
private String nome
instâncias da entidade Reserva), que é po-
private String cor private Date fim private String endereco pulada automaticamente pelo TopLink.
private Double diaria Dois atributos da anotação são utilizados
reserva nesse mapeamento: cascade = CascadeType.ALL
indica que alterações na entidade Cliente
Esportivo Utilitario Locacao serão refletidas automaticamente nas
{ From model } { From model } { From model } entidades Reserva relacionadas. O atributo
Attributes Attributes Attributes mappedBy = “cliente” indica que na classe
private Integer velocidade private Integer passageiros private Integer codigo
Reserva existe uma propriedade denomi-
nada cliente, que mapeia o cliente do rela-
Figura 1. Diagrama de classes do sistema de locação de veículos. cionamento (veremos mais sobre a classe
Reserva adiante).
@OneToMany(cascade =
CascadeType.ALL, mappedBy = “cliente”)
private List<Reserva> reservas;
Mapeamento do veículo
Na modelagem OO da aplicação decidi-
mos especializar a classe Veiculo, guardan-
do as particularidades de cada veículo em
classes específicas (veja a Figura 1). Veiculo
é uma classe abstrata, que possui duas
Figura 2. Modelo Entidade-Relacionamento para o sistema de locação de veículos. subclasses: Esportivo e Utilitario.
No modelo relacional a abordagem foi
distinta. Para evitar o custo de joins, to-
Listagem 1.Cliente.java
dos os veículos foram mapeados em uma
package br.com.jm.locadora.model; única tabela, que contém propriedades
import java.util.List; tanto genéricas quanto específicas. Como
import javax.persistence.*; veremos a seguir, o nosso mapeamento
@Entity deve contemplar essa decisão arquitetural
public class Cliente { e permitir que os objetos sejam instan-
@Id ciados corretamente (de acordo com sua
@Column(nam e = “CD_CLIENTE”)
@GeneratedValue(strategy = GenerationType.IDENTITY)
classe), mesmo com todos residindo em
private Integer codigo; uma tabela genérica.
@Column(nam e = “DS_NOME”, nullable = false)
Vamos analisar o código da entidade
private String nome; Veiculo (Listagem 2). Como já conhecemos
@Column(nam e = “DS_ENDERECO” , nullable = false) as anotações @Entity, @Id e @Column, veremos
private String endereco; apenas as novas construções.
@OneToMany( cascade = CascadeType .ALL, mappedBy = “cliente”) O mapeamento da herança de entidades
private List<Reserva> reservas; é descrito através da anotação @Inheritance,
// ... gets e sets omitidos que define a estratégia usada no mape-
} amento. De forma semelhante a outros
Listagem 5.Reserva.java
package br.com.jm.locadora.model;
import java.util.Date;
import javax.persistence.*;
@Entity
@NamedQueries({
@NamedQuery( name = “Reserva.lis tarPorPeriodo ”,
query = “SELECT r FROM Reserva r WHERE “ +
“r.inicio >= :inicio AND r.fim <= :fim”),
@NamedQuery(name = “Reserva.ultima”,
query = “SELECT r FROM Reserva r WHERE r.codigo = “ +
“(SELECT MAX(r1.codigo ) FROM Reserva r1)”)
})
public class Reserva {
@Id
@Column(name = “CD_RESERVA”)
@GeneratedVa lue(strategy = GenerationTy pe.IDENTITY)
private Integer codigo;
@ManyToOne
@JoinColumn( name = “CD_CLIENTE” , nullable = false)
private Cliente cliente;
@ManyToOne
@JoinColumn( name = “DS_PLACA”, nullable = false)
private Veiculo veiculo;
Listagem 6.Locacao.java
package br.com.jm.locadora.model;
import java.util.Date;
import javax.persistence.*;
@Entity
public class Locacao {
@Id
@Column(name = “CD_LOCACAO”)
@GeneratedVa lue(strategy = GenerationTy pe.IDENTITY)
private Integer codigo;
@OneToOne
@JoinColumn( name = “CD_RESERVA” )
private Reserva reserva;
<class>br.com.jm.locadora.model.Cliente</class>
Mapeamento da locação <class>br.com.jm.locadora.model.Reserva</class>
<class>br.com.jm.locadora.model.Locacao</class>
O mapeamento da entidade Locacao <class>br.com.jm.locadora.model.Veiculo</class>
(Listagem 6) é simples. Além das ano- <class>br.com.jm.locadora.model.Utilitario</class>
<class>br.com.jm.locadora.model.Esportivo</class>
tações @Id e @GeneratedValue abordadas
anteriormente, essa entidade apresenta <properties>
<property name=”topli nk.logging.le vel” value=”INFO ” />
um relacionamento um-para-um com <property name=”topli nk.jdbc.drive r” value=”com. mysql.jdbc.Dr iver” />
a entidade Reserva, pois uma locação só <property name=”topli nk.jdbc.url”
value=”jdbc:m ysql://127.0 .0.1:3306/loc adora” />
pode existir para uma reserva criada <property name=”topli nk.jdbc.user” value=”root ” />
<property name=”toplink.jdbc.password” value=”” />
anteriormente. </properties>
O relacionamento é descrito pela anotação
</persistence-unit>
@OneToOne, e possui uma sintaxe semelhante </persistence>
à de um mapeamento um-para-muitos:
o Goo
Google
gle Web Toolkit
ARI DIAS NETO
sua utilização. Para uma introdução ao • A tabela terá campos editáveis, sensí- • br.com.jm.gwt.server – Onde estarão a
GWT,, sua API básica e a estrutura
GWT estrutu ra utiliza- veis a cliques do mouse e à tecla Enter. implementações dos serviços, como código
da para projetos, recomendo a leitura do • A persistência é feita de forma trans- de acesso a dados e classes de negócio.
artigo “Google Web Toolkit”
Toolkit” na Edição 38 parente: assim que o campo editável não • br.com.jm.gwt.public – Contendo imagens,
da Java Magazine. possuir mais o foco, os dados serão atua- arquivos CSS, páginas HTML etc.
lizados na base de dados, sem necessidade
Preparação de intervenção do usuário. Note que alguns arquivos também foram
Para a construção do exemplo, vamos • A caixa de diálogo pode ser fechada criados:
utilizar o IDE
I DE Eclipse com dois plug-ins:
plug-ins: tanto com o mouse como com o teclado •
public Button btnProxima = new Button(“> ”, this); correto do objeto Contato e persiste a altera- de explicarmos seu código, veremos uma
public Button btnAnterior = new Button(“&l t;”, this); ção através da fonte de dados. breve introdução sobre esses serviços.
Além disso, para saber qual registro foi O GWT já traz pronta uma infra-estru-
Assim que um dos botões é clicado, é selecionado, é mantido um mapeamento tura para trabalhar com RPCs ( Remote
chamado o método onClick(). Em seqü- interno entre as linhas da grade e os con- Procedure Calls ) facilitando a troca de
ência, o componente atualiza o atributo tatos exibidos. Assim, quando uma linha objetos Java entre o cliente (o browser)
paginaAtual, muda a mensagem do Label é selecionada, o objeto Contato correspon- e o servidor. Todas as chamadas são
para “Carregando...”, e chama o método dente também o é. assíncronas, logo a interface gráfica fica
setPagina() da fonte de dados.
Veja que a barra de navegação não possui Componente ListaContatos
referência ao componente TabelaEditavel , O componente ListaContatos , com código
interagindo apenas com a fonte de dados. mostrado na Listagem 9, reúne uma fonte
É a fonte de dados que é responsável por de dados (objeto FonteDeDados ) e um com-
atualizar os objetos conectados a ela. ponente TabelaEditavel. A fonte de dados
recebe o número de registros por página,
Componente TabelaEditavel e a tabela editável recebe os nomes das
O componente TabelaEditavel é o mais colunas, o número de registros por página
complexo que criaremos neste artigo. e a própria fonte de dados.
Veja seu código na Listagem 8. A estru-
tura interna do componente é construída Serviços no GWT
dentro de um DockPanel, com um compo- Para fazer acesso aos dados dos contatos
nente BarraNavegacao na posição NORTH, e um no banco, utilizaremos a classe FonteDeDados.
Grid (da API do GWT) no centro, onde serão Esta classe faz uso da infra-estrutura de
exibidos os dados dos contatos. serviços remotos do GWT, assim antes Figura 4. Configurando o serviço remoto
O construtor instancia a barra de navega-
ção já com uma fonte de dados, guarda o Listagem 9.ListaContatos.java: componente que reúne a tabela editável e a fonte de dados
número de registros por página, configura
public class ListaContatos extends Composite {
a própria instância como o listener do Grid
(para capturar os cliques sobre ele), e de- private TabelaEditavel tabelaEditavel;
private FonteDeDados fdContatos;
termina o layout dos componentes dentro
do DockPanel. public ListaContatos Widget(int nroRegistros Pagina) {
String[] nomesColuna s = new String[] { “”, “Nome”, “Telefone”, “Celular”,
O método onCellClicked() é chamado quan- “E-mail” };
do algum evento de clique ocorre na gra- this.fdConta tos = new FonteDeDados( nroRegistros Pagina);
this.tabelaE ditavel = new TabelaEditave l(fdContatos , nomesColunas,
de. Caso o clique tenha sido na primeira nroRegistrosPagina);
coluna, é mostrada uma caixa de diálogo setWidget(tabelaEditavel);
}
com o endereço do contato. Um clique nas }
outras colunas tornará a célula correspon-
dente editável. Listagem 10.ContatosService.java: interface de serviço
O método mostraDialogBox() instancia a package br.com.jm.gwt.client.service;
caixa de dialogo já com uma fotografia
e o endereço do contato configurados. //… imports
Complete
a sua 1
o
2
o
3
o
coleção!
ã ã ã
ç ç ç
i i i
d d d
E E E
- Java no Governo - Códigos no Eclipse - Tutorial de NetBeans - Eclipse para Web - Relatórios Corporativos
- Apache FOP - New I/O Fundamental - API New I/O (java.nio) - Fome Zero com Java - Gráficos com Java 2D
- JSTL – Guia Completo - Game API - Cesta de compras com Struts - Tags Customizadas em JSP 2.0 - Java.net na Prática
- Cocoon Inicial - Criando Plug-ins para Eclipse - Testes de carga com JMeter - Tiger: A Evolução do Java - Raio-X do Tiger
- Pacotes WAR e JAR - Preferences API - Concorrência e a JVM - Dicas para Web - Paginação na Web
9
1
o
ã
ç
0
2
o
ã
1
2
o
ã
ç
2
2
o
ã
ç
3
2
o
ã
ç
i ç i
i i
d i
d
d d
E d E E E
E
- Eclipse inicial - JBoss Inicial - Introdução ao Tomcat - Bancos de dados livres - JavaOne 2003
- O mercado J2ME - Introdução ao JMX - Conectivade com MIDP - Testes unitários com JUnit - Conhecendo o CVS
- Segurança em aplicações web - Java no Lego Mindstorms - Struts, primeiros passos - JSTL- Guia Completo: tags Core - JSTL- Guia completo SQL e Format
- Interfaces ricas com Flash - Logging - Automação com XDoclet - Java na Droga Raia - Tomcat e o Servidor Apache
- Expressões regulares no J2SE 1.4 - Memória e desempenho - Jakarta Velocity - Validação na Web
Java 5 Impressão Java Content Repository Caches e JDBC NetBeans JavaOne
• • • •
•
Imprimindo com Java
ConheçaduasAPIsdeimpressãodo
J2SEeobtenhacontrolefino
sobrelayouteformatação
Gerência deConteúdo
Edição24-AnoIII-R$9,90 DetalhessobreaNovíssimaAPI
JCRea CriaçãodeRepositórios
deConteúdonaWeb
Uma Aplicação Java Tira-Dúvidas Especial
CacheseDAOscomJDBC, Usando
Completa com NetBeans
Partefinal–Acessoa Banco
JVMsAlternativas,Relatóriose
DriblandoRestrições
deDadoseGerênciade
PreferênciasdeUsuários
daMáquina
Java:
Futuro
Presente
4
5 6 7
& 8
2
2 2 2 JavaOne 2005 2
o Grandesnovidadesem
ã o o o produtoseAPIs,planose Migrando para o Java 5 o
ç ã ã ã comemoraçõesno evento Conheça na prática eem detalhes ã
i ç ç ç mundialda tecnologia Java como,porquee quando fazero ç
i i i i
d upgradepara o J2SE 5.0
E d d d d
E E E E
- Novo NetBeans - Aplicação Completa - Parte 1 - Aplicação Completa - Parte 2 - Aplicação Completa - Parte 3 - Hibernate Fundamental
- Máquinas virtuais alternativas - Desempenho com JDBC e DAOs - Mais Desempenho com JDBC - Migrando para o Java 5 - Apache Geronimo na Web
- Gráficos com JFreeChart - Portlets - Fundamentos - Portlets - Recursos Avançados - Impress ão com Java - Ajax: Interatividade Turbinada
- SuperWaba Inicial - JFreeChart Avançado - Jakarta Commons Inicial - Gerenciamento de Conteúdo - Tutorial de Genéricos
- Tag Files do JSP 2.0 - O Novo Extreme P rogramming - Números: Conceitos e Formatação - JavaOne 2005 - De Volta aos Patterns
4
3
5
3
6
3
7
3
Leia uma vez,
o
ã
ç
i
o
ã
ç
i
o
ã
ç
i
o
ã
ç
i
use em todos
d
E
d
E
d
E
d
E os lugares
- Para onde vai o Struts - Frameworks de Logging - Conhecendo o Ant - Criação de Plug-ins
- Teste com J2MEUnit - Otimização de Código - Acessando Código Nativo - Os 10 Mais do Eclipse 3.2
- Web Services - Ajuda com JavaHelp - Qualidade Aplicada - JavaOne 2006
- Scripting na JVM - Maven 2 Essencial - Migrando para o Maven 2 - Relatórios Passo a Passo
- Aspectos no Mundo Real - Java ME no Eclipse - Logging no Java SE - Testes com mock objects
livre para eventuais mudanças enquanto Para criar um serviço remoto no GWT te- da API do GWT.
os dados não chegam. Isso aumenta a mos que definir uma interface de serviço, Outra interface também deve ser criada: a
performance da aplicação e faz com que na qual são escritos os métodos a serem interface assíncrona. Seus métodos serão os
se consiga paralelismo mesmo sem usar expostos. A implementação dos métodos mesmos da interface de serviço, porém terão
múltiplos threads – já que uma parte do fica a cargo de uma classe que será exe- um parâmetro a mais: um objeto de callback,
código é executada no servidor e a outra, cutada no servidor como um servlet. Esta que receberá o retorno do serviço assim que
que trata dos eventos da interface gráfica, classe além de implementar a interface de ele for processado. Outra diferença é que
executa no cliente. serviço estende a classe RemoteServiceServlet todos os seus métodos retornam void.
Listagem 11.ContatosServiceAsync.java: interface assíncrona Listagem 13.JMListaContatos.gwt.xml: arquivo de configuração do módulo GWT
<module>
package br.com.jm.gwt.client.service; <inherits name=’com.google.gwt.user.User’ />
//… imports <!-- Especifica o Entry Point do módulo -->
<entry-poin t class=’br.com .jm.gwt.clie nt.JMListaCon tatos’ />
public interface ContatosServiceAsync {
public void getContatos(int posicaoInicial, <!-- Serviço criado para acesso a dados -->
int nroRegistrosPagina, AsyncCallback callback); <servlet path=’/contat osService’
public void updateContato (Contato contato, class=’br.c om.jm.gwt.ser ver.Contatos ServiceImpl’ />
AsyncCallback callback); </module>
}
Listagem 14.FonteDeDados.java
Listagem 12.Implementa os serviços de acesso a dados – ContatosServiceImpl.java
public class FonteDeDados {
private int nroRegistrosPagina;
package br.com.jm.gwt.server; private TabelaEditavel tabelaEditabel;
//… imports
public FonteDeDados( int nroRegistros ) {
public class ContatosServiceImpl extends RemoteServiceServlet this.nroReg istrosPagina = nroRegistros ;
implements setPagina(0);
ContatosService }
{ public void setPagina(in t pagina) {
ContatosServiceAsync service =
public ContatosSer viceImpl() {}
ContatosService.Util.getInstance();
service.getContatos(pagina * nroRegistrosPagina,
public List getContatos(int posicaoInicial, nroRegistrosPagina, new ContatosCallBack());
int nroRegistrosPagina) throws Exception }
{ public void setTabelaEdi tabel(Tabela Editavel tabelaEditab el) {
List temp = new ArrayList(); this.tabela Editabel = tabelaEditab el;
}
String sql =
“select contato_id, nome, telefone, celular, email,” public void updateContat o(Contato contato) {
+ “endereco from contato limit “ ContatosServiceAsync service =
+ posicaoInicial + “,” + nroRegistrosPagina); ContatosService.Util.getInstance();
Connection conn = getConnection (); service.updateContato(contato, new UpdateCallBack());
Statement stmt = conn.createStatement(); }
ResultSet rs = stmt.executeQuery(sql);
private class ContatosCallBack implements AsyncCallback {
public void onFailure(Th rowable caught) {
while (rs.next()) {
Window.alert(caught.getMessage());
temp.add(buildContato(rs)); }
} public void onSuccess(Object result) {
return temp; tabelaEdita bel.atualizaD ados((List) result);
} }
}
public void updateContato (Contato contato) throws Exception {
String sql = “update contato set nome = ?, private class UpdateCallBack implements AsyncCallback {
telefone = ?, celular = ?, public void onFailure(Th rowable caught) {
email = ? where contato_id = ?”; Window.aler t(“Erro ao atualizar o banco de dados”);
Connection conn = getConnection (); }
PreparedStat ement stmt = conn.prepare Statement(sql ); public void onSuccess(Object result) {}
stmt.setStri ng(1, contato.getNo me());
stmt.setStri ng(2, contato.getTe lefone()); }
stmt.setStri ng(3, contato.getCe lular()); }
stmt.setStri ng(4, contato.getEm ail());
stmt.setLong (5, contato.getCo ntatoId()); Listagem 15.Inici aliza os componentes do módulo – JMListaContatos.java
stmt.execute();
}
public class JMListaContatos implements EntryPoint {
private Contato buildContato( ResultSet rs)
throws Exception {...} public void onModuleLoad() {
public Connection getConnection () //lista os contatos com 15 registros por página
throws ClassNotFoundException, SQLException {...} RootPanel.g et(“contatos” ).add(new ListaContatos (15));
} }
}
HUGO VIDAL TEIXEIRA
construímos um exemplo que apresenta usuário com a GUI, reproduzindo cliques Model – não possui uma referência para a
diversas características desejadas em do mouse e eventos de teclado 1. classe View. Ocorre exatamente o contrário:
aplicações modernas. Mas será que a separação de interesses é a classe View que guarda uma referência
não poderia ajudar nesses testes, já que para a classe Presentation Model. Isso é extre-
Patterns e testes em GUIs a lógica está separada dos componentes mamente valioso na criação de testes.
A alta produtividade no desenvolvi- gráficos? Para responder essa pergunta,
mento de GUIs em aplicações desktop vamos examinar a Figura 1, que apresenta Estrutura e classes
pode ser alcançada com a ajuda de dois os três principais patterns para o desenvol- Quando aplicamos o pattern Presenta-
elementos importantes no nível do código: vimento de GUIs em aplicações desktop. tion Model no desenvolvimento de uma
a separação de interesses e a eficácia de Observe a estrutura do Mod el-Vie w- GUI, precisamos criar basicamente três
testes unitários. Presenter (MVP) que é uma pequena varia- classes:
ção do MVC. O importante a ser observado • View – Classe simples que contém os
Separação de interesses aqui é o fato de que tanto no MVC quanto componentes gráficos da GUI. Os dados
A separação de interesses, no nosso caso, no MVP, o controlador ( Controller/Presenter) apresentados na tela refletem o estado
significa separar o estado e a lógica da GUI, possui uma referência para a visão ( View). mantido pela classe Presentation Model.
dos componentes gráficos utilizados. Você Assim, para instanciar um controlador • Presentation Model – Classe que con-
provavelmente já deve ter ouvido falar em dentro de um teste unitário, precisamos tém o estado e a lógica da GUI. Os dados
patterns que fazem essa separação, como da visão com seus componentes gráficos e variáveis são manipulados em memória,
o Model-View-Controller (MVC), que vem também. Isso faz com que o desenvolvi- independentemente da existência de com-
sendo usado tanto no desenvolvimento de mento de testes unitários ainda continue ponentes e formas de apresentação.
aplicações desktop quanto web. bastante difícil. • Service Layer – Classe que oferece à
Embora a separação de interesses traga Existe uma solução para contornar esse classe Presentation Model uma comunica-
muitas vantagens ao desenvolvimento, problema: adicionar uma interface entre o ção com o mundo exterior, onde serviços
ela exige código específico para sincro- controlador e a visão. Mas não vale a pena externos podem existir (como EJBs, bancos
nizar as variáveis que guardam o estado explorar essa alternativa quando temos de dados etc.)
da GUI com os componentes gráficos. uma terceira opção como o Presentation
Normalmente as telas recebem objetos Model, descrito a seguir. A separação em classes com diferen-
de negócio (JavaBeans, por exemplo) do tes responsabilidades traz vantagens
backend e precisam transferir seus dados O pattern Presentation Model
para os componentes gráficos, e vice-versa. O pattern Presentation Model, também 1
Um dos fatores que torna isso muito difícil é a exis-
Para que essa conexão entre os dois lados ilustrado na Figura 1, é bastante diferente tência de somente uma thread para executar o código do
teste e o código que renderiza os componentes na tela. A
possa ser programada sem muito esforço, dos outros dois porque quem detém a lógica thread única é um requisito imutável de APIs como Swing
precisamos da ajuda de um framework e o estado da GUI – a classe Presentation e AWT.
genérico que interligue objetos de
negócio e componentes gráficos. Model-View-Controller Model-View-Presenter Presentation Model
Esse é papel da API Binding do
Model Model View
JGoodies, que estudaremos nesse
artigo.
importantes para a implementação e a JRadioButton, JPasswordField e JFormattedTextField. que guarda um valor booleano, mas não a
manutenção da GUI. Quando trabalha- A variável que pode ser conectada a eles é um que contém um String, por exemplo. Se
mos assim, as classes ficam mais “finas” uma implementação da interface ValueModel o ValueModel receber um valor incompatível
e consequentemente mais simples, o que (pacote com.jgoodies.binding.value ), que arma- com o valor esperado pelos componentes
facilita o entendimento do código e sua zena um valor e o mantém sincronizado conectados a ele, uma exceção será lançada
manutenção. com o que é apresentado pelo compo- durante a tentativa de conversão.
Na verdade, essas vantagens também nente. Ao mudar o valor do ValueModel, o A outra questão é a emissão de eventos
existem no MVC e no MVP. A grande componente refletirá essa mudança. Da PropertyChangeEvent, que acontece quan-
vantagem no Presentation Model é que não mesma forma, se o usuário editar esse do é alterado o valor guardado pelo
precisamos da classe View para testar a valor pela GUI, o ValueModel receberá o ValueModel . Isso permite que o valor seja
lógica da GUI. Isso permite a criação de valor fornecido. “observado” com PropertyChangeListeners.
testes unitários simples, eficientes e sem Existem duas formas de conec- Demonstraremos esse recurso na prática
a presença de componentes gráficos para tar um ValueModel a um componente. mais adiante.
atrapalhar. Uma opção é utilizar o método está-
tico bind () da classe Bindings (do pacote Conectando componentes a listas de objetos
A API JGoodies Binding com.jgoodies.binding.adapter ): Os componentes que podem ser conec-
A API Binding do JGoodies oferece um tados a listas de objetos são JComboBox, JList
conjunto de classes que simplifica muito JTextField textField = new JTextField(); e JTable. A lista de objetos, por sua vez, é
ValueModel valueModel = new ValueHolder();
a aplicação do pattern Presentation Model. Bindings.bind(textField, valueModel); representada por um objeto da interface
Essa API foi desenvolvida para trabalhar javax.swing.ListModel do Swing, que define
com o JFC/Swing e possui mecanismos Repare que criamos um ValueModel ins- métodos para a manipulação da lista e emi-
para conectar componentes gráficos a tanciando a classe ValueHolder (do mesmo te eventos quando ela for modif icada.
variáveis que podem ser manipuladas pacote de ValueModel ), que é a implementa- A contribuição do JGoodies Binding foi
independentemente de suas formas de ção que precisamos para esse caso. criar implementações que combinassem
apresentação. A segunda maneira de fazer a conexão a interface ListModel com a simplicidade
Para entender essa idéia, imagine, por é utilizando uma classe de conveniência da interface java.uti l.List , resultando em
exemplo, uma variável booleana que está chamada BasicComponentFactory (também duas classes: ArrayListModel (que herda
conectada a um JCheckBox (Figura 2). Sem- de com.jgoodies.binding.adapter), que possui de ArrayList e implementa ListModel ) e
pre que trocarmos o valor dessa variável, o métodos prontos para criar componentes. LinkedListModel (que herda de LinkedList e
JCheckBox irá refletir a mudança e vice-ver- Assim, podemos fazer: implementa ListModel). Dessa forma, po-
sa. Ao mesmo tempo, poderíamos conectar demos atuar sobre essas classes dentro
ValueModel valueModel = new ValueHolder();
outros componentes gráficos a essa mesma JTextField textField = da classe Presentation Model, enquanto os
variável, por exemplo um JToggleButton . BasicComponentFactory.createTextField(valueModel); componentes gráficos refletem as mudan-
Assim, podemos ter quantos componentes ças na classe View.
quisermos ligados a uma mesma variável, Essa segunda alternativa será utilizada Entretanto, ainda existe um problema.
sendo que a mudança feita em um dos pelo nosso exemplo por ser mais simples. Sabemos que os componentes desta
componentes é refletida nos outros. Duas questões importantes ainda pre- categoria guardam, além da lista de
Uma variável pode conter tanto um valor cisam ser discutidas. Primeiro, o valor objetos, um item selecionado 2. Portanto,
simples quanto uma lista de objetos. Va- mantido pelo ValueModel pode ser lido e o ListModel sozinho não resolve nosso
mos analisar cada caso separadamente. alterado através dos métodos getValue () e problema. Precisamos da ajuda da classe
setValue (). É importante lembrar que para SelectionInList (em com.jgoodies.binding.list ), que
Conectando componentes a valores simples conectar um componente a um ValueModel, o guarda um ListModel e também contém um
Entre os componentes que podem ser componente precisa conhecer o valor guar- ValueModel que aponta para o item selecio-
conectados a um valor simples, os princi- dado por ele. Portanto, um JCheckBox pode nado. Veja um exemplo:
pais são JLabel, JTextField, JTextArea, JCheckBox, se conectar sem problemas a um ValueModel
ListModel listModel = new ArrayListModel();
ValueModel itemSelecionadoHolder = new ValueHolder();
View Presentation Model SelectionInList selectionInList =
new Selecti onInList(listModel, itemSelecionadoHolder);
JToggleButton
true
JCheckBox
Variável Com isso, podemos conectar o objeto
JCheckBox JToggleButton Booleana
false
2
Os casos em que há mais de um item selecionado são
normalmente raros, e por isso não serão tratados neste
Figura 2. Variável booleana conectada a um JCheckBox e a um JToggleButton. artigo.
litados.
classe View do exemplo, podemos adiantar Para que você entenda o significado desse gerenciando as mudanças de valores quan-
que o objeto usuarioSelectionInList conecta-se objeto, considere a nossa situação: temos do a seleção na lista de usuários mudar,
ao JList que apresenta os usuários na tela uma lista de objetos JavaBeans (usuários) podemos usar a classe BeanAdapter.
(usuariosList). e precisamos amarrar as propriedades do A classe BeanAdapter funciona como
O próximo objeto a ser criado chama-se JavaBean que está selecionado aos com- uma “caixa”, na qual podemos colocar
usuarioSelecionadoBeanAdapter : ponentes da tela: nome, cargo, adminis- um objeto JavaBean. Essa classe fornece
trador e controle de permissões. Para não um ValueModel para cada propriedade do
usuarioSelecionadoBeanAdapter = termos que declarar um ValueModel para JavaBean – justamente o que precisamos.
new BeanAdapter(usuarioSelecionadoHolder, true); cada propriedade desse JavaBean e ficar Assim, quando mudamos o usuário sele-
cionado na lista, os ValueModel s fornecidos
CadastroUsuarioView CadastroUsuarioPresentationModel pelo BeanAdapter irão refletir os valores do
usuarioSelectionInList usuarioListModel novo usuário.
usuarioSelecionadoHolder
Repare que passamos o objeto
usuarioSelecionadoHolder como parâmetro
usuarioSelecionadoBeanAdapter
na criação do BeanAdapter . Isso faz com
nomeHolder
cargoSelectionInList que o BeanAdapter sempre exiba os dados
cargoListModel cargoHolder do usuário selecionado. Observe ainda
administradorHolder
o valor true como segundo parâmetro do
construtor, o que indica que as mudanças
controlePermissaoHolder
no JavaBean precisam ser observadas. No
Figura 4. Conexão entre os modelos da classe Presentation Model com os componentes da classe View . nosso caso, isso é importante porque temos
que atualizar certas partes da GUI quando
Modelo Classe Descrição
os valores do usuário mudarem (ex.: para
habilitar/desabilitar o JCheckBox “Controle
usuarioListModel ArrayListModel Lista observável que guarda todos os usuários. de Permissões” quando a propriedade
Administrador for alterada).
Mantém uma referência para o usuário sele- Por fim, para adquirir os ValueModels
usuarioSelecionadoHolder ValueModel
cionado na lista. fornecidos pelo BeanAdapter, utilizamos
o método getValueModel() , passando o
Une o usuarioListModel e o nome da propriedade em que estamos
usuarioSelectionInList SelectionInList
usuarioSelecionadoHolder em um mesmo objeto.
interessados. Assim, para conectar o
Fornece um ValueModel para cada propriedade
usuarioSelecionadoBeanAdapter BeanAdapter
do usuário selecionado.
ValueModels (fornecidos pelo
nomeHolder, usuarioSelecionadoBeanAdapter) que
cargoHolder, contém, para o usuário selecionado, o nome,
ValueModel
administradorHolder, o cargo, um booleano indicando se é um
controlePermissaoHolder administrador, e um booleano indicando se
pode controlar as permissões do sistema.
ObservadorNomeUsuario PropertyChangeListener Observa as mudanças no nome do usuário selecionado e preenche o valor dotituloHolder.
javax.mail.Session
A classe Session re-
presenta uma sessão
de e-mail. É através
dela que obtemos os
objetos responsáveis
pelo envio e leitura de e-mails,
como por exemplo Transport , Store e
Folder. Para obter um Session precisa-
mos de informações sobre o servidor de
e-mails, que podem ser passadas através dereço de e-mail, incluindo opcionalmente Nessa segunda etapa, é feita a substituição
de um objeto java.util.Properties . um nome. do nome do cliente, e caso o telefone esteja
em um formato incorreto, será adicionada
javax.mail.Authenticator e
javax.mail.Transport uma mensagem no corpo do e-mail solici-
A classe abstrata Transport encapsula javax.mail.PasswordAuthentication tando a atualização cadastral.
o protocolo de envio de e-mails (geral- Um objeto da classe Authenticator sabe As próximas seções descrevem o proces-
mente SMTP) e contém métodos para como obter os dados para autentica- so passo a passo e apresentam detalhes de
envio de mensagens. Um objeto do ção do usuário, retornando um objeto cada classe.
tipo Transport é obtido através do objeto PasswordAuthentication . Não há restrição para
Session informando-se o protocolo uti- as formas de se obter esses dados, que Classe EnviadorDeEmail: enviando
lizado. A API JavaMail fornece apenas podem vir de um arquivo, de entradas do mensagens em HTML com um anexo
uma subclasse concreta de Transport : usuário em um prompt, de uma conexão A classe EnviadorDeEmail tem apenas um
javax.mail.internet.SMTPTransport . a uma fonte de dados externa, ou mesmo método público: enviarEmail() . Neste método
informando-se o usuário e a senha no é obtido um Session e criado um Message já
javax.mail.Store e javax.mail.Folder construtor do objeto, como implementa- com o destinatário e o assunto. Em segui-
Apesar de não utilizarmos estas classes mos no exemplo deste artigo. da, o método adiciona o conteúdo e anexa
no nosso exemplo pois são usadas apenas um arquivo à mensagem. São usados vá-
para leitura/transferência de mensagens, O projeto de Mala Direta rios métodos auxiliares para modularizar
vale a pena citá-las. A classe abst rata Store A aplicação de exemplo é formada por o código.
é utilizada para a leitura de mensagens de quatro classes. A classe EnviadorDeEmail
um servidor de e-mail. Ao obter um objeto (Listagem 1) é responsável por criar a Obtendo a sessão
Store através da sessão indicamos qual o mensagem, anexar um arquivo e fazer O método obterSessao() é o primeiro a ser
protocolo utilizado, por exemplo POP3 o envio (e numa segunda etapa, por chamado em enviarEmail(). Ele configura
ou IMAP (há duas subclasses concretas personalizar as mensagens). A classe um objeto da classe Properties indicando,
de Store na API: POP3Store e IMAPStore). Então MalaDireta (Listagem 2) é a classe execu- através de propriedades pré-estabeleci-
nos conectamos ao servidor informando tável da aplicação; ela cuida da leitura das pela API, o nome do servidor SMTP
os dados para autenticação e recebimento dos clientes do banco de dados e chama (propriedade mail.smtp.host ), e se o servidor
das pastas ( javax.mail.Folder) que contêm os os métodos da classe EnviadorDeEmail para exige ou não autenticação (propriedade
e-mails do usuário autenticado. cada cliente recuperado. Cada destina- mail.smtp.auth). No nosso caso consideramos
A classe abstrata Folder representa uma tário da mala direta é representado por que a autenticação é necessária.
pasta de e-mails do usuário autenticado. um objeto Cliente (Listagem 3), com nome,
Properties props = new Properties();
Objetos Folder (há as subclasses POP3Folder endereço de e-mail, telefone e id. A classe props.put(“mail.smtp.host”, SERVIDOR_SMTP);
e IMAPFolder na API) são obtidos através de Autenticador (Listagem 4) faz a autenticação props.put(“mail.smtp.auth”, “true”);
um objeto Store fornecendo seu nome. no servidor de e-mails, necessária para o
envio. Na Listagem 5 é mostrado o coman- Depois, obterSessao() obtém o objeto Session
javax.mail.internet.MimeMessage do SQL para criação da tabela de clientes usando Session.getDefaultInstance() . Como
A classe MimeMessage representa uma no banco de dados (chamamos o banco de indicamos que o servidor exige auten-
mensagem a ser lida ou enviada por e-mail, “maladireta”). ticação, é necessário passar um objeto
e estende a classe abstrata javax.mail.Message. Inicialmente iremos mostrar como en- que implementa a interface Authenticator.
Para criarmos uma MimeMessage é necessá- viar e-mails em formato HTML com um Passamos um objeto da nossa classe
rio termos um objeto Session. A mensagem anexo. Depois veremos a personalização Autenticador (Listagem 4), que é instancia-
fica associada à sessão de e-mail. do conteúdo do e-mail. A Listagem 7 e a da informando o usuário e a senha para
Listagem 8 exibem as alterações nas clas- autenticação no servidor SMTP.
javax.mail.internet.InternetAddress ses EnviadorDeEmail e MalaDireta necessárias
sessao = Session.getDefaultInstance(
A classe InternetAddress representa um en- para a personalização das mensagens. props, new Autenticador(EMAIL, SENHA));
Criando o objeto Message representados por atributos da inner class enderecoRemetente = new InternetAddress(
EMAIL_REMETENTE, NOME_REMETENTE);
Em seguida, o método enviarEmail() cria RecipientType da classe Message . message.setFrom(enderecoRemetente);
uma mensagem chamando criarMensagem(), No trecho a seguir de criarMensagem() é
que retorna um MimeMessage . Note que é criado um InternetAddress com o e-mail e o O assunto e a data de envio são confi-
passado como parâmetro o objeto Session; nome do destinatário, e depois este ende- gurados através dos métodos setSubject() e
dessa forma a mensagem fica vinculada reço é associado à mensagem, informan- setSentDate(), que são bastante simples.
a esta sessão. do que será utilizado como destinatário
message.setSubject(assunto);
principal (TO). message.setSentDate(new Date()) ;
MimeMessage mensagem =
criarMensagem(sessao, assunto, destinatario);
enderecoDestinatario = new InternetAddress( E por fim o método criarMensagem() retorna
É possível enviar mensagens para um destinatario.getEmail(), destinatario.getNome()); a mensagem criada.
message.addRecipient(Message.RecipientType.TO,
ou mais destinatários, que podem ser enderecoDestinatario);
configurados com CC (Carbon Copy), BCC Definindo o conteúdo do e-mail
(Blind Carbon Copy) e TO (Destinatário O remetente também é representado por O próximo método a ser executado é
principal). Além disso, cada destinatário uma instância da classe InternetAddress , que anexarConteudoEAnexo() . O conteúdo do e-
pode ter um nome e um e-mail (um objeto é associada à mensagem através do método mail é representado por um objeto Multipart,
InternetAddress ). Os tipos do destinatário são setFrom(). sendo que nossa mensagem terá duas
package maladireta; }
catch (MessagingExcepti on e) {
import java.io.*; System.out.prin tln(“Erro ao enviar email para “
import java.sql.*; + cliente.getNome ());
import java.util.*; e.printStackTrace();
import javax.mail.MessagingException; }
}
public class MalaDireta { }
private final static String STRING_CON = “ catch (Exception e) {
jdbc:mysql://localhost/maladireta”; System.out.printl n(“Erro ao ler clientes do banco de dados.\n”);
private final static String USUARIO_BD = “root”; throw e;
private final static String SENHA_BD = “root”; }
private final static String ANEXO = “C:\\temp\\teste.txt”; }
public static void main(String[] args) throws Exception { public static List obterClientes() throws SQLException,
String assunto = “Teste de envio de e-mail do projeto MalaDireta”; ClassNotFoundException
{
StringBuilder conteudo = new StringBuilder(); Connection con = obterConexao();
conteudo.append(“ Statement st = null;
<!DOCTYPE html PUBLIC ‘-//W3C//DTD HTML 4.01 Transitional//EN’>”); ResultSet rs = null;
conteudo.append( List listaClientes = new ArrayList();
“<html><head><title>Teste de envio de e-mail</title></head>”); try {
conteudo.append(“<body> Caro(a) cliente,<br> <br>”); st = con.createStat ement();
conteudo.append( rs = st.executeQuer y(“select * from clientes”);
“Você está cadastrado(a) no nosso sistema e esta“); while (rs.next()) {
conteudo.append(“é uma mensagem que testa o envio de” Cliente cliente = new Cliente(rs.getL ong(“id”), rs
+ “ e-mail para a sua conta.<br>”); .getString(“nome ”), rs.getString(“e mail”), rs
conteudo.append(“<br> Se você não quer mais” .getString(“telefone”));
+ “ receber nossos e-mails, por “); listaClientes.add(cliente);
conteudo.append( }
“favor escreva para <a href=’mailto:contato@globalcode.com.br’>”); return listaClientes;
conteudo.append( }
“contato@globalcode.com.br</a> solicitando descadastramento.<br>”); finally {
conteudo.append(“Pedimos a gentileza de responder este ”
if (rs != null)
+“e-mail confirmando o recebimento.<br>”);
rs.close();
conteudo.append(
if (st != null)
“<br>Atenciosam ente,<br><br>Equ ipe Globalcode<br>< br>”);
st.close();
conteudo.append(“<a href=’http://www.globalcode.com.br’>”
if (con != null)
+ “www.globalcode.com.br</a><br>”);
con.close();
conteudo.append(“Telefone: (11) 3171-1987<br> </body></html>”);
}
}
EnviadorDeEmail enviadorDeEmail = new EnviadorDeEmail();
try {
public static Connection obterConexao() throws SQLException,
List clientes = obterClientes();
ClassNotFoundException
// envia o e-mail para todos os clientes
{
for (Iterator it = clientes.iterator(); it.hasNext();) {
Cliente cliente = (Cliente) it.next(); Class.forName(“com.mysql.jdbc.Driver”);
try { Connection con = DriverManager.g etConnection(STRI NG_CON,
enviadorDeEmail.enviarEmail(assunto, conteudo.toString(), USUARIO_BD, SENHA_BD);
cliente, ANEXO); return con;
System.out.println(“e-mail enviado com sucesso para “ }
+ cliente.getNome()); }
portantes na classe MalaDireta, mostradas na com oito dígitos, sendo que o DDD pode MalaDireta, que realiza a substituição do
Listagem 7. Observe que no texto do e-mail estar colado ao número, ou separado por nome e a verificação do telefone.
incluímos no conteúdo HTML do e-mail a um espaço ou hífen. De acordo com essa
ser enviado “pedaços” de texto para serem expressão, os seguintes números seriam 1. Utilizamos o método replaceAll() da
substituídos: %cliente.nome% e %cliente. considerados válidos: classe String. Este método recebe uma string
telefone% . Vamos utilizar expressões re- • 11-31711987 contendo uma expressão regular e a string
gulares através do método replaceAll() da • 11 31711987 que deve substituir o texto localizado. Neste
classe String para substituir esses pedaços • 1131711987 caso a expressão contém apenas caracteres,
pelo nome e o telefone do cliente. ou seja, não utilizamos símbolos espe-
Observe que este é o caso mais simples Já os números a seguir não estariam de ciais como /d, ou [A-Z] , apenas uma string
de uso de expressões regulares, em que acordo com a expressão: %cliente.nome% (note que a porcentagem
o padrão fornecido é exatamente igual • 31711987 não é um símbolo especial de expressão
ao texto que deve ser localizado. Para • 222323 regular).
demonstrar mais recursos de expressões • 7632323r34
conteudo = conteudo.replaceAll(
regulares, vamos verificar se um tele- “%cliente.nome%”,destinatario.getNome());
fone de cada cliente segue um padrão Agora vamos analisar passo a passo o
estabelecido, de acordo com a seguinte novo método personalizarConteudo() da classe 2. Compilamos a expressão regular que
expressão:
\\d{2}(-|\\s)??\\d{8}
Listagem 6. Trecho demonstrando o uso da expressão regular ilustrada na Figura 1.
Conclusões
Neste artigo, vimos como usar recursos
essenciais da API JavaMail aplicando-os
em uma situação real. Usamos também
expressões regulares, um recurso podero-
so que é suportado por classes específicas
da API do Java SE, bem como a classe
String.
java.sun.com/products/javamail/
Página oficial do JavaMail.
java.sun.com/docs/books/tutorial/extra/
regex/intro.html
Figura 3. E-mail com conteúdo personalizado
Tutorial sobre Expressões Regulares
Listagem 8. Alterações na classe EnviadorDeEmail para personalização
public class EnviadorDeEmail { javamagazine.com.br/downloads/jm39/
//... jm-maladireta.zip
private void adicionarConteudoEAnexo(Message message,
String conteudo, Cliente destinatario, String arquivo)
throws MessagingException, AddressException
{ Yara M. H. Senger
conteudo = personalizarConteudo(conteudo, destinatario); ( yara@globalcode.com.br ) é
//... Igual à Listagem 1 formada em Ciências da Com-
} putação na USP em São Carlos,
private String personalizarConteudo(String conteudo, Cliente destinatario){ especialista em desenvolvimento web;
// personalização do conteúdo possui as certificações SCJA, SCJP e
conteudo = conteudo.replaceAll(“%cliente.nome%”,destinatario.getNome());
SCWCD. Atualmente é Instrutora e Diretora Educacional
Pattern p = Pattern.compile(“\\d{2}(-|\\s)??\\d{8}”);
String telefone = destinatario.getTelefone(); da Globalcode, criadora e coordenadora de diversos
Matcher m = p.matcher(telefone); cursos das carreiras Academia do Java e Academia do
if (m.matches()){
System.out.println(“O “+telefone+” está no padrão”); Web Developer.
conteudo = conteudo.replaceAll(“%corrigir_telefone%”,””);
}
else {
System.out.println(“O “+telefone+” não está no padrão”); Ana Abrantes
conteudo = conteudo.replaceAll(“%corrigir_telefone%”,
“<br>Seu telefone “+ telefone + “ parece estar incorreto,”
(ana.abrantes@globalcode.com.br ) é
+ “solicitamos a gentileza de entrar em contato” desenvolvedora Java na Globalcode,
+ “para atualização do cadastro<br>”);
} co-autora do curso de JasperReports/
return conteudo; iReport e possui algumas certificações
}
//... em Java (SCJA, SCJP e SCWCD). É formada pela FATEC-
} SP e atua na área de informática há mais de 15 anos.
C om o crescimento da internet, a
distribuição e a manutenção de
aplicações tornaram-se muito
mais simples e rápidas. Utilizando um
brows er, o usuário passou a aces sar o
premissa de rodar na máquina do usu-
ário todo o processamento de interface
gráfica, deixando para o lado do servidor
o processamento da lógica de negócio.
O lado cliente das aplicações RIA pode
aplicação de exemplo funcional.
Funcionamento do OpenLaszlo
Aplicações OpenLaszlo são definidas em
documentos na linguagem LZX, baseada
último release sem ter que se preocupar ser implementado de diversas maneiras, em XML. A engine de renderização do
com versionamento ou procedimentos dentre elas applets Java, páginas DHTML, OpenLaszlo (que chamaremos de “Ser-
de instalação. Mas um efeito colateral do aplicativos Macromedia Flash, JavaScript vidor OpenLaszlo”) é uma aplicação Java
paradigma web não tardou a aparecer. e outros. para web, portanto deve ser instalada em
Interfaces mais pobres e menos intuitivas O OpenLaszlo é uma plataforma madura um container web como o Tomcat, ou num
substituíram os sistemas “fat-client” antes de desenvolvimento RIA baseada em Ja- servidor de aplicações Java EE.
largamente utilizados, forçando o usuário vaScript e XML com suporte à depuração Em tempo de execução, o servidor Open-
a se acostumar com o “clicar e esperar” das de aplicações, que renderiza aplicações Laszlo “compila” os arquivos-fonte LZX
interfaces web. em Macromedia Flash. para um aplicativo Flash ( .SWF) que é
O conceito de Rich Internet Application Neste artigo va- enviado ao cliente. Na máquina cliente,
(RIA) é uma das respostas a este problema. mos apresentar os o browser roda o aplicativo (às vezes
Permitindo que o usuário interaja com a principais concei- chamado de “Cliente OpenLaszlo”)
aplicação como se esta fosse um sistema tos dessa platafor- normalmente, utilizando o plug-in Flash.
desktop tradicional, o RIA baseia-se na ma e construir uma A Figura 1 ilustra a organização dos com-
ponentes-chave do OpenLaszlo.
Obtendo e configurando o
OpenLaszlo Server
O download do OpenLaszlo pode ser fei-
to em openlaszlo.org/download, selecionan-
do-se a plataforma desejada (Windows, Li-
nux ou Mac OS). Para outras plataformas,
ou para fazer a instalação manualmente,
obtenha o pacote identificado como “Dev
Kit”. O download já inclui o Tomcat, com o
servlet do Servidor OpenLaszlo configura-
do, bem como documentação e exemplos.
Para verificar a instalação, inicie o
servidor com um duplo-clique no
arquivo server\lps-3.3.3\lps\utils\
startTomcat, dentro do diretório raiz
do OpenLaszlo (ajustando sempre o
número da versão para o seu caso). Após Salve-o com extensão . lzx (ex.: OlaMundo. Como se trata de uma linguagem orien-
iniciá-lo, aponte o browser para: http:// lzx) no diretório server\lps-3.3.3\my-apps, tada a objetos, a LZX nos permite definir
localhost:8080/lps-3.3.3/examples/hello.lzx. e teste a aplicação apontando o browser classes e métodos e usar herança e poli-
Se tudo estiver OK, deverá aparecer a para http://localhost:8080/lps-3.3.3/my- morfismo. Tomemos como exemplo a classe
mensagem “Hello Laszlo!”. (Para parar o apps/OlaMundo.lzx. meuBotao. Ela herda da classe button e define
servidor, dê um duplo-clique no arquivo Toda aplicação OpenLaszlo começa com um método que será disparado pelo evento
server\lps-3.3.3\lps\utils\stopTomcat. ) a tag <canvas>, que renderiza o painel onclick. O corpo do método é todo escrito
principal. Já a tag <text> renderiza um em JavaScript e faz referência a outros
Primeiro aplicativo OpenLaszlo texto qualquer. objetos do documento, através dos seus
Criar uma aplicação “Olá Mundo” no respectivos ids. Um id permite que um ob-
OpenLaszlo é muito simples. Comece Aplicação de exemplo jeto seja referenciado de qualquer parte do
criando um arquivo texto com o conteúdo Como exemplo, iremos desenvolver uma documento LZX. Por exemplo, na chamada
a seguir: aplicação simples de calculadora, cujos visor.setAttribute(‘text’, ‘ ‘) visor é o id.
cálculos são realizados no lado do servidor Ao desenvolver aplicações OpenLaszlo,
<canvas width=”200” >
<text>Ola Mundo!</text> por uma página JSP. Os cálculos a serem geralmente criamos primeiro toda a es-
</canvas> processados são submetidos ao Tomcat trutura estática da aplicação, definindo os
usando parâmetros HTTP, e o resultado é componentes visuais e o layout, e depois
um documento XML como a seguir: adicionamos o comportamento e o proces-
samento de eventos. Para a calculadora,
<resultado>25</resultado>
definimos uma janela, instanciando uma
O objetivo é demonstrar como uma apli- classe window. Dentro dela adicionamos
cação cliente criada com o OpenLaszlo uma caixa de texto edittext (o visor), e os
(a interface gráfica da calculadora) pode botões do tipo meuBotao. Em arquivos LZX,
submeter dados para processamento no o layout é definido pela classe lzLayout e
servidor e obter o resultado mostrando-o suas classes filhas. No exemplo utilizamos
para o usuário. Com as técnicas mostra- a classe simplelayout que estende lzLayout e
das, você poderá criar aplicações RIA em
Flash que acessam recursos corporativos
rodando, por exemplo, em um Browser Cliente
servidor Java EE.
Plug-in Flash
Listagem 1. calculadora.lzx