Você está na página 1de 66

Uma nova marca,

a confiabilidade de sempre.

Conhea nossos frameworks open-source

genesis

O framework genesis garante uma maior produtividade no desenvolvimento de aplicaes


desktop, permitindo a utilizao de Swing, SWT e Thinlet de forma declarativa e com suporte
a anotaes como forma de evitar as complexidades e particularidades de cada API grfica.
Seu modelo de integrao entre interface e camada de negcios possibilita que aplicaes
locais, implementadas de forma simples e facilmente testvel, possam ser posteriormente disponibilizadas em arquitetura rich-client distribuda, simplesmente reconfigurando-se sua lgica
de negcios para execuo remota em servidores Java EE. Alm de open-source e gratuito, o
genesis possui extensa documentao (em ingls e portugus) e uma ativa comunidade de
desenvolvedores.

DevWare

O DevWare um ambiente virtual completo de desenvolvimento j instalado e configurado, composto exclusivamente por produtos open source. Inclui
controle de issues e de verso, automao de buid, frum, wiki corporativa,
servidores web, email e ftp, repositrio maven2, servidor ldap para controle
de usurios, console administrativo, entre outros. Com baixo consumo de recursos e baseado em tecnologia de virtualizao, o DevWare foi projetado
especialmente para facilitar tarefas administrativas como backup e migrao
entre mquinas. Consulte-nos para saber como o DevWare, combinado com
boas prticas de desenvolvimento, pode aumentar a qualidade e produtividade
de seus projetos Java.

Os frameworks genesis e DevWare foram criados pela


Summa Technologies, disponibilizados de forma livre e
gratuita (licena open source LGPL).
Para maiores informaes, downloads e
documentaes consulte os sites:
https://genesis.dev.java.net/
https://devware.dev.java.net/

Uma empresa premiada


Entre os projetos que j contaram com a consultoria da Summa Technologies, incluem-se os trs
nicos sistemas brasileiros premiados com o Duke
Award, conferido anualmente durante o JavaOne
Conference: Carto Nacional de Sade do Datasus
(2003); IRPF Multiplataforma da Receita Federal
e Serpro (2004); e Sistema Integrado de Agendamento de Pacientes da Secretaria de Sade da
Prefeitura de So Paulo (2005).

Summa Technologies do Brasil . +55.11.3055.2060 . www.summa-tech.com

Consultoria . Arquitetura . Mentoring . Treinamento . Framework . Componentes


Em busca de novos desafios em sua carreira? Envie seu currculo para: curriculo@summa-tech.com

Especial

Contedo
NO MUNDO DA INTERNACIONALIZAO
FERNANDO LOZANO

08

Entendendo e usando os recursos da plataforma Java para a construo de aplicaes internacionalizveis, de sistemas console a aplicaes desktop e web

Mobile e Web

WIRELESS UPDATE: MIDP 2.1


MARLON LUZ
Conhecendo mudanas na verso final mais recente do perfil MIDP, que s agora
est chegando aos celulares do mercado mundial e brasileiro

30

PORTLETS COM JBOSS PORTAL


EDGAR SILVA
Saiba como construir de forma simples portlets para portais corporativos em Java,
utilizando APIs padres de mercado e o container de portlets da JBoss

JAVA EE NO ECLIPSE COM WTP 2.0


OSVALDO DOEDERLEIN

60

18

Domine a nova verso do projeto da Fundao Eclipse para desenvolvimento de aplicaes corporativas em Java, e crie exemplos para web e Java EE 5

LAYOUTS EFICAZES COM SITEMESH

Qualidade

DANIEL CICERO AMADEI

40

Tcnicas para manter um look-and-feel e uma estrutura consistentes entre todas as


pginas de suas aplicaes web, usando o framework livre da OpenSymphony

JAVAFX SCRIPT ATRAVS DE EXEMPLOS


JORGE DIZ & YARA SENGER

34

Conhea a nova linguagem JavaFX Script, que permite criar interfaces grficas ricas
mais facilmente, com cdigo parecido estrutura dos componentes visuais

TRATAMENTO DE EXCEES NA PRTICA


ANDR DINIZ

48

Entendendo conceitos de excees do Java, usando boas prticas e evitando armadilhas, para tornar suas aplicaes mais robustas e organizar a manipulao de erros

Core

SISTEMAS MULTIAGENTES
RICARDO MARQUES PORTO
Usando a tecnologia de agentes inteligentes e o framework open source JADE para
criar aplicaes dinmicas e altamente distribudas

52

Ano VI Edio 50 2007 ISSN 1676-8361

Direo

Carta ao Leitor

Diretor de Marketing Gladstone Matos

Edio
Publisher e Editor-Chefe
Leonardo Galvo (leonardo@javamagazine.com.br)
Editores adjuntos
Osvaldo Doederlein (osvaldo@javamagazine.com.br)

Retornamos mais uma vez ao assunto de desenvolvimento web e Java EE,

Fernando Lozano (lozano@javamagazine.com.br)

mas nesta edio com um toque especial de modernidade. Voc vai ver, por

Colaboraram nesta edio


Andr Diniz, Daniel Cicero Amadei, Fernando Lozano, Jorge Diz, Marlon Luz,
Osvaldo Doederlein, Ricardo Marques Porto, Yara Senger

Arte

exemplo, como criar uma aplicao com acesso a banco de dados usando o
novo JavaFX Script. O conjunto de tecnologias JavaFX, que inclui alm do
JavaFX Script, o JavaFX Mobile (para dispositivos mveis de alta capacidade) foi lanado no incio desse ano e possibilita a criao de interfaces ricas

Diagramao Vinicius O. Andrade

com recursos similares ao Flash, porm com a vantagem do acesso s APIs

Ilustraes e Capa: Antonio Xavier

do Java, sem adaptaes foradas. Com o suporte crescente a ferramentas, o

Produo

JavaFX est se tornando uma soluo eficaz para a criao de aplicaes com

Gerncia de Marketing Kaline Dolabella

GUIs interativas e ricas.

Distribuio
Fernando Chinaglia Distribuidora S.A.

A esperada verso 2.0 do Web Tools Project coloca o Eclipse de volta na disputa

Rua Teodoro da Silva, 907, Graja - RJ

pela liderana no desenvolvimento Java EE 5, trazendo muitos novos recursos e

CEP 20563-900, (21) 3879-7766 - (21) 2577-6362

mais robustez. Nos exemplos criados no artigo sobre o WTP, so exercitadas as

Atendimento ao leitor

principais facilidades do projeto. Voc ver como desenvolver passo a passo uma

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.

aplicao Java EE fazendo uso de JSF, EJB 3.0, JPA e Apache Derby.
Sitemesh, um framework que compete de frente com o Apache Tiles (discutido nas
duas edies anteriores) e oferece vantagens em certos aspectos. Voc poder entender o funcionamento interno do Sitemesh, alm de como us-lo da melhor forma em

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

suas aplicaes web, para padronizar e organizar o layout das pginas.


Com a expanso das empresas nacionais no exterior e o inexorvel crescimento da web, vem se tornando ainda mais importante a criao de aplicaes internacionalizveis: prontas para serem traduzidas e adaptadas para

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.
Java, o logotipo da xcara de caf Java e todas as marcas e logotipos baseados em ou
referentes a Java so marcas comerciais ou marcas registradas da Sun Microsystems,
Inc. nos Estados Unidos e em outros pases.
Realizao

Ainda dentro dos destaques de capa, trazemos um artigo aprofundado sobre o

novos idiomas e culturas. Um artigo especial nesta edio esmia o assunto,


mostrando como usar os muitos recursos que o Java oferece para i18n, tanto
para aplicaes console como para as Swing e web.
Veja ainda como criar portlets e rod-los no JBoss Portal; conhea as novidades do MIDP 2.1 na nossa coluna sobre tecnologias wireless, e confira um
artigo para iniciantes voltado ao tratamento de excees. Tambm no perca
a matria sobre o uso de agentes inteligentes com Java, que demonstra como
tcnicas antes exploradas apenas no meio acadmico j esto sendo usadas
com sucesso em aplicaes comerciais e como voc pode
aproveit-las em suas aplicaes.
Boa leitura!

Apoio

Leonardo Galvo

Conhea a assinatura Java


Magazine Plus mais contedo
Java com mais de 200 vdeo-aulas
para voc e dois Cursos Online.

www.devmedia.com.br/javaplus .

aro leitor, como voc j sabe, o conceito de assinatura da

Na DevMedia, o leitor de banca tambm ganha!

revista Java Magazine mudou. O novo assinante da revista

Java Magazine possui uma Assinatura de Contedo Java Plus:

Na compra desta edio, tenha acesso a 10 aulas sobre a criao de relatrios em Java com o iReport:

Java Plus = Revista impressa + Vdeo-aulas + Cursos online

1. Configurao do ambiente e viso geral


2. Criando um relatrio diretamente, sem o assistente
3. Manipulao de classes e realizao de clculos
4. Agrupamentos e parmetros
5. Quebras e Bookmarks
6. Relatrios com cores alternadas (zebrados)
7. Relatrios CrossTab bsico
8. Relatrios CrossTab avanados
9. Grficos de piizza 3D
10. Grficos em linhas

O pacote Java Plus inclui:


Recebimento mensal da revista Java Magazine (12 edies)
Acesso, durante um ano, ao portal JavaPlus, contendo vdeoaulas e cursos online.
Continuamos estendendo o portal com vdeo-aulas voltadas ao
desenvolvedor Java e para iniciantes na tecnologia. J so mais de
200 aulas, alm de dois cursos online. Acesse o portal JavaPlus e
saiba como obter esse novo benefcio em sua assinatura!

Para visualizar, acesse o link:


w w w.devmedia.com.br/ar ticles/listcomp.asp?key word=jm51&codigobanca=metrojava

Novidades recentes em vdeo-aulas


Tipos enumerados: coisas que talvez voc no
soubesse que pudesse fazer com eles
Nesta vdeo-aula, so apresentados os tipos enumerados, presentes
na linguagem Java a partir da verso 5, desmistificando a viso
comum a diversos desenvolvedores de que os enums no passam
de valores numricos glorificados.

Web Services e XML - DOM Partes 1, 2 e 3


Nestas aulas, veja uma introduo ao uso de XML via DOM, bem como
uma anlise dessas tecnologias no contexto de web services

Persistncia Flexvel com BoxSQL Partes 1 a 4


Como criar uma camada de persistncia flexvel utilizando o framework
BoxSQL, Generics e Reflection. Na primeira aula, estruturamos o projeto
e apresentamos o BoxSQL. Depois construda a interface DAO e a classe

6 Java Magazine Edio 50

Cursos Online
GenericBoxDAO, buscando a utilizao com diversos beans. Construmos
ento os templates SQL, explicando a forma como os parmetros so
mapeados. Na quarta parte, vemos como construir a classe de testes
unitrios para o DAO genrico que criamos.

Padres de Projeto em Java


Apresentando diversos design patterns, e aplicando-os na
prtica usando a linguagem e as plataformas Java.
http://www.devmedia.com.br/cursos/saibamais.asp?curso=25

Ruby on Rails Partes 1 a 6


O Ruby on Rails j foi concorrente direto do Java, mas hoje a
JVM e ferramentas como o NetBeans so ambientes excelentes para execuo de aplicaes e o desenvolvimento com o
RoR. Veja nesta srie de artigos como desenvolver com Ruby
e o framework Rails. O curso comea com uma viso geral
do Rails, passa ao Scaffold e IRB e depois entra na discusso
do Active Record e recursos de validao. A quarta aula trata
da associao de entidades. Em seguida, voc v como usar
o console do Rails, em duas aulas.

Introduo ao desenvolvimento para celulares


com Java ME
Apresentando tcnicas, APIs e ferramentas para a criao de
aplicaes com a tecnologia Java Micro Edition.
http://www.devmedia.com.br/cursos/saibamais.asp?curso=17

Edio 46
50 Java Magazine

No Mundo da Internaci
Construindo aplicaes para vrios idiomas e

ma aplicao internacionalizvel
tem seu cdigo escrito de modo que
seja adaptvel a diferentes idiomas
e a diferentes culturas, sem que para isso seja
necessrio modificar os fontes ou mesmo recompilar a aplicao. Muitas vezes a palavra
internacionalizao abreviada para i18n,
que vem do termo ingls internationalization
(representando a primeira e ltima letra,
com 18 caracteres entre elas).
No mundo globalizado, onde vrias empresas brasileiras atuam fortemente em
pases diversos, importante desenvolver
desde o incio aplicaes internacionalizveis. Tambm comum que sistemas
inicialmente desenvolvidos internamente
por filiais no Brasil de empresas multinacionais sejam posteriormente adotados em
outras filiais e at mesmo pela matriz. Por
isso fundamental saber como desenvolver aplicaes i18n.
A plataforma Java foi o primeiro ambiente de desenvolvimento de uso amplo
a trazer funcionalidades voltadas para a

internacionalizao de aplicaes. Estas


funcionalidades tm vrias formas, sendo
duas de interesse especial para o desenvolvedor de aplicaes:
1- A possibilidade de se obter automaticamente verses especficas de recursos
(arquivos de dados) para as configuraes regionais1 do usurio, em tempo de
execuo.
2- A capacidade de vrias classes da
biblioteca padro do Java SE modificar
seu comportamento de acordo com as
configuraes regionais do usurio.
A primeira funcionalidade torna fcil
exibir mensagens (strings) diferentes de
acordo com o idioma do usurio. J a
segunda faz com que operaes como for1 Estamos usando o termo configuraes regionais
para indicar as preferncias do usurio em relao a idioma, fuso horrio, formato de datas, nmeros e quaisquer
outras caractersticas culturais que possam ser configuradas pelos mecanismos padres do sistema operacional
nativo ou pelo navegador web.

matao de datas para exibio assumam


as configuraes corretas, sem interveno
do usurio ou do programador.
Em uma avaliao superficial, o processo
de internacionalizao2 de uma aplicao
pode parecer trivial, o que pode levar
o desenvolvedor a no valorizar tanto
as facilidades embutidas na plataforma
Java. Afinal, bastaria fazer coisas simples
como trocar arquivo por file em todo
o cdigo, ou exibir datas em formato ms/
dia/ano em vez de dia/ms/ano, para se
ter uma aplicao internacionalizvel.
Entretanto, ao se levar em conta problemas
como a correta ordenao de strings acentuadas, diferenas gramaticais e mscaras
para entrada de dados, a questo deixa de
ser simples. Por exemplo, ma deve vir
antes ou depois de maca? Ou ento, as
mensagens devem seguir a forma verboquantificador-substantivo, por exemplo
encontrados 3 registros, ou devem seguir
a forma quantificador-substantivo-verbo
como em 3 records found)?
Muitas dessas questes so resolvidas pela
plataforma Java sem interveno do programador (simplesmente funciona!). Mesmo assim,
o programador deve fazer sua parte para criar
aplicaes 100% internacionalizveis. Por isso
este artigo apresenta as principais funcionalidades para internacionalizao oferecidas pelas
plataformas Java SE e Java EE, exemplificando
seu uso em aplicaes Swing e web.

Sobre os exemplos
Os exemplos iniciais deste artigo sero
compilados e executados diretamente pela
linha de comando do sistema operacional,
utilizando os comandos fornecidos com o
2 importante no confundir o processo de internacionalizao, que responsabilidade do programador, com
o processo de localizao. Este ltimo a traduo de
uma aplicao para um idioma e uma regio especficos
que em geral realizado por profissionais sem conhecimentos de programao de computadores.

8 Java Magazine Edio 51

onalizao
culturas

Conhea os recursos da
plataforma Java para a
construo de aplicaes
internacionalizveis
de sistemas console a
aplicaes desktop e web

Fernando Lozano
JDK. J os exemplos mais complexos sero
compilados e executados (ou, no caso daqueles para web, deployados) por meio de
um buildfile do Ant. Todos os exemplos foram testados com o JDK 1.5.0 e o Tomcat 5.5,
mas devem funcionar sem modificaes em
verses mais recentes do Java e em outros
containers web aderentes s especificaes
Servlets 2.4 e JSP 2.0 ou superiores.

guraes regionais do usurio. Para deixar


evidente a presena do Locale na JVM, as
Listagens 1 e 2 apresentam dois exemplos, VerLocalidade.java e ListaLocalidades.
java, que permitem consultar a localidade
padro ou obter informaes sobre as localidades disponveis na JVM. As mesmas
listagens apresentam exemplos de utiliza-

Localidades, idiomas e pases

Listagem 1. Exemplo de manipulao de Locales

As funcionalidades para internacionalizao do Java so baseadas no conceito de


locale, ou localidade. Mais especificamente,
um java.util.Locale representa a combinao
de um idioma e uma regio geogrfica
(sendo esta ltima opcional). O idioma e a
regio de um locale so identificados por
cdigos de duas letras padronizados pela
ISO, por exemplo o familiar pt_BR para
o portugus brasileiro ou en_GB para o
ingls da Gr-Bretanha.
A classe Locale em si quase no tem
inteligncia. Ela basicamente agrupa os
dois identificadores, junto a um terceiro
identificador para a variante (tambm
opcional). Esta serve apenas para acomodar dialetos regionais3 e para compatibilidade retroativa com o comportamento de
verses antigas dos sistemas operacionais
nativos. A funcionalidade de internacionalizao em si fornecida por vrias classes
que aceitam uma instncia de Locale como
parmetro, por exemplo java.util.Calendar,
java.util.Currency e java.text.NumberFormat.
Se o leitor nunca precisou se preocupar
com objetos Locale, porque a JVM fornece
um Locale default, que instanciado na inicializao da JVM de acordo com as confi-

VerLocalidade.java

3 Certamente nenhum desenvolvedor julgaria necessrio ter uma verso especfica de uma aplicao para o
portugus da Bahia ou para o portugus gacho, mas
em vrios pases da Europa e da sia os dialetos regionais
dentro de um mesmo pas so to ou mais diversos em
termos de vocabulrio, e at de variaes gramaticais,
quanto o portugus do Brasil e o de Portugal.

o destes dois programas pela linha de


comando do sistema operacional.
A localidade default da JVM pode ser modificada pela chamada a Locale.setDefault(),
embora o mais comum seja manter qualquer que seja a localidade selecionada
pela prpria JVM em sua inicializao.
O programa na Listagem 3 demonstra a

import java.util.*;
public class VerLocalidade {
public static void main(String[] args) {
Locale localidade = null;
if (args.length == 0) {
localidade = Locale.getDefault();
System.out.println(A localidade padro do usurio : + localidade);
}
else {
if (args.length == 1)
localidade = new Locale(args[0]);
else if (args.length == 2)
localidade = new Locale(args[0], args[1]);
else if (args.length == 3)
localidade = new Locale(args[0], args[1], args[2]);
System.out.println(A localidade requisitada : + localidade);
}

System.out.println(Idioma: + localidade.getDisplayLanguage());
System.out.println(Pas: + localidade.getDisplayCountry());
System.out.println(Variante: + localidade.getDisplayVariant());

Exemplos de execuo de VerLocalidade


$ java VerLocalidade
A localidade padro do usurio : pt_BR
Idioma: portugus
Pas: Brasil
Variante:
$ java VerLocalidade pt
A localidade requisitada : pt
Idioma: portugus
Pas:
Variante:
$ java VerLocalidade en GB
A localidade requisitada : en_GB
Idioma: English
Pas: United Kingdom
Variante:
$ java VerLocalidade no NO NY
A localidade requisitada : no_NO_NY
Idioma: Norwegian
Pas: Norway
Variante: Nynorsk

Edio 51 Java Magazine

No Mundo da Internacionalizao

Listagem 2. Exemplo de como relacionar as localidades reconhecidas pela JVM


ListaLocalidades.java
import java.util.*;
public class ListaLocalidades {
public static void main(String[] args) {
Locale[] localidades = Locale.getAvailableLocales();
System.out.println(Esto disponveis na JVM + localidades.length + localidades:);
for (Locale localidade : localidades) {
System.out.print(localidade + \t);
System.out.print(( + localidade.getDisplayLanguage());
System.out.print(, + localidade.getDisplayCountry());
System.out.println(, + localidade.getDisplayVariant() + ));
}
}
}

Execuo de ListaLocalidade
$ java ListaLocalidades
Esto disponveis na JVM 132 localidades:
ar
(Arabic, , )
ar_AE
(Arabic, United Arab Emirates, )
ar_BH
(Arabic, Bahrain, )
ar_DZ
(Arabic, Algeria, )
ar_EG
(Arabic, Egypt, )
ar_IQ
(Arabic, Iraq, )
... restante da listagem omitida para poupar espao

Listagem 3. Exemplo de configurao explcita de Locale


MudaLocalidade.java
import java.util.*;
import java.text.*;
public class MudaLocalidade {
public static void main(String[] args) {
//... instanciao do locale igual ao Exemplo 1 da listatem 1
Locale.setDefault(localidade);
DateFormat df = DateFormat.getDateInstance();
Date agora = new Date();
System.out.println(Data corrente na localidade + localidade
+ : + df.format(agora));
}
}

Exemplo de MudaLocalidade
$ java MudaLocalidade
Data corrente na localidade pt_BR: 11/09/2007
$ java MudaLocalidade en US
Data corrente na localidade en_US: Sep 11, 2007
$ java MudaLocalidade en GB
Data corrente na localidade en_GB: 11-Sep-2007

Listagem 4. Faixas.java
import java.util.*;
import java.text.*;
public class Faixas {
public static void main(String[] args) {
double[] limites = { 0, 1, ChoiceFormat.nextDouble(1) };
String[] mensagens = { No foi encontrado nenhum registro,
Foi encontrado um nico registro, Foram encontrados vrios registros };
ChoiceFormat resultado = new ChoiceFormat(limites, mensagens);
int numero = Integer.parseInt(args[0]);
System.out.println(resultado.format(numero));
}
}

Execuo de Faixas
$ java Faixas 0
No foi encontrado nenhum registro
$ java Faixas 1
Foi encontrado um nico registro
$ java Faixas 2
Foram encontrados vrios registros

10 Java Magazine Edio 51

mudana de localidade, e tambm como


o formato padro para exibio de datas
modificado de acordo com a localidade
default configurada para a JVM.
Na verdade, no necessrio mudar a
localidade para a JVM como um todo, pois
todos os mtodos cujo comportamento seja
afetado pela localidade possuem tambm
uma sobrecarga que recebe um java.util.Locale
como argumento. Ento estas duas linhas:
Locale.setDefault(localidade);
DateFormat df = DateFormat.getDateInstance();

Poderiam ser substitudas por:


DateFormat df = DateFormat.getDateInstance(
DateFormat.DEFAULT, localidade);

E o exemplo da Listagem 3 funcionaria


exatamente da mesma forma.

Formatao de mensagens
As classes java.text.DateFormat e java.text.
NumberFormat so de utilizao bem direta,
como foi demonstrado pelo exemplo da
Listagem 3. Entretanto, o pacote java.text
fornece ainda duas classes que so muito
teis para aplicaes internacionalizveis,
e que curiosamente no so afetadas diretamente pela localidade default da JVM.
Elas so ChoiceFormat e MessageFormat.
ChoiceFormat retorna mensagens diferentes
de acordo com faixas de valores para um
argumento numrico. Sua maior utilidade
em lidar com plurais, permitindo gerar
mensagens gramaticalmente corretas,
como mostra o exemplo da Listagem 4.
O exemplo define trs faixas de valores:
zero; maior que zero e menor ou igual
a um; e maior que um. Os limites para
cada faixa so valores decimais (double),
mas como no exemplo estamos utilizando
apenas valores inteiros, as faixas so na
verdade: zero, um e maior que um.
Observe o uso do mtodo nextDouble() para
que o limite final seja aberto ou infinito, de modo que qualquer valor maior que
um caia na terceira faixa. Dessa forma, o
ChoiceFormat seleciona a mensagem correta,
substituindo um conjunto de comandos
if...else if...else.

Mensagens com valores


J a classe MessageFormat permite compor
mensagens reunindo variveis e texto

fixo, de forma similar ao mtodo printf()


de PrintWriter. Mas, ao contrrio de printf(),
a classe MessageFormat respeita as configuraes regionais, pois delega a formatao de nmeros e datas para as classes
NumberFormat e DateFormat.
O exemplo da Listagem 5 demonstra
o uso de MessageFormat para inserir uma
contagem de registros dentro da mensagem, simulando um cenrio tpico
de aplicaes de busca. Observe o uso
da notao {0,number} dentro da string
passada como padro (atravs do argumento pattern) para o mtodo format() de
MessageFormat. Isso indica que o primeiro
argumento (ndice zero, como em um
array) depois da string de padro ser
formatado como um nmero, ou seja,
por um NumberFormat. Poderia haver
vrias outras mscaras e argumentos
no mtodo format(), possibilitando a
composio de mensagens com diversos
argumentos.
Como mencionamos, a classe
MessageFormat em si no afetada pela localidade configurada para a JVM, mas os
formatos aninhados (identificados pelas
mscaras dentro da string de formatao)
podem sim ser afetados. Por isto fornecido um construtor que recebe a string
com o padro de formatao e a localidade
desejada. Entretanto, ao se configurar um
MessageFormat com localidade diferente da
default da JVM, deve ser utilizado um
StringBuffer para armazenar o resultado
da formatao.
Ento, o que o segundo exemplo faz com
uma nica linha de cdigo, aproveitando
a verso esttica do mtodo format() de
MessageFormat:
System.out.println(MessageFormat.format(mensagem, numero));

... passaria a ser feito com vrias linhas


de cdigo, utilizando a verso no-esttica
do mesmo mtodo:
MessageFormat formato =
new MessageFormat(locale, mensagem);
StringBuffer buffer = new StringBuffer();
Object[] argumentos = { numero };
formato.format(argumentos, buffer, null);
System.out.println(buffer);

Preferimos, portanto, usar a verso esttica do mtodo format().


Utilizar um MessageFormat bem melhor

do que montar a mensagem pela concatenao de strings. Isso porque, quando


o programa for traduzido, fica fcil modificar a posio das mscaras dentro da
string que passada como padro para
o mtodo format, e assim adequar a mensagem s regras gramaticais de idiomas
diferentes. J com a simples concatenao
de strings, seria necessrio modificar a
lgica do programa.
Outra vantagem de MessageFormat que
uma simples string pode ser colocada
fora do programa, em um arquivo de propriedades. Dessa forma, a localizao do
programa deixa de exigir a sua recompilao. Mais adiante, veremos como obter as
mensagens de arquivos de propriedades;

por enquanto vamos continuar com o foco


nas classes do pacote java.text.

Conjugando faixas e valores


Um MessageFormat isolado capaz de lidar
apenas com a posio dos parmetros dentro da mensagem; porm ele no capaz de
modificar a parte fixa da mensagem para
acomodar regras gramaticais como concordncia verbal. No exemplo da Listagem 5,
note como fica deselegante a mensagem
foram encontrados 1 registros. O problema resolvido usando um ChoiceFormat
junto com o MessageFormat.
O exemplo da Listagem 6 mostra como
essas classes se complementam para
gerar uma mensagem natural para o

Listagem 5. Uso de MessageFormat


Mensagem.java
//... imports omitidos
public class Mensagem {
public static void main(String[] args) {
int numero = Integer.parseInt(args[0]);
System.out.println(MessageFormat.format(
Foram encontrados {0,number} registros,numero));
}
}

Execuo de Mensagem
$ java Mensagem 1
Foram encontrados 1 registros
$ java Mensagem 2
Foram encontrados 2 registros

Listagem 6. Uso conjugado de ChoiceFormat e MessageFormat


MensagemComFaixas.java (destacadas em negrito as diferenas entre este e o exemplo da Listagem 4)
//... imports omitidos
public class MensagemComFaixas {
public static void main(String[] args) {
double[] limites = { 0, 1, ChoiceFormat.nextDouble(1) };
String[] mensagens = { No foi encontrado nenhum registro,
Foi encontrado um nico registro,
Foram encontrados {0,number} registros };
ChoiceFormat resultado = new ChoiceFormat(limites, mensagens);
System.out.println(MessageFormat.format(resultado.format(numero), numero));
}
}

Execuo de MensagemComFaixas
$ java MensagemComFaixas 1
Foi encontrado um nico registro
$ java MensagemComFaixas 2
Foram encontrados 2 registros

MensagemComFaixas.java (segunda verso)


//... imports omitidos
public class MensagemComFaixas {
public static void main(String[] args) {
String mensagem = {0,choice, + 0#no foi encontrado nenhum registro| +
1#foi encontrado um nico registro| + 1<foram encontrados {0,number} registros};
int numero = Integer.parseInt(args[0]);
System.out.println(MessageFormat.format(mensagem, numero));
}
}

Edio 51 Java Magazine

11

No Mundo da Internacionalizao

usurio, com poucas linhas de cdigo. A


mensagem retornada pelo ChoiceFormat
utilizada como string de formatao por
um MessageFormat. Nas faixas limitadas
por zero e um, a mensagem retornada
por ChoiceFormat fixa. J para valores
maiores que um, a mensagem retornada
por ChoiceFormat contm uma mscara para
a insero do nmero de registros, que
ento processada pelo MessageFormat.
possvel simplificar o cdigo utilizando
o ChoiceFormat implicitamente, como uma
mscara de formatao de um MessageFormat,
tal qual foi feito com o NumberFormat.
possvel ainda aninhar mscaras de formatao dentro de uma string de padro
do MessageFormat, outra coisa que no seria
possvel fazer com printf().
A Listagem 6 apresenta tambm uma
segunda verso de MensagemComFaixas.
java usando mscaras aninhadas. Mais
especificamente, temos uma mscara
{0,choice} que aninha uma mscara {0,number}
em uma string de padro do MessageFormat.
Esta segunda verso funcionalmente

equivalente primeira, mas o cdigo


bem mais conciso.
A sintaxe para se aninhar um ChoiceFormat
dentro de um padro para MessageFormat
pode ser um tanto confusa nos seus primeiros usos. Ento vamos desmontar o
terceiro exemplo, passo a passo:
1. A notao {0,choice,...} indica que o
primeiro argumento (zero) utilizar um
ChoiceFormat;
2. O primeiro limite e a mensagem correspondente so indicados por 0#no foi..., onde
o caractere jogo-da-velha separa o valor do
limite da mensagem correspondente;
3. Uma barra vertical (ou pipe) indica o final da primeira mensagem em
...registro|1#foi encontrado... Depois vem o
segundo limite, e novamente um sinal de
jogo-da-velha separa o segundo limite da
segunda mensagem;
4. Mais uma vez, temos uma barra vertical para finalizar a segunda mensagem
em ...registro|1<foram encontrados..., s que
desta vez um sinal de maior-que substitui
o jogo-da-velha, indicando que o terceiro

Listagem 7. Uso de ResourceBundles para armazenar mensagens localizadas


Recurso.java
import java.util.*;
import java.text.*;
public class Recurso {
public static void main(String[] args) {
PropertyResourceBundle mensagens = (PropertyResourceBundle)
ResourceBundle.getBundle(mensagens);
int numero = Integer.parseInt(args[0]);
System.out.println(MessageFormat.format(
mensagens.getString(resultado_busca),numero));
}
}

mensagens_pt_BR.properties (todo o texto deve ser digitado em uma nica linha!)


resultado_busca=
{0,choice,0#No foi encontrado nenhum registro|
1#Foi encontrado um nico registro|
1<Foram encontrados {0,number} registros}

mensagens_en.properties (todo o texto deve ser digitado em uma nica linha!)


resultado_busca=
{0,choice,0#No records found|
1#Just one record found|
1<{0,number} records found}

Execuo de Recurso
$ java Recurso 4
Foram encontrados 4 registros
$ LANG=en_US java Recurso 4
4 records found
$ LANG=pt java Recurso 4
4 records found
$ LANG=es java Recurso 4
4 records found

12 Java Magazine Edio 51

limite aberto;
5. Dentro da terceira mensagem, h
um NumberFormat aninhado: ...encontrados
{0,number} registros...;
6. Como a terceira mensagem a ltima
do ChoiceFormat, no temos uma barra vertical, e sim o sinal de fecha-chaves para
finalizar o formato iniciado por {0,choice...
Vimos como utilizar as classes do pacote
java.text para formatar mensagens que
soem naturais quando lidas pelo usurio.
Agora falta remover as strings do cdigo
Java, colocando-as em arquivos propriedades que podem ser editados e traduzidos
sem afetar os bytecodes da aplicao.

Recursos da JVM
Um recurso da JVM um arquivo de
dados que carregado por um classloader da JVM, em vez de por acesso direto
ao sistema de arquivos. A idia que o
mesmo algoritmo utilizado para se localizar os bytecodes de uma classe seja
utilizado para se localizar os arquivos de
dados necessrios para esta classe. Dessa
forma, no importa se a classe est em um
arquivo .class isolado, dentro de um JAR,
ou mesmo se foi carregada remotamente,
como ocorre com applets. O resultado so
aplicaes mais portveis e com menos
cdigo, pois no mais necessrio para a
aplicao lidar com detalhes como letras
de drives e convenes para a localizao
de arquivos de configurao em cada sistema operacional.
Se todas as mensagens (e padres de
formatao) utilizados por uma aplicao
forem colocados em um arquivo carregado
como um recurso da JVM, torna-se fcil
localizar uma aplicao: basta modificar
um arquivo de mensagens.
As bibliotecas do Java SE vo mais alm,
fornecendo a classe java.util.ResourceBundle,
que rene os conceitos de recursos da
JVM e de localidade, resultando em uma
maneira simples de se carregar mensagens customizadas para as configuraes
regionais dos usurios. ResourceBundle
utiliza os identificadores de idioma, pas
e variante da localidade para gerar um
nome de arquivo, e este arquivo ento
carregado como um recurso da JVM. O
arquivo (se encontrado) interpretado

como sendo um arquivo de propriedades


e encapsulado em uma instncia de java.
util.PropertyResourceBundle4.
O exemplo da Listagem 7 demonstra
como usar recursos da JVM para obter a
string a ser utilizada como padro para
MessageFormat. Neste exemplo, a string
mensagens, passada para o mtodo
getBundle(), a base para o nome do arquivo de recursos a ser localizado. O nome
construdo pela adio de um ou mais sufixos correspondentes aos identificadores
de idioma, pas e variante armazenados
no Locale. J a string resultado_busca
passada para o mtodo getString() a chave
para a entrada no arquivo que retorna a
4 Na verdade, a classe ResourceBundle ainda mais poderosa, fornecendo um mecanismo genrico para a obteno de recursos, os quais podem envolver outras coisas
que no arquivos de propriedades. Entretanto as alternativas no so to utilizadas quanto o PropertyResourceBundle
e, na maioria dos casos, exigem a definio de uma especializao de ResourceBundle; por isso no sero apresentadas neste artigo.

mensagem desejada.
Fazem parte do exemplo dois arquivos de
propriedades: mensagens_pt_BR.properties
e mensagens_en.properties. Note que se
ResourceBundle no encontrar um arquivo de
propriedades correspondente localidade
desejada, como no caso en_US, ele descarta a variante e o pas e tenta localizar um
arquivo que corresponda apenas ao idioma
da localidade. Neste caso encontrado
mensagens_en.properties. Por outro lado, o
ResourceBundle no ir tentar usar arquivos
do mesmo idioma mas com pas diferente;
por isso mensagens_pt_BR.properties no foi
localizado para a localidade pt.
No sendo encontrado um arquivo de propriedades correspondente localidade desejada,
ResourceBundle utiliza o arquivo disponvel para
en ou en_US. Ou seja, para qualquer localidade
ainda no suportada pela aplicao (como no
caso de es espanhol no exemplo) sero utilizados os recursos para o idioma ingls.

Usurios de sistemas Unix, como o


Linux e o MacOS X, podero fazer como
no exemplo de execuo da Listagem 7,
utilizando na linha de comando a notao
LANG=localidade para executar a classe
Recurso sob uma localidade diferente da especificada nas configuraes regionais do
usurio corrente. J usurios de sistemas
Windows tero de mudar a localidade pelo
Painel de Controle, ou ento modificar
o programa para forar uma localidade
diferente (com Locale.setDefault()).

Excees e internacionalizao
A apresentao da classe ResourceBundle
encerra nosso estudo sobre os recursos gerais para internacionalizao de aplicaes
Java. Agora podemos tratar de consideraes especficas para aplicaes grficas
(Swing) e web. Mas, antes de entrar nos
exemplos de aplicaes mais elaboradas,
vale chamar a ateno para um erro conceitual s vezes cometido por iniciantes.

Edio 51 Java Magazine

13

No Mundo da Internacionalizao

Muitos desenvolvedores se questionam


porque a classe java.lang.Throwable e suas
subclasses, ou seja, as excees do Java,
no so internacionalizveis. Eles sugerem
que uma instncia de Throwable poderia ser
inicializada contendo vrias mensagens,
uma para cada localidade suportada pela
aplicao. Outros se do ao trabalho de
obter, via programao, as mensagens de
erro a serem embutidas nas suas excees,
a partir de ResourceBundles.
O erro conceitual aqui exibir para o
usurio a mensagem de erro embutida
em uma exceo, quando esta mensagem
na verdade serve para consulta por um
desenvolvedor (que est depurando um
erro de cdigo, por exemplo), ou para o
suporte tcnico, que veria a mensagem de
erro e o stack trace da exceo registrados
em um arquivo de log.
A questo que, na maioria dos casos, a
mensagem de erro de uma exceo muito
tcnica para um usurio final. A situao
se complica ainda mais se levarmos em
conta que excees de negcio podero
aninhar excees de mais baixo nvel, por
exemplo erros de rede, como suas causas.
Alm disso, uma exceo geralmente no

Figura 1. A mesma aplicao Swing, em dois idiomas

Figura 2. Servlet Internacionalizado

14 Java Magazine Edio 51

Listagem 8. Aplicao Swing localizada para portugus e ingls


package localidades;
//... imports omitidos
public class Janela extends JFrame {
public Janela() {
initComponents();
setLocationRelativeTo(null);
localidade.setSelectedItem(getLocale().toString());
}
private void initComponents() {
//... algumas inicializaes omitidas
ResourceBundle mensagens = ResourceBundle.getBundle(
localidades/mensagens, getLocale());
FormListener formListener = new FormListener();
setTitle(mensagens.getString(titulo));
rotuloLocalidade.setLabelFor(localidade);
rotuloLocalidade.setText(mensagens.getString(rotuloLocalidade));
dataCorrente.setValue(new Date());
localidade.setModel(new DefaultComboBoxModel(
new String[] { pt_BR, en_US }));
localidade.addItemListener(formListener);
rotuloDataCorrente.setText(mensagens.getString(rotuloData));
//... outras inicializaes omitidas
pack();
}
private class FormListener implements ItemListener {
public void itemStateChanged(ItemEvent evt) {
if (evt.getSource() == localidade) {
Janela.this.mudaLocalidade(evt);
}
}
}
private void mudaLocalidade(ItemEvent evt) {
if (evt.getStateChange() == evt.SELECTED) {
Locale novaLocalidade = null;
String[] ids = ((String)evt.getItem()).split(_);
if (ids.length == 1)
novaLocalidade = new Locale(ids[0]);
else if (ids.length == 2)
novaLocalidade = new Locale(ids[0], ids[1]);
if (novaLocalidade.equals(getLocale()))
return;
this.setVisible(false);
Locale.setDefault(novaLocalidade);
JComponent.setDefaultLocale(novaLocalidade);
Janela janela = new Janela();
janela.setVisible(true);
this.dispose();
}
}
private JFormattedTextField dataCorrente;
private JComboBox localidade;
private JLabel rotuloDataCorrente;
private JLabel rotuloLocalidade;

public static void main(String[] args) {


new Janela().setVisible(true);
}

tem conhecimento do contexto em que


foi gerada, ou seja, de quais mtodos de negcio a provocaram. Isto limita seriamente
a possibilidade de se gerar uma mensagem
inteligvel para o usurio e ao mesmo tempo preservar o isolamento entre as classes
de diferentes camadas da aplicao.
A prtica correta utilizar o tipo da
exceo, ou seja, sua classe, para gerar
na camada de apresentao uma mensagem de erro contextualizada. Dessa
maneira, em vez de informar ao usurio
caminho de rede no encontrado, sem
rota para o host, fornecemos algo como
No foi possvel realizar a consulta, tente
novamente mais tarde. A sim, o cdigo
da camada de apresentao utilizar recursos para obter a mensagem localizada
para o idioma do usurio.
Em caso de dvida, lembre que formatao e traduo de mensagens responsabilidade da camada de apresentao. Ento
classes de negcios, DAOs e outros tipos

caelum-novoanuncio-meiapagina.aiPage 1 21/09/2007 12:33:17

de objetos fora da camada de apresentao


no precisam e nem devem ser localizveis (com o sentido de serem traduzveis
para outros idiomas).
No queremos dizer que classes de
negcio no so internacionalizveis,
mas apenas que devemos prestar especial ateno s responsabilidades de
cada camada. Por exemplo, a exibio
do indicador de moeda R$ ou US$
responsabilidade da camada de apresentao mas saber se um valor especificado em reais ou dlares americanos
responsabilidade da camada de negcios.
No mesmo exemplo, tambm com a camada de negcio manter o valor da taxa
de cmbio, caso seja necessrio fazer a
converso entre valores armazenados em
diferentes moedas. Por outro lado, decidir
se deve ser utilizado vrgula ou ponto
decimal claramente responsabilidade
da camada de apresentao (e j previsto
pela classe NumberFormat).

Localizando aplicaes Swing


O desenvolvedor de aplicaes desktop
poder se surpreender com a aparente
falta de suporte internacionalizao na
biblioteca de componentes visuais padro
do Java SE, o Swing. Com exceo da
superclasse comum de todos os componentes Swing/AWT, java.awt.Component, que
define uma propriedade locale5 (mtodos
getLocale() e setLocale()), praticamente no
se encontram mtodos relacionados com
localidades.
Todo componente Swing especializa
javax.swing.JComponent (por sua vez uma subclasse de java.awt.Component), que acrescenta
a propriedade esttica defaultLocale. Ela
fornece o valor default para a propriedade
locale utilizado na instanciao de compo5 A maioria dos IDEs visuais, por exemplo o NetBeans,
no exibe a propriedade locale na janela de propriedades do componente selecionado, pois no faz sentido
na maioria dos casos haver componentes em localidades
diferentes dentro do mesmo formulrio.

CM

MY

CY

CMY

Edio 51 Java Magazine

15

No Mundo da Internacionalizao

nentes Swing.
Mas o fato que a maioria dos componentes Swing no utiliza para nada a sua
prpria configurao de localidade. Por
exemplo, no possvel inicializar um
JLabel com valores especficos para a propriedade text de acordo com a localidade, e
deixar que o prprio componente escolha
qual valor exibir em tempo de execuo.
Alguns componentes Swing realizam
trabalho diretamente relacionado com

internacionalizao por baixo dos panos,


por exemplo, suportando diferentes mtodos de entrada para digitao de texto (j
parou para pensar como deve ser digitar
um texto em japons?).
Os recursos gerais de internacionalizao j apresentados sero suficientes para
a maioria das situaes. Afinal, no h
necessidade de se onerar um simples JLabel
com vrias strings localizadas. Seria mais
eficiente, em termos de uso de memria,

Listagem 9. Servlet internacionalizvel e localizado para portugus e ingls


package localidades;
//... imports omitidos
public class Hoje extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws java.io.IOException, ServletException
{
Locale localidade = request.getLocale();
PropertyResourceBundle mensagens = (PropertyResourceBundle)
ResourceBundle.getBundle(localidades/mensagens, localidade);
DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, localidade);

PrintWriter out = response.getWriter();


out.println(<html><body>);
out.println(<h1> + mensagens.getString(titulo) + </h1>);
out.println(<big> + mensagens.getString(textoData));
out.println(df.format(new java.util.Date()));
out.println(<p><hr> + mensagens.getString(textoLocalidade));
out.println(localidade.getDisplayName());
out.println(</big></body></html>);

Listagem 10. Pgina JSP internacionalizvel e localizada para portugus e ingls


hoje.jsp: Pgina JSP localizada com uso do JSTL
<%@ page contentType=text/html; charset=utf-8 pageEncoding=utf-8%>
<%@ taglib uri=http://java.sun.com/jsp/jstl/fmt prefix=fmt %>
<html>
<c:if test=${! empty param[locale]}>
<fmt:setLocale value=${param[locale]}/>
</c:if>
<body>
<h1><fmt:message key=tituloJSP/></h1>
<big>
<fmt:message key=textoData/>
<jsp:useBean id=hoje class=java.util.Date/>
<fmt:formatDate value=${hoje} dateStyle=long/>
<p>
<hr>
<fmt:message key=textoLocalidade/>
<%= request.getLocale().getDisplayName() %>
[ <a href=?locale=pt_BR>pt_BR</a> | <a href=?locale=en>en</a> ]
</big>
</body>
</html>

obter a string correta para a propriedade


text na instanciao do componente, utilizando para isso um ResourceBundle.
Ento o cdigo que i n icializa um
componente Swing poderia utilizar
seu atributo locale para instanciar um
PropertyResourceBundle e da inicializar
propriedades como Window.title e Label.text.
Caso o usurio deseje mudar o idioma da
aplicao, basta modificar a localidade
padro da classe JComponent e ento reinstanciar todos os componentes visuais.
Esta a abordagem utilizada pelo exemplo
da Listagem 8.
Esse um exemplo minimalista de
aplicao Swing internacionalizvel
(veja-a em funcionamento na Figura 1).
H poucos componentes: dois JLabels, um
JFormattedTextField, pr-inicalizado para a
data corrente, e um JComboBox que permite
modificar a localidade da aplicao e ver
imediatamente o resultado. Esto inclusos
tambm arquivos de propriedades para
portugus e ingls, mas convidamos o
leitor a experimentar incluindo outros
arquivos, por exemplo para espanhol.
Uma possvel surpresa para o desenvolvedor que no basta modificar
a propriedade esttica defaultLocale de
JComponent. Afinal, as classes do Java SE
externas ao Swing no tm a menor idia
do que seja localidade configurada para
um dado componente Swing. Infelizmente
alguns componentes Swing, por exemplo
JFormatedTextField falham em repassar sua
prpria localidade para outras classes utilizadas internamente (no caso DateFormat,
utilizada para formatar a data exibida pelo
componente).
Por isto necessrio manter em sincronia
as localidades default configuradas para
JComponent e para a JVM. Alguns IDEs
(e desenvolvedores) Swing optam por
ignorar completamente a localidade do
componente, utilizando apenas a localidade da JVM.

Modificaes sobre o descritor web.xml necessrios para o funcionamento correto da pgina JSP
<?xml version=1.0 encoding=UTF-8?>
<web-app xmlns=...>
<context-param>
<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
<param-value>localidades/mensagens</param-value>
</context-param>
<!-- omitido o mapeamento do servlet para /dataDeHoje -->
</web-app>

16 Java Magazine Edio 51

Testando o exemplo Swing


O exemplo Swing traz um buildfile do
Ant com os alvos limpar, compilar, empacotar
e rodar. Tambm inclui o alvo tudo, que
executa os outros quatro alvos na ordem
apresentada. Este buildfile demonstra
como os arquivos de propriedades uti-

lizados por um ResourceBundle podem ser


convenientemente empacotados dentro
do JAR de uma aplicao.

Localizando aplicaes web


Aplicaes web representam um problema
um pouco diferente do enfrentado nas aplicaes desktop. Enquanto que uma aplicao
desktop em geral tem uma JVM inteiramente dedicada a um nico usurio, aplicaes
web tm, claro, que atender a vrios
usurios simultaneamente com a mesma
JVM e cada usurio pode preferir operar
a aplicao em um idioma diferente.
O protocolo HTTP ajuda a resolver a
questo com o cabealho Accept-Language,
que especifica um ou mais identificadores
de localidades, na ordem de preferncia do
usurio. No Firefox, os valores enviados
por este cabealho so configurados na
aba Avanado da janela de preferncias,
clicando-se no boto Selecionar, dentro do
grupo Idioma.
A classe javax.servlet.ServletRequest expe o
cabealho HTTP Accept-Language, j traduzido para objetos java.util.Locale, atravs dos
mtodos getLocale() e getLocales(). Ento fica
fcil para um servlet ou pgina JSP selecionar mensagens em um ResourceBundle,
ou instanciar formatadores com a configurao correta, conforme o exemplo da
Listagem 9.
A Figura 2 apresenta o aspecto da pgina
gerada pelo servlet. Para ver essa pgina
em um idioma diferente, modifique as
preferncias de idioma do seu navegador
web, ou ento passe na URL parmetros
correspondentes aos cdigos de idioma
e de pas da localidade desejada; por
exemplo:
http://127.0.0.1:8080/localidades/
dataDeHoje?idioma=en&pais=GB

As mesmas APIs (mtodo ServletRequest.


getLocale() e a classe ResourceBundle) so utilizadas por frameworks web como o Struts,
ou bibliotecas de tags como o JSTL, as quais
oferecem suporte internacionalizao. O
exemplo da Listagem 10 apresenta uma
pgina JSP mais ou menos equivalente ao
servlet do exemplo na listagem anterior.
A pgina utiliza os tags do JSTL, e
o nome do arquivo de propriedades
configurado no descritor web.xml da

aplicao, como um parmetro de contexto (<context-param>).


). So utilizados os
mesmos arquivos de propriedades pelo
serlvet e pela pgina JSP. A diferena
que, enquanto que o cdigo do servlet
referencia os arquivos explicitamente, os
tags JSTL na JSP utilizam o arquivo configurado no descritor web.xml. Tambm
seria possvel utilizar o tag <fmt:bundle>
do JSTL para indicar explicitamente o
nome o arquivo de propriedades, dentro
da prpria pgina.
Os tags com prefixo fmt:format so equivalentes ao uso das classes com nomes parecidos no pacote java.text, ento
<fmt:formatDate> baseado em DateFormat, e
<fmt:message> baseado em MessageFormat.
MessageFormat
Portanto possvel aplicar aqui as mesmas
tcnicas vistas no incio do artigo, como o
uso de mscaras {choice} e parmetros posicionais, que so indicados na pgina JSP
pelo tag <fmt:param>. J o tag <fmt:setLocale>
permite configurar outra localidade (diferente da indicada pela requisio HTTP),
para uso pelos tags do JSTL dentro da
mesma pgina.

Testando o exemplo web


O exemplo web traz um buildfile do Ant
semelhante ao utilizado para o exemplo
Swing. Os alvos tudo, limpar, compilar e
empacotar so mais ou menos equivalentes
em ambos os exemplos, mas o exemplo web substitui o alvo rodar pelo alvo
instalar. O novo alvo faz o deployment da
aplicao em um Tomcat 5.x ou 6.x, cujo
caminho de instalao deve ser modificado dentro do prprio buildfile. Ento
o usurio pode acessar a aplicao pela
URL http://127.0.0.1:8080/localidades e ento seguir os links na pgina inicial para
executar o servlet ou a pgina JSP.

especficos da interao entre as APIs


Swing e de servlets e o JSTL, com os recursos de internacionalizao do Java SE.
Dominando essas tcnicas e APIs, o leitor
estar preparado para construir aplicaes
internacionalizveis com o mnimo de esforo e o mximo de flexibilidade.

java.sun.com/javase/technologies/core/
basic/intl/
Guia de internacionalizao do Java SE
java.sun.com/developer/
technicalArticles/Intl/MultilingualJSP/index.
html
Descreve estratgias para a construo de pginas
JSP internacionalizadas
jakarta.apache.org/taglibs
Implementao do JSTL e outros taglibs da
Apache Software Foundation
www.loc.gov/standards/iso639-2/
Cdigos de idiomas no padro ISO
www.iso.org/iso/country_codes.htm
Cdigos de pases no padro ISO

Concluses
Este artigo apresentou as APIs essenciais
do Java para lidar com aplicaes internacionalizveis, em especial a classe java.util.
Locale e o pacote java.text. Vimos tambm
dicas para sua utilizao em aplicaes
reais, por exemplo evitar a localizao de
mensagens de excees Java.
Em seguida foram apresentados exemplos da aplicao destas APIs em aplicaes desktop e web, assim como detalhes

Fernando Lozano
(lozano@javamagazine.com.br,
www.lozano.eti.br) trabalha h
mais de 10 anos com desenvolvimento de sistemas de informaes e
integrao de redes, sendo um dos pioneiros do uso do
Software Livre no Brasil. Dentro da comunidade, atua
como Conselheiro do LPI Brasil, Webmaster da FSF e
Community Manager do Java.net. Atualmente consultor associado Neki Technologies (www.neki.com.br).

Edio 51 Java Magazine

17

Web Tools Platform 2.0


Desenvolvendo aplicaes web e Java EE com

a Edio 47 apresentamos a nova


verso 3.3 do Eclipse, tambm
mencionando vrios outros projetos da Eclipse Software Foundation (ESF)
que fizeram parte do release Europa (O
Europa foi discutido tambm na edio)
. Embora o IDE bsico do Eclipse contenha as ferramentas mais essenciais para
qualquer projeto (editor, compilador etc.)
a crescente riqueza da plataforma Java
torna importante o uso de ferramentas
mais especializadas. Isso especialmente
verdadeiro para projetos Java EE, os quais
demandam muitas atividades alm de
programao pura: editar pginas web
estticas e dinmicas, trabalhar com XML,
mapear objetos para tabelas, configurar

descritores de deployment, fazer testes


em servidores de aplicaes, e assim por
diante. Por isso, o complemento mais fundamental de qualquer IDE Java o suporte
a Java EE. Neste artigo, apresentaremos o
WTP 2.0, o componente fundamental de
suporte a Java EE para o Eclipse 3.3.
Note que este artigo no pretende ensinar
tcnicas ou APIs do Java EE, nem as especificidades de servidores Java EE. So assuntos j
cobertos com freqncia em vrios artigos da
Java Magazine. Vamos focar no ferramental do
WTP e no uso prtico das APIs e do servidor.
O leitor que j tem alguma familiaridade conceitual com Java EE (mas no necessariamente
experincia) ser capaz de acompanhar este
artigo sem problemas.

Ambiente e instalao
Alguns IDEs j trazem funcionalidades
Java EE no produto bsico, e o Eclipse
costumava ser criticado por no ser assim.
Mas isso apenas um efeito da estrutura
extremamente modular dos projetos da Fundao Eclipse. O verdadeiro problema que
a ESF, tradicionalmente, no disponibilizava
distribuies orientadas ao usurio final.
Isso comeou a melhorar com o Eclipse 3.2
(Callisto), cujo Update Manager permite comear com uma instalao bsica, selecionar
componentes que sabemos que precisamos,
e clicar em Select Required para marcar todos
os subcomponentes e dependncias.
Com o Eclipse 3.3 e o Europa, temos uma
nova facilidade: a Fundao Eclipse criou
uma srie de pacotes padronizados, para
os conjuntos de funcionalidades mais
populares (essas distribuies so detalhadas no artigo de Fernando Lozano, na
Edio 50). No caso de desenvolvimento
Java EE, voc s precisa ir em eclipse.org/
downloads e escolher a opo Eclipse IDE
for Java EE Developers. Isso o conduzir a
um download nico de 125Mb. Ao leitor
que ainda no tem familiaridade com o
Eclipse ou com o WTP, recomendamos este
download para acompanhar o presente
artigo. Existem tambm (como j existiam
antes) vrias distribuies de terceiros,
mas no h dvida que as distribuies
oficiais da ESF contribuiro para melhorar
a reputao do Eclipse quanto facilidade
de instalao.

Escolhendo um servidor Java EE


Precisaremos tambm de um servidor
Java EE para exercitar o WTP. O primeiro exemplo s utiliza tecnologias web e
poder rodar em containers web como o
Tomcat. J o segundo utiliza EJB, exigindo
portanto um container Java EE completo,
como JBoss, GlassFish etc.
Uma vez instalado o servidor de sua

Domine a nova verso do


projeto da Fundao Eclipse
para desenvolvimento de
aplicaes corporativas em
Java, e crie exemplos para
web e Java EE 5

o Eclipse

oSvaLdo PinaLi doederLein


preferncia, voc deve configurar o
Eclipse para utiliz-lo. Para fazer isso, v
em Window|Preferences>Server>Installed
Runtimes (Figura 1) e escolha o tipo e a
verso de servidor que voc quer usar. Este
artigo utilizar novos recursos do Java EE
5, portanto, preciso escolher um servidor
recente que tenha este suporte. Escolhi o
Glassfish por ser um produto open source e
certificado Java EE 5. (Veja o quadro Servidores suportados pelo WTP, especialmente se o seu servidor favorito no aparecer
inicialmente na lista dos suportados, o que
o caso do Glassfish.)
Minha experincia com WTP e Glassfish foi excelente, para minha surpresa, pois o adaptador do
Glassfish para WTP bem recente (usei a v1.0.1) e a
IBM (a principal fora por trs dos principais projetos
da ESF incluindo o WTP) e Sun (Glassfish) no so
l grandes parceiros quando se trata de IDEs. S
uma pena observar que o adaptador do Glassfish
no poder ser includo nos downloads do WTP ou
nas distribuies de IDE da ESF, pois este adaptador
usa a licena CDDL da Sun; por isso provvel que
ser sempre necessrio instal-lo parte (a no ser
que a licena seja alterada, claro).

Facets (facetas). importante


entender este conceito do WTP.
Um projeto contm uma coleo
de facets, que podem ser descritas como suporte para alguma tecnologia especfica. Por
exemplo, JavaServer Faces
um facet, sendo que existem
duas verses dela, para JSF 1.1
e 1.2. Ao selecionar um facet
num projeto, o WTP automatiza
tarefas como a configurao do
classpath do projeto, a gerao de
artefatos de deployment (como
os arquivos web.xml e faces-config.
xml) e o funcionamento de etapas
especiais de edio, compilao,
validao e deployment. Por
exemplo, o WTP saber editar
o faces-config.xml com um editor
visual customizado para os
recursos do JSF 1.2.
A Tabela 1 detalha os facets

Figura 1. Configurao do Server Runtime para o servidor Java EE utilizado.

Criando um projeto web


Nosso primeiro exerccio com o WTP ser
criar uma aplicao web; simples, porm
moderna, usando a JavaServer Faces (JSF).
Mesmo que voc j tenha familiaridade
com aplicaes web, JSF e verses anteriores do WTP, o exemplo ser til para
investigar caractersticas do WTP.
Acione New|Project>Web>D ynamic
Web Project e na primeira pgina do assistente, faa Project name=TesteWeb,
Target runtime=<seu runtime Java> e
Configurations=JavaServer Faces 1.2 Project. Na
pgina seguinte, voc poder ver (e se quiser,
modificar) as configuraes do projeto.
A Figura 2 mostra esta pgina. Note
que o WTP chama essas configuraes de

Figura 2. Detalhamento dos facets de um projeto do WTP.

Edio 51 Java Magazine

19

Web Tools Platform 2.0

que so suportados pelo WTP 2.0, incluindo as verses suportadas de cada


um, correspondendo s verses das APIs
ou especificaes correspondentes. (Por
exemplo, Dynamic Web Module 2.5
significa aplicao web utilizando Servlet
2.5 (JSR-154 MR2), JSP 2.1 (JSR-245) e JSTL
1.2 (JSR-52 MR2).
Ao combinar facets, voc deve respeitar
as dependncias e compatibilidade entre
elas: por exemplo, o JSF1.2 exige Dynamic Web Module 2.5 ou superior. No se
preocupe com isso, pois se fizer selees
erradas, estas sero detectadas e proibidas
pela pgina de configurao de facets.
Note tambm que as verses indicadas geralmente significam igual ou maior que.
Por exemplo, no h uma facet Java 6.0,

mas voc pode usar a facet Java 5.0 com


um runtime Java SE 6, sem problemas.
No assistente de criao de projetos, a
seleo de facets j ter efeitos visveis: a
ltima pgina a JSF Capabilities (Figura3),
que permite configurar de forma ainda mais
refinada as opes especficas a esta facet
do projeto. A opo mais importante nesta
pgina JSF Libraries: escolha Server supported JSF Implementation. Isso porque vamos
usar um servidor Java EE 5, que j possui o
runtime JSF 1.2 integrado. Assim voc evita
inchar o WAR do projeto com os JARs da JSF,
algo que s seria necessrio para um projeto
destinado a servidores J2EE 1.4.
Para mais detalhes sobre as configuraes de projetos do WTP, que tambm podem ser modificadas aps a criao inicial

Servidores suportados pelo WTP

WTP 2.0 suporta, de fbrica, uma boa


seleo de servidores (de J2EE 1.3 a Java EE
5). So eles Tomcat, JBoss, WebSphere, JOnAS
e Oracle OC4J. Mas caso o seu servidor favorito
no conste da lista dos suportados pelo WTP,
no se preocupe. No dilogo Installed Runtimes,
acione o comando Download additional server
adapters. Quando executei este procedimento, o

Eclipse detectou novos adaptadores para Apache


Geronimo, BEA WebLogic, GlassFish (incluindo o
Sun Java System Application Server) e Pramati, e
IBM WebSphere Community Edition (que uma
variante do Geronimo). Quando voc estiver
lendo este artigo, possvel que outros estejam
disponveis. Mas os listados j cobrem todos os
principais produtos open source e comerciais.

do projeto, veja o quadro Configuraes


de projetos do WTP.

Deploy e execuo
Criado o projeto, faremos um teste mnimo de deployment. Primeiro, no diretrio
WebContent, use New>Other>Web>JSP para
criar um arquivo index.jsp contendo uma
mensagem qualquer (Al, mundo! no
seria m idia). Agora selecione a view
Servers que dever estar disponvel, pois
normalmente o WTP ativa a perspectiva
Java EE ao criar um projeto. Comande
New>Server, selecione o tipo de servidor
utilizado (ex.: Glassfish / Glassfish v2 Java
EE 5), passe pela prxima pgina aceitando
os defaults (a no ser que voc tenha instalado o servidor com valores no-default
para configuraes como porta HTTP e
login de administrador), e observe a ltima pgina do assistente (Figura4), que
permite selecionar projetos para deploy
neste servidor. Basta ento adicionar o
seu projeto ao painel direito (Configured
projects) e finalizar. (Se alguma coisa pareceu confusa ou repetida, veja o quadro
Runtimes e Servers no WTP.)
Com tudo configurado, vamos executar
o servidor de aplicaes, com uma das opes Start ou Debug sobre a sua definio na
view Servers. Aps a inicializao, abra um
browser com a URL http://localhost:8080/
TesteWeb. Aquela mensagem que voc definiu na index.jsp dever aparecer.

Um micro-tutorial
Para colocar o WTP em prtica, vamos
construir uma aplicao JavaServer Faces
mnima. O primeiro passo ser criar o
esqueleto das pginas a usar:
Recrie a pgina index.jsp, vazia (isto ,
s com o cdigo do template html).
Crie mais uma pgina, ok.jsp, contendo
apenas uma mensagem Login efetuado
com sucesso.
Crie outra pgina erro.jsp, com a mensagem Login incorreto.

Figura3. Configurao do facet JSF do projeto.

20 Java Magazine Edio 51

Agora, abra o arquivo WebContent/WEBINF/faces-config.xml. Ser apresentado um


editor com diversas pginas; v pgina
ManagedBean, onde podemos definir os
managed beans (classes Java que interagem com as pginas JSF). Selecione o

escopo request e clique no boto Add.


No assistente que aparece, selecione Create a new Java class, e na pgina seguinte faa
Package=teste e Name=Login. Crie o managed
bean aceitando os defaults para as demais
opes. O resultado dever parecer com a
Figura5, e voc dever ter uma nova classe
teste.Login no projeto.
Edite a classe gerada para conter o cdigo
da Listagem1. Como voc pode ver, no
estamos implementando uma tecnologia
de autenticao muito sofisticada o
mtodo loginUser() s compara o nome do
usurio com um valor fixo, retornando true
para sucesso ou false para falha de login.
O nome do usurio uma propriedade do
managed bean, que, como veremos, ser
alterada pela pgina.

Listagem1. Managed bean para o login.


package teste;
public class Login {
private String nome;
public Login () {}
public boolean loginUser () {
return Osvaldo.equalsIgnoreCase(nome);
}
public String getNome () {
return nome;
}
public void setNome (String nome) {
this.nome = nome;
}
}

Edio da pgina JSF


Agora edite a pgina login.jsp para ficar
parecida com a Figura6. Mas no vamos
digitar tags; faremos tudo visualmente.
Ao criar as JSPs, voc pode j t-las aberto
no editor, e provavelmente o IDE abriu um
editor tradicional. Trata-se de um excelente
editor com destaque sinttico, auto-completamento e outras facilidades, mas ainda
assim, um editor de texto. Mesmo com o
WTP instalado, a extenso .jsp associada
ao JSP Editor tradicional (disponvel desde
as primeiras verses do WTP).
Mas existe um editor mais poderoso,
orientado composio visual de pginas
JSP, HTML e variantes, como JSP com tags
JSF, fragmentos etc. Para us-lo, abra as
pginas com Open With>Web Page Editor.
Outra opo, se voc quiser sempre usar
este editor, ir em Window|Preferences>
General>Editors>File Associations e marcar o

Figura4. Instalando projetos em um server.

Runtimes e Servers no WTP

o configurar o Eclipse para suportar seu


servidor de aplicaes e depois configurar
o projeto para deploy e execuo neste servidor, voc pode ter achado redundantes as
configuraes da pgina Installed Runtimes e
da view Servers, at porque algumas opes
so comuns a ambas. Isso s vezes confunde
iniciantes no WTP, mas tem suas razes.
Um Installed Runtime uma configurao que

s informa ao WTP quais servidores existem no


sistema, como executar cada um (diretrio, JVM
utilizada etc.), e fornece valores default para opes como portas e login. A partir de cada runtime
conhecido, o WTP permite criar vrias configuraes de servidor, ou simplesmente servers.
Um server um conjunto de arquivos de
configurao e diretrios de trabalho (para
deploy, logs e outras finalidades as opes

exatas variam com o servidor). O WTP mantm


estes arquivos dentro do workspace, em <workspace>/.metadata/.plugins/org.wtp.server.core.
Podemos ter vrios servidores para um mesmo
tipo de runtime, o que importante, por exemplo, para desenvolvedores com workspaces
complexos contendo diversos projetos, e que
no querem fazer deploy de todos os projetos
no mesmo servidor.

Edio 51 Java Magazine

21

Web Tools Platform 2.0

Web Page Editor como Default para *.jsp.


O editor visual bastante fcil de usar.
Inicialmente a pgina exibida apenas
com a estrutura criada pelo template: a
diretiva page, as tags html, head, meta, title
e body. No painel superior (visual), o body
ter uma mensagem Drag and drop Web
content here; ento vamos fazer isso. O
WTP apresenta uma extensa Palette com
componentes para todas as tags de HTML,
JSP, JSTL e JSF (ou seja, a totalidade do que
padronizado pelo Java EE 5). Os passos
so os seguintes:
1. Abra o grupo JSF Core, selecione o

componente view e clique dentro do body.


Ser criada uma tag <f:view> vazia. Este o
componente-container principal da JSF.
2. Agora abra o grupo JSF HTML. Dentro
do view, crie um Form. Na view Properties
do WTP, preencha ID = login.
3. Dentro do Form, digite o texto Nome:.
4. Aps inserir esse texto, crie um Text
Input. Preencha sua propriedade Value
com #{login.nome}. Esta expresso associa
o valor do controle de entrada de texto (o
componente <h:inputText> da JSF) com a
propriedade nome do managed bean login.
5. Aps o Text Input, crie um Command

Button. Preencha ID=login, Value=Login


e principalmente, Action=#{login.loginUser}.
Com isso, ao acionarmos este boto do
form, o mtodo loginUser() do mesmo managed bean login ser executado.
Pronto, nossa pgina est completa! Voc
pode aproveitar para explorar tambm outras facilidades deste editor. Por exemplo,
a maioria dos componentes HTML possui
uma propriedade Style onde voc pode
digitar o estilo CSS do elemento; mas se
no for expert em CSS, voc pode clicar
o boto Edit e usar a conveniente caixa de

Configuraes de projetos do WTP

o abrir a janela de propriedades de um projeto


do WTP, voc encontrar uma srie de novas
pginas de configuraes. O WTP d continuidade
tradio do IDE Eclipse de expor configuraes
extremamente detalhadas, o que costuma ser visto
tanto como um ponto positivo (flexvel e poderoso,
para usurios experientes) quanto negativo (potencialmente confuso, para iniciantes).
De qualquer maneira, vale a pena analisar
essas configuraes, pois elas tambm expem
alguns recursos importantes do WTP. Algumas
delas refletem opes presentes no assistente
de criao de projetos, mas outras esto disponveis para customizao somente na pgina de
propriedades do projeto j criado. Cada item a
seguir corresponde a uma pgina do dilogo de
propriedades de projeto, obtido com a opo
Properties (Alt+Enter).

Builders
Esta pgina existe em qualquer projeto do
Eclipse, e lista os chamados builders, que so
plug-ins que processam de alguma forma o
projeto quando h alteraes nos seus recursos.
Alm do Java Builder (responsvel por compilar
arquivos .java), um projeto do WTP ser configurado com os builders Faceted Project Validation
Builder e Validation. Ambos so responsveis por
diferentes tipos de validao.
No recomendado alterar essas opes, que
existem principalmente para permitir que builders exigidos por um projeto, mas no instalados,
sejam desativados, evitando assim a ocorrncia
de erros no Eclipse. Isso poderia acontecer, por

22 Java Magazine Edio 51

exemplo, se um projeto feito com o WTP fosse


carregado numa instalao do Eclipse que no
inclui o WTP.

ou <%@include%>. Isso hoje uma tcnica obsoleta, substituda por recursos como tagfiles ou
frameworks de templates.)

J2EE Module Dependencies

Profile Compliance and Validation

Lista outros mdulos dos quais o projeto


depende para deployment. Digamos que um
projeto TesteWeb precisa de classes de outro
projeto, TesteLib. Ao invs de inserir TesteLib no
classpath (via Java Build Path>Projects), voc deve
usar a pgina de dependncias de TesteWeb,
marcando o projeto TesteLib como dependente.
Assim, quando gerar o WAR para deployment, o
WTP automaticamente criar um arquivo WEBINF/lib/TesteLib.jar com o contedo do projeto
dependente.
Para mdulos EJB e WAR, esta pgina o editor
do arquivo META-INF/MANIFEST.MF; ser usada
principalmente para configurar dependncias
de bibliotecas externas, ou mdulos EJB Client
(contendo stubs para invocao entre EJBs de
diferentes mdulos).
Observe que no ttulo desta pgina do dilogo de configuraes, bem como em outros
lugares, aparece a sigla J2EE, ao invs do mais
moderno Java EE. Mas o WTP suporta vrias
verses da edio Enterprise do Java do J2EE
1.2 ao Java EE 5.

Para projetos que utilizam funcionalidades de


web services, esta pgina determina a compatibilidade com os padres WS-I SSBP (Simple SOAP
Binding Profile) e WS-I AP (Attachments Profile).

JSP Fragment
Permite especificar opes default (linguagem e
content type) para fragmentos de JSP. (Os framentos so arquivos .jspf, normalmente criados para
incorporao em outras JSPs via <jsp:include>

Project Facets
Permite configurar os facets do projeto (mais
detalhes podem ser vistos no corpo do artigo).

Server
Possibilita a seleo de um servidor (container
Java EE) para executar o projeto. Isso importante
se o projeto tiver deploy configurado para mais
de um server e afeta o comportamento de opes
como Run As>Run on Server.

Targeted Runtimes
Seleciona os runtimes para os quais o projeto
ser compilado. Os JARs desses runtimes sero
automaticamente includos no classpath do projeto. Assim, no caso de um projeto configurado
para um runtime JBoss AS 5, por exemplo, todas
as APIs do Java EE 5 estaro disponveis e tambm muitas APIs proprietrias do JBoss sem a
necessidade de incluir os JARs desse servidor
manualmente no classpath do projeto.

Validation
Aqui vemos um ponto forte do WTP (veja a

dilogo CSS Style Definition.


Observe tambm a rica funcionalidade
do editor textual de JSPs, que torna a edio
neste modo at mais produtiva que com o
uso de assistentes ou pginas de propriedades, para quem j conhece bem HTML,
JSP, JSTL e JSF. Por exemplo, ao comear a
editar o trecho value = #{', acionando o autocompletamento com CTRL+Space voc ver
que o managed bean login uma das opes
oferecidas. Completando aps 'value = #{login.',
somente as propriedades deste bean (como
nome) sero oferecidas, pois o editor sensvel ao contexto e sabe que a propriedade value

FiguraQ1). Existem plug-ins de validao para


praticamente todos os tipos de arquivos que
podem fazer parte de um projeto web: HTML,
JSP, XML (inclusive schemas e DTDs), e outros.
Alguns tipos de arquivos mais complexos suportam diversos validadores: por exemplo, para
JSP, temos o JSP Syntax Validator que valida as

do componente <h:inputText> da JSF requer


uma propriedade. Mas aps 'action=#{login.',
o auto-completamento oferece os mtodos
do bean, pois a action do <h:commandButton>
exige um mtodo.
Um dos melhores recursos do suporte a
desenvolvimento web do WTP que suas
ferramentas visuais so baseadas unicamente nos padres Java EE 5. H IDEs que
apresentam editores visuais mais sofisticados, mas com sacrifcio dos padres.
Por exemplo, o editor visual de pginas
do NetBeans 6.0 (antigo Visual Web Pack)
contm um editor de pginas superior ao

diretivas e tags da JSP (inclusive de taglibs), o


JSP Content Validator que valida os elementos
HTML da pgina, e o JSP Semantics Validator
(JSF) que valida as tags da JavaServer Faces e
de expresses EL.
Voc pode configurar essas opes de validao
tanto globalmente (seguindo o link Configure

do WTP, mas impe o uso de uma biblioteca de tags proprietria chamada webui.
que a JSF ainda no suficientemente
poderosa para habilitar editores visuais
mais sofisticados. Isso dever melhorar em
verses futuras da JSF, mas com o padro
atual, creio que o WTP 2.0 faz um excelente
trabalho. Pessoalmente, prefiro ter a opo
de gerar uma aplicao puro-Java EE, do
que ter um editor visual melhor, mas ser
obrigado a usar alguma API/framework/
biblioteca que no certificada, integrada
e suportada por todos os fornecedores de
servidores de aplicaes.

Workspace Settings), ou de forma local para cada


projeto. Pode tambm ativar determinados validadores para executar automaticamente aps
alteraes dos arquivos, ou s manualmente (ao
acionar o comando Validate no menu do projeto).
Para usurios com projetos de grande porte e
mquinas modestas, o tempo de execuo de
todos esses validadores pode ser relativamente
longo (especialmente aps operaes que alteram
muitos arquivos, como refatoraes); em tais casos,
pode ser boa idia desativar a execuo automtica, e deixar ligada apenas a manual.

Web Content Settings


Usado apenas para proejtos web. Opes default
para o tipo de arquivos HTML e CSS.

Web Project Settings


Usado apenas para projetos web. Seleciona a
raiz do contexto web, que por default igual ao
nome do projeto.

XDoclet

FiguraQ1. Configuraes de projeto Web do WTP, destacando as opes de validao.

Usado somente para projetos EJB com a facet


EJB Project (XDoclet). Permite definir opes para
o XDoclet, uma ferramenta para desenvolvimento
de aplicaes Java EE (entre outros tipos) atravs
de anotaes em cdigo primitivas, usando tags
especiais em comentrios.
A XDoclet anterior ao Java SE 5, o qual possui
uma facilidade de anotaes superior, bem explorada pelas APIs do Java EE 5. Assim, esta ferramenta
interessante apenas para projetos que precisem
executar em servidores J2EE 1.4 ou inferiores.

Edio 51 Java Magazine

23

Web Tools Platform 2.0

Regras de Navegao

Figura 5. O editor de configurao de JSF, aps criar o managed bean.

S ficou faltando uma coisa para a nossa


aplicao funcionar: o fluxo de navegao
de pginas, ou seja, regras do tipo quando
acontecer tal coisa na pgina X, v para a
pgina Y. Faremos isso tambm de forma
totalmente visual.
No editor de configurao JSF, selecione
a pgina Navigation Rule. Voc ver uma
rea quadriculada vazia. Arraste todas as
trs JSPs do projeto para dentro desta rea.
Na view Palette (onde agora aparecero
os componentes de navegao), selecione
Link. Clique no cone da index.jsp e clique
novamente no cone da ok.jsp; uma seta
ser criada ligando as duas pginas. Faa
o mesmo para conectar a index.jsp com a
erro.jsp.
Selecione a primeira seta (para a ok.jsp) e
edite a propriedade From Outcome = true.
E na seta para a pgina erro.jsp, preencha
From Outcome = false. Estes outcome
referem-se ao valor gerado pelo mtodo da
ao, no caso o mtodo Login.loginUser() que
invocado ao acionarmos o boto do form.
(Existe tambm uma propriedade From
Action, mas no precisamos identificar a
ao, j que s existe uma nica ao no
form da index.jsp.)
s isso. Voc j pode executar a aplicao
no container. Ao preencher o campo de texto
e pressionar o boto Login, como esperado,
voc ser direcionado pgina ok.jsp ou
error.jsp, conforme a validao do valor
digitado feita pelo mtodo loginUser().

EJB e JPA

Figura 6. O WTP exibindo sua capacidade de edio visual de pginas.

24 Java Magazine Edio 51

Alm de desenvolvimento web, o WTP


tambm possui suporte bastante completo
para outras tecnologias do Java EE, incluindo
web services. Mas como o tempo e o espao
so finitos, concentraremos o restante deste
artigo no suporte a EJB, em especial EJB 3.0
e JPA (Java Persistence API), uma novidade
muito esperada do WTP 2.0.
O primeiro passo criar um novo projeto.
Dessa vez criaremos uma aplicao Java
EE 5 completa, com direito a projetos EAR,
EJB e Web separados. Acione File|New>Pro
ject>J2EE>Enterprise Application Project. Na
primeira pgina do assistente, faa Project
name=Teste, escolhendo tambm o runtime correto. Na segunda pgina, aquela das
facets, haver uma nica opo: EAR. S

possvel escolher a verso desta facet, que


voc deve deixar em 5.0. Na prxima pgina, selecione o mdulo TesteWeb: vamos
reusar a parte web j construda. Clique
tambm no boto New Module e selecione
apenas EJB Module (que pode ficar com o
nome oferecido, TesteEJB). Finalize o
assistente e voc ter dois novos projetos
Teste e TesteEJB.
O WTP (como a maioria dos IDEs Java EE)
trabalha com uma estrutura de mltiplos
projetos, um para cada artefato: cada WAR
(mdulo web), EJB-JAR (mdulo EJB), EAR
(aplicao Java EE), e RAR (Resource adapter) gerado por um projeto separado.
A nossa aplicao Java EE completa
ser uma melhoria da anterior. Teremos
uma tabela USUARIO contendo os nomes
dos logins permitidos, com os registros
mapeados para o uma entidade Usuario via
JPA, e um session bean LoginServerBean para
fazer o login. O managed bean Login, do
projeto web ser modificado para invocar
o LoginServerBean, ao invs de fazer aquela
comparao com uma string fixa. Ento,
vamos pr mos obra.

Criando a entidade persistente


Vamos comear pela persistncia. Abra
a nova perspectiva JPA. Vamos comear
criando a base de dados, conectando-se a
ela e configurando a base a ser utilizada
pela aplicao. Como banco de dados,
vamos usar o Derby, por este vir includo
no Java SE 6.0 Update 2 ou superior (sob
o nome de JavaDB). Mas voc poder usar
outro banco de dados, bastando, claro,
modificar detalhes como a configurao
do driver e a URL de conexo.
Na view Data Source Explorer, em Databases,
comande New>Derby Embedded Database e
faa Name=Teste. Na pgina de seleo do
driver e detalhes de conexes, para escolher
o driver comece clicando o boto ...; aparecer um dilogo Driver Definitions, selecione
Derby 10.2 e clique em Add. Na rvore de
templates, escolha o Derby Embedded JDBC
Driver. Voc voltar ao dilogo de definies
de driver, que reclama que no localiza o arquivo derby.jar. Use Edit jar/zip para localizar
este arquivo no diretrio lib da instalao do
Derby/JavaDB.
De volta ao dilogo Driver Definitions,
selecione o Derby Embedded JDBC Driver e

confirme com OK. Finalmente voc volta


ao dilogo de criao de bases de dados, na
pgina de detalhes de conexo. Preencha
o caminho para o diretrio que ir conter
a base de dados (Figura 7). Basta ento
finalizar o assistente.

a tabela! Mas ela no aparece automaticamente na rvore de bancos de dados; para


isso voc deve executar um Refresh.
Como preguia pouca bobagem, vamos
inserir dados tambm do jeito mais fcil.
Sobre a tabela USUARIO, comande Data>Edit.
Digite alguns nomes e grave com CTRL+S.

A partir deste ponto, a definio de driver ficar


armazenada no workspace, e no teremos a mesma trabalheira para criar novas bases de dados ou
novas conexes com o mesmo tipo de driver.

No Data Source Explorer, no novo node


Databases|Teste, comande Connect. Em
SAMPLE>Schemas>APP>Tables, acione
New Table e passe pela primeira pgina do
assistente aceitando os defaults. Na segunda pgina, faa Table name = USUARIO, e
adicione uma coluna com Name=nome e
DataType=VARCHAR. Na terceira pgina,
escolha um nome qualquer para a chave
primria (ou aceite o default) e selecione
em Members a coluna nome; finalize.
O resultado no uma tabela e sim um
editor SQL Statement contendo a DDL
para criar essa tabela. Execute este cdigo
(usando Execute All no menu de contexto
do editor, ou Ctrl+Alt+X). Agora sim temos

Figura 7. Configurando uma base de dados Derby.

Figura 8. A perspectiva JPA.

Edio 51 Java Magazine

25

Web Tools Platform 2.0

Pronto. Na view SQL Results voc poder


visualizar os INSERTs gerados e executados.
Estes recursos para trabalho com SQL e bases de
dados no so algo especfico do WTP; so recursos
do plug-in DTP (Data Tools Platform), que faz parte
da distribuio Eclipse IDE for Java EE Developers e tambm pode ser instalado parte numa
configurao do Eclipse sem o WTP. O DTP usado
por outros plug-ins que trabalham com bancos
de dados, como o gerador de relatrios BIRT. Ele
tambm pode ser utilizado como um cliente SQL
conveniente, integrado ao Eclipse.

A prxima etapa configurar o suporte


JPA no nosso projeto EJB. Na pgina
de propriedades do projeto TesteEJB, em
Project Facets, acione Modify Project e ative
a faceta Java Persistence 1.0. No menu do
projeto, acione JPA Tools>Generate Entities.
Escolha a conexo Teste e o schema APP
(que s aparecer automaticamente se
esta conexo estiver aberta no Data Source

Explorer). Na pgina seguinte, preencha


Package=entidades e selecione a tabela
USUARIO, finalizando o assistente.
O resultado ser uma nova classe
entidades.Usuario, que aparece na Figura8,
onde tambm ilustramos diversas funcionalidades para JPA do WTP. O suporte
a mapeamento vai bem alm desse assistente que acabamos de utilizar. Se voc
tiver uma entidade selecionada, esta ser
detalhada na view JPA Structure. E selecionando algum elemento desta, a view
auxiliar JPA Details permitir editar toda
espcie de opes de mapeamento.
Para programadores j experientes em
JPA, poder ser mais fcil simplesmente
digitar suas anotaes no cdigo. Mas
no h dvida que este suporte do WTP
um grande auxlio, no s para atividades
bsicas, mas tambm para o uso de opes
de mapeamento menos comuns ou ainda
para gerar um mapeamento inicial a partir
de uma base de dados.

Listagem2. Cdigo para o session bean de login quente, consultando a base de dados.
LoginServer.java
package session;
import javax.ejb.Local;
@Local
public interface LoginServer {
boolean loginUser (String nome);
}

LoginServerBean.java
package session;
import
import
import
import

javax.ejb.Stateless;
javax.persistence.EntityManager;
javax.persistence.PersistenceContext;
entidades.Usuario;

@Stateless
public class LoginServerBean implements Login {
@PersistenceContext private EntityManager em;
public boolean loginUser (String nome) {
return em.find(Usuario.class, nome) != null;
}
}

Listagem3. Conmfigurando o datasource para a unidade de persistncia JPA.


<?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
xsi:schemaLocation=http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd>
<persistence-unit name=TesteEJB>
<jta-data-source>java:/Teste</jta-data-source>
</persistence-unit>
</persistence>

26 Java Magazine Edio 51

Criando o session bean


Para criar um session bean, o WTP no
disponibiliza nenhum assistente especfico. Assim, vamos fazer isso moda
antiga, escrevendo cdigo (felizmente,
com EJB 3.0 isso j no pode ser considerado difcil ou trabalhoso). Crie o session
bean LoginServerBean, e sua interface local
LoginServer, conforme a Listagem2.
Graas JPA, a implementao do novo
mtodo loginUser() to curta quanto a
implementao mock j mostrada na
Listagem1: s precisamos fazer um find()
do usurio que tem chave primria igual
ao nome recebido. Se este usurio for
encontrado, retornamos true indicando
sucesso no login.
O projeto EJB est completo; agora s
falta invocar o LoginServerBean a partir do
mdulo Web. Antes de fazer isso, voc
ter que abrir as propriedades do projeto
TesteWeb e em J2EE Module Dependencies,
selecionar o mdulo TesteEJB.jar. Isso ter
o efeito de incluir uma referncia para o
JAR no WebContent/WEB-INF/MANIFEST.
MF deste projeto, alm de permitir a
importao e uso das classes do projeto
TesteEJB no TesteWeb.
O leitor j versado em Java EE 5 saber que
esta configurao do MANIFEST.MF no
mais necessria: como tanto o TesteEJB.jar
quanto o TesteWeb.war sero includos num
mesmo mdulo, Teste.ear, as classes do mdulo EJB ficaro visveis automaticamente
pelo mdulo Web. Isso faz parte das melhorias de facilidade de deployment do Java
EE 5, exigindo menos descritores. Porm,
a configurao do MANIFEST.MF uma
forma de fazer o Eclipse incluir as classes
de um projeto no classpath do outro.
No a nica forma: voc poderia ir em
Java Build Path>Projects e adicionar uma
referncia para o projeto TesteEJB. Funciona do mesmo jeito. S que prefiro manter
as dependncias entre projetos atravs do
MANIFEST.MF, que um arquivo padro
do Java EE, ao invs de usar os arquivos
de metadados proprietrios do Eclipse.
Isso pode facilitar as coisas, por exemplo
se um dia o projeto tiver que ser migrado
para outro IDE, ou caso seus fontes tenham
que ser processados por ferramentas no
amarradas a nenhum IDE.
Agora, para que tudo funcione, s

precisamos configurar o datasource. Primeiro, abra o arquivo TesteEJB/ejbModule/


META-INF/persistence-unit.xml e edite-o,
acrescentando o elemento <jta-data-source>,
conforme a Listagem3.
Depois, crie um datasource com o nome
JNDI jdbc/Teste, apontando para a base
de dados que criamos. Esta configurao
especfica para cada servidor de aplicaes. Algumas notas:
Para o Glassfish, isso pode ser feito pelo seu Admin Console (normalmente acessado em localhost:4848). Em
Resources>JDBC>Connection Pools, crie
um pool com Name=Teste, Datasource
Classname=org.apache.derby.jdbc.EmbeddedDataSource e, na pgina Additional Properties, somente a propriedade
DatabaseName=<caminho da base de dados>. Depois, em Resources>JDBC>JDBC
Resource, crie um novo resource com JNDI
Name=jdbc/Teste e Pool Name=Teste.
A distribuio do Glassfish j incorpora o JavaDB. Em outros servidores que
no faam isso, alm de criar o datasource ser preciso configurar o servidor
para carregar o derby.jar. Por exemplo,
no JBoss (pressupondo a configurao
default), basta copiar o derby.jar para
<jboss>/server/default/lib.
Um cuidado especfico ao Derby em
modo embutido (uma escolha que fiz para
evitar a complicao de ter que rodar o
servidor de BD como um processo parte):
voc deve fechar a conexo do Data Source
Explorer quando estiver executando o
container, caso contrrio ocorrer um erro,
pois apenas um processo pode executar
o servidor Derby carregando uma determinada base de dados. Esta limitao no
existir para um servidor convencional,
multiusurio (isso inclui o Derby no modo
NetworkServer).

Pronto, temos uma aplicao Java EE 5


completa com EJB, persistncia e uma
GUI web feita com JSF. Tudo programado
em minutos!

Concluses
O Eclipse, mesmo com as primeiras
verses do WTP, j foi o patinho feio dos
IDEs para J2EE/Java EE; mas isso mudou.
Com o Eclipse 3.3 e o WTP 2.0, temos finalmente suporte abrangente e poderoso

para as necessidades mais importantes em


aplicaes enterprise ou server side.
O WTP est atualizado com as ltimas
especificaes, no caso a Java EE 5; e possui
diversas ferramentas de alta produtividade assistentes para de gerao de cdigo
ou automao de tarefas corriqueiras e editores visuais para tarefas crticas como
edio de pginas ou mapeamento O/R.
Existem ainda algumas lacunas em comparao com outros IDEs. Por exemplo,

Na view Servers, remova do server o


projeto TesteWeb, e adicione o novo projeto
Teste. (Voc ver que os projetos TesteEJB
e TesteWeb aparecero como dependentes
de Teste.) Agora s executar o container e
testar novamente a aplicao (mesma URL
do exemplo anterior). Verifique se o login
permitido para todos os usurios cujos
nomes esto cadastrados na tabela USUARIO,
e nenhum outro.
Edio 51 Java Magazine

27

Web Tools Platform 2.0

v i mos que no h
recursos como assistentes para criao de
session beans (o que at
o J2EE 1.4, exige a criao
de diversos fontes e a alterao de um descritor). Se por
um lado o EJB 3.0 torna esse tipo de
coisa muito menos essencial que antes,
bom lembrar que o Java EE 5 ainda uma
plataforma relativamente recente.
Mas se formos pensar nisso, h lacunas
maiores, e no s no WTP: em especial
a ausncia total de suporte para a velha
persistncia EJB/CMP, que tambm no
suportada por outros IDEs open source.
(Exceto via XDoclet, que o prprio WTP
suporta desde verses anteriores, mas que
no nenhuma maravilha de produtividade comparada JPA e s ferramentas que
vimos aqui.) Em resumo, o lema do WTP

pra frente que se anda; um ferramental


mais adequado a projetos que possam usar
a especificao Java EE 5 ou superior.
O leitor que j experimentou outros
IDEs atuais pode tambm achar que
o WTP peca na falta de recursos mais
ava nados e moder nos, como SOA.
Mas o WTP tem a inteno de agregar
somente as funcionalidades do Java
EE. Outras so fornecidas por plug-ins
complementares da Fundao Eclipse,
como os fornecidos pelos projetos SOA
Tools Platform, BPEL, AJAX Toolkit
Framework, entre outros. Estes plug-ins
so extenses do WTP, portanto funcionaro de maneira integrada com os
recursos que j vimos (em geral, beneficiando-se do sistema de facets do WTP).
Mesmo para as funcionalidades suportadas pelo prprio WTP, no tivemos
espao para mostrar tudo. O quadro

Outros tipos de projetos do WTP


cobre algumas lacunas; outra importante o suporte para web services.

eclipse.org/webtools
Projeto WTP.
java.sun.com/javaee
Plataforma Java EE.
jcp.org/en/jsr/detail?id=244
Especificao da plataforma Java EE 5.
Osvaldo Pinali Doederlein
(opinali@gmail.com)
Mestre em Engenharia de
Software Orientado a Objetos,
membro individual do Java Community
Process e trabalha na Visionnaire Informtica como
arquiteto e desenvolvedor.

Outros tipos de projetos do WTP

este artigo s criamos os projetos Web, EJB


e EAR, mas o WTP suporta outros tipos, que
mencionaremos aqui de forma resumida.
O conceito de Application Client uma parte
da especificao J2EE que no pegou. So aplicaes-cliente que so programadas da mesma
forma que outros mdulos J2EE, inclusive gerando
um arquivo EAR. Mas ao invs de ser instalado no
container, um EAR de application client executado de forma independente, s com uma JVM J2SE
(ou quase: com um utilitrio fornecido por cada
servidor no caso do Glassfish, o appclient).
Os application clients no fizeram sucesso porque o programa cliente depende das volumosas
APIs do J2EE, para poder invocar remotamente
funes do container (ex.: lookup de JNDI) e de
aplicaes servidoras que executam no container (tipicamente via interfaces EJB remotas ou
web services). No caso do JBoss 5, por exemplo,
essas bibliotecas de cliente somam absurdos
26 Mb (embora isso possa ser reduzido se o
cliente no precisar de certas funcionalidades,
por exemplo web services).
Somando isso com a exploso de popularidade da tecnologia web, fcil ver por que
praticamente ningum desenvolve application
clients, e porque essa parte da especificao no
recebe melhorias h bastante tempo. No Java EE

28 Java Magazine Edio 51

6 (em desenvolvimento: JSR-316), que ter uma


estrutura mais modular com vrios perfis e a
possibilidade de tornar algumas APIs opcionais
ou mesmo remov-las completamente, minha
expectativa que os application clients encarem
a guilhotina, ou pelo menos sejam declarados
opcionais.
Um Connector Project ir gerar um conector
(com deploy para arquivo RAR). Conectores
so mdulos que funcionam como plug-ins
do servidor de aplicaes, e geralmente tm a
funo de se comunicar com sistemas no-Java
EE, como por exemplo alguma aplicao nativa
que precise ser acessada via JNI ou sockets, ou
mesmo programas Java SE via RMI, CORBA e
outros mecanismos.
Um Utility Project um projeto definvel
por excluso: no possui nem EJBs, nem um
website; no possui nenhum descritor. Mas pode
utilizar APIs do Java EE. Use esse tipo de projeto
para criar bibliotecas, que podem ser includas
como dependncias de projetos EJB ou Web,
sendo ento automaticamente agregadas aos
mdulos de deployment EAR e WAR. Isso lhe
poupa o trabalho de gerar um JAR a partir do seu
projeto utilitrio e copi-lo (a cada atualizao!)
para dentro do /lib de um projeto EJB, ou do
WebContent/WEB-INF/lib do projeto Web.

Um JPA Project um tipo especial de Utility


Project, que ir conter somente entidades
persistentes programadas com a JPA. muito
interessante por dois motivos. Primeiro, em
aplicaes complexas, com dois ou mais grupos
independentes de entidades (onde as entidades
de um grupo no possuem nenhum relacionamento com entidades dos outros grupos),
interessante manter cada grupo de entidades
num subprojeto parte. Tipicamente, cada
grupo corresponder a um esquema de dados
separado, possibilitando tambm a administrao de dados independente. O segundo motivo
que algum outro projeto por exemplo, um
projeto de aplicao Java SE poderia importar
o projeto JPA para tambm fazer acesso direto
mesma base de dados.
Um Static Web Project, como diz o nome, um
projeto web que no contm contedo dinmico,
somente esttico (HTML, CSS, JavaScript, imagens).
Sites com contedo predominantemente esttico
so melhor desenvolvidos em ferramentas especializadas de web design. Mas depois de tal desenvolvimento inicial ser feito, pode ser uma boa
idia importar o site para um projeto do WTP de
forma a facilitar a sua integrao em um EAR que
rene diversos mdulos web, juntando contedos
estticos e dinmicos.

Wireless Update

Explorando o MIDP 2.1


O

MIDP 2.1 foi criado pelo Expert


Group da JSR 118 (MIDP 2.0), para
reduzir a fragmentao existente
no ambiente Java ME. O principal objetivo
da nova verso tornar obrigatrias caractersticas que na verso anterior eram
opcionais devido a limitaes do hardware mas que so totalmente viveis nos
dispositivos mveis atuais. Nesta edio,
vamos discutir as principais mudanas
na verso 2.1 e o que elas significam na
prtica para os desenvolvedores de aplicaes Java ME.

Interface de usurio
As diretivas de layout passam a ser
obrigatrias no MIDP 2.1 (antes, as implementaes dos fabricantes podiam
no incluir essa funcionalidade). Essas
diretivas especificam o posicionamento de componentes Item (por exemplo,
StringItem, TextField e DateField) de forma
alinhada direita, esquerda, centralizada etc. A Listagem 1 mostra uma
MIDlet com trs StringItems, com alinhamentos diferentes, e a Figura 1 apresenta
como fica o resultado desse exemplo no
emulador do Wireless Toolkit da Sun.
Outra alterao relacionada a obrigatoriedade de um StringItem ter a aparncia
de link web, sempre que houver um
Command (javax.microedition.lcdui.Command)
associado a ele. O objetivo aumentar
a navegabilidade. Commands podem ser
adicionados tanto a telas (Form, TextBox,
Canvas) quanto a Items especficos de um
formulrio.
H alteraes importantes tambm
na interao do usurio com o dispositivo. Com o novo release, passa a ser
obrigatrio o suporte a telas sensveis
a canetas apontadoras, quando o dispositivo oferecer esse recurso. Com
isso, os mtodos Canvas.hasPointerEvents() e
Canvas.hasPointerMotionEvents() devem sempre

30 Java Magazine Edio 51

Conhea a mais recente


verso final do MIDP e
o que ela traz de novo
para o mercado

Marlon Luz
retornar valor verdadeiro. Alm disso,
todas as implementaes devem suportar
eventos repetitivos como os de pressionar
e segurar uma tecla do dispositivo. Sendo
assim, o mtodo Canvas.hasRepeatEvents(),
por exemplo, tambm deve retornar valor
verdadeiro.
O suporte a grficos double-buffered 1
tambm deve existir em dispositivos
MIDP 2.1, garantindo assim melhor qua1 A tcnica de double-buffering utilizada para reduzir ou
remover problemas de renderizao na tela, como piscadas,
imagens rasgadas ou sombras. Com ela, so feitas operaes
de escrita em um buffer fora da tela e quando a imagem escrita estiver pronta para ser exibida, esta transferida para a
tela de uma s vez. O double-buffering pode ser implementado tanto por software como por hardware.

lidade para animaes (assim, o mtodo


Canvas.isDoubleBuffered() tambm deve retornar verdadeiro).

Conexes em rede
Outra novidade uma conveno para
nomes de portas seriais. Essa conveno
resolve problemas de falta de normalizao para os nomes das portas, bem como
a dificuldade de acesso. O nome da porta
agora deve ser seguido de uma abreviao
do tipo de porta e depois de um ndice
que sempre inicia em 1. Veja exemplos
abaixo, onde n deve ser substitudo por
um dgito:
COMn, para portas RS-232

IRn, para portas de conexes infravermelho.


USBn, para portas USB.
BTn, para portas seriais por Bluetooth.
No exemplo a seguir podemos ver como
obter uma conexo serial por Bluetooth,
usando a nova conveno:
CommConnection cc = (CommConnection)
Connector.open(comm:BT1;baudrate=19200);

Para as conexes seguras, representadas por javax.microedition.io.HttpsConnection e


javax.microedition.io.SecureConnection, passa a
ser obrigatrio o suporte ao protocolo SSL
V3. Outros protocolos seguros como TLS

Listagem 1. MIDlet que exibe trs StringItems com layouts diferentes


import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class TesteLayout extends MIDlet implements CommandListener {
Form form = new Form(Teste de Layout);
Command cmdExit = new Command(Sair, Command.EXIT, 1);
public TesteLayout() {
form.addCommand(cmdExit);
form.setCommandListener(this);
StringItem si1 = new StringItem(StringItem1, );
StringItem si2 = new StringItem(StringItem2, );
StringItem si3 = new StringItem(StringItem3, );
si1.setLayout(Item.LAYOUT_LEFT);
si2.setLayout(Item.LAYOUT_CENTER);
si3.setLayout(Item.LAYOUT_RIGHT);
form.append(si1);
form.append(si2);
form.append(si3);
}
protected void destroyApp(boolean arg0)
throws MIDletStateChangeException {}
protected void pauseApp() {}
protected void startApp() throws MIDletStateChangeException {
Display.getDisplay(this).setCurrent(form);
}
public void commandAction(Command c, Displayable d) {
if (c == cmdExit) notifyDestroyed();
}
}

Figura 1. Layouts de StringItem

Edio 51 Java Magazine

31

Wireless Update Explorando o MIDP 2.1

e WTLS tambm podem ser suportados


pela implementao no dispositivo, mas
no so obrigatrios.

Outras alteraces
O MIDP 2.1 torna obrigatrio como
configurao mnima o CLDC 1.1. uma
mudana significativa, pois embora muitos dispositivos j implementem a dupla
MIDP 2.0/CLDC 1.1, existem outros que
tm a verso mais nova do MIDP junto
com o CLDC 1.0, o que fragmenta muito a
plataforma Java ME2.
Outra mudana que temos uma definio sobre o tamanho do cone do aplicativo (declarado no atributo MIDlet-Icon do
descritor JAD). Agora exigido o tamanho
mnimo de 16x16 pixels, mas recomenda-se
o tamanho de 24x24 pixels.
As notificaes de instalao e excluso
dos aplicativos tambm foram alteradas.
Essas notificaes so definidas nos atributos MIDlet-Install-Notify e MIDlet-Delete-Notify
do descritor JAD, e so adicionadas para
notificar um servidor na internet sobre a
instalao ou a excluso do aplicativo em
um dispositivo.
Na nova verso do MIDP, o dispositivo
deve tentar pelo menos cinco vezes fazer
essa notificao, enquanto no obtiver resposta do servidor. Um dos motivos para essa
mudana que algumas implementaes
tentavam fazer a notificao, mas quando
no obtinham resposta, apenas ignoravam
o problema. Era uma estratgia ruim, pois
a falta de resposta poderia ter sido causada,
por exemplo, pela ausncia de sinal do telefone naquele momento, e uma nova tentativa
poderia resolver a questo.
2 No Java ME, fragmentao significa a existncia de
vrias implementaes diferentes da plataforma, criando
assim variaes que devem ser tratadas pelo desenvolvedor de aplicaes. Quando mais fragmentao houver,
mais trabalho ter o desenvolvedor (com testes e implantao, por exemplo) para garantir que suas aplicaes
funcionem no nmero mximo de dispositivos diferentes.
Um dos motivos para a fragmentao no Java ME que
as primeiras verses das especificaes (CLDC, MIDP etc.)
continham diversos itens opcionais, e muitos fabricantes
ento criaram implementaes que variavam muito com
relao a esses itens.

32 Java Magazine Edio 51

Figura 1. Tela de configurao de projeto no Sun Java Wireless Toolkit 2.5.1 para CLDC

Wireless Toolkit
A srie 2.5.x do Sun Java Wireless Toolkit
para CLDC traz a opo de desenvolver
aplicativos compatveis com o MIDP 2.1.
Ao criar um novo projeto na ferramenta,
possvel configurar qual o perfil da
aplicao, escolhendo uma dentre as trs
verses do MIDP (1.0, 2.0 e 2.1). A Figura 1
mostra essa tela de configurao.

Concluses
O MIDP 2.1 um importante passo para
reduzir a fragmentao no Java ME, e
facilitar o desenvolvimento para novos
dispositivos, oferecendo aos desenvolvedores plataformas mais compatveis para
suas aplicaes.
Grandes fabricantes de celulares como
Nokia e Sony-Ericsson j esto tornando
disponveis aparelhos compatveis com o
MIDP 2.1. No site da Nokia j possvel

ver alguns telefones da Srie 40 (5 Edio)


com suporte nova verso do perfil. J a
Sony Ericsson tem o MIDP 2.1 na linha JP-8
(Java Platform 8), que atualmente inclui os
modelos K850 e W910.

Marlon Luz
(marlon.luz@gmail.com)
consultor Java e possui as
certificaes SCJP, SCMAD, SCJA,
SCWCD. membro individual do Java
Community Process e integra o Expert Group da JSR271 (MIDP 3.0)

jcp.org/en/jsr/detail?id=118
Site do JCP para o MIDP 2.1
java.sun.com/products/sjwtoolkit
Pgina do Sun Java Wireless Toolkit

JavaFX Script: a forma se


Criando uma aplicao JavaFX acessando banco

3 (Form Follows Function) foi o


nome original da tecnologia que
hoje chamada de JavaFX Script. E
no por acaso: a idia principal do F3 era
criar uma linguagem especfica ao domnio das interfaces grficas com o usurio,
que descrevesse apenas a funcionalidade
necessria aos componentes de GUI e
apresentasse o mnimo de rudo.
O lanamento do JavaFX Script foi
feito com certo estardalhao no ltimo
JavaOne, em maio deste ano, como parte
do conjunto de tecnologias JavaFX. Esse
conjunto inclui tambm a plataforma para
dispositivos mveis JavaFX Mobile (um
sistema operacional baseado num kernel
Linux com infra-estrutura para a execuo
de aplicaes Java SE em dispositivos com
maior capacidade).
As tecnologias JavaFX so produtos da
Sun. No seguem ainda o caminho da
padronizao pelo JCP(Java Community

Process), mas um ponto importante a


promessa de que todas estaro disponveis
sob licena open source.
Embora a tecnologia JavaFX esteja
comumente associada a designs chamativos, nosso foco neste artigo mostrar
a integrao de aplicaes JavaFX com
banco de dados, usando uma arquitetura
no-trivial.

A linguagem, o ambiente e exemplos


As linguagens de script tm crescido
em popularidade e tendem a ganhar
ainda mais espao, visto que a mquina
virtual Java, atravs da JSR-223, oferece
suporte para diversas linguagens de script.
Veja mais sobre este assunto no quadro
JavaFX, JSR-223 e outras linguagens de
script.
A JavaFX Script incorpora conceitos de
vrias outras linguagens, incluindo Java,
JavaScript, XML, SQL, ActiveScript, SVG

e AspectJ. (Para amenizar a repetio


de Java, vamos encurtar o nome da
linguagem para FX Script no restante
do artigo.)
Na definio de GUIs, o forte da FX Script
o estilo declarativo, em que a estrutura
visual se reflete diretamente na linguagem
de programao. Outra vantagem a simplicidade no vnculo (binding) entre dados
e elementos visuais.
Vamos explorar a linguagem, atravs de
um exemplo concreto. Ao final teremos
construdo uma aplicao JavaFX que
acessa um banco de dados via JDBC. Antes
de criar esta aplicao, no entanto, iremos
apresentar alguns conceitos atravs de
exemplos mais simples, comeando pela
preparao do ambiente.

Pr-requisitos e preparao do ambiente


Vamos utilizar a forma mais direta de
executar aplicaes FX Script: via linha
de comando. Necessitamos das seguintes
instalaes:
JDK 1.6 ou JRE 1.6
Distribuio do Openjfx (que pode
ser obtida em openjfx.dev.java.net/servlets/
ProjectDocumentList).
A distribuio do Openjfx, que inclui
um ambiente de runtime para aplicaes
FX Script, vem na forma de um arquivo
.zip ou .tgz. Uma vez descompactado o
arquivo, teremos a seguinte estrutura de
diretrios:
+-- OpenJFX-200707201531
+-- branches
+-- LICENSE
+-- tags
+-- trunk
+-- bin
+-- demos
+-- doc
+-- lib
+-- src
+-- www

34 Java Magazine Edio 51

gue a funo
de dados

Conhea a linguagem JavaFX


Script, que permite criar
interfaces grficas mais
facilmente, com cdigo parecido
estrutura dos componentes
visuais e capacidade de criar
GUIs mais ricas

Jorge Diz e Yara H. Senger


No diretrio trunk/bin, temos os utilitrios javafx.bat e javafx.sh, que permitem a
execuo dos scripts FX a partir da linha
de comando. Devemos tambm definir
uma varivel de ambiente JAVAFX_HOME
apontando para o subdiretrio trunk da
instalao, e adicionar o subdiretrio
trunk/bin varivel de ambiente PATH.
Com o ambiente preparado, podemos
iniciar os exemplos.

Exemplo 1: Criando uma janela vazia


Vamos comear criando uma janela com
tamanho fixo, mas sem incluir nenhum
outro componente visual. Em FX Script,
essa implementao ficaria assim:
1: import javafx.ui.*;
2:
3: Frame {
4: height: 300
5: width: 400
6: title: Cadastro de Clientes
7: visible: true
8:}

Crie um arquivo texto com este cdigo


(sem os nmeros de linha) e salve-o como
FrameCadastro.fx, em um diretrio sua
escolha. Execute ento o seguinte comando
neste diretrio:
javafx FrameCadastro

A Figura 1 exibe a tela (muito simples)


resultante da execuo deste script. Vamos
analisar o cdigo. A clusula import da
primeira linha funciona da mesma forma
que em Java, ou seja, ela estabelece que os
identificadores no script vo ser procurados dentro do pacote javafx.ui.
Entre as linhas 3 e 8, instanciado um objeto do tipo Frame (javafx.ui.Frame). Note que
isso feito apenas com o nome da classe,
neste caso com um bloco delimitado por { },
que especifica os valores das propriedades
da instncia.

Observe que estamos usando o estilo


declarativo, em oposio forma imperativa com a qual estamos acostumados
a programar em Java (onde temos uma
seqncia de comandos que so seguidos
passo a passo). Esse estilo de codificao
da FX Script conceitualmente similar
ao usado em arquivos XML, mas sem a
poluio visual de marcaes repetidas e
caracteres < >. Outra similaridade com a
sintaxe do JSON (JavaScript Object Notation), conhecida pelos programadores de
aplicaes Ajax e utilizada como uma das
alternativas para transferncia de dados.
Vemos tambm, na linha 7, a atribuio
visible: true. Esta e outras partes do cdigo sugerem que temos como base um componente
Swing. De fato, os componentes visuais do
FX Script encapsulam a utilizao de componentes Swing (para as interfaces simples)
e de componentes Java2D (que suportam
a definio de componentes vetoriais para
interfaces visualmente mais ricas).
Definir declarativamente uma instncia
de uma classe equivale a invocar nela
o operador new. Em FX Script, podemos

muitas vezes optar por uma forma mais


declarativa ou mais imperativa, mas a
declarativa prefervel para representar
a estrutura de uma interface visual.

Exemplo 2: Adicionando os componentes


visuais janela
Vamos implementar agora uma interface
simples para operaes de cadastro em uma
base de clientes. Incluiremos um combobox
para escolha de um cliente, alm de um
conjunto de campos de texto para a edio
das propriedades do cliente escolhido, com
rtulos identificando cada propriedade.
Usaremos como base a janela do primeiro

Figura 1. Execuo da verso inicial de FrameCadastro.fx

JavaFX, JSR-223 e outras linguagens de script

utilizao de outras linguagens dentro da


plataforma Java est se tornando cada vez
mais comum, e podemos dizer que se trata de
um bom casamento de convenincia. Para o
Java, este relacionamento permite unir esforos
para tarefas nas quais h uma sinergia forte
com uma determinada linguagem (avaliao
de regras de negcio, processamento de expresses regulares, clientes web etc.). J para
a outra linguagem, uma espcie de golpe do
ba: toda a infra-estrutura da plataforma Java
bibliotecas, frameworks, containers, padres
e tudo o mais vm de graa.
Neste contexto, foi padronizada uma API para

a utilizao de linguagens de script na plataforma Java, atravs da JSR-223. A implementao


desta API (pacote javax.script) foi includa no
Java SE 6, e permite plugar facilmente diversos
engines de interpretao de linguagens. O JDK
1.6 inclui o Rhino, um engine para JavaScript, e
a mesma API utilizada para plugar o engine
de FX Script, sendo portanto um pr-requisito
para o desenvolvimento e a implantao nesta
linguagem. Note que a implementao de
referncia da JSR-223 est disponvel para a
verso anterior do Java tambm; portanto,
possvel trabalhar com FX Script mesmo com
o Java SE 5.

Edio 51 Java Magazine

35

JavaFX Script: a forma segue a funo

exemplo, incrementando-a para a estrutura


mostrada na Listagem 1 (veja esta aplicao
em execuo na Figura 2).
O atributo content do Frame sendo instanciado recebe a raiz de uma hierarquia de
componentes visuais, que so especificados em estilo declarativo. Note que o texto
espelha a estrutura visual da interface. Os
Panels que aparecem nesta interface so
componentes visuais que podem conter
sub-componentes e serem configurados
com gerenciadores de layout, da mesma
forma que em Swing.

No exemplo, o BorderPanel raiz utiliza um


layout que fixa cinco regies para os componentes: topo, centro, base, esquerda e direita. O espao correspondente a algumas
regies no preenchidas ocupado pelas
vizinhas. No nosso caso, preenchemos as
regies do topo, do centro e da base com
sub-componentes.
No topo, temos um combobox, e no centro h um GridPanel, que usa um formato
de tabela. Este componente preenchido
pelos sub-componentes denotados pelo
atributo multivalorado cells, com Labels

Listagem 1. Verso final de FrameCadastro.fx


package myfx;
import javafx.ui.*;
Frame {
height: 150
width: 400
title: Cadastro de Clientes
content: BorderPanel {
top : ComboBox
center: GridPanel {
rows: 4 columns: 2 cells: [
Label { text: nome: }, TextField,
Label { text: cdigo: }, TextField,
Label { text: cpf: }, TextField,
Label { text: email: }, TextField,
]
}
bottom: FlowPanel {
content: [
Button { text: Salvar }, Button {text: Novo }
]
}
}
visible: true
}

e campos de texto (TextFields) para cada


atributo do cliente.
Fi n a l m e nt e, n a b a s e, t e m o s u m
FlowPanel com os botes correspondentes s
operaes de cadastro Salvar e Novo.
Isto conclui a estrutura visual. O prximo
passo adicionar comportamento GUI.

A aplicao completa
Agora que vimos alguns exemplos e
conceitos fundamentais, podemos iniciar
a criao da aplicao com acesso a dados.
Ela ser composta por trs componentes
e utilizar recursos mais avanados de
JavaFX Script, os quais sero apresentados
medida que forem utilizados. Os componentes da nossa aplicao so:
GerenciadorConexoes Responsvel por
abrir e fechar as conexes com o banco
de dados, bem como pela execuo de
instrues SQL.
Cliente Classe que espelha as propriedades de cada cliente, correspondentes s
colunas no banco de dados.
ClienteUI Interface grfica da aplicao.

Figura 2. Execuo da segunda verso do FrameCadastro.fx

Principais ferramentas que suportam JavaFX

pesar de a JavaFX Script ser praticamente


uma novidade, j existem diversas IDEs que
suportam o desenvolvimento com esta linguagem. Citamos neste quadro as ferramentas de
maior destaque no momento de escrita.

Plugins para IDEs: NetBeans 5.5 e 6.0, Eclipse


3.2.2
O NetBeans um dos IDEs com melhor suporte para JavaFX. H plug-ins disponveis nos
Beta Update Centers para as duas verses mais
recentes. O plug-in para 6.0 inclui um painel que
permite visualizar a interface grfica enquanto
o texto do programa est sendo editado. Instrues detalhadas para a instalao dos plugins
so encontradas em:

36 Java Magazine Edio 51

openjfx.dev.java.net/javafx-nb55-plugininstall.html (para NetBeans 5.5.x)


openjfx.dev.java.net/javafx-nb60-plugininstall.html (para NetBeans 6)
openjfx.dev.java.net/javafx-eclipse-plugininstall.html (para Eclipse)

JavaFX Script runtime (openjfx)


O runtime do Openjfx, que necessrio para
executar cdigo FX Script, implementa um engine de scripting compatvel com a JSR-223. A
distribuio pode ser baixada a partir de openjfx.
dev.java.net/servlets/ProjectDocumentList.

JavaFXPad
O JavaFXPad uma ferramenta stand-alone

que permite editar um programa em FX Script


enquanto se visualiza o resultado em tempo
real. excelente para aprendizado da linguagem sem precisar de uma IDE. Ele includo
na distribuio do Openjfx e tambm pode ser
instalado via Java Web Start, acessando:
download.java.net/general/openjfx/demos/
javafxpad.jnlp.

JFXBuilder
Ferramenta dirigida a programadores visuais, o
JFXBuilder permite montar interfaces arrastando
e soltando componentes, e tem bons recursos
para a montagem de animaes e efeitos no
estilo do Flash. Instalvel a partir de www.
reportmill.com/jfx.

Apresentaremos a seguir os passos necessrios para a criao da aplicao.

1. Criando o GerenciadorConexoes
GerenciadorConexoes uma classe utilitria,
responsvel pela interao com o banco de
dados, de forma independente da classe de
negcios sendo utilizada. Nela definimos
dois atributos e trs operaes.
class GerenciadorConexoes {
private attribute conexao: Connection;
private attribute sql: Statement;
public operation abre();
public operation fecha();
public operation consulta(sql: String): ResultSet;
}

As operaes so um dos recursos da


linguagem FX Script para especificar
comportamento (tambm temos funes
e triggers).
A Listagem 2 contm a implementao completa da classe GerenciadorConexoes. Nela voc
pode ver como utilizar classes Java do pacote java.sql e um driver JDBC. A carga do
driver para o BD especfico (MySQL, neste
caso) efetuada em tempo de interpretao. (O FX Script interpretado por um
engine chamado a partir de cdigo Java.)
Observe que estamos deixando as excees serem lanadas se houver algum
problema, mas que garantimos a liberao de recursos com o bloco finally. Note
ainda a sintaxe similar ao SQL, quando
manipulamos variveis que representam
grupos de elementos em JavaFX (insert
... into clientes).

2. Criando a classe Cliente


Cliente uma classe de modelo que no
exemplo vai funcionar ao mesmo tempo
como um objeto de acesso a dados (DAO)
e como um componente de retaguarda da
interface grfica (de maneira anloga a um
form bean do Struts). Iremos definir quatro
atributos e uma operao que retorna todos os clientes cadastrados:
public class Cliente {
attribute nome: String;
attribute codigo: String;
attribute cpf: String;
attribute email: String;
}
operation todosOsClientes(): Cliente* {
// cdigo do mtodo
}

Listagem 2. GerenciadorConexoes.fx: classe utilitria para acesso ao banco de dados


package myfx;
import java.sql.*;
import java.lang.*;
import com.mysql.jdbc.Driver as MySqlDriver;
class GerenciadorConexoes {
private attribute conexao: Connection;
private attribute sql: Statement;
public operation abre();
public operation fecha();
public operation consulta(sql: String): ResultSet;
}
operation GerenciadorConexoes.abre() {
try {
var driver = MySqlDriver.class;
var url = jdbc:mysql://192.168.0.1/aj;
this.conexao = DriverManager.getConnection(url, aj, aj);
this.sql = conexao.createStatement();
} catch (e: Exception) {
fecha();
throw e;
}
}
operation GerenciadorConexoes.fecha() {
try {
sql.close();
} finally {
if (conexao <> null) {
conexao.close();
}
}
}
operation GerenciadorConexoes.consulta(comando: String): ResultSet {
return sql.executeQuery(comando);
}

Listagem 3. Cliente.fx: classe de modelo


package myfx;
import java.lang.*;
public class Cliente {
attribute nome: String;
attribute codigo: String;
attribute cpf: String;
attribute email: String;
}
operation todosOsClientes(): Cliente* {
var clientes : Cliente* = [];
var conexao: GerenciadorConexoes;
try {
conexao = new GerenciadorConexoes;
conexao.abre();
var resultados =
conexao.consulta(select * from clientes);

while(resultados.next()) {
insert Cliente {
nome : resultados.getString(nome),
email : resultados.getString(email),
cpf : resultados.getString(cpf),
codigo : {resultados.getInt(id)},
} into clientes;
}
} finally {
if (conexao <> null) {
conexao.fecha();
}
}
return clientes;

Edio 51 Java Magazine

37

JavaFX Script: a forma segue a funo

Para que seja possvel obter a lista completa de clientes do banco de dados,
necessrio abrir e fechar a conexo com
o banco e tambm executar uma instruo SQL. Para isso, utilizamos a classe
GerenciadorConexoes. Veja a implementao
completa de Cliente na Listagem 3.

3. Criando a classe ClienteUI


A classe ClienteUI a que contm praticamente toda a complexidade da aplicao. Por
isso vamos discutir cada trecho em detalhe.
Veja seu cdigo completo na Listagem 4.

A interface definida por ClienteUI deve


mostrar as informaes do cliente obtidas
de um banco de dados. Precisamos, ento,
de um mecanismo para vincular os dados
obtidos de uma consulta com os componentes visuais.
Iremos definir dois atributos e uma operao, conforme o trecho a seguir:
public class ClienteUi extends Frame {
public attribute clientes: Cliente*;
public attribute combo: ComboBox;
operation comboCells() : ComboBoxCell*;
}

Listagem 4. ClienteUi.fx: classe de interface usurio


package myfx;
import myfx.Cliente;
import java.lang.System;
import javafx.ui.*;
public class ClienteUi extends Frame {
public attribute clientes: Cliente*;
public attribute combo: ComboBox;
operation comboCells() : ComboBoxCell*;
}
attribute ClienteUi.clientes = bind todosOsClientes();
attribute ClienteUi.combo = ComboBox { cells: bind comboCells() };
operation ClienteUi.comboCells(): ComboBoxCell* {
var comboCells : ComboBoxCell* = [];

for (cliente in clientes) {


insert ComboBoxCell {
text: {cliente.nome} ({cliente.codigo})
} into comboCells;
}
return comboCells;

trigger on new ClienteUi {


title = Cliente UI;
width = 400;
height = 300;

content = BorderPanel {
top : combo
center: GridPanel {
var cliente = bind clientes[combo.selection]
columns: 2
cells: [
Label { text: nome: },
TextField { value: bind cliente.nome },
Label { text: codigo: },
TextField { value: bind cliente.codigo },
Label { text: cpf: },
TextField { value: bind cliente.cpf },
Label { text: email: },
TextField { value: bind cliente.email },
]
}
bottom: FlowPanel {
content: [
Button {text: Salvar},
Button {text: Novo},
]
}
};
visible = true;

38 Java Magazine Edio 51

Repare que o atributo clientes foi declarado como sendo do tipo Cliente*. O asterisco
indica que se trata de um grupo de objetos.
Este grupo utilizado para armazenar os
clientes que iro popular o combobox e
mantm as referncias para as informaes
de cada cliente.
O atributo combo, do tipo ComboBox um
componente visual que ser referenciado
em outras operaes; por isto declarado como atributo. O atributo clientes est
vinculado, atravs da clusula bind,
operao todosOsClientes(), que tem escopo
global e est definida no arquivo Cliente.fx
(Listagem 2):
attribute ClienteUi.clientes = bind todosOsClientes();

Construtores so representados em FX
Script atravs do uso de triggers, conforme
podemos verificar no seguinte trecho de
cdigo:
trigger on new ClienteUi {
title = Cliente UI;
width = 400;
height = 300;
...
}

So definidos o ttulo, a largura e a altura da janela, indicando o que deve ser


executado ao criar um novo objeto do tipo
ClienteUI. Observe agora este trecho:
content = BorderPanel {
top : combo
...
}

Nele, o contedo do Frame (content) recebe


um componente visual, BorderPanel, definido de forma declarativa. No BorderPanel
colocamos no top o combobox de clientes
definido atravs do atributo combo. No
centro do BorderPanel, inserimos os componentes para visualizao das informaes
do cliente selecionado, utilizando o gerenciador de layout GridPanel:

Figura 3. Execuo de ClienteUI.fx

center: GridPanel {
var cliente = bind clientes[combo.selection]
columns: 2
cells: [
Label { text: nome: },
TextField { value: bind cliente.nome },
Label { text: codigo: },
TextField { value: bind cliente.codigo },
...
}

Repare no uso da palavra reservada var,


que no tem similar em Java quando utilizada nesse contexto. Neste caso, a varivel
cliente tem como escopo a instncia da classe Cliente selecionada no combobox:
var cliente = bind clientes[combo.selection]

Os elementos visuais esto vinculados


com cliente atravs da clausula bind, e a
varivel cliente, por sua vez, est vinculada
ao elemento selecionado no combobox,
atravs da mesma clusula:
Label { text: nome: },
TextField { value: bind cliente.nome }

Na parte inferior do BorderPanel, inserimos


dois botes aos quais no associamos
comportamento:
bottom: FlowPanel {
content: [
Button {text: Salvar},
Button {text: Novo},
]
}

conceitos e sintaxes de vrias outras linguagens. Foi criada especialmente para


descrever a estrutura e o comportamento
de interfaces com o usurio, permitindo
criar GUIs com uma quantidade de cdigo
muito reduzida se comparada programao em Swing e a diferena ainda
maior quando comparamos a quantidade
de cdigo Java2D necessria para a criao
de aplicaes ricas.
Em suma, a promessa de FX Script
ter produtividade no desenvolvimento
de interfaces ricas, e tudo indica que no
sero poupados esforos para viabilizar
essas interfaces para clientes na web, sem
termos de renunciar aos benefcios da
plataforma Java.
Uma ltima observao: o mecanismo
de binding (vinculao) do FX Script, que
usamos no exemplo final, lembra bastante

o mecanismo de binding via Expression


Language que vincula componentes de
interface com o usurio a Managed Beans
do JSF. Como JavaFX Script ainda muito
nova e ainda no open source, nem
regida pelo Java Community Process,
possvel que a sinergia entre JavaFX Script e
o JavaServer Faces torne-se ainda maior.

Jorge Alberto Diz


(jorge@globalcode.com.br)
instrutor da Globalcode, mestre
em Engenharia Eltrica e Bacharel
em Cincia da Computao. Possui
ampla experincia em desenvolvimento de software,
tendo participado de projetos em reas diversas,
principalmente financeiras, assim como em sistemas
de telecomunicaes, logstica e manufatura. Tem as
certificaes SCJP e SCWCD.

Yara M. H. Senger
(yara@globalcode.com.br)
formada em Cincias da Computao na USP em So Carlos, e
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.

openjfx.dev.java.net
Site oficial do JavaFX Script
jfx.wikia.com
Wiki onde acontece boa parte da discusso
que est moldando a tecnologia JavaFX
blogs.sun.com/chrisoliver
Blog de Chris Oliver, criador da tecnologia
precursora do JavaFX Script (F3).

Depois alteramos a visibilidade do


Frame para true (visible = true). Finalizando,
o preenchimento do combobox feito
atravs do vinculo do atributo combo operao comboCells(). Esta operao converte
os dados dos objetos cliente encontrados
na lista definida pelo atributo clientes em
objetos ComboBoxCell, os quais so inseridos
no combo.
attribute ClienteUi.combo =
ComboBox { cells: bind comboCells() };
operation ClienteUi.comboCells(): ComboBoxCell* {
var comboCells : ComboBoxCell* = [];
for (cliente in clientes) {
insert ComboBoxCell {
text: {cliente.nome} ({cliente.codigo})
} into comboCells;
}
return comboCells;
}

Concluses
A FX Script bastante sofisticada para
uma linguagem de script, incorporando
Edio 51 Java Magazine

39

Decorando a Web com


Estabelea o layout de suas pginas de forma

esse art igo apresentamos o


Sitemesh, que permite obter um
layout consistente em suas aplicaes web de forma simples. Com esse
framework open source possvel tambm
compor sites com base em partes menores,
estruturando-os como portais.

O problema
Quando vrias tecnologias web (JSP/
Servlets, PHP, HTML etc.) so utilizadas

40 Java Magazine Edio 51

por uma empresa para compor seus sites


de internet ou intranet, fica difcil manter
um layout padronizado entre todas as tecnologias. Mesmo quando apenas uma tecnologia utilizada (Java EE, por exemplo),
a tarefa de manter um layout consistente
tambm no nada fcil.
Tais problemas se agravam quando o
layout est espalhado por centenas ou
milhares de pginas, o que torna muito trabalhoso realizar mesmo as alteraes mais
simples. Trocar as cores que representam
a empresa ou realizar uma campanha de
Natal, por exemplo, mudando o layout de

um conjunto das pginas, torna-se uma


tarefa onerosa.
Sem uma forma de separar o layout do
contedo, tambm fica difcil compor pginas a partir de outras pginas. Quando
isso feito, so necessrias adaptaes,
especialmente no cdigo HTML, o que no
o ideal. Deveria ser possvel inserir pginas em outras, formando composies,
sem que as pginas saibam que esto
sendo compostas e possam ser usadas de
maneira independente.

A soluo
O framework Sitemesh permite separar
o layout das pginas do seu contedo. Ele
funciona independentemente da tecnologia utilizada, atravs da definio de
decorators. Esses decorators atuam como
templates, permitindo a insero do contedo varivel em pontos especficos.
Ao se requisitar uma pgina, o contedo
dela extrado e analisado e ento efetuada uma juno das partes desse contedo
com o decorator. Ou seja, os pontos relevantes obtidos ao analisar a pgina so
inseridos em partes pr-determinadas,
fazendo com que o resultado final contenha os dados da pgina, mas com o layout
definido pelo decorator. Com o Sitemesh
podemos decorar pginas sem que elas
saibam que sero decoradas. Isso facilita
a manuteno, pois possibilita centralizar
o cdigo necessrio para o layout em um
ponto nico: o decorator.
Alm da decorao, o Sitemesh permite
formar pginas a partir de outras pginas
ou de outras composies. Geralmente a
composio das pginas acabar em uma
estrutura similar a uma rvore, contendo
pginas simples ou outras composies.
O Sitemesh foi baseado em conceitos de
design patterns estruturais bem conhecidos: Decorator e Composite. Veja o quadro
Baseado em design patterns que faz uma

Sitemesh
simples

Veja como fcil


mantendo um look-andfeel e uma estrutura
consistentes entre todas
as pginas de suas
aplicaes web

Daniel Cicero Amadei


reviso breve dos patterns que inspiraram
o framework e mostra como eles se encaixam na arquitetura do Sitemesh. Observe
que tais patterns so somente uma base
para entender o funcionamento do framework, j que apenas as idias e conceitos
dos patterns foram aplicados.

Como funciona o Sitemesh?


Veremos a seguir, de forma mais detalhada, como o Sitemesh realiza tanto a decorao das pginas quanto a composio.

Decorao
A decorao realizada pelo Sitemesh
ocorre atravs de um Servlet Filter. Isso
proporciona vantagens, pois possvel
decorar at mesmo pginas estticas.
Quando uma pgina interceptada pelo
filtro do Sitemesh, ocorre uma srie de
eventos. Veja um resumo:
1. Aps o processamento da requisio
pelo objeto responsvel (servlet, action, JSP
etc.), o HTML resultante obtido.
2. O Sitemesh solicita o parse do contedo: o que era texto HTML se transforma
em uma estrutura de objetos em mem-

ria. Essa estrutura encapsulada em um


objeto que implementa uma subinterface
de com.opensymphony.module.sitemesh.Page.
Para pginas HTML, especificamente,
implementada a interface HTMLPage,
do mesmo pacote. O quadro Sitemesh
e performance discute as implicaes

que essa estratgia pode trazer para suas


aplicaes.
3. Um DecoratorMapper (objeto responsvel
por associar um decorator requisio)
consultado para determinar qual decorator deve ser aplicado.
4. O filtro do Sitemesh redireciona para

Sitemesh e performance

ara que possa aplicar a decorao, o Sitemesh realiza o parse do cdigo HTML resultante do processamento de pginas dinmicas
ou simplesmente da obteno de pginas
estticas. Esse processo no demorado e no
coloca em risco o uso do Sitemesh em aplicaes cujo tempo de resposta crtico.
Um possvel problema no uso do Sitemesh
a quantidade de memria necessria para
as operaes de decorao. Como a pgina
que est sendo decorada deve ter seu corpo
obtido pelo Sitemesh para que seja includo
no template, esse contedo deve ficar em
memria durante alguns instantes. Caso as
pginas forem exageradamente grandes e a

quantidade de acessos simultneos for significativa, podero ocorrer problemas de uso


excessivo de memria, o que pode ocasionar
at mesmo a parada da aplicao devido a erros
do tipo OutOfMemoryError.
Devido a essa questo, recomendado
realizar um teste de estresse prvio, com uma
ferramenta de profiling, para verificar o consumo mdio de memria que est ocorrendo com
o uso do Sitemesh, e identificar se esse valor
aceitvel ou no. Determinar se a quantidade
de memria consumida pelo Sitemesh aceitvel, claro, depender muito do tamanho
mdio das pginas decoradas e da quantidade
de memria disponvel no servidor.

Figura1. Processo de decorao do Sitemesh

Edio 51 Java Magazine

41

Decorando a Web com Sitemesh

Baseado em design patterns

omo vimos no corpo do artigo, o Sitemesh


foi concebido com dois design patterns
estruturais em mente: o Decorator e o Composite.
Ele tambm aplica uma adaptao do pattern
Java EE CompositeView. A seguir, apresentamos
brevemente esses trs patterns.

Decorator
O pattern Decorator tem como princpio adicionar responsabilidades a objetos de forma individual, e no a todos os objetos de uma mesma
classe. Como essa adio de responsabilidade
efetuada de forma dinmica e individualizada, o
simples uso de herana no uma boa soluo,
pois exigiria que todos os objetos possussem o
mesmo comportamento.

A estrutura do pattern bem simples, com o


decorator implementando a mesma interface
que o componente que ele decora. Isso faz com
que a presena de um componente realizando
a decorao seja transparente para os clientes,
e permite adicionar funcionalidade antes ou
depois de delegar as chamadas ao componente
decorado. O diagrama da Figura Q1 ilustra a
estrutura do pattern.
No Sitemesh, a parte de decorao das pginas aplica alguns princpios desse design
pattern, pois temos a decorao de objetos de
forma transparente e a seleo individualizada
desses objetos (atravs do DecoratorMapper);
ou seja, nem todas as pginas so decoradas
da mesma forma.

Composite
Um princpio do pattern Composite permitir
que objetos sejam agrupados em estruturas
hierrquicas (no estilo rvore). Outro objetivo
fazer com que o cliente trate objetos simples
ou compostos da mesma forma ambos devem
implementar uma interface comum e passam a
ser manipulados atravs dessa interface. Objetos
podem ser compostos por outros objetos compostos, recursivamente e sem limites. O diagrama na Figura Q2 ilustra a estrutura do pattern.
Com o uso do Sitemesh, possvel montar
pginas a partir de outras pginas, o que permite criar estruturas estilo rvore para que
elas sejam compostas. Alm disso, podemos
decorar nossas pginas independentemente
do fato de serem compostas por outras pginas
ou no. Ou seja, tratamos objetos compostos da
mesma forma que objetos simples, seguindo os
princpios do pattern Composite.

CompositeView
O pattern Java EE CompositeView baseado
no Composite. possvel afirmar que o Sitemesh
uma implementao de uma verso adaptada desse pattern. O CompositeView prega
que views (pginas, no nosso caso) complexas
devem ser compostas por subviews menores.
Com isso, separa-se o layout da composio da
pgina. O Sitemesh implementa esses conceitos.
O diagrama na Figura Q3 ilustra a estrutura do
pattern.

Figura Q1. Estrutura do pattern Decorator

Figura Q2. Estrutura do pattern Composite

42 Java Magazine Edio 51

Figura Q3. Estrutura do pattern CompositeView

o decorator, que na verdade uma pgina


JSP com marcadores (isso, claro, quando
usamos JSP podemos tambm usar Velocity ou FreeMarker). Os marcadores na
pgina indicam onde os trechos obtidos
no parse do HTML, realizado no passo 2,
sero inseridos.
5. Os elementos que atuam como marcadores (tags, no caso dos JSPs) so
substitudos pelo contedo presente no
objeto HTMLPage (disponvel em memria).
A resposta finalmente enviada para o
cliente, decorada.
A Figura1 ilustra, de forma simplificada, o processo de decorao do Sitemesh.

Composio
A composio de uma pgina a partir de
outras realizada atravs de uma tag. Veja
um exemplo:
<page:applyDecorator
page=/jsp/menu.jsp name=menu />

Aqui a pgina menu.jsp inserida na


pgina que contm esta tag. O decorator a
ser usado indicado no atributo name.

Entendendo o exemplo para entender o


Sitemesh
O exemplo que apresentaremos constitudo por uma aplicao que utiliza Struts
para a camada de apresentao, alm da
API ROME para fazer o acesso a sites que
disponibilizam feeds. (Com o objetivo de

focar no Sitemesh, o nmero de camadas


utilizadas no exemplo foi reduzido.)
O ROME uma API open source que permite
interpretar, consumir e publicar contedo disponibilizado na forma de feeds RSS e ATOM. A grande
vantagem em seu uso que trata de forma transparente as diferentes verses desses padres. Para
se ter uma idia, existem sete verses de RSS e duas
de ATOM suportadas pelo ROME. Alm disso, para
quem quer ainda mais independncia da fonte
de dados, o ROME possui um modelo abstrato,
o SyndFeed, que permite tratar os formatos RSS e
ATOM de maneira uniforme

Preparando o ambiente
O projeto de exemplo est disponvel
para download no site da Java Magazine,
sendo disponibilizado como um WAR dentro de um ZIP. Utilizaremos o Eclipse com
WTP e o Apache Tomcat (5.5 ou superior).
Deve ser utilizada a verso 5 do Java SE,
ou mais recente.
No Eclipse, importe o projeto smesh.war,
usando File|Import>Web>WAR. Utilize

o nome do projeto como o contexto da


aplicao (/smesh) e na tela seguinte no
selecione os JARs para que sejam criados
como projetos. A estrutura criada dever
ser similar da Figura2.

Ententendo a configurao do Sitemesh


O primeiro passo na configurao do
Sitemesh a definio do filtro responsvel pela decorao das pginas. Na Listagem1, destacado o trecho do web.xml
com a definio do filtro, alm da definio
de dois servlets que permitem realizar a
decorao atravs de templates do Velocity
e do FreeMarker. O filtro intercepta todos
os arquivos, pois mapeado como /* no
elemento url-pattern. Atravs desse mapeamento, podemos decorar todas as requisies que retornem contedo HTML.
Aps modificar o web.xml, devemos editar
o sitemesh.xml, presente na pasta WEB-INF
e exposto na Listagem2. Neste arquivo so
declarados todos os DecoratorMappers do Sitemesh, que so componentes responsveis

Listagem1. Configurao do web.xml para o Sitemesh


<?xml version=1.0 encoding=UTF-8?>
<web-app ...>
<filter>
<filter-name>sitemesh</filter-name>
<filter-class>
com.opensymphony.module.sitemesh.filter.PageFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>sitemesh</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>sitemesh-velocity</servlet-name>
<servlet-class>
com.opensymphony.module.sitemesh.velocity.VelocityDecoratorServlet
</servlet-class>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet>
<servlet-name>sitemesh-freemarker</servlet-name>
<servlet-class>
com.opensymphony.module.sitemesh.freemarker.FreemarkerDecoratorServlet
</servlet-class>
<init-param>
<param-name>TemplatePath</param-name>
<param-value>/</param-value>
</init-param>
<init-param>
<param-name>default_encoding</param-name>
<param-value>ISO-8859-1</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<!-- outras definies... -->
</web-app>

Figura2. Estrutura do projeto aps importao no Eclipse

Edio 51 Java Magazine

43

Decorando a Web com Sitemesh

Listagem2. Arquivo sitemesh.xml, onde so declarados os DecoratorMappers


<sitemesh>
<property name=decorators-file value=/WEB-INF/decorators.xml />
<excludes file=${decorators-file} />
<page-parsers>
<parser content-type=text/html
class=com.opensymphony.module.sitemesh.parser.FastPageParser />
</page-parsers>
<decorator-mappers>
<mapper
class=com.opensymphony.module.sitemesh.mapper.PageDecoratorMapper>
<param name=property.1 value=meta.decorator />
<param name=property.2 value=decorator />
</mapper>
<mapper
class=com.opensymphony.module.sitemesh.mapper.FrameSetDecoratorMapper>
</mapper>
<mapper
class=com.opensymphony.module.sitemesh.mapper.AgentDecoratorMapper>
<param name=match.MSIE value=ie />
<param name=match.Mozilla [ value=ns />
<param name=match.Opera value=opera />
<param name=match.Lynx value=lynx />
</mapper>
<mapper
class=com.opensymphony.module.sitemesh.mapper.PrintableDecoratorMapper>
<param name=decorator value=printable />
<param name=parameter.name value=printable />
<param name=parameter.value value=true />
</mapper>
<mapper
class=com.opensymphony.module.sitemesh.mapper.RobotDecoratorMapper>
<param name=decorator value=robot />
</mapper>
<mapper
class=com.opensymphony.module.sitemesh.mapper.ParameterDecoratorMapper>
<param name=decorator.parameter value=decorator />
<param name=parameter.name value=confirm />
<param name=parameter.value value=true />
</mapper>
<mapper
class=com.opensymphony.module.sitemesh.mapper.FileDecoratorMapper>
</mapper>
<mapper
class=com.opensymphony.module.sitemesh.mapper.ConfigDecoratorMapper>
<param name=config value=${decorators-file} />
</mapper>
</decorator-mappers>
</sitemesh>

Listagem3. Declarao dos decorators no arquivo decorators.xml


<?xml version=1.0 encoding=ISO-8859-1?>
<decorators defaultdir=/decorators>
<excludes>
<pattern>/exclude.jsp</pattern>
<pattern>/exclude/*</pattern>
</excludes>
<decorator name=main page=main.jsp>
<pattern>/*</pattern>
</decorator>
<decorator name=panel page=panel.jsp />
</decorators>

44 Java Magazine Edio 51

por selecionar o decorator a ser aplicado


requisio, de forma dinmica (a partir
de agora chamaremos esses componentes
apenas de mappers).
A requisio percorre todos os mappers,
e quando um deles capaz de retornar um
decorator para ela (baseando-se em dados
e atributos presentes na prpria requisio), este decorator utilizado. Todos os
mappers fornecidos pelo Sitemesh esto
no pacote com.opensymphony.module.sitemesh.
mapper. Entre eles, podemos destacar os
decorators a seguir, sendo que geralmente
voc utilizar o ltimo da lista:
LanguageDecoratorMapper, OSDecoratorMapper
e AgentDecoratorMapper o primeiro seleciona o decorator baseado na linguagem
configurada no browser e enviada atravs do cabealho HTTP Accept-Language; o
segundo se baseia no sistema operacional
do cliente, que uma informao enviada
no cabealho UA-OS (User Agent Operating
System). Finalmente, o AgentDecoratorMapper
seleciona o decorator baseado no browser
do cliente (indicado no cabealho User-Agent
da requisio).
FileDecoratorMapper e CookieDecoratorMapper
o primeiro seleciona o decorator a partir
do nome de um arquivo no contexto da
aplicao web e o segundo, a partir do
valor contido por um cookie enviado pelo
cliente;
PageDecoratorMapper permite que a prpria pgina selecione o decorator que ser
aplicado a ela. O decorator selecionado
atravs de um atributo decorator na tag
<HTML> ou de uma tag <META> com atributo
name=decorator e o nome do decorator no
atributo content.
ParameterDecoratorMapper permite que o
decorator seja especificado atravs do contedo de um parmetro decorator enviado
na requisio HTTP.
PrintableDecoratorMapper permite que seja
aplicado um decorator capaz de transformar a pgina corrente em uma verso
para impresso (atravs de um parmetro
printable=true na requisio). muito til,
pois evita que voc duplique suas pginas
criando uma verso para impresso.
RobotDecoratorMapper possibilita que seja
aplicado um decorator quando a requisio for identificada como procedente de

um crawler que pertence a um bot de um


mecanismo de buscas, como o GoogleBot,
por exemplo.
SessionDecoratorMapper permite que o
decorator seja selecionado baseado em
um atributo da sesso HTTP, denominado
decorator.
ConfigDecoratorMapper a implementao
padro. Obtm as configuraes dos decorators a partir de um arquivo XML, que
o /WEB-INF/decorators.xml (outro nome
para esse arquivo pode ser especificado).
Geralmente esse o mapper que voc
utilizar.
Caso deseje alguma funcionalidade
adicional, voc pode criar o seu prprio
mapper, implementando a interface com.
opensymphony.module.sitemesh.DecoratorMapper
e declarando-o no arquivo sitemesh.xml,
como se faz com os decorators providos
pelo Sitemesh.
No sitemesh.xml, os mappers seguem uma
hierarquia. Um mapper sempre pai do
mapper localizado acima dele nesse arquivo
de configurao. Com isso, se um mapper
no capaz de obter um decorator para
determinada requisio, ele delega isso para
o seu pai. Como o ConfigDecoratorMapper
o ltimo mapper declarado no arquivo de
configurao sitemesh.xml , ele acaba sempre
sendo o ltimo consultado. Quando nenhum
mapper consegue atender requisio antes
de chegar ao ConfigDecoratorMapper, este passa
a ser responsvel por selecionar o decorator
baseado em um arquivo de configuraes.
Caso nem mesmo o ConfigDecoratorMapper seja
capaz de decorar a requisio, a pgina no
decorada.
Mesmo quando um dos mappers identifica que capaz de decorar a requisio, ele
pode usar getNamedDecorator() para solicitar
um decorator pelo nome. Neste caso, geralmente o ConfigDecoratorMapper que retorna
o decorator solicitado, pois ele armazena
uma lista de decorators cujos nomes
so obtidos a partir do decorators.xml. A
maioria dos mappers utiliza essa tcnica.
Por exemplo, o ParameterDecoratorMapper
identifica que capaz de decorar a requisio quando o parmetro HTTP decorator
foi enviado pelo cliente. A nica coisa que
esse mapper faz obter o valor desse pa-

rmetro e invocar getNamedDecorator(). Isso


faz com que o mapper ConfigDecoratorMapper
seja acionado e seja obtido o decorator
pelo nome.

decorators.xml
A configurao dos decorators fica em
um arquivo denominado decorators.xml,
na pasta WEBINF da aplicao web. O
decorators.xml de nosso exemplo est na
Listagem 3. Analisando o arquivo, primeiramente temos o elemento <decorators
defaultdir=/decorators>. O atributo defaultdir
indica onde esto localizados os templates
que fazem o papel de decorators. No nosso

caso, os decorators so pginas JSP.


Em seguida, temos o elemento <exclude>,
que define o padro de nome dos arquivos
que no devem ser decorados. Declaramos
depois um ou mais elementos <decorator>
que armazenam as informaes dos nossos decorators. Cada elemento <decorator>
possui um atributo name, que indica o
nome do decorator, e page, que indica o
template (pgina JSP, no nosso caso).
Vale destacar que um elemento <decorator>
pode conter um ou mais elementos
<pattern>, os quais iro conter o padro
das URLs onde o decorator ser aplicado.
Caso voc utilize a declarao <pattern>/*</

Listagem4. Declarao da pgina main.jsp, utilizada em nosso exemplo como o decorator main, aplicado maioria das pginas
<%@ taglib uri=http://www.opensymphony.com/sitemesh/decorator
prefix=decorator%>

<%@ taglib uri=http://www.opensymphony.com/sitemesh/page prefix=page%>
<html>
<head>
<title><decorator:title default= /></title>
<link href=<%= request.getContextPath() %>/decorators/main.css rel=stylesheet
type=text/css>
<decorator:head />
</head>
<body>
<table width=100% height=50% border=0>
<tr>

<td valign=top align=center>
<page:applyDecorator page=/feedsites.jsp name=panel />

</td>

<td width=70% valign=top align=center>
<decorator:body />

</td>
</tr>
</table>
<table width=100% height=50%>
<tr>

<td valign=top>

</td>
</tr>
</table>
</body>
</html>

Listagem5. Declarao da pgina panel.jsp, utilizada em nosso exemplo para o decorator denominado panel
<%@ taglib uri=http://www.opensymphony.com/sitemesh/decorator prefix=decorator %>
<p>
<table border=0 cellpadding=0 cellspacing=0>

<tr>
<th class=panelTitle>

<decorator:title default=Unknown panel />
</th>

</tr>

<tr>
<td class=panelBody>

<decorator:body />
</td>

</tr>
</table>
</p>

Edio 51 Java Magazine

45

Decorando a Web com Sitemesh

pattern>, estar indicando um decorator


default, que ser aplicado a todas as requisies.

O que mesmo um decorator?


Um decorator pode ser um template
do Freemarker ou do Velocity, ou simplesmente uma pgina JSP. O decorator
sempre um template que define a estrutura
e o look-and-feel da pgina. Todo decorator
conta com uma sintaxe para definir os
pontos onde o contedo das pginas decoradas ser inserido. No caso do Velocity

e Freemarker so usadas variveis, disponibilizadas no contexto pelo Sitemesh. No


caso de pginas JSP, so usadas tags da
taglib do Sitemesh.
A Listagem 4 apresenta o nosso decorator main. Ele representado pela pgina
main.jsp e aplicado a todas as pginas
(veja a declarao no decorators.xml). Este
o principal decorator do exemplo. Ao
analisar a estrutura da pgina, temos
duas tags declaradas: decorator e page. A tag
decorator utilizada para inserir os pedaos
dinmicos onde ela posicionada.
Quando efetuamos uma requisio, o
Sitemesh faz o parse do HTML resultante,
e no local onde declaramos <decorator:head>
insere todo o contedo da tag HTML
<head> obtida no parse. Onde declaramos
<decorator:body>, o Sitemesh faz a mesma
coisa com o contedo da tag <body>. Outra
tag importante a <decorator:title>, que obtm o ttulo da pgina a partir do contedo
da tag HTML <title> e o insere no lugar
dessa tag (<decorator:title>).
A tag <page:applyDecorator> permite inserir
uma pgina no contexto da pgina atual,
aplicando outro decorator pgina inserida. No nosso caso, solicitamos a incluso
de feedsites.jsp, aplicando o decorator panel.

Listagem 6. Declarao da Action responsvel pela obteno das notcias


package br.com.jm.sitemesh.action;
//imports...
public class ObterFeedsAction extends Action {
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String url = request.getParameter(url);
SyndFeed feed = FeedService.getInstance().getFeeds(url);
request.setAttribute(syndFeed, feed);

return mapping.findForward(SUCCESS);

Listagem 7. Declarao da pgina showSite.jsp


<!DOCTYPE HTML PUBLIC -//W3C//DTD HTML 4.01 Transitional//EN>
<%@ page session=false contentType=text/html;charset=utf-8%>
<%@ taglib uri=http://www.opensymphony.com/sitemesh/page prefix=page%>
<html>
<head>
</head>
<body>
<page:applyDecorator page=${param[link]} name=panel />
</body>
</html>

46 Java Magazine Edio 51

atravs dessa tag que o Sitemesh realiza


a composio, conforme mencionado no
incio do artigo.

Funcionamento do exemplo
Ao acessar a aplicao, a pgina index.
html exibida. Essa pgina possui apenas o esqueleto HTML, sem nada que
seria exibido pelo browser. Em tempo
de execuo, ela sofre ao do decorator
padro main. Esse decorator declarado
para interceptar todas as pginas da
aplicao (lembre-se do elemento pattern
com valor /*). Como o decorator utiliza
recursos de composio atravs da tag
<page:applyDecorator>, a pgina feedsites.jsp
includa. Essa pgina apresenta uma
lista de alguns sites onde podemos obter
notcias sobre Java, publicadas na forma
de RSS ou ATOM. Repare no uso das
tags <decorator:head> e <decorator:body> que
indicam onde o contedo da pgina ser
inserido.
Utilizamos outro decorator para a
pg i na feedsites.jsp, at ravs da tag
<page:applyDecorator>. Esse decorator
denominado panel e representado pela
pgina panel.jsp (Listagem 5). Ao utiliz-lo,
o main no aplicado, pois indicamos explicitamente qual o decorator que desejamos.
Utilizamos ainda a tag <decorator:title>
para incluir o ttulo da pgina feedsites.jsp
(Feeds sobre Java).
Ao clicar em um dos links, invocada
a action /obterFeeds (Listagem 6). Essa
action recorre classe br.com.jm.sitemesh.
service.FeedService para a obteno da lista
de notcias e envia essa listagem para a pgina feeds.jsp. Esta ltima pgina tambm
sofre ao do decorator main. Ao listar as
notcias obtidas pela action, apresentada
a listagem dos sites do lado esquerdo em
um painel, graas ao do decorator
main. Isso tambm ocorre com a index.
html, obedecendo ao padro visual que
criamos. A Figura 3 mostra nosso exemplo
em funcionamento, aps o clique em um
dos links dos sites.
Ao clicar em uma das notcias, a pgina
showSite.jsp (Listagem 7) acessada. Essa
pgina tambm decorada pelo decorator
main e aplica o decorator panel ao contedo
exibido. O contedo do site obtido pelo
Sitemesh e mostrado em um painel na

tela. O ttulo do site aplicado ao ttulo


do painel, emulando a funcionalidade e a
aparncia de um portal.
A Figura 4 exibe o resultado aps o
clique em uma das notcias. As imagens
e os links relativos no funcionam, pois a
pgina passa a estar no contexto de nosso
site, mas j possvel ter uma boa idia do
que o Sitemesh capaz. Se voc estivesse
inserindo um site com links e imagens
contendo caminhos absolutos, no ocorreria nenhum problema nem nos links nem
nas imagens.

Concluses
Atravs de um exemplo pudemos ver o
Sitemesh em ao, apresentando muitos
dos seus recursos. Com o que foi apresentado, fica claro que o Sitemesh uma
excelente opo para manter o layout
de suas aplicaes consistente, mesmo
quando somente pginas estticas so
utilizadas.
O recurso de composio, que permite
montar pginas a partir de outras pginas, tambm importante para facilitar
a construo de sites e fazer a agregao
de contedo. Junto a isso, a separao
da pgina da forma como ela decorada
facilita a manuteno, reduz a quantidade
de cdigo repetitivo e permite mudar o
layout de forma simples. A alterao passa
a ser centralizada e o esforo para testes
reduzido drasticamente.

Figura 3. Exemplo em funcionamento.

www.opensymphony.com/sitemesh
Site oficial do Sitemesh
rome.dev.java.net
Site oficial do ROME, biblioteca que
utilizamos para o consumo de feeds RSS e ATOM
Daniel Cicero Amadei
(daniel.amadei@gmail.com)
Bacharel em Sistemas de Informao pela Universidade Presbiteriana Mackenzie e ps-graduado
em Gesto de Projetos pela Fundao Vanzolini. Trabalha com Java desde 1999 e possui as certicaes
SCJP, SCWCD, SCBCD, SCDJWS e SCEA, atuando como
Arquiteto de Sistemas Java SE e Java EE.

Figura 4. Site includo dinamicamente.

Edio 51 Java Magazine

47

Tratamento de Excees
Conceitos bsicos, armadilhas e boas prticas

este artigo, vamos explorar desde


os conceitos bsicos o tratamento
de excees em aplicaes Java,
traando um paralelo entre as situaes
encontradas no dia-a-dia e o impacto em
suas aplicaes. Falamos tambm um
pouco sobre questes levantadas sobre
excees checadas na linguagem Java, e
apresentamos dicas e boas prticas para
o uso deste recurso.

Conceitos iniciais

Uma exceo em programao pode ser


vista como um evento que disparado
sempre que alguma coisa errada ou no
prevista ocorre durante a execuo. Esse
evento altera o fluxo normal do programa,
geralmente cancelando a execuo de
aes esperadas de um ou mais mtodos.
A linguagem Java e o Java SE fornecem
recursos sofisticados para manipulao de

excees, atravs das clusulas try, catch e


finally. H tambm todo um mecanismo de
runtime para lidar com excees.
Veremos que adotar uma boa estratgia para manipular excees facilita na
deteco de erros e torna as aplicaes
mais robustas (ou seja, mais tolerantes a
erros). Veja na Listagem 1 um exemplo de
estrutura para o tratamento de excees
em Java.
Vamos comentar esse cdigo, ao mesmo
temo que apresentamos conceitos fundamentais. Uma clusula try vem acompanhada de zero ou mais clusulas catch, e
uma ou nenhuma clusula finally. Pelo
menos uma destas clusulas obrigatria,
sendo ilegal um bloco try sem nenhum
catch nem finally.
Observe que a ordem das clusulas
catch significativa. As classes de exceo StringIndexOutOfBoundsException e
ArrayIndexOutOfBoundsException so subclasses de IndexOutOfBoundsException, e por serem mais especializadas, seus catch devem
ser declarados antes. J a ordem relativa
dos catch de StringIndexOutOfBoundsException
e de ArrayIndexOutOfBoundsException no
forada pelo compilador, pois elas esto
no mesmo nvel hierrquico. Note ainda
que tratamos a classe Exception por ltimo,
porque ela a mais geral entre as utilizadas no exemplo.
Caso a ordenao da exceo mais especfica para a mais geral no seja obedecida,
o compilador apresentar um erro de
compilao indicando que a exceo j foi
tratada anteriormente. O cdigo da Listagem 2, por exemplo, no compila porque a
classe Exception mais geral do que a classe
IndexOutOfBoundsException.
A clusula finally
O cdigo contido no bloco finally sempre
ser executado, mesmo se uma exceo
for lanada ou se um return for encontrado

48 Java Magazine Edio 51

na Prtica

Entenda o mecanismo de
controle e tratamento de
excees do Java e evite
problemas comuns

Andr Diniz
dentro de um catch do mesmo bloco try. O
bloco finally deve ser includo quando desejamos garantir a execuo de algum cdigo
de limpeza do mtodo, por exemplo, o
fechamento de arquivos, liberao de conexes de rede ou de banco de dados etc.
Vale ressaltar que existem situaes
excepcionais (!):
O bloco finally no ser executado
se a JVM for encerrada explicitamente
dentro de um bloco try/catch, atravs de
uma instruo System.exit(), por falhas de
hardware ou at mesmo por restries de
acesso a recursos do computador. Tambm existem situaes em que o cdigo
escrito dentro do bloco finally tambm
pode provocar uma exceo.
Se um bloco finally executar um return
ou lanar uma nova exceo, dessa
forma que o mtodo terminar. Se algum
bloco catch do mesmo mtodo tiver sido
executado (lembre que isso acontece
antes do finally) e tiver retornado outro
valor, ou gerado outra exceo, este valor
ou exceo sero simplesmente ignorados.
Isso pode ser bastante confuso; portanto
recomenda-se evitar instrues return ou
throw em blocos finally.

Hierarquia de excees

A Figura 1 mostra algumas classes importantes na hierarquia de erros e excees


de Java. A classe Throwable a superclasse
para todas as classes de erros e excees
em Java. A partir dela, temos as classes
Error e Exception, e cada uma possui uma
ramificao (veja nos links um site onde
voc pode ver uma rvore extensa de
excees do Java).

Categorias de excees

Em Java, podemos separar as excees


em duas categorias: checked (checadas) e
unchecked (no-checadas).

Checked exceptions
As classes de excees checadas so
der ivada s de Exception, ma s no de
RuntimeException. O cdigo a seguir mostra
um mtodo declarando uma exceo checada (NumberFormatException uma subclasse
direta de Exception):
public int stringToInt(String value)
throws NumberFormatException{ . . };
Ao chamar o mtodo stringToInt() do
exemplo, o desenvolvedor obrigado a
tratar a exceo NumberFormatException. Caso
contrrio, um erro de compilao ser
apontado. Isso acontece devido presena
da clusula throws declarada no mtodo, e
porque NumberFormatException checada.
Note que, com isso, a responsabilidade
de tratar a exceo passa a ser de quem vai
utilizar o mtodo e no de quem o codificou.

Em suma, as excees checadas sempre


obrigam ao desenvolvedor estabelecer uma
poltica para o tratamento de excees, seja
utilizando try/catch, seja propagando-a
atravs da clusula throws.
Unchecked exceptions
A categoria das excees no-checadas
inclui as excees que no derivam de
Exception (nem mesmo indiretamente), e
as que derivam de RuntimeException (veja a
Figura 1). Excees unchecked so imprevistas num sentido mais amplo: no
devem ocorrer nem mesmo em cenrios
anormais previsveis pelo desenvolvedor,
tais como a entrada de dados invlidos.
Dito de outra forma, a ocorrncia de uma
exceo unchecked quase sempre indica
um bug da aplicao.
Por exemplo, imagine um mtodo que re-

Listagem 1. Estrutura bsica para o tratamento de excees


try{
/* cdigo que pode lanar uma exceo. */
}
catch (StringIndexOutOfBoundsException e){
/* tratamento da exceo mais especializada */
}
catch (ArrayIndexOutOfBoundsException e){
/* tratamento da exceo mais especializada */
}
catch (IndexOutOfBoundsException e){
/* tratamento da exceo geral */
}
catch (Exception e){
/* tratamento da exceo mais geral */
}
finally{
/* trecho de cdigo que sempre vai ser executado
(exceto se a JVM for encerrada antes) */
}

Listagem 2. Tratamento de excees errado porque no obedeceu a hierarquia de excees


try{
/* cdigo que pode lanar uma exceo. */
}
catch (Exception e){
/* tratamento da exceo mais geral */
}
/* Erro de compilao neste ponto porque Exception j engloba a IndexOutOfBoundsException */
catch (IndexOutOfBoundsException e){
/* tratamento da exceo mais especfica */
}

Edio 51 Java Magazine

49

Tratamento de Excees na Prtica

cebe uma String como argumento e retorna


os trs primeiros caracteres dessa String:
public String getPrefixo(String texto){
return value.substring(0,3);
}

Aparentemente, no h nada de errado neste mtodo, mas o fato que o


mtodo getPrefixo() falha em no validar
o valor recebido. Se este mtodo receber um null para texto, ele ir lanar
uma NullPointerException; se receber uma
string vazia, lanar StringIndexOutOfBounds
Exception. Ambos os casos so bugs do
mtodo getPrefixo(), e no deveriam ocorrer
em nenhuma circunstncia.
Algum at poderia argumentar que o
bug est no cdigo que invocou getPrefixo(),
por ter passado um parmetro ilegal. Mas
seguindo boas prticas da orientao
a objetos, cada mtodo deve assumir
a responsabilidade pela validao dos
dados que recebe. Veja ento uma reviso do mtodo, lanando uma exceo
no-checada:
/**
* Obtm o prefixo do valor.
* @param value String no-nula, com pelo menos 3 caracteres.
*/
public String getPrefixo(String value) {
if (value == null)
throw new IllegalArgumentException
("Argumento nulo");
if (value.length() < 3)
throw new IllegalArgumentException
("Tamanho do argumento menor que 3");
return value.substring(0,3);
}

50 Java Magazine Edio 51

Figura 1. rvore parcial de excees em Java.


importante entender que, nos dois
casos, a chamada do mtodo getPrefixo()
passando argumentos invlidos continuar dando erro. No h como evitar isso.
Porm o novo cdigo melhor, porque
gera uma exceo mais especfica e com
uma mensagem de erro mais clara. Alm
disso, tambm importante documentar
os valores vlidos para o parmetro.
Como as excees no-checadas costumam indicar bugs, pssimo hbito tratlas com catch. No existe motivo defensvel
para se tolerar, por exemplo, um mtodo
que gera uma NullPointerException. Mas nem
todas as excees checadas so iguais. No
exemplo, tratamos excees de baixo nvel como NullPointerException, mas emitimos uma IllegalArgumentException
que tambm unchecked. Esta exceo pelo menos de mais alto
nvel: no s indica a causa
do problema, mas tambm
o localiza melhor, pois deixa
claro que o bug est no mtodo que passou o parmetro ilegal para getPrefixo() e
no no mtodo que recebeu
estes parmetros e emitiu a
exceo. Ainda assim, uma

exceo que nunca deve ocorrer em um


programa sem bugs.

Polmica sobre as checked exceptions


Atualmente, existe certa polmica entre
os desenvolvedores sobre a real necessidade das checked exceptions. Algumas
linguagens de programao, tais como
com C++, C# e Python, s possuem as
unchecked exceptions; Java foi a primeira
a adotar as do tipo checked.
Apesar de a Sun recomendar as checked exceptions sempre que criarmos
excees customizadas (especialmente
de nvel de aplicao coisas como
ChequeSemFundosException etc.), alg uns
autores afirmam que as checked exceptions atrapalham mais do que ajudam.
O problema que as elas foram o
tratamento da exceo e certos desenvolvedores, apenas para evitar um erro
de compilao, terminam mascarando
o problema, por exemplo escrevendo
clusulas catch vazias. Mas no justo
julgar um recurso da linguagem a partir de cdigo que o usa de forma errada!
como dizer que a obrigatoriedade do
uso de cintos de segurana ruim porque algum pode sair dirigindo bbado

a 200 km/h e se julgar seguro porque


est com o cinto.
Uma crtica mais vlida que s vezes
difcil decidir se uma exceo deve ser
checked ou unchecked, e esta deciso nem
sempre feita corretamente. Por exemplo,
certas excees das APIs do Java, como
RemoteException, so muito criticadas pela
sua tendncia em poluir o cdigo. Mas
se voc concorda com esta crtica, isso
apenas quer dizer que os designers destas
APIs cometeram um erro, e talvez estas
excees deveriam ter sido unchecked.
De qualquer maneira, isso no significa
que o recurso no seja correto e til para
muitos outros casos.

Neste caso muito comum, o programador, por ser obrigado a tratar a exceo,
apenas registra no console o erro ocorrido, atravs do mtodo printStackTrace() da
classe Exception. Apesar de ser melhor que
o caso anterior, pois a informao sobre
o erro no perdida, provavelmente o
usurio no vai tomar conhecimento do
que aconteceu (a no ser que o programa
tenha interface de linha de comando, ou
que a sada do console seja interceptada
por um arquivo de log).

Evitando armadilhas

Neste caso, o programador se livra das


reclamaes do compilador, passando
a responsabilidade do tratamento da
exceo para quem vai chamar o mtodo executar(). Aparentemente no h
nada de errado nisso, mas a pergunta
que precisamos fazer : ser que essa
responsabilidade no mesmo desse
mtodo? Note que quem implementou
processar() tambm passou a responsabilidade para cima!
No proibido usar clusulas throws
para passar adiante a responsabilidade
pelo tratamento de uma exceo, mas
isso no deve ser feito pelo motivo errados, como a preguia de escrever um
bloco try/catch.

Vamos explorar alguns trechos de cdigo


comumente encontrados em aplicaes
Java e que devem ser evitados para que
tenhamos um controle eficiente de excees. Mostramos um pequeno trecho
para cada situao e o comentamos em
seguida. Nos exemplos, vamos considerar
que o mtodo processar() pode lanar uma
exceo checada.

Bloco catch vazio

public void executar() {


try{
processar();
}
catch (Exception e){ }
}

Esse o mais perigoso dos casos. O programador mascara a exceo apenas para
se livrar das mensagens do compilador.
Dessa forma, se o mtodo processar() lanar
uma exceo, nada vai acontecer, e o programa vai continuar funcionando como
se nada de errado tivesse acontecido. Bugs
da aplicao podem ser mascarados, e se
acontecerem em produo, voc no ter
nem mesmo uma mensagem ou log de erro
para ajud-lo a diagnosticar o problema.

Bloco com printStackTrace()


public void executar() {
try{
processar();
}
catch (Exception e){
e.printStackTrace();
}
}

Transferncia de responsabilidade
public void executar() throws Exception {
processar();
}

Boas prticas

Podemos tornar nossas aplicaes mais


robustas e fceis de manter quando evitamos as armadilhas impostas pelo mecanismo de excees do Java. Vejamos algumas
boas prticas em resumo.
No use excees para controlar o fluxo
do programa. Excees devem ser usadas
para tratar situaes anormais.
Para decidir quando usar excees
checadas ou no, responda s seguintes
perguntas: a exceo pode acontecer
numa execuo normal do cdigo (sem
bugs)? O usurio precisa ser informado
sobre o problema para que alguma ao
seja tomada? Se responder sim a alguma
dessas perguntas, utilize uma exceo
checada.
Nunca ignore as excees. Quando um

mtodo provocar uma ou vrias excees,


trate-as efetivamente, sem cair nas armadilhas citadas no tpico anterior.
Faa o log das excees que podem
indicar bugs.

Concluses

Apresentamos neste artigo alguns pontos importantes sobre a manipulao de


excees conceitos e exemplos que nos
ajudam a entender melhor o mecanismo
fornecido pelo Java. O tratamento de excees pode parecer primeira vista uma
tarefa cansativa e desinteressante, mas as
situaes que geram excees so uma
realidade inevitvel para a maioria das
aplicaes. E voc pode ter certeza que teria bem mais trabalho para lidar com erros
e situaes imprevistas, de forma robusta,
numa linguagem que no possusse uma
facilidade de tratamento de erros sofisticada como a do Java.

java.sun.com/docs/books/tutorial/
essential/exceptions
Tutorial sobre controle de excees fornecido
pela Sun Microsystems.
java.sun.com/j2se/1.5.0/docs/api/index.html
Hierarquia do pacote java.lang completa.
java.sun.com/docs/books/tutorial/essential/
exceptions/runtime.html
A controvrsia das checked exceptions.

Andr Diniz
(andre.l.diniz-politec@hsbcglt.com.br)
bacharel em Cincia da Computao (UNIFACS Universidade Salvador), e atualmente Software Analyst do
HSBC Global Technology Brazil.Tambm ps-graduado
em Sistemas de Informao com nfase em Componentes
Distribudos e Web, pela Faculdade Ruy Barbosa.

Edio 51 Java Magazine

51

Sistemas Multiagentes
Usando agentes inteligentes com a plataforma

uso aplicado da computao tem


possibilitado criar entidades
artificiais inteligentes, capazes
de tomar decises de forma autnoma
e independente. Hoje comum ouvirmos falar de sistemas especialistas ou
inteligentes e essa definio est normalmente associada ao desenvolvimento de
programas capazes de aprender com o
ambiente em que so inseridos. Sistemas
crticos e complexos so candidatos tpicos aplicao da inteligncia artificial e,
nesse domnio, podemos destacar o uso de
sistemas multiagentes.
possvel tambm utilizar essas tcnicas
em atividades do dia-a-dia, construindo solues elegantes e eficazes, em situaes que
exijam certo nvel de aprendizagem automtica. Atualmente, a principal plataforma
open source disponvel para a construo de
aplicaes multiagentes o JADE, que conta

52 Java Magazine Edio 51

com uma comunidade ativa de usurios.


Nesse artigo, exploraremos a API da
plataforma JADE, que envolve uma arquitetura de comunicao e de mensagens e
suporta as principais caractersticas de
sistemas especialistas. Comeamos com
uma breve introduo ao mundo dos
agentes inteligentes.

Desmistificando os agentes
Podemos definir um agente inteligente
como um sistema de computao capaz de
interagir em algum ambiente e de realizar
aes de forma autnoma (dependendo
apenas das informaes que o agente
possui no momento) para atingir seus
objetivos. Normalmente, agentes possuem
caractersticas tanto reativas (aes provocadas pelo ambiente) como proativas
(aes voluntrias do agente). So tambm
adaptativos e orientados a objetivos.

Entretanto, normalmente um agente no


atua de forma isolada. Cada agente possui
tarefas especficas dentro de um conjunto
maior de atividades. Baseado nisso, podemos pensar em um sistema multiagentes
como um conjunto de agentes especialistas
em determinadas tarefas, interagindo para
buscar um objetivo especfico.
A Figura 1 apresenta o comportamento
bsico de um agente. Atravs de um sensor
de entrada, o agente capaz de capturar
estmulos do ambiente em que est inserido e reagir a partir de um conjunto de
aes pr-definidas.
Um bom exemplo do uso de agentes
um sistema de diagnstico mdico. Esse
sistema recebe como entrada os sintomas
do paciente e respostas a vrias perguntas
definidas por um profissional de sade, e
prope um diagnstico e um tratamento
adequado com base em um histrico de

em Java

Aprenda a desenvolver
sistemas flexveis com
Java utilizando o conceito
de agentes inteligentes,
usando a API e plataforma
open source JADE

JADE

Ricardo Marques Porto


informaes anteriores. Os agentes so
capazes, atravs de tarefas especializadas e
coordenadas, de encontrar uma soluo tima baseando-se nas entradas que recebem.
Nesse caso, pacientes e o hospital so parte
do ambiente do sistema e as questes, testes
e tratamentos so as aes do agente.

Agentes aplicados
O uso de agentes est longe de ser algo
puramente acadmico e sem aplicao
comercial. Agentes j so aplicados em diversas reas e podem tirar grande proveito
de ambientes distribudos como a Internet.
Diversas aplicaes peer-to-peer (P2P), baseadas em tecnologia de agentes vm sendo
usadas e desenvolvidas durante os ltimos
anos, impulsionadas pelo aumento na
largura de banda de transmisso e apostando, por exemplo, nos relacionamentos
virtuais. Outras aplicaes tpicas que
esto inseridas neste contexto so sistemas
baseados em e-learning e e-commerce.
Na rea de aplicaes mveis, podemos
destacar ainda servios de busca e localizao, como encontrar o estacionamento mais
prximo e mais barato, ou fazer reserva em
um restaurante de acordo com as preferncias do usurio. H tambm aplicaes no
ambiente corporativo. Agentes inteligentes
tm obtido sucesso em reas desde sistemas
para gesto do conhecimento, at em aplicaes de suporte deciso, passando por
controle industrial, e sistemas de logstica e
de gerenciamento de trfego de rede.

A FIPA (Foundation for Intelligent Physical


Agents) tem como objetivo a promoo de tecnologias e especificaes de interoperabilidade que
facilitem a comunicao e o trabalho fim-a-fim
entre agentes inteligentes, em aplicaes comerciais e industriais.

A Listagem 1 apresenta a estrutura bsica de um agente construdo com o JADE.


A criao de um agente com JADE
to simples quanto estender a classe
jade.core.Agent e implementar o mtodo
setup(). O objetivo desse mtodo inicializar
os recursos e comportamentos do agente e
chamado pelo runtime do JADE (veja mais
no quadro Agentes e comportamentos)
Alm da i n icializao, no mtodo
setup(), o agente pode disponibilizar seus

Figura 1. Comportamento bsico de um agente

Listagem 1. Estrutura bsica de um agente


package br.com.javamagazine.exemplo;
import jade.core.Agent;
import jade.core.behaviours.Behaviour;
public class ExemploEstruturaAgente extends Agent {
@Override
protected void setup() {
/*Nesse mtodo o agente pode disponibilizar seus
servios para outros atravs de uma publicao
no diretrio de servios da plataforma e pode
buscar servios especficos disponibilizados
por outros agentes, dentre outras atividades.*/
}
@Override
protected void takeDown() {
/*Aqui ficam cdigos de limpeza para serem
executados quando o agente est sendo finalizado.*/
}
private class AlgumComportamento extends Behaviour {
@Override
public void action() {
/*Executa atividades especializadas e/ou se
comunica com outros agentes atravs de mensagens. */
}

O cdigo de um agente com JADE


O JADE (Java Agent DEvelopment Framework) um framework open source
em Java que simplifica a implementao
de sistemas multiagentes, atravs de um
conjunto de funcionalidades que atende s
especificaes da Fundao para Agentes
Inteligentes Fsicos (FIPA), seguindo uma
abordagem P2P.

servios para outros agentes atravs da


publicao em um diretrio de servios.
Pode tambm buscar servios especficos
publicados por outros agentes, para completar suas atividades.
O mtodo takeDown(), da classe Agent, invocado imediatamente antes do trmino de

@Override
public boolean done() {
boolean condicaoTermino = false;
//Faz uma avaliao da condio de trmino...
return condicaoTermino;
}

Edio 51 Java Magazine

53

Sistemas Multiagentes em Java

execuo de um agente, geralmente executa


operaes de limpeza. Os mtodos action() e
done() fazem parte do ciclo de vida do comportamento de um agente e sero melhor
compreendidos nos exemplos posteriores.

Arquitetura
Com o JADE, o conjunto de agentes pode
ser distribudo em vrias mquinas e sua
configurao pode ser controlada atravs
de uma interface remota. H tambm
a possibilidade de mover agentes entre
mquinas virtuais em hosts diferentes,
permitindo balanceamento de carga. Com
isso, um agente pode parar a execuo e
migrar para outro host, sem a necessidade
de prvia instalao do agente. O nico
requisito para o uso do JADE a instalao
de uma JRE 1.4 ou superior.
O desenvolvimento utilizando a API do
JADE baseado na construo de POJOs
(classes Java comuns), permitindo o reuso
com outras tecnologias Java. Boa parte
da complexidade envolvida no JADE fica
por conta da plataforma. Assim, uma
abstrao simplificada apresentada ao
desenvolvedor para facilitar o entendi-

mento e a implementao.
A arquitetura de comunicao do JADE
flexvel e ela quem gerencia as mensagens de cada agente, permitindo o acesso
a essas mensagens de vrias formas.
utilizada a notificao de eventos, RMI e
IIOP, e h recursos para integrao a outros
protocolos, como HTTP.

Funcionamento do JADE
O JADE d o suporte aos servios bsicos
necessrios a aplicaes P2P distribudas
em ambientes fixos e mveis. Os agentes
utilizam esse suporte para disponibilizar
servios e descobrir dinamicamente outros
agentes para estabelecer uma interao.
A comunicao acontece atravs da troca
de mensagens assncronas. Em conseqncia disso, no existe uma dependncia
temporal entre agentes interessados em
trocar informaes.
Cada agente possui seu identificador
nico, representado por uma instncia da
classe jade.core.AID. Esse identificador pode
ser recuperado pelo mtodo getAID() da classe Agent e tem a forma <apelido>@<nomeda-plataforma>:<nmero-da-porta>/JADE,

como neste exemplo:


AgenteFornecedor@home:1099/JADE.

A estrutura de mensagens utilizada est


em conformidade com a linguagem ACL,
definida pela FIPA (veja mais sobre ela
adiante). So disponibilizados, tambm,
esqueletos de padres de interao tpicos
que executam tarefas especficas como
negociao, leilo e delegao de tarefas.
Isso facilita o desenvolvimento, uma vez
que oculta requisitos de sincronizao,
expirao de tempo e condies de erro,
dentre outros.

A plataforma JADE
Cada instncia do runtime do JADE
chamada container. O conjunto desses
containers forma uma plataforma, que
proporciona uma camada homognea,
ocultando a diversidade e a especificidade
de outras camadas da aplicao.
Um container especial, o Main Container,
deve estar sempre ativo de forma nica,
e todos os outros containers devem se registrar nele no momento de inicializao.
Portanto, se um segundo Main Container
inicializado em algum lugar da rede, ele
constituir uma plataforma diferente, onde
novos containers podem ser registrados. A
arquitetura do JADE pode ser visualizada
na Figura 2, onde A1, A2, A3 e A4 representam diversos agentes em execuo.

O Main Container e seus servios

Figura 2. Arquitetura de aplicaes multiagentes com JADE

54 Java Magazine Edio 51

Alm da habilidade de aceitar registros de


outros containers, um Main Container se
diferencia dos outros por manter dois servios parte, inicializados automaticamente. Um deles o Servio de Gerenciamento
de Agentes (SGA), que disponibiliza um
servio de nomes semelhante ao JNDI do
Java EE. O SGA mantm um ndice com
todos os agentes atualmente registrados
e representa uma entidade gerencial na
plataforma. Este servio tambm responsvel pela criao, deleo e migrao de
agentes. O outro servio o de Descoberta
de Diretrios (DD), que funciona como um
servio de pginas amarelas. Atravs dele,
agentes podem encontrar outros agentes
especializados em uma tarefa necessria
para atingir seus objetivos.
Existe ainda o Canal de Comunicao de

Agentes (CCA), um sistema que controla


a troca de mensagens dentro de uma plataforma e entre plataformas remotas. Por
utilizar um mecanismo assncrono de comunicao, o JADE faz uso de uma fila de
mensagens. A linguagem ACL, utilizada
para essa comunicao, bem como alguns
mecanismos relacionados, esto descritos
no quadro Mensagens entre agentes. O
exemplo apresentado a seguir mostra na

prtica o funcionamento dos servios e


mensagens citados.

Codificando
Uma vez apresentados os princpios, a
arquitetura e alguns detalhes de implementao do JADE, chegou a hora de ver
na prtica como tudo funciona.
Vamos usar um exemplo de um sistema de
cadeia de suprimentos. Nele, uma organiza-

o que possui diversos fornecedores pode


fazer a cotao de preo de um produto o
qual tenha interesse em adquirir. A partir
da anlise dos preos ofertados, a aquisio
efetivada. A Listagem 2 apresenta a classe
AgenteCadeiaSuprimento, cuja funcionalidade
bsica buscar fornecedores que possuam
um produto especfico.
Os agentes fornecedores (FornecedorA,
FornecedorB e FornecedorC) so semelhantes.

Agentes e comportamentos

m agente s pode ser til se executa


alguma tarefa especf ica dentro do
contexto de uma aplicao. Na API do JADE,
as tarefas de um agente so tratadas como
um comportamento e so encapsuladas em
uma classe apropriada (jade.core.Behaviour).
Isso permite a separao entre a definio da
estrutura de um agente e os comportamentos
que ele possui.
Para que um agente execute as tarefas implementadas em uma classe Behaviour, basta que
esse comportamento seja adicionado atravs
do mtodo addBehaviour(). Comportamentos
podem ser adicionados a qualquer momento,
embora isso seja feito geralmente na inicializao do agente (mtodo setup()).
Toda classe que estende Behaviour deve implementar o mtodo action(), o qual define as
operaes a serem executadas. O mtodo done()
(que retorna um boolean), tambm deve ser implementado. Ele especifica se um comportamento
completou suas atividades ou no e consequentemente se j pode ser terminado e retirado do
pool de comportamentos de um agente.

Tipos de comportamento
Podemos distinguir trs tipos de comportamentos dentro da plataforma JADE, e todos podem ser
convenientemente estendidos:
OneShotBehaviour Completa imediatamente e
o mtodo action() executado apenas uma vez.
Tem uma implementao do mtodo done() que
sempre retorna true.
CyclicBehaviour Nunca completa e seu mtodo
action() sempre executa as mesmas operaes. Seu
mtodo done() sempre retorna false.
GenericBehaviour Executa diferentes operaes
dependendo de um status interno. Completa
quando uma dada condio verdadeira.
Existe ainda a possibilidade de combinar
comportamentos, mas no vamos detalhar essa

facilidade neste artigo. O diagrama de classes


na Figura Q2 mostra a hierarquia de classes
de comportamento.

Figura Q1. Processo de execuo do agente.

Agendamento e execuo de
comportamentos
Um agente pode executar diversos comportamentos concorrentemente. O agendamento
de comportamentos cooperativo (nopreemptivo). Isso significa que quando um
comportamento agendado para execuo,
seu mtodo action() chamado e executa at
terminar. Portanto, o desenvolvedor quem
define quando um agente troca a execuo de
comportamentos. O processo de execuo de
um agente pode ser descrito como no diagrama
da Figura Q1.

Figura Q2. Classes de comportamento do JADE

Edio 51 Java Magazine

55

Sistemas Multiagentes em Java

Por isso ser apresentado apenas o cdigo


de uma das classes, na Listagem 3. A diferena entre o cdigo desses agentes est
apenas no valor a ser ofertado. Observe
que o uso de trs classes distintas para
representar os fornecedores, apesar de incomum no mundo orientado a objetos, foi
escolhido para simplificar a inicializao
dos agentes no exemplo (sem parmetros).
Note ainda que, para simplificar a compreenso, damos enfoque apenas s funcionalidades da API JADE, deixando alguns
mtodos de negcio incompletos.

Registrando o agente no container


Uma das primeiras atividades de um
agente normalmente o registro de sua

existncia na plataforma. Isso feito


utilizando-se o servio de pginas amarelas do JADE, atravs da classe DFService (o
prefixo DF vem de Directory Facilitator).
Para tanto, utiliza-se o mtodo esttico
register() de DFService, informando o agente
e uma DFAgentDescription que possui uma
ServiceDescription, contendo a descrio do
servio que est sendo publicado.
Essa descrio usada, posteriormente,
por outros agentes na procura de servios
e permite especificar protocolos de comunicao, o tipo do servio e outras propriedades importantes. Nas Listagens 2 e 3,
possvel perceber a tentativa de registro
dos agentes logo no incio do mtodo setup().
Observe que, em caso de fracasso, o agente

imediatamente destrudo, utilizando-se


a chamada ao mtodo doDelete() (herdado
da superclasse Agent e que por padro
executa o mtodo takeDown(), redefinido
no exemplo). O cdigo a seguir, extrado
da Listagem 2 mostra isso:
try {
DFService.register(this,dfd);
} catch (FIPAException e) {
doDelete();
}

Passando argumentos
possvel passar tambm argumentos
na construo de um agente. No exemplo
em questo, o AgenteCadeiaSuprimento recebe
a informao do produto a ser pesquisado,
atravs de um argumento, como pode ser
visto na Figura 5. Esses argumentos so recuperados atravs do mtodo getArguments()
da classe Agent. Observe o trecho de cdigo
a seguir:
Object[] args = getArguments();
if (args != null && args.length > 0) {
produto = (String) args[0];
addBehaviour(new BuscaProdutos());
}

Adicionando comportamentos

Figura 3. Agente sniffer em ao

tambm no mtodo setup() da classe


Agent que os comportamentos so adicionados, usando-se o mtodo addBehaviour().
Mas note que isso no uma regra, j que
comportamentos podem ser adicionados
de outras formas (o quadro sobre comportamentos contm mais informaes).
O nosso agente possui um comportamento personalizado. Por isso, a classe de
comportamento BuscaProdutos deriva diretamente de Behaviour, ao invs de a partir de
uma subclasse com caractersticas especficas. As aes desse agente dependem da
varivel passo. Esta varivel define quando
o comportamento pode ser retirado do
pool de comportamentos1 do agente, j que
o mtodo done() testa seu valor (done() um
mtodo abstrato da classe Behaviour, que
implementado por BuscaProdutos).

Construindo e enviando mensagens


A primeira atividade no mtodo action()

Figura 4. Inicializando um novo agente

56 Java Magazine Edio 51

1 Pool de comportamentos o jargo para o conjunto


de comportamentos que um agente pode apresentar.

buscar todos os fornecedores disponveis.


Para isso utilizado o DFService.search(), de
forma bastante parecida com a que usamos
para se registrar na plataforma. Uma vez
localizados os fornecedores disponveis,
eles so adicionados como destinatrios da
mensagem ACLMessage, do tipo REQUEST.
for (int i = 0; i < resultado.length; ++i) {
fornecedores[i] = resultado[i].getName();
request.addReceiver(fornecedores[i]);
}

Alm disso, o AgenteCadeiaSuprimento informa o produto desejado atravs do contedo


da mensagem enviada aos fornecedores.
request.setContent(produto);

Para identificar as respostas dos fornecedores, utiliza-se um ID de conversao,


que encapsulado pelo mtodo setConvers
ationId(solicitacaoProduto). Posteriormente,
a classe MessageTemplate usada para a
construo de um filtro para as respostas

dos fornecedores. Ela inclui o ID da conversao e uma espcie de timestamp do


remetente encapsulado por setReplyWith().
O envio da mensagem, depois de criada,
feito atravs de send():
request.setConversationId(solicitacaoProduto);
request.setReplyWith(AgenteCadeiaSuprimento+ System.
currentTimeMillis());
myAgent.send(request);

Observe que as classes internas (inner

Listagem 2. AgenteCadeiaSuprimento
package br.com.javamagazine.agentes;
import
import
import
import
import
import

java.util.*;
jade.core.*;
jade.core.behaviours.*;
jade.domain.*;
jade.domain.FIPAAgentManagement.*;
jade.lang.acl.*;

public class AgenteCadeiaSuprimento extends Agent {


private AID[] fornecedores;
private String produto;
@Override
protected void setup() {
DFAgentDescription dfd = new DFAgentDescription();
ServiceDescription sd = new ServiceDescription();
sd.setType(CadeiaSuprimento);
sd.setName(getName());
dfd.setName(getAID());
dfd.addServices(sd);
try {
DFService.register(this, dfd);
}
catch (FIPAException e) {
doDelete();
}
Object[] args = getArguments();
if (args != null && args.length > 0) {
produto = (String) args[0];
addBehaviour(new BuscaProdutos());
}
else {
doDelete();
}
}
@Override
protected void takeDown() {
System.out.println(O agente + getName()
+ esta sendo finalizado.);
}
private class BuscaProdutos extends Behaviour {
private MessageTemplate mt;
private int passo = 0;
private int numeroRespostas = 0;
private int numeroFornecedores = 0;
private Map<AID, String> respostasPositivas =
new LinkedHashMap<AID, String>();
private List respostasNegativas = new LinkedList();
public void action() {
switch (passo) {
case 0:
ACLMessage request =
new ACLMessage(ACLMessage.REQUEST);
DFAgentDescription template =
new DFAgentDescription();
ServiceDescription sd = new ServiceDescription();

sd.setType(Fornecedor);
template.addServices(sd);
try {
DFAgentDescription[] resultado = DFService.search(
myAgent, template);
fornecedores = new AID[resultado.length];
numeroFornecedores = resultado.length;
for (int i = 0; i < resultado.length; ++i) {
fornecedores[i] = resultado[i].getName();
request.addReceiver(fornecedores[i]);
}
}
catch (FIPAException fe) {}
request.setContent(produto);
request.setConversationId(solicitacaoProduto);
request.setReplyWith(AgenteCadeiaSuprimento
+ System.currentTimeMillis());
myAgent.send(request);
mt = MessageTemplate.and(MessageTemplate
.MatchConversationId(solicitacaoProduto),
MessageTemplate.MatchInReplyTo(request.getReplyWith()));
passo++;
break;
case 1:
ACLMessage reply = myAgent.receive(mt);
String valor = null;
if (reply != null) {
if ((reply.getPerformative() == ACLMessage.INFORM)
|| (reply.getPerformative() == ACLMessage.REFUSE))
{
valor = reply.getContent();
if (reply.getPerformative() == ACLMessage.INFORM) {
respostasPositivas.put(reply.getSender(), valor);
}
else {
respostasNegativas.add(reply.getSender());
}
numeroRespostas++;
if (numeroRespostas == numeroFornecedores) {
// Recebeu todas as respostas e processa informaes.
passo++;
break;
}
}
}
else {
block();
}
break;
}//Fim do switch
}//Fim do mtodo action()
public boolean done() {
System.out.println(Passo: + passo);
return (passo == 2);
}
}//Fim da classe BuscaProdutos
}//Fim da classe AgenteCadeiaSuprimento

Edio 51 Java Magazine

57

Sistemas Multiagentes em Java

classes) BuscaProdutos (na Listagem 2) e


CotacaoPrecoProduto (na Listagem 3), referenciam as classes dos agentes que as
possuem, atravs do atributo myAgent. Esse
atributo herdado da classe Behaviour.
Para receber as mensagens de resposta,
o mtodo receive() verifica se h mensagens na fila, utilizando o MessageTemplate
criado. Caso negativo, o agente bloqueia e
s volta a executar quando chega alguma
mensagem. Caso positivo, trata a mensagem e verifica se todos os fornecedores
j responderam solicitao de preo do
produto. Novamente, se ainda existirem
fornecedores pendentes, o agente bloqueia
e aguarda as respostas restantes. Quando todas as respostas dos fornecedores
chegam, a varivel passo incrementada e

done() retorna true, encerrando as atividades


previstas no comportamento do agente.
ACLMessage reply = myAgent.receive(mt);
...
if(reply.getPerformative() == ACLMessage.INFORM){
respostasPositivas.put(reply.getSender(), valor);
} else {
respostasNegativas.add(reply.getSender());
}
numeroRespostas++;
if(numeroRespostas == numeroFornecedores){
// Recebeu todas as respostas e processa informaes.
passo++;
break;
}

O comportamento dos fornecedores pode


ser caracterizado como cclico. Observe
que a classe CotacaoPrecoProduto, implementada como classe interna, estende
CyclicBehaviour. O comportamento padro

Mensagens entre agentes


oda a comunicao entre agentes feita
atravs da troca de mensagens, cuja
representao baseada na Linguagem de
Comunicao de Agentes (ACL na sigla em
ingls), formulada pela FIPA. A Figura Q1
ilustra a estrutura de uma mensagem nesse
padro.
Mensagens ACL possuem um conjunto de
elementos que especificam atributos. Alguns
destes so:
performative Tipo de ao executada.
sender Remetente da mensagem.
receiver Destinatrio da mensagem.
reply-to Destinatrio da resposta.
content Contedo da mensagem.
conversation-id Identificador de um dilogo entre agentes.
Algumas possveis aes, indicadas no atributo performative, so:
accept-proposal Aceita uma proposta submetida previamente.
agree Concorda com a execuo de alguma

58 Java Magazine Edio 51

Ambiente de execuo
A execuo do exemplo na plataforma
JADE simples. necessrio apenas
ter uma JRE instalada (superior a 1.4) e
adicionar ao classpath o projeto, que est
disponvel para download no site da revista, assim como os seguintes JARs: http.
jar, iiop.jar, jade.jar e jadeTools.jar (includos
na distribuio binria do JADE). Depois
disso, basta executar o comando a seguir,
em uma linha:
java jade.Boot -gui
FornA:br.com.javamagazine.agentes.FornecedorA
FornB:br.com.javamagazine.agentes.FornecedorB
FornC:br.com.javamagazine.agentes.FornecedorC
Sniffer:jade.tools.sniffer.Sniffer(FornA; FornB; FornC)

Figura 5. Informando os dados de um novo agente

desses agentes aguardar uma solicitao


de preo, verificar a disponibilidade do
produto e informar o preo ou recusar a
solicitao. Para isso, so utilizados dois
tipos de mensagem: INFORM e REFUSE.
Outro ponto que merece ser mencionado
a forma como a resposta criada pelo fornecedor, atravs do mtodo createReply(). Assim,
parte dos dados aproveitada da requisio,
diretamente, para a criao da resposta.

Esse comando (que est includo em

ao no futuro.
cancel Cancela alguma ao requisitada
previamente.
failure Informa outro agente a respeito da
falha de alguma ao.
inform Transmite alguma informao (geral)
ao destinatrio.
not-understood Informa ao destinatrio que
a mensagem no foi compreendida.
query-if Questiona outro agente se uma
dada proposio verdadeira.
request Requisita ao destinatrio a execuo de alguma ao.

Figura Q1. Estrutura de mensagem do padro FIPA (ACL)

Figura 6. Analisando dados de uma mensagem transmitida

um .bat nos downloads) ir inicializar


a plataforma usando uma ferramenta
grfica, criar os agentes fornecedores e
ativar o sniffer (que tambm um agente
disponibilizado junto com a plataforma).
O sniffer ativado para que a troca de
mensagens possa ser visualizada. A tela
do sniffer, aps a execuo do exemplo,
pode ser vista na Figura 3.
Tendo o ambiente em operao e os
for necedores dispon veis, o agente

AgenteCadeiaSuprimento pode ser inicializado


tambm, como mostram as Figuras 4 e 5.
preciso passar um parmetro (o nome do
produto solicitado) para que o agente seja
construdo corretamente.
Devemos, claro, inicializar os fornecedores antes, j que no momento de execuo do AgenteCadeiaSuprimento, ele buscar
algum fornecedor disponvel para suprir
a demanda de um produto. No prompt
podem ser observadas mensagens de log,

Listagem 3. Cdigo de um dos fornecedores


package br.com.javamagazine.agentes;
// ...imports
public class FornecedorA extends Agent {
@Override
protected void setup() {
DFAgentDescription dfd = new DFAgentDescription();
ServiceDescription sd = new ServiceDescription();
sd.setType(fornecedor);
sd.setName(getName());
dfd.setName(getAID());
dfd.addServices(sd);

try {
DFService.register(this, dfd);
}
catch (FIPAException e) {
doDelete();
}
addBehaviour(new CotacaoPrecoProduto());

@Override
protected void takeDown() {
System.out.println(O agente + getName()
+ est sendo finalizado.);
}
private class CotacaoPrecoProduto extends CyclicBehaviour {
private MessageTemplate mt;
public void action() {
mt = MessageTemplate.MatchConversationId(solicitacaoProduto);
ACLMessage request = myAgent.receive(mt);

if (request != null) {
String produto = request.getContent();
ACLMessage reply = request.createReply();
String valor = recuperaCotacaoProduto(produto);
if (valor != null) {
reply.setPerformative(ACLMessage.INFORM);
reply.setContent(valor);
}
else {
reply.setPerformative(ACLMessage.REFUSE);
reply.setContent(FornecedorA --> Nao temos o produto);
}
myAgent.send(reply);
}
else {
block();
}

private String recuperaCotacaoProduto(String produto) {


/* Para simplificar, retornamos apenas um valor fixo. */
String valor = R$ 150,00;
return valor;
}

indicando as atividades e a troca de mensagens entre os agentes. A Figura 6 mostra


os dados de uma ACLMessage que contm a
resposta de um fornecedor, transmitida
durante a execuo do exemplo.
As ferramentas disponveis com a
plataforma JADE, como se v, permitem
controle total do ambiente para fins de
depurao. possvel visualizar graficamente tudo que acontece entre os agentes
em tempo de execuo.

Concluses
O potencial de um sistema multiagentes
vai muito alm do que foi apresentado
nesse artigo. O objetivo aqui foi mostrar
o funcionamento bsico da plataforma
e da API do JADE e dar as bases para o
leitor explorar essa interessante rea do
desenvolvimento de software.
Sistemas mais sofisticados lidam com APIs
e tecnologias que abstraem mquinas de
inferncia, protocolos de interao e estruturas de informaes. Algumas delas como
Jess e Jena, bem como o uso de ontologias,
permitem definir relacionamentos complexos e realizar tarefas muito especializadas,
de forma extremamente distribuda. Mesmo
assim, fcil perceber que abordagens como
a apresentada esto prximas das nossas tarefas e desafios dirios e que podemos tirar
proveito delas para construir sistemas mais
eficientes e flexveis.

www.fipa.org
Pgina principal da FIPA
jade.tilab.com
Pgina principal do JADE
www.agentcities.org
Pgina sobre pesquisas em sistemas multiagentes
www.agentlink.org
Pgina sobre pesquisa em tecnologia de agentes
em geral
Ricardo Marques Porto
(correiodoricardo@gmail.com)
consultor da Summa Technologies, mestrando em informtica
pela Universidade de Braslia na rea
de Sistemas Inteligentes e ps-graduado pela Fundao Getlio Vargas em Administrao Estratgica de
Sistemas de Informao.

Edio 51 Java Magazine

59

Portlets com JBoss Portal


Explorando conceitos de portlets e criando

ortais trazem uma infra-estrutura


centralizada de servios para aplicaes web e corporativas, ainda
que estes servios estejam em diferentes
servidores ou mesmo usem tecnologias
distintas. Todos os elementos de um portal
geralmente so reunidos em uma nica
viso, no estilo de pginas como java.net,
globo.com etc. Dentro da tecnologia Java,
dado o nome de Portlet a cada um dos
pequenos componentes ou peas exibidos nessas pginas. Neste artigo, vamos
apresentar a construo e o uso de portlets
de forma aplicada, tratando dos conceitos
necessrios medida que desenvolvemos
um exemplo de portlet que ser hospedado
no JBoss Portal.

JSRs e containers

Os Portlets so o resultado da JSR (Java


Specification Request) 168, a Portlet Specification, que foi finalizada em outubro de
2003. Com quase cinco anos de existncia,
este um padro estabelecido, contando
com muitas implementaes, tanto open
source como proprietrias.
Com o passar dos anos e a evoluo do
mercado de portais, no entanto, foram
sendo identificadas lacunas no supridas
pela JSR-168. Alguns fornecedores comearam ento a resolver essas deficincias
por sua conta, levando perda de portabilidade entre os Containers de Portlets.
Isto motivou a criao, no incio de 2006,
da JSR-286 (Portlet Specification 2.0), que

visa preencher tais lacunas. Embora esta


JSR ainda esteja em draft, alguns recursos
como Web Services for Remote Portlets e o
suporte a Ajax previstos na especificao j
esto presentes em algumas implementaes de containers de portlets do mercado.
Entre eles est o JBoss Portal.

Realizando o download do JBoss Portal

Utilizaremos a verso 2.6.1 do JBoss


Portal, o release estvel mais recente no
momento de escrita. V at a pgina de download (labs.jboss.com/jbossportal/download)
e escolha a opo JBoss Portal+JBoss AS
4.2.1. Este download inclui o container de
portlets pr-configurado, juntamente com
o servidor JBoss Application Server.
A verso atual do JBoss Portal roda apenas
sobre o JBoss AS, mas nas prximas verses est
previsto que poder ser executado em qualquer
outro servidor de aplicaes aderente especificao Java EE.

O processo de instalao similar ao de


outras aplicaes em Java: basta descompactar o arquivo ZIP em alguma pasta e
tudo estar pronto. Para executar o JBoss
Portal, v at a pasta <jbportal>/bin e
execute ./run.sh para Linux ou run.bat no
caso do Windows. (Nos paths indicados
neste artigo, <jbportal> representa a pasta
onde voc descompactou a distribuio
do JBoss Portal.)
Aps a inicializao, visite o endereo
http://localhost:8080/portal. Se voc vir uma
pgina de boas vindas, isso significa que
seu ambiente est pronto para fazermos o
deploy de nossos portlets e configur-los.

Estados e modos de visualizao

No nvel de programao, um portlet um


componente web criado em Java que processa requisies e devolve respostas. Essas
respostas so chamadas de fragmentos e

60 Java Magazine Edio 51

um portlet completo

Saiba como construir de


forma simples portlets
para portais corporativos
em Java utilizando APIs
padres de mercado

Edgar A. Silva
podem ser formatadas atravs de diversas
linguagens de marcao, por exemplo
HTML e WML. Cada portlet pode ter um
contexto parte, em que trata suas variveis
e outras informaes de forma particular;
tem tambm a capacidade de interagir
com o contexto do container de portlets e,
atravs deste, com outros portlets.
A especificao de Portlets determina que
um portlet pode estar em trs estados:
VIEW Estado padro, em que apresentado o contedo do portlet.
EDIT Para edio de preferncias/configuraes do portlet. Alteraes nessas
configuraes geralmente tm impacto
sobre o que mostrado no modo VIEW.
HELP Fornece uma visualizao de
ajuda para o usurio do portlet.
H tambm trs modos de visualizao
definidos, similares aos que temos em
janelas de sistemas operacionais:
NORMAL Nesta visualizao, o portlet
compartilha o espao com outros portlets, obedecendo sua posio e tamanho
definidos.
MINIMIZED O portlet aparece minimizado, na maioria das vezes sendo mostrada
apenas a sua barra de ttulo .
MAXIMIZED O portlet expandido como
se fosse o nico portlet da pgina, escondendo todos os outros.
Estes modos de visualizao so indicados por cones no topo dos espaos reservados para os portlets, reforando a idia
de que funcionam como mini-aplicaes.

Criando um projeto de portlets

Como exemplo, vamos criar um portlet


que permite postar blogs no site de blogs
WordPress (wordpress.org). O WordPress
criado em PHP, mas expe um servio
baseado em XML-RPC para integrao
com outras aplicaes. Nosso portlet vai se

Listagem 1. conf.jsp
<%@ taglib uri=http://java.sun.com/portlet prefix=portlet %>
<portlet:defineObjects/>
<h2>WordPress Portlet</h2>
<hr size=1>
<h3>Dados do Blog</h3>
<form action=<portlet:actionURL/>>
<table border=0>
<tr>
<td>Endereco do Site WordPress:</td>
<td><input type=text name=url
value=<%=request.getAttribute(WORDPRESS_URL)%> size=40 />
</td>
</tr>
<tr>
<td>Usuario:</td>
<td><input type=text name=usuario
value=<%=request.getAttribute(USER)%> size=20 />
</td>
</tr>
<tr>
<td>Senha:</td>
<td><input type=password name=senha value= size=20 /></td>
</tr>
<tr>
<td></td>
<td> <input type=submit value=Salvar name=op /> </td>
</tr>
</table>
</form>

Listagem 2. post.jsp
<%@ taglib uri=http://java.sun.com/portlet prefix=portlet %>
<portlet:defineObjects/>
<h2>WordPress Portlet</h2>
<hr size=1>
<h3>Escreva aqui seu Post:</h3>
<table>
<tr class=portlet-msg>
<td colspan=2>
<%= request.getAttribute(message) != null ?
request.getAttribute(message) : %></td>
</tr>
</table>
<form action=<portlet:actionURL/>>
<table border=0>
<tr>
<td></td>
<td><p>Titulo:</p>
<p> <input type=text name=titulo value= size=60 /> </p> </td>
</tr>
<tr>
<td></td>
<td> <p>Texto:</p> <p><textarea name=post rows=20 cols=50>
</textarea> </p> </td>
</tr>
<tr>
<td></td>
<td> <input type=submit value=Publicar name=op /> </td>
</tr>
</table>
</form>

Edio 51 Java Magazine

61

Portlets com JBoss Portal

comunicar com esse servio e a partir dele


poderemos publicar qualquer post.
Para construir o aplicativo, vamos deixar
para sua escolha o IDE, e utilizaremos o
Ant como ferramenta de build. O ZIP com
o cdigo do exemplo contm o arquivo
build.xml. A estrutura do projeto, que chamamos de wordpress-portlet, ser como
na Figura 1. No build.xml, voc deve alterar
as informaes da propriedade portal.deploy.
dir para indicar o diretrio de deploy do

JBoss Portal no seu sistema (geralmente,


<jbportal>\server\default\deploy). Feito
isso, voc poder usar o comando ant para
realizar todas as tarefas de compilao,
empacotamento e deploy do exemplo.

Mais sobre a API

A classe javax.portlet.GenericPortlet a que


seus portlets por padro iro estender. Ela
implementa a interface javax.portlet.Portlet,
que define alguns mtodos importantes

Listagem 3. Classe BlogInfo.java


package jm.portlet.wordpress;
public class BlogInfo {
private String apiKey;
private String userName;
private String password;
private String blogId;
private String content;
// ... Mtodos get/set

public BlogInfo(String apiKey, String userName, String password, String blogId) {


this.apiKey = apiKey;
this.userName = userName;
this.password = password;
this.blogId = blogId;
}

Listagem 4. Classe BlogPoster.java


package jm.portlet.wordpress;
import java.io.IOException;
import java.util.Vector;
import org.apache.xmlrpc.XmlRpcClient;
import org.apache.xmlrpc.XmlRpcException;
public class BlogPoster {
private static final String POST_METHOD_NAME = blogger.newPost;
private XmlRpcClient client;
private BlogInfo blogInfo;
private PostType postType = PostType.draft;
public BlogPoster(XmlRpcClient client, BlogInfo blogInfo) {
this.client = client;
this.blogInfo = blogInfo;
}
public void setPostType(PostType postType) {
this.postType = postType;
}
@SuppressWarnings(value = unchecked)
public Integer post(String contents) throws XmlRpcException, IOException {
Vector v = new Vector();
v.add(blogInfo.getApiKey());
v.add(blogInfo.getBlogId());
v.add(blogInfo.getUserName());
v.add(blogInfo.getPassword());
v.add(contents);
v.add(postType.booleanValue());
return (Integer) client.execute(POST_METHOD_NAME, v);
}
public static enum PostType {
publish(true), draft(false);
private final boolean value;
PostType(boolean value) {
this.value = value;
}
public boolean booleanValue() {
return value;
}
}
}

62 Java Magazine Edio 51

para gerncia de ciclo de vida, interao


dos portlets com o container e outras atividades. Veja alguns mtodos comumente
implementados em uma classe de potlet:
init(PortletConfig config) Este mtodo chamado logo depois da classe do
portlet ser instanciada, e somente uma
vez. o mtodo apropriado para carregar
recursos necessrios para o funcionamento do portlet, relacionados a banco
de dados por exemplo.
handleRequest() Manipula as aes
solicitadas pelos usurios e renderiza as
visualizaes resultantes.
processAction(ActionRequest request, Action
Response response) Responsvel por notificar qual ao o usurio solicitou do portlet.
Aps a ao ser selecionada, processamos
e criamos a renderizao da resposta
(fragmento). Apenas uma ao pode ser
chamada pelo cliente de cada vez. Cabe a
este mtodo retornar o contedo da resposta usando a tecnologia mais apropriada
(HTML, WML etc.).
render(RenderRequest request, RenderResponse
response) De acordo com parmetros de
renderizao, atributos de requisio ou de
sesso, este mtodo pode mudar a forma
de renderizao do portlet.
destroy() Chamado logo antes de o container de portlets destruir a instncia do
portlet e remov-lo de sua lista de servios.
Este mtodo permite, por exemplo, liberar
recursos antes alocados no mtodo init().

Trabalhando com JSPs em conjunto


com o portlet

Nosso portlet faz uso de trs pginas JSP.


A pgina conf.jsp (Listagem 1) serve para
editar e gerenciar as informaes a respeito do blog, como URL, nome do usurio,
senha etc. A pgina post.jsp (Listagem

Figura 1. Estrutura do projeto de exemplo

2) envia o ttulo e o texto do post para o


WordPress. H ainda a pgina help.jsp (no
listada) que mostra informaes de ajuda
sobre o portlet.
Note que estas pginas incluem a declarao da taglib de portlets:
<%@ taglib uri=http://java.sun.com/portlet prefix=portlet %>.

Nelas, so usados simples elementos


HTML e deixado a cargo da API de Portlets renderizar a pgina de acordo com
o container.

Classes para integrao

Como indicamos no incio, o WordPress


expe alguns de seus servios via XMLRPC. Para acess-los vamos usar a implementao Java do XML-RPC da Apache.
O XML-RPC uma tecnologia para integrao
entre aplicaes, em que trafegamos XML usando o protocolo HTTP pra trocar informaes. A
tecnologia e o Apache XML-RPC foi discutida com
exemplos na edio anterior da Java Magazine.

Vamos criar duas classes que cuidam


da integrao com o WordPress. A classe
BlogInfo (Listagem 3) um POJO simples,
com as informaes a respeito do blog, e
BlogPoster (Listagem 4) a classe que de fato
realiza o post no WordPress, formatando
as informaes para o envio.

Figura 2. Editando as configuraes do portlet para conversar com o WordPress

Programando o portlet

Cada portlet tem uma espcie de classe


controladora, a qual estende GenericPortlet.
Nela, implementamos mtodos que correspondem aos trs estados em que um portlet pode ficar, alm de criamos o mtodo
processAction(), para controle do portlet. Veja
o cdigo completo do nosso WordpressPortlet
na Listagem 5.
O mtodo doView() encarregado de renderizar a visualizao padro do portlet,
no estado VIEW. Por exemplo, poderamos
gerar uma listagem de dados ou exibir
um formulrio de pesquisa. Em nosso
exemplo, temos a entrada do ttulo e do
contedo do blog.
No mtodo doEdit(), geramos um formulrio que permite a edio de configuraes do portlet, no estado EDIT. Para nosso
exemplo, vamos atribuir configuraes do
WordPress, no caso URL, usurio e senha.

Figura 3. Criando o post no blog via nosso portlet

Edio 51 Java Magazine

63

Portlets com JBoss Portal

Listagem 5. Classe WordpressPortlet.java completa


package jm.portlet;
//...imports;

prefs = request.getPreferences();
response.setContentType(text/html);
PortletRequestDispatcher prd = null;

public class WordpressPortlet extends GenericPortlet {


private final String WORDPRESSURL_KEY = WORDPRESS_URL;
private final String USER_KEY = USER;
private final String PASSWORD_KEY = PASSWORD;
private boolean possuiInfo = false;
protected String message;
protected PortletPreferences prefs;
@Override
public void processAction
(ActionRequest request, ActionResponse response)
throws PortletException, IOException, UnavailableException
{
String op = request.getParameter(op);
prefs = request.getPreferences();

@Override
protected void doHelp(RenderRequest request,
RenderResponse response)

if (op.equalsIgnoreCase(salvar)) {
this.getPortletContext().log(Evento Salvar....);
prefs.setValue
(WORDPRESSURL_KEY, request.getParameter(url));
prefs.setValue
(USER_KEY, request.getParameter(usuario));
prefs.setValue
(PASSWORD_KEY, request.getParameter(senha));
this.getPortletContext().log
(Preferencias alteradas....);
prefs.store();

throws PortletException, IOException, UnavailableException


{
response.setContentType(text/html);
StringBuffer help = new StringBuffer();
help.append(Portlet de Ajuda ao Wordpress Portlet <br>);
request.setAttribute(message, help.toString());

this.getPortletContext().log(Preferencias Salvas!);
response.setPortletMode(PortletMode.VIEW);
return;
} else {

@Override
protected void doEdit(RenderRequest request,
RenderResponse response)
throws PortletException, IOException, UnavailableException
{
setRenderParameters(request);
response.setContentType(text/html);
PortletRequestDispatcher prd =
getPortletContext().getRequestDispatcher(
/WEB-INF/jsp/wordpress/conf.jsp);
prd.include(request, response);
}

if (op.equalsIgnoreCase(publicar)) {
try {
BlogInfo blog = new BlogInfo(1,
prefs.getValue(USER_KEY, null),
prefs.getValue(PASSWORD_KEY, null), 1);
XmlRpcClient client = new XmlRpcClient(
prefs.getValue(WORDPRESSURL_KEY, null));
BlogPoster poster = new BlogPoster(client, blog);
poster.setPostType(PostType.publish);
poster.post(getContents(request));
log(Post Publicado ... );
String site = prefs.getValue(WORDPRESSURL_KEY, null);
site = site.substring(0, site.lastIndexOf(/));
message = String.format(
Post salvo em <a href=%s>%s</a> com o titulo %s,
site, site, request.getParameter(titulo));

if (possuiInfo) {
request.setAttribute(message, message);
prd = getPortletContext().getRequestDispatcher
(/WEB-INF/jsp/wordpress/post.jsp);
} else {
prd = getPortletContext().getRequestDispatcher
(/WEB-INF/jsp/wordpress/conf.jsp);
}
prd.include(request, response);

private void setRenderParameters(RenderRequest request) {


prefs = request.getPreferences();
if (null == prefs.getValue(USER_KEY, null)) {
possuiInfo = false;
} else {

response.setPortletMode(PortletMode.VIEW);
return;
} catch (XmlRpcException ex) {
Logger.getLogger(WordpressPortlet.class.
getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(WordpressPortlet.class.
getName()).log(Level.SEVERE, null, ex);
}

@Override
protected void doView(RenderRequest request,
RenderResponse response)
throws PortletException, IOException, UnavailableException
{
setRenderParameters(request);

64 Java Magazine Edio 51

PortletRequestDispatcher prd = getPortletContext().


getRequestDispatcher(/WEB-INF/jsp/wordpress/help.jsp);
prd.include(request, response);

possuiInfo = true;
request.setAttribute(USER_KEY,
prefs.getValue(USER_KEY, null));
request.setAttribute(PASSWORD_KEY,
prefs.getValue(PASSWORD_KEY, null));
request.setAttribute(WORDPRESSURL_KEY,
prefs.getValue(WORDPRESSURL_KEY, null));

protected void log(String str) {


this.getPortletContext().log(str);
}

protected String getContents(ActionRequest request) {


return String.format(
<title>%s</title><category>1</category>
<post>%s</post>, request.getParameter(titulo),
request.getParameter(post));
}

O mais simples de todos os mtodos


o doHelp(), que renderiza uma pgina de
ajuda. No exemplo, geramos informaes
de ajuda dinamicamente, dando uma
idia de como se pode criar uma nica
pgina de help para diversos portlets de
um projeto.
O mtodo processAction() contm o cdigo
de controle do portlet. Ele decide o que
ser feito e qual o estado de retorno. Em
nosso caso, usamos uma tcnica similar
do Struts. No boto Submit do HTML,
atribumos o nome op, e dependendo
do valor passado, fazemos a deciso
do que fazer. No caso, se o boto clicado tiver o valor salvar, persistimos
as informaes do portlet; caso seja
publicar executamos o processo de
publicao do blog.

Descritores XML

A especificao de Portlets define um


descritor XML padro, portlet.xml, onde
declaramos cada portlet com sua respectiva classe, seu tipo MIME de renderizao
e os modos suportados, em nosso caso,
VIEW, EDIT e HELP. Veja o descritor para nosso
portlet na Listagem 6. Temos ainda descritores especficos ao JBoss Portal:
jboss-portlet.xml Inclui a declarao
dos portlets, para que sejam conhecidos
pelo JBoss Portal.
jboss-app.xml Descreve a sua aplicao,
que pode reunir um ou mais portlets.

Listagem 6. O descriptor padro portlet.xml


<portlet-app version=1.0 xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=http://java.sun.com/xml/ns/portlet
xmlns=http://java.sun.com/xml/ns/portlet>
<portlet>
<portlet-name>WordPressPortlet</portlet-name>
<portlet-class>jm.portlet.WordpressPortlet</portlet-class>
<portlet-info>
<title>Wordpress Portlet</title>
</portlet-info>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
<portlet-mode>EDIT</portlet-mode>
<portlet-mode>HELP</portlet-mode>
</supports>
</portlet>
</portlet-app>

Listagem 7. O descritores do JBoss Portal jboss-portal.xml


jboss-portal.xml
<portlet-app>
<portlet>
<portlet-name>WordPressPortlet</portlet-name>
</portlet>
</portlet-app>

jboss-app.xml
<jboss-app>
<app-name>WordPressPortletAPP</app-name>
</jboss-app>

wordpressportlet-object.xml
<?xml version=1.0 encoding=UTF-8?>
<deployments>
<deployment>
<parent-ref>default</parent-ref>
<if-exists>overwrite</if-exists>
<instance>
<instance-name>WordPressPortlet</instance-name>
<component-ref>WordPressPortletAPP.WordPressPortlet</component-ref>
</instance>
</deployment>
</deployments>

Edio 51 Java Magazine

65

Portlets com JBoss Portal

wordpressportlet-object.xml Descritor
que relaciona nosso portlet declarado no
jboss-portlet.xml com a aplicao presente
no jboss-app.xml, alm de definir como o
container instancia o portlet.
Todos estes descritores, que so mostrados na Listagem 7, ficam no mesmo local:
na pasta WEB-INF, junto com o web.xml
padro. Eles faro parte do pacote WAR
que nosso script Ant ir gerar.

Empacotando e configurando

O build.xml fornecido com o download do


artigo faz a compilao, o empacotamento
e o deploy do WAR automaticamente.
Voc ver ento a mensagem de aviso de
deployment no console do JBoss AS, onde
o JBoss Portal est rodando.
Certifique-se de que o JBoss Portal est
em execuo, abra seu navegador e acesse
http://localhost:8080/portal. No link Login

autentique-se com nome de usurio admin e senha admin. Clique ento no


item Configure dashboard no canto superior
direito. Na rea com o nome Content Definition, em Window Name, fornea WordpressWindow. Uma lista indica todos os
portlets instalados. Clique sobre o nome
do nosso portlet, WordpressPortlet.
direita, h duas regies do layout onde
voc pode inserir a janela do portlet: center e left. Clique no boto Add ao lado da
regio center, a qual j possui uma janela,
que a CMSWindow. Em seguida clique no link Dashboard no canto superior
direito e ser mostrado nosso portlet em
funcionamento.

dever configurar suas informaes do


WordPress. Veja um exemplo na Figura 2.
Voc deve informar no campo endereo do
site http://<seusite_wordpress>/xmlrpc.php.
Esta a pgina PHP que faz a interface
XML-RPC para ns. Aqui estamos pressupondo que voc instalou o WordPress
em seu provedor ou localmente (o site de
downloads wordpress.org/download).
Voc deve fornecer ainda o seu nome de
usurio e senha. Estas informaes ficam
guardadas, pois no mtodo doEdit() do
portlet, salvamos essas informaes nas
preferncias, em linhas como:

Testes finais

A partir deste momento essas configuraes vo associadas ao portlet. Voc poder


ento publicar um post no blog a partir do
portlet. Veja o preenchimento dos dados
na Figura 3 e o resultado na Figura 4.

Para testar o exemplo, voc precisar ter


uma conta criada no WordPress. Voc pode
criar contas gratuitamente no site wordpress.org. De posse da conta criada, voc

prefs.setValue(WORDPRESSURL_KEY,
request.getParameter("url"));

Edgar A. Silva
(edgar.silva@redhat.com,
www.edgarsilva.com.br)
Solutions Architect da JBoss,uma
diviso da Red Hat. responsvel por
pr-vendas e tecnologias JBoss. Como Arquiteto Java
ajuda no desenho de solues de Middleware de misso crtica e SOA para vrios segmentos de indstria.
Possui nove anos de experincia com Java alm de
vrias certificaes na tecnologia, entre elas SCEA.

Figura 4. Resultado da ao do nosso blog em um site onde o blog gerenciado pelo WordPress

66 Java Magazine Edio 51

jcp.org/en/jsr/detail?id=168
JSR 169, Portlet Specification
labs.jboss.com/jbossportal
Site do projeto open source JBoss Portal
developers.sun.com/portalserver/reference/
techart/jsr168/
Referncias sobre as JSRs 168 e 286
docs.sun.com/source/817-5319/ch12a.html
Entendendo como estender a classe
GenericPortlet
ws.apache.org/xmlrpc
Site do Apache XML-RPC
onjava.com/pub/a/onjava/2006/02/01/
what-is-a-portlet-2.html
Usando a biblioteca de tags de portlets