Você está na página 1de 76

Criao de componentes e acesso a dados

Especial

AJAX Avanado com GWT


A Revista da Comunidade Java Brasileira

Edio 39 - Ano V - R$ 9,90

JGoodies Binding
Ligue componentes grficos a objetos
de negcio mantendo a abstrao OO

JavaMail Aplicado
Criando uma mala direta em HTML
com anexos, fazendo personalizao
atravs de expresses regulares

RIA com OpenLaszlo


Crie Rich Internet Applications e traga
interatividade de desktop s suas
aplicaes web, com Flash, XML e Java

Dicas na Web
Recapitulando tcnicas essenciais
na programao com servlets e JSPs

SWT com Visual XP


Torne suas aplicaes grficas mais
integradas ao sistema operacional

JAVA EE 5
jm39.indb 1

Explorando a Plataforma

Java Persistence API

Conhea a fundo todas as novidades,


de motivaes a efeitos prticos com
um tutorial no GlassFish

A nova API de persistncia do EJB 3.0


que muda as bases do mapeamento
objeto-relacional em Java
15/8/2006 18:11:24

jm39.indb 2

15/8/2006 18:11:30

Contedo
CAFENA

News & Bits


LEONARDO GALVO
Novos produtos wireless, TestNG 5, repositrio open source do Google,
Subversive 1.0

06

Sees

SWT com visual nativo do XP


FERNANDO LOZANO
Faa o Eclipse e outras aplicaes SWT assumirem o visual do Windows XP

RECAPITULANDO: DICAS NA WEB


FELIPE LEME
Obtendo as verses suportadas de JSP e servlets, usando forward e redirect,
manipulando JavaBeans em taglibs e alterando o nome de arquivos para download

10

JAVA EE 5
OSVALDO PINALI DOEDERLEIN

Capa

Explorando a nova verso do Java corporativo: anotaes, injeo de dependncias, novas JSRs e um exemplo prtico usando o servidor open source GlassFish

16

PERSISTNCIA NO JAVA EE 5
ANDR DANTAS ROCHA E SRGIO OLIVEIRA KUBOTA
Aprenda a utilizar a nova Java Persistence API, de conceitos de mapeamento
objeto-relacional, a um exemplo completo usando Toplink Essentials e MySQL

28

AJAX AVANADO COM GWT


ARI DIAS NETO
Explore a API do Google Web Toolkit e crie novos componentes,
desenvolvendo aplicaes altamente interativas com AJAX e Java

38

UMA MALA DIRETA COM JAVAMAIL


YARA SENGER E ANA ABRANTES

Desktop

Web

Utilize a API JavaMail para enviar e-mails em HTML com anexos para mltiplos
destinatrios, e personalize mensagens usando expresses regulares

jm39.indb 3

62

RIA COM OPEN LASZLO


ANDR LUS MONTEIRO
Turbine suas interfaces grficas e maximize a interatividade com o usurio
utilizando uma plataforma open source baseada em Flash, XML e Java

70

INTERFACES GRFICAS COM QUALIDADE PARTE 2


HUGO VIDAL TEIXEIRA
Descubra como aplicar o pattern Presentation Model e a API Binding do
JGoodies para construir GUIs com produtividade, favorecendo os testes unitrios

50

15/8/2006 18:12:15

Esp a

Ano V Edio 39 2006 ISSN 1676-8361

Direo
Diretor Editorial Leonardo Galvo
Diretor de Marketing Gladstone Matos
Diretor Comercial Casseano Filho

Edio
Publisher e Editor-Chefe
Leonardo Galvo (leonardo@javamagazine.com.br)
Editores-Adjuntos
Fernando Lozano (lozano@javamagazine.com.br)
Osvaldo Doederlein (osvaldo@javamagazine.com.br)
Colaboraram nesta edio
Ana Abrantes, Andr Dantas Rocha, Andr Lus Monteiro,
Ari Dias Neto, Fernando Lozano, Hugo Vidal, Leonardo Galvo,
Osvaldo Doederlein, Srgio Kubota, Yara Senger

Arte
Diretor de Arte Tarcsio Bannwart (phdesign@phdesign.com.br)
Diagramao Jaime Peters Junior, Lais Pancote e Tersis Zonato
Ilustraes Felipe Machado e Francisco Peixoto
Capa Felipe Machado

Produo
Gerncia de Marketing Kaline Dolabella
Distribuio
Fernando Chinaglia Distribuidora S.A.
Rua Teodoro da Silva, 907, Graja - RJ
CEP 20563-900, (21) 3879-7766 - (21) 2577-6362

Atendimento ao leitor
A DevMedia possui uma Central de Atendimento on-line, onde voc pode
tirar suas dvidas sobre servios, enviar crticas e sugestes e falar com um
de nossos atendentes. Atravs da nossa central tambm possvel alterar
dados cadastrais, consultar o status de assinaturas e conferir a data de envio
de suas revistas. Acesse www.devmedia.com.br/central, ou se preferir
entre em contato conosco atravs do telefone 21 2283-9012.

Edies anteriores
Adquira as edies anteriores da revista Java Magazine ou de qualquer outra
publicao do Grupo DevMedia de forma prtica e segura, em
www.devmedia.com.br/anteriores.

Publicidade
publicidade@javamagazine.com.br, 21 2213-0940
Anncios Anunciando nas publicaes e nos sites do Grupo DevMedia,
voc divulga sua marca ou produto para mais de 100 mil desenvolvedores
de todo o Brasil, em mais de 200 cidades. Solicite nossos Media Kits, com
detalhes sobre preos e formatos de anncios.
Reprints Editoriais Se foi publicado na Java Magazine um artigo que
possa alavancar as suas vendas, multiplique essa oportunidade! Solicite a
reimpresso da matria junto com a capa da edio em que saiu, e distribua
esse reprint personalizado entre seus clientes.
Encarte de CDs Faa como nossos maiores anunciantes. Encarte um CD
com uma amostra de seus produtos na Java Magazine e atinja um pblico
segmentado e formador de opinio.
Realizao

Apoio

om o Java Enterprise Edition 5.0, entramos em numa nova e importante


gerao do desenvolvimento corporativo. O foco na facilidade de uso, a absoro de tcnicas utilizadas em produtos open source, uma participao sem
precedentes da comunidade e uma implementao de referncia que j rivaliza com
os melhores servidores de aplicaes... Talvez pela primeira vez na histria do Java
corporativo vemos lanada uma verso que sucesso entre as mais diversas castas
de desenvolvedores Java. O Java EE 5.0 faz grandes correes de rumo, criando novas
tecnologias que tornam obsoletas reas problemticas da especificao como os to
polmicos Entity Beans, incorpora mais do que nunca os web services, e j olha adiante
integrando-se com vrias novidades que viro no Java SE 6.0 (Mustang). Quem diria
que uma especificao do JCP, envolvendo gigantes do mercado com vises e perfis
to distintos como Sun, IBM, Oracle, BEA, Motorola, Cisco e SAP, chegaria a um consenso de tal solidez, criando uma especificao to eficaz e alinhada s necessidades
do mercado? Mas foi o que aconteceu, em mais uma demonstrao da efetividade do
Java Community Process e da fora da comunidade Java.
Nesta edio, o Java EE 5 tratado em dois artigos aprofundados. Em uma viso
geral da plataforma, voc conhece todas as grandes novidades, com diversos exemplos funcionais, e ainda um tutorial mostrando como criar uma aplicao usando
uma seleo dos novos recursos da especificao, alm do GlassFish, o servidor que
a base da implementao de referncia do novo Java EE. Em um segundo artigo,
vista em detalhes a API que tem chamado mais ateno no Java EE 5, a Java Persistence API (JPA). Parte da especificao do EJB 3.0, mas planejada como especificao
independente na sua prxima verso, a JPA se inspira fortemente em ferramentas
de mapeamento objeto-relacional como Hibernate e iBatis, padronizando uma rea
fundamental do desenvolvimento corporativo. Voc vai conhecer os fundamentos da
JPA, e criar um exemplo completo usando vrios tipos de associaes e herana.
Ainda nesta edio, confira um artigo sobre desenvolvimento AJAX que explora a
API do Google Web Toolkit para criar componentes altamente interativos e integrlos em uma aplicao sofisticada com acesso a dados. Veja tambm como melhorar
suas aplicaes desktop usando o pattern Presentation Model e a API JGoodies Binding, que permite vincular os seus modelos OO interface grfica de forma eficaz
e organizada.
Em outra matria passo a passo, mostrado como criar uma mala direta completa
usando a API JavaMail e expresses regulares. E mais um artigo voltado internet
mostra como usar o OpenLaszlo para criar Rich Internet Applications, baseadas em
Flash, XML e Java. Finalmente, nesta edio retomamos a seo Recapitulando, dessa
vez trazendo dicas sobre o desenvolvimento com JSP e servlets; tambm inclumos
um artigo especial no Cafena mostrando como fazer sua aplicao
SWT se integrar perfeitamente ao visual do Windows XP.

Boa leitura!
Parceiros

Leonardo Galvo

jm39.indb 4

15/8/2006 18:12:21

p ao do Leitor
Dilogos modais para a rea de trabalho

stou desenvolvendo uma aplicao Swing


usando NetBeans 5 e JDK 1.5, a qual solicita
login e senha. Ela deveria bloquear todas as janelas
da rea de trabalho, s liberando-as aps a autenticao. Mas no consigo descobrir como configurar
um dilogo modal para a rea de trabalho como
um todo, como seria possvel usando Delphi ou
Visual Basic.
Eloir Cortes
Infelizmente nem o Swing nem o AWT fornecem o recurso conhecido como system modal
no Windows, que permite bloquear todas as
aplicaes na rea de trabalho at que o dilogo
seja fechado. At o Java SE 5.0, possvel criar

SOA
Sou assinante da Java Magazine e gostaria
primeiramente de parabeniz-los pela excelente
qualidade do material apresentado. Tambm
gostaria de saber de vocs se h possibilidade de
publicar na revista um artigo falando sobre SOA e
web services, visto que o assunto cada vez mais
comentado na comunidade Java.
Michel Pires da Silva
Web Services e SOA (Service-Oriented Architecture) foi um dos assuntos de capa da Java
Magazine 34. O artigo de Osvaldo Doederlein
cobriu desde as tecnologias precursoras dos web
services como RPC, at o atual enfoque na criao
de arquiteturas orientadas a servios.

Java EE 5
Gostaria de ver as novidades do Java EE 5 nas
prximas edies. Afinal de contas, a especificao
j foi aprovada, e a Java Magazine sempre nos
apresenta as novidades em primeira mo.
Michel Zanini
Esta edio atende ao seu pedido! Alm de
um artigo fornecendo uma viso geral da nova
plataforma destacando as principais mudanas,
voc ver uma matria sobre uma das mais

dilogos modais apenas com respeito prpria


aplicao que o criou. No Java 6 (Mustang),
haver um controle mais fino sobre dilogos
modais, mas ainda assim o mximo ser restringir
todas as aplicaes Java na rea de trabalho, no
afetando as aplicaes nativas. Veja mais sobre
as mudanas em dilogos modais no Java 6 em
java.sun.com/developer/technicalArticles/J2SE/
Desktop/mustang/modality.
possvel, pelo menos no Windows, configurar
dilogos Swing como system modal mas isto
envolve o uso da tecnologia JNI (Java Native
Interface) para chamar funes da API nativa
do Windows (Win32 API). Lembrando que uma
aplicao usando este recurso, claro, no seria

portvel. O site para desenvolvedores da Borland


tem um bom artigo explicando como fazer isso:
community.borland.com/article/0,1410,20679,00.
html.
Por outro lado,
aplicaes SWT
tm o recurso
de system modal disponvel:
basta configurar o estilo
SWT.SYSTEM_MODAL
na criao de
um Dialog ou
de um Shell.

importantes novidades do Java EE 5: a Java


Persistence API.

simples configurao do container web (no caso


do Tomcat, a ativao da vlvulaSingleSignOn) faz
com que o login em uma aplicao seja automaticamente repassado para todas as outras aplicaes
dentro do mesmo servidor de aplicaes, ou do
mesmo cluster de servidores de aplicaes.
As dificuldades surgem quando o desenvolvedor, em vez de adaptar seus programas aos
recursos de segurana previstos pelo Java EE,
cria sua prpria soluo personalizada de
autenticao. Mas no h motivos para se fugir
aos recursos padres do Java EE, pois qualquer
servidor de aplicaes com um mnimo de qualidade capaz de usar senhas armazenadas em
vrios locais, como bancos de dados, diretrios
LDAP ou mesmo as senhas de rede em Windows,
Linux e Netware.

Ferramentas
Parabenizo a Java Magazine pelas excelentes
edies. Sou iniciante em Java e uma das grandes
dificuldades para um iniciante , alm de aprender
a linguagem, saber utilizar as ferramentas existentes. E a Java Magazine sabe nos mostrar como
utilizar essas ferramentas de forma muito didtica,
o que facilita bastante a vida dos iniciantes.
Rubens Renato Lima

Autenticao integrada no Java EE


Tenho vrias aplicaes Java EE e preciso que elas
trabalhem com um nico login. Ou seja, quando
o usurio efetuar o login em uma das aplicaes,
ser necessrio que todas as outras trabalhem
com essa autenticao. Existe alguma forma de
compartilhar as informaes de autenticao entre
as aplicaes?
Everton Trindade
Os dois artigos Segurana no J2EE, publicados
nas Edies 22 e 23 respondem em detalhes sua
pergunta. De forma resumida, se sua aplicao utiliza os recursos de autenticao e controle de acesso
baseados em roles definidos pelo Java EE, uma

Participe!
Envie sua dvida,
comentrio, correo ou
sugesto, com nome completo, cidade e
estado, para:
cartas@javamagazine.com.br
Cartas publicadas podem ser editadas por
motivos de clareza ou extenso.

Edio 39 Java Magazine

jm39.indb 5

15/8/2006 18:12:31

Cafen
News & Bits

Nokia Carbide.j 1.5


O

Carbide.j um conjunto de ferramentas integradas voltado


criao, depurao e testes de aplicaes Java para dispositivos Nokia, que pode ser executado independentemente
ou de forma integrada a um IDE (so suportados o Eclipse 3.0 e
3.1, JBuilder Mobile Edition, NetBeans 4.x e 5.0, e IBM WebSphere
Studio Device Developer 5.6 e 5.7). Com o Carbide.j, voc pode
criar aplicaes baseadas nos perfis MIDP e Personal Profile, assinar pacotes de aplicaes MIDP, configurar e gerenciar SDKs da

Nokia (h um SDK da empresa para cada srie de dispositivos), e


realizar a instalao/deployment usando conexes RS232 (serial),
IrDA (infra-vermelho) e Bluetooth, assim como FTP. H ainda um
designer de interfaces grficas com suporte a dez tamanhos de
telas, entre outras funcionalidades.
A novidade mais importante da verso 1.5 o suporte ao chamado on-device debugging, que permite realizar a depurao
de aplicaes em execuo no prprio dispositivo. H tambm
suporte a novos dispositivos e vrias melhorias, especialmente na
integrao com o Eclipse e no designer de interfaces. forum.nokia.
com/main/resources/tools_and_sdks/carbide.

SNAP Mobile SDK 1.2

plataforma Scalable Network Application Package (SNAP)


da Nokia suporta a criao de jogos mveis conectados e
comunidades de jogadores, atravs de uma API cliente e
uma infra-estrutura de servios. Para comunidades, so
oferecidos recursos para conversas on-line e criao
de listas de amigos, indicadores de presena (online, offline, jogando) e rankings, para estimular
a competio. H funcionalidades para jogos
ponto a ponto, nos quais dois adversrios
jogam um contra o outro do comeo ao fim,
e tambm a possibilidade de pesquisar e
escolher adversrios e montar salas virtuais.
Outro ponto forte so os recursos para a
criao de sites com notcias e eventos,
quadros de mensagens moderados e
pginas de apresentao dos jogos. A
plataforma SNAP roda sobre o MIDP
2.0 e baseada na plataforma Arena
criada para o N-Gage (os primeiros celulares da Nokia com suporte especial
a jogos), que j conta com mais de 500
mil usurios cadastrados. Um atestado
da importncia do SNAP a sua incluso no novo Wireless Toolkit 2.5 da Sun.
snapmobile.nokia.com.

6 Java Magazine Edio 39


jm39.indb 6

15/8/2006 18:12:40

n a
Leonardo Galvo
TestNG 5.0
O framework de testes TestNG o principal
concorrente do JUnit, e se posiciona como
uma alternativa mais capaz e mais moderna
(NG uma abreviao de New Generation).
Primeiro framework de testes a suportar
anotaes (mesmo antes do Java 5), o TestNG inclui suporte a mtodos dependentes
e parmetros, distribuio de testes e testes
orientados a dados.
O TestNG segue um modelo de execuo que
dispensa o uso do tradicional TestSuite e traz
o BeanShell embutido. H tambm plug-ins
para vrias ferramentas, entre elas o Eclipse e
o Apache Maven. A verso 5.0 tem melhorias
importantes nos relatrios de testes gerados,
com uma estrutura mais organizada e mudanas visuais. Outro destaque o trabalho com
stack traces, que agora podem ser mostrados
interativamente nos relatrios HTML, sendo
possvel tambm filtr-los. testng.org

Subversive 1.0.0

nvel de suporte oferecido no IDE para o CVS.

construdo sobre o Apache Lucene. Recursos

polarion.org.

enterprise no disponveis na verso Commu-

LimpidLog

nity, como Single Sign-On e suporte a clusters


esto acessveis sob uma licena baseada na

A n ov a API d e l o g g i n g o p e n s o u rce

idia de contribuio ou pagamento, pela

LimpidLog tem uma proposta radical, que

qual empresas ou indivduos podem escolher

pode simplificar o log de informaes sobre

pagar royalties pelos recursos adicionais, ou

classes durante a execuo. Em vez de codificar

troc-los por contribuies para o projeto.

chamadas API de logging, voc registra a

jahia.org.

classe a ser monitorada e o LimpidLog acompanha e loga informaes importantes sobre

Google lana repositrio open source

o que est sendo feito na classe (isso vale

O Google lanou um novo repositrio de

para mensagens do tipo TRACE e ERROR; para

projetos open source, baseado no sistema de

outros casos, ainda ser necessrio chamar

controle de verses Subversion, e subordinado

uma API de logging comum). A API usa a classe

ao portal Google Code (que hospeda pro-

java.lang.instrument.Instrumentation para instru-

jetos como a Google Search API). O cadastro

mentar classes e capaz de logar eventos de

de novos projetos simples e h recursos

chamada/entrada/sada de mtodos, atribui-

completos de busca, alm de navegao por

o de variveis e levantamento de excees.

palavras-chave. Para registrar um projeto,

acelet.com/limpidlog.

necessrio ter uma conta no Google, o que

Jahia Community Edition


Mais um produto importante liberado como

abre a possibilidade de se usar diversos outros servios da empresa juntamente com o


repositrio.

Um dos mais populares plug-ins Eclipse

open source, o Jahia Community Edition torna

Um detalhe interessante que apenas algu-

para integrao com o sistema de controle de

disponvel sob uma licena CDDL modificada,

mas licenas open source so aceitas. Diz o FAQ

verses Subversion, o Subversive chegou

80% do cdigo do produto. So mais de 2.200

do Google, A comunidade open source est

verso 1.0.0. O Subversion considerado em

classes e arquivos.

cheia de licenas 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 licenas mais populares e maduras. O repo-

de verses oficial da Fundao Apache, entre

Content Management) e portlets, bem como

sitrio inclui ainda recursos de issue tracking,

outras organizaes. O objetivo do plug-in

um gerenciador de documentos baseado

em um mdulo 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.

Edio 39 Java Magazine


jm39.indb 7

15/8/2006 18:12:41

Cafena Especial

SWT com visual


nativo do XP

Fernando LoZano

uito se fala que uma das grandes


vantagens do SWT sobre o Swing
a aderncia ao visual nativo da
plataforma, obtido graas ao uso dos componentes grficos nativos. Entretanto, desenvolvedores de aplicaes SWT e usurios do
Eclipse em geral devem ter percebido que,
no Windows XP, assumido o visual nativo
do Windows 98 e 2000, em vez do visual mais
moderno do Windows XP.
Veja na Figura 1, por exemplo, o exemplo
EnderecoTerrestre.java publicado originalmente no artigo da Edio 31 sobre desenvolvimento SWT. A Figura 2 ilustra como
deveria ser a aparncia da aplicao com o
visual nativo do XP.
A boa notcia que as duas figuras foram
geradas pela mesma aplicao. No foi necessrio modificar uma nica linha do cdigo
Java, nem recompilar a aplicao contra uma
verso diferente do SWT.
A soluo exige que o arquivo javaw.exe.
manifest, apresentado na Listagem 1, seja
manifest
copiado para a mesma pasta que contm o

executvel javaw.exe utilizado para rodar as


aplicaes SWT em seu computador.
Os programas javaw.exe e java.exe so ambos
alternativas para a execuo de uma mquina
virtual Java (JVM). A nica diferena entre eles
que o cabealho do javaw.exe diz ao Windows que
ele uma aplicao grfica, e assim sua execuo
no provoca a abertura de uma janela de console
ou prompt do MS-DOS.

manifest instalao padro do JRE ou JDK.


Assim sendo, o arquivo deve ser instalado
manualmente pelos prprios usurios.
Do lado da Microsoft, este arquivo tem
sua razo de ser, pois ele permite que aplicaes criadas para verses anteriores do
Windows executem sem modificaes no
XP. Ao mesmo tempo, ele torna fcil para os
desenvolvedores adequarem suas aplicaes
ao novo visual, sem esforo adicional de
programao.
Em verses anteriores do Windows, a
Microsoft simplesmente forava todas as
aplicaes a assumirem o novo visual (por
exemplo, do Windows 3.1 para o Windows
95). Entretanto, isto criava problemas quando
a aplicao utilizava componentes customizados que no se adequavam bem ao novo
visual. Por isso, no XP, qualquer aplicao
pode ser configurada para o visual antigo
ou para o novo.

Uma vez criado (ou copiado) o arquivo, a


linha de comando a seguir executa o exemplo
conforme visto na Figura 2:
javaw EnderecoTerrestre

A criao do arquivo ir afetar todas as aplicaes SWT executadas neste computador,


inclusive o prprio Eclipse. As Figuras 3 e 4
mostram o prprio Eclipse antes e depois da
criao do javaw.exe.manifest.
Fica a pergunta: por que essa mgica
no parte da instalao padro do Eclipse
para Windows? Afinal o arquivo javaw.exe.
manifest seria simplesmente ignorado em
verses mais antigas do Windows, e assim
no causaria prejuzo algum.
A impossibilidade de o arquivo ser instalado
pelo prprio Eclipse decorre da licena do
Java. A redistribuio do Java da Sun deve ser
feita de modo inalterado, assim no possvel
para o Eclipse (ou para qualquer outro fornecedor que no tenha adquirido uma licena
especial junto Sun) acrescentar o javaw.exe.

Figura 1. Exemplo EnderecoTerrestre.java como exibido na


instalao padro do SWT no Windows XP, assumindo a
aparncia padro do Windows 98 e 2000.

Figura 2. Exemplo EnderecoTerrestre.java com a aparncia


nativa do Windows XP.

8 Java Magazine Edio 39


jm39.indb 8

15/8/2006 18:12:48

Listagem 1. Arquivo javaw.exe.manifest que permite a aplicaes SWT assumirem a aparncia nativa do Windows XP
<?xml version=1.0 encoding=UTF-8 standalone=yes?>
<assembly xmlns=urn:schemas-microsoft-com:asm.v1 manifestVersion=1.0>
<assemblyIdentity version=1.0.0.0
processorArchitecture=X86
name=SWT.javaw
type=win32/>
<description>Standard Widget Toolkit</description>
<dependency>
<dependentAssembly>
<assemblyIdentity type=win32
name=Microsoft.Windows.Common-Controls
version=6.0.0.0
processorArchitecture=X86
publicKeyToken=6595b64144ccf1df
language=*/>
</dependentAssembly>
</dependency>
</assembly>

Figura 3. Eclipse com sua aparncia padro no Windows XP

Figura 4. Eclipse depois de criado o arquivo javaw.exe.manifest


Edio 39 Java Magazine
jm39.indb 9

15/8/2006 18:12:56

Recapi t
Dicas na

Web
N

este artigo so apresentadas dicas


teis sobre JSP e servlets, solues
para problemas recorrentes no desenvolvimento web, e esclarecimentos sobre
alguns procedimentos comuns.

Obtendo as verses de JSP


e Servlets

Nesta edio,
recapitulamos um dos
assuntos mais populares
na Java Magazine: o
desenvolvimento com JSP e
servlets. Foram selecionadas
quatro dicas, ainda
totalmente atuais, do artigo
Dicas na Web publicado
na Edio 12, que resolvem
dvidas comuns e exploram
detalhes importantes da
programao web com Java.

As tecnologias JSP e servlets


evoluram muito desde suas
primeiras verses. Por exemplo,
a API de servlets 2.3 introduziu
o conceito de filtros (interface
javax.sevlet.Filter), e com o JSP
2.0, veio o suporte a uso da Expression Language dentro das
pginas.

Para garantir a compatibilidade de suas


aplicaes web, portanto, sempre importante saber as verses das APIs suportadas
nos containers web utilizados. Os mtodos
getMajorVersion() e getMinorVersion() da classe
javax.servlet.ServletContext permitem obter a
verso da API de servlets. Esta classe fornece
ainda o mtodo getServerInfo(), que descreve
o nome do servidor e sua verso.
J para a verso da especificao JSP, preciso obter um objeto javax.servlet.jsp.JspEngine e
chamar seu mtodo getSpecificationVersion(). A
Listagem 1 contm uma pgina JSP que pode
ser usada para obter essas informaes.

Definindo o nome do
arquivo em downloads
Um uso comum para servlets (e mesmo
para pginas JSP) a gerao dinmica de
arquivos, tais como planilhas ou documentos
PDF. Nessas situaes, ao enviar o arquivo
gerado, preciso que o servlet especifique
o tipo do contedo atravs do mtodo
response.setContentType(String tipo). O tipo segue
no cabealho da resposta HTTP retornada pelo
servlet e, de acordo com ele, o navegador poder decidir o que fazer com o arquivo.
Normalmente o arquivo exibido atravs
de um plug-in, ou oferecida a opo de
salv-lo no disco, mas nos casos onde a in-

Listagem 1. versoes.jsp, obtendo a verso das APIs web suportadas


<%@ page import=javax.servlet.ServletContext %>
<%@ page import=javax.servlet.jsp.JspFactory %>
<%

ServletContext sc = pageContext.getServletContext();
String servidor = sc.getServerInfo();
String versaoServlet = + sc.getMajorVersion() + .
+ sc.getMinorVersion();
String versaoJsp = JspFactory.getDefaultFactory().
getEngineInfo().getSpecificationVersion();

%>

<b>Servidor:</b> <i><%= servidor %></i><br>


<b>Servlet:</b> <i><%= versaoServlet %></i><br>
<b>JSP:</b> <i><%= versaoJsp %></i><br>

10 Java Magazine Edio 39


jm39.indb 10

15/8/2006 18:13:03

i tulando
teno que o usurio faa o download, esse
procedimento traz alguns problemas:
No garantido que o usurio tenha a
opo de salvar o arquivo em vez de o navegador abrir automaticamente um plug-in.
Mesmo que o navegador web oferea a
opo de salvamento, o nome sugerido ser
o do servlet ou o da pgina JSP (por exemplo,
contador.jsp), sendo que o ideal seria um
nome mais amigvel, ou ao menos com a
extenso correta (como "contador-10.txt").
Para resolver esses problemas, a soluo
definir a propriedade content-disposition do
cabealho da resposta HTTP, com o valor
attachment;filename=nome.extenso, como no
trecho de cdigo a seguir:

sejado (como relatorio.pdf ou contador.


txt) para o servlet ou pgina JSP responsvel
pela gerao do arquivo, o que funcionar
independente do navegador utilizado. No
entanto essa soluo no tem a flexibilidade
de permitir a definio do nome no momento
de execuo do servlet/JSP.

Forward ou redirect?
Uma necessidade muito comum na programao web passar o fluxo de execuo

1
RFCs (Requests for Comments) so documentos que
definem protocolos, modelos ou especificaes para os
sistemas da internet. De forma ampla, representam para
a internet o que os JSRs (Java Specification Requests) so
para Java.

para outra pgina. Existem duas formas de se


fazer isso forward (encadeamento) e redirect
(redirecionamento). Embora o resultado final
parea muitas vezes ser o mesmo, o funcionamento bem diferente sob o ponto de vista
do navegador web.

Forward
A primeira forma usa o mtodo forward()
da classe RequestDispatcher, como mostra o
cdigo da Listagem 3.

Listagem 2. contador.jsp, exemplo simples para demonstrar mudana de nome do download


<%

int limite = 10; // valor padro


try {
limite = Integer.parseInt(request.getParameter(limite));
}
catch(Exception exc) {
// ignora exceo (limite=10)
}
String nomeArquivo = contador- + limite + .txt;
response.setContentType(text/plain);
response.setHeader(content-disposition,
attachment;filename= + nomeArquivo);
for (int i=1; i<=limite; i++) {
out.println(i);
}

response.setHeader(
content-disposition,
attachment;filename= + nomeArquivo
);

A Listagem 2 inclui uma pgina JSP que


imprime um contador, de 1 at 10 (ou at
o valor definido no parmetro limite). Note
que o navegador no exibe o contedo da
pgina; em vez disso abre a janela com a opo de salvar o arquivo, com nome sugerido
contador-XX.txt (sendo XX o limite).
A propriedade content-disposition definida
no protocolo HTTP (RFC 21831), e no na
API de servlets/JSP. Assim o funcionamento
dessa dica depende da compatibilidade do
navegador com os padres W3C, e pode
no funcionar em navegadores mais antigos
(nesses casos, o nome sugerido continuar
sendo o nome do JSP).
Outra opo def inir no descritor
web.xml um mapeamento com o nome de-

Felipe Leme

%>

Listagem 3. Forwards em JSPs e servlets


Em pginas JSP:
RequestDispatcher dispatcher =
pageContext.getServletContext().getRequestDispatcher(/novaPagina.jsp);
dispatcher.forward(request, response);

Em servlets:
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher(/novaPagina.jsp);
dispatcher.forward(request, response);

Figura 1. Uso de RequestDispatcher.forward() numa arquitetura simplificada


Edio 39 Java Magazine

jm39.indb 11

11

15/8/2006 18:13:04

Recapitulando Dicas na Web

O mtodo forward() repassa a requisio


para outro recurso como um servlet, pgina
JSP ou pgina HTML dentro do mesmo container web. Esse recurso pode fornecer uma
resposta final ao cliente, ou ento repassar
novamente a requisio (veja a Figura 1).
Usar forward() til quando o primeiro servlet
precisa fazer algum pr-processamento
(por exemplo, validar se o usurio atual tem
permisses para acessar a URL especificada),
antes de passar a requisio para o servlet ou
JSP que realizar o processamento final. Em
particular, dessa forma que o Struts e outras
implementaes da arquitetura MVC realizam
o trabalho do controller (veja a Figura 2).

chamada a out.print() ou out.println(), como


mostrado nos exemplos.

1. O corpo da tag <jsp:useBean> s executado quando o JavaBean instanciado.


Assim, se o escopo do bean for de sesso,
o cdigo de inicializao s ser executado
uma vez. Cdigos como o seguinte so causa
constante de bugs:

Cuidados com <jsp:useBean>


e <jsp:setProperty>
Uma prtica muito comum no desenvolvimento de pginas JSP o uso das tags
<jsp:useBean> e <jsp:setProperty> para, respectivamente, instanciar JavaBeans e preencher
suas propriedades com os valores fornecidos
no formulrio da pgina. Embora a prtica
seja correta, preciso tomar alguns cuidados
com o uso dessas duas tags:

<jsp:useBean id=beanEntrada scope=session


class=jm.dicas.EntradaDadosBean
scope=session>
<jsp:setProperty name=beanEntrada property=*/>
</jsp:useBean>

O problema aqui que os valores do formulrio


s so repassados para o bean na primeira vez

Redirect
A segunda forma de passar o fluxo de execuo para outra pgina consiste em usar o
mtodo sendRedirect() da classe HttpResponse,
enviando com isso um comando HTTP SEND
REDIRECT para o navegador web. Nesse caso
a requisio volta para o navegador, que
automaticamente faz a requisio da pgina
especificada (que no precisa estar localizada no mesmo servidor). A Figura 3 ilustra o
procedimento.

Figura 2. Uso de RequestDispatcher.forward() na arquitetura MVC

Comparando as tcnicas
A Tabela 1 mostra as demais diferenas
entre cada opo, e a Listagem 4 contm
uma pgina JSP com exemplos das duas
tcnicas. Note que, em ambos os casos,
se o buffer de resposta j tiver recebido
alguma sada, a tentativa de mudar o fluxo
de execuo lana uma IllegalStateException.
Assim, recomendvel que chamadas a
forward () ou a sendRedirect() sejam feitas
no comeo do cdigo principal do servlet
(doPost(), doGet() etc.), antes de qualquer

RequestDispatcher.forward()

Response.sendRedirect()

Fluxo de execuo permanece no servidor

Fluxo volta ao cliente

Atributos definidos no request so acessveis na


nova pgina

O request da nova pgina no tem nenhum atributo definido

Nova pgina deve obrigatoriamente estar no


mesmo contexto web

No h restries quanto localizao da nova


pgina

A URL exibida no navegador continua sendo a da


pgina que originou a chamada de forward()
A URL da nova pgina deve comear com /

A URL no navegador muda para a da nova pgina


Endereo da nova pgina pode ser qualquer URL
vlida

Tabela 1. Diferenas entre redirecionamento e encadeamento

Listagem 4. mudaFluxo.jsp, exemplos de encadeamento e redirecionamento


Teste de forward e sendRedirect<br><br>
<a href=mudaFluxo.jsp?tipo=forward&flush=false>
forward vlido</a><br>
<a href=mudaFluxo.jsp?tipo=forward&flush=true>
forward invlido</a><br>
<a href=mudaFluxo.jsp?tipo=sendRedirect&flush=false>
sendRedirect vlido</a><br>
<a href=mudaFluxo.jsp?tipo=sendRedirect&flush=true>
sendRedirect invlido</a><br>
<br><br>
<%
if (true.equals(request.getParameter(flush))) {
out.println(<br>Chamando out.flush()<br>);
out.flush();
}

String tipo = request.getParameter(tipo);


if (tipo != null) {
request.setAttribute(atributo, teste);
try {
if (tipo.equals(forward)) {
RequestDispatcher dispatcher =
pageContext.getServletContext().
getRequestDispatcher(/novaPagina.jsp);
dispatcher.forward(request, response);
}
if (tipo.equals(sendRedirect)) {
response.sendRedirect(/jm12/novaPagina.jsp);
}
}
catch(Throwable t) {
out.println(Exceo: + t.getMessage() + <br>);
}
}
%>

12 Java Magazine Edio 39


jm39.indb 12

15/8/2006 18:13:06

Edio 39 Java Magazine


jm39.indb 13

13

15/8/2006 18:13:12

Recapitulando Dicas na Web

Listagem 5. usoCorreto.jsp, uso correto das tags <jsp:useBean> e <jsp:setProperty>


Exemplo do uso correto das tags:<br>
<jsp:useBean id=beanEntrada
class=jm.dicas.EntradaDadosBean scope=session/>
<jsp:setProperty name=beanEntrada property=*/>
<form>
Nome:

<input type=text name=nome


value=<jsp:getProperty
name=beanEntrada property=nome/>><br>
Email: <input type=text name=email
value=<jsp:getProperty
name=beanEntrada property=email/>><br><br>
<input type=submit value=Enviar>
</form>

class=jm.dicas.EntradaDadosBean
scope=session>
<jsp:setProperty name=beanEntrada property=*/>
</jsp:useBean>
<form>
Nome:

<input type=text name=nome


value=<jsp:getProperty name=beanEntrada
property=nome/>><br>
Email: <input type=text name=email
value=<jsp:getProperty name=beanEntrada
property=email/>><br><br>
</form>

Listagem . EntradaDadosBean.java, JavaBean utilizado nas Listagens 5 e 6


package jm.dicas;

Listagem 6. usoIncorreto.jsp, uso incorreto das tags <jsp:useBean> e <jsp:setProperty>


Exemplo do uso incorreto das tags
(valores dos textfields nunca mudam):<br>
<jsp:useBean id=beanEntrada

public class EntradaDadosBean {


private String nome;
private String email;
//... mtodos get/set
}

seria equivalente a2:


Object meuBean = (Object) pageContext.getAttribute(
meuBean, PageContext.SESSION );
if (meuBean == null) {
meuBean = new java.util.Date();
pageContext.setAttribute(meuBean, meuBean,
PageContext.SESSION_SCOPE);
}

Figura 3. Redirecionamento com Response.sendRedirect()


que o formulrio submetido. Nas submisses
seguintes, o bean j est presente na sesso e
no precisa mais ser instanciado; conseqentemente a tag <jsp:setProperty> no executada.
A soluo para o problema retirar a tag
<jsp:setProperty> do corpo de <jsp:useBean>:
<jsp:useBean id=beanEntrada
class=jm.dicas.EntradaDadosBean
scope=session/>
<jsp:setProperty name=beanEntrada property=*/>

Ou ento mudar o escopo do bean:


<jsp:useBean id=beanEntrada
class=jm.dicas.EntradaDadosBean
scope=request>
<jsp:setProperty name=beanEntrada property=*/>
</jsp:useBean>

Os exemplos nas Listagens 5 e 6 demonstram o uso correto e incorreto dessas tags (e


a Listagem 7 inclui o bean simples utilizado
por estas).

2. A especificao JSP diz que quando um


parmetro da requisio nulo ou vazio,
a respectiva propriedade no setada
atravs da tag <jsp:setProperty>. muito
comum, porm, o desenvolvedor criar cdigo supondo que essa propriedade ser
definida com o valor nulo (ou vazio), o que
mais uma vez causa bugs quando o bean
est armazenado em escopo de sesso. A
Figura 4 ilustra o comportamento da tag
<jsp:setProperty>, passo a passo, sobre o
cdigo da Listagem 6.
3. O tipo do bean a ser usado por <jsp:useBean>
pode ser definido atravs dos atributos type e
class. Embora os significados desses atributos
sejam semelhantes, eles representam conceitos ligeiramente diferentes: class define a classe
sendo instanciada, enquanto que type define
o tipo do bean, que, alm da classe do bean,
pode ser uma das suas superclasses ou uma
interface implementada por ele. Por exemplo,
o cdigo abaixo:
<jsp:useBean id=meuBean scope=session
type=java.lang.Object class=java.util.Date/>

Ou seja, o cdigo gerado tenta recuperar


um bean existente no escopo de sesso e
associ-lo a uma varivel da classe Object
(definida no atributo type). Caso o bean no
exista no escopo, uma nova instncia da classe Date (definida no atributo class) gerada e
atribuda varivel meuBean.
Quando apenas type usado, o bean precisa
obrigatoriamente estar disponvel no escopo,
seno lanada uma exceo. Por exemplo,
o seguinte trecho de cdigo:
<jsp:useBean id=meuBean scope=session
type=java.lang.Object/>

seria equivalente a:
Object meuBean = (Object) pageContext.getAttribute(
meuBean, PageContext.SESSION );
if (meuBean == null) {
throw new InstantiationException(
bean meuBean not found within scope);
}

2
O cdigo mostrado aqui parecido com o gerado pelo
compilador JSP, porm simplificado: alm do tratamento
de excees ter sido omitido, os objetos foram instanciados atravs do operador new, enquanto que o compilador
JSP usa java.beans.Beans.instantiate().

14 Java Magazine Edio 39


jm39.indb 14

15/8/2006 18:13:17

Assim que a pgina acessada, o bean instanciado, porm nenhuma propriedade setada (j que no foram passados parmetros
requisio).

Aps serem preenchidos os valores do nome e e-mail, o formulrio


submetido. No servidor, o bean j existe na sesso e no instanciado
novamente. Porm, como os valores dos parmetros nome e email so
no-nulos, as respectivas propriedades do bean so setadas.

O formulrio submetido com um novo nome, mas sem o endereo


de e-mail fornecido, ento apenas a propriedade nome ser setada

Usar a variao de <jsp:useBean> apenas


com type muito til em alguns casos; por
exemplo, quando um objeto representando um usurio criado apenas na pgina
de login e precisa ser acessado em outras
pginas. Mas preciso se ter em mente que
o tag pode causar uma exceo (se a sesso
expirar, digamos), e dessa forma ter os devidos cuidados. Uma sada seria o uso de tags
JSTL para checar a existncia do objeto na
sesso, como no cdigo seguinte:
<c:if test=${empty sessionScope.beanEntrada}>
<c:redirect url=sessaoExpirada.jsp/>
</c:if>
<jsp:useBean id=beanEntrada scope=session
type=jm.dicas.EntradaDadosBean/>

no bean que est na sesso.

Resultado final: o nome foi alterado, mas o e-mail no.

Figura 4. Exemplo de uso incorreto do tag <jsp:setProperty>

Felipe Leme
(felipeal@gmail.com)
Engenheiro de Computaco pela
UNICAMP, membro atuante das
comunidades Java brasileira e mundial,
tendo publicado artigos em revistas tcnicas e sites
internacionais e palestrado nas principais conferncias
sobre Java, alm de participar como expert no JCP e
ser committer em projetos da Apache. Atualmente
Diretor Tcnico da Voxblue (voxblue.com)
e instrutor da Globalcode.

Edio 39 Java Magazine


jm39.indb 15

15

15/8/2006 18:13:19

Byte Code

Java EE 5

Um Enterprise Edition muito mais fcil

16 Java Magazine Edio 39


jm39.indb 16

15/8/2006 18:13:45

Explorando a nova verso do


Java corporativo: anotaes,
injeo de dependncias,
novas JSRs e um exemplo
prtico no servidor open
source GlassFish

osvaLdo pinaLi doederLein

o reler meu primeiro artigo na


Java Magazine, J2EE Fundamental (Edio 1, julho de 2002),
abordando o ento recm-lanado J2EE 1.3,
pude verificar como o status da plataforma
mudou. Eram apresentados fundamentos
como containers, servidores de aplicaes
e EJB, at ento pouco familiares para
muitos desenvolvedores. Servidores J2EE
eram ferramentas caras e pesadas, e a
portabilidade ainda deixava a desejar para
os padres do Java. Alguns componentes,
como os Entity Beans, estavam francamente imaturos isso quando no j tinham
sido descartados por muitos. O artigo terminava com uma seo Web services: o
futuro, j anunciando o J2EE 1.4 (lanado
em novembro de 2003), mas apontando os
problemas de compatibilidade de padres
ainda em definio. Hoje em dia, poderamos reclamar que j existem padres de
Web Services at em demasia.

Passados quatro anos, a plataforma,


agora rebatizada Java EE, dispensa apresentaes, tendo se constitudo num componente obrigatrio do conhecimento de
qualquer desenvolvedor Java atuando no
lado do servidor (server-side). Mesmo
frameworks que correm por fora e ganharam prestgio e popularidade, como
Spring e Hibernate, tm ocupado um lugar
mais complementar do que alternativo
em relao ao Java EE. E numa exibio
surpreendente de resposta s direes
escolhidas pela comunidade, o novo Java
EE 5 adere a prticas popularizadas por
estas outras solues, como inverso de
controle, uso mais intenso de metadados,
e persistncia baseada em POJOs (Plain
Old Java Objects).
Este artigo inicia com uma discusso
geral sobre esta grande atualizao da
plataforma. Diferentemente de outros
artigos desta coluna, no entraremos em

Complexidade escalvel

comum que problemas complexos tenham


solues complexas, e as opes que parecem
mais simples s vezes no escalam com as demandas das aplicaes com mais complexidade
essencial. A plataforma J2EE foi por muito tempo
vista como canho para matar mosca: aplicaes
mais simples, sem necessidades avanadas de
integrao, escalabilidade, segurana etc., eram
mais bem servidas por concorrentes mais leves e
produtivos. Mas no deveramos ter que migrar
para outra plataforma perdendo investimentos
de cdigo, treinamento e ferramentas conforme
cada projeto for mais simples ou complexo.
Tanto o velho J2EE quanto os competidores
mais simples (ex. Ruby on Rails) exibem a falta
de uma qualidade que poderamos chamar de
escalabilidade de complexidade: a mesma
plataforma deveria comportar o desenvolvimento de uma grande gama de aplicaes, das
mais triviais at as mais sofisticadas. E recursos

avanados devem estar disponveis para quem


precisar, mas sem impor esforo de desenvolvimento extra para aplicaes com requisitos
mais modestos.
O Java EE 5 bem mais escalvel quanto
complexidade. Por um lado, quando voc tiver
problemas muito complexos para resolver, as
qualidades enterprise continuam l: todo o
poder dos EJBs, alm de segurana declarativa,
transaes distribudas, conectores, web services, JNDI, clusters etc. J aplicaes simples
sero codificadas de forma simples. No J2EE
tradicional, artefatos burocrticos acabavam
constituindo uma frao significativa do cdigo
de aplicaes de menor porte, ridicularizando
o J2EE em cenrios al mundo. Com o Java
EE 5 isso deixa de acontecer. E mesmo para as
aplicaes mais ambiciosas, a facilidade de programao do Java EE 5 dever ser sensivelmente
maior em comparao com o J2EE 1.4.

detalhe sobre APIs e funcionalidades especficas, o que seria pouco vivel devido
extenso da plataforma. Esta necessidade
ser melhor servida por artigos futuros especializados em temas como JPA (coberto
nesta edio), EJB etc. Aqui nosso objetivo
fornecer uma viso conceitual. Mas agora
assumimos que o leitor j possui familiaridade bsica com a plataforma J2EE. Assim,
podemos enfocar as novidades, e analisar
e discutir a natureza e as motivaes por
trs de cada mudana dessa atualizao
que pode mudar radicalmente sua rotina
de desenvolvimento de aplicaes Enterprise Edition. E para comear uma
explorao prtica, o quadro GlassFish:
o Java EE open source mostra como
instalar a implementao de referncia
(RI) desta plataforma, e desenvolver uma
aplicao Java EE 5 simples com o IDE
NetBeans 5.5.

Java EE 5: Produtividade Corporativa


Se o release anterior, J2EE 1.4, era a verso
dos web services, o Java EE 5 a verso da
produtividade. No por coincidncia, este
o mesmo foco do Java SE 5.0, especialmente com a nova sintaxe de anotaes.
As anotaes so o veculo principal
das melhorias de produtividade do
Java EE 5. Quer que uma classe seja um
Stateless Session Bean? Basta declarar
@Session class MinhaClasse {...}. Precisa expor
a funcionalidade de uma classe como um
web service? Use a tag @WebService. E para
conectar a um DataSource? Nada de cdigo
JNDI InitialContext, lookup(), narrow(), tratamento de excees basta usar a anotao
apropriada, como:
@Resource(name= jdbc/minhaDS)
DataSource minhaDS;

POJOs e anotaes versus descritores


O paradigma de programao do Java EE
5 d um guinada espetacular, abandonanEdio 39 Java Magazine

jm39.indb 17

1

15/8/2006 18:13:53

Java EE 5

do boa parte da burocracia do tradicional


J2EE em favor de uma opo preferencial
pela simplicidade. A programao baseada em POJOs1 fortemente suportada.
Veja algumas novas caractersticas:
Temos POJOs no lugar de implementao de interfaces. No precisam mais ser
escritos centenas de mtodos completamente vazios, como ejbActivate(), s porque
uma interface de EJB os exige.
usada a Injeo de Dependncias em
vez de aborrecidos lookups na JNDI.
As anotaes assumem o lugar de descritores XML.
H muitos comportamentos default que
evitam a necessidade de especificar opes comuns, seja com descritores ou com
anotaes. Por exemplo, um @WebMethod
(mtodo de web service) suporta anotaes
@WebParam para os parmetros, mas estas
so opcionais. Na sua falta, o container
assumir defaults bons para a maioria dos
usos (como holder=Mode.IN).
Mas ser que este paradigma de programao sempre melhor? Em relao s
anotaes, que so o instrumento fundamental do novo modelo, j as questionamos em artigos anteriores, em sees com
ttulos como Cuidados com as anotaes
e Uma crtica s anotaes. O motivo
de tanta precauo que uma reviso to
radical no processo de desenvolvimento
no deve ser abordada sem cuidado e
viso crtica.
Felizmente, com a forma que o Java EE
5 tomou, esses temores no se concretizaram. Em especial, os descritores ainda so
suportados (o que j bom por motivo de
compatibilidade) e eles tm prioridade sobre informaes declaradas por anotaes.
Isso evita que as anotaes eliminem a
flexibilidade garantida pelos descritores.
Por exemplo, numa classe persistente voc
pode usar uma anotao @Table(name=TAB)
para determinar que os objetos da classe
sero persistidos na tabela TAB. Isso
muito conveniente, mas o que acontece se
um dia o nome da tabela tiver que mudar?
No J2EE tradicional (EJB/CMP), bastaria
alterar o descritor. No Java EE 5 poderamos alterar a anotao @Table, mas isto no
obrigatrio. Podemos tambm criar um
descritor e informar nele o nome atualizado da tabela. No caso de redundncia

(mesma informao em anotaes e no


descritor), o container dar preferncia ao
descritor. Preserva-se assim a flexibilidade
dos descritores e s h o trabalho de
manipul-los quando isso for realmente
necessrio.
Mas note que estes casos so a minoria.
Na prtica, as oportunidades de adaptar aplicaes a mudanas no ambiente
externo mexendo apenas no descritor s
costumam ocorrer em casos triviais, como
mudanas nos nomes JNDI de DataSources
ou filas de JMS, causadas talvez por uma
migrao de ambiente (ex.: homologao
para produo). E mesmo nestes casos, a
indireo proporcionada pelas resource references (J2EE 1.3+) j evita a necessidade de
alteraes at nos nomes JNDI internos,
usados nos descritores e no cdigo.
Observamos que existem algumas caractersticas, consideradas estruturais,
que se definidas por anotaes no so
redefinveis por descritores. Por exemplo,
novamente com EJBs, anotaes como
@Stateless e @Stateful denotam os diferentes
tipos de Session Beans. Mas se uma classe
for anotada com @Stateless, no ser possvel, pelo descritor, transform-la num EJB
Stateful. O motivo simples: a diferena
entre um bean Stateless e um Stateful no
est apenas no descritor beans Stateful,
presumivelmente, mantm algum estado
interno, enquanto beans Stateless no o
fazem, portanto transformar um tipo no
outro exige alteraes de cdigo de qualquer maneira.

Anotaes versus Orientao a Objetos


As anotaes constituem uma alternativa a tcnicas mais tradicionais na
programao OO, como herana ou
design patterns. O J2EE tradicional,
como sabemos, fortemente baseado em
herana. Um Entity Bean, por exemplo,
uma classe que implementa a interface
javax.ejb.EntityBean, o que obriga a definir
sete mtodos (como ejbActivate(), ejbLoad()
etc.), que na sua maioria so desnecessrios para a maior parte dos beans. H
certamente algo errado numa arquitetura
que obriga as aplicaes a definir at sete
mtodos vazios para cada entidade de
negcio. (Lembrando que em Java, nem
sempre uma boa idia usar classes-base
que forneam implementaes default

destas interfaces de framework, pois isto


queima a oportunidade nica de herana
de implementao2).
Em oposio rigidez da herana, as
anotaes enriquecem uma classe com
comportamentos de forma muito mais
granular. H anotaes por tipo, atributo,
mtodo, e at por parmetro ou varivel
local. Assim, se o seu bean realmente precisa executar algum cdigo especial aps
a ativao, basta implementar um mtodo
anotado por @PostActivate.
As anotaes possuem uma vantagem
crucial: so estaticamente tipadas. Podem
ser verificadas e validadas de forma
offline, o que evita toda uma categoria
de bugs. O javac s verificar a correo
sinttica das anotaes, por exemplo reclamando se voc usar uma propriedade
inexistente numa anotao; no reportar
erros semnticos, ex.: uma propriedade
@EJB.beanInterface com um valor que no
seja uma interface local/remota de EJB.
Mas as ferramentas de validao includas
em IDEs com suporte a Java EE e em servidores de aplicaes podero fazer estas
validaes no momento da implantao
ou antes, evitando que o bug fique oculto
e estoure somente quando a aplicao j
estiver em operao.

Injeo de Dependncias
A persistncia de POJOs, no estilo do
Hibernate, tem chamado ateno como
a grande novidade que o Java EE 5 pega
emprestada de outros frameworks. Mas
no menos importante a Injeo de Dependncias (ID). Para compreender a idia
fundamental da ID, podemos classificar as
1
Plain Old Java Objects, algo como bons e velhos objetos Java. uma definio por excluso: objetos que no
so obrigados a herdar/implementar nenhuma interface
imposta por uma API. Tambm se usa POJI para interfaces
que no precisam herdar nenhuma outra interface. Um
framework que suporta POJOs, no lugar de herana, utiliza mecanismos mais fracamente acoplados, como anotaes ou arquivos de configurao, para interagir com
seus objetos.
2
A exceo fica por conta de casos simplistas como os
listeners da AWT/Swing, ex.: MouseListener, acompanhados
por classes adapter, como MouseAdapter, que facilitam a
criao de inner classes que implementam somente um
dos mtodos exigidos por listeners que agrupam vrios
eventos. Como tratadores de eventos so simples e raramente se beneficiariam de herana de implementao,
nestes casos no faz mal usar a herana nica para derivar do adapter. O mesmo no pode ser dito de EJBs que
implementam complexas regras de negcio.

18 Java Magazine Edio 39


jm39.indb 18

15/8/2006 18:13:54

aplicaes em trs graus de evoluo:


1. Todas as dependncias (de configuraes e de cdigo) esto amarradas
no cdigo. Neste caso, mudar qualquer
coisa exige alterar cdigo, recompilar e
reiniciar a aplicao. o grau zero, hoje
em dia s encontrado em aplicaes de
iniciantes ou em cdigos descartveis,
como prottipos.
2. Dependncias de configurao esto
fora do cdigo. A aplicao parametrizada por informaes carregadas a partir
de arquivos, bancos de dados, diretrios
ou outros locais externos. A alterao
destes parmetros pode ser feita por um
no-desenvolvedor, no exige mudanas
no cdigo e talvez nem indisponibilidade
do sistema. Por outro lado, dependncias
de cdigo continuam amarradas. Em
qualquer circunstncia onde a classe A
precisa utilizar a classe B, isto feito com
cdigo, ex.:
class A {
void m() {
B b = new B();
// usa b...
}
}.

Alguns design patterns, como Abstract


Factory e Service Locator, ajudam a encapsular e concentrar num s lugar a deciso
de quais objetos instanciar ou utilizar, e
permitem aos dependentes de um componente depender apenas de interfaces
abstratas. Mas isso no uma soluo
completa, pois as dependncias de cdigo
continuam sendo resolvidas por cdigo,
ainda que de forma mais elegante e sem
repeties. neste ponto de evoluo que
se encontra a maioria das aplicaes atuais
bem escritas.
3. Uso de Injeo de Dependncias. As
dependncias de cdigo no so responsabilidade do cdigo da aplicao, e sim
de um runtime de Injeo de Dependncias, que injeta em cada objeto-cliente
os recursos dos quais ele depende. As
regras que determinam como esta injeo
feita qual classe instanciar e com quais
parmetros ficam em metadados externos, que so manipulados pelo runtime
de ID.
O exemplo mais comum de Injeo de
Dependncias, em aplicaes Java EE,

o da comunicao com EJBs. Se voc j


programou com EJB, j deve ter visto ou escrito muito cdigo como o da Listagem 1.
Neste exemplo, na camada de apresentao
de uma aplicao (no caso, uma GUI web
implementada com o Struts), precisamos
invocar um Session Bean que executa o
login do usurio. Todo o cdigo destacado
em negrito no passa de burocracia do
J2EE. Veja quanta coisa precisamos fazer
s para invocar um simples mtodo login()
no bean remoto:
Configurar a conexo com a JNDI (simplificado, neste cdigo pode ser preciso
setar propriedades para o InitialContext).
Fazer um lookup na JNDI.
Tratar possveis erros deste lookup.
Como o que retornado pelo lookup
na verdade a interface Home, deve-se
invocar um dos seus mtodos create() para
gerar a referncia ao Session Bean que
realmente desejamos.
Se estivermos usando uma interface
remota, ainda precisamos usar a operao
narrow() ao invs de um simples typecast do
Java.
Finalmente, como estes lookups so
relativamente custosos, aplicaes preocupadas com o desempenho devem tentar
reduzi-los, por exemplo com a estratgia
de cache e inicializao sob demanda
ilustrada com o mtodo lookupLoginServer()
e o atributo loginServer.

Por essas e outras, os nicos desenvolvedores que acham o EJB simples costumam
ser aqueles que j utilizaram geraes anteriores de componentes distribudos, como o
COM/COM+ da Microsoft ou o CORBA da
OMG. H justificativas para expor algumas
das etapas que descrevemos, mas nem sempre. Por exemplo, nunca entendi a utilidade
da interface Home para Stateless Session
Beans, que s podem ter um mtodo create(),
sem parmetros e cujas invocaes retornam sempre a mesma referncia.
Mais grave nos obrigar a escrever
cdigo que quase nunca necessrio.
Por exemplo, quanta gente trata excees
como NamingException, com um cdigo de
recuperao de falha especfico a cada
local de ocorrncia? Quase ningum; o que
todo mundo faz tratar de forma genrica
estas excees, talvez encapsulando-as em
outra exceo que o framework utilizado
sabe tratar (como uma ServletException para
aplicaes web). Da o framework se encarrega da exceo, cancelando a operao
em andamento, roteando a GUI para uma
pgina de erro configurvel, etc. Mas se
para deixar que o framework ou o container trate excees, no deveramos ter
que escrever centenas de blocos try/catch
exatamente iguais, nem saber que existe
a NamingException! Alis, nem deveramos
precisar lidar com a JNDI, ou as interfaces
Home, exceto em casos excepcionais.

Listagem 1. Cdigo de exemplo numa Web Application J2EE que acessa um servidor EJB.
public class LoginAction extends DispatchAction // usando Struts
protected LoginServer loginServer;
protected synchronized LoginServer lookupLoginServer ()
throws ServletException
{
if (login == null) try
{
InitialContext ctx = new InitialContext();
Object obj = ctx.lookup(ejb/session/LoginServer);
LoginServerHome home = (LoginServerHome)
PortableRemoteObject.narrow(obj, LoginServerHome.class);
loginServer = home.create();
}
catch (final NamingException e) { throw new ServletException(e); }
return login;
}
public ActionForward doLogin (final ActionMapping mapping, final ActionForm form,
final HttpServletRequest request, final HttpServletResponse response)
throws ServletException
{
LoginServer loginServer = lookupLoginServer();
LoginForm f = (LoginForm)form;
boolean ok = loginServer.login(f.getUser(), f.getPassword());
// ... etc.
}
}

Edio 39 Java Magazine


jm39.indb 19

19

15/8/2006 18:13:54

Tutorial

Java EE 5

GlassFish:

O Java EE 5
open source

Java EE 5 um padro formal do JCP, e logo ter muitas implementaes


concorrentes. Mas vale a pena dar uma ateno privilegiada para uma
destas implementaes, o projeto GlassFish. Trata-se do mais novo servidor
Java EE 5 de fonte aberto. Alis, o nico por ora, j que o JBoss, apesar do pioneirismo
com o EJB 3.0, ainda no parece perto de finalizar o suporte para a Java EE 5 como
um todo, e o Geronimo provavelmente demorar muito mais.
O GlassFish foi baseado em cdigo doado pela Sun, sendo a base
do Sun Java System Application Server 9 (tambm conhecido
como Java EE SDK 5), que a implementao de referncia (RI)
do Java EE 5. Tanto a verso open source quanto a da Sun so
certificadas. O GlassFish vem sendo desenvolvido como um
projeto do portal java.net, onde j angariou bastante suporte
da comunidade open source. Resta saber se isso se traduzir em
ganhos significativos de mercado para este servidor, que at hoje, a
despeito da liderana da Sun no desenvolvimento da tecnologia J2EE /
Java EE e fortes resultados recentes de benchmarks SPEC jAppServer
2004, tem amargado pouca popularidade, apesar de gratuito para
uso comercial (um apelo que se mostrou insuficiente, j que o
JBoss tanto gratuito quanto open source).

Testando o Java EE 5 com o Glassfish


Para exercitar um pouco os novos recursos do Java
EE 5 apresentados neste artigo, veremos uma aplicao al mundo de duas camadas, com uma
interface web JSF que invoca um Session Bean
executando no GlassFish.
Para este exerccio, utilizaremos o IDE
NetBeans 5.5. Usurios do Eclipse 3.2 /
WTP 1.5 tambm podem desenvolver

para o GlassFish, utilizando o plug-in disponvel


em glassfishplugins.dev.java.net, mas o WTP (e
verses anteriores do NetBeans) ainda no possui
suporte especfico para o Java EE 5.
O NetBeans pode ser baixado numa verso que
j inclui o servidor Java EE, que desta forma prconfigurado na instalao, ou se pode instalar o
Glassfish parte. Neste caso, ser preciso ir em
Tools > Server Manager > Add Server e criar um novo
registro do tipo Sun Java System Application Server, entrando com seus parmetros de instalao
(diretrio, login de administrador etc.). (Este mesmo tipo de servidor funciona com o Java EE SDK
5.0 / SJSAS 9 e com o Glassfish; para simplificar, nos
referiremos ao servidor como apenas GlassFish.)
Agora v na janela Runtime do NetBeans e, sob
Servers, encontre o servidor GlassFish e comande
Start in Debug Mode.
Em File | New Project, selecione Enterprise / Enterprise Application na primeira pgina, e preencha
a segunda conforme a Figura Q1 (modificando
claro os drives e diretrios), selecionando o
GlassFish e criando um mdulo EJB e um mdulo
web. O NetBeans criar trs projetos, para os mdulos EJB, WAR e EAR.
No projeto EJB, acione New > Session Bean, e crie
um EJB com nome Alo, tipo Stateless e interface
apenas Remote. O assistente ir criar os fontes da
interface AloRemote e da implementao AloBean.
Aps customizarmos estes fontes, eles devero
ficar como nas Listagens Q1 e Q2.
Examinando o projeto, voc ver que temos
apenas estes dois arquivos .java, e alm disso
dois descritores sun-ejb-jar.xml e MANIFEST.MF.
Mas ambos esto vazios; foram criados apenas
por convenincia. Apague estes dois arquivos do
projeto, para comprovar o que dissemos sobre
serem opcionais.
No projeto do EAR, acione Deploy Project. O
NetBeans ir executar a compilao dos mdulos
dependentes, o empacotamento do EAR, e sua

Figura Q1. Criando o projeto de exemplo.

20 Java Magazine Edio 39


jm39.indb 20

15/8/2006 18:15:03

instalao no servidor GlassFish que j havamos


deixado executando.
Vamos agora interface web com a JSF. Nas
propriedades do projeto WAR, na categoria
Frameworks, comande Add / Java Server Faces, aceitando as opes default; isto configura o projeto
para suportar a JSF. Alm disso, como o projeto
WAR precisar utilizar a interface AloRemote do
projeto EJB, voc deve configurar o classpath do
projeto WAR: em Libraries / Add Project, selecione
o diretrio do projeto EJB.
Nossa GUI ter apenas uma pgina, que invoca o
Session Bean e exibe a mensagem retornada. Para
fazer esta invocao, vamos usar um managed
bean. Na JSF, managed beans so classes equivalentes s Forms do Struts (mas com a vantagem
de serem POJOs), normalmente contendo dados
(modelo) manipulados pelas telas (views). O nosso
managed bean s ter uma propriedade virtual
cujo getter invoca o Session Bean.
Crie o managed bean com New > File/Folder
> Web > JSF Managed Bean. Modifique o nome
da classe para Alo, e aceite os defaults para
as demais opes. Finalmente, edite o cdigo
gerado para ficar como a Listagem Q3. Observe
o uso de Injeo de Dependncias para conectar
com o Session Bean. (O assistente de criao
de managed beans til principalmente por
registrar o bean na configurao da JSF, o facesconfig.xml).
A ltima etapa criar a pgina index.jsp, conforme a Listagem Q4. Pginas JSF so basicamente
JSPs que utilizam as taglibs da JSF; neste caso, utilizamos as tags (ou componentes) view, que deve
englobar todo o contedo da pgina gerenciado

pela JSF, e outputText, que exibe dados (equivalente


desta funcionalidade. Entre o que utilizamos,
est a arquitetura de componentes distribudos
<c:out> da JSTL). O argumento da nossa outputText
do EJB: seria possvel fazer o deploy dos mdulos
uma expresso EL que obtm a propriedade alo
EJB e web em servidores separados e a aplicao
do managed bean.
funcionaria da mesma forma.
Para executar o exemplo, faa o deploy do
A Figura Q2 mostra o ambiente de desenvolprojeto principal (o EAR), e acesse com o browser
vimento do NetBeans 5.5, onde podemos ver a
o endereo: http://localhost:8080/AloEE5-war/
edio de JSP/JSF, o runtime e os logs do servidor
faces/index.jsp
Glassfish, e a estrutura dos projetos AloEE. Como
Sendo que 8080 a porta HTTP default do Glasa especificao e as implementaes de Java EE
sFish, AloEE5-war o nome do projeto do mdulo
5 ainda so muito recentes, o suporte de IDEs
Web, faces/ o padro de URL default para acionar
ainda preliminar (o NetBeans 5.5, no momento
o controller da JSF (equivale ao *.do da Struts),
em que escrevo, ainda est em beta). Mas at em
e index.jsp a nossa pgina. O resultado do teste
funo das simplificaes do Java EE 5, a tendncia
no ser surpreendente a mensagem Al, Java
dependermos cada vez menos de ferramentas
EE 5! exibida no seu browser. O surpreendente,
elaboradas.
em comparao com verses anteriores do J2EE,
a simplicidade do
cdigo, com menos de
40 linhas (ou menos
de 50 se contarmos
o faces-config.xml ).
Pode no parecer assim to pouco para
um programa al
mundo, mas note que
o programa executa
num container Java
EE 5, que disponibiliza s aplicaes um
formidvel volume
de funcionalidades
ainda que isso possa
ser difcil de perceber
para o iniciante, pois
Figura Q2. O NetBeans 5.5, durante o desenvolvimento de uma aplicao Java EE 5.
o exemplo usa pouco

Listagem Q1. Interface remota do stateless session bean Alo.

import javax.ejb.EJB;

package aloee;

public class Alo {


private @EJB AloRemote aloServer;
public String getAlo () {
return aloServer.alo();
}
}

import javax.ejb.Remote;
@Remote public interface AloRemote {
String alo ();
}

Listagem Q2. Implementao do stateless session bean Alo.

Listagem Q4. Pgina de teste da JSF.

package aloee;

<%@ taglib uri=http://java.sun.com/jsf/html prefix=h %>


<%@ taglib uri=http://java.sun.com/jsf/core prefix=f %>

import javax.ejb.Stateless;
@Stateless public class AloBean implements aloee.Alo {
public String alo () {
return Al, Java EE 5!;
}
}

Listagem Q3. Managed Bean para a tela de entrada.


package aloee;

<html>
<head>
<title>Al, Mundo</title>
</head>
<body>
<f:view>
<h:outputText value=#{Alo.alo}/>
</f:view>
</body>
</html>

Edio 39 Java Magazine


jm39.indb 21

21

15/8/2006 18:15:11

Java EE 5

para resolver esses problemas que


surgiram design patterns como o Service
Locator, que j comentamos. Estes patterns
reduzem o problema podemos ter todos
os lookups de EJBs numa nica classe, e
no em dezenas de classes Action mas
no eliminam o problema totalmente.
A soluo definitiva proposta pelo
sistema de Injeo de Dependncias, cuja
implementao no Java EE 5 nos permite
escrever cdigo como o da Listagem 2,
na qual foram destacadas as mudanas
em relao verso anterior. Observe que
no precisamos mais nos preocupar com
JNDI, lookup, excees, interfaces Home,
converses de interfaces remotas, ou mesmo otimizaes para reduzir os lookups.
S precisamos declarar uma varivel (local
ou atributo) que seja do tipo da interface
de Session Bean desejada, e complementar
esta declarao com a anotao @EJB. Esta
anotao simples: basta informar o nome
JNDI do bean desejado, e o runtime de ID
faz o resto.
O cdigo resultante muito menor. At
mesmo o mtodo doLogin() foi simplificado.
O funcionamento bsico da ID simples:
quando o artefato que contm a dependncia (no caso, a LoginAction3) for criado, o container far o lookup, a invocao do create()
etc. Se o lookup falhar, ocorrer um erro
impedindo a inicializao da Action, e este
erro ser tratado pelo framework web.
Existem variantes neste comportamento,
que recuperam muito da flexibilidade que
voc poderia imaginar ter perdido na transio da Listagem 1 para a Listagem 2:
Ao invs de anotar com @EJB o atributo
loginServer, poderamos utilizar esta anotao num setter (setLoginServer(LoginServer)),
que seria invocado pelo container. Isto nos
daria maior grau de controle sobre sua
inicializao.
A anotao @EJB suporta outras pro-

priedades, permitindo escolher a interface


local ou remota, ou o nome lgico (java:
comp/env) ou o nome proprietrio do container EJB (mapped name).
H anotaes para interagir com o
ciclo de vida do objeto sujeito Injeo
de Dependncias. Por exemplo, poderamos criar um mtodo com a anotao
@InjectionComplete, que seria ento invocado
uma nica vez, aps a inicializao de
todos os recursos que usam Injeo de
Dependncias na sua classe.

A Injeo de Dependncias no Java EE 5


Quem j conhece a Injeo de Dependncias em frameworks como Spring,
PicoContainer e outros, poder se perguntar se o suporte a ID do Java EE 5 melhor
ou pior. As anotaes de ID utilizadas
pelo Java EE 5, especificadas pela JSR-250
(Anotaes Comuns para a Plataforma
Java), so tambm includas no Java SE
6. Isso abre a possibilidade de melhorias
de APIs fundamentais e at otimizaes
da JVM, para tirar proveito da Injeo de
Dependncias, ou torn-la mais eficiente
e poderosa.
Por outro lado, sistemas de ID mais maduros como o Spring so mais poderosos.
Por exemplo, o Spring pode injetar objetos arbitrrios com construo complexa
(algo que pode exigir arquivos XML bem
grandes...), enquanto o mecanismo do Java
EE 5 mais orientado a objetos publicados
na JNDI. Entretanto, a nova especificao
torna obsoletos os sistemas anteriores de
ID, pelo menos para as funcionalidades
em comum.
Uma maneira de ver essa diferena que
a JSR-250 oferece um suporte a ID menos
radical, mais orientado ao desacoplamento
entre cdigo de aplicao e recursos de
deployment (como DataSources, filas etc.),
e entre mdulos numa arquitetura com-

Listagem 2. Injeo de Dependncias no Java EE 5.


public class LoginAction extends DispatchAction // usando Struts
@EJB(beanName=ejb/session/Login) protected LoginServer loginServer;
public ActionForward doLogin (final ActionMapping mapping, final ActionForm form,
final HttpServletRequest request, final HttpServletResponse response)
{
LoginForm f = (LoginForm)form;
boolean ok = loginServer.login(f.getUser(), f.getPassword());
// ... etc.
}
}

ponentizada (neste caso, a ID configura


referncias para EJBs ou web services).
J frameworks especializados como o
Spring incentivam e permitem o uso de
ID intenso, de alta granularidade. Neste
estilo, praticamente nenhum recurso
inicializado em cdigo, coisa que para
alguns desenvolvedores parece ser uma
maravilha e para outros um excesso ou
abuso da tcnica. Assim, podemos arriscar
que o Java EE 5 satisfar s necessidades de
ID da maioria dos desenvolvedores, mas
os adeptos mais radicais da tcnica tero
que avaliar se preferem continuar usando
algo como o Spring4, ou se preferem moderar para ter os benefcios de escrever
aplicaes puro-Java EE.

Os componentes do Java EE 5
Nada menos que 21 JSRs separadas, que
podemos ver na Tabela 1, contribuem
diretamente para o Java EE 5. Novas funcionalidades so poucas, mas importantes:
a Java Persistence API (que sucede os EJB/
CMP) a nica API totalmente nova. Alm
disso, temos a incorporao de APIs anteriormente independentes, como a StAX e
a JAXB, e atualizaes de muitas outras. A
mudana mais sensvel ao programador,
que a introduo de anotaes para facilitar o uso de muitas APIs, d uma cara
de novidade, mas por si s no cria novas
funcionalidades s permite fazer com
anotaes as mesmas coisas que podamos
e continuamos podendo fazer invocando
as APIs tradicionais.
Verses do Java EE e SE sempre compartilham algumas novas APIs, e cada verso
do Java EE depende da verso anterior
mais recente do Java SE, ambas tradicionalmente compartilhando o mesmo nmero.
O Java EE 5 depende do Java SE 5. Mas as
verses subseqentes do Java SE sempre
incorporam algumas APIs introduzidas
inicialmente no Java EE. O Mustang (Java
SE 6) um exemplo disso, integrando as
3
Este exemplo fictcio, pois a ID s pode ser usada em
classes que so gerenciadas pelo container, o que incluiria uma Servlet, mas no uma Action da Struts (que no
faz parte do Java EE). Mas confiamos que verses prximas de frameworks populares como a Struts suportaro
integrao com o Java EE, dando suporte ID nos seus
artefatos.
4
Note que estes frameworks podem oferecer outras
funcionalidades alm de ID por exemplo, no Spring, temos os mdulos de AOP e Web Flow.

22 Java Magazine Edio 39


jm39.indb 22

15/8/2006 18:15:12

APIs de web services e XML agora incorporadas ao Java EE 5.


Um fenmeno importante que podemos
observar no Java EE 5 o refactoring
de algumas especificaes. Primeiro foi
a EL (Expression Language). Embora o
padro JSP j possusse uma linguagem de
expresses, a JSF criou uma nova e mais
poderosa, parecida mas no totalmente
compatvel com a da JSP. Isso confundiu
os desenvolvedores e causou problemas
para a mistura de ambas as tecnologias em
uma mesma aplicao. A JSF tambm tinha
outras incompatibilidades com a especificao JSP, gerando pginas incorretas para
certas combinaes de funcionalidades.
Estes problemas agora foram resolvidos
pelas ltimas verses: temos uma nova EL
unificada que dever servir igualmente s
necessidades da JSP e da JSF, e talvez de
outros frameworks. (Minha opinio que
esta funcionalidade fundamental, e com
as melhorias introduzidas pela nova EL,
deveramos pensar em abandonar alternativas como a OGNL, usada no Tapestry
e no WebWork.)
O segundo caso a Java Persistence API
(JPA). Alm do suporte a POJOs e anotaes, igualmente importante o fato de a
nova API de persistncia do Java EE 5 ser
independente da tecnologia EJB. A JPA
definida num documento isolado e num
pacote prprio (javax.persistence), e pode ser
utilizada tambm na plataforma Java SE
(o artigo Persistncia no Java EE nesta
edio mostra um exemplo completo).
um grande contraste com a especificao
EJB/CMP, que obriga a aplicao a suportar o peso de um container EJB e dos
Entity Beans.

EJB 3.0
Se existe um patinho feio na histria do
J2EE, sem dvida a tecnologia EJB, em
especial os Entity Beans, acusados de baixa
eficincia, alta complexidade e dificuldade
de uso. Por outro lado, os Session Beans
foram um sucesso. Com eles, obteve-se um
excelente equilbrio entre a sofisticao e
o desempenho do CORBA, a simplicidade
do RMI, e as vantagens de baixo acoplamento do COM/COM+. Os EJBs tambm
implementam facilidades de controle declarativo de segurana e de transaes, alta
integrao entre todo o stack de servidor

JSR

Descrio

JSR-244: Java EE 5

Especificao guarda-chuva da plataforma Java EE 5.

Java SE?
-

JSR-250: Anotaes Comuns


para a Plataforma Java

Anotaes compartilhadas pelo Java SE 6 e Java EE 5.

JSR-181: Anotaes para Web


Services

Especifica as anotaes utilizadas pela JAX-WS 2.0.

JSR-224: JAX-WS 2.0

Novo agrupamento de APIs para web services, sucedendo a


antiga JAX-RPC. Suporta padres de web services como SOAP
1.2 e WSDL 1.2, e binding pela JAXB 2.0.

JSR-222: JAXB 2.0

Mapeamento automtico entre objetos Java e XML. Agora


dirigido por anotaes, otimizado com o uso da StAX (JSR-173),
e com um runtime portvel.

JSR-173: StAX

Nova API para parsing de XML no estilo streaming (ou pull),


mais eficiente que SAX (push) ou DOM.

JSR-220: EJB 3.0

Arquitetura de componentes com funcionalidades enterprise


(distribuio, segurana, transaes etc.). A persistncia agora
uma seo em separado, e introduz a Java Persistence API 1.0
(verses futuras tero JSR prpria).

No

JSR-252: Java Server Faces 1.2

Toolkit orientado a componentes para criao de GUIs para


web. No possui muitas novas funcionalidades, mas traz um
alinhamento com a JSP, especialmente atravs da nova linguagem de expresses (EL) unificada.

No

JSR-245: JSP 2.1

No possui muitas novas funcionalidades, exceto pela nova


Expression Language, que agora especificada em separado
(na mesma JSR, mas verses futuras tero JSR prpria).

No

JSR-52: JSTL 1.2

o Maintenance Release 2 da mesma JSR da JSTL 1.0 e 1.1,


contendo s correes.

No

JSR-154: Servlet 2.5

o Maintenance Release 1 da mesma JSR da Servlet 2.4, contendo s correes.

No

JSR-54: JDBC 3.0

Mesma verso do J2EE 1.4. O plano era incluir no Java EE 5 a


JDBC 4.0 (JSR-221), mas devido a atrasos, a nova JDBC foi reagendada para o Java SE 6 e verses futuras do Java EE.

JSR-919: JavaMail 1.4

Atualizao da API para e-mail, com muitas novas funcionalidades e melhorias de desempenho.

No

JSR-925: JavaBeans Activation


Framework 1.1

Pequena atualizao da API que estende os JavaBeans com


suporte a handlers ativados conforme tipos MIME. Usada tradicionalmente pela API JavaMail, e agora tambm pela JAX-WS.

JSR-115: JACC 1.1

Maintenance Release 1 da API para provedores de autorizao.

No

JSR-45: Debugging para


Outras Linguagens

Mesma verso do J2EE 1.4. Permite a depurao de cdigos


no-Java que gerem bytecode, por exemplo JSP e SQLJ.

No

JSR-914: JMS 1.1

Mesma verso do J2EE 1.4.

No

JSR-907: JTA 1.1

Maintenance Release 1 da API para transaes.

No

JSR-112: JCA 1.5

Arquitetura de conectores para sistemas de informao (EIS)


no-Java. Mesma verso do J2EE 1.4.

No

JSR-88: Java EE Application


Deployment 1.2

Maintenance Release 2 do padro de APIs e descritores que


permitem o deployment portvel de aplicaes Enterprise.

No

JSR-77: Java EE Management 1.1 Maintenance Release 1 da API para gerenciamento de servidores.

No

Tabela 1. JSRs componentes do Java EE 5.


Edio 39 Java Magazine

jm39.indb 23

23

15/8/2006 18:15:12

Java EE 5

de aplicaes (ex.: uma mensagem SOAP


chega num Message-Driven Bean, onde
automaticamente mapeada, verificaes
de segurana so feitas, uma transao
XA criada etc.).
Este artigo no teria espao para tratar
igualmente todas as funcionalidades do
Java EE 5, mas basta dizer aqui que outros
recursos do EJB tambm so envenenados por Injeo de Dependncias e por
anotaes como @SecurityRoles, @Interceptor,
@MessageDriven etc.

A Java Persistence API (JPA)


Qual a nova prtica recomendada para
aplicaes Java EE que acessam bancos de
dados? A mesma que muita gente, fugindo dos Entity Beans, j vinha praticando
h anos: usar s Session Beans (para a
comunicao remota, controle de transaes, segurana etc.), criar uma camada
de POJOs para as entidades, e persisti-los
com uma ferramenta como o Hibernate. A
diferena que agora voc pode substituir
a API do Hibernate pela JPA, que funciona
da mesma maneira, mas um padro do
Java EE. E pode esquecer dos DAOs, pois
a persistncia direta de POJOs dispensa
cdigos de converso de/para objetos
exigidos pela persistncia, e o cdigo de
persistncia que voc ter que escrever
to pouco que no justifica encapsul-los
numa camada de DAOs.
A Listagem 3 apresenta um exemplo
completo de EJB 3.0 e da Persistence API.
O cdigo simples, e alm disso familiar
para quem j usou o Hibernate. A classe
EntityManager faz as vezes da classe Session
do Hibernate, sendo at mais fcil de usar
no precisamos implementar uma Factory para ler a configurao, instanciar a
Session, garantir que cada thread use sempre a mesma Session etc. So as vantagens
da integrao com o container Java EE, e
claro, da Injeo de Dependncias. Note
que o mtodo EntityManager.find() genrico,
retornando o objeto j com o tipo correto, o
que dispensa o typecast que precisaramos
com o Session.get() do Hibernate.
O cdigo da Listagem 3 s no constitui
uma aplicao completa porque tambm
precisamos de um descritor de unidade
de persistncia (persistence.xml). Bastaria
ento reunir estas classes e o descritor num
arquivo .ear, e instal-lo no container.

Aproveite para observar, neste exemplo


concreto, outras simplificaes do EJB
3.0 que j mencionamos: nada de interfaces Home, nem excees RemoteException
(mesmo ao usar a interface remota), nem
herana de interfaces do framework, e
como veremos, um empacotamento mais
simples.
As especificaes CMP e CMR so agora desaprovadas (deprecated); no haver mais evoluo
destas tecnologias, e implementaes futuras (talvez a partir do Java EE 6) no tero que suport-las
para obter certificao. Note que o pacote javax.ejb
define anotaes para Session Beans (@Stateful e
@Stateless) e MDBs (@MessageDriven), mas nenhuma
anotao para Entity Beans. A minha interpretao que alm dos CMPs, os prprios Entity Beans
esto marcados para morrer num release futuro
do Java EE. Alguns podem ficar confusos, pois a
Persistence API possui uma anotao @Entity que
denota entidades persistentes; mas esta anotao no tem qualquer relao com Entity Beans.
Resumindo, se voc est na fase de prospeco

de um novo projeto que precisa de persistncia


objeto-relacional, recomendo pensar bem antes
de decidir usar os j obsoletos Entity Beans, seja
com BMP ou com CMP.

Qual a relevncia da JPA para os adeptos de outras solues (no-EJB) de persistncia? Nenhum sistema O/R ser ideal
para todas as aplicaes e a concorrncia
deve continuar existindo, mas creio que a
JPA tende a se impor como um forte padro, ao unificar o status de API oficial do
Java EE 5 com qualidades de facilidade de
uso e compatibilidade com o Java SE (antes
exclusividades do JDO, Hibernate e outras
solues). At mesmo a API do popular
Hibernate deve perder terreno; o projeto j
oferece uma implementao (hoje em beta)
da Persistence API, o Hibernate Entity
Manager (HEM). O HEM uma casca
que implementa a nova API padronizada
pela JSR-220, mas que possui no ncleo o
runtime tradicional do Hibernate5. Pode

Listagem 3. Uma aplicao EJB 3.0 completa, com persistncia e Session Bean.
// Entidade persistente simples
import
import
import
import
import

java.io.Serializable;
javax.persistence.Entity;
javax.persistence.GeneratedValue;
javax.persistence.GenerationType;
javax.persistence.Id;

@Entity public class Usuario implements Serializable {


private Long id;
private String nome;
private String senha;
@Id @GeneratedValue(strategy=GenerationType.AUTO)
public Long getId ()
{ return id; }
public void setId (Long id)
{ this.id = id; }
public String getNome ()
{ return nome; }
public void setNome (String nome)
{ this.nome = nome; }
public String getSenha()
{ return senha; }
public void setSenha (String senha) { this.senha = senha; }
}
// Interface remota do Session Bean
import javax.ejb.Remote;
@Remote public interface LoginServer {
Usuario find (Long id);
}
// Session Bean que utiliza a entidade persistente
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Stateless public class LoginServerBean implements LoginServer {
@PersistenceContext EntityManager em;
public Usuario find (Long id) {
return em.find(Usuario.class, id);
}
}

24 Java Magazine Edio 39


jm39.indb 24

15/8/2006 18:15:14

Edio 39 Java Magazine


jm39.indb 25

25

15/8/2006 18:15:18

Java EE 5
ser usado em qualquer servidor Java EE
5 que suporte EJB 3.06 e at sem servidor
algum, em aplicaes Java SE 5.

Empacotamento
Uma das melhorias de facilidade de
uso mais discretas do Java EE 5, mas nem
por isso pouco importante, est nos seus
padres de pacotes para deployment, os
arquivos EAR, WAR e outros, que tradicionalmente exigiam uma estrutura bastante
complexa.
A estrutura bsica continua existindo.
Por exemplo, uma enterprise application
continua sendo empacotada num arquivo
EAR, dentro do qual pode-se ter arquivos
JAR com os EJBs, um folder META-INF com
descritores e assim por diante. As melhorias
so duas. Primeiro, os descritores tendem a
ser bem menores (e at opcionais), graas
ao novo modelo de anotaes + POJOs +
defaults. Segundo, no mais preciso declarar obviedades ou informar a mesma coisa
duas vezes o Java EE aprendeu a seguir o
princpio DRY (dont repeat yourself).
Um bom exemplo disso a configurao
de JARs utilitrios, que so colocados na
pasta /lib de um EAR, mas antigamente
isso no era suficiente: era preciso declarar
todos os JARs no META-INF/MANIFEST.
MF, na diretiva Classpath. Agora nada disso
necessrio o container ir detectar todos
os arquivos lib/*.jar e inclu-los no classpath
do mdulo EAR.
Aplicaes web (WAR) que usem somente
JSP e tecnologias relacionadas como JSTL,
mas no servlets, no precisam de nenhum
descritor (WEB-INF/web.xml). O mesmo
vale para WARs expondo web services (no
precisam mais de um webservices.xml, nem
de arquivos da JAX-RPC).
Alm disso, os EARs no precisam mais
do application.xml. Os application clients
tambm dispensam o application-client.xml;
basta ter no META-INF/MANIFEST.MF o
Main-Class apontando para a classe principal da aplicao. Finalmente, mdulos EJB
tambm no precisam obrigatoriamente do
ejb-jar.xml, bastando que o arquivo JAR do
mdulo possua anotaes como @Stateless.
Tudo isso no quer dizer que os descritores tenham desaparecido completamente.
Continuam sendo suportados, e s vezes
podem ser necessrios. A diferena que
agora, s preciso criar descritores quando
so realmente necessrios.

JavaServer Faces
A incluso da JSF 1.2 a nica grande
novidade de funcionalidade do Java EE 57.
Este anncio de grande novidade pode
parecer uma surpresa para os j adeptos
da JSF, comumente utilizada em servidores
J2EE 1.4. Mas o fato que at ento, nenhuma verso da JSF fez parte, oficialmente, da
plataforma J2EE (a JSF 1.0, JSR-127 (maro
de 2004) posterior J2EE 1.4 (novembro
de 2003)).
Mas isto talvez tenha sido bom, pois a
JSF uma tecnologia complexa que teve
um perodo relativamente longo de amadurecimento de reclamaes sobre o desempenho das primeiras implementaes,
a trapalhadas como problemas de compatibilidade com as especificaes JSP e EL, que
s recentemente foram resolvidos. Assim,
pode ser uma boa coisa que somente agora,
j na sua terceira reviso e com muitas dessas dores de crescimento superadas, a JSF
tenha sido integrada ao complexo conjunto
de especificaes e tecnologias que forma a
plataforma Java EE.
A JSF um framework orientado a componentes para gerao de GUIs web. Isto se
insere melhor na arquitetura geral do Java
EE, que j possui modelos de componentes
para regras de negcio, servios, integrao com recursos e sistemas externos etc.
Faltava suportar o mesmo paradigma no
lado do cliente, at ento servido apenas
por opes fora-bruta (Servlets) ou de
templates (JSP mesmo com extenses
como EL, JSTL, Struts etc.). Por orientado
a componentes queremos dizer que a JSF
permite construir GUIs atravs da composio de objetos e (em se tratando de GUI)
do tratamento de eventos gerados por estes
objetos. Um benefcio desta arquitetura a
separao entre o comportamento da GUI
e a sua apresentao. Outro a facilidade
para a construo de ferramentas puramente visuais.

Web services e XML: JAXB 2.0, JAX-WS 2.0, StAX


O Java EE 5 incorpora uma segunda gerao de APIs para web services, integradas
inicialmente ao J2EE 1.4. No h novidades
revolucionrias, mas temos muitas atualizaes no suporte s ltimas especificaes
do W3C, WS-I e OASIS. Melhorias de desempenho crticas, como o suporte a StAX
e Fast Infoset (codificao binria de XML);
aperfeioamentos de arquitetura, como o

runtime portvel da JAXB 2.0; e claro,


facilidade de programao com anotaes
e suporte a POJOs.
Quanto aos web services, seu principal
atrativo sobre solues mais maduras
e eficientes segundo as ms lnguas,
qualquer outra coisa sempre foi a interoperabilidade. Um importante anncio
no JavaOne 2006 foi o Projeto Tango8, um
esforo conjunto da Sun e da Microsoft
para alinhar as implementaes de web
services de um lado, as APIs do Java Web
Services Developer Pack (JWSDP) e do Java
EE 5; do outro, o Windows Communication
Framework (parte do .NET 3.0). O projeto
Tango foi focado no s na interoperabilidade, mas tambm em eficincia, facilidade
de uso, segurana, suporte a transaes e
outras caractersticas.
Pode parecer estranho que uma tecnologia criada sob medida para a interoperabilidade, baixo acoplamento etc., precise
de esforos contnuos para funcionar
corretamente entre as duas principais plataformas de mercado que a implementam.
Mas o problema que as especificaes de
web services continuam se multiplicando e
evoluindo a uma velocidade to grande que
as implementaes esto sempre correndo
atrs, e tendo que corrigir dificuldades causadas por bugs de implementao ou por
especificao insuficiente. Para mais sobre
o assunto, veja meu artigo Web services e
SOA, na Edio 34.

Concluses
Neste artigo demos as primeiras pinceladas no Java EE 5, a plataforma que todos
usaremos em algum ponto para aplicaes
5
A API proprietria do Hibernate possui algumas funcionalidades que ainda no existem na JPA (como as queries
Criteria), mas isso s afeta usurios mais avanados. A
maioria pode migrar facilmente para a JPA, ganhando
com isso as vantagens de padres do Java EE, como implementaes concorrentes, maior suporte de IDEs etc.
6
o caso do JBoss 4.0, cujos ltimos releases (compatveis com o J2EE 1.4) suportam tambm o EJB 3.0, embora
o JBoss ainda no possua (no momento em que escrevo)
uma verso que suporte a plataforma Java EE como um
todo.
7
A JPA uma nova API, mas no uma nova funcionalidade (a no ser qualitativamente), j que as verses anteriores do J2EE j suportavam persistncia O/R com os
Entity Beans.
8
O codinome Tango especfico ao lado da Sun do
projeto, e achei timo. Afinal, o Tango uma dana lenta,
formal e sombria, e das mais difceis de executar sem escorregar para o ridculo (pelo menos no esteretipo que
aprendi no cinema: ver Quanto Mais Quente Melhor com
Jack Lemmon, e O Baile de Ettore Scola).

26 Java Magazine Edio 39


jm39.indb 26

15/8/2006 18:15:21

Java server-side. Como vimos, a principal


promessa desta verso a mesma do Java
SE 5: facilidade de desenvolvimento. E no
sem tempo, pois a escalada dos requisitos
das aplicaes que temos que construir, e
das tecnologias em voga (SOA, Web 2.0...)
j torna nosso trabalho difcil mesmo
quando nossas ferramentas so simples
e racionais.
Com o objetivo de cumprir esta promessa, o grupo de experts que definiu
o Java EE 5 (e suas muitas APIs componentes) tomou decises corajosas,
como a substituio total da malfadada especificao de persistncia
do EJB, e decises humildes como a
introduo de tcnicas popularizadas por projetos open source, que
acabaram conquistando a comunidade de desenvolvedores Java.
Procuramos exibir um pouco
destes avanos na facilidade de
desenvolvimento com o tutorial
no quadro Glassfish: O Java EE
5 open source. Algumas vantagens s sero sentidas de fato em
aplicaes bem mais complexas
do que os limites impostos por
um artigo (mesmo com um
tutorial mais extenso). Mas
transparente o esforo que o
JCP fez, nesta ltima reviso
do Java EE, para renovar o
velho J2EE, reduzindo muito
sua complexidade.

jcp.org/en/jsr/detail?id=244
JSR-244, padro 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
Osvaldo Pinali Doederlein
(opinali@gmail.com) Mestre em
Engenharia de Software Orientado a Objetos, membro individual
do Java Community Process (tendo participado do Expert Group da JSR-170: Tiger/J2SE 5.0), e
trabalha na Visionnaire Informtica como arquiteto e
desenvolvedor.

Edio 39 Java Magazine


jm39.indb 27

2

15/8/2006 18:15:26

Persistncia no Java E
Iniciando com a Java Persistence API

principal foco da verso 5 do Java


EE a facilidade de uso. O novo
Java EE bem mais simples que
sua verso anterior e suas novas APIs
aumentam a produtividade dos desenvolvedores, exigindo menos esforo de codificao. Uma das principais novidades do
Java EE 5 a sua nova API de persistncia.
H muito tempo esperada pela comunidade
Java, a Java Persistence API (JPA) padroniza
as operaes de persistncia sobre entidades Java, definindo uma especificao para
mapeamento objeto-relacional. Neste artigo
apresentaremos a JPA atravs da criao de
um exemplo completo.

Persistncia e mapeamento O/R


Como sabemos, a tecnologia de banco
de dados relacionais existe h dcadas, e
hoje os SGBDs so robustos e confiveis.
Os principais problemas relacionados ao
armazenamento e recuperao de dados j
foram solucionados, e o investimento das
empresas nesses sistemas tambm imenso, o que torna a sua utilizao uma regra.
O uso dos bancos de dados relacionais,
no entanto, traz alguns inconvenientes ao
programador de linguagens orientadas
a objetos como Java. As tecnologias OO e
relacional so bastante diferentes, e seu uso
conjunto normalmente implica em enfatizar uma tecnologia em sacrifcio da outra.
Como os bancos de dados OO ainda esto
muito menos disseminados que os bancos
de dados relacionais, o desafio atual dos desenvolvedores unir dois mundos completamente distintos, utilizando a tecnologia
relacional para armazenar objetos.
O armazenamento de objetos de uma
aplicao denominado persistncia de objetos. Essa tcnica permite que as instncias
existentes no sistema sejam armazenadas e
posteriormente recuperadas, conservandose o seu estado mesmo aps a aplicao ter
sido finalizada.

Abordagens atuais de mapeamento


Desde as suas primeiras verses, a plataforma Java oferece
acesso a bancos de dados atravs da API JDBC, que trabalha no mesmo nvel do banco, sendo o acesso s informaes armazenadas feito atravs de comandos
SQL. Em muitos aspectos, a JDBC uma API de
baixo nvel, que muitas vezes exige do desenvolvedor o conhecimento das nuances do
banco de dados. Apesar de ser uma maneira eficiente de acessar dados em SGBDs
relacionais, e a opo que normalmente
oferece melhor performance, a JDBC
oferece uma abstrao OO bastante
limitada (trabalha-se com tabelas,
registros e resultsets, ao invs de
objetos).
Para usar os recursos de bancos
de dados relacionais em Java e
ainda assim aproveitar os conceitos do paradigma OO, necessrio fazer o que se conhece como
mapeamento objeto-relacional (ou
simplesmente mapeamento O/R).
No mapeamento O/R as classes
e os atributos do sistema so
mapeados para tabelas e campos/colunas, e a persistncia
feita de forma transparente
pela aplicao. Assim, objetos
em memria so armazenados
no banco, e objetos do banco so
trazidos para a memria sempre
que necessrio. Com paradigmas
to diferentes, diversas questes
surgem durante o mapeamento:
Como mapear herana? E agregao?
Cada classe deve virar uma tabela?
Como aproveitar os recursos do banco
sem perder a abstrao de objetos?
Para suprir essas necessidades, surgiram
diversos frameworks e tecnologias de persistncia, a exemplo do Hibernate e do iBatis. Essas
ferramentas facilitam o trabalho do desenvolvedor
e aumentam sua produtividade, fornecendo poderosas
APIs de manipulao de dados. Apesar de cada ferramenta

28 Java Magazine Edio 39


jm39.indb 28

15/8/2006 18:16:30

a EE 5

Aprenda a utilizar a nova API


de persistncia do Java atravs
de um exemplo completo,
com foco no uso em
aplicaes Java SE

andr dantas roCHa e srGio oLiveira KUbota


possuir uma forma distinta de efetuar o mapeamento O/R, os
conceitos so semelhantes e relativamente simples, baseandose em POJOs (Plain Old Java Objects).
O termo Plain Java Old Object (ou simplesmente POJO)
foi criado por Martin Fowler, Rebecca Parsons e Josh MacKenzie em 2000. A traduo algo como velho e bom
objeto Java e refere-se a objetos/classes Java simples,
no atrelados a ferramentas ou frameworks.

A Java Persistence API


At o J2EE 1.4 a plataforma Java
no possua uma forma simples de
mapear objetos no banco de dados.
A nica opo era a utilizao de
Entity Beans, que exigem um
container EJB e possuem uma
complexidade razovel1. Aplicaes cuja arquitetura no envolvia EJBs precisavam utilizar
ferramentas no padronizadas
como o Hibernate para fazer
a persistncia, ou fazer a implementao de persistncia
manualmente.
A Java Persistence API, definida na JSR-220 (Enterprise
JavaBeans,Version 3.0), padroniza o mapeamento objeto-relacional na plataforma Java. Apesar
de descrita na especificao do
novo EJB, a JPA no depende de
um container para funcionar, sendo possvel usar e testar solues
apenas com o Java SE2.
A JPA uma especificao baseada
no conceito de POJOs, que incorpora
idias de renomados frameworks de persistncia para padronizar o mapeamento
O/R em Java. A API oferece uma soluo
completa para mapeamento e persistncia de
objetos:
Um modo declarativo de descrever mapeamentos O/R
Uma linguagem de consulta

Um conjunto de ferramentas para


manipular entidades
Em se tratando de um padro do Java
Community Process, a JPA traz diversos
benefcios. O uso de um padro para a persistncia de objetos permite que diversos
fabricantes trabalhem sobre os mesmos
conceitos e que o desenvolvedor escolha
a implementao de sua preferncia. A
padronizao tambm traz outra importante vantagem: pode-se alternar entre
implementaes de fabricantes distintos,
que estejam em conformidade com a
JSR-220, sem nenhum esforo adicional.
Dessa forma, uma aplicao codificada de
acordo com o novo padro ir funcionar
com qualquer implementao da JPA, no
havendo necessidade de se conhecer (a
princpio) qual tecnologia ser utilizada
para essa implementao.

Conceitos bsicos
Na JPA os objetos persistentes so denominados entidades (entities). Uma entidade
um objeto simples (POJO), que representa
um conjunto de dados persistido no banco.
Como entidades so definidas por classes
Java comuns, sem relao com frameworks
ou bibliotecas, elas podem ser abstratas ou
herdar de outras classes, sem restries.
Um conceito importante que as entidades possuem um identificador (descrito
pela chave primria) e estado, sendo seu
tempo de vida independente do tempo
de vida da aplicao. Assim, aplicaes
distintas podem compartilhar a mesma
entidade, que referenciada atravs de
seu identificador.

1
No Java EE 5.0, os Entity Beans foram revistos e se tornaram bem mais simples de usar
2
A independncia do container trouxe uma grande melhoria na testabilidade das aplicaes que mapeiam dados
do banco

Edio 39 Java Magazine


jm39.indb 29

29

15/8/2006 18:17:25

Persistncia no Java EE 5

Para que uma entidade se torne persistente necessrio associ-la a um persistence


context (contexto de persistncia), que
fornece a conexo entre as instncias e
o banco de dados. A manipulao das
entidades feita, a partir desse contexto,
por meio do entity manager (gerenciador
de entidades), que responsvel por
executar as operaes bsicas sobre a
entidade (criao, atualizao, excluso,
localizao, consultas etc.). O entity manager na JPA uma instncia da interface
javax.persistence.EntityManager.
A implementao da JPA feita por um
persistence provider (provedor de persistncia). O provedor define como as coisas
funcionam, atravs da implementao de
todas as interfaces definidas pela especificao da JPA. Dessa forma, cada provedor
decide a maneira e o momento de carregar, atualizar e armazenar as entidades,
assim como sincronizar os dados com o
banco. As configuraes utilizadas pelo
provedor em uma determinada aplicao
(conexo com o banco de dados, entidades
que sero gerenciadas, tipo de transao
etc.) so descritas em uma persistence unit,
que configurada num arquivo especial
denominado persistence.xml.

Mapeamento
As classes e interfaces da JPA esto
localizadas no pacote javax.persistence. A
API faz uso intensivo de anotaes3; por
isso no necessrio criar descritores
XML para cada uma das entidades da
aplicao 4. Uma entidade uma classe
Java comum, rotulada atravs da anotao @Entity. No preciso implementar
interfaces ou estender outras classes
para tornar uma classe persistvel; a
nica exigncia que a classe da entidade
possua um construtor sem parmetros,
pois a instanciao da classe feita por
reflexo.
No cdigo a seguir a classe Pessoa representa uma entidade. O atributo cpf o
identificador da entidade (chave primria),
especificado atravs da anotao @Id:
@Entity
public class Pessoa {
@Id
private String cpf;
}

Grande parte da produtividade trazida


pela JPA deve-se utilizao de valores
default de mapeamento, que facilitam
bastante o trabalho do desenvolvedor.
Assim, o que no definido explicitamente
assume a configurao padro da API. Por
exemplo, por padro a JPA considera o
nome da entidade o mesmo nome da tabela
no banco de dados e o nome da propriedade o mesmo nome da coluna. No cdigo
anterior, a entidade Pessoa ser salva na
tabela PESSOA e a propriedade cpf na coluna
CPF. Caso seja necessrio alterar a forma de
mapeamento, devem-se utilizar as anotaes @Table e @Column, por exemplo:
@Entity
@Table(name=TB_PESSOA)
public class Pessoa {
@Id
@Column(name=DS_CPF)
private String cpf;
}

Outro padro utilizado pelo JPA considerar todas as propriedades de uma entidade como persistentes (o mapeamento
segue as regras descritas anteriormente).
Caso seja desejvel excluir alguma propriedade do mapeamento (ex.: no caso
de ela poder ser criada a partir de outras
propriedades), basta marc-la com a anotao @Transient:
@Entity
public class Pessoa {
@Id
private String cpf;
@Transient
private String nomeCompleto;
}

Os dados de uma nica entidade podem estar distribudos em mais de uma


tabela, e diversos tipos de relacionamentos entre entidades so possveis. Os
mais comuns so os de agregao (anotaes @OneToOne, @OneToMany, @ManyToOne,
@ManyToMany, etc.) e herana (anotao
@Inheritance), que sero vistos mais adiante.

Consultas
A JPA oferece suporte a consultas estticas e dinmicas. A API fornece uma
linguagem prpria de consulta, que
uma extenso bastante poderosa da EJB
QL (a linguagem de consultas do EJB).
Essa linguagem pode ser usada como

uma alternativa ao SQL, que tambm


suportado. As consultas suportam polimorfismo, o que significa que quando uma
entidade consultada, todas as entidades
descendentes que atendam ao critrio da
consulta tambm so retornadas. A criao
de consultas feita atravs do EntityManager,
que fornece mtodos especficos para
instanciar consultas estticas e dinmicas,
alm de permitir a execuo das operaes
CRUD5.
As consultas estticas possuem nomes e
so descritas pela anotao @NamedQuery.
Elas so definidas nas entidades correspondentes e ficam pr-compiladas. Veja
um exemplo de consulta esttica para
localizar uma pessoa pelo seu CPF:
@NamedQuery(name = consultarPorCPF,
query = SELECT p FROM Pessoa p WHERE p.cpf = :cpf)

O EntityManager utiliza o nome da consulta para instanci-la, o que feito atravs


do mtodo createNamedQuery(). Depois que
a consulta criada, basta setar os parmetros e execut-la. A execuo pode
ser feita pelos mtodos getSingleResult()
ou getResultList(), a depender do resultado
esperado. Por exemplo, para localizar uma
pessoa pelo CPF (supondo que o retorno
ser nico), basta executar a consulta conforme o exemplo abaixo:
Query consulta =
manager.createNamedQuery(consultarPorCPF);
consulta.setParameter(cpf, 111.111.111-11);
Pessoa pessoa = consulta.getSingleResult();

As consultas dinmicas no possuem


nome, e podem ser construdas em tempo de execuo. A criao desse tipo
de consulta feito atravs do mtodo
createQuery():
Query consulta = manager.createQuery(
SELECT p FROM Pessoa p WHERE p.cpf = :cpf);

3
As anotaes surgiram da verso 5.0 do Java e esto
presentes na maioria das APIs do novo JEE.
4
Mesmo no sendo obrigatrio o uso de XML para
descrever o mapeamento, ainda possvel utilizar essa
opo. Um exemplo tpico o arquivo persistence.xml,
que guarda as configuraes da unidade de persistncia
e utilizado neste artigo.
5
As principais operaes executadas sobre dados so
conhecidas atravs da sigla CRUD (Create, Read, Update,
e Delete).

30 Java Magazine Edio 39


jm39.indb 30

15/8/2006 18:17:25

interessante notar que a execuo de


ambas as consultas idntica, uma vez
que as duas so objetos do tipo Query.

Um exemplo completo
Agora que os conceitos bsicos da JPA
foram apresentados, partiremos para
um exemplo completo, onde a API ser
demonstrada na prtica.
Enquanto a maioria dos artigos sobre
JPA foca no uso de EJBs, aqui faremos
uma abordagem distinta. No exemplo
deste artigo implementaremos uma aplicao desktop sem nenhum vnculo com
um container EJB. O objetivo mostrar
que a JPA pode ser utilizada no Java SE
facilmente. Usaremos na camada de persistncia o TopLink Essentials e o MySQL.
O TopLink Essentials a verso open
source do TopLink, uma ferramenta de
mapeamento objeto-relacional da Oracle.
O TopLink Essentials implementa a JPA e
utilizado no projeto GlassFish, que a
base da implementao de referncia do
Java EE 5.0. Por simplicidade, e para focar
melhor na API, no implementamos uma
interface grfica. O cdigo completo da
aplicao est disponvel no site da Java
Magazine. Veja mais sobre o ambiente
utilizado e como executar a aplicao
de exemplo no quadro Configurando o
ambiente.
A aplicao implementa um sistema
(bastante simplificado) para gerenciamento de uma locadora de veculos. Na
Figura 1 exibido seu diagrama de classes e na Figura 2 o modelo ER (EntidadeRelacionamento) utilizado.

Mapeamento do cliente
Comearemos com o mapeamento da
classe Cliente, a mais simples da aplicao. O cdigo da classe mostrado na
Listagem 1. Como vimos, a anotao
@Entity torna a classe persistvel, permitindo a sua manipulao pela JPA.
Note que no foi necessrio utilizar a
anotao @Table para especificar a tabela
utilizada para persistncia, uma vez que
uma tabela de mesmo nome usada para
persistir os clientes (CLIENTE). A identidade de cada cliente definida atravs da
propriedade codigo. A anotao @Id indica
que esse campo utilizado como iden-

tificador ou chave primria, e @Column


especifica a coluna correspondente no
banco (CD_CLIENTE). No nosso caso, a chave
primria da entidade ser gerada automaticamente pelo banco atravs de um
campo de auto-incremento, o que es-

pecificado pela anotao @GeneratedValue(


strategy = GenerationType.IDENTITY):
@Id
@Column(name = CD_CLIENTE)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer codigo;

Configurando o ambiente

ara executar o exemplo disponvel no


site da Java Magazine, ser necessrio ter
instaladas as ferramentas Eclipse 3.2, MySQL e
TopLink Essentials.

pode variar.) Isso extrai, entre outros, o arquivo


toplink-essentials.jar, que deve ser adicionado
ao projeto no Eclipse.

Executado a aplicao
Eclipse 3.2
O Eclipse 3.2 foi o IDE escolhido para implementar o exemplo. O download pode ser feito
a partir de eclipse.org/downloads. Para quem
ainda no usa o Eclipse, a instalao simples,
bastando extrair o contedo do arquivo compactado para o diretrio de sua preferncia.
Aps a instalao do Eclipse, o projeto de exemplo deve ser importado para o IDE. A estrutura
do projeto mostrada na Figura Q1.

MySQL
O MySQL usado no exemplo devido sua
facilidade de instalao e configurao. O
download do MySQL e do MySQL Connector/J
(driver JDBC) podem ser feitos em dev.mysql.
com/downloads. Escolha a verso adequada
ao seu sistema operacional e siga as instrues
fornecidas no help. Aps instalar, crie um database com nome locadora e execute o script
de criao das tabelas.
O arquivo compactado do drive r Co n n e c to r /J co nt m a b i b l i ote c a
mysql-connector-java-3.1.12-bin.jar (a verso
pode variar), que deve ser adicionado ao projeto do Eclipse.

Aps esses passos, a aplicao estar pronta para ser iniciada. O projeto j contm a
configurao do persistence unit, localizada
no arquivo META-INF/persistence.xml. Para
rodar a aplicao basta executar a classe
br.com.jm.locadora.Principal. Durante a execuo,
o console mostrar as seguintes mensagens:
Populando tabelas... OK
Listando todas as reservas...
Srgio - BMW
Andr - ECO SPORT
Listando todas as locacoes...
Andr - ECO SPORT
Listando reservas entre 01/06/2006 e 01/08/2006...
Andr - ECO SPORT
Listando dados do veculo ABC1234...
ECO SPORT - ABC1234 [Utilitario]

Toplink Essentials
O Toplink Essentials a implementao da
JPA utilizada no projeto GlassFish (glassfish.dev.
java.net). O download pode ser feito a partir
da pgina do projeto: oracle.com/technology/
products/ias/toplink/jpa/download.html. Aps
baixar o arquivo execute o comando:
java jar glassfish-persistence-installer-v2-b11.jar
(Lembrando mais uma vez que a verso

Figura Q1. Estrutura do projeto.

Edio 39 Java Magazine


jm39.indb 31

31

15/8/2006 18:17:26

Persistncia no Java EE 5

O mapeamento das propriedades nome


e endereco muito simples. Ambas as propriedades possuem a anotao @Column,
contendo dois atributos: name, que define a
coluna correspondente no banco; e nullable,

que define se a propriedade em questo


pode ser nula:
@Column(name = DS_NOME, nullable = false)
private String nome;

Veiculo
Reserva

Cliente

{ From model }

{ From locadora }

{ From model }
Attributes

veiculo

private String placa

Attributes

cliente

Attributes

private String modelo

private String codigo

private String codigo

private Integer ano

private Date inicio

private String nome

private String cor

private Date fim

private String endereco

private Double diaria

reserva

Esportivo

Utilitario

Locacao

{ From model }

{ From model }

{ From model }

Attributes
private Integer velocidade

Attributes
private Integer passageiros

Attributes
private Integer codigo

Figura 1. Diagrama de classes do sistema de locao de veculos.

A propriedade reservas um pouco mais


complexa, pois ela determina um relacionamento um-para-muitos. No nosso
modelo, um cliente pode estar relacionado
a diversas reservas, sendo que cada reserva
relaciona-se a um nico cliente.
A anotao @OneToMany usada para
indicar o relacionamento entre as entidades (um cliente para muitas reservas).
As reservas do cliente so armazenadas
na propriedade reservas (uma lista de
instncias da entidade Reserva), que populada automaticamente pelo TopLink.
Dois atributos da anotao so utilizados
nesse mapeamento: cascade = CascadeType.ALL
indica que alteraes na entidade Cliente
sero refletidas automaticamente nas
entidades Reserva relacionadas. O atributo
mappedBy = cliente indica que na classe
Reserva existe uma propriedade denominada cliente, que mapeia o cliente do relacionamento (veremos mais sobre a classe
Reserva adiante).
@OneToMany(cascade =
CascadeType.ALL, mappedBy = cliente)
private List<Reserva> reservas;

Mapeamento do veculo

Figura 2. Modelo Entidade-Relacionamento para o sistema de locao de veculos.


Listagem 1. Cliente.java
package br.com.jm.locadora.model;
import java.util.List;
import javax.persistence.*;
@Entity
public class Cliente {
@Id
@Column(name = CD_CLIENTE)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer codigo;
@Column(name = DS_NOME, nullable = false)
private String nome;
@Column(name = DS_ENDERECO, nullable = false)
private String endereco;
@OneToMany(cascade = CascadeType.ALL, mappedBy = cliente)
private List<Reserva> reservas;
}

// ... gets e sets omitidos

Na modelagem OO da aplicao decidimos especializar a classe Veiculo, guardando as particularidades de cada veculo em
classes especficas (veja a Figura 1). Veiculo
uma classe abstrata, que possui duas
subclasses: Esportivo e Utilitario.
No modelo relacional a abordagem foi
distinta. Para evitar o custo de joins, todos os veculos foram mapeados em uma
nica tabela, que contm propriedades
tanto genricas quanto especficas. Como
veremos a seguir, o nosso mapeamento
deve contemplar essa deciso arquitetural
e permitir que os objetos sejam instanciados corretamente (de acordo com sua
classe), mesmo com todos residindo em
uma tabela genrica.
Vamos analisar o cdigo da entidade
Veiculo (Listagem 2). Como j conhecemos
as anotaes @Entity, @Id e @Column, veremos
apenas as novas construes.
O mapeamento da herana de entidades
descrito atravs da anotao @Inheritance,
que define a estratgia usada no mapeamento. De forma semelhante a outros

32 Java Magazine Edio 39


jm39.indb 32

15/8/2006 18:17:28

frameworks O/R, a JPA oferece trs tipos


de mapeamento de herana. Estes so
descritos na enumerao InheritanceType:
SINGLE_TABLE, TABLE_PER_CLASS e JOINED.
A estratgia SINGLE_TABLE a mais comum,
sendo a opo default da JPA. Nessa estratgia todas as entidades da hierarquia
so persistidas em uma nica tabela, que
deve conter todos os campos necessrios.
Na estratgia TABLE_PER_CLASS cada entidade
mapeada em uma tabela especfica, enquanto na estratgia JOINED uma associao
de tabelas usada para persistncia de
cada entidade.
A estratgia de mapeamento deve ser
especificada na entidade raiz da hierarquia, atravs do atributo strategy. Seguindo
o nosso modelo, a hierarquia de veculos
seguir a estratgia SINGLE_TABLE:

que o valor E for encontrado no campo


CD_TIPO da tabela VEICULO, uma entidade
Esportivo ser criada. Quando o campo
CD_TIPO contiver o texto U uma entidade
Utilitario ser criada, como especificado
Listagem 2. Veiculo.java
package br.com.jm.locadora.model;
import java.util.List;
import javax.persistence.*;

@Entity
@Table(name = VEICULO)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = CD_TIPO, discriminatorType = DiscriminatorType.STRING)
public abstract class Veiculo {
@Id
@Column(name = DS_PLACA, nullable = false)
private String placa;
@Column(name = DS_MODELO, nullable = false)
private String modelo;
@Column(name = NR_ANO, nullable = false)
private Integer ano;

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)

@Column(name = DS_COR, nullable = false)


private String cor;

O mesmo mapeamento pode ser definido de forma simplificada, visto que


SINGLE_TABLE a estratgia de mapeamento
default da JPA:

@Column(name = VL_DIARIA, nullable = false)


private Double diaria;
@OneToMany(cascade = CascadeType.ALL, mappedBy = veiculo)
private List<Reserva> reservas;
@Column(name = CD_TIPO, nullable = false)
public abstract String getTipo();

@Inheritance

Como todas as entidades da hierarquia


so armazenadas em uma nica tabela,
necessrio determinar a correspondncia
entre registros e entidades. A anotao
@DiscriminatorColumn define a regra utilizada
pela JPA para reconhecer cada registro
e instanciar a entidade correspondente.
O atributo name especifica a coluna que
armazena o descritor da entidade, enquanto o atributo discriminatorType define o tipo
dessa coluna:
@DiscriminatorColumn(name = CD_TIPO,
discriminatorType = DiscriminatorType.STRING)

pela anotao @DiscriminatorValue(U) da


etintidade Utilitario.
importante notar que, como as entidades Esportivo e Utilitario derivam de Veiculo, s
necessrio mapear as novas propriedades

// ... gets e sets omitidos

Listagem 3. Esportivo.java
package br.com.jm.locadora.model;
import javax.persistence.*;
@Entity
@DiscriminatorValue(E)
public class Esportivo extends Veiculo {
@Column(name = VL_VELOCIDADE, nullable = false)
private Integer velocidade;
}

// ... gets e sets omitidos

Listagem 4. Utilitario.java

Durante a persistncia, a JPA l o valor


armazenado na coluna CD_TIPO (uma string)
e escolhe a entidade com a qual ir trabalhar. Essa escolha feita a partir de uma
outra anotao, especificada nas entidades
descendentes: @DiscriminatorValue.
Nas Listagens 3 e 4 so exibidos os cdigos das entidades Esportivo e Utilitario. A
anotao @DiscriminatorValue(E), contida na
entidade Esportivo, especifica que sempre

package br.com.jm.locadora.model;
import javax.persistence.*;
@Entity
@DiscriminatorValue(U)
public class Utilitario extends Veiculo {
@Column(name = NR_PASSAGEIROS, nullable = false)
private Integer passageiros;
}

// ... gets e sets omitidos

Edio 39 Java Magazine


jm39.indb 33

33

15/8/2006 18:17:29

Persistncia no Java EE 5

especificadas nessas entidades (velocidade


e passageiros). Alm disso, possvel especificar a obrigatoriedade dos campos das
entidades descendentes (nullable = false)
mesmo com todas compartilhando uma s
tabela. A obrigatoriedade s ser avaliada
para registros correspondentes entidade
em questo.

Mapeamento da reserva
J apresentamos a entidade Reserva
(Listagem 5), que descreve a reserva de um
veculo, relacionando-se com as entidades
Veiculo e Cliente. Reserva representa o lado
filho dos relacionamentos veiculo-reserva
e cliente-reserva, e armazena o cliente e o veculo nas propriedades cliente e veiculo. Para

Listagem 5. Reserva.java
package br.com.jm.locadora.model;
import java.util.Date;
import javax.persistence.*;
@Entity
@NamedQueries({
@NamedQuery(name = Reserva.listarPorPeriodo,
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)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer codigo;
@ManyToOne
@JoinColumn(name = CD_CLIENTE, nullable = false)
private Cliente cliente;
@ManyToOne
@JoinColumn(name = DS_PLACA, nullable = false)
private Veiculo veiculo;
@Column(name = DT_INICIO, nullable = false)
@Temporal(TemporalType.DATE)
private Date inicio;
@Column(name = DT_FIM, nullable = false)
@Temporal(TemporalType.DATE)
private Date fim;
}

// ... gets e sets omitidos

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)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer codigo;
@OneToOne
@JoinColumn(name = CD_RESERVA)
private Reserva reserva;
}

// ... gets e sets omitidos

34 Java Magazine Edio 39


jm39.indb 34

15/8/2006 18:17:37

mapear o relacionamento entre as entidades so usadas anotaes @ManyToOne, que


definem que muitas reservas esto relacionadas a um cliente e muitas reservas
esto relacionadas a um veculo. A anotao @JoinColumn usada para especificar
a coluna que contm a chave estrangeira
de cada relao. O relacionamento com a
entidade Cliente exibido a seguir:
@ManyToOne
@JoinColumn(name = CD_CLIENTE, nullable = false)
private Cliente cliente;

Vale lembrar que as propriedades cliente


e veiculo so referenciadas nas entidades
pai da relao (Cliente e Veiculo), atravs dos atributos mappedBy = cliente e
mappedBy = veiculo, como possvel ver nas
Listagens 1 e 2.
A entidade Reserva possui duas propriedades de data/hora ou temporais: fim e
inicio. Na JPA, todas as propriedades temporais (do tipo java.util.Date ou java.util.Calendar)
devem ser marcadas com a anotao
@Temporal, que especifica o tipo no banco
de dados usado para persistncia.
@Column(name = DT_INICIO, nullable = false)
@Temporal(TemporalType.DATE)
private Date inicio;

A entidade Reserva tambm apresenta


uma particularidade em relao s outras entidades descritas anteriormente.
Em Reserva esto codificadas algumas
consultas estticas, que podem ser executadas sobre a entidade. A anotao
@NamedQueries usada para agrupar todas
as consultas estticas da entidade, que so
descritas individualmente em anotaes
@NamedQuery.

Mapeamento da locao
O mapeamento da entidade Locacao
(Listagem 6) simples. Alm das anotaes @Id e @GeneratedValue abordadas
anteriormente, essa entidade apresenta
um relacionamento um-para-um com
a entidade Reserva, pois uma locao s
pode existir para uma reserva criada
anteriormente.
O relacionamento descrito pela anotao
@OneToOne, e possui uma sintaxe semelhante
de um mapeamento um-para-muitos:

@OneToOne
@JoinColumn(name = CD_RESERVA)
private Reserva reserva;

O mapeamento est especificado em


apenas um lado da relao (na entidade
Locacao) e, por isso, dito unidirecional. Isso
significa que a locao conhece a reserva,
mas a reserva no conhece a locao.

Persistindo dados e executando consultas


Como explicado anteriormente, a interface EntityManager a responsvel pelas
operaes de persistncia. A estratgia de
criao da instncia desse gerenciador vai
variar de acordo com o padro de arquitetura escolhido. Se a implementao de JPA
for executada a partir de um servidor de
aplicaes Java EE, o EntityManager deve ser
declarado pela anotao @PersistenceContext
e ser criado automaticamente pelo container (via injeo de dependncia). J no Java
SE o EntityManager deve ser instanciado pela
aplicao, o que feito atravs da fbrica
abstrata EntityManagerFactory:

guraes da persistence unit do arquivo


persistence.xml (Listagem 7). Esse arquivo
possui um significado especial, armazenando as configuraes de conexo e
a descrio das entidades. O arquivo de
configurao deve residir numa pasta
com nome META-INF, na raiz do projeto
(veja o quadro Configurando o ambiente
para conhecer a estrutura do projeto de
exemplo).
A classe EntityManager define os principais
mtodos para incluir, localizar e salvar
entidades. Os mtodos de persistncia
no declaram excees checadas, portanto no obrigatrio declarar excees no
cdigo.
Com o objeto EntityManager criado, basta
executar o mtodo correspondente sobre
a entidade. Por exemplo, para localizar
um veculo atravs da sua placa (chave
primria), basta chamar o mtodo find()
passando como parmetros a classe da
entidade e sua chave:
Veiculo veiculo = manager.find(Veiculo.class, ABC1234);

EntityManagerFactory factory =
Persistence.createEntityManagerFactory(locadora);
EntityManager manager =
factory.createEntityManager();

A classe EntityManagerFactory criada


pela classe Persistence, que l as confi-

A insero e atualizao da entidade so


feitas atravs do mtodo persist(). A primeira chamada ao mtodo torna a entidade
persistente, associando-a ao contexto de
persistncia:

Listagem . persistence.xml
<?xml version=1.0 encoding=UTF-8?>
<persistence xmlns=http://java.sun.com/xml/ns/persistence
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance version=1.0
xsi:schemaLocation=http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd>
<persistence-unit name=locadora>
<provider>
oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider
</provider>
<class>br.com.jm.locadora.model.Cliente</class>
<class>br.com.jm.locadora.model.Reserva</class>
<class>br.com.jm.locadora.model.Locacao</class>
<class>br.com.jm.locadora.model.Veiculo</class>
<class>br.com.jm.locadora.model.Utilitario</class>
<class>br.com.jm.locadora.model.Esportivo</class>
<properties>
<property name=toplink.logging.level value=INFO />
<property name=toplink.jdbc.driver value=com.mysql.jdbc.Driver />
<property name=toplink.jdbc.url
value=jdbc:mysql://127.0.0.1:3306/locadora />
<property name=toplink.jdbc.user value=root />
<property name=toplink.jdbc.password value= />
</properties>
</persistence-unit>
</persistence>

Edio 39 Java Magazine


jm39.indb 35

35

15/8/2006 18:17:37

Persistncia no Java EE 5

Dali JPA Tools

Dali JPA Tools um plug-in da Fundao Eclipse que oferece


suporte ao JPA. Alm de views que auxiliam no mapeamento
entre propriedades e colunas, o plug-in tambm fornece ferramentas para a gerao das entidades a partir do modelo relacional e
para gerao do modelo relacional a partir das entidades. Aqui
demonstraremos como instalar o plug-in e gerar as entidades a
partir do banco de dados.
Supondo que o ambiente j est configurado (veja o quadro
Configurando o ambiente), o primeiro passo consiste em efetuar
o download do Dali de eclipse.org/dali. A instalao simples,
bastando extrair o arquivo compactado para o diretrio raiz do
Eclipse e reiniciar o IDE. Aps a instalao, a perspectiva de persistncia estar disponvel.
Em seguida necessrio criar um novo projeto Java e adicionar

Figura Q3. Configurando a conexo.


Clique novamente em Finish para finalizar a configurao. Com
a conexo funcionado, a ltima etapa gerar as entidades. Para
isso, clique com o boto direito sobre o projeto e selecione Java
Perspective>Generate Entities. A tela de gerao de entidades ser
exibida (Figura Q4) listando todas as entidades encontradas
no banco. Selecione as entidades que deseja gerar e clique em
Finish.
Todas as entidades e mapeamentos sero gerados automaticamente, assim como o arquivo persistence.xml. Para mapeamentos
mais complexos provvel que algum ajuste manual ainda seja
necessrio.

Figura Q2. Adicionado persistncia ao projeto.


os JARs do Toplink Essentials e do driver do MySQL. Aps a criao
do projeto, deve-se torn-lo persistvel. Para isso clique com o
boto direito sobre o projeto e selecione Java Perspective>Add
Java Persistence. Uma caixa de dilogo semelhante da Figura Q2
ser exibida.
Preencha os dados conforme a figura e clique em Add Connections para criar uma nova conexo ao MySQL. A tela de configurao de conexo ser exibida (Figura Q3). Preencha os dados
conforme ilustrado e clique em Finish.

Figura Q4. Gerando as entidades.

36 Java Magazine Edio 39


jm39.indb 36

15/8/2006 18:17:42

Veiculo veiculo = new Veiculo(ABC1234);


manager.persist(veiculo);

A excluso da entidade feita atravs do


mtodo remove():
manager.remove(veiculo);

Consultas mais complexas so efetuadas


atravs da interface Query. Como visto anteriormente, o EntityManager responsvel
por instanciar as consultas, que podem ser
tanto dinmicas quanto estticas. A seguinte consulta esttica lista todas as reservas
existentes em um determinado perodo:
@NamedQuery(name = Reserva.listarPorPeriodo,
query = SELECT r FROM Reserva r WHERE +
r.inicio >= :inicio AND r.fim <= :fim)

Para exibir as reservas do perodo basta


criar a consulta, preencher os parmetros
e executar o mtodo getResultList(). No necessrio efetuar joins com as tabelas VEICULO
e CLIENTE, pois a JPA j faz as agregaes automaticamente a partir do mapeamento:
Query query = manager.createNamedQuery(
Reserva.listarPorPeriodo);
query.setParameter(inicio, formataData(01/06/2006));
query.setParameter(fim, formataData(01/08/2006));
List<Reserva> reservas = query.getResultList();
for (Reserva reserva : reservas) {
System.out.println( + reserva);
}

A JPA tambm permite criar consultas


complexas, incluindo sub-consultas e funes agregadas. A consulta Reserva.ultima,
por exemplo, seleciona a ltima reserva
cadastrada (a que possui maior cdigo):
@NamedQuery(name = Reserva.ultima,
query = SELECT r FROM Reserva r WHERE r.codigo = +
(SELECT MAX(r1.codigo) FROM Reserva r1))

Apoio de ferramentas
possvel perceber que a JPA
oferece recursos avanados de consulta

e facilidades na execuo de operaes


CRUD. Mas a extenso da JPA e o nmero
de anotaes e opes suportadas podem
tornar a API muitas vezes difcil de usar;
no fcil, por exemplo, conhecer todas
as anotaes e atributos envolvidos em
um mapeamento O/R. Alm disso, a codificao manual de mapeamento (anotar
entidades e propriedades) um trabalho
geralmente maante e propenso a erros.
Embora seja uma API nova, diversas
ferramentas j oferecem apoio ao desenvolvimento com JPA, fornecendo comandos
para mapeamento automtico e recursos
para edio de anotaes. Essas ferramentas aumentam a produtividade do
desenvolvedor e diminuem a possibilidade
de erros.
O NetBeans 5.5, atualmente em beta,
inclui vrios wizards que auxiliam na
criao de entidades e na definio do
mapeamento e a gerao do persistence.xml.
J o Eclipse Dali, um projeto da Fundao
Eclipse, adiciona suporte a JPA no Eclipse.
Veja um tutorial sobre o Dali no quadro
Dali JPA Tools.

Concluses
A Java Persistence API traz diversos benefcios para o desenvolvedor Java e para os
fabricantes de produtos relacionados persistncia de objetos. A criao de um padro
baseado em frameworks lderes de mercado
incentiva o uso da API e facilita a migrao
de softwares existentes. Desenvolvedores
com alguma vivncia em ferramentas como
Hibernate e TopLink no tero dificuldades
em utilizar a nova API.
Com um padro de persistncia, a escolha
de uma determinada implementao passa
a ser guiada por critrios como preo, robustez e tradio do fabricante, e no mais
por operaes suportadas por um fabricante
especfico ou simplicidade de mapeamento
O/R provida por um framework.
Os servidores de aplicaes j iniciaram
a incorporao do novo padro e s

uma questo de tempo at que a JPA esteja


disponvel para qualquer aplicao. Agora
aprofundar os conceitos e estar preparado
para o futuro quando ele chegar.

jcp.org/aboutJava/communityprocess/
final/jsr220
Especificao do EJB 3.0 e JPA
java.sun.com/developer/
technicalArticles/J2EE/jpa
Introduo JPA
eclipse.org/dali
Dali JPA Tools
oracle.com/technology/products/ias/toplink
Pgina do Oracle Toplink
glassfish.dev.java.net/javaee5/persistence/
entity-persistence-support.html
Sobre o suporte persistncia no projeto
GlassFish
javamagazine.com.br/downloads/jm39/
jm-jpa.zip
Andr Dantas Rocha
(ad-rocha@uol.com.br) mestre
em Engenharia de Software pela
USP e arquiteto da Fidelity SA.

Srgio Oliveira Kubota


(sergio_kubota.@hotmail.com) PsGraduado em Objetos Distribudos com
Java pela FIAP e atua como arquiteto
de sistemas corporativos baseados nas
tecnologias Java SE e EE, no segmento de inovaes
tecnolgicas da Caixa Econmica Federal.

Edio 39 Java Magazine


jm39.indb 37

3

15/8/2006 18:17:55

AJAX Avanado c
Criando componentes e servios com

algum tempo houve uma mudana


significativa na forma como interagimos com as aplicaes web. Uma nova
tendncia, denominada Web 2.0, tem mudado
nossas concepes sobre o paradigma request/wait/
response, usado na maioria dos sites tradicionais.
O conjunto de tecnologias AJAX (Asynchronous
JavaScript and XML) tornou possvel trazer s
aplicaes web recursos de aplicaes desktop
com que sonhvamos desde nossos
primeiros websites.
Uma grande divulgao
do AJAX aconteceu atravs de aplicaes criadas
pelo Google, como Google
Maps e GMail, e a empresa empresa vislumbrou a necessidade de se
construir um framework
para facilitar o desenvolvimento de aplicaes
com AJAX. Foi assim que
nasceu o Google Web Toolkit
(GWT).
Neste artigo abordaremos a
construo de uma aplicao AJAX que
utiliza diversos componentes personalizados estendendo a API
do GWT. Veremos como
criar uma tabela paginada com campos
editveis e uma caixa de dilogo personalizada, alm
de demonstrar
o gerenciamento de eventos e
chamadas de
servios para
acesso a dados. Para cada
componente
abordaremos
particularidades
da API e dicas sobre

38 Java Magazine Edio 39


jm39.indb 38

15/8/2006 18:18:05

o com GWT

Explorando a API do GWT


para criar aplicaes
AJAX sofisticadas e novos
componentes

o Google Web Toolkit

Ari Dias Neto


sua utilizao. Para uma introduo ao
GWT, sua API bsica e a estrutura utilizada para projetos, recomendo a leitura do
artigo Google Web Toolkit na Edio 38
da Java Magazine.

Preparao
Para a construo do exemplo, vamos
utilizar o IDE Eclipse com dois plug-ins:
WTP (Web Tools Project) e Googlipse. No
site do WTP (eclipse.org/webtools) existe
uma verso do Eclipse com este plug-in
incluso. Se voc j tem o Eclipse instalado,
pode baixar e instalar o WTP pelo prprio
IDE, acessando o site de atualizaes do
Callisto (veja um artigo sobre o Callisto
na edio anterior).
Tendo instalado o WTP, faa o download do JAR do Googlipse (em googlipse.
com) e coloque-o dentro da pasta eclipse/
plugins. Depois, dentro do Eclipse, abra
o menu Window|Preferences, escolha a
opo Googlipse e defina a pasta onde
est instalado o GWT (download em
code.google.com/webtoolkit). Com isso sua
IDE fica preparada para o desenvolvimento dos exemplos mostrado neste artigo.
Como banco de dados usaremos o
MySQL. A Listagem 1 mostra o script
para a criao da nica tabela que precisamos. Todo o cdigo aqui demonstrado
est disponvel no site da Java Magazine.
Para facilitar os testes, o download inclui
tambm uma classe que carrega o banco de
dados com nomes e endereos aleatrios.

Construo de componentes
O exemplo que construiremos ser uma
lista de contatos (veja a Figura 1), formada
por uma tabela com paginao e uma rea
de exibio de fotos. Alm disso, criaremos
uma caixa de dilogo que mostra mais
informaes sobre um contato selecionado
na tabela. Veja algumas particularidades
do exemplo:

A tabela ter campos editveis, sensveis a cliques do mouse e tecla Enter.


A persistncia feita de forma transparente: assim que o campo editvel no
possuir mais o foco, os dados sero atualizados na base de dados, sem necessidade
de interveno do usurio.
A caixa de dilogo pode ser fechada
tanto com o mouse como com o teclado
(Enter ou Esc).

Iniciando o projeto

br.com.jm.gwt.server Onde estaro a


implementaes dos servios, como cdigo
de acesso a dados e classes de negcio.
br.com.jm.gwt.public Contendo imagens,
arquivos CSS, pginas HTML etc.
Note que alguns arquivos tambm foram
criados:

br.com.jm.gwt.public.JMListaContatos.html
Arquivo HTML com tags indicando as
posies onde sero includos os componentes AJAX, e onde importada a
biblioteca JavaScript do GWT (gwt.js). Esse
arquivo, que chamado na documentao
do GWT de Host Page, possui tambm um
elemento <meta> definindo qual mdulo
ser carregado.

Comeamos criando um projeto GWT.


No Eclipse (com o WTP e o Googlipse
instalados), acione File|New>Project>
Web>Dynamic Web Project. Na primeira
tela (Figura 2) preencha apenas o nome
do projeto (ComponentesGWT) e clique
em Next. Marque a opo Googlipse e finalize. O
projeto criado j possuir
Listagem 1. Script para criao do banco de dados. Apenas uma tabela ser
necessria.
as bibliotecas do GWT no
classpath.
CREATE TABLE artigogwt.contato (
contato_id BIGINT NOT NULL AUTO_INCREMENT,
Para comear a consnome VARCHAR(45),
truir nossos componentelefone VARCHAR(45),
celular VARCHAR(45),
tes precisamos criar um
email VARCHAR(45),
GWT Module. Clique com
endereco VARCHAR(150),
PRIMARY KEY(contato_id)
o boto direito sobre o
)
nome do projeto, navegue
at New>Other>Googlipse
e escolha a opo GWT
Module. Na prx i ma
tela configure o campo
Location: clique no boto
Create, e em Name fornea
br.com.jm.gwt; depois clique em Finish. Em Name
digite JMListaContatos
para o nome do mdulo.
Aps finalizar, trs pacotes sero criados:
br.com.jm.gwt.client Com
cdigo Java que ser transformado em JavaScript e
executar no browser.
Figura 1. Lista de contatos com paginao, DialogBox, campos editveis e fotografia.
Edio 39 Java Magazine

jm39.indb 39

39

15/8/2006 18:18:12

AJAX Avanado com GWT

br.com.jm.gwt.client.JMListaContatos.
java Classe responsvel por inicializar
os componentes e posicion-los dentro
do HTML. chamada pelo GWT de
Entry Point.
br.com.jm.gwt.JMListaContatos.gwt.xml
Documento que define as configuraes
do mdulo GWT e seus servios.
Deixe a classe JMListaContatos e o arquivo JMListaContatos.gwt.xml inalterados
por enquanto. Mas modifique o arquivo
JMListaContatos.html deixando-o igual
Listagem 2. Este arquivo inclui dois
componentes que so referenciados pelos
seus ids (contatos e fotografia) dentro de uma
tabela HTML:

Figura 2. Criando de um Dynamic Web Project

<table>
<tr>
<td id=contatos></td>
<td id=fotografia valign=top></td>
</tr>
</table>

Com a organizao do projeto concluda


(veja a Figura 3), podemos passar construo dos nossos componentes. Todos
os componentes sero criados dentro do
pacote br.com.jm.gwt.client.

Componente Fotografia
O primeiro componente que vamos criar
mostra a fotografia do contato selecionado, e estende a classe Image do GWT. Uma
funcionalidade adicional da nossa classe
Fotografia (mostrada na Listagem 3) que se no houver
imagem cadastrada para o
contato, ser mostrada uma
imagem padro. A classe
tambm demonstra o tratamento de eventos na leitura
de imagens.
Observe que o construtor de Fotografia recebe um
ob j e to da c l a s s e Contato
(Listagem 4). Na instanciao j definido o tamanho,
o estilo CSS e qual a URL da
imagem. Outro fato importante est na implementao
da interface LoadListener, atravs dos mtodos onError() e
onLoad(). O mtodo onError()

Listagem 2. HTML que define onde ficaro nossos componentes - JMListaContatos.html


<html>
<head>
<title>JavaMagazine - Lista de Contatos</title>
<meta name=gwt:module content=br.com.jm.gwt.JMListaContatos>
<link rel=stylesheet href=estilosListaContatos.css type=text/css>
</head>
<body>
<script language=javascript src=gwt.js></script>
<h1>Lista de contatos</h1>
<table>
<tr>
<!-- lista de contatos -->
<td id=contatos></td>
<!-- fotografia do contato -->
<td id=fotografia valign=top></td>
</tr>
</table>
</body>
</html>

chamado quando houver algum problema no carregamento da imagem, por


exemplo, quando ela no existir. nele
que carregamos uma imagem padro.
J o mtodo onLoad() chamado quando
a imagem carregada corretamente; ele
est vazio porque no precisamos de nenhum tratamento caso a imagem tenha
sido carregada com sucesso. Note ainda
que no construtor definida a prpria
instncia da classe como listener, com
addLoadListener(this).
O componente Fotografia ser utilizado em
dois lugares na nossa aplicao. Ao lado
da tabela de contatos e na caixa de dilogo
mostrada ao se selecionar um contato.

Componente MeuDialogBox
A API do GWT inclui o componente
DialogBox, que permite mostrar janelas
popup com informaes ou avisos. Em
nosso exemplo vamos criar uma classe que
estende DialogBox, para aproveitar caractersticas desse componente, como a exibio de uma rea de ttulo, a possibilidade
de arrast-lo e sua caracterstica modal
(enquanto a janela estiver ativa o restante
da aplicao fica bloqueado).
A Figura 1 mostra como ficar o layout da
nossa caixa de dilogo. Utilizamos um pouco
de CSS para ajudar na formatao do ttulo e
bordas. Colocamos a definio dos estilos no
arquivo estilosListaContatos.css (Listagem 5),
dentro da pasta br.com.jm.gwt.public. O CSS
importado pela pgina JMListaContatos.
html.
A maioria dos componentes grficos
(widgets) do GWT possui um estilo CSS
pr-definido, ou seja, voc precisa apenas defini-lo no seu arquivo CSS, que
o componente j o usar. O DialogBox
utiliza dois estilos, um para a janela e
outro para a rea de ttulo: gwt-DialogBox e
gwt-DialogBox .Caption.
A Listagem 6 mostra o cdigo do componente MeuDialogBox. No construtor foram
definidos o ttulo, o tamanho e a localizao da caixa de dilogo. A fotografia,
o contedo e o boto foram posicionados
dentro de um componente DockPanel. Para
entender mais sobre painis como este e
outros componentes grficos do GWT, veja
o quadro Panels e Widgets.

40 Java Magazine Edio 39


jm39.indb 40

15/8/2006 18:18:13

Note tambm que na criao do boto


de fechar j instanciamos um ClickListener,
que no evento de clique (onClick()) fechar a
caixa de dilogo atravs do mtodo hide(),
herdado da superclasse. E por ltimo, o
mtodo onKeyDownPreview(), que trata dos
eventos do teclado, define que ao pressionar Enter ou Esc a caixa de dilogo seja
fechada, tambm usando hide().

Trabalhando com Composites


A classe Composite do GWT tem a funo
de organizar a construo de componentes mais complexos. Ela funciona
como um wrapper de componentes,
escondendo os mtodos pblicos do
componente embrulhado. Normalmente configuramos o Composite com
um panel (ex. DockPanel) contendo vrios
componentes, pois dessa maneira possvel trat-los como um elemento nico.
Criaremos trs componentes baseados na
classe Composite:
BarraNavegacao Composto de u m
HorizontalPanel, que contm dois Buttons e
um Label.
TabelaEditavel Composto de um DockPanel
com a barra de navegao no topo e um Grid
centralizado.
ListaContatos Que instancia um componente TabelaEditavel com uma fonte de dados
e nomes das colunas.

Observe que um Composite pode ter


outros objetos Composite. Esse o caso da
ListaContatos e da TabelaEditavel. A seguir,
veremos detalhadamente como criar os
trs componentes citados.

Componente BarraNavegacao
A barra de navegao, cujo cdigo mostrado na Listagem 7, ter trs elementos:
dois botes (prximo e anterior) e um
Label. Seu construtor configura o posicionamento dos elementos dentro de um
HorizontalPanel, e recebe uma fonte de dados.
No se preocupe com a fonte de dados por
enquanto; veremos mais sobre ela ao tratar
dos servios do GWT.
A principal funo da barra de navegao

gerenciar os cliques nos botes de prximo e anterior, e mostrar a mensagem


Carregando... enquanto a tabela populada. A barra ser exibida acima da lista de
contatos, como j mostrado na Figura 1 e
seu layout definido como a seguir:
horizontalPanel.add(mensagemStatus);
horizontalPanel.setCellWidth(mensagemStatus, 100%);
horizontalPanel.add(btnAnterior);
horizontalPanel.add(btnProxima);

Para capturar os cliques de prximo


ou anterior, o componente BarraNavegacao
implementa ClickListener e se registra como
listener no momento da instanciao
dos botes (passando this como segundo
parmetro):

Figura 3. Estrutura de pacotes e arquivos de um projeto GWT

Edio 39 Java Magazine


jm39.indb 41

41

15/8/2006 18:18:15

AJAX Avanado com GWT

Listagem 3. Componente Fotografia Fotografia.java


import com.google.gwt.user.client.ui.*;

//posicao do DialogBox
setPopupPosition(DESLOCAMENTO_ESQUERDA,
DESLOCAMENTO_SUPERIOR);

public class Fotografia extends Image implements LoadListener {


public Fotografia(Contato contato) {

setWidth(TAMANHO_JANELA);

//configura o endereo da foto


setUrl(fotos/ + Long.toString(contato.getContatoId())
+ .jpg);

//Criando o boto para fechar o DialogBox, e o seu listener


Button btnFechar =
new Button(Fechar, new ClickListener() {
public void onClick(Widget sender) {
hide();
}
});

//configurando o tamanho da imagem


setWidth(110);
setHeight(110);
//configurando o estilo/css da imagem
setStyleName(fotografia);

//cria um DockPanel e define o layout do DialogBox


DockPanel panelBase = new DockPanel();
panelBase.add(imagem, DockPanel.WEST);
panelBase.add(btnFechar, DockPanel.SOUTH);
panelBase.add(new HTML(conteudo), DockPanel.CENTER);

//configura a prpria instncia como o loadListener


addLoadListener(this);

public void onError(Widget sender) {


setUrl(fotos/foto_padrao.jpg);
}
public void onLoad(Widget sender) {}

//configura a distncia entre os componentes deste panel


panelBase.setSpacing(4);

Listagem 4. Contato.java
public class Contato implements IsSerializable {
public long contatoId;
public String nome;
public String telefone;
public String celular;
public String email;
public String endereco;
public Contato() {}
}

//getters e setters ...

setText(titulo);

//configura o conteudo do DialogBox como sendo o DockPanel


add(panelBase);

public boolean onKeyDownPreview(char key, int modifiers) {


//caso o usurio tecle ESC ou ENTER o DialogBox se fechar
switch (key) {
case KeyboardListener.KEY_ENTER:
case KeyboardListener.KEY_ESCAPE:
hide();
break;
}
return true;
}

Listagem 7. BarraNavegacao.java

Listagem 5. Arquivo CSS com estilos utilizados pelos componentes GWT estilosListaContatos.css
.gwt-TextBox {
border-width: 0px;
height: 15;
width: 140;
font-size: 12;
}

public class BarraNavegacao extends Composite


implements ClickListener
{
public Button btnProxima = new Button(&gt;, this);
public Button btnAnterior = new Button(&lt;, this);
public Label mensagemStatus = new Label();
//... outros atributos

.gwt-DialogBox {
border: 2px solid #AAAAAA;
background-color: white;
}

public BarraNavegacao(FonteDeDados fdContatos) {


this.fdContatos = fdContatos;

.gwt-DialogBox .Caption {
background-image: url(imagens/back_degrad.gif);
background-repeat: repeat-x;
padding: 4px;
padding-bottom: 8px;
font-weight: bold;
cursor: default;
}

this.horizontalPanel.add(btnAnterior);
this.horizontalPanel.add(btnProxima);
this.btnAnterior.setEnabled(false);
setWidget(horizontalPanel);
}

public void onClick(Widget sender) {


if (sender == btnProxima) {
paginaAtual++;
}
else if (sender == btnAnterior) {
paginaAtual--;
}
setStatus(Carregando ...);
fdContatos.setPagina(paginaAtual);
}

.gwt-Button {
border: 1px solid #8E8E8E;
width: 70;
}

Listagem 6. Componente personalizado para o endereo do contato MeuDialogBox.java


public class MeuDialogBox extends DialogBox {
private final static int DESLOCAMENTO_ESQUERDA = 80;
private final static int DESLOCAMENTO_SUPERIOR =
(Window.getClientHeight() - 256) / 2;
private final static String TAMANHO_JANELA = 400px;
public MeuDialogBox(Image image, String titulo,
String conteudo)

// definio do layout da barra de navegao

public void setStatus(String status) {}


public void enable(boolean ultimaPagina) {}
}

42 Java Magazine Edio 39


jm39.indb 42

15/8/2006 18:18:15

Listagem 8. TabelaEditavel.java
public class TabelaEditavel extends Composite
implements TableListener
{
public TabelaEditavel(FonteDeDados fonteDeDados,
String[] nomesColunas,int nroRegistrosPagina)
{
//... config. dos atributos com os valores dos parmetros
// configura esta instncia como o Listener do Grid
// para receber informaes sobre o clique, linha e coluna
grid.addTableListener(this);
//adiciona a barra de navegao e o Grid ao DockPanel
panelBase.add(barraNavegacao, DockPanel.NORTH);
panelBase.add(grid, DockPanel.CENTER);
//configura o Composite com o DockPanel
setWidget(panelBase);
}

//... mtodos para layout tamanho, cabealho, css, etc

/* trata os eventos de cliques na tabela */


public void onCellClicked(SourcesTableEvents
sender, int row, int cell)
{
//retornar se clique for no cabealho
if (row == 0) return;

//se clicado na primeira coluna, mostra a caixa de dilogo


if (cell == 0) {
mostraDialogBox(row);
return;
}
//troca o contedo da clula por um campo editvel
if (cell > 1) {
editaCelula(row, cell, widget);
}
// definies de layout - destacar linha selecionada
}

private void mostraDialogBox(int row) {


Contato contato = getContato(row);
Fotografia fotografia = new Fotografia(contato);

private void atualizaRegistro(


int row, int coluna, String conteudoCelula)
{
//substitui o TextBox por um Label
Label label = new Label();
TextBox textBox = (TextBox) grid.getWidget(row, coluna);
label.setText(textBox.getText());
grid.setWidget(row, coluna, label);

//instancia o DialogBox que criamos


MeuDialogBox dialogBox = new MeuDialogBox(
fotografia, Contato:
+ contato.getNome(), <b>Endereco: </b> <br />
+ contato.getEndereco());
}

dialogBox.show();

//busca o registro alterado


Contato contato = getContato(row);

private void editaCelula(final int row,


final int cell, Widget labelCelula)
{
//troca o contedo da clula - de Label para TextBox
final TextBox textBox = new TextBox();
textBox.setText(((Label) labelCelula).getText());
grid.setWidget(row, cell, textBox);

// como o GWT no possui suporte para reflection,


// usamos um switch
switch (coluna) {
case 2:
contato.setTelefone(conteudoCelula);
break;
case 3:
contato.setCelular(conteudoCelula);
break;
case 4:
contato.setEmail(conteudoCelula);
break;
}

//ao pressionar Enter atualiza o registro com a alterao


textBox.addKeyboardListener(new KeyboardListener() {
public void onKeyDown(Widget sender,
char keyCode, int modifiers) {}
public void onKeyPress(Widget sender,
char keyCode, int modifiers) {}
public void onKeyUp(Widget sender,
char keyCode, int modifiers)
{
switch (keyCode) {
case KeyboardListener.KEY_ENTER:
atualizaRegistro(row, cell, textBox.getText());
break;
}
}
});

//ao perder o foco atualiza a base de dados com o novo valor


textBox.addFocusListener(new FocusListener(){});

//atualiza base de dados


fontDeDados.updateContato(contato);

private void mostraFoto(int row) {}


public void atualizaDados(List contatos) {}
private void configuraGridLayout() {}
private Contato getContato(int row) {}
private void marcarLinha(int row) {}

Edio 39 Java Magazine


jm39.indb 43

43

15/8/2006 18:18:20

AJAX Avanado com GWT

public Button btnProxima = new Button(&gt;, this);


public Button btnAnterior = new Button(&lt;, this);

Assim que um dos botes clicado,


chamado o mtodo onClick(). Em seqncia, o componente atualiza o atributo
paginaAtual, muda a mensagem do Label
para Carregando..., e chama o mtodo
setPagina() da fonte de dados.
Veja que a barra de navegao no possui
referncia ao componente TabelaEditavel,
interagindo apenas com a fonte de dados.
a fonte de dados que responsvel por
atualizar os objetos conectados a ela.

Componente TabelaEditavel
O componente TabelaEditavel o mais
complexo que criaremos neste artigo.
Veja seu cdigo na Listagem 8. A estrutura interna do componente construda
dentro de um DockPanel, com um componente BarraNavegacao na posio NORTH, e um
Grid (da API do GWT) no centro, onde sero
exibidos os dados dos contatos.
O construtor instancia a barra de navegao j com uma fonte de dados, guarda o
nmero de registros por pgina, configura
a prpria instncia como o listener do Grid
(para capturar os cliques sobre ele), e determina o layout dos componentes dentro
do DockPanel.
O mtodo onCellClicked() chamado quando algum evento de clique ocorre na grade. Caso o clique tenha sido na primeira
coluna, mostrada uma caixa de dilogo
com o endereo do contato. Um clique nas
outras colunas tornar a clula correspondente editvel.
O mtodo mostraDialogBox() instancia a
caixa de dialogo j com uma fotografia
e o endereo do contato configurados.
A caixa de dilogo exibida atravs do
mtodo show(). E editaCelula() substitui
o Label na clula clicada por um TextBox
(da API do GWT) para edio do valor.
Este TextBox ter dois listeners. Um para
eventos de foco, FocusListener, e outro para
eventos de teclado, KeyboardListener. Quando o TextBox perder o foco ou o usurio
pressionar Enter, ser chamado o mtodo
atualizaRegistro() para persistir no banco de
dados a alterao efetuada.
Por fim, o mtodo atualizaRegistro() substitui o TextBox por um Label, atualiza o campo

correto do objeto Contato e persiste a alterao atravs da fonte de dados.


Alm disso, para saber qual registro foi
selecionado, mantido um mapeamento
interno entre as linhas da grade e os contatos exibidos. Assim, quando uma linha
selecionada, o objeto Contato correspondente tambm o .

de explicarmos seu cdigo, veremos uma


breve introduo sobre esses servios.
O GWT j traz pronta uma infra-estrutura para trabalhar com RPCs (Remote
Procedure Calls) facilitando a troca de
objetos Java entre o cliente (o browser)
e o servidor. Todas as chamadas so
assncronas, logo a interface grfica fica

Componente ListaContatos
O componente ListaContatos, com cdigo
mostrado na Listagem 9, rene uma fonte
de dados (objeto FonteDeDados) e um componente TabelaEditavel. A fonte de dados
recebe o nmero de registros por pgina,
e a tabela editvel recebe os nomes das
colunas, o nmero de registros por pgina
e a prpria fonte de dados.

Servios no GWT
Para fazer acesso aos dados dos contatos
no banco, utilizaremos a classe FonteDeDados.
Esta classe faz uso da infra-estrutura de
servios remotos do GWT, assim antes

Figura 4. Configurando o servio remoto

Listagem 9. ListaContatos.java: componente que rene a tabela editvel e a fonte de dados


public class ListaContatos extends Composite {
private TabelaEditavel tabelaEditavel;
private FonteDeDados fdContatos;

public ListaContatosWidget(int nroRegistrosPagina) {


String[] nomesColunas = new String[] { , Nome, Telefone, Celular,
E-mail };
this.fdContatos = new FonteDeDados(nroRegistrosPagina);
this.tabelaEditavel = new TabelaEditavel(fdContatos, nomesColunas,
nroRegistrosPagina);
setWidget(tabelaEditavel);
}

Listagem 10. ContatosService.java: interface de servio


package br.com.jm.gwt.client.service;
// imports
public interface ContatosService extends RemoteService {
//mtodos de servios
public List getContatos(int posicaoInicial, int nroRegistrosPagina)
throws Exception;
public void updateContato(Contato contato) throws Exception;
public static final String ENTRY_POINT = /contatosService;

public static class Util {


public static ContatosServiceAsync getInstance() {
ContatosServiceAsync instance = (ContatosServiceAsync) GWT
.create(ContatosService.class);
ServiceDefTarget target = (ServiceDefTarget) instance;
target.setServiceEntryPoint(ENTRY_POINT);
return instance;
}
}

44 Java Magazine Edio 39


jm39.indb 44

15/8/2006 18:18:21

Panels e Widgets

este artigo utilizamos vrios painis (panels)


e componentes grficos (widgets) da API do
GWT. Aqui apresentamos uma breve explicao
sobre cada um deles.

Panels
Os panels so recipientes de componentes
grficos utilizados para facilitar o posicionamento e o agrupamento. Utilizamos trs tipos
de painis no exemplo: HorizonalPanel, DockPanel
e RootPanel.

HorizontalPanel
Este tipo de painel organiza seus componentes
da esquerda para direita em uma mesma linha,
e o utilizamos para organizar os Buttons e o Label
de mensagem na barra de navegao.

seguir um pouco sobre os componentes utilizados neste artigo.

TextoBox
Campo simples para entrada de texto. Seu
estilo CSS padro : gwt-TextBox. Principais
mtodos:
getText():: retorna o texto digitado no campo;
getSelectedText():: retorna o texto selecionado
dentro do campo;
selectAll():: seleciona todo o texto dentro do
campo;
setText(String):: configura o valor do campo;
addChangeListener ( ) , addClickListener ( ) ,
addKeyboardListener(): adicionam listeners para
mudana do contedo, eventos de mouse e
teclado, respectivamente.

DockPanel
O DockPanel possiciona os seus elementos
seguindo a numerao da Figura Q1 (extrada
da documentao do GWT). Aps colocar um
widget na posio central nenhum outro widget deve ser adicionado ao DockPanel. Se no
for indicado o posicionamento ao adicionar os
componentes, o ltimo a ser adicionado ocupar a posio central. No exemplo, utilizamos o
DockPanel para fazer o layout da caixa de dilogo
e da tabela editvel.

RootPanel
O RootPanel o ltimo painel no qual um componente deve ser adicionado. Sua localizao
definida dentro do HTML principal (Host Page),
normalmente utilizando-se um id. O RootPanel
instanciado pelo GWT e obtido atravs de dois
mtodos estticos:
RootPanel.get(): retorna o RootPanel padro
da aplicao.
RootPanel.get(String id): retorna o RootPanel associado a um elemento/id definido no HTML.
O RootPanel no possui um layout definido.
Sua funo apenas receber componentes e
exibi-los.

Widgets
A API do GWT fornece componentes grficos
(widgets) para vrios fins, por exemplo campos
de texto, checkboxes, tabelas, menus, janelas
popup, rvores de navegao e grades. Veja a

Button
Um boto HTML normal. Seu estilo CSS padro
: gwt-Button. Principais mtodos:
click(): equivalente a clicar no boto;
addClickListener(), addKeyboardListener(): adiciona listeners para eventos de clique e de
teclado.

Image
Componente para exibio de imagens a
partir de uma dada URL. Seu estilo padro :
gwt-Image{}. Principais mtodos:
setUrl(): configura a URL da imagem a ser
exibida;
addClickListener () , addLoadListener () ,
addMouseListener(): adiciona listeners para eventos
de clique, carregamento de imagem e mouse.

setHTML(int linha, int coluna, String str): adiciona


um cdigo HTML em uma determinada clula;
getWidget(), getText(), getHTML(): retornam o
widget, a string ou cdigo HTML de uma determinada clula;
addTableListener(): adiciona um listener para
eventos de clique sobre a tabela.

DialogBox
Caixa de dilogo que possui rea de ttulo e a
possibilidade de arrast-la. O DialogBox utiliza dois
estilos, um para a janela e outro para a rea de
ttulo: gwt-DialogBox e gwt-DialogBox .Caption.
No nosso exemplo, estendemos este componente para customiz-lo conforme nossas
necessidades de layout, e para tratar eventos de
teclado. Principais mtodos:
setText(): configura o ttulo da caixa de dilogo.
setHTML(): configura o contedo da caixa de
dilogo com um cdigo HTML.
addWidget(): configura o contedo da caixa
com um widget.

Grid
Tabela redimensionvel que pode
conter texto, html ou widgets. No
possui estilo padro. Principais mtodos:
resize(int, int): redimensiona a
tabela;

setWidget(int linha, int coluna, Widget w):
adiciona um widget em uma determinada clula;
setText(int linha, int coluna, String str):
adiciona uma String em uma determina
clula;

north (0)

west
(1)

west
(2)

center
(5)

east
(3)

south (4)
Figura Q1. Ordem de posicionamento de componentes em um
DockPanel

Edio 39 Java Magazine


jm39.indb 45

45

15/8/2006 18:18:25

- Java no Governo
- Apache FOP
- JSTL Guia Completo
- Cocoon Inicial
- Pacotes WAR e JAR

- Cdigos no Eclipse
- New I/O Fundamental
- Game API
- Criando Plug-ins para Eclipse
- Preferences API

- Multimdia no celular
- Automao com Ant
- Robocode
- Tag Libraries JSP
- Processando XML em Java

- Ec
-O
- Se
- In
- Ex

Edio 14

Edio 13

- Dados em J2ME
- JavaServer Faces
- Jogos wireless
- Certificao J2EE
- Montando um ambiente Java

Edio 12
- Tutorial de NetBeans
- API New I/O (java.nio)
- Cesta de compras com Struts
- Testes de carga com JMeter
- Concorrncia e a JVM

Edio 4

Edio 3

Edio 2
- Ferramentas livres
- Introduo ao J2EE 1.4
- Introduo a J2ME
- J2EE Fundamental
- Dados com JDBC

Edio 11

Edio 9

Edio 10

Complete
a sua
coleo!

Edio 1

AJAX Avanado com GWT

- Relatrios Corporativos
- Grficos com Java 2D
- Java.net na Prtica
- Raio-X do Tiger
- Paginao na Web

- Eclipse para Web


- Fome Zero com Java
- Tags Customizadas em JSP 2.0
- Tiger: A Evoluo do Java
- Dicas para Web

- Fo
- AN
- JB
- Ex
- Me


GINAS

.EWS #ARTAS 4IRA $VIDAS%XTREME0ROGRAMMING #OLLECTIONS 4OMCAT

*AVA7EB3TARTNAPRTICA

!TECNOLOGIAPARADISTRIBUIODEAPLICAES*AVA

)NTEGRANDOO*-%EM0$!S

!CESSESISTEMASDEARQUIVOSEAPLICAESNATIVAS

4HINLET,EVEZANO$ESKTOP

5MAALTERNATIVAAO3WINGPARAAPLICAES'5)

$OMANDOO#LASSPATH

4IRESUASDVIDASSOBREESTECONCEITOESSENCIAL

%SPECI

*6

%SPECIAL

'ERENCIAMENTOCOM*-8

#ONH
*AVAE
EBEN

- JavaMail
- Por Dentro do Apache Derby
- Clusters com Tomcat e Apache
- Mais HttpClient
- Examinando o Mustang

- SWT no Eclipse
- Eclipse Web Tools Project
- Validao avanada com Struts
- Fronteiras do Java
- CD do NetBeans

- NetBeans 5.0
- Aprendendo Groovy
- Test-Driven Development
- Debate Internacional Sou+Java
- Java Business Integration (parte 1)

Edio 24

/)$
NOV
ESTR

-N
-M
- Gr
- Su
- Ta

- O Projeto Eclipse
- Segurana no JBoss
- JSF Avanado
- Comeando com Java
- Tira-dvidas

Edio 32

- Criptografia aplicada
- XML de alto desempenho
- Segurana em apllicaes web
- JSF Passo a Passo
- Datas e Horas em Java

Edio 34

*ASPER2EPORTSEI2EPORT0ASSAGEMDE
0ARMETROS 2ELATRIOSDINMICOS
)MAGENSE*AVA"EANS

Edio 23

2ELATRIOS!VANADOS

Edio 33

!PLIQUE0ADRESDE0ROJETO
%SSENCIAISNOSSEUS0ROJETOSE
'ANHEEM1UALIDADEE2EUTILIZAO

Edio 31
- HSQLDB
- Internacionalizao de MIDlets
- Performance na JVM
- Caso de sucesso: Procon
- Benchmarks JME

46 Java Magazine Edio 39


www.javamagazine.com.br
jm39.indb 46

-AIS0ATTERNS!PLICADOS

- Relatrios avanados
- Mais design patterns
- Gerenciamento com JMX
- Java Web Start
- Dvidas de classpath

- Threads no Java 5.0


- Cadastros com Struts
- MVC na web
- Servlet API Avanada
- Padres de projeto

Edio 30

Edio 29

- JSTL aplicado no Tomcat 5


- Modularizando pginas com Tiles
- Componentes View do Struts
- O rugido do Java livre

0ATTERNS

2ELATRIOS

Edio 22

Edio 21

Edio20

Edio 19

%XTRAIAOMXIMODASTECNOLOGIASDE
GERENCIAMENTODEAPLICAES QUEHOJEFAZEM
PARTEDOCORAODE*AVAESOESSENCIAISEM
SISTEMASCOMPLEXOS

- Hibernate em aplicaes web


- Java 6 (Mustang)
- Programao em par
- Processos geis
- Java Business Integration (parte 2)

devmedia.com
15/8/2006 18:18:38

-P
- Te
-W
- Sc
-A

.b

arte 2)

om

- Formulrios com Swing


- ANT - Automatizando Java
- JBoss e Entity Beans
- Extreme Programming
- Metaprogramao e Reflection

GINAS

Edio 8

Edio 7
Edio 17

Edio 16
- Genricos no Tiger
- JBuilder para web
- MIDP 2.0
- JavaOne 2004
- Segurana com JAAS

- Otimizao de EJBs no JBoss


- Processamento de imagens
- Programao com regras
- Jakarta Taglibs
- Case J2ME

Java 5 Impresso Java Content Repository Caches e JDBC NetBeans JavaOne

'RFICOSCOM*&REE#HART

!2EVISTADA#OMUNIDADE*AVA"RASILEIRA

Imprimindo com Java

#RIEGRFICOSDENEGCIOSPARAAPLICAES
DESKTOPEWEBUSANDO!0)SLIVRES

Conhea duas APIs de impresso do


J2SE e obtenha controle fino
sobre layout e formatao

3UPER7ABA)NICIAL

$ESENVOLVAPARA0$!SCOM
FERRAMENTAS*AVAECONHEA
OMUNDODOSHANDHELDS

Gerncia de Contedo
Detalhes sobre a Novssima API
JCR e a Criao de Repositrios
de Contedo na Web

Edio 24 - Ano III - R$ 9,90

4AGS*30COM4AG&ILES

!MANEIRAMAISSIMPLESDECRIARTAGS
CUSTOMIZADASPARAPGINAS*30
%SPECIAL

*6-S!LTERNATIVAS
#ONHEAMAISDEMQUINASVIRTUAIS
*AVAEEXPLORETCNICASDEOTIMIZAO
EBENCHMARKS

- JSP 2 e Servlets no Tomcat 5


- Primeiros passos com wireless
- Collections avanado
- Conhecendo o JDeveloper 10g
- Servlets: do bsico ao avanado

- SwingWT
- Java 2D: Animao e impresso
- Anotaes no Java 5
- Projeto Looking Glass
- Java 2D: Animaes e Impresso

*6-Sv*30v%CLIPSEv!NTv3UPER7ABAv*&REE#HARTv.OTCIASv#ARTAS

- JavaOne 2003
- Conhecendo o CVS
- JSTL- Guia completo SQL e Format
- Tomcat e o Servidor Apache

- Bancos de dados livres


- Testes unitrios com JUnit
- JSTL- Guia Completo: tags Core
- Java na Droga Raia
- Validao na Web

- Introduo ao Tomcat
- Conectivade com MIDP
- Struts, primeiros passos
- Automao com XDoclet
- Jakarta Velocity

Edio 18

- JBoss Inicial
- Introduo ao JMX
- Java no Lego Mindstorms
- Logging
- Memria e desempenho

Edio 15

Edio 14

Edio 6

Edio 5

Edio 4
- Eclipse inicial
- O mercado J2ME
- Segurana em aplicaes web
- Interfaces ricas com Flash
- Expresses regulares no J2SE 1.4

Uma Aplicao Java


Completa com NetBeans

%CLIPSE#ON

!SNOVIDADESDO)$%EDEOUTROS
PROJETOSDA&UNDAO%CLIPSE

Parte final Acesso a Banco


de Dados e Gerncia de
Preferncias de Usurios

Tira-Dvidas Especial
Caches e DAOs com JDBC, Usando
JVMs Alternativas, Relatrios e
Driblando Restries
da Mquina

- Aplicao Completa - Parte 1


- Desempenho com JDBC e DAOs
- Portlets - Fundamentos
- JFreeChart Avanado
- O Novo Extreme Programming

Edio 35

Edio 34

- Novo NetBeans
- Mquinas virtuais alternativas
- Grficos com JFreeChart
- SuperWaba Inicial
- Tag Files do JSP 2.0

- Para onde vai o Struts


- Teste com J2MEUnit
- Web Services
- Scripting na JVM
- Aspectos no Mundo Real

.br/anteriores
jm39.indb 47

- Frameworks de Logging
- Otimizao de Cdigo
- Ajuda com JavaHelp
- Maven 2 Essencial
- Java ME no Eclipse

Edio 27

&

- Aplicao Completa - Parte 2


- Mais Desempenho com JDBC
- Portlets - Recursos Avanados
- Jakarta Commons Inicial
- Nmeros: Conceitos e Formatao

JavaOne 2005

Grandes novidades em
produtos e APIs, planos e
comemoraes no evento
mundial da tecnologia Java

Migrando para o Java 5


Conhea na prtica e em detalhes
como, porque e quando fazer o
upgrade para o J2SE 5.0

- Aplicao Completa - Parte 3


- Migrando para o Java 5
- Impress o com Java
- Gerenciamento de Contedo
- JavaOne 2005

- Conhecendo o Ant
- Acessando Cdigo Nativo
- Qualidade Aplicada
- Migrando para o Maven 2
- Logging no Java SE

Edio 28

Futuro
Presente

- Hibernate Fundamental
- Apache Geronimo na Web
- Ajax: Interatividade Turbinada
- Tutorial de Genricos
- De Volta aos Patterns

Leia uma vez,


use em todos
os lugares

Edio 37

/)$%LIVREPATROCINADOPELA3UNHOJEUMAFERRAMENTAINTEIRAMENTE
NOVA2EVEJAOSFUNDAMENTOSDO)$% CONHEANAPRTICAANOVA
ESTRUTURADEPROJETOSBASEADANO!NTESAIBAOQUEVIRNAVERSO

Edio 26

.ET"EANS
.ET
ET

Edio 36

/NOVO

Edio 25

Edio 24

Java:

- Criao de Plug-ins
- Os 10 Mais do Eclipse 3.2
- JavaOne 2006
- Relatrios Passo a Passo
- Testes com mock objects

4
21 2283 9012

Edio 39 Java Magazine

15/8/2006 18:18:46

AJAX Avanado com GWT

livre para eventuais mudanas enquanto


os dados no chegam. Isso aumenta a
performance da aplicao e faz com que
se consiga paralelismo mesmo sem usar
mltiplos threads j que uma parte do
cdigo executada no servidor e a outra,
que trata dos eventos da interface grfica,
executa no cliente.

Para criar um servio remoto no GWT temos que definir uma interface de servio,
na qual so escritos os mtodos a serem
expostos. A implementao dos mtodos
fica a cargo de uma classe que ser executada no servidor como um servlet. Esta
classe alm de implementar a interface de
servio estende a classe RemoteServiceServlet

da API do GWT.
Outra interface tambm deve ser criada: a
interface assncrona. Seus mtodos sero os
mesmos da interface de servio, porm tero
um parmetro a mais: um objeto de callback,
que receber o retorno do servio assim que
ele for processado. Outra diferena que
todos os seus mtodos retornam void.

Listagem 11. ContatosServiceAsync.java: interface assncrona

Listagem 13. JMListaContatos.gwt.xml: arquivo de configurao do mdulo GWT

package br.com.jm.gwt.client.service;

<module>
<inherits name=com.google.gwt.user.User />

// imports
public interface ContatosServiceAsync {
public void getContatos(int posicaoInicial,
int nroRegistrosPagina, AsyncCallback callback);
public void updateContato(Contato contato,
AsyncCallback callback);
}

<!-- Especifica o Entry Point do mdulo -->


<entry-point class=br.com.jm.gwt.client.JMListaContatos />
<!-- Servio criado para acesso a dados -->
<servlet path=/contatosService
class=br.com.jm.gwt.server.ContatosServiceImpl />
</module>

Listagem 14. FonteDeDados.java


Listagem 12. Implementa os servios de acesso a dados ContatosServiceImpl.java
package br.com.jm.gwt.server;
// imports

public class FonteDeDados {


private int nroRegistrosPagina;
private TabelaEditavel tabelaEditabel;
public FonteDeDados(int nroRegistros) {
this.nroRegistrosPagina = nroRegistros;
setPagina(0);
}
public void setPagina(int pagina) {
ContatosServiceAsync service =
ContatosService.Util.getInstance();
service.getContatos(pagina * nroRegistrosPagina,
nroRegistrosPagina, new ContatosCallBack());
}
public void setTabelaEditabel(TabelaEditavel tabelaEditabel) {
this.tabelaEditabel = tabelaEditabel;
}

public class ContatosServiceImpl extends RemoteServiceServlet


implements
ContatosService
{
public ContatosServiceImpl() {}
public List getContatos(int posicaoInicial,
int nroRegistrosPagina) throws Exception
{
List temp = new ArrayList();
String sql =
select contato_id, nome, telefone, celular, email,
+ endereco from contato limit
+ posicaoInicial + , + nroRegistrosPagina);
Connection conn = getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);

public void updateContato(Contato contato) {


ContatosServiceAsync service =
ContatosService.Util.getInstance();
service.updateContato(contato, new UpdateCallBack());
}
private class ContatosCallBack implements AsyncCallback {
public void onFailure(Throwable caught) {
Window.alert(caught.getMessage());
}
public void onSuccess(Object result) {
tabelaEditabel.atualizaDados((List) result);
}
}

while (rs.next()) {
temp.add(buildContato(rs));
}
return temp;
}
public void updateContato(Contato contato) throws Exception {
String sql = update contato set nome = ?,
telefone = ?, celular = ?,
email = ? where contato_id = ?;
Connection conn = getConnection();
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, contato.getNome());
stmt.setString(2, contato.getTelefone());
stmt.setString(3, contato.getCelular());
stmt.setString(4, contato.getEmail());
stmt.setLong(5, contato.getContatoId());
stmt.execute();
}
private Contato buildContato(ResultSet rs)
throws Exception {...}
public Connection getConnection()
throws ClassNotFoundException, SQLException {...}

private class UpdateCallBack implements AsyncCallback {


public void onFailure(Throwable caught) {
Window.alert(Erro ao atualizar o banco de dados);
}
public void onSuccess(Object result) {}
}

Listagem 15. Inicializa os componentes do mdulo JMListaContatos.java


public class JMListaContatos implements EntryPoint {

}
}

public void onModuleLoad() {


//lista os contatos com 15 registros por pgina
RootPanel.get(contatos).add(new ListaContatos(15));
}

48 Java Magazine Edio 39


jm39.indb 48

15/8/2006 18:18:46

Criando nosso servio


Para criar nosso servio utilizaremos o
plug-in Googlipse que facilita a criao
e sincroniza os mtodos entre a interface
de servio e a interface assncrona. Clique
com o boto direito sobre o nome do projeto, siga New>Other>Googlipse e escolha
GWT Remote Service. No campo Module,
clique em Browse, navegue at o pacote
br.com.jm.gwt e escolha o XML do nosso
mdulo; em Service Name, fornea ListaContatosService, digite contatosService em
Service URI (veja Figura 4), e finalize.
Sero geradas a interface de servio
ContatosService, a i nterface ass ncrona
ContatosServiceAsync e a classe de implementao ContatosServiceImpl.
Definiremos na nossa interface de
servio dois mtodos: getContatos(), para
buscar a lista de contatos; e updateContato(),
para atualizar o contato que foi editado.
Veja as mudanas na Listagem 10. Ao
salvar a interface alterada, voc ver que o
Googlipse atualiza a interface assncrona
criando dois mtodos semelhantes aos de
ContatosService (veja a Listagem 11).
Na classe ContatosServiceImpl implementamos os mtodos de servio definidos
em ContatosService, como mostrado na
Listagem 12. Observe que fizemos acesso
direto ao banco de dados; em uma aplicao real seria recomendado o uso do
pattern DAO (por exemplo).
Devemos tambm adicionar os servios

criados ao arquivo de configurao do


nosso mdulo, br.com.jm.JMListaContatos.
gwt.xml. Deixe esse arquivo como na
Listagem 13.

Montando o quebra-cabea
Com os servios e os componentes
prontos, vamos agora uni-los. Chegou
a hora de falar da fonte de dados, cujo
cdigo mostrado na Listagem 14. A
classe FonteDeDados bem simples; ela
contm duas inner classes, ContatosCallBack
e UpdateCallBack. Ambas possuem dois mtodos: onFailure(), para tratamento de erros
na chamada do servio, e onSuccess(), para
receber o retorno.
A classe ContatosCallBack ser usada para
receber o resultado da pesquisa de contatos e configurar a tabela com os dados retornados. A segunda no possui nenhuma
implementao especfica pois o servio
se trata de um update, no havendo neste
exemplo retorno do servidor. Em ambas
tratamos os erros de maneira simples,
monstrando um PopUp com uma mensagem. Os mtodos updateContato() e setPagina()
fazem as chamadas de servios.
Vamos voltar agora classe JMListaContatos,
a classe que o ponto de entrada (Entry Point) do mdulo GWT. Altere esta
classe e deixe-a como na Listagem 15.
Em seu mtodo onModuleLoad() buscamos
um RootPanel com id contatos. Lembre
que definimos este mesmo id no arquivo
JMListaContatos.html e
justamente l que colocaremos nossa lista de
contatos. Ento adicionamos um componente
ListaContatos ao RootPanel.
Com isso, assim que
o arquivo HTML for
exibido, o GWT iniciar
o mdulo e carregar
nossa lista de contatos.

Visualizando
o exemplo

Figura 5. Criando uma configurao para executar o exemplo

Pa r a v i s u a l i z a r a
aplicao de exemplo,
abra o menu de configuraes de execuo
(Run|Run). Na rvore

de configuraes escolha a opo GWT


Application e crie uma nova configurao.
Preencha a tela como a Figura 5 e clique
em Run. Sua aplicao ser exibida e dever estar semelhante Figura 1.

Concluses
O GWT uma excelente opo para
tornar o desenvolvimento web mais
produtivo na criao de aplicaes AJAX.
Alguns sites j se especializaram em componentes para GWT, o que pode salvar
muito tempo de desenvolvimento (veja
links). H inclusive IDEs que j trazem
suporte nativo ao GWT, como o IntelliJ e
o VistaFei (este ltimo j possui suporte
a arrastar-e-soltar para os widgets).

google.com/options
Links para os produtos do Google, como Google
Maps.
www.googlipse.com
Plugin do Eclipse para o GWT.
eclipse.org/webtools
Plugin do Eclipse para desenvolvimento Web.
intellij.net
IDE para desenvolvimento Java com suporte
nativo ao GWT.
www.wirelexsoft.com/VistaFei.html
IDE com desenvolvimento arrastar-e-soltar para
o GWT.
gwtpowered.org
Site com tutoriais, artigos e links para download
de componentes GWT.
java.sun.com/blueprints/corej2eepatterns/
Patterns/DataAccessObject.html
Artigo sobre o design pattern Data Access Object
(DAO)
javamagazine.com.br/downloads/jm39/
jm-componentesgwt.zip
Ari Dias Neto
(aridiasneto@gmail.com)
consultor Java/J2EE com experincia de mais de sete anos em
tecnogias para web. Atualmente atua
em projeto internacional para IBM. Certificados: SCJP,
SCWCD, EA(I) e Borland CaliberRM Certified.

Edio 39 Java Magazine


jm39.indb 49

49

15/8/2006 18:18:49

Interfaces Grficas co m
Parte 2: Presentation Model e a API Binding

a primeira parte desta


srie apresentamos tcnicas bsicas para um bom
projeto visual de interfaces grficas (GUIs), discutindo questes
de organizao e posicionamento
de elementos que compem as telas. Criamos tambm um exemplo
demonstrando como a API Forms do
JGoodies pode ajudar na construo
de GUIs que utilizam componentes
Swing.
Nesta segunda e ltima parte,
iremos nos aprofundar no cdigo
que est por trs da interface e
que se comunica com o ncleo
do software. Nossa discusso
comea tratando de algumas
questes que envolvem problemas e necessidades do
desenvolvimento de GUIs.
Apresentamos o pattern Presentation Model, como uma das
estratgias mais eficazes atualmente para o desenvolvimento de
aplicaes desktop, e vemos seu funcionamento detalhado e a contribuio trazida pela API
Binding do JGoodies.
Ao longo de todo
o processo,

50 Java Magazine Edio 39


jm39.indb 50

15/8/2006 18:18:56

Descubra como aplicar o


padro Presentation Model
e a API Binding do JGoodies
para construir GUIs de
alta produtividade que
favorecem os testes unitrios

o m Qualidade

do JGoodies

HUGo vidaL teiXeira


construmos um exemplo que apresenta
diversas caractersticas desejadas em
aplicaes modernas.

Patterns e testes em GUIs


A alta produtividade no desenvolvimento de GUIs em aplicaes desktop
pode ser alcanada com a ajuda de dois
elementos importantes no nvel do cdigo:
a separao de interesses e a eficcia de
testes unitrios
unitrios.

Separao de interesses
Sep
A separao de interesses, no nosso caso,
significa separar o estado e a lgica da GUI,
dos componentes grficos utilizados. Voc
provavelmente j deve ter ouvido falar em
patterns que fazem essa separao, como
o Model-View-Controller (MVC), que vem
sendo usado tanto no desenvolvimento de
aplicaes desktop quanto web.
Embora a separao de interesses traga
muitas vantagens ao desenvolvimento,
ela exige cdigo especfico para sincronizar as variveis que guardam o estado
da GUI com os componentes grficos.
Normalmente as telas recebem objetos
de negcio (JavaBeans, por exemplo) do
backend e precisam transferir seus dados
para os componentes grficos, e vice-versa.
Para que essa conexo entre os dois lados
possa ser programada sem muito esforo,
precisamos da ajuda de um framework
genrico que interligue objetos de
negcio e componentes grficos.
Esse papel da API Binding do
JGoodies, que estudaremos nesse
artigo.

Eficcia de testes unitrios


Outro problema que atinge o
desenvolvimento de GUIs a
dificuldade de se construir testes
unitrios abrangentes e eficazes,
que simulem as interaes do

usurio com a GUI, reproduzindo cliques


do mouse e eventos de teclado1.
Mas ser que a separao de interesses
no poderia ajudar nesses testes, j que
a lgica est separada dos componentes
grficos? Para responder essa pergunta,
vamos examinar a Figura 1, que apresenta
os trs principais patterns para o desenvolvimento de GUIs em aplicaes desktop.
Observe a estrutura do Model-ViewPresenter (MVP) que uma pequena variao do MVC. O importante a ser observado
aqui o fato de que tanto no MVC quanto
no MVP, o controlador (Controller/Presenter)
possui uma referncia para a viso (View).
Assim, para instanciar um controlador
dentro de um teste unitrio, precisamos
da viso com seus componentes grficos
tambm. Isso faz com que o desenvolvimento de testes unitrios ainda continue
bastante difcil.
Existe uma soluo para contornar esse
problema: adicionar uma interface entre o
controlador e a viso. Mas no vale a pena
explorar essa alternativa quando temos
uma terceira opo como o Presentation
Model, descrito a seguir.

O pattern Presentation Model


O pattern Presentation Model, tambm
ilustrado na Figura 1, bastante diferente
dos outros dois porque quem detm a lgica
e o estado da GUI a classe Presentation
Model-View-Controller

Estrutura e classes
Quando aplicamos o pattern Presentation Model no desenvolvimento de uma
GUI, precisamos criar basicamente trs
classes:
View Classe simples que contm os
componentes grficos da GUI. Os dados
apresentados na tela refletem o estado
mantido pela classe Presentation Model.
Presentation Model Classe que contm o estado e a lgica da GUI. Os dados
e variveis so manipulados em memria,
independentemente da existncia de componentes e formas de apresentao.
Service Layer Classe que oferece
classe Presentation Model uma comunicao com o mundo exterior, onde servios
externos podem existir (como EJBs, bancos
de dados etc.)
A separao em classes com diferentes responsabilidades traz vantagens
1
Um dos fatores que torna isso muito difcil a existncia de somente uma thread para executar o cdigo do
teste e o cdigo que renderiza os componentes na tela. A
thread nica um requisito imutvel de APIs como Swing
e AWT.

Model-View-Presenter

Model

View

Model no possui uma referncia para a


classe View. Ocorre exatamente o contrrio:
a classe View que guarda uma referncia
para a classe Presentation Model. Isso extremamente valioso na criao de testes.

Model

Controller

View

Refercia
Notificao por Eventos

Presentation Model
View

Presenter

Presentation Model

Service Layer

Figura 1. Estrutura dos principais patterns para GUIs desktop

Edio 39 Java Magazine


jm39.indb 51

51

15/8/2006 18:19:00

Interfaces Grficas com Qualidade Parte 2

importantes para a implementao e a


manuteno da GUI. Quando trabalhamos assim, as classes ficam mais finas
e consequentemente mais simples, o que
facilita o entendimento do cdigo e sua
manuteno.
Na verdade, essas vantagens tambm
existem no MVC e no MVP. A grande
vantagem no Presentation Model que no
precisamos da classe View para testar a
lgica da GUI. Isso permite a criao de
testes unitrios simples, eficientes e sem
a presena de componentes grficos para
atrapalhar.

A API JGoodies Binding


A API Binding do JGoodies oferece um
conjunto de classes que simplifica muito
a aplicao do pattern Presentation Model.
Essa API foi desenvolvida para trabalhar
com o JFC/Swing e possui mecanismos
para conectar componentes grficos a
variveis que podem ser manipuladas
independentemente de suas formas de
apresentao.
Para entender essa idia, imagine, por
exemplo, uma varivel booleana que est
conectada a um JCheckBox (Figura2). Sempre que trocarmos o valor dessa varivel, o
JCheckBox ir refletir a mudana e vice-versa. Ao mesmo tempo, poderamos conectar
outros componentes grficos a essa mesma
varivel, por exemplo um JToggleButton.
Assim, podemos ter quantos componentes
quisermos ligados a uma mesma varivel,
sendo que a mudana feita em um dos
componentes refletida nos outros.
Uma varivel pode conter tanto um valor
simples quanto uma lista de objetos. Vamos analisar cada caso separadamente.

Conectando componentes a valores simples


Entre os componentes que podem ser
conectados a um valor simples, os principais so JLabel, JTextField, JTextArea, JCheckBox,

JRadioButton, JPasswordField e JFormattedTextField.


A varivel que pode ser conectada a eles
uma implementao da interface ValueModel
(pacote com.jgoodies.binding.value), que armazena um valor e o mantm sincronizado
com o que apresentado pelo componente. Ao mudar o valor do ValueModel, o
componente refletir essa mudana. Da
mesma forma, se o usurio editar esse
valor pela GUI, o ValueModel receber o
valor fornecido.
E x i s t e m du a s f o r m a s d e c o n e c tar um ValueModel a um componente.
Uma opo utilizar o mtodo esttico bind() da classe Bindings (do pacote
com.jgoodies.binding.adapter):
JTextField textField = new JTextField();
ValueModel valueModel = new ValueHolder();
Bindings.bind(textField, valueModel);

Repare que criamos um ValueModel instanciando a classe ValueHolder (do mesmo


pacote de ValueModel), que a implementao que precisamos para esse caso.
A segunda maneira de fazer a conexo
utilizando uma classe de convenincia
chamada BasicComponentFactory (tambm
de com.jgoodies.binding.adapter), que possui
mtodos prontos para criar componentes.
Assim, podemos fazer:
ValueModel valueModel = new ValueHolder();
JTextField textField =
BasicComponentFactory.createTextField(valueModel);

Essa segunda alternativa ser utilizada


pelo nosso exemplo por ser mais simples.
Duas questes importantes ainda precisam ser discutidas. Primeiro, o valor
mantido pelo ValueModel pode ser lido e
alterado atravs dos mtodos getValue() e
setValue(). importante lembrar que para
conectar um componente a um ValueModel, o
componente precisa conhecer o valor guardado por ele. Portanto, um JCheckBox pode
se conectar sem problemas a um ValueModel

View
JCheckBox

JToggleButton

JCheckBox

JToggleButton

Presentation Model

que guarda um valor booleano, mas no a


um que contm um String, por exemplo. Se
o ValueModel receber um valor incompatvel
com o valor esperado pelos componentes
conectados a ele, uma exceo ser lanada
durante a tentativa de converso.
A outra questo a emisso de eventos
PropertyChangeEvent, que acontece quando alterado o valor guardado pelo
ValueModel. Isso permite que o valor seja
observado com PropertyChangeListeners.
Demonstraremos esse recurso na prtica
mais adiante.

Conectando componentes a listas de objetos


Os componentes que podem ser conectados a listas de objetos so JComboBox, JList
e JTable. A lista de objetos, por sua vez,
representada por um objeto da interface
javax.swing.ListModel do Swing, que define
mtodos para a manipulao da lista e emite eventos quando ela for modificada.
A contribuio do JGoodies Binding foi
criar implementaes que combinassem
a interface ListModel com a simplicidade
da interface java.util.List, resultando em
duas classes: ArrayListModel (que herda
de ArrayList e implementa ListModel) e
LinkedListModel (que herda de LinkedList e
implementa ListModel). Dessa forma, podemos atuar sobre essas classes dentro
da classe Presentation Model, enquanto os
componentes grficos refletem as mudanas na classe View.
Entretanto, ainda existe um problema.
Sabemos que os componentes desta
categoria guardam, alm da lista de
objetos, um item selecionado2. Portanto,
o ListModel sozinho no resolve nosso
problema. Precisamos da ajuda da classe
SelectionInList (em com.jgoodies.binding.list), que
guarda um ListModel e tambm contm um
ValueModel que aponta para o item selecionado. Veja um exemplo:
ListModel listModel = new ArrayListModel();
ValueModel itemSelecionadoHolder = new ValueHolder();
SelectionInList selectionInList =
new SelectionInList(listModel, itemSelecionadoHolder);

true
Varivel
Booleana

Com isso, podemos conectar o objeto

false

Figura 2. Varivel booleana conectada a um JCheckBox e a um JToggleButton.

2
Os casos em que h mais de um item selecionado so
normalmente raros, e por isso no sero tratados neste
artigo.

52 Java Magazine Edio 39


jm39.indb 52

15/8/2006 18:19:00

SelectionInList aos componentes da View da


seguinte forma:

A classe Usuario

Ainda no construtor, repare a chamada de dois mtodos: iniciaModelos() e


iniciaLogicaApresentacao(). nesses mtodos
que o estado e a lgica da GUI comeam a
surgir. Para entender o cdigo, acompanhe
a Figura4 e veja como a API Binding est
sendo usada. A Tabela 1 apresenta um
resumo dos objetos citados a seguir.
O mtodo iniciaModelos() comea criando
o objeto usuarioSelectionInList, a partir de um
ListModel (usuarioListModel) e um ValueModel
(usuarioSelecionadoHolder):

Repa re que preci sa mos da classe


ComboBoxAdapter (pacote com.jgoodies.binding.
adapter) para conectar o JComboBox ao
SelectionInList. O caso do JList mais simples,
pois podemos usar a fbrica de componentes da API Binding. Para a classe JTable,
precisaramos implementar um TableModel
que defina as colunas e exiba os objetos do
ListModel. Esse caso no ser tratado neste
artigo, mas h exemplos dele dentro do ZIP
de distribuio da API Binding.

Comearemos construindo o exemplo pela classe Usuario, mostrada na


Listagem1. Para essa classe JavaBean,
o ponto mais importante a destacar
a emisso de eventos, que realizada
quando os dados do usurio so alterados.
Precisamos implementar isso porque as
classes da API Binding exigem que os
objetos manipulados sejam observveis3.
Assim sendo, o primeiro passo fazer a
classe Usuario herdar da classe Model (pacote com.jgoodies.binding.beans); em seguida
alteramos todos os mtodos setXxx() para
que chamem firePropertyChange() e, dessa
forma, avisem que a propriedade em
questo mudou seu valor.

A aplicao de exemplo

A classe Presentation Model

Apresentaremos a partir de agora um


exemplo de uso do pattern Presentation
Model com a API JGoodies Binding. O
cdigo completo est disponvel para
download no site da Java Magazine (para
rodar o exemplo, basta executar a classe
Programa).
Alm da API Binding voc vai precisar
das APIs Forms e Looks do JGoodies. Para
obt-las, no site do projeto (jgoodies.com) v
at a seo Download e clique em Libraries.
L voc ter acesso aos arquivos zipados
de todas as APIs, contendo exemplos, documentao, cdigo-fonte e os JARs que
devem ser includos no classpath da sua
aplicao.

Basicamente, um objeto observvel quando mudanA segunda classe que vamos desenvolver
as nele emitem eventos. O objeto que escuta esses evenchama-se CadastroUsuarioPresentationModel
tos chama-se observador. Esses so conceitos trazidos pelo
(Listagem2). Conforme vimos na Figura1,
pattern Observer do livro Design Patterns [Gamma et al.].
essa classe deve possuir
uma referncia para a classe Service Layer, que o
nico meio de comunicao da GUI com o resto do
software. Assim, o construtor da classe recebe e
guarda um objeto do tipo
CadastroUsuarioServiceLayer,
que ex pl icado m a i s
adiante.
Figura 3. Tela de cadastro de usurios.

JComboBox comboBox =
new JComboBox(new ComboBoxAdapter(selectionInList));
JList list = BasicComponentFactory.createList(selectionInList);

Apresentando a aplicao
O exemplo que vamos construir um
cadastro de usurios conforme apresentado na Figura3. mostrada uma lista
contendo todos os usurios cadastrados;
as informaes do usurio selecionado
so exibidas direita. Cada usurio possui
quatro atributos: o nome, o cargo, e dois
indicadores definindo se administrador e
se tem acesso ao controle de permisses da
aplicao. O acesso ao controle de permisses s possvel para administradores.
Um ttulo no lado direito apresenta qual
usurio estamos editando. Se nenhum
estiver selecionado, apresentado o texto
Nenhum usurio selecionado e todos
os componentes de edio ficam desabilitados.

usuarioListModel = new ArrayListModel();


usuarioSelecionadoHolder = new ValueHolder(null, true);
usuarioSelectionInList = new SelectionInList((ListModel)
usuarioListModel, usuarioSelecionadoHolder);

Embora ainda no tenhamos explicado a

Listagem 1. Classe de modelo Usuario.


import com.jgoodies.binding.beans.Model;
public class Usuario extends
public static final String
public static final String
public static final String
public static final String
private
private
private
private

Model {
PROPERTY_NOME = nome;
PROPERTY_CARGO = cargo;
PROPERTY_ADMINISTRADOR = administrador;
PROPERTY_CONTROLE_PERMISSAO = controlePermissao;

String nome;
String cargo;
boolean isAdministrador;
boolean isControlePermissao;

public String getNome() {


return nome;
}
public void setNome(String nome) {
String valorAntigo = this.nome;
this.nome = nome;
// Todos os metodos set lanam eventos...
this.firePropertyChange(PROPERTY_NOME, valorAntigo, this.nome);
}
}

/*...Os outros metodos get/set so similares */

Edio 39 Java Magazine


jm39.indb 53

53

15/8/2006 18:19:01

Interfaces Grficas com Qualidade Parte 2

Listagem 2. Classe CadastroUsuarioPresentationModel, onde fica o estado e a lgica da GUI.


import
import
import
import
import
import
import

com.jgoodies.binding.beans.*;
com.jgoodies.binding.list.*;
com.jgoodies.binding.value.*;
javax.swing.*;
java.awt.event.ActionEvent;
java.beans.*;
java.util.*;

private void removeUsuario() {


int indice = usuarioSelectionInList.getSelectionIndex();
if (indice != -1) {
usuarioListModel.remove(indice);
}
}

public class CadastroUsuarioPresentationModel extends Model {


public static final String TITULO_SEM_SELECAO =
Nenhum usurio selecionado.;
public static final String TITULO_COM_SELECAO = Detalhes de ;
private
private
private
private
private
private
private
private
private
private
private
private

private void salvaUsuarios() {


List lista = Collections.unmodifiableList(usuarioListModel);
serviceLayer.salvaUsuarios(lista);
}

CadastroUsuarioServiceLayer serviceLayer;
ArrayListModel usuarioListModel;
BeanAdapter usuarioSelecionadoBeanAdapter;
SelectionInList usuarioSelectionInList;
SelectionInList cargoSelectionInList;
ValueHolder usuarioSelecionadoHolder;
ValueHolder tituloHolder;
ValueHolder usuarioDisponivelHolder;
ValueHolder campoPermissaoDisponivelHolder;
Action adicionarAction;
Action removerAction;
Action salvarAction;

private void habilitaCampos() {


boolean enabled =
usuarioSelecionadoHolder.getValue() != null;
usuarioDisponivelHolder.setValue(enabled);
habilitaCampoControlePermissao();
}
private void habilitaCampoControlePermissao() {
Usuario selecionado = (
Usuario) usuarioSelecionadoHolder.getValue();
boolean enabled = selecionado !=
null && selecionado.isAdministrador();
campoPermissaoDisponivelHolder.setValue(enabled);
}

public CadastroUsuarioPresentationModel(
CadastroUsuarioServiceLayer serviceLayer) {
this.serviceLayer = serviceLayer;
iniciaModelos();
iniciaLogicaApresentacao();
}

/* Inner classes de aes */


private class AdicionarAction extends AbstractAction {
public void actionPerformed(ActionEvent e) {
adicionaUsuario();
}
}

private void iniciaModelos() {


usuarioListModel = new ArrayListModel();
usuarioSelecionadoHolder = new ValueHolder(null, true);
usuarioSelectionInList = new SelectionInList(
(ListModel) usuarioListModel, usuarioSelecionadoHolder);
usuarioSelecionadoBeanAdapter = new BeanAdapter(
usuarioSelecionadoHolder, true);

private class RemoverAction extends AbstractAction {


public void actionPerformed(ActionEvent e) {
removeUsuario();
}
}

ArrayListModel cargoListModel = new ArrayListModel(


Arrays.asList(Cargos.TODOS));
cargoSelectionInList = new SelectionInList(
(ListModel) cargoListModel, getCargoHolder());

private class SalvarAction extends AbstractAction {


public void actionPerformed(ActionEvent e) {
salvaUsuarios();
}
}

tituloHolder = new ValueHolder();


usuarioDisponivelHolder = new ValueHolder();
campoPermissaoDisponivelHolder = new ValueHolder();

adicionarAction = new AdicionarAction();


removerAction = new RemoverAction();
salvarAction = new SalvarAction();

/* Inner classes de observadores */


private class ObservadorNomeUsuario implements
PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
if (getUsuarioSelecionadoHolder().getValue() == null) {
getTituloHolder().setValue(TITULO_SEM_SELECAO);
} else {
getTituloHolder().setValue(TITULO_COM_SELECAO +
getNomeHolder().getValue());
}
// Emite um evento de mudana para que a GUI reflita o novo
// nome.
usuarioListModel.fireContentsChanged(
usuarioSelectionInList.getSelectionIndex());
}
}

private void iniciaLogicaApresentacao() {


ObservadorSelecaoUsuario observadorSelecao =
new ObservadorSelecaoUsuario();
usuarioSelecionadoHolder.addValueChangeListener(
observadorSelecao);
observadorSelecao.propertyChange(null);
ObservadorNomeUsuario observadorNome =
new ObservadorNomeUsuario();
this.getNomeHolder().addValueChangeListener(observadorNome);
observadorNome.propertyChange(null);
ObservadorCampoAdmin observadorAdmin =
new ObservadorCampoAdmin();
this.getAdminHolder().addValueChangeListener(
observadorAdmin);
observadorAdmin.propertyChange(null);

private class ObservadorSelecaoUsuario implements


PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
habilitaCampos();
}
}

PropertyConnector connector = new PropertyConnector(


usuarioDisponivelHolder, value, removerAction,
enabled);
connector.updateProperty2();

List usuarios = serviceLayer.buscaUsuarios();


usuarioListModel.addAll(usuarios);

/* Metodos get omitidos */


private void adicionaUsuario() {

Usuario novoUsuario = new Usuario(Novo Usurio, null);


usuarioListModel.add(novoUsuario);

private class ObservadorCampoAdmin implements


PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
habilitaCampoControlePermissao();
}
}

54 Java Magazine Edio 39


jm39.indb 54

15/8/2006 18:19:04

Eventos Java

Agende-se!

O SouJava est preparando um final de ano movimentado


para o desenvolvedor Java brasileiro. Confira o que vem por a.

O Maior Evento Java do Brasil


30/Nov a 2/Dez
So Paulo - SP

De Competies a Workshops
Outubro
Vrias Cidades
E para o primeiro semestre de

A Conferncia Internacional do SouJava

A Tecnologia
Java, Livre

2007

Java e o Governo
Brasileiro
Edio 39 Java Magazine 55
www.soujava.org.br

jm39.indb 55

15/8/2006 18:19:11

Interfaces Grficas com Qualidade Parte 2

classe View do exemplo, podemos adiantar


que o objeto usuarioSelectionInList conecta-se
ao JList que apresenta os usurios na tela
(usuariosList).
O prximo objeto a ser criado chama-se
usuarioSelecionadoBeanAdapter:
usuarioSelecionadoBeanAdapter =
new BeanAdapter(usuarioSelecionadoHolder, true);
CadastroUsuarioView

Para que voc entenda o significado desse


objeto, considere a nossa situao: temos
uma lista de objetos JavaBeans (usurios)
e precisamos amarrar as propriedades do
JavaBean que est selecionado aos componentes da tela: nome, cargo, administrador e controle de permisses. Para no
termos que declarar um ValueModel para
cada propriedade desse JavaBean e ficar
CadastroUsuarioPresentationModel
usuarioSelectionInList

usuarioListModel
usuarioSelecionadoHolder
usuarioSelecionadoBeanAdapter
nomeHolder

cargoSelectionInList

cargoHolder

cargoListModel

administradorHolder
controlePermissaoHolder

Figura 4. Conexo entre os modelos da classe Presentation Model com os componentes da classe View.

Modelo

Classe

Descrio

usuarioListModel

ArrayListModel

Lista observvel que guarda todos os usurios.

usuarioSelecionadoHolder

ValueModel

Mantm uma referncia para o usurio selecionado na lista.

usuarioSelectionInList

SelectionInList

Une o usuarioListModel e o
usuarioSelecionadoHolder em um mesmo objeto.

usuarioSelecionadoBeanAdapter

BeanAdapter

Fornece um ValueModel para cada propriedade


do usurio selecionado.

nomeHolder,
cargoHolder,
administradorHolder,
controlePermissaoHolder

ValueModel

ValueModels (fornecidos pelo


usuarioSelecionadoBeanAdapter) que
contm, para o usurio selecionado, o nome,
o cargo, um booleano indicando se um
administrador, e um booleano indicando se
pode controlar as permisses do sistema.

cargoListModel

ArrayListModel

Lista observvel com os possveis cargos de


um usurio.

cargoSelectionInList

SelectionInList

Une o cargoHolder e o cargoListModel em um


mesmo objeto.

usuarioDisponivelHolder

ValueModel

Contm um booleano que indica se existe um


usurio disponvel para edio.

campoPermissaoDisponivelHolder

ValueModel

Contm um booleano que indica se o campo


Controle de Permisses deve estar habilitado ou no.

tituloHolder

ValueModel

Contm o texto que apresentado no topo


da tela.

gerenciando as mudanas de valores quando a seleo na lista de usurios mudar,


podemos usar a classe BeanAdapter.
A classe BeanAdapter funciona como
uma caixa, na qual podemos colocar
um objeto JavaBean. Essa classe fornece
um ValueModel para cada propriedade do
JavaBean justamente o que precisamos.
Assim, quando mudamos o usurio selecionado na lista, os ValueModels fornecidos
pelo BeanAdapter iro refletir os valores do
novo usurio.
Repare que passamos o objeto
usuarioSelecionadoHolder como parmetro
na criao do BeanAdapter. Isso faz com
que o BeanAdapter sempre exiba os dados
do usurio selecionado. Observe ainda
o valor true como segundo parmetro do
construtor, o que indica que as mudanas
no JavaBean precisam ser observadas. No
nosso caso, isso importante porque temos
que atualizar certas partes da GUI quando
os valores do usurio mudarem (ex.: para
habilitar/desabilitar o JCheckBox Controle
de Permisses quando a propriedade
Administrador for alterada).
Por fim, para adquirir os ValueModels
fornecidos pelo BeanAdapter, utilizamos
o mtodo getValueModel (), passando o
nome da propriedade em que estamos
interessados. Assim, para conectar o

Tabela 1. Resumo dos objetos mantidos pela classe CadastroUsuarioPresentationModel.

56 Java Magazine Edio 39


jm39.indb 56

15/8/2006 18:19:14

JTextField nomeTextField propriedade Nome do


usurio selecionado na lista, a classe View
utiliza o mtodo getNomeHolder() da classe
CadastroUsuarioPresentationModel:
// Definido na classe CadastroUsuarioPresentationModel
public ValueModel getNomeHolder() {
return usuarioSelecionadoBeanAdapter.getValueModel(
Usuario.PROPERTY_NOME);
}
// Na classe View
JComponent nomeTextField = BasicComponentFactory.
createTextField(
pm.getNomeHolder(), false);

O parmetro false passado para o mtodo


createTextField() significa que o valor editado
pelo usurio ser transferido ao ValueModel
a cada tecla pressionada. Se o parmetro
fosse true, o valor s seria transferido
quando o componente JTextField perdesse
o foco.
O caso do JComboBox de cargos segue
um estilo diferente, porque um com-

ponente que contm uma lista de objetos


e uma seleo (da mesma forma que o
JList de usurios). Portanto precisamos
criar o objeto cargoSelectionInList a partir do
cargoListModel e do ValueModel que aponta
para o cargo selecionado (o cargoListModel
um ListModel preenchido com uma lista fornecida pela classe Cargos4 ):
// Na classe CadastroUsuarioPresentationModel...
ArrayListModel cargoListModel = new ArrayListModel(
Arrays.asList(Cargos.TODOS));
cargoSelectionInList = new SelectionInList(
(ListModel) cargoListModel, getCargoHolder());
// Na classe View...
JComboBox cargoComboBox = new JComboBox(
new ComboBoxAdapter(pm.getCargoSelectionInList()));

Continuando no mtodo iniciaModelos(),


vemos a criao do objeto tituloHolder,
que guarda o texto apresentado no topo
da tela, informando o usurio sendo
editado. Depois temos a criao de dois

outros ValueHolders: usuarioDisponivelHolder e


campoPermissaoDisponivelHolder. O primeiro
guarda um booleano que indica se existe
um usurio disponvel para edio, e o segundo contm outro booleano que indica
se o JCheckBox Controle de Permisses
est habilitado. Esses valores so manipulados pelos observadores descritos
mais adiante.
Ainda nesse mtodo temos a criao de
trs aes (objetos que implementam a
interface javax.swing.Action): adicionarAction,
removerAction e salvarAction. Essas aes
so usadas pela classe View para criar
os botes da tela (com exceo do boto
Fechar que implementado na prpria
classe View por no possuir lgica de
negcio). A implementao dessas aes
bem simples, por exemplo:
4
A classe Cargos, no listada, bem simples e define apenas um array de strings.

Edio 39 Java Magazine


jm39.indb 57

5

15/8/2006 18:19:17

Interfaces Grficas com Qualidade Parte 2

Classe

Interface Implementada

ObservadorSelecaoUsuario

PropertyChangeListener

ObservadorNomeUsuario

PropertyChangeListener

ObservadorCampoAdmin

PropertyChangeListener

Descrio
Observa o usuarioSelecionadoHolder: qualquer mudana de seleo na lista de usurios resulta
numa chamada ao mtodo habilitaCampos().

Observa as mudanas no nome do usurio selecionado e preenche o valor do tituloHolder.

Observa a propriedade Administrador do usurio selecionado para inferir se o campo Controle de Permisses deve estar habilitado (chama o mtodo habilitaCampoControlePermissao())

Tabela 2. Observadores definidos na classe CadastroUsuarioPresentationModel.


Listagem 3. CadastroUsuarioServiceLayer: classe Service Layer com dados fixos de teste.
import java.util.*;
public class CadastroUsuarioServiceLayer {
public List buscaUsuarios() {
// Retorna dados fixos para nosso exemplo...
// O primeiro usurio um administrador (true no terceiro parmetro)
ArrayList usuarios = new ArrayList();
usuarios.add(new Usuario(Deodoro da Fonseca, Cargos.GERENTE_PROJETO, true));
usuarios.add(new Usuario(Floriano Peixoto, Cargos.DESENVOLVEDOR));
usuarios.add(new Usuario(Prudente de Moraes, Cargos.LIDER_EQUIPE));
usuarios.add(new Usuario(Campos Salles, Cargos.SUPORTE));
return usuarios;
}

public void salvaUsuarios(List listaUsuarios) {


// Aqui voc coloca seu cdigo para salvar na base de dados.
}

private class AdicionarAction extends AbstractAction {


public void actionPerformed(ActionEvent e) {
adicionaUsuario();
}
}

E para criar um boto a partir de uma


ao, basta passar uma instncia da ao
ao construtor do JButton:
JButton botaoAdicionar = new JButton(pm.getAdicionarAction());

Agora que os modelos esto criados e conectados, o mtodo iniciaLogicaApresentacao()


(ainda na Listagem 2) adiciona mais vida
GUI. Comeamos com a criao de objetos observadores que implementam a
interface PropertyChangeListener. A Tabela 2
explica os trs observadores presentes no
final da classe Presentation Model. A implementao deles bastante simples e segue
este estilo:
private class ObservadorSelecaoUsuario
implements PropertyChangeListener
{
public void propertyChange(PropertyChangeEvent evt) {
habilitaCampos();
}
}

Para fazer o ObservadorSelecaoUsuario observar o objeto usuarioSelecionadoHolder, devemos adicion-lo como sendo seu listener:
ObservadorSelecaoUsuario observadorSelecao =
new ObservadorSelecaoUsuario();
usuarioSelecionadoHolder.
addValueChangeListener(observadorSelecao);

Assim, quando o valor guardado pelo


usuarioSelecionadoHolder mudar, o mtodo
habilitaCampos() ser invocado.
Logo aps criar e configurar os obser vadores, ut i l i za mos a c la sse
PropertyConnector para habilitar/desabilitar
a ao removerAction. Isso feito conectando-se a propriedade value do objeto
usuarioDisponivelHolder com a propriedade
enabled da ao:

usuarioDisponivelHolder nos indica se h um


usurio disponvel para edio. S se
houver, habilitamos a remoo.

A classe Service Layer


A c l a s s e CadastroUsuarioSer viceLayer,
mostrada na Listagem 3, a fronteira
atravs da qual passam os dados do exemplo. Temos dois mtodos: buscaUsuarios() e
salvaUsuarios(). Para o nosso caso, criamos
o mtodo buscaUsuarios(), que retorna um
conjunto fixo de objetos Usuario para que
a GUI possa ser testada sem depender de
qualquer outra coisa.
Em sistemas mais robustos, recomendo
a adoo de duas prticas importantes. A
primeira criar uma interface para a Service Layer que resume todos os mtodos de
manipulao de dados. A idia que haja
duas implementaes para ela: uma de
teste e uma real. A implementao de teste
igual nossa, onde dados fixos ajudam no
desenvolvimento e nos testes. A implementao real a que acessa verdadeiramente o
backend do sistema (bancos de dados, EJBs,

PropertyConnector connector = new PropertyConnector(


usuarioDisponivelHolder, value, removerAction, enabled);

Assim, sempre que o valor booleano em usuarioDisponivelHolder mudar, o


PropertyConnector vai transmitir esse valor
ao enabled da ao (via setEnabled()). Fazemos isso porque o valor mantido pelo

58 Java Magazine Edio 39


jm39.indb 58

15/8/2006 18:19:19

etc). Recomendo manter ambas as implementaes juntas no cdigo e utilizar uma


ou outra conforme o objetivo. A segunda
prtica recomendada criar, dentro da
classe Service Layer, uma outra thread para
comunicao com o restante do sistema.
Normalmente, chamadas ao backend demoram alguns segundos; assim disparar uma
nova thread para processar as chamadas
evita o travamento da GUI e possveis irritaes por parte dos usurios.

A classe View
A classe CadastroUsuarioView (Listagem 4)
contm os componentes grficos da nossa GUI. Ela possui uma referncia para

a classe CadastroUsuarioPresentationModel,
que esperada em seu construtor. A
montagem da tela feita dentro do
mtodo createViewComponent(), onde os
componente grficos so instanciados e
conectados aos modelos mantidos pela
classe CadastroUsuarioPresentationModel, conforme foi visto na Figura 4.
Repare que no h necessidade de manter
referncias para os componentes criados,
j que os valores mostrados neles vm dos
modelos com os quais esto conectados.
Alm disso, o mtodo conectaHabilitacao() estabelece uma ligao entre o valor mantido
pelo usuarioDisponivelHolder e a propriedade
enabled dos componentes (da mesma forma

que fizemos com a removerAction dentro do


mtodo iniciaLogicaApresentacao()). No caso
do controlePermissaoCheckBox, amarramos o
enabled ao valor do controlePermissaoHolder.
Dessa forma, a lgica que controla a habilitao desses componentes fica inteiramente dentro da classe Presentation Model.
Como a classe View a responsvel
pela apresentao visual da GUI, nela
que colocamos os textos e cones da tela:
veja os mtodos criaBarraFerramentas() e
montaBarraBotoes(). Poderamos ter colocado
essas informaes dentro das aes, mas
estaramos introduzindo informaes
visuais em classes que no deveriam ter
esse conhecimento.

Listagem 4. CadastroUsuarioView: classe View com os componentes grficos.


import
import
import
import
import
import
import
import
import
import

com.jgoodies.binding.adapter.*;
com.jgoodies.binding.beans.PropertyConnector;
com.jgoodies.forms.builder.DefaultFormBuilder;
com.jgoodies.forms.factories.ButtonBarFactory;
com.jgoodies.forms.layout.*;
javax.swing.*;
java.awt.*;
java.awt.event.ActionEvent;
java.io.File;
java.net.URL;

private void conectaHabilitacao(JComponent component) {


PropertyConnector connector = new PropertyConnector(
pm.getUsuarioDisponivelHolder(
), value, component, enabled);
connector.updateProperty2();
}
private Component criaBarraFerramentas() {
JButton botaoAdicionar = new JButton(pm.getAdicionarAction());
botaoAdicionar.setIcon(getIcon(add.png));

public class CadastroUsuarioView {


private CadastroUsuarioPresentationModel pm;
private JFrame frame;

JButton botaoRemover = new JButton(pm.getRemoverAction());


botaoRemover.setIcon(getIcon(remove.png));
/* Aqui a toolbar montada e retornada */

public CadastroUsuarioView(CadastroUsuarioPresentationModel pm) {


this.pm = pm;
}

}
private Component montaBarraBotoes() {
JButton botaoSalvar = new JButton(pm.getSalvarAction());
botaoSalvar.setText(Salvar);

protected Component createViewComponent() {


JList usuariosList = BasicComponentFactory.createList(
pm.getUsuarioSelectionInList());

JButton botaoCancelar = new JButton(new FecharAction());


botaoCancelar.setText(Fechar);

JLabel tituloLabel = BasicComponentFactory.createLabel(


pm.getTituloHolder());
tituloLabel.setFont(tituloLabel.getFont().deriveFont(
Font.BOLD, 14f));

return ButtonBarFactory.buildCenteredBar(
botaoSalvar, botaoCancelar);
}

JComponent nomeTextField = BasicComponentFactory


.createTextField(pm.getNomeHolder(), false);
conectaHabilitacao(nomeTextField);

public JFrame criaFrame() {


if (frame == null) {
frame = new JFrame(Exemplo do Padro Presentation Model);
frame.getContentPane().add(createViewComponent());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
return frame;
}

JComboBox cargoComboBox = new JComboBox(


new ComboBoxAdapter(pm.getCargoSelectionInList()));
conectaHabilitacao(cargoComboBox);
JCheckBox administradorCheckBox =
BasicComponentFactory.createCheckBox(
pm.getAdminHolder(), Administrador);
conectaHabilitacao(administradorCheckBox);

private Icon getIcon(String fileName) {


String path = images + File.separator + fileName;
URL url = CadastroUsuarioView.class.getResource(path);
return new ImageIcon(url);
}

JCheckBox controlePermissaoCheckBox =
BasicComponentFactory.createCheckBox(
pm.getControlePermissaoHolder(), Controle de Permisses);
PropertyConnector connector = new PropertyConnector(
pm.getCampoPermissaoDisponivelHolder(), value,
controlePermissaoCheckBox, enabled);
connector.updateProperty2();

private class FecharAction extends AbstractAction {


public void actionPerformed(ActionEvent e) {
frame.hide();
System.exit(0);
}
}

/* Aqui so posicionados os componentes no painel... */


}
}

Edio 39 Java Magazine


jm39.indb 59

59

15/8/2006 18:19:20

Interfaces Grficas com Qualidade Parte 2

Desenvolvendo testes
unitrios sobre a GUI
Como vimos no incio do artigo, uma
das ma iores va nt agen s do pat ter n
Presentation Model a facilidade de criao de testes unitrios sobre a GUI. Para
ilustrar isso, criamos diversos testes na
classe CadastroUsuarioPresentationModelTest
(Listagem5), utilizando o JUnit.
Essa classe cria no mtodo setUp () u ma i n st nc ia da c la ss e
CadastroUsuarioPresentationModel e outra de
CadastroUsuarioServiceLayer, que contm nossos dados de teste. Conforme dito antes,
no precisamos da classe View para testar
a lgica da GUI.
O nosso primeiro teste feito pelo

mtodo testAdicionarUsuario(), que mede


o tamanho da lista de usurios antes e
depois de executar a ao adicionarAction
da classe CadastroUsuarioPresentationModel. O
tamanho final da lista deve ser o tamanho
inicial mais uma unidade. Da mesma
forma, temos o teste testRemoverUsuario(),
que comea selecionando o primeiro usurio (ndice zero) e depois executa a ao
removerAction.
O o b j e t ivo do te r c e i r o te ste
testHabilitacaoControles() verificar se a
habilitao dos controles est funcionando corretamente. Para isso, limpamos a seleo da lista de usurios
com o mtodo clearSelection() e depois
verificamos se o usuarioDisponivelHolder e o

Listagem 5. CadastroUsuarioPresentationModelTest.java: Testes sobre a lgica da GUI.


import junit.framework.TestCase;
public class CadastroUsuarioPresentationModelTest extends TestCase {
private CadastroUsuarioServiceLayer serviceLayer;
private CadastroUsuarioPresentationModel pm;
protected void setUp() throws Exception {
serviceLayer = new CadastroUsuarioServiceLayer();
pm = new CadastroUsuarioPresentationModel(serviceLayer);
}
public void testAdicionaUsuario() {
int tamanhoInicial = pm.getUsuarioListModel().getSize();
pm.getAdicionarAction().actionPerformed(null);
int tamanhoFinal = pm.getUsuarioListModel().getSize();
assertEquals(Deveria ter mais um usurio na lista,
tamanhoInicial + 1, tamanhoFinal);
}
public void testRemoveUsuario() {
pm.getUsuarioSelectionInList().setSelectionIndex(0);
int tamanhoInicial = pm.getUsuarioListModel().getSize();
pm.getRemoverAction().actionPerformed(null);
int tamanhoFinal = pm.getUsuarioListModel().getSize();
assertEquals(Deveria ter menos um usurio na lista,
tamanhoInicial - 1, tamanhoFinal);
}
public void testHabilitacaoControles() {
pm.getUsuarioSelectionInList().clearSelection();
assertEquals(Os controles devem estar desabilitados,
pm.getUsuarioDisponivelHolder().getValue(), Boolean.FALSE);
assertEquals(O campo controle de permisses deve estar desabilitado,
pm.getCampoPermissaoDisponivelHolder().getValue(), Boolean.FALSE);
assertFalse(A ao de remover deve estar desabilitada,
pm.getRemoverAction().isEnabled());

pm.getUsuarioSelectionInList().setSelectionIndex(0);
assertEquals(Os controles devem estar habilitados,
pm.getUsuarioDisponivelHolder().getValue(), Boolean.TRUE);
assertEquals(O campo controle de permisses deve estar habilitado,
pm.getCampoPermissaoDisponivelHolder().getValue(), Boolean.TRUE);
assertTrue(A ao de remover deve estar habilitada,
pm.getRemoverAction().isEnabled());

public void testHabilitacaoCampoPermissao() {...}


public void testLabelTitulo() {...}
public void testConexaoNomeTitulo() {...}

campoPermissaoDisponivelHolder contm o valor


false. Ainda nesse caso, a ao removerAction
deve estar desabilitada. Depois disso,
selecionamos o primeiro usurio da lista
e checamos se tudo est habilitado (considerando que o primeiro usurio um
administrador).
Outros trs testes foram omitidos da listagem, mas seus cdigos esto bem documentados na verso completa disponvel
no site da Java Magazine.

Concluses
Apresentamos nesse artigo a combinao do padro Presentation Model com a
API Binding do JGoodies, que nos permite
construir GUIs pela simples conexo de
modelos e propriedades. Dentre as vantagens dessa abordagem, temos um cdigo
mais limpo, separado em responsabilidades, e a simplificao da criao de testes
unitrios eficazes sobre a GUI.
Assim terminamos a srie sobre qualidade de interfaces grficas que abordou
os dois lados do desenvolvimento de
GUIs: a aparncia das aplicaes, na
Parte 1, e o cdigo escondido por trs das
telas nesta segunda parte.

martinfowler.com/eaaDev/
OrganizingPresentations.html
Pgina escrita pelo autor Martin Fowler
que discute os diferentes padres para o
desenvolvimento de GUIs em aplicaes desktop.
jgoodies.com
Site do JGoodies com tutoriais, artigos, aplicaes
e APIs para download.
javamagazine.com.br/downloads/jm39/
jm-gui2.zip

Hugo Vidal Teixeira


(hugo.tech@gmail.com) Bacharel
em Informtica pela UFRJ, mestre
em Engenharia de Software pela
COPPE/UFRJ e pesquisador da rea de
componentes e GUI Design. Atua como
consultor integrado Sakonnet Technology, onde trabalha
diretamente com Karsten Lentzsch (criador do JGoodies) e
empresas especializadas em GUI design, como Ergosign
(.de), Centigrade(.de) e OculusInfo(.com).

60 Java Magazine Edio 39


jm39.indb 60

15/8/2006 18:19:23

Edio 39 Java Magazine


jm39.indb 61

61

15/8/2006 18:19:26

Uma Mala Direta com J


Mensagens Personalizadas e Express

este artigo, vamos demonstrar a


API JavaMail criando uma aplicao completa. Iniciamos com
conceitos bsicos sobre a API, depois mostramos passo a passo o desenvolvimento
de uma aplicao de mala direta funcional,
na qual lemos informaes sobre clientes
de uma tabela em um banco de dados
MySQL e enviamos e-mails personalizados para cada cliente. Tambm apresentamos o conceito de expresses regulares e
as funcionalidades relacionadas oferecidas
pela plataforma Java, usando-as para personalizar as mensagens enviadas.

A API JavaMail
A API JavaMail utilizada para leitura e
envio de e-mails, e oferece diversos recursos essenciais para aplicaes corporativas,
entre os quais destacamos:
Suporte a vrios protocolos de envio e
leitura de e-mail (ex.: POP3, SMTP, IMAP)
Suporte a mensagens em HTML
Suporte a envio de mensagens com
anexos
A API JavaMail no includa com o
JDK, portanto necessrio fazer o download e disponibiliz-la para a aplicao.
Alm disso, ser necessria a API JavaBeans Activation Framework (JAF). Os
downloads podem ser feitos em java.sun.
com/products/javamail/downloads
e java.sun.com/products/javabeans/jaf/downloads. Ser preciso
adicionar dois JARs ao classpath da aplicao: mail.jar e
activation.jar.
Se voc est desenvolvendo aplicaes Java EE, no
h nenhuma preocupao
adicional, pois as APIs JavaMail
e JAF fazem parte do Java EE.

Viso geral das classes da API


Apresentamos a seguir uma breve
descrio de algumas classes fundamentais do
JavaMail.

javax.mail.Session
A classe Session representa uma sesso
de e-mail. atravs
dela que obtemos os
objetos responsveis
pelo envio e leitura de e-mails,
como por exemplo Transport, Store e
Folder. Para obter um Session precisamos de informaes sobre o servidor de

62 Java Magazine Edio 39


jm39.indb 62

15/8/2006 18:19:52

m JavaMail

es Regulares

Aprenda como utilizar a API


JavaMail para enviar e-mails
com HTML, enviar anexos e
ainda personalizar o e-mail com
os dados dos clientes utilizando
expresses regulares

Yara Senger e Ana Abrantes


e-mails, que podem ser passadas atravs
de um objeto java.util.Properties.

dereo de e-mail, incluindo opcionalmente


um nome.

javax.mail.Transport

javax.mail.Authenticator e
javax.mail.PasswordAuthentication

A classe abstrata Transport encapsula


o protocolo de envio de e-mails (geralmente SMTP) e contm mtodos para
envio de mensagens. Um objeto do
tipo Transport obtido atravs do objeto
Session informando-se o protocolo utilizado. A API JavaMail fornece apenas
uma subclasse concreta de Transport:
javax.mail.internet.SMTPTransport.

javax.mail.Store e javax.mail.Folder
Apesar de no utilizarmos estas classes
no nosso exemplo pois so usadas apenas
para leitura/transferncia de mensagens,
vale a pena cit-las. A classe abstrata Store
utilizada para a leitura de mensagens de
um servidor de e-mail. Ao obter um objeto
Store atravs da sesso indicamos qual o
protocolo utilizado, por exemplo POP3
ou IMAP (h duas subclasses concretas
de Store na API: POP3Store e IMAPStore). Ento
nos conectamos ao servidor informando
os dados para autenticao e recebimento
das pastas (javax.mail.Folder) que contm os
e-mails do usurio autenticado.
A classe abstrata Folder representa uma
pasta de e-mails do usurio autenticado.
Objetos Folder (h as subclasses POP3Folder
e IMAPFolder na API) so obtidos atravs de
um objeto Store fornecendo seu nome.

javax.mail.internet.MimeMessage
A classe MimeMessage representa uma
mensagem a ser lida ou enviada por e-mail,
e estende a classe abstrata javax.mail.Message.
Para criarmos uma MimeMessage necessrio termos um objeto Session. A mensagem
fica associada sesso de e-mail.

javax.mail.internet.InternetAddress
A classe InternetAddress representa um en-

Um objeto da classe Authenticator sabe


como obter os dados para autenticao do usurio, retornando um objeto
PasswordAuthentication. No h restrio para
as formas de se obter esses dados, que
podem vir de um arquivo, de entradas do
usurio em um prompt, de uma conexo
a uma fonte de dados externa, ou mesmo
informando-se o usurio e a senha no
construtor do objeto, como implementamos no exemplo deste artigo.

O projeto de Mala Direta


A aplicao de exemplo formada por
quatro classes. A classe EnviadorDeEmail
(Listagem 1) responsvel por criar a
mensagem, anexar um arquivo e fazer
o envio (e numa segunda etapa, por
personalizar as mensagens). A classe
MalaDireta (Listagem 2) a classe executvel da aplicao; ela cuida da leitura
dos clientes do banco de dados e chama
os mtodos da classe EnviadorDeEmail para
cada cliente recuperado. Cada destinatrio da mala direta representado por
um objeto Cliente (Listagem 3), com nome,
endereo de e-mail, telefone e id. A classe
Autenticador (Listagem 4) faz a autenticao
no servidor de e-mails, necessria para o
envio. Na Listagem 5 mostrado o comando SQL para criao da tabela de clientes
no banco de dados (chamamos o banco de
maladireta).
Inicialmente iremos mostrar como enviar e-mails em formato HTML com um
anexo. Depois veremos a personalizao
do contedo do e-mail. A Listagem 7 e a
Listagem 8 exibem as alteraes nas classes EnviadorDeEmail e MalaDireta necessrias
para a personalizao das mensagens.

Nessa segunda etapa, feita a substituio


do nome do cliente, e caso o telefone esteja
em um formato incorreto, ser adicionada
uma mensagem no corpo do e-mail solicitando a atualizao cadastral.
As prximas sees descrevem o processo passo a passo e apresentam detalhes de
cada classe.

Classe EnviadorDeEmail: enviando


mensagens em HTML com um anexo
A classe EnviadorDeEmail tem apenas um
mtodo pblico: enviarEmail(). Neste mtodo
obtido um Session e criado um Message j
com o destinatrio e o assunto. Em seguida, o mtodo adiciona o contedo e anexa
um arquivo mensagem. So usados vrios mtodos auxiliares para modularizar
o cdigo.

Obtendo a sesso
O mtodo obterSessao() o primeiro a ser
chamado em enviarEmail(). Ele configura
um objeto da classe Properties indicando,
atravs de propriedades pr-estabelecidas pela API, o nome do servidor SMTP
(propriedade mail.smtp.host), e se o servidor
exige ou no autenticao (propriedade
mail.smtp.auth). No nosso caso consideramos
que a autenticao necessria.
Properties props = new Properties();
props.put(mail.smtp.host, SERVIDOR_SMTP);
props.put(mail.smtp.auth, true);

Depois, obterSessao() obtm o objeto Session


usando Session.getDefaultInstance(). Como
indicamos que o servidor exige autenticao, necessrio passar um objeto
que implementa a interface Authenticator.
Passamos um objeto da nossa classe
Autenticador (Listagem 4), que instanciada informando o usurio e a senha para
autenticao no servidor SMTP.
sessao = Session.getDefaultInstance(
props, new Autenticador(EMAIL, SENHA));

Edio 39 Java Magazine


jm39.indb 63

63

15/8/2006 18:19:53

Uma Mala Direta com JavaMail

Criando o objeto Message


Em seguida, o mtodo enviarEmail() cria
uma mensagem chamando criarMensagem(),
que retorna um MimeMessage. Note que
passado como parmetro o objeto Session;
dessa forma a mensagem fica vinculada
a esta sesso.
MimeMessage mensagem =
criarMensagem(sessao, assunto, destinatario);

possvel enviar mensagens para um


ou mais destinatrios, que podem ser
configurados com CC (Carbon Copy), BCC
(Blind Carbon Copy) e TO (Destinatrio
principal). Alm disso, cada destinatrio
pode ter um nome e um e-mail (um objeto
InternetAddress). Os tipos do destinatrio so

representados por atributos da inner class


RecipientType da classe Message.
No trecho a seguir de criarMensagem()
criado um InternetAddress com o e-mail e o
nome do destinatrio, e depois este endereo associado mensagem, informando que ser utilizado como destinatrio
principal (TO).

enderecoRemetente = new InternetAddress(


EMAIL_REMETENTE, NOME_REMETENTE);
message.setFrom(enderecoRemetente);

enderecoDestinatario = new InternetAddress(


destinatario.getEmail(), destinatario.getNome());
message.addRecipient(Message.RecipientType.TO,
enderecoDestinatario);

E por fim o mtodo criarMensagem() retorna


a mensagem criada.

O remetente tambm representado por


uma instncia da classe InternetAddress, que
associada mensagem atravs do mtodo
setFrom().

O prximo mtodo a ser executado


anexarConteudoEAnexo(). O contedo do email representado por um objeto Multipart,
sendo que nossa mensagem ter duas

O assunto e a data de envio so configurados atravs dos mtodos setSubject() e


setSentDate(), que so bastante simples.
message.setSubject(assunto);
message.setSentDate(new Date());

Definindo o contedo do e-mail

Listagem 1. EnviadorDeEmail.java sem personalizao


package maladireta;
import
import
import
import
import
import

throw new AddressException(ex.getMessage());


}
mensagem.addRecipient(Message.RecipientType.TO,
enderecoDestinatario);
mensagem.setFrom(enderecoRemetente);
mensagem.setSubject(assunto);
mensagem.setSentDate(new Date());
return mensagem;

java.io.*;
java.util.*;
java.util.regex.*;
javax.activation.*;
javax.mail.*;
javax.mail.internet.*;
}

public class EnviadorDeEmail {


private static String EMAIL_REMETENTE = yara@globalcode.com.br;
private static String NOME_REMETENTE = Yara;
private static String SERVIDOR_SMTP = smtp.globalcode.com.br;
private static String SENHA = senha;

private void adicionarConteudoEAnexo(Message message,


String conteudo, Cliente destinatario, String arquivo)
throws MessagingException, AddressException
{
// Cria um Multipart que ser composto pelo conteudo e pelo anexo
Multipart multipart = new MimeMultipart();

public void enviarEmail(String assunto, String conteudo,


Cliente destinatario, String arquivo) throws AddressException,
MessagingException
{
Session sessao = obterSessao();
Message mensagem = criarMensagem(sessao, assunto, destinatario);
adicionarConteudoEAnexo(
mensagem, conteudo, destinatario, arquivo);
mensagem.saveChanges();
Transport transport = null;
try {
transport = sessao.getTransport(smtp);
transport.send(mensagem);
}
finally {
transport.close();
}
}

// Cria a parte do corpo da mensagem (texto do contedo do e-mail)


BodyPart messageBodyPartConteudo = new MimeBodyPart();
messageBodyPartConteudo.setContent(conteudo, text/html);
// Adiciona o corpo da mensagem ao Multipart
multipart.addBodyPart(messageBodyPartConteudo);
// Cria uma segunda parte do corpo (anexos do contudo do e-mail)
BodyPart messageBodyPartAnexo = new MimeBodyPart();
// Cria o anexo
DataSource source = new FileDataSource(arquivo);
// Define o data handler para o anexo
messageBodyPartAnexo.setDataHandler(new DataHandler(source));
// Define o nome do arquivo
String nomeArquivo = new File(arquivo).getName();
messageBodyPartAnexo.setFileName(nomeArquivo);
// Adiciona o anexo ao Multipart
multipart.addBodyPart(messageBodyPartAnexo);
// Adiciona o Multipart a mensagem
message.setContent(multipart);

private Message criarMensagem(Session session, String assunto,


Cliente destinatario) throws MessagingException,
AddressException
{
MimeMessage mensagem = new MimeMessage(session);
Address enderecoRemetente = null;
Address enderecoDestinatario = null;
try {
enderecoDestinatario = new InternetAddress(
destinatario.getEmail(), destinatario.getNome());
enderecoRemetente = new InternetAddress(EMAIL_REMETENTE,
NOME_REMETENTE);
}
catch (UnsupportedEncodingException ex) {

}
private Session obterSessao() {
Session sessao = null;
Properties props = new Properties();
props.put(mail.smtp.host, SERVIDOR_SMTP);
props.put(mail.smtp.auth, true);
sessao = Session.getDefaultInstance(props, new Autenticador(
EMAIL_REMETENTE, SENHA));
return sessao;
}
}

64 Java Magazine Edio 39


jm39.indb 64

15/8/2006 18:19:54

partes, uma com o corpo do e-mail e outra


com o arquivo a ser anexado. As partes so
representadas por objetos MimeBodyPart.
O corpo do e-mail deve estar em HTML,
por isto a instncia de MimeBodyPart
configurada informando o tipo como
text/html:

Anexando um arquivo

Multipart multipart = new MimeMultipart();


BodyPart messageBodyPartConteudo = new MimeBodyPart();
messageBodyPartConteudo.setContent(conteudo, text/html);

Para anexar o arquivo ao e-mail necessrio realizar os seguintes passos:


1. Criar um FileDataSource a partir do caminho completo do arquivo que queremos
anexar:

Depois associamos esta parte ao objeto


Multipart que representa todo o contedo
da mensagem.
multipart.addBodyPart(messageBodyPartConteudo);

O anexo do e-mail tambm representado por uma instncia da classe


MimeBodyPart, criada com seu construtor
default:

FileDataSource instanciado, e associ-lo


ao objeto da classe MimeBodyPart que
representa o anexo atravs do mtodo
setDataHandler():
messageBodyPartAnexo.setDataHandler(
new DataHandler(source));

BodyPart messageBodyPartAnexo = new MimeBodyPart();

DataSource source = new FileDataSource(arquivo);

2 . Criar um DataHandler a partir do

3. E indicar qual o nome do arquivo


anexo para o objeto MimeBodyPart, atravs
do mtodo setFileName(String nome):
String nomeArquivo = new File(arquivo).getName();
messageBodyPartAnexo.setFileName(nomeArquivo);

Depois, mais uma vez, associamos esta


parte da mensagem ao objeto Multipart, que
representa todo o contedo da mensagem:

Listagem 2. MalaDireta.java sem personalizao


package maladireta;
import
import
import
import

}
catch (MessagingException e) {
System.out.println(Erro ao enviar email para
+ cliente.getNome());
e.printStackTrace();
}

java.io.*;
java.sql.*;
java.util.*;
javax.mail.MessagingException;

}
}
catch (Exception e) {
System.out.println(Erro ao ler clientes do banco de dados.\n);
throw e;
}

public class MalaDireta {


private final static String STRING_CON =
jdbc:mysql://localhost/maladireta;
private final static String USUARIO_BD = root;
private final static String SENHA_BD = root;
private final static String ANEXO = C:\\temp\\teste.txt;

public static void main(String[] args) throws Exception {


String assunto = Teste de envio de e-mail do projeto MalaDireta;

public static List obterClientes() throws SQLException,


ClassNotFoundException
{
Connection con = obterConexao();
Statement st = null;
ResultSet rs = null;
List listaClientes = new ArrayList();
try {
st = con.createStatement();
rs = st.executeQuery(select * from clientes);
while (rs.next()) {
Cliente cliente = new Cliente(rs.getLong(id), rs
.getString(nome), rs.getString(email), rs
.getString(telefone));
listaClientes.add(cliente);
}
return listaClientes;
}
finally {
if (rs != null)
rs.close();
if (st != null)
st.close();
if (con != null)
con.close();
}
}

StringBuilder conteudo = new StringBuilder();


conteudo.append(
<!DOCTYPE html PUBLIC -//W3C//DTD HTML 4.01 Transitional//EN>);
conteudo.append(
<html><head><title>Teste de envio de e-mail</title></head>);
conteudo.append(<body> Caro(a) cliente,<br> <br>);
conteudo.append(
Voc&ecirc; est&aacute; cadastrado(a) no nosso sistema e esta);
conteudo.append(&eacute; uma mensagem que testa o envio de
+ e-mail para a sua conta.<br>);
conteudo.append(<br> Se voc&ecirc; n&atilde;o quer mais
+ receber nossos e-mails, por );
conteudo.append(
favor escreva para <a href=mailto:contato@globalcode.com.br>);
conteudo.append(
contato@globalcode.com.br</a> solicitando descadastramento.<br>);
conteudo.append(Pedimos a gentileza de responder este
+e-mail confirmando o recebimento.<br>);
conteudo.append(
<br>Atenciosamente,<br><br>Equipe Globalcode<br><br>);
conteudo.append(<a href=http://www.globalcode.com.br>
+ www.globalcode.com.br</a><br>);
conteudo.append(Telefone: (11) 3171-1987<br> </body></html>);
EnviadorDeEmail enviadorDeEmail = new EnviadorDeEmail();
try {
List clientes = obterClientes();
// envia o e-mail para todos os clientes
for (Iterator it = clientes.iterator(); it.hasNext();) {
Cliente cliente = (Cliente) it.next();
try {
enviadorDeEmail.enviarEmail(assunto, conteudo.toString(),
cliente, ANEXO);
System.out.println(e-mail enviado com sucesso para
+ cliente.getNome());

public static Connection obterConexao() throws SQLException,


ClassNotFoundException
{
Class.forName(com.mysql.jdbc.Driver);
Connection con = DriverManager.getConnection(STRING_CON,
USUARIO_BD, SENHA_BD);
return con;
}
}

Edio 39 Java Magazine


jm39.indb 65

65

15/8/2006 18:19:55

Uma Mala Direta com JavaMail

multipart.addBodyPart(messageBodyPartAnexo);

Finalmente, colocamos as duas partes na


mensagem:
mensagem.setContent(multipart);

Classe MalaDireta:
controlando a aplicao
Por simplicidade, no nosso exemplo o
acesso ao banco de dados foi realizado

inteiramente na classe MalaDireta; em um


projeto real haveria uma separao de
responsabilidades muito maior. O acesso
feito atravs dos mtodos obterConexao() e
obterClientes(), que retornam respectivamente uma conexo ao banco de dados e uma
lista de objetos Cliente criados a partir dos
dados na tabela de clientes.
No mtodo main() criamos um String com
o assunto da mensagem e um StringBuilder
para armazenar o contedo a ser enviado

Listagem 3. Cliente.java
package maladireta;
import java.io.Serializable;
public class Cliente implements Serializable {
private long id;
private String nome = ;
private String email = ;
private String telefone = ;
public Cliente() {}
public Cliente(String nome, String email, String telefone) {
this.nome = nome;
this.email = email;
this.telefone = telefone;
}
public Cliente(long id, String nome, String email, String telefone) {
this(nome, email, telefone);
this.id = id;
}
// get/set
}

Listagem 4. Autenticador.java
package maladireta;
import javax.mail.PasswordAuthentication;
public class Autenticador extends javax.mail.Authenticator {
private String user;
private String senha;
public Autenticador() {}
public Autenticador(String user, String senha) {
this.user = user;
this.senha = senha;
}
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(user, senha);
}
}

Listagem 5. Script para criao da tabela no banco de dados


CREATE TABLE `clientes` (
`id` int(11) NOT NULL auto_increment,
`nome` char(40) NOT NULL default ,
`email` char(40) NOT NULL default ,
`telefone` char(20) NOT NULL default ,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED;

(o cdigo HTML do corpo da mensagem).


Obtemos a lista de clientes do banco de
dados atravs da chamada ao mtodo
obterClientes() e enviamos um e-mail para
cada cliente recuperado utilizando o mtodo enviarEmail() da classe EnviadorDeEmail discutida anteriormente. Veja o cdigo completo da classe MalaDireta na Listagem 2. A
Figura 2 mostra o e-mail enviado.
At aqui mostramos como enviar e-mails
para mltiplos destinatrios, mas sem personalizar as mensagens para cada cliente.
No nosso exemplo, essa personalizao
ser feita usando expresses regulares.
Por isso, antes de continuar com o cdigo,
vamos apresentar conceitos gerais sobre
este tema e suas diversas aplicaes.

Conceitos gerais de
expresses regulares
Expresses regulares so muito utilizadas para localizao de informaes
dentro de textos e para validao de dados
textuais que devem seguir formatos especficos, como URLs, datas, endereos de
e-mail, CEPs, nmeros de telefone etc.
Na API do Java SE, o pacote javax.util.regex
contm duas classes principais voltadas
ao trabalho com expresses regulares.
Pattern representa uma expresso regular
compilada, e Matcher capaz de verificar
se uma dada string est de acordo com a
expresso regular em um objeto Pattern.
A documentao JavaDoc da classe
Pattern inclui um resumo dos principais
smbolos utilizados para expresses
regulares. Veja alguns exemplos de expresses usando esses smbolos e o que
elas representam:
\d um digito [0-9]
[a-zA-Z] qualquer letra
[a-z] qualquer letra minscula
? o smbolo antes do ? aparece zero
ou uma vez
* o smbolo antes do * aparece zero
ou mais vezes
+ o smbolo antes do + aparece uma
ou mais vezes
{n} o smbolo antes do {n} aparece exatamente n vezes
{n,m} o smbolo antes do {n,m} aparece
no mnimo n vezes e no mais do que m
vezes
{n,} o smbolo que est antes do {n,}

66 Java Magazine Edio 39


jm39.indb 66

15/8/2006 18:19:55

aparece no mnimo n vezes


X|Y ou X ou Y
\s espao em branco
Na Figura 1 analisado um exemplo
complexo de expresso regular. A figura
inclui tambm uma tabela com nomes
que esto ou no de acordo com essa
expresso.
O trecho de cdigo na Listagem 6 ilustra
a utilizao das classes Pattern e Matcher
para verificar vrios nomes com a expresso regular detalhada na Figura 1.
As classes Pattern e Matcher atendem das
mais simples s mais complexas situaes
envolvendo expresses regulares. No entanto, outras classes do Java SE tambm
suportam essas expresses, como a prpria
classe String, que oferece funcionalidades
suficientes em muitos casos. Veja alguns
mtodos da classe String que suportam
expresses regulares:
St r i n g r e p l a c e A l l ( St r i n g r e g e x , St r i n g
replacement) Substitui todos os pedaos
da string que obedecem ao padro estabelecido pela expresso regular em regex.
String replaceFirst (String regex, String
replacement) Substitui a primeira ocorrncia dentro da string que obedea o padro
estabelecido pela expresso regular.

[A-Z]
O texto deve comear com
uma letra maiuscula

[a-z] +
Seguido de uma ou
mais letras minusculas

\\s[A-Z][a-z]+
Um espao, seguido de
uma letra maiscula e uma
ou mais letras minsculas

|
ou

[A-Z][a-z]+((\\s [A-Z][a-z]+)|\\s [a-z]{2}|\\s [A-Z] .)+


+ Uma ou mais vezes

\\s[a-z]{2}
Um espao, seguido de duas letras minsculas

\\s[A-Z] .
Um espao, seguido de uma letra
maiscula, seguido de um ponto

Nomes vlidos de acordo com a expresso

Nomes invlidos de acordo com a expresso

Maria Aparecida
Maria A. Soares
Maria Aparecida Soares
Maria da Silva

maria aparecida
MARIA APARECIDA
Maria A Soares

Figura 1. Um exemplo de expresso regular

Vamos apresentar agora a aplicao de


expresses regulares no nosso exemplo,
realizando a substituio do nome do
cliente no e-mail e tambm a verificao
do telefone. Se o telefone for considerado
invlido pela expresso regular construda, iremos inserir um texto no e-mail
solicitando que o cliente atualize seus
dados cadastrais.

Aplicando as expresses regulares


Para permitir a personalizao das mensagens vamos fazer algumas alteraes im-

Figura 2. E-mail enviado em HTML com anexo teste.txt

Edio 39 Java Magazine


jm39.indb 67

6

15/8/2006 18:19:57

Uma Mala Direta com JavaMail

portantes na classe MalaDireta, mostradas na


Listagem 7. Observe que no texto do e-mail
inclumos no contedo HTML do e-mail a
ser enviado pedaos de texto para serem
substitudos: %cliente.nome% e %cliente.
telefone%. Vamos utilizar expresses regulares atravs do mtodo replaceAll() da
classe String para substituir esses pedaos
pelo nome e o telefone do cliente.
Observe que este o caso mais simples
de uso de expresses regulares, em que
o padro fornecido exatamente igual
ao texto que deve ser localizado. Para
demonstrar mais recursos de expresses
regulares, vamos verificar se um telefone de cada cliente segue um padro
estabelecido, de acordo com a seguinte
expresso:
\\d{2}(-|\\s)??\\d{8}

Essa expresso verifica se o telefone


contm um DDD
com dois dgitos
e um nmero

com oito dgitos, sendo que o DDD pode


estar colado ao nmero, ou separado por
um espao ou hfen. De acordo com essa
expresso, os seguintes nmeros seriam
considerados vlidos:
11-31711987
11 31711987
1131711987
J os nmeros a seguir no estariam de
acordo com a expresso:
31711987
222323
7632323r34
Agora vamos analisar passo a passo o
novo mtodo personalizarConteudo() da classe

MalaDireta, que realiza a substituio do


nome e a verificao do telefone.
1. Utilizamos o mtodo replaceAll() da
classe String. Este mtodo recebe uma string
contendo uma expresso regular e a string
que deve substituir o texto localizado. Neste
caso a expresso contm apenas caracteres,
ou seja, no utilizamos smbolos especiais como /d, ou [A-Z], apenas uma string
%cliente.nome% (note que a porcentagem
no um smbolo especial de expresso
regular).
conteudo = conteudo.replaceAll(
%cliente.nome%,destinatario.getNome());

2. Compilamos a expresso regular que

Listagem 6. Trecho demonstrando o uso da expresso regular ilustrada na Figura 1.


Pattern p = Pattern.compile(
[A-Z][a-z]+((\\s[A- Z][azz]+)|\\s[a-z]{2}|\\s[A-Z].)+);
String nomeCorreto = Maria Aparecida da Silva;
String nomeCorreto1 = Maria Aparecida Silva;
String nomeCorreto2 = Maria A. Soares;
String nomeIncorreto = maria aparecida;
String nomeIncorreto2 = MARIA APARECIDA;
String nomeIncorreto3 = Maria;
String[] nomes = {nomeCorreto, nomeCorreto1, nomeCorreto2,
nomeIncorreto, nomeIncorreto2, nomeIncorreto3};
for (String nome: nomes){
Matcher m = p.matcher(nome);
if (m.matches()){
System.out.println(nome+: est no padro);
}
else{
System.out.println(nome+: no est no padro);
}

Listagem . Alteraes na classe MalaDireta para personalizao das mensagens


public class MalaDireta {
//...
public static void main(String[] args) throws Exception {
String assunto = Teste de envio de e-mail do projeto MalaDireta;
StringBuilder conteudo = new StringBuilder();
conteudo.append(<!DOCTYPE html PUBLIC -//W3C//DTD HTML 4.01 Transitional//EN>);
conteudo.append(<html><head> <title>Teste de envio de e-mail</title></head>);
conteudo.append(<body> Caro(a) %cliente.nome%,<br> <br>);
conteudo.append(Voc&ecirc; est&aacute; cadastrado(a) no nosso sistema e esta );
conteudo.append(&eacute; uma mensagem que testa o envio de e-mail para a sua conta.<br>);
conteudo.append(<br> Se voc&ecirc; n&atilde;o quer mais receber nossos e-mails, por );
conteudo.append(favor escreva para <a href=mailto:contato@globalcode.com.br>);
conteudo.append(contato@globalcode.com.br</a> solicitando descadastramento.<br>);
conteudo.append(<br> %corrigir_telefone% <br>);
conteudo.append(Pedimos a gentileza de responder este e-mail confirmando o
+recebimento.<br>);
//...
}

68 Java Magazine Edio 39


jm39.indb 68

15/8/2006 18:20:16

ir validar o telefone com um mtodo


esttico da classe Pattern.
Pattern p = Pattern.compile(\\d{2}(-|\\s)??\\d{8});

3. Depois Verificamos se o telefone do


destinatrio est de acordo com a expresso regular compilada. Esta operao
retorna um objeto da classe Matcher, sobre
o qual podemos chamar o mtodo matches()
que retorna verdadeiro ou falso.

String telefone = destinatario.getTelefone();


Matcher m = p.matcher(telefone);

4. Se o telefone estiver no padro, a cadeia


de caracteres %corrigir_telefone% ser
removida do e-mail, atravs da substituio
por uma string vazia. Se o telefone no estiver no padro esperado, ser substitudo
por um texto que solicita que o cliente entre
em contato para atualizao do cadastro.

if (m.matches()){
System.out.println(O +telefone+ est no padro);
conteudo = conteudo.replaceAll(%corrigir_telefone%,);
} else {
System.out.println(O +telefone+ no est no padro);
conteudo = conteudo.replaceAll(%corrigir_
telefone%,<br>Seu telefone + telefone+
parece estar incorreto /*... */ );
}

O mtodo personalizarConteudo() deve ser


chamado na classe EnviadorDeEmail. Veja na
Listagem 8 o trecho alterado nesta classe.
A Figura 3 mostra um exemplo de e-mail
enviado com o contedo personalizado.

Concluses
Neste artigo, vimos como usar recursos
essenciais da API JavaMail aplicando-os
em uma situao real. Usamos tambm
expresses regulares, um recurso poderoso que suportado por classes especficas
da API do Java SE, bem como a classe
String.

java.sun.com/products/javamail/
Pgina oficial do JavaMail.
Figura 3. E-mail com contedo personalizado

java.sun.com/docs/books/tutorial/extra/
regex/intro.html
Tutorial sobre Expresses Regulares

Listagem 8. Alteraes na classe EnviadorDeEmail para personalizao


public class EnviadorDeEmail {
//...
private void adicionarConteudoEAnexo(Message message,
String conteudo, Cliente destinatario, String arquivo)
throws MessagingException, AddressException
{
conteudo = personalizarConteudo(conteudo, destinatario);
}

//... Igual Listagem 1

private String personalizarConteudo(String conteudo, Cliente destinatario){


// personalizao do contedo
conteudo = conteudo.replaceAll(%cliente.nome%,destinatario.getNome());
Pattern p = Pattern.compile(\\d{2}(-|\\s)??\\d{8});
String telefone = destinatario.getTelefone();
Matcher m = p.matcher(telefone);
if (m.matches()){
System.out.println(O +telefone+ est no padro);
conteudo = conteudo.replaceAll(%corrigir_telefone%,);
}
else {
System.out.println(O +telefone+ no est no padro);
conteudo = conteudo.replaceAll(%corrigir_telefone%,
<br>Seu telefone + telefone + parece estar incorreto,
+ solicitamos a gentileza de entrar em contato
+ para atualizao do cadastro<br>);
}
return conteudo;

}
//...
}

javamagazine.com.br/downloads/jm39/
jm-maladireta.zip
Yara M. H. Senger
(yara@globalcode.com.br)
formada em Cincias da Computao na USP em So Carlos,
especialista em desenvolvimento web;
possui as certificaes SCJA, SCJP e
SCWCD. Atualmente Instrutora e Diretora Educacional
da Globalcode, criadora e coordenadora de diversos
cursos das carreiras Academia do Java e Academia do
Web Developer.
Ana Abrantes
(ana.abrantes@globalcode.com.br)
desenvolvedora Java na Globalcode,
co-autora do curso de JasperReports/
iReport e possui algumas certificaes
em Java (SCJA, SCJP e SCWCD). formada pela FATECSP e atua na rea de informtica h mais de 15 anos.

Edio 39 Java Magazine


jm39.indb 69

69

15/8/2006 18:20:18

RIA com Open L


Construindo Rich Internet Applications

om o crescimento da internet, a
distribuio e a manuteno de
aplicaes tornaram-se muito
mais simples e rpidas. Utilizando um
browser, o usurio passou a acessar o
ltimo release sem ter que se preocupar
com versionamento ou procedimentos
de instalao. Mas um efeito colateral do
paradigma web no tardou a aparecer.
Interfaces mais pobres e menos intuitivas
substituram os sistemas fat-client antes
largamente utilizados, forando o usurio
a se acostumar com o clicar e esperar das
interfaces web.
O conceito de Rich Internet Application
(RIA) uma das respostas a este problema.
Permitindo que o usurio interaja com a
aplicao como se esta fosse um sistema
desktop tradicional, o RIA baseia-se na

premissa de rodar na mquina do usurio todo o processamento de interface


grfica, deixando para o lado do servidor
o processamento da lgica de negcio.
O lado cliente das aplicaes RIA pode
ser implementado de diversas maneiras,
dentre elas applets Java, pginas DHTML,
aplicativos Macromedia Flash, JavaScript
e outros.
O OpenLaszlo uma plataforma madura
de desenvolvimento RIA baseada em JavaScript e XML com suporte depurao
de aplicaes, que renderiza aplicaes
em Macromedia Flash.
Neste artigo vamos apresentar os
principais conceitos dessa plataforma e construir uma

aplicao de exemplo funcional.

Funcionamento do OpenLaszlo
Aplicaes OpenLaszlo so definidas em
documentos na linguagem LZX, baseada
em XML. A engine de renderizao do
OpenLaszlo (que chamaremos de Servidor OpenLaszlo) uma aplicao Java
para web, portanto deve ser instalada em
um container web como o Tomcat, ou num
servidor de aplicaes Java EE.
Em tempo de execuo, o servidor OpenLaszlo compila os arquivos-fonte LZX
para um aplicativo Flash ((.SWF) que
enviado ao cliente. Na mquina cliente,
o browser roda o aplicativo (s vezes
chamado de Cliente OpenLaszlo)
normalmente, utilizando o plug-in Flash.
A Figura 1 ilustra a organizao dos componentes-chave do OpenLaszlo.

Obtendo e configurando o
OpenLaszlo Server
O download do OpenLaszlo pode ser feito em openlaszlo.org/download, selecionando-se a plataforma desejada (Windows, Linux ou Mac OS). Para outras plataformas,
ou para fazer a instalao manualmente,
obtenha o pacote identificado como Dev
Kit. O download j inclui o Tomcat, com o
servlet do Servidor OpenLaszlo configurado, bem como documentao e exemplos.
Para verificar a instalao, inicie o
servidor com um duplo-clique no
arquivo server\lps-3.3.3\lps\utils\
startTomcat, dentro do diretrio raiz
do OpenLaszlo (ajustando sempre o

0 Java Magazine Edio 39


jm39.indb 70

15/8/2006 18:20:28

Laszlo
com Flash e Java

Turbine suas interfaces grficas


e maximize a interatividade
com o usurio utilizando
uma plataforma open source
baseada em XML e Java

andr LUs monteiro


nmero da verso para o seu caso). Aps
inici-lo, aponte o browser para: http://
localhost:8080/lps-3.3.3/examples/hello.lzx.
Se tudo estiver OK, dever aparecer a
mensagem Hello Laszlo!. (Para parar o
servidor, d um duplo-clique no arquivo
server\lps-3.3.3\lps\utils\stopTomcat.)

Primeiro aplicativo OpenLaszlo


Criar uma aplicao Ol Mundo no
OpenLaszlo muito simples. Comece
criando um arquivo texto com o contedo
a seguir:
<canvas width=200 >
<text>Ola Mundo!</text>
</canvas>

Salve-o com extenso .lzx (ex.: OlaMundo.


lzx) no diretrio server\lps-3.3.3\my-apps,
e teste a aplicao apontando o browser
para http://localhost:8080/lps-3.3.3/myapps/OlaMundo.lzx.
Toda aplicao OpenLaszlo comea com
a tag <canvas>, que renderiza o painel
principal. J a tag <text> renderiza um
texto qualquer.

Aplicao de exemplo
Como exemplo, iremos desenvolver uma
aplicao simples de calculadora, cujos
clculos so realizados no lado do servidor
por uma pgina JSP. Os clculos a serem
processados so submetidos ao Tomcat
usando parmetros HTTP, e o resultado
um documento XML como a seguir:
<resultado>25</resultado>

O objetivo demonstrar como uma aplicao cliente criada com o OpenLaszlo


(a interface grfica da calculadora) pode
submeter dados para processamento no
servidor e obter o resultado mostrando-o
para o usurio. Com as tcnicas mostradas, voc poder criar aplicaes RIA em
Flash que acessam recursos corporativos
rodando, por exemplo, em um
servidor Java EE.

Componentes grficos e layout


O primeiro passo criar um arquivo LZX de acordo com a Listagem 1.
Analisando o cdigo, voc ver que os
elementos XML representam componentes visuais, e definies de classes
e de funes JavaScript (estas ltimas
em tags <script>). Outro item que chama
ateno o fato de as classes usadas como
elementos XML comearem com letra
minscula, por exemplo button, o que
pode soar um tanto estranho para
quem est acostumado s convenes do Java.

Como se trata de uma linguagem orientada a objetos, a LZX nos permite definir
classes e mtodos e usar herana e polimorfismo. Tomemos como exemplo a classe
meuBotao. Ela herda da classe button e define
um mtodo que ser disparado pelo evento
onclick. O corpo do mtodo todo escrito
em JavaScript e faz referncia a outros
objetos do documento, atravs dos seus
respectivos ids. Um id permite que um objeto seja referenciado de qualquer parte do
documento LZX. Por exemplo, na chamada
visor.setAttribute(text, ) visor o id.
Ao desenvolver aplicaes OpenLaszlo,
geralmente criamos primeiro toda a estrutura esttica da aplicao, definindo os
componentes visuais e o layout, e depois
adicionamos o comportamento e o processamento de eventos. Para a calculadora,
definimos uma janela, instanciando uma
classe window. Dentro dela adicionamos
uma caixa de texto edittext (o visor), e os
botes do tipo meuBotao. Em arquivos LZX,
o layout definido pela classe lzLayout e
suas classes filhas. No exemplo utilizamos
a classe simplelayout que estende lzLayout e

Browser Cliente
Plug-in Flash
Cliente OpenLaszlo

HTTP

Container Web / Servidor Java EE


Servidor OpenLaszlo

Figura 1. Arquitetura da plataforma OpenLaszlo

Edio 39 Java Magazine


jm39.indb 71

1

15/8/2006 18:20:40

RIA com Open Laszlo

organiza os componentes na tela, vertical e horizontalmente.


Alm desses componentes grficos, criamos tambm as views que so recipientes
para outros componentes (similares aos
containers do Swing/AWT) e ajudam na
organizao visual. A Figura 2 ilustra
como foi feito o layout da calculadora
os retngulos em laranja so views. A
Figura 3 mostra a calculadora em sua
verso final.

Definindo o comportamento
Com o layout definido e a parte esttica
construda, partimos para o comportamento da aplicao e a interao com
o usurio. A comear com os botes, o
leitor notar que todos so instncias
da classe meuBotao criada no incio do
arquivo LZX, e que contm um mtodo
para o evento onclick definido no elemento
<method event=onclick>. Ou seja, toda instncia desta classe invocar este mtodo

Listagem 1. calculadora.lzx
<canvas width=400 debug=false>
<simplelayout axis=y spacing=5/>
<script>
<![CDATA[
var param1 = 0;
var param2 = 0;
var operacao = ;
function chamaServidor() {
anm.doStart();
var p = new LzParam();
p.addValue(par1, param1, true);
p.addValue(par2, param2, true);
p.addValue(op, operacao, true);
myData.setQueryString(p);
myData.doRequest();
}
function mostraResultado() {
var resultado = myData.getPointer().xpathQuery(
RESULTADO/text());
Debug.write(resultado);
visorResultado.setAttribute(
text, param1 + operacao + param2 + = + resultado);
anm2.doStart();
}
function animaJanela() {
tsp = janela.getAttribute(opacity);
if (tsp < 1)
janela.animate(opacity,+1,3500,true);
else
janela.animate(opacity,-1,3500,true);

}
]]>

</script>

<dataset name=myData id=myData


src=http://localhost:8080/calculadora.jsp
ondata=mostraResultado()/>
<class name=meuBotao extends=button width=30>
<method event=onclick>
var textoBotao = this.getAttribute(text);
var valorVisor = visor.getAttribute(text);
if (textoBotao == + || textoBotao == - ||
textoBotao == / || textoBotao == X)
{
operacao = textoBotao;
param1 = valorVisor.substring(1);
visor.setAttribute(text, );
} else if (textoBotao == =) {
param2 = valorVisor.substring(1);
visor.setAttribute(text, );
chamaServidor();
}
else if (textoBotao == C) {
visor.setAttribute(text, );
} else {

if (valorVisor == 0) {
visor.setAttribute(text, );
}
visor.setAttribute(text, valorVisor + textoBotao);

}
</method>
</class>

<text id=visorResultado bgcolor=#ffcccc width=0>


<animatorgroup id=anm2 start=false process=simultaneous>
<animator attribute=width to=150
duration=2500 motion=linear/>
<animator attribute=opacity from=0 to=100
duration=2000/>
</animatorgroup>
</text>
<window id=janela>
<animatorgroup id=anm start=false process=simultaneous>
<animator attribute=x
to=100 duration=1000 motion=linear/>
<animator attribute=y to=100 duration=1000/>
</animatorgroup>
<view bgcolor=#666699 id=minhaView>
<simplelayout axis=y spacing=5/>
<edittext id=visor text= enabled=false/>
<view bgcolor=#666699>
<simplelayout axis=x spacing=5/>
<meuBotao text=1/>
<meuBotao text=2/>
<meuBotao text=3/>
<meuBotao text=X/>
</view>
<view bgcolor=#666699>
<simplelayout axis=x spacing=5/>
<meuBotao text=4/>
<meuBotao text=5/>
<meuBotao text=6/>
<meuBotao text=+/>
</view>
<view bgcolor=#666699>
<simplelayout axis=x spacing=5/>
<meuBotao text=7/>
<meuBotao text=8/>
<meuBotao text=9/>
<meuBotao text=-/>
</view>
<view bgcolor=#666699>
<simplelayout axis=x spacing=5/>
<meuBotao text=C/>
<meuBotao text=0/>
<meuBotao text==/>
<meuBotao text=//>
</view>
</view>
</window>
<button text=Clique aqui onclick=animaJanela()/>
</canvas>

2 Java Magazine Edio 39


jm39.indb 72

15/8/2006 18:20:48

Edio 39 Java Magazine


jm39.indb 73

73

15/8/2006 18:20:51

RIA com Open Laszlo

Figura2. Layout da calculadora.

Figura3. Verso final da calculadora.

ao receber o evento onclick. O mtodo


seta as variveis param1, operacao e param2
de acordo com a operao indicada pelo
usurio.
Para submeter os dados para o JSP,
utilizamos a classe dataset, que permite
enviar parmetros HTTP e recuperar
a resposta formatada em XML. Note
que na definio do dataset myData, o
evento ondata chama a funo JavaScript
mostraResultado(). Dessa forma, assim que o
servidor retornar a reposta, a funo ser
invocada. O cdigo do JSP bem simples,
conforme ilustra a Listagem2.
Aps os dados serem submetidos e a
resposta do clculo ser recuperada, uma
animao faz com que a calculadora se
mova para a direita, para que o resultado
seja mostrado no plano de fundo. Isso
possvel graas ao mtodo animate() da
classe lzNode (que a superclasse de todos
os componentes grficos). Este mtodo
permite que alteraes nas propriedades
de um objeto sejam feitas num espao de
tempo determinado. A nossa aplicao
contm algumas animaes, como a definida no elemento <animatorgroup>. Este
elemento agrupa um conjunto de animaes relacionadas, que so executadas
simultaneamente ou em seqncia.
A funo animaJanela() tambm utiliza
recursos de animao. No cdigo dessa
funo, observe que o mtodo animate()
recebe quatro parmetros: o atributo que
ser animado, o valor que o atributo dever receber; o tempo total da animao,
para que o atributo assuma o novo valor;
e um booleano, indicando se a alterao
do atributo deve ser relativa ou no.

Listagem 2. calculadora.jsp
<%@ page contentType=text/xml %>
<%@ taglib prefix=c uri=http://java.sun.com/jstl/core %>
<c:set var=par1 value=${param[par1]}/>
<c:set var=par2 value=${param[par2]}/>
<c:set var=op value=${param[op]}/>
<c:if test=${op==+}>
<c:out value=<RESULTADO>${(par1 + par2)}</RESULTADO>
</c:if>
<c:if test=${op==-}>
<c:out value=<RESULTADO>${(par1 - par2)}</RESULTADO>
</c:if>
<c:if test=${op==/}>
<c:out value=<RESULTADO>${(par1 / par2)}</RESULTADO>
</c:if>
<c:if test=${op==X}>
<c:out value=<RESULTADO>${(par1 * par2)}</RESULTADO>
</c:if>

escapeXml=false/>

Para rodar a aplicao, basta copiar o


arquivo calculadora.lzx para o diretrio
server\lps-3.3.3\myapps de sua instalao
do OpenLaszlo. necessrio tambm
instalar o JSP no Tomcat. Para simplificar,
vamos coloc-lo no diretrio server\tomcat-5.0.24\webapps\ROOT (a verso do
Tomcat pode variar). Alm disso, como o
JSP usa a JSTL precisamos do jstl.jar e do
standard.jar (disponveis em jakarta.apache.org/site/downloads/downloads_taglibs.
html, na seo Standard 1.1 Taglib).
Copie estes dois JARs para o diretrio
Server\tomcat-5.0.24\webapps\ROOT\
WEB-INF\lib.
Pronto. Basta apontar o browser para
http://localhost:8080/lps-3.3.3/my-apps/
calculadora.lzx para ver o exemplo funcionando.

Concluses
Neste artigo apresentamos o bsico do
OpenLaszlo, da instalao criao de
uma aplicao funcional que faz uso de
cdigo Java no servidor. O OpenLaszlo
uma plataforma que vem ganhando apoio
crescente da comunidade de desenvolvedores e integra-se especialmente bem com
a tecnologia Java. A plataforma est em
franca evoluo, como atesta o novo projeto Legals com release final previsto
para o final deste ano, e que suportar a
gerao para Flash 9 e DHTML.

OpenLaszlo.org
Site oficial do OpenLaszlo que contm
tutoriais e um frum com participao da
comunidade.
laszlosystems.com
Empresa que criou o Laszlo original. Disponibiliza
aplicaes comerciais bastante profissionais.
laszlomail.com
Exemplo de uma aplicao feita em Laszlo.
javamagazine.com.br/downloads/jm39/
jm-openlaszlo.zip

escapeXml=false/>
escapeXml=false/>
escapeXml=false/>

Andr Lus Monteiro


(andre.monteiro@fiveware.com.
br) consultor snior da Fiveware
Solutions e tem as certificaes
SCJP, SCWCD e SCEA.

74 Java Magazine Edio 39


jm39.indb 74

15/8/2006 18:20:52

jm39.indb 75

15/8/2006 18:20:56

Se voc anda precisando de ajuda para manter a sua empresa na internet,


est na hora de conhecer as solues completas da LocaWeb.
A LocaWeb torna-se mais completa a cada dia que passa. Hoje ela oferece todos os tipos de servios e
ferramentas de internet, atendendo s diversas necessidades de seus clientes. E para estar ainda mais
prxima deles, a LocaWeb no pra de investir para ter um atendimento cada vez mais gil e eficiente. Mude
para a LocaWeb. A gente garante a sua tranqilidade. www.locaweb.com.br

Na contratao de um Plano de Hospedagem* voc tem: Blog Gratuito E-mails LocaMail com antivrus e anti-spam Completo painel de controle
Suporte s linguagens ASP**, .NET 2.0, JSP e Servlets***, PHP 5***, PERL, Python***, C,C++***, Ruby on Rails***, PERL/CGL, XML, WML/WAP
Diversos componentes para ASP e .NET Relatrios de visita em portugus Certificado seguro com SSL Banco de dados Access**, MySQL
5.0*** e PostgreSQL 8.1*** Podcast Backup dirio incluso Garantia de disponibilidade de 99,5%
E ainda pode contratar servios adicionais hospedagem como: comrcio eletrnico, banco de dados MS SQL Server, Oracle compartilhado, MySQL
para Windows, MySQL adicional para Linux, domnios e pacotes de e-mails adicionais e muito mais.
*Para mais detalhes e complementao de condies, consulte o modelo de contrato disponvel no site www.locaweb.com.br **em Windows ***em Linux

jm39.indb 76

15/8/2006 18:20:58