Você está na página 1de 369

J2EE Primeiros Passos

Desenvolvendo Aplicaes Java


com JSP, Servlets e EJB

J2EE Primeiros Passos

J2EE Primeiros Passos


Desenvolvendo Aplicaes Java
com JSP, Servlets e EJB
Carlos Eduardo Ribeiro do Valle
Andr Temple
Rodrigo Fernandes de Mello
Danival Taffarel Calegari
Maurcio Schiezaro

Novatec Editora Ltda.


www.novateceditora.com.br
3

J2EE Primeiros Passos

Copyright 2003 da Novatec Editora Ltda.

Todos os direitos reservados e protegidos pela Lei 5.988 de 14/12/1973.


proibida a reproduo desta obra, mesmo parcial, por qualquer processo,
sem prvia autorizao, por escrito, do autor e da Editora.
Editor: RUBENS PRATES
Capa: CAMILA MESQUITA
Reviso de texto: ????????????????

ISBN: 85-7522-???-?

NOVATEC EDITORA LTDA.


Rua Cons. Moreira de Barros 1084 Conj. 01
02018-012 So Paulo SP Brasil
Tel.: +55 11 6959-6529
Fax: +55 11 6950-8869
E-mail: novatec@novateceditora.com.br
Site: www.novateceditora.com.br

Este livro dedicado Clarissa e minha famlia, que sempre estiveram ao meu
lado.
Carlos Eduardo Ribeiro do Valle
Aos meus pais, pelos valores a mim ensinados, aos amigos e famlia, pelos
momentos de descontrao, e em especial minha namorada Regina, pelo constante
apoio e estmulo, sem o qual a concluso deste trabalho no seria possvel.
Andr Temple
A Deus, minha esposa Claudia e minha famlia.
Rodrigo Fernandes de Mello
Aos meus pais, por todo o apoio que prestaram durante todas as duras tarefas que
realizei. minha noiva Cristiane, pela compreenso nos momentos que tive que
deixar de lhe dar ateno para me dedicar escrita deste livro.
Danival
Agradeo minha famlia por sempre me apoiar em todos os momentos da minha
vida e minha equipe de trabalho da Fundao CPqD pelas experincias
vivenciadas.
Maurcio Schiezaro

J2EE Primeiros Passos

Sobre os autores
Carlos Eduardo Ribeiro do Valle Bacharel em Cincias da Computao pelo
Instituto de Cincias Matemticas e Computao da USP. scio-diretor da
NZTech (http://www.nztech.com.br), empresa de desenvolvimento de software
que atua no mercado corporativo. Trabalha com projetos de consultoria e desenvolvimento de sistemas envolvendo tecnologias Wireless, XML, Server-Side Computing,
entre outras.
Andr Temple graduado em Cincia da Computao pela UNESP Universidade
Estadual Paulista e atua no desenvolvimento de solues de billing na arquitetura
J2EE, no CPqD Telecom & IT Solutions.
Rodrigo Fernandes de Mello doutorando do Departamento de Engenharia Eltrica
da Escola de Engenharia de So Carlos, Universidade de So Paulo. Mestre em Cincia da Computao pela Universidade Federal de So Carlos na rea de sistemas distribudos e redes de computadores. Trabalha com sistemas distribudos desde 1998.
Autor do livro Aprendendo Java 2 da Editora Novatec.
Danival Taffarel Calegari mestre em Cincia da Computao pela Unicamp e trabalha no CPqD Telecom & IT Solutions utilizando J2EE no desenvolvimento de solues de billing.
Mauricio Schiezaro bacharel em Cincia da Computao pela UNESP - Universidade Estadual Paulista e tcnico em eletro-eletrnica formado pelo Cotuca - Unicamp e
trabalha no desenvolvimento de solues de billing utilizando a arquitetura J2EE no
CPqD Telecom & IT Solutions.

Sumrio
Sobre os autores ........................................................................................................ 6
Prefcio ....................................................................................................................... 12

Parte I .............................................................................................................................. 14
Desenvolvendo Interfaces e Controles de Interao com o Usurio ...................................... 14
Captulo 1 ......................................................................................................................... 16
Introduo ................................................................................................................. 16

1.1Aplicaes na Web ................................................................................................... 16


1.1Comparando Servlets com CGIs ......................................................................... 17
1.2O que so Servlets? .................................................................................................. 18
1.3O que so pginas JSP? ............................................................................................19

Captulo 2 ......................................................................................................................... 21
Instalao e Configurao .................................................................................... 21

2.1Pr-requisitos ............................................................................................................. 21
2.1Instalao e configurao no Apache Tomcat ............................................... 22
2.2Instalao e Configurao de uma Aplicao Web ...................................... 22

Captulo 3 ......................................................................................................................... 31
Servlets caractersticas bsicas ......................................................................... 31

3.1Biblioteca e documentao .................................................................................. 31


3.2O protocolo HTTP ................................................................................................... 31
3.3Hierarquia de um Servlet ....................................................................................... 33
3.4Ciclo de vida de um Servlet .................................................................................. 34
3.5Inicializao ............................................................................................................... 35
3.6A classe ServletContext ....................................................................................... 38
3.7Finalizao .................................................................................................................. 42
3.8Atendimento de Requisies ............................................................................... 43
3.9Concorrncia no atendimento de requisies .............................................. 45
3.10Retornando informaes sobre o Servlet ...................................................... 47

Captulo 4 ......................................................................................................................... 49
Servlets Gerao da sada .................................................................................. 49

4.1Gerao de sada HTML simples ......................................................................... 49


4.2Headers da resposta HTTP ................................................................................... 51
4.3Gerao de outros tipos de sadas ...................................................................... 55
4.4Gerando contedo XML ........................................................................................ 56
4.5Status HTTP ................................................................................................................ 58
4.6Cdigo de Status de erro ....................................................................................... 62
4.7Buffering da resposta .......................................................................................... 63

Captulo 5 ......................................................................................................................... 65
Servlets Captura de parmetros da requisio ........................................... 65
5.1Informaes sobre o servidor .............................................................................. 65
5.2Informaes sobre a requisio .......................................................................... 66
7

J2EE Primeiros Passos


Sumrio
5.3Formulrios HTML e parmetros da requisio ............................................ 70
5.4Captura de parmetros da requisio ............................................................... 71
5.5Headers da requisio HTTP ............................................................................... 73
5.6Upload de arquivos ................................................................................................. 75
5.7Atributos da requisio .......................................................................................... 76

Captulo 6 ......................................................................................................................... 78
Servlets Cookies e Sesses ................................................................................ 78

6.1Armazenando informaes do usurio ............................................................ 78


6.2Campos escondidos de formulrios HTML ..................................................... 78
6.3Informaes adicionais de caminho ................................................................. 80
6.4Cookies ........................................................................................................................ 81
6.5Gerenciamento de sesses ................................................................................... 85

Captulo 7 ......................................................................................................................... 95
Pginas JSP ................................................................................................................. 95

7.1Formatao do contedo da resposta com Servlets .................................... 95


7.2Formatao do contedo da resposta com pginas JSP ............................. 97
7.3Funcionamento interno ......................................................................................... 98
7.4Ciclo de vida ............................................................................................................. 100
7.5Elementos dinmicos ............................................................................................ 100
7.6Diretivas ..................................................................................................................... 100
7.7Expresses ................................................................................................................ 103
7.8Scriptlets ..................................................................................................................... 103
7.9Objetos implcitos .................................................................................................. 104
7.10Declaraes ............................................................................................................ 106
7.11Comentrios ........................................................................................................... 107
7.12JavaBeans ................................................................................................................ 108
7.13Bibliotecas de Tags (Tag Libraries) ................................................................ 111

Captulo 8 ....................................................................................................................... 115


Modelo MVC ........................................................................................................... 115
8.1Programao e layout ............................................................................................ 115
8.2Arquitetura bsica ................................................................................................... 115
8.3Forward de requisies ........................................................................................ 116
8.4Atributos de requisies ...................................................................................... 117
8.5Juntando as partes ................................................................................................... 119

Captulo 9 ....................................................................................................................... 122


Tpicos adicionais ................................................................................................ 122

9.1Arquivos WAR .......................................................................................................... 122


9.2Autenticao HTTP ................................................................................................ 122
9.3Pools de conexes a base de dados ................................................................ 125

Parte II ........................................................................................................................... 132


Desenvolvimento de Aplicaes Distribudas Utilizando EJB ............................................. 132
Captulo 10 ..................................................................................................................... 133
Novas Tcnicas de Desenvolvimento ............................................................ 133

10.1 Desenvolvimento de Clssico de Aplicaes .............................................. 133

Sumrio
10.2 Sistemas Distribudos ........................................................................................... 135
10.3 Primeiros Ensaios de Arquiteturas para Sistemas Distribudos no Mercado ................................................................................................................................... 141
10.4 Mercado Atual para Sistemas Distribudos ................................................... 144

Captulo 11 ..................................................................................................................... 145


J2EE e Enterprise JavaBeans .............................................................................. 145

11.1 O que J2EE? .......................................................................................................... 145


11.2 Viso da plataforma .............................................................................................. 145
11.3 Instalando o J2SDKEE .......................................................................................... 146
11.4 O que so Enterprise JavaBeans? ..................................................................... 147
11.5 Para que servem e por que utiliz-los? ........................................................... 147
11.6 Componentes EJB ................................................................................................. 148
11.7 Classes e interfaces ................................................................................................ 148
11.8 Acesso local e/ou remoto ................................................................................... 149
11.9 EJBObject e EJBHome ......................................................................................... 150
11.10 Como construir, executar e acessar os componentes ............................. 151

Captulo 12 ..................................................................................................................... 154


Session Beans ......................................................................................................... 154

12.1 O que so Session Beans? .................................................................................. 154


12.2 Quando usar um Session Bean? ....................................................................... 157
12.3 Session Bean Stateless ......................................................................................... 157
12.4 Ciclo de vida - Session Bean Stateless ........................................................... 159
12.5 Session Bean Stateful ........................................................................................... 160
12.6 Ciclo de vida - Session Bean Stateful .............................................................. 161

Captulo 13 ..................................................................................................................... 163


Entity Beans ............................................................................................................. 163

13.1 O que so Entity Beans? ...................................................................................... 163


13.2 Quando usar um Entity Bean? .......................................................................... 164
13.3 Entity Bean Bean-Managed-Persistence ....................................................... 164
13.4 Ciclo de vida Entity Bean BMP ...................................................................... 168
13.5 Entity Bean Container-Managed-Persistence .............................................. 168
13.6 Ciclo de vida Entity Bean CMP ...................................................................... 171
13.7 Relacionamento EJB Entity Bean CMP .......................................................... 172
13.8 EJB-QL ....................................................................................................................... 175

Captulo 14 ..................................................................................................................... 178


Message-Driven Beans ........................................................................................ 178

14.1 O que so Message-Driven Beans? ................................................................. 178


14.2 Quando usar um Message-Driven Bean? ...................................................... 180
14.3 Ciclo de vida - Message-Driven Bean ............................................................ 180
14.4 O que e para que serve o JMS? ...................................................................... 181

Captulo 15 ..................................................................................................................... 187


Transaes e Segurana ...................................................................................... 187
15.1 Transaes ............................................................................................................... 187
15.2 Segurana ................................................................................................................. 193

J2EE Primeiros Passos


Sumrio

Captulo 16 .................................................................................................................... 205


Descobrindo Enterprise JavaBeans ............................................................... 205

16.1 Qual servidor J2EE utilizar? ................................................................................ 205


16.2 Instalando, configurando e executando um Servidor J2EE ................... 205
16.3 Criando um Session Bean Stateless ................................................................. 206
16.4 Criando um Session Bean Stateful ................................................................... 209
16. 5 Criando um Entity Bean BMP .......................................................................... 212
16.6 Criando um Entity Bean CMP ........................................................................... 219
16.7 Criando um Message-Driven Bean ................................................................. 222
16.8 Empacotando a aplicao .................................................................................. 224
16.9 Instalando a aplicao no servidor J2EE ....................................................... 226

Captulo 17 .................................................................................................................... 228


Deployment Descriptor ..................................................................................... 228

17.1 O que um deployment descriptor? .............................................................. 228


17.2 Elementos do deployment descriptor ejb-jar.xml ...................................... 228

Captulo 18 .................................................................................................................... 237


API Enterprise JavaBeans .................................................................................. 237

18.1 Interfaces .................................................................................................................. 237


18.2 Excees ................................................................................................................... 242

Captulo 19 .................................................................................................................... 244


Aplicao J2EE Exemplo ................................................................................ 244
EJB Session Bean Stateless - SalesSupport ............................................................ 245

10

Prefcio
J2EE uma tecnologia muito recente e no muito simples de ensinar e de aprender.
Dessa forma, dividimos o livro em duas grandes partes que tratam dos componentes
principais da arquitetura. Preferimos apresentar primeiramente os conceitos relacionados aos componentes de apresentao, pois acreditamos serem mais fceis de entender e que seja o caminho mais correto no seu aprendizado. Gradualmente fornecemos ao leitor conceitos mais avanados da arquitetura, tratando dos componentes
de negcio e finalizando com uma aplicao prtica.
A primeira parte aborda de forma consistente e didtica o contedo relacionado
camada de apresentao, utilizando os componentes Java Server Pages (JSP) e Servlets. Apresentamos um histrico do desenvolvimento de aplicaes Web, relembrando o uso comum de CGI e linguagens de script. So abordados tambm os tpicos
JavaBeans, Taglibs, modelo MVC e instalao e configurao do container Web.
A segunda parte foca no paradigma de desenvolvimento de aplicaes distribudas,
destacando a evoluo das tcnicas de desenvolvimento, desde a programao estrutural at o atual uso de sistemas distribudos. So detalhados os componentes de
negcio Enterprise JavaBeans e os recursos oferecidos no uso desta tecnologia.
Esta diviso visa oferecer um contedo mais abrangente e completo ao leitor. O intuito de todo o livro ser prtico nos temas que apresenta. Todos os captulos apresentam exemplos que simplificam o processo de entendimento dos temas.
Esperamos que voc, profissional, estudante, ou entusiasta de novas tecnologias, faa
bom proveito desta literatura e que ela seja uma boa orientao para seus estudos e
realizaes profissionais.

11

J2EE Primeiros Passos

12

Parte I
Desenvolvendo Interfaces e
Controles de Interao com o Usurio
Esta primeira parte aborda de forma consistente e didtica o contedo relacionado
camada de apresentao, utilizando os componentes Java Server Pages (JSP) e Servlets. Apresentamos um histrico do desenvolvimento de aplicaes Web, relembrando o uso comum de CGI e linguagens de script. So abordados tambm os tpicos
JavaBeans, Taglibs, modelo MVC e instalao e configurao do container Web.

13

J2EE Primeiros Passos

14

Captulo 1
Introduo
Introduzimos, nesse captulo, a tecnologia de Servlets e JSP (JavaServer Pages), e
mostramos algumas caractersticas que tornam essas tecnologias bastante atraentes
para o desenvolvimento de aplicaes na Web.

1.1 Aplicaes na Web


Se um dia a Internet era composta, principalmente, de pginas estticas com contedo institucional, hoje ela oferece uma infinidade de aplicaes com contedo dinmico e personalizado.
Diversas tecnologias possibilitaram essa revoluo: seja para construir um simples
site com contedo dinmico ou para construir um complexo sistema de Business-ToBusiness, necessria a utilizao de ferramentas que possibilitem consultas a bancos de dados, integrao com sistemas corporativos, entre outras inmeras funcionalidades.
Dentre as diversas tecnologias disponveis atualmente para o desenvolvimento dessa
classe de aplicaes, destaca-se a de Servlets e a de pginas JSP (JavaServer Pages).
A utilizao de Servlets e de pginas JSP oferece diversas vantagens em relao ao
uso de outras tecnologias (como PHP, ASP e CGI). As principais vantagens so herdadas da prpria linguagem Java:
Portabilidade a aplicao desenvolvida pode ser implantada em diversas plataformas, como por exemplo Windows, Unix e Macintosh, sem que seja necessrio
modificar ou mesmo reconstruir a aplicao.
Facilidade de programao a programao orientada a objetos, simplificando
o desenvolvimento de sistemas complexos. Alm disso, a linguagem oferece algumas facilidades, como por exemplo, o gerenciamento automtico de memria
(estruturas alocadas so automaticamente liberadas, sem que o desenvolvedor
precise se preocupar em gerenciar esse processo).

15

J2EE Primeiros Passos


Flexibilidade a linguagem Java j se encontra bastante difundida, contando com
uma enorme comunidade de desenvolvedores, ampla documentao e diversas
bibliotecas e cdigos prontos, dos quais o desenvolvedor pode usufruir.
Alm dessas vantagens, a arquitetura de Servlets e pginas JSP possibilita alguns benefcios adicionais:
Escalabilidade na maior parte dos servidores de aplicaes modernos, possvel distribuir a carga de processamento de aplicaes desenvolvidas em diversos
servidores, sendo que servidores podem ser adicionados ou removidos de maneira a acompanhar o aumento ou decrscimo dessa carga de processamento.

Figura 1.1 Exemplo de arquitetura distribuda com Servlets e Pginas JSP.


Eficincia os Servlets carregados por um servidor persistem em sua memria at
que ele seja finalizado. Assim, ao contrrio de outras tecnologias, no so iniciados novos processos para atender cada requisio recebida; por outro lado, uma
mesma estrutura alocada em memria pode ser utilizada no atendimento das diversas requisies que chegam a esse mesmo Servlet.
Recompilao automtica pginas JSP modificadas podem ser automaticamente
recompiladas, de maneira que passem a incorporar imediatamente as alteraes
sem que seja necessrio interromper o funcionamento da aplicao como um
todo.

1.1 Comparando Servlets com CGIs


O CGI, ou Common Gateway Interface, surgiu como uma das primeiras tecnologias
disponveis para a gerao de contedo dinmico em servidores Web. O desenvolvedor implementa uma aplicao que deve ser executada a cada requisio recebida,
sendo que o servidor Web passa para essa aplicao, por meio de variveis de ambiente e entrada padro, os parmetros recebidos, e retorna a sada da aplicao como
resposta da requisio.

16

Captulo 1 Introduo

Figura 1.2 Funcionamento de um CGI.


Podemos utilizar o CGI para analisar algumas das vantagens em se utilizar Servlets.
Em primeiro lugar, h um grande ganho em performance na utilizao de Servlets; ao
invs de iniciar um novo processo a cada requisio recebida, um Servlet fica carregado em memria e atende as requisies recebidas atravs de novos threads.
Alm disso, um Servlet pode tirar proveito dessa persistncia para manter tambm
em memria recursos que demandem grande processamento para serem inicializados. Um exemplo tpico, para esse caso, a manuteno de conexes com banco de
dados, ao invs de inicializar uma nova conexo com o banco de dados a cada requisio recebida, um Servlet pode inicializar diversas conexes ao ser carregado, e simplesmente alocar uma conexo desse pool a cada requisio recebida (e retornar a
conexo ao pool aps o atendimento da requisio).
Alm destes ganhos de performance, a utilizao de um Servlet possibilita uma maneira mais padronizada e portvel de se distribuir e implantar sua aplicao. Conforme explicado mais adiante no Captulo 2 Instalao e Configurao, o ambiente
onde sua aplicao ser implantada no precisa ser igual ao ambiente onde foi feito o
desenvolvimento, seus Servlets podem ser instalados em qualquer ambiente onde
haja um Servidor de Aplicaes que implemente a especificao de Servlets.
Por fim, estaremos apresentando ao longo destes primeiros captulos as diversas caractersticas e funcionalidades da tecnologia de Servlets que tornam o seu desenvolvimento muito mais simples, e o resultado, muito mais eficiente e robusto.

1.2 O que so Servlets?


Servlets so classes Java, desenvolvidas de acordo com uma estrutura bem definida, e
que, quando instaladas junto a um Servidor que implemente um Servlet Container
(um servidor que permita a execuo de Servlets, muitas vezes chamado de Servidor
de Aplicaes Java), podem tratar requisies recebidas de clientes.

17

J2EE Primeiros Passos


Um cenrio tpico de funcionamento de uma aplicao desenvolvida com Servlets
o seguinte:

Figura 1.3 Exemplo de funcionamento de uma aplicao com Servlets.


Ao receber uma requisio, um Servlet pode capturar parmetros dessa requisio,
efetuar qualquer processamento inerente a uma classe Java, e devolver uma pgina
HTML por exemplo.

Exemplo de Servlet
import java.io.*;
import javax.servlet.http.*;

// Servlet simples que retorna pgina HTML com o endereo IP


// do cliente que est fazendo o acesso
public class RemoteIPServlet extends HttpServlet {

public void doGet(HttpServletRequest p_request,


HttpServletResponse p_response) throws IOException {
PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);
l_pw.println(Endereo IP \ + p_request.getRemoteAddr () + \);
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}
}

1.3 O que so Pginas JSP?


As pginas JSP, ou JavaServer Pages, foram criadas para contornar algumas das limitaes no desenvolvimento com Servlets. Se em um Servlet a formatao da pgina
HTML resultante do processamento de uma requisio se mistura com a lgica da
aplicao em si, dificultando a alterao dessa formatao, em uma pgina JSP essa
formatao se encontra separada da programao, podendo ser modificada sem afetar o restante da aplicao.

18

Captulo 1 Introduo
Assim, um JSP consiste de uma pgina HTML com alguns elementos especiais, que
conferem o carter dinmico da pgina. Esses elementos podem tanto realizar um
processamento por si, como podem recuperar o resultado do processamento realizado em um Servlet, por exemplo, e apresentar esse contedo dinmico junto a pgina
JSP.
Existe tambm um recurso adicional bastante interessante na utilizao de pginas
JSP: a recompilao automtica, que permite que alteraes feitas no cdigo da pgina sejam automaticamente visveis em sua apresentao. Assim, no necessrio interromper o funcionamento da aplicao para incorporar uma modificao de layout,
por exemplo.

Exemplo de Pgina JSP


<!Pgina JSP Simples que imprime endereo IP da mquina que est fazendo o acesso a
esta pgina >
<HTML>
<BODY>
O seu endereo IP <%= request.getRemoteAddr () %>
</BODY>
</HTML>

19

J2EE Primeiros Passos

20

Captulo 2
Instalao e Configurao
Nesse captulo so apresentados os tpicos referentes a instalao e configurao de
um ambiente bsico para a implantao e execuo de aplicaes Web com Servlets
e pginas JSP.

2.1 Pr-requisitos
O primeiro passo para desenvolver aplicaes Web com Servlets e pginas JSP a
configurao de um ambiente bsico para a implantao e execuo dessas aplicaes. Esse ambiente bsico pressupe a instalao de dois componentes principais:
o Java 2 Standard Development Kit (J2SDK), utilizado para compilar aplicaes Java,
e um Servlet Container, que ir executar os Servlets desenvolvidos.
Alguns sistemas operacionais j possuem um J2SDK instalado por default. Caso esse
ainda no se encontre instalado, pode-se obt-lo no site oficial do Java (http://
java.sun.com). Neste site possvel selecionar entre as verses de J2SDK para as diversas plataformas de mercado tais como Windows, Linux, Solaris e outros.
O outro componente necessrio para o desenvolvimento de Servlets e JSP um servidor que implemente um Servlet Container. Esse servidor ser responsvel por prover um framework bsico para as diversas aplicaes desenvolvidas, inicializandoas, distribuindo as requisies entre elas e tratando os resultados do processamento
de cada aplicao.
Apesar de existirem diversos servidores disponveis no mercado, para efeito dos exemplos apresentados neste livro, utilizaremos o Apache Tomcat, disponvel no site http:/
/jakarta.apache.org. Esse servidor de aplicaes atende s especificaes mencionadas anteriormente e pode ser utilizado sem nenhum custo para o desenvolvedor.
Um ltimo componente normalmente utilizado para o desenvolvimento de Servlets e
pginas JSP um ambiente grfico de desenvolvimento (IDE). Porm, a escolha e
configurao desse ambiente foge do escopo deste livro, sendo deixado para o leitor
a tarefa de escolher a ferramenta que melhor atenda s suas necessidades.

21

J2EE Primeiros Passos

2.1 Instalao e Configurao no Apache Tomcat


No site do Apache Tomcat so disponibilizadas verses do software com instaladores
para os diversos sistemas operacionais.
Normalmente esse processo de instalao simples, e, uma vez finalizado, tem-se
um servidor de aplicaes pronto para produo. De qualquer forma, o site disponibiliza toda a documentao necessria para resolver problemas encontrados e esclarecer dvidas com relao ao processo de instalao e configurao do servidor.
Para entender um pouco mais a fundo o funcionamento do Tomcat, deve-se examinar os diretrios criados durante o processo de instalao. Veja na figura 21. os principais diretrios criados:

Figura 2.1 Subdiretrios na instalao do Apache Tomcat.

22

Diretrio

Descrio

bin

Executveis, incluindo os aplicativos para iniciar e para encerrar a execuo do


servidor

conf

Arquivos de configurao do Tomcat. O arquivo server.xml, em particular, define


uma srie de parmetros para a execuo do servidor, como por exemplo, a porta
onde o servidor ir receber requisies (essa porta , por default, 8080), devendo ser
examinado com cuidado e modificado conforme as necessidades.

logs

Arquivos de log do servidor. Alm de gerar arquivos de log contendo entradas para
cada requisio recebida, como qualquer servidor Web, o Tomcat tambm pode gerar
arquivos de log com tudo o que as aplicaes desenvolvidas enviam para as sadas
padro do sistema: tipicamente, o que impresso atravs do System.out acrescido
no arquivo stdout.log, e tudo o que impresso atravs do System.err acrescido
no arquivo stderr.log.

work

Diretrio temporrio do Tomcat. Esse diretrio utilizado, por exemplo, para realizar
a recompilao automtica de pginas JSP (esse processo explicado mais adiante
no captulo Pginas JSP).

webapps

Nesse diretrio so instaladas as diversas aplicaes web desenvolvidas por voc ou


por terceiros.

Captulo 2 Instalao e Configurao

2.2 Instalao e Configurao de uma Aplicao Web


Conforme vimos anteriormente, existe um diretrio no Apache Tomcat chamado
webapps onde devem ser instaladas as diversas aplicaes desenvolvidas por voc
ou por terceiros.
Para que possamos mostrar como so feitas essas instalaes, precisamos antes definir o que uma aplicao Web: a partir de agora, estaremos chamando de uma aplicao Web um conjunto de Servlets, pginas JSP, classes Java, bibliotecas, cones,
pginas HTML e outros elementos, que podem ser empacotados juntos e que provem as funcionalidades previstas pela aplicao.
Essa definio est contida, na verdade, na prpria especificao de Servlets Java,
no sendo especfica, portanto, utilizao do Servidor de Aplicaes Apache Tomcat. Isso significa que as aplicaes desenvolvidas por voc podem ser instaladas em
qualquer servidor que implemente a especificao de Servlets (como o IBM Websphere e o Bea Weblogic): com isso, segue-se o princpio da linguagem Java de
desenvolver o cdigo uma s vez e implant-lo em mltiplas plataformas.
Aplicao Web: Aplicao composta de Servlets + Pginas JSP + Bibliotecas e classes Java +
imagens + pginas HTML e outros componentes estticos que podem ser empacotados juntos e
instalados em qualquer Servlet Container.
De acordo com a especificao de Servlets, existem duas maneiras pelas quais uma
aplicao web pode ser instalada junto a um Servlet Container: por meio de um arquivo WAR (Web Application Archive), explicado mais adiante no Captulo 9, ou por
meio de uma estrutura de diretrios criada junto ao servidor. No caso especfico do
Tomcat, essa estrutura deve ser criada abaixo do diretrio webapps.
Para uma determinada aplicao Web, a estrutura de diretrios mnima que deve ser
criada abaixo do diretrio webapps a seguinte:

Figura 2.2 Estrutura mnima de diretrios de uma aplicao Web.


Conforme pode ser visto na figura anterior, deve ser criado, abaixo do diretrio webapps, um diretrio com o nome da aplicao. Esse diretrio deve conter pelo menos um subdiretrio WEB-INF; podem haver alm do subdiretrio WEB-INF, por
outro lado, outros subdiretrios e arquivos, como pginas html, pginas JSP etc.

23

J2EE Primeiros Passos


O diretrio WEB-INF, por sua vez, deve conter um arquivo chamado web.xml e
dois subdiretrios: classes, com todas as classes, e lib, com as bibliotecas utilizadas. Obviamente, abaixo do diretrio classes podem haver subdiretrios para refletir o path relacionado aos packages Java (mais informaes sobre packages podem ser obtidas em qualquer livro introdutrio sobre a linguagem Java).
Utilizando como exemplo uma aplicao chamada RemoteIP, contendo o Servlet
RemoteIPServlet do exemplo do captulo 1 desse livro, uma estrutura possvel abaixo
do diretrio webapps seria a seguinte:

Figura 2.3 Exemplo de estrutura para aplicao RemoteIP .


Obviamente, podem haver diversas aplicaes instaladas, gerando diversas rvores
de diretrios abaixo do diretrio webapps:

Figura 2.4 Exemplo de aplicaes instaladas abaixo do diretrio webapps.


24

Captulo 2 Instalao e Configurao


Cada uma dessas aplicaes carregada pelo Servidor em um Servlet Context (Contexto do Servlet). Cada contexto d sua aplicao uma URL base, chamada de Context Path (Path do Contexto), e prov um ambiente comum para todos os Servlets da
aplicao.
O path do contexto serve para que o Servidor possa mapear e distribuir as requisies recebidas para as diversas aplicaes instaladas. No Apache Tomcat, o path do
contexto coincide com o nome do subdiretrio criado abaixo do webapps.
Assim, no nosso exemplo, supondo que o endereo IP do servidor onde instalamos o
Apache Tomcat 192.168.0.1, teremos os acessos s URLs iniciadas por
http://192.168.0.1:8080/RemoteIP

direcionadas para a aplicao RemoteIP, os acessos s URLs iniciadas por


http://192.168.0.1:8080/CadastroClientes

direcionadas para a aplicao CadastroClientes, e assim por diante.

Figura 2.5 Exemplo de mapeamento de requisies para aplicaes instaladas


no Tomcat.
Por fim, conforme o leitor pode ter reparado nos exemplos citados anteriormente,
para cada aplicao h um Deployment Descriptor: trata-se de um arquivo, chamado web.xml e localizado abaixo do diretrio WEB-INF, e que contm informaes
de configurao da aplicao, tais como, parmetros de inicializao, mapeamentos
de Servlets, entre outros.
Deployment Descriptor: Arquivo XML com as informaes de configurao de uma Aplicao Web.
Esse arquivo fica abaixo do diretrio WEB-INF e se chama web.xml.
Um possvel Deployment Descriptor para a aplicao RemoteIP, por exemplo, seria o seguinte:

25

J2EE Primeiros Passos

Exemplo de Deployment Descriptor


<?xml version=1.0" encoding=ISO-8859-1"?>

<!DOCTYPE web-app PUBLIC -//Sun Microsystems, Inc.//DTD Web Application 2.3//EN


http://java.sun.com/dtd/web-app_2_3.dtd>

<web-app>
<display-name>RemoteIP</display-name>
<servlet>
<servlet-name>RemoteIP</servlet-name>
<servlet-class>RemoteIPServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RemoteIP</servlet-name>
<url-pattern>/RemoteIP</url-pattern>
</servlet-mapping>
</web-app>

Como o Deployment Descriptor composto de muitas sees, procuraremos apresentar as principais e suas respectivas funes, usando como exemplo a aplicao
CadastroClientes mencionada anteriormente. Uma apresentao mais detalhada e
aprofundada desse arquivo pode ser encontrada na prpria especificao de Servlets.
Pressupomos, para essa apresentao um conhecimento mnimo de XML; caso voc
no tenha familiaridade com esse tipo de documento, sugerimos que voc tente acompanhar os exemplos, e os utilize como templates para criar seus prprios Deployment Descritors.

Estrutura geral do Deployment Descriptor


<?xml version=1.0" encoding=ISO-8859-1"?>

<!DOCTYPE web-app
PUBLIC -//Sun Microsystems, Inc.//DTD Web Application 2.3//EN
http://java.sun.com/dtd/web-app_2_3.dtd>

<web-app>
.
.
.
</web-app>

26

Captulo 2 Instalao e Configurao


Assim, como em qualquer documento XML, inicialmente so colocados os elementos de declarao do XML e do tipo de documento (XML declaration e Document
type declaration). Na figura anterior, esses elementos correspondem s seis primeiras linhas listadas.
Em seguida, vem o elemento web-app: esse o elemento root (raiz) desse XML, ou
seja, deve haver somente um elemento web-app, e abaixo dele devem ficar todos os
outros elementos do XML.
Os principais elementos abaixo do elemento root so os seguintes: display-name,
context-param, session-config, welcome-file-list, error-page, servlet e servlet-mapping.
O elemento display-name deve conter um nome da aplicao a ser apresentado por
ferramentas GUI de gerenciamento/desenvolvimento de Aplicaes Web. Esse elemento opcional, porm caso voc decida utiliz-lo, importante que haja somente
um desses elementos por Deployment Descriptor.

Exemplo de utilizao do elemento display-name


<display-name>Cadastro de Clientes</display-name>

O elemento context-param serve para que se possam definir parmetros de inicializao do contexto da aplicao; esses parmetros estaro disponveis para todos os
Servlets e pginas JSP da aplicao. Cada elemento presente deve conter o nome de
um parmetro e o seu valor correspondente. O desenvolvedor pode tambm optar
por no utilizar nenhum desses elementos em seu XML.

Exemplo de utilizao do elemento context-param


<context-param>
<param-name>NomeBaseDados</param-name>
<param-value>dbaplic</param-value>
</context-param>
<context-param>
<param-name>IPBancoDados</param-name>
<param-value>192.168.0.2</param-value>
</context-param>

O elemento seguinte, session-config, serve para que se possa especificar o perodo


mximo, em minutos, de uma sesso (esse recurso explicado mais adiante no livro,
no captulo 6 Sesses). Assim como o elemento display-name, esse elemento opcional, mas caso o desenvolvedor opte por utiliz-lo, deve existir somente uma instncia desse elemento no arquivo.

27

J2EE Primeiros Passos

Exemplo de utilizao do elemento session-config


<session-config>
<session-timeout>15</session-timeout>
</session-config>

Os elementos welcome-file-list e error-page contm, respectivamente, a lista ordenada de pginas a serem utilizadas como index e as pginas a serem apresentadas em
casos de erros HTTP ou excees no tratadas pela aplicao. Esses dois elementos
so opcionais, sendo que somente o primeiro admite uma instncia por Deployment
Descriptor.

Exemplo de utilizao dos elementos welcome-file-list e error-page


<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/404Error.html</location>
</error-page>
<error-page>
<exception-type>com.minhaempresa.exceptions.DBConnException</exception-type>
<location>/DBError.html</location>
</error-page>

De acordo com o que apresentado na listagem anterior, se tomarmos como exemplo nossa aplicao CadastroClientes, quando feito um acesso a URL http://
192.168.0.1:8080/CadastroClientes/, o Servidor tentar retornar a pgina index.html,
conforme especificado na lista do welcome-file-list. Caso essa pgina no exista, o
Servidor tentar utilizar a pgina index.jsp.
A figura anterior tambm demonstra a utilizao do elemento error-page duas vezes:
a primeira vez para mapear erros HTTP 404 (pgina no encontrada) a uma pgina de
erro-padro, e a segunda, para mapear exceptions com.minhaempresa.exceptions.
DBConnException a uma outra pgina de erro.
Os ltimos dois elementos, servlet e servlet-mapping, servem para definir, respectivamente, os Servlets da aplicao, com seus respectivos parmetros, e os mapeamentos de URLs a cada Servlet da aplicao.
Cada elemento servlet, por sua vez, composto dos seguintes elementos:

28

Captulo 2 Instalao e Configurao


Elemento

Descrio

servlet-name

Deve conter o nome do Servlet.

servlet-class

Deve conter o nome da classe (incluindo a informao sobre o package, se


existir).

init-param

Deve conter um parmetro de inicializao do Servlet; pode haver nenhum,


somente um, ou mais de um elemento deste tipo para cada Servlet.

load-on-startup

Deve conter um inteiro positivo indicando a ordem de carga deste Servlet em


relao aos outros Servlets da aplicao, sendo que inteiros menores so
carregados primeiro; se este elemento no existir, ou seu valor no for um
inteiro positivo, fica a cargo do Servlet Container decidir quando o Servlet ser
carregado (possivelmente, no instante em que chegar a primeira requisio
a esse Servlet).

Exemplo de utilizao do elemento servlet


<servlet>
<servlet-name>ProcessaCadastro</servlet-name>
<servlet-class>com.minhaempresa.CadastroClientes.ProcCadastro</servlet-class>
<init-param><param-name>Email.ServidorSMTP</param-name><paramvalue>smtp.minhaempresa.com.br</param-value></init-param>
<init-param><param-name>Email.Remetente</param-name><paramvalue>site@minhaempresa.com.br</param-value></init-param>
<init-param><param-name>Email.Destinatario</param-name><paramvalue>vendas@minhaempresa.com.br</param-value></init-param>
<init-param><param-name>Email.Assunto</param-name><param-value>Novo cadastro de
cliente</param-value></init-param>
<load-on-startup>0</load-on-startup>
</servlet>

Por fim, um elemento servlet-mapping contm um nome de Servlet, conforme definido em servlet-name, e um padro da URL do Servlet no servidor (URL pattern).

Exemplo de utilizao do elemento servlet-mapping


<servlet-mapping>
<servlet-name>ProcessaCadastro</servlet-name>
<url-pattern>/Processamento</url-pattern>
</servlet-mapping>

No exemplo anterior, todos as requisies com URLs iniciadas por /CadastroClientes/Processamento/ sero mapeadas para o Servlet cujo nome ProcessaCadastro.
Outros mapeamentos interessantes podem ser obtidos atravs de padres de URL do
tipo *.<extenso>, como por exemplo, *.wm ou *.pdf, de maneira que o acessos a
todas as URLs com o sufixo indicado sejam tratados por um mesmo Servlet.

29

J2EE Primeiros Passos


Um ltimo exemplo de mapeamento interessante diz respeito ao padro /, que define o Servlet default para todos os acessos que no se encaixarem em nenhum outro
padro.
Juntando ento todos os elementos apresentados anteriormente, temos o Deployment Descriptor de exemplo apresentado a seguir:

Exemplo de Deployment Descriptor completo para a aplicao CadastroClientes


<?xml version=1.0" encoding=ISO-8859-1"?>

<!DOCTYPE web-app
PUBLIC -//Sun Microsystems, Inc.//DTD Web Application 2.3//EN
http://java.sun.com/dtd/web-app_2_3.dtd>

<web-app>
<display-name>Cadastro de Clientes</display-name>
<context-param>
<param-name>NomeBaseDados</param-name>
<param-value>dbaplic</param-value>
</context-param>
<context-param>
<param-name>IPBancoDados</param-name>
<param-value>192.168.0.2</param-value>
</context-param>
<session-config>
<session-timeout>15</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/404Error.html</location>
</error-page>
<error-page>
<exception-type>com.minhaempresa.exceptions.DBConnException</exception-type>
<location>/DBError.html</location>
</error-page>

30

Captulo 2 Instalao e Configurao


<servlet>
<servlet-name>ProcessaCadastro</servlet-name>
<servlet-class>com.minhaempresa.CadastroClientes.ProcCadastro</servlet-class>
<init-param><param-name>Email.ServidorSMTP</param-name><param-value>
smtp.minhaempresa.com.br</param-value></init-param>
<init-param><param-name>Email.Remetente</param-name><param-value>
site@minhaempresa.com.br</param-value></init-param>
<init-param><param-name>Email.Destinatario</param-name><param-value>
vendas@minhaempresa.com.br</param-value></init-param>
<init-param><param-name>Email.Assunto</param-name><param-value>
Novo cadastro de cliente</param-value></init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet>
<servlet-name>FormularioCadastro</servlet-name>
<servlet-class>com.minhaempresa.CadastroClientes.FormCadastro</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ProcessaCadastro</servlet-name>
<url-pattern>/Processamento</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>FormularioCadastro</servlet-name>
<url-pattern>/Formulario</url-pattern>
</servlet-mapping>
</web-app>

31

J2EE Primeiros Passos

32

Captulo 3
Servlets caractersticas bsicas
Nesse captulo, exploramos as caractersticas bsicas de Servlets, mostrando o funcionamento e sua interao com o Servlet Container. Implementamos tambm nossos
primeiros Servlets de exemplo.

3.1 Biblioteca e documentao


Antes que voc possa iniciar o desenvolvimento de seus Servlets, imprescindvel
que voc tenha disponvel a biblioteca de Servlets Java (normalmente, um arquivo
chamado servlet.jar; se voc estiver utilizando o Apache Tomcat, voc pode encontrar esse arquivo abaixo do diretrio de instalao do Tomcat, no subdiretrio
common\lib). Essa biblioteca contm todas as classes e interfaces necessrias para o
desenvolvimento de Servlets, e deve estar contida em seu classpath.
Outro item importante, embora no imprescindvel, a documentao da API de
Servlets. Por meio dessa documentao, voc poder verificar todos as classes, com
seus respectivos mtodos e variveis, com os quais voc poder contar durante o
processo de desenvolvimento. Essa documentao pode ser obtida diretamente do
site oficial do Java (http://java.sun.com).

3.2 O protocolo HTTP


Embora Servlets possam ser utilizados no s para o desenvolvimento de aplicaes
HTTP, a maior parte das aplicaes desenvolvidas so destinadas a esse fim. Sendo
assim, vale a pena estudar um pouco mais a fundo o funcionamento e caractersticas
desse protocolo.
O protocolo HTTP utilizado na navegao nas pginas da Internet: quando voc
abre uma janela de um browser, acessa uma pgina Web e navega em seus links, voc
est, na verdade, utilizando esse protocolo para visualizar, em sua mquina, o contedo que est armazenado em servidores remotos.

33

J2EE Primeiros Passos


O HTTP um protocolo stateless de comunicao cliente-servidor: o cliente envia
uma requisio para o servidor, este processa a requisio e devolve uma resposta
para o cliente, sendo que, a princpio, nenhuma informao mantida no servidor
em relao s requisies previamente recebidas.
Assim, quando digitamos o endereo de uma pgina em um browser Web, estamos
gerando uma requisio a um servidor, que ir, por sua vez, devolver para o browser
o contedo da pgina HTML requisitada.
A requisio enviada por um cliente deve conter, basicamente, um comando (tambm chamado de mtodo), o endereo de um recurso no servidor (tambm chamado
de path) e uma informao sobre a verso do protocolo HTTP sendo utilizado.
Supondo, por exemplo, que utilize-se o mtodo GET, o path /index.html e a verso
1.0 do protocolo HTTP (o que equivale a digitar um endereo http://<endereo de
algum servidor>/index.html em um browser), temos a seguinte requisio enviada:

Exemplo de requisio HTTP


GET /index.html HTTP/1.0

Existem diversos mtodos HTTP que podem ser especificados em requisies, sendo
os mais comuns o mtodo GET, normalmente utilizado para obter o contedo de um
arquivo no servidor, e o mtodo POST, utilizado para enviar dados de formulrios
HTML ao servidor. Alm desses mtodos, o protocolo HTTP 1.0 admite tambm o
mtodo HEAD, que permite que o cliente obtenha somente os headers da resposta; j
o protocolo HTTP verso 1.1 admite os seguintes mtodos:
Mtodo

Descrio

PUT

Transfere um arquivo do cliente para o servidor.

DELETE

Remove um arquivo do servidor.

OPTIONS

Obtm a lista dos mtodos suportados pelo servidor.

TRACE

Retorna o contedo da requisio enviada de volta para o cliente.

Alm do mtodo, path e verso, uma requisio pode conter parmetros adicionais,
chamados headers. Dois headers comuns so, por exemplo, o header User-Agent,
que contm informaes sobre o cliente que est gerando a requisio (tipo, verso
do browser etc.) e o header Accept, que serve para especificar os tipos de recursos
aceitos pelo cliente para a requisio enviada.

Exemplo de requisio HTTP com headers


GET /index.html HTTP/1.0
User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 98; DigExt)
Accept: text/html

34

Captulo 3 Servlets caractersticas bsicas


Uma vez processada a requisio, o servidor, por sua vez, manda uma resposta para
o cliente, sendo que essa resposta tambm tem um formato predeterminado: a primeira linha contm informaes sobre a verso do protocolo, um cdigo de status da
resposta e uma mensagem associada a esse status; em seguida so enviados tambm
headers (com informaes do servidor que gerou a resposta, por exemplo); e finalmente, enviado o contedo, propriamente dito, da resposta.

Exemplo de resposta HTTP com headers


HTTP/1.1 200 OK
Server: Apache/1.3.26 (Unix)
Last-Modified: Sun, 22 Dec 2002 17:47:59 GMT
Content-Type: text/html
Content-Length: 30

<HTML>
<BODY>
</BODY>
</HTML>

Assim, no exemplo anterior, o cdigo de status 200 indica que houve sucesso no
atendimento da requisio enviada pelo cliente, os headers indicam o tipo, tamanho
e data e hora de ltima modificao do contedo requisitado, e por fim, temos uma
pgina HTML em branco, com o contedo propriamente dito.
Outros cdigos de status bastante comuns so o 404, que indica que o recurso no foi
localizado no servidor, e o cdigo 500, que indica que houve erro no processamento
da requisio enviada.
Se voc quiser se aprofundar no estudo deste protocolo, uma boa pedida a leitura
do Guia de Referncia HTTP da Editora Novatec.

3.3 Hierarquia de um Servlet


Conforme descrito anteriormente, um Servlet nada mais que uma classe Java que
obedece a uma estrutura bem definida. Em especial, essa classe deve implementar a
interface javax.servlet.Servlet.
Existem duas classes, na biblioteca de Servlets, que implementam essa interface:
javax.servlet.GenericServlet e sua sub-classe, javax.servlet.http.HttpServlet. A classe
GenericServlet, como o prprio nome indica, serve para atender requisies genricas (utilizando qualquer protocolo), e a classe HttpServlet, para atender requisies
HTTP.

35

J2EE Primeiros Passos

Figura 3.1 Hierarquia de classes associadas a um Servlet.


No desenvolvimento do Servlet de nossa aplicao exemplo CadastroClientes, temos
assim a seguinte declarao de classe:

Declarao do Servlet ProcCadastro


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Servlet para processamento do cadastro de novos clientes


public class ProcCadastro extends HttpServlet {
...
}

3.4 Ciclo de vida de um Servlet


Todo Servlet segue, por outro lado, um ciclo de vida composto de 3 fases: inicializao, atendimento de requisies e finalizao.
A inicializao ocorre quando o Servlet Container carrega o Servlet: se o parmetro
load-on-startup, do Deployment Descriptor (vide seo 2.2), estiver presente e contiver um inteiro positivo, essa carga ocorre quando o prprio servidor iniciado; caso
contrrio, essa carga ocorre quando recebida a primeira requisio a ser mapeada
para a aplicao que contm o Servlet.
Aps a inicializao, o Servlet pode atender requisies. Assim, enquanto o servidor
estiver ativo, e a aplicao que contem o Servlet estiver carregada, este permanecer
na fase 2 de seu ciclo.
Um ponto importante com relao a essa fase, e que na verdade constitui uma vantagem da tecnologia de Servlets e pginas JSP com relao a outras tecnologias, que o
fato do Servlet permanecer carregado permite que dados armazenados em variveis
de classe persistam ao longo das diversas requisies recebidas. Assim, possvel
manter um pool de conexes ao banco de dados, por exemplo, de maneira que no
seja necessrio iniciar e estabelecer uma nova conexo ao banco de dados a cada
requisio recebida.

36

Captulo 3 Servlets caractersticas bsicas


Finalmente, quando o servidor finalizado, ou quando a aplicao tornada inativa
pelo Servlet Container, o Servlet finalizado.

Figura 3.2 Ciclo de vida de um Servlet.


Cada uma das fases se traduz, na verdade, em mtodos do Servlet que so chamados
pelo Servlet Container nos diversos instantes do ciclo.
Apresentamos, nas sees subsequentes, os mtodos relacionados s fases de inicializao, finalizao e de atendimento de requisies.

3.5 Inicializao
Conforme apresentado nos pargrafos anteriores, a inicializao do Servlet ocorre no
instante em que feita a carga da aplicao pelo Servlet Container.
Nesse instante, o Servlet Container executa o mtodo init do Servlet, dando chance
ao Servlet de executar quaisquer passos necessrios para sua inicializao, tais como:
1) leitura de parmetros de configurao
2) inicializao de variveis de classe (variveis estticas)
3) inicializao de conexes ao banco de dados, etc.
Assim, podemos ter implementado em nosso Servlet ProcCadastro, por exemplo:

Inicializao do Servlet ProcCadastro


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Servlet para processamento do cadastro de novos clientes: a cada novo cadastro


bem sucedido,
// envia email com os dados do cadastro
public class ProcCadastro extends HttpServlet {
...
public void init () {
...
}
...
}

37

J2EE Primeiros Passos


As assinaturas do mtodo init() so:

Assinaturas do mtodo init ()


public void init();
public void init( javax.servlet.ServletConfig p_config );

Conforme pode ser visto, o mtodo init() admite duas assinaturas, sendo que em uma
delas, recebido como parmetro um objeto da classe javax.servlet.ServletConfig:
atravs desse objeto, o Servlet pode obter os parmetros de inicializao do Servlet,
contidos no Deployment Descriptor (veja seo 2.2). Por outro lado, caso voc opte
por implementar o mtodo init() sem nenhum parmetro, possvel tambm obter
uma referncia para o objeto ServletConfig por meio da chamada getServletConfig()
da prpria classe javax.servlet.GenericServlet (a qual nossa classe estende).

Assinatura do mtodo getServletConfig ()


public javax.servlet.ServletConfig getServletConfig ();

Para obter um parmetro de inicializao do Servlet usando o objeto ServletConfig,


deve-se utilizar o mtodo getInitParameter(), passando como parmetro o nome do
parmetro que se deseja obter.

Assinatura do mtodo getInitParameter ()


public java.lang.String getInitParameter( java.lang.String p_parameterName );

Temos, a seguir, um exemplo de uso desse mtodo:

Exemplo de uso do mtodo getInitParameter() de um objeto ServletConfig


public void init(ServletConfig p_servletConfig) throws ServletException {
super.init(p_servletConfig);

String l_servidorSMTP = p_servletConfig.getInitParameter(Email.ServidorSMTP);


if(l_servidorSMTP != null) {
...
}
}

Obviamente o mtodo getInitParameter() pode retornar um valor nulo caso o parmetro inicial a ser obtido no tenha sido definido, e por isso importante que voc
faa a verificao do String retornado pela chamada do mtodo antes de utiliz-lo.
possvel tambm, a partir de um objeto da classe ServletConfig, percorrer a lista dos
parmetros de inicializao do Servlet, bastando utilizar o mtodo getInitParameterNames().

38

Captulo 3 Servlets caractersticas bsicas

Assinatura do mtodo getInitParameterNames ()


public java.util.Enumeration getInitParameterNames();

Temos, a seguir, um exemplo de uso deste outro mtodo:

Exemplo de uso do mtodo getInitParameterNames() de um objeto


ServletConfig
public void init(ServletConfig p_servletConfig) throws ServletException {
super.init(p_servletConfig);

Enumeration l_parameterNames = p_servletConfig.getInitParameterNames ();


if(l_parameterNames != null)
while(l_parameterNames.hasMoreElements ())
{
String l_parameterName = (String) l_parameterNames.nextElement ();
String l_parameterValue =
p_servletConfig.getInitParameter(l_parameterName);
...
}
}
}

Assim, em nossa aplicao de exemplo CadastroClientes, podemos implementar o


mtodo de inicializao do Servlet ProcCadastro como:

Inicializao do Servlet ProcCadastro


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Servlet para processamento do cadastro de novos clientes:


// a cada novo cadastro bem sucedido, envia email com os dados do cadastro
public class ProcCadastro extends HttpServlet {

// Servidor SMTP a ser usado para o envio de email


private static String _ServidorSMTP = null;

// Remetente, destinatrio e assunto do email a ser enviado a cada cadastro


private static String

_Remetente = null, _Destinatario = null, _Assunto = null;

39

J2EE Primeiros Passos


public void init(ServletConfig p_servletConfig) throws ServletException {
super.init(p_servletConfig);
// Recuperando os

parmetros de inicializao do Servlet

_ServidorSMTP = p_servletConfig.getInitParameter(Email.ServidorSMTP);
_Remetente = p_servletConfig.getInitParameter(Email.Remetente);
_Destinatario = p_servletConfig.getInitParameter(Email.Destinatario);
_Assunto = p_servletConfig.getInitParameter(Email.Assunto);
...
}

Outro uso comum para o mtodo de inicializao do Servlet para o despacho de um


ou mais Threads, que devero ser executados durante o perodo em que o Servlet
permanecer carregado. Assim, um servlet pode, por exemplo, iniciar um Thread que
ir verificar continuamente a disponibilidade de uma conexo com o banco de dados, independente de qualquer requisio que receba. Este Servlet de exemplo
apresentado a seguir:

Inicializao do Servlet VerificaConBD


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Servlet para verificar conexo com banco de dados: lana thread que verifica
status da conexo periodicamente
public class VerificaConDB extends HttpServlet implements Runnable {

// Referncia ao thread que ir fazer a verificao da conexo


Thread _ThreadVerif = null;

// Inicializao do Servlet
public void init(ServletConfig p_servletConfig) throws ServletException {
super.init(p_servletConfig);

// Lanando Thread ...


_ThreadVerif = new Thread(this);
_ThreadVerif.start ();
...
}

40

Captulo 3 Servlets caractersticas bsicas


// Execuo do thread
public void run() {
while(_ThreadVerif != null) {
if(!ConBD.OK ()) {
...
}
}
}
...
}

Uma observao importante com relao a esse processo de inicializao que o


Servlet somente poder receber requisies aps a concluso de seu processo de
inicializao.
O desenvolvedor pode, por outro lado, indicar que esse processo de inicializao
no foi bem sucedido, atravs do lanamento da exceptions ServletException ou UnavailableException; nestes casos, o Servlet Container ir deixar o Servlet em um estado
inativo, ou seja, sem poder receber requisies. A exception UnavailableException,
em particular, pode receber como parmetro em seu construtor, um nmero de segundos com uma estimativa de quanto tempo o Servlet dever ficar inativo.

Exemplo de uso da exceo UnavailableException para indicar fracasso na


inicializao
public void init(ServletConfig p_servletConfig)
throws ServletException, UnavailableException

super.init(p_servletConfig);
...
// Recuperando e validando parmetros de inicializao do Servlet
_ServidorSMTP = p_servletConfig.getInitParameter(Email.ServidorSMTP);
_Remetente = p_servletConfig.getInitParameter(Email.Remetente);
_Destinatario = p_servletConfig.getInitParameter(Email.Destinatario);
_Assunto = p_servletConfig.getInitParameter(Email.Assunto);
if((_ServidorSMTP == null) || (_Remetente == null) || (_Assunto == null))
throw new UnavailableException(Erro: parmetros de inicializao no
encontrados!);

No caso de voc no ter percebido, todos os mtodos init() apresentados at agora


nos exemplos foram declarados de maneira a possibilitar o lanamento do exception
ServletException: isso necessrio devido chamada do mtodo super.init (), que
pode, por si, lanar essa exceo para indicar problemas em sua execuo.

41

J2EE Primeiros Passos

3.6 A classe ServletContext


Alm da referncia ao objeto da classe ServletConfig recebido como parmetro na
inicializao, o Servlet pode obter tambm uma referncia a um objeto da classe
javax.servlet.ServletContext atravs do mtodo getServletContext (), herdado da classe GenericServlet.

Assinatura do mtodo getServletContext ()


public javax.servlet.ServletContext getServletContext();

Esse objeto ServletContext contm os atributos e informaes sobre o contexto em


que o Servlet est sendo executado e, sendo assim, compartilhado por todos os
Servlets que fazem parte da Aplicao Web.
Analogamente ao que acontece com o objeto ServletConfig, existem mtodos para
recuperar os parmetros iniciais do contexto definidos no Deployment Descriptor
(vide seo 2.2).

Assinatura dos mtodos getInitParameterNames () e getInitParameter ()


public java.util.Enumeration getInitParameterNames();
public java.util.Enumeration getInitParameter(java.lang.String p_parameterName);

Por outro lado, importante fazer a distino entre os parmetros iniciais do Servlet e
os parmetros iniciais do contexto, lembrando sempre que esses parmetros so definidos em sees distintas do Deployment Descriptor.

Exemplo de uso do mtodo getInitParameter do objeto ServletConfig e do


objeto ServletContext
public void init(ServletConfig p_servletConfig) throws ServletException {
super.init(p_servletConfig);

// Recuperando parmetros de execuo do Servlet


String l_paramExec = p_servletConfig.getInitParameter(ParametroExecucao);

// Se no existir tal parmetro do Servlet, tentamos como parmetro do contexto


if(l_paramExec == null) {
ServletContext l_servletContext = getServletContext ();
l_paramExec = l_servletContext.getInitParameter(ParametroExecucao);
}
...
}

42

Captulo 3 Servlets caractersticas bsicas


Alm dos parmetros de inicializao do contexto do Servlet, podemos usar esse
objeto para atribuir e recuperar atributos que sero compartilhados por todos os Servlets do contexto. Assim, temos os mtodos:

Assinatura dos mtodos getAttribute (), getAttributeNames (),


removeAttribute() e setAttribute()
public java.lang.Object getAttribute(java.lang.String p_attributeName);
public java.util.Enumeration getAttributeNames();
public void removeAttribute(java.lang.String p_attributeName);
public void setAttribute(java.lang.String p_attributeName,
java.lang.Object p_attributeValue);

No exemplo a seguir, temos dois Servlets que fazem parte de uma mesma Aplicao
Web e que utilizam os atributos do contexto para indicar falhas em suas respectivas
inicializaes.

Exemplo de uso dos mtodos getAttribute e setAttribute do objeto


ServletContext
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Primeiro Servlet do exemplo


public class PrimeiroServlet extends HttpServlet {

public void init(ServletConfig p_servletConfig) throws ServletException {


super.init(p_servletConfig);

// Carregando o parmetro inicial


boolean l_sucesso = true;
String l_paramInicial =
p_servletConfig.getInitParameter(ParamPrimeiroServlet);
if(l_paramInicial == null) l_sucesso = false;
...
// Usando o atributo de contexto para indicar status da inicializao
ServletContext l_servletContext = getServletContext ();
l_servletContext.setAttribute(PrimeiroServlet, new Boolean(l_sucesso));

// Verificando status do segundo Servlet


Boolean l_statusSegundoServlet = (Boolean)
l_servletContext.getAttribute(SegundoServlet);

43

J2EE Primeiros Passos


while(l_statusSegundoServlet == null) {
Thread.sleep(5000); // Espera 5 segundos e verifica o status novamente
l_statusSegundoServlet = (Boolean)
l_servletContext.getAttribute(SegundoServlet);
}

// Se houve fracasso na inicializao deste Servlet ou do segundo,


// lanamos uma exceo
if((l_sucesso == false) || (l_statusSegundoServlet.booleanValue () == false))
throw new UnavailableException(Erro: os dois Servlets no puderam ser
carregados com sucesso!);
}

...
}

// Segundo Servlet do exemplo


public class SegundoServlet extends HttpServlet {

public void init(ServletConfig p_servletConfig) throws ServletException {


super.init(p_servletConfig);

// Carregando o parmetro inicial


boolean l_sucesso = true;
String l_paramInicial =
p_servletConfig.getInitParameter(ParamSegundoServlet);
if(l_paramInicial == null) l_sucesso = false;
...
// Usando o atributo de contexto para indicar status da inicializao
ServletContext l_servletContext = getServletContext ();
l_servletContext.setAttribute(SegundoServlet, new Boolean(l_sucesso));

// Verificando status do segundo Servlet


Boolean l_statusPrimeiroServlet = (Boolean)
l_servletContext.getAttribute(PrimeiroServlet);
while(l_statusPrimeiroServlet == null) {
Thread.sleep(5000); // Espera 5 segundos e verifica o status novamente
l_statusPrimeiroServlet = (Boolean)
l_servletContext.getAttribute(PrimeiroServlet);
}

// Se houve fracasso na inicializao deste Servlet ou do primeiro,


// lanamos uma exceo

44

Captulo 3 Servlets caractersticas bsicas


if((l_sucesso==false) || (l_statusPrimeiroServlet.booleanValue () == false))
throw new UnavailableException(Erro: os dois Servlets no puderam
ser carregados!);
}

...
}

Por fim, h um outro mtodo da classe ServletContext que vale a pena conhecer: o
mtodo log() permite que voc adicione mensagens em um arquivo de log do Servidor de Aplicaes. Voc poder utilizar esse mtodo para depurar seus Servlets, gerar
alertas de problemas na sua execuo etc.

Assinatura dos mtodo log ()


public void log(java.lang.String p_msg);

Em alguns Servidores de Aplicao voc pode tambm tentar usar as sadas-padro


(System.out, System.err) para gerar suas mensagens de log, porm, muito mais
interessante que voc use o mtodo anterior, de maneira que o ServletContainer possa separar as suas mensagens em um log diferenciado. No caso especfico do Tomcat,
as mensagens geradas por meio do mtodo log() so adicionadas a um arquivo de
log normalmente chamado localhost_log.ext.txt, onde ext uma extenso contendo
a data corrente.

Exemplo de uso do mtodo log () (da classe ServletContext)


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Servlet para teste de gerao de mensagens de log


public class TesteLog extends HttpServlet {

// Valor default para parametro inicial do Servlet


private static final String _ValorDefaultParamInicial = ;

public void init(ServletConfig p_servletConfig) throws ServletException {


super.init(p_servletConfig);

// Recuperando os

parmetros de inicializao do Servlet

String l_paramInicial = p_servletConfig.getInitParameter(ParametroInicial);


if(l_paramInicial == null) {
ServletContext l_context = p_servletConfig.getServletContext ();

45

J2EE Primeiros Passos


l_context.log(Aviso: no foi possvel se carregar o parmetro inicial;
atribuindo valor default ...);
l_paramInicial = _ValorDefaultParamInicial;
}
...
}

...
}

3.7 Finalizao
A finalizao de um Servlet deve ser tratada atravs da implementao do mtodo
destroy: no instante em que o Servlet descarregado, seu mtodo destroy(), se
tiver sido implementado, chamado, permitindo a execuo de rotinas de finalizao (como por exemplo, o encerramento de conexes com bancos de dados, finalizao de threads que tenham sido lanados etc.).
A assinatura do mtodo destroy() a seguinte:

Assinatura do mtodo destroy ()


public void destroy();

Utilizando nosso exemplo de cadastro de clientes, temos a seguir um exemplo de


nosso Servlet VerificaConBD com os mtodos init() e destroy() implementados:

Inicializao do Servlet VerificaConBD


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Servlet para verificar conexo com banco de dados: lana thread que verifica
status da conexo periodicamente
public class VerificaConDB extends HttpServlet implements Runnable {

// Referncia ao thread que ir fazer a verificao da conexo


Thread _ThreadVerif = null;

// Inicializao do Servlet
public void init(ServletConfig p_servletConfig) throws ServletException {
super.init(p_servletConfig);

46

Captulo 3 Servlets caractersticas bsicas


// Lanando Thread ...
_ThreadVerif = new Thread(this);
_ThreadVerif.start ();
...
}

// Execuo do thread
public void run() {
while(_ThreadVerif != null) {
if(!ConBD.OK ()) {
...
}
}
}

// Finalizao do Servlet
public void destroy() {
_ThreadVerif = null;
}

...
}

No exemplo, o mtodo destroy() serve para indicar que o thread deve ser finalizado:
a atribuio do valor null varivel _ThreadVerif faz com que o looping principal do
mtodo run() seja finalizado.

3.8 Atendimento de Requisies


Conforme descrito anteriormente na seo sobre o ciclo de vida de um Servlet, entre
as fases de inicializao e finalizao, existe uma fase onde o Servlet ir, efetivamente,
atender as requisies recebidas.
No caso da classe GenericServlet, que a classe utilizada para Servlets genricos
(classe-pai para a classe HttpServlet, que atende requisies HTTP), o mtodo relacionado a essa fase o mtodo service ().

Assinatura do mtodo service ()


public void service(javax.servlet.ServletRequest p_request,
javax.servlet.ServletResponse p_response);

47

J2EE Primeiros Passos


Assim, para cada requisio recebida de um cliente, o ServletContainer efetua uma
chamada a esse mtodo service(...) do Servlet; os parmetros desse mtodo so referncias para um objeto que encapsula a requisio recebida e para um objeto que
encapsula a resposta que dever ser encaminhada para o cliente.
Por outro lado, como voc normalmente estar desenvolvendo Servlets HTTP, dificilmente voc ter que implementar esse mtodo; em vez disso, para classes que extendam a classe HttpServlet, voc dever implementar um ou mais dos seguintes mtodos: doDelete, doGet, doOptions, doPost, doPut ou doTrace.

Assinatura dos mtodos de atendimento de requests da classe HttpServlet


public void doGet(javax.servlet.http.HttpServletRequest p_request,
javax.servlet.http.HttpServletResponse p_response);
public void doPost(javax.servlet.http.HttpServletRequest p_request,
javax.servlet.http.HttpServletResponse p_response);
public void doDelete( javax.servlet.http.HttpServletRequest p_request,
javax.servlet.http.HttpServletResponse p_response);
public void doPut(javax.servlet.http.HttpServletRequest p_request,
javax.servlet.http.HttpServletResponse p_response);
public void doOptions(javax.servlet.http.HttpServletRequest p_request,
javax.servlet.http.HttpServletResponse p_response);
public void doTrace(javax.servlet.http.HttpServletRequest p_request,
javax.servlet.http.HttpServletResponse p_response);

Quando uma requisio HTTP recebida por uma classe que estende HttpServlet,
seu mtodo service() chamado, sendo que a implementao default desse mtodo
ir chamar a funo doXXX () correspondente ao mtodo da requisio recebida. Ou
seja, caso uma requisio com mtodo GET, por exemplo, seja recebida (vide seo
3.2, sobre o protocolo HTTP), o mtodo doGet() implementado por voc ser chamado.
Geralmente, desenvolvedores de Servlets implementam somente os mtodos doGet()
e doPost (); os mtodos restantes s so implementados em casos especiais, e requerem um conhecimento mais avanado por parte do desenvolvedor. Por ora, estaremos utilizando o mtodo doGet(); nos captulos seguintes demonstraremos com mais
detalhes alguns dos outros mtodos (principalmente, o mtodo doPost()).
Um exemplo simples de implementao do mtodo doGet() pode ser observado a
seguir:

Servlet HelloWorld
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

48

Captulo 3 Servlets caractersticas bsicas


// Servlet para pgina HelloWorld
public class HelloWorld extends HttpServlet {

// Atendimento de requisies HTTP com mtodo GET


public void doGet(HttpServletRequest p_request,
HttpServletResponse p_response) throws IOException {
PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);
l_pw.println(Hello World!);
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}
}

3.9 Concorrncia no atendimento de requisies


Durante o ciclo de vida de um Servlet, o ServletContainer ir fazer a carga de um
Servlet instanciando um nico objeto e chamando seu mtodo init(); a finalizao
tambm efetuada chamando o mtodo destroy desse objeto.
Na fase de atendimento de requisies, por outro lado, o mtodo service() (e, consequentemente, os mtodos doXXX(), no caso de Servlets HTTP), so chamados na
medida em que so recebidas as requisies, ou seja, pode haver, em um determinado instante, um ou mais threads do ServletContainer executando mtodos service()
simultaneamente.

Figura 3.3 Concorrncia no atendimento de requisies.


Por isso muito importante que voc se preocupe com acesso a variveis de instncia ou classe e concorrncia no seu desenvolvimento (maiores detalhes sobre esses
tpicos podem ser obtidos, por exemplo, no livro Aprendendo Java 2, da Editora
Novatec).

49

J2EE Primeiros Passos


Nesse sentido, uma opo para garantir a execuo livre de problemas de concorrncia a implementao da interface SingleThreadModel em seu Servlet.
Essa interface no define, na verdade, novos mtodos ou variveis de classe, ela serve somente para indicar ao ServletContainer que o atendimento de requisies do
Servlet em questo deve ser feito de forma a serializar as chamadas ao mtodo service(). Ou seja, somente uma requisio ser atendida por vez pelo seu Servlet.

Exemplo de Servlet que implementa a interface SingleThreadModel


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Servlet simples que retorna pgina HTML com


// requisies recebidas at o momento
public class ServletContador extends HttpServlet

o nmero de
implements SingleThreadModel {

// Contador das requisies recebidas


private int _Contador = 0;

public void doGet(HttpServletRequest p_request, HttpServletResponse


p_response) throws IOException {
PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);
l_pw.println(Requisies recebidas: + Integer.toString(++ _Contador));
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}
}

No exemplo anterior, o Servlet utiliza uma varivel de instncia _Contador e, por isso,
h a necessidade de se preocupar com a concorrncia no acesso a esta varivel.
Imagine, por exemplo, que esse Servlet no implemente a interface SingleThreadModel, e receba duas requisies simultaneamente: o primeiro doGet() poderia incrementar o contador, seguido do segundo doGet() incrementando o contador, seguido
dos dois threads, cada um por sua vez, imprimindo o valor do contador. Nessa situao, o mesmo valor de contador seria impresso nas duas pginas HTML resultantes.

Resultado da primeira requisio


<HTML><BODY>
Requisies recebidas: 2
</BODY></HTML>

50

Captulo 3 Servlets caractersticas bsicas

Resultado da segunda requisio


<HTML><BODY>
Requisies recebidas: 2
</BODY></HTML>

Obviamente a implementao dessa interface tem um custo na performance de execuo do Servlet, pois, no Servlet anterior, por exemplo, no s o acesso a varivel
_Contador serializado, mas a execuo do mtodo doGet() como um todo. Em particular, a execuo dos cdigos de gerao do header e do footer HTML no precisariam ser serializados, mas so.
Por isso, em vez de implementar esta interface, na maioria das vezes mais conveniente implementar diretamente um cdigo de sincronizao nos trechos que precisam ser serializados. O Servlet ServletContador, por exemplo, poderia ser implementado da seguinte forma (com exatamente o mesmo resultado):

Exemplo de Servlet que substitui a implementao da interface


SingleThreadModel por cdigo de sincronizao
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
// Servlet simples que retorna pgina HTML com

o nmero de

// requisies recebidas at o momento


public class ServletContador extends HttpServlet {
// Contador das requisies recebidas
private int _Contador = 0;
public void doGet(HttpServletRequest p_request, HttpServletResponse
p_response) throws IOException {
// Imprimindo cabealho
PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);
// Armazenando valor do contador em uma varivel local usando sincronizao
int l_contador;
synchronized(this) {
l_contador = ++ _Contador;
}
// Imprimindo nmero de requisies recebidas e rodap
l_pw.println(Requisies recebidas: + Integer.toString(l_contador));
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}
}

51

J2EE Primeiros Passos

3.10 Retornando informaes sobre o Servlet


Alm dos mtodos doXXX(), init() e destroy(), voc tambm pode implementar o
mtodo getServletInfo() de um Servlet.

Assinatura do mtodo getServletInfo () da classe HttpServlet


public String getServletInfo ();

A implementao desse mtodo dever retornar um texto contendo informaes gerais sobre o Servlet desenvolvido, como por exemplo, o autor, verso e informaes
de copyright de seu Servlet.
Implementando esse mtodo para o nosso Servlet HelloWorld, temos:

Servlet HelloWorld com implementao do mtodo getServletInfo()


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Servlet para pgina HelloWorld


public class HelloWorld extends HttpServlet {

// Atendimento de requisies HTTP com mtodo GET


public void doGet(HttpServletRequest p_request, HttpServletResponse
p_response) throws IOException {
PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);
l_pw.println(Hello World!);
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}

// Retornando informaes sobre esse Servlet


public String getServletInfo () {
return Autor: Autores do livro; Verso: 1.0;
}
}

Caso voc no implemente esse mtodo, um texto vazio ser retornado pela implementao default desse mtodo.

52

Captulo 4
Servlets Gerao da sada
Embora j tenhamos visto um pouco sobre o funcionamento da gerao de uma resposta simples de um Servlet, estaremos neste captulo analisando esse processo mais
a fundo e apresentando algumas funcionalidades mais avanadas.

4.1 Gerao de sada HTML simples


Quando o Servlet recebe uma requisio, o mtodo doXXX() chamado com dois
parmetros: uma referncia a um objeto da classe javax.servlet.http.HttpServletRequest,
que encapsula a requisio recebida, e uma referncia a um objeto da classe
javax.servlet.http.HttpServletResponse, que encapsula a resposta do Servlet.

Figura 4.1 Atendimento de uma requisio por um Servlet.


Sendo assim, a manipulao da resposta do Servlet passa, na verdade, pela manipulao do objeto dessa classe javax.servlet.http.HttpServletResponse.
Para gerar uma sada simples, por exemplo, voc deve utilizar o mtodo getWriter()
desse objeto. A chamada desse mtodo ir retornar uma referncia a um objeto da
classe java.io.PrintWriter, que encapsula um stream de sada para um contedo do
tipo texto. Esse stream deve ser utilizado para enviar a resposta de seu Servlet para o
cliente que enviou a requisio.

53

J2EE Primeiros Passos

Assinatura do mtodo getWriter ()


public java.io.PrintWriter getWriter () throws java.io.IOException;

Embora a anlise dos mtodos dessa classe fuja um pouco ao escopo deste livro (trata-se de uma classe do prprio core Java), interessante apresentar alguns de seus
mtodos aqui.
Os mtodos print () e println () dessa classe, por exemplo, podem ser utilizados para
adicionar Strings ao stream de sada do Servlet; como a sada mantida em um buffer
por questes de performance, voc pode tambm utilizar o mtodo flush () para
forar a liberao desse buffer de sada, fazendo que o contedo da resposta definido
por voc seja imediatamente enviado para o cliente.

Exemplo de gerao de sada simples de Servlet


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Servlet para pgina HelloWorld


public class HelloWorld extends HttpServlet {

// Atendimento de requisies HTTP com mtodo GET


public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
PrintWriter l_pw = p_response.getWriter ();
l_pw.print( <HTML><BODY> );
l_pw.print( Hello World! );
l_pw.println( </BODY></HTML> );
l_pw.flush ();
}
}

Assim, nesse exemplo, utilizamos o objeto da classe java.io.PrintWriter para adicionar


um contedo texto (no caso uma pgina HTML) ao stream de sada do Servlet. A
resposta recebida pelo cliente ser justamente essa pgina HTML.
Se voc observou o exemplo anterior com cuidado (e, na verdade, todos os exemplos anteriores que incluiam algum mtodo doXXX ()), voc percebeu que o mtodo
doGet () foi declarado de maneira a possibilitar o lanamento de uma exceo
java.io.IOException: essa exceo pode ser lanada pelo mtodo getWriter () caso
haja algum problema gerao de sada do Servlet.

54

Captulo 4 Servlets Gerao da sada


Outra opo de implementao para o Servlet HelloWorld seria, portanto:
Exemplo de gerao de sada simples de Servlet com captura de exceo:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Segunda implementao do Servlet para pgina HelloWorld


public class HelloWorld extends HttpServlet {

// Atendimento de requisies HTTP com mtodo GET


{

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


try {
PrintWriter l_pw = p_response.getWriter ();
l_pw.print(<HTML><BODY>);
l_pw.print(Hello World!);
l_pw.println(</BODY></HTML>);
l_pw.flush ();
} catch( IOException p_e ) {
ServletContext l_context = getServletContext ();

l_context.log(Erro: no foi possvel


PrintWriter);

utilizar a referncia ao objeto

}
}
}

Dessa forma, podemos capturar e tratar a exceo java.io.IOException caso ela ocorra, gerando, por exemplo, uma mensagem de log.
Mais detalhes sobre essas excees lanadas durante o processo de gerao da sada
do Servlet, incluindo suas possveis causas, so apresentadas ao longo das prximas
sees desse captulo.

4.2 Headers da resposta HTTP


Conforme apresentado na seo 3.2 deste livro, a resposta a uma requisio HTTP
composta de diversos elementos, sendo que alguns desses elementos so headers
(cabealhos) HTTP.

55

J2EE Primeiros Passos

Exemplo de resposta HTTP do Servlet HelloWorld


HTTP/1.1 200 OK
Server: Apache/1.3.26 (Unix)
Last-Modified: Sun, 22 Dec 2002 17:47:59 GMT
Content-Type: text/html
Content-Length: 40

<HTML><BODY>Hello World!</BODY></HTML>

Embora alguns headers sejam adicionados por default pelo ServletContainer, como
no caso da resposta do Servlet HelloWorld acima, podem haver situaes em que
voc queira definir ou modificar seus prprios headers HTTP, e para fazer isso, voc
deve utilizar o mtodo setHeader ().

Assinatura do mtodo setHeader ()


public void setHeader( java.lang.String p_headerName, java.lang.String p_headerValue
);

Para indicar, por exemplo, que a resposta de um Servlet no deve ficar armazenada
em nenhum cache (armazenamento temporrio) do browser do usurio, nem em
nenhum proxy, podemos definir alguns headers adicionais especiais por meio do
seguinte trecho de cdigo:

Headers para evitar cacheamento da resposta de um Servlet


public void doGet( HttpServletRequest p_request, HttpServletResponse p_response ) {
...
p_response.setHeader( Cache-Control, no-cache, must-revalidate );
p_response.setHeader( Pragma, no-cache );
p_response.setHeader( Expires, Mon, 26 Jul 1997 05:00:00 GMT );
p_response.setDateHeader( Last-Modified, System.currentTimeMillis ());
...
}

Nesse cdigo, o header Expires indica a data de expirao, o header Last-Modified indica a data de ltima modificao, e os headers Cache-Control e Pragma
indicam o tratamento que o documento (ou seja, a resposta do Servlet) deve receber
se houver cacheamento.
Com a incluso do cdigo anterior, a resposta do Servlet passa a ser:

56

Captulo 4 Servlets Gerao da sada

Exemplo de resposta HTTP do Servlet HelloWorld com headers adicionais


HTTP/1.1 200 OK
Server: Apache/1.3.26 (Unix)
Cache-Control: no-cache, must-revalidate
Pragma: no-cache
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Last-Modified: Sun, 22 Dec 2002 17:47:59 GMT
Content-Type: text/html
Content-Length: 40

<HTML><BODY>Hello World!</BODY></HTML>

Uma observao muito importante que essas adies / modificaes de headers


HTTP devem acontecer antes da gerao do contedo da sada, para garantir a ordem
dos elementos da resposta HTTP (ou seja, primeiro status, depois headers e, por fim,
contedo). A alterao de um header aps a escrita de parte ou de todo o contedo
pode gerar uma exceo java.lang.IllegalStateException e interromper o processo de
gerao da sada do Servlet.
Assim, o cdigo completo para o Servlet HelloWorld sem cacheamento pode ser escrito como:

Servlet HelloWorld com headers para evitar cacheamento da pgina


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Terceira implementao do Servlet para pgina HelloWorld


public class HelloWorld extends HttpServlet {

// Atendimento de requisies HTTP com mtodo GET


{

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


try {

// Passo 1 Definindo headers


p_response.setHeader(Cache-Control, no-cache, must-revalidate);
p_response.setHeader(Pragma, no-cache);
p_response.setHeader(Expires, Mon, 26 Jul 1997 05:00:00 GMT);
p_response.setDateHeader(Last-Modified, System.currentTimeMillis ());

57

J2EE Primeiros Passos


// Passo 2 Gerando a pgina de resposta
PrintWriter l_pw = p_response.getWriter ();
l_pw.print(<HTML><BODY>);
l_pw.print(Hello World!);
l_pw.println(</BODY></HTML>);
l_pw.flush ();

} catch( IOException p_e ) {


ServletContext l_context = getServletContext ();
l_context.log(Erro: no foi possvel obter referncia ao objeto
PrintWriter);
}
}
}

Se voc observou atentamente o cdigo para a modificao dos headers, voc deve
ter reparado no uso de um mtodo setDateHeader(): esse mtodo , na verdade, uma
variante do mtodo setHeader() que simplifica a definio de um header com uma
data. Assim como esse mtodo, existe um outro mtodo setIntHeader() para a definio de headers que contenham valores inteiros.

Assinaturas dos mtodos setDateHeader() e setIntHeader()


public void setDateHeader(java.lang.String p_headerName, long p_date);
public void setIntHeader(java.lang.String p_headerName, long p_int);

O segundo parmetro do mtodo setDateHeader() deve conter o nmero de milisegundos desde epoch (meia-noite, do dia 1 de Janeiro de 1970); o mtodo currentTimeMillis() do objeto java.lang.System retorna esse valor para o instante corrente.
Alm dos mtodos anteriores, existe o mtodo containsHeader(), para verificar se um
header j foi definido, e os mtodos addHeader(), addDateHeader() e addIntHeader() que permitem a adio de mais de um valor para um mesmo header.

Assinaturas dos mtodos containsHeader(), addHeader(),addDateHeader() e


addIntHeader()
public boolean containsHeader(java.lang.String p_headerName);
public void addHeader(java.lang.String p_headerName, java.lang.String
p_headerValue);
public void addDateHeader(java.lang.String p_headerName, long p_date);
public void addIntHeader(java.lang.String p_headerName, long p_int);

Podemos usar o mtodo containsHeader() para verificar, por exemplo, se o header


Content-Type j foi definido, e defini-lo em caso negativo:

58

Captulo 4 Servlets Gerao da sada

Servlet HelloWorld com definio do header Content-Type


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Quarta implementao do Servlet para pgina HelloWorld


public class HelloWorld extends HttpServlet {

// Atendimento de requisies HTTP com mtodo GET


{

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


try {
// Passo 1 - Definindo headers
if(!p_responde.containsHeader(Content-Type))
p_response.setHeader(Content-Type, text/html);

// Passo 2 Gerando a pgina de resposta


PrintWriter l_pw = p_response.getWriter ();
l_pw.print(<HTML><BODY>);
l_pw.print(Hello World!);
l_pw.println(</BODY></HTML>);
l_pw.flush ();
} catch( IOException p_e ) {
ServletContext l_context = getServletContext ();
l_context.log(Erro: no foi possvel obter referncia ao obj
PrintWriter);
}
}
}

A funo desse header Content-Type informar o tipo do contedo que est contido
na resposta, para que o browser (ou dispositivo cliente que est fazendo o acesso)
saiba como esse contedo deve ser interpretado e apresentado.
Nos exemplos anteriores esse header no foi definido explicitamente em cdigo:
nesses casos, o ServletContainer automaticamente define seu valor como text/html.
Esse valor indica que o contedo deve ser interpretado pelo browser como uma pgina HTML.
Outro header que definido automaticamente pelo ServletContainer, caso o desenvolvedor no o defina explicitamente, o header Content-Length. Esse header indica
o tamanho em bytes do contedo contido na resposta.

59

J2EE Primeiros Passos


Podem haver casos em que seja necessrio se alterar esse comportamento default:
nesses casos, o desenvolvedor pode utilizar os mtodos setXXXHeader () apresentados anteriormente, ou o mtodo setContentLength () diretamente.

Assinatura do mtodo setContentLength()


public void setContentLength( int p_contentLength );

4.3 Gerao de outros tipos de sadas


Conforme mencionado na seo anterior, o header Content-Type serve para indicar
o tipo do contedo contido na resposta do Servlet. Dessa maneira, o valor text/html
indica uma pgina HTML, o valor image/jpeg indica uma imagem JPEG, e assim por
diante.
Devido a sua importncia, existe uma funo especial utilizada para a definio do
valor desse header.

Assinatura do mtodo setContentType()


public void setContentType(java.lang.String p_contentType);

Embora a gerao de uma sada HTML seja a situao mais comum, podem haver
situaes em que voc deseje gerar outros tipos de sada. Nesses casos, voc deve
utilizar o mtodo setContentType para especificar o tipo do contedo desejado.
Assim, podemos usar o seguinte trecho de cdigo para retornar uma imagem JPEG
contida em um arquivo:

Servlet ImageServlet
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Servlet para gerao de sada com imagem JPEG


public class ImageServlet extends HttpServlet {

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


{
FileInputStream l_imageFile = null;
try {
// Definindo o tipo do contedo
p_response.setContentType(image/jpeg);

60

Captulo 4 Servlets Gerao da sada


// Obtendo o arquivo com a imagem JPEG a partir dos parmetros
// de inicializao do Servlet
l_imageFile = new FileInputStream(getServletConfig
().getInitParameter(JpegFilename));

// Lendo o contedo de um arquivo contendo uma imagem e


// retornando este contedo como resposta
ServletOutputStream l_os = p_response.getOutputStream ();
byte [] l_buffer = new byte[1024];
int l_bytes = 0;

while((l_bytes = l_imageFile.read(l_buffer)) != -1)


l_os.write(l_buffer, 0, l_bytes);

// Finalizando processo de gerao de sada e fechando o arquivo


l_os.flush ();
l_imageFile.close ();

} catch(IOException p_e) {
try {
if(l_imageFile != null) l_imageFile.close ();
} catch(Exception p_e2) {}
ServletContext l_context = getServletContext ();
l_context.log(Erro: no foi possvel ler imagem de arquivo);
}
}
}

No exemplo anterior, voc poder observar tambm a utilizao do mtodo getOutputStream (). Esse mtodo deve ser utilizado, em substituio ao mtodo getWriter ()
que foi usado nos exemplos anteriores, para obter uma referncia a um stream de
sada binria do Servlet.
Assim, quando voc desejar que seu Servlet retorne um contedo binrio (no-texto), como uma imagem JPEG no cdigo anterior, voc dever utilizar esse mtodo
getOutputStream (), e obter uma referncia a um objeto da classe
javax.servlet.ServletOutputStream.
Esse stream ServletOutputStream estende, na verdade, a classe java.io.OutputStream
e, sendo assim, herda os diversos mtodos write() e o mtodo flush() da classe-me.

61

J2EE Primeiros Passos

Assinaturas dos mtodos write() e flush ()


public void write(byte [] p_byteArray);
public void write( byte [] p_byteArray, int p_offset, int p_length );
public void write( int p_byte );
public void flush();

Obviamente, a utilizao dos mtodos anteriores e at mesmo a obteno desse stream de sada binria do Servlet podem gerar excees do tipo java.io.IOException, em
situaes em que o usurio que est operando o browser aperta o boto Stop, antes
de todo o contedo gerado pelo seu Servlet seja enviado, por exemplo. Por isso
importante que voc se preocupe em capturar essas excees, e fazer os tratamentos
necessrios caso isso ocorra.

4.4 Gerando contedo XML


Dentre os diversos tipos de contedos que podem ser gerados como resposta de um
Servlet, apresentamos aqui, como mais um exemplo, a gerao de documentos XML.
Documentos XML so normalmente usados para estruturar um conjunto de dados de
maneira simples, bem-definida e eficiente. Um exemplo de documento XML j foi
apresentado no Captulo 2 Instalao e Configurao: o Deployment Descriptor
um arquivo XML que descreve a maneira como o ServletContainer deve carregar e
gerenciar uma Aplicao Web.
Um outro tipo de documento XML bastante utilizado atualmente o WML (definido
dentro do padro WAP, ou Wireless Application Protocol): atravs desse formato, um
servidor pode formatar um contedo que ser visualizado na tela de telefones celulares.
Embora a explicao detalhada do formato de um documento WML fuja ao escopo
deste livro (mais detalhes podem ser obtidos no site do WapForum, http://
www.wapforum.org), apresentamos abaixo o cdigo de um Servlet que gera uma
pgina WML apenas para exemplificar a gerao de um documento XML.

Servlet HelloWorldWML
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Quarta implementao do Servlet para pgina HelloWorld, desta vez com a gerao
da resposta em formato WML

62

Captulo 4 Servlets Gerao da sada


public class HelloWorldWML extends HttpServlet {

// Atendimento de requisies HTTP com mtodo GET


{

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


try {
// Passo 1 Definindo headers
// Em um documento XML normal, o Content-Type normalmente definido
// como text/xml; no caso especfico do WML este header deve ser
// definido como text/vnd.wap.wml.
p_response.setContentType(text/vnd.wap.wml);

// Passo 2 Gerando a pgina de resposta


PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<?xml version=\1.0\?>);
l_pw.println(<!DOCTYPE xml PUBLIC \-//WAPFORUM//DTD WML 1.1//EN\
\http://www.wapforum.org/DTD/wml_1.1.xml\>);
l_pw.print(<wml><card>);
l_pw.print(<p align=\center\>Hello World</p>);
l_pw.print(</card></wml>);
l_pw.flush ();
} catch(IOException p_e) {
ServletContext l_context = getServletContext ();
l_context.log(Erro: + p_e.getMessage ());
}
}
}

interessante observar no exemplo anterior a utilizao do mtodo setContentType


() para indicar o tipo do contedo na resposta; embora para documentos XML esse
tipo seja geralmente o text/xml, no caso especfico do WML ele deve ser definido
como text/vnd.wap.wml.

4.5 Status HTTP


Como explicamos na seo 3.2 deste livro, alm dos headers e do contedo propriamente dito, a resposta a uma requisio HTTP deve conter tambm a informao do
status da resposta, sendo que essa informao composta por um cdigo numrico
mais um string com uma mensagem.
Esse status utilizado no s para indicar se o processamento da requisio recebida
foi bem-sucedida ou no, mas tambm para indicar algumas outras situaes possveis, como por exemplo que o documento solicitado encontra-se disponvel em uma
outra URL.

63

J2EE Primeiros Passos


Um Servlet pode definir esse status atravs do mtodo setStatus () da classe HttpServletResponse, sendo que, conforme explicado anteriormente, para preservar a ordem
dos elementos da resposta HTTP, a chamada a esse mtodo deve ser feita antes de
qualquer definio de headers ou incio da gerao do contedo da resposta.

Assinatura do mtodo setStatus()


public void setStatus(int p_statusCode);

Nos exemplos apresentados anteriormente, como esse status no foi atribudo explicitamente em cdigo, automaticamente o ServletContainer o definiu como sendo 200,
ou status OK. Vemos a seguir, por exemplo, a resposta do Servlet HelloWorld:

Exemplo de resposta HTTP do Servlet HelloWorld


HTTP/1.1 200 OK
Server: Apache/1.3.26 (Unix)
Last-Modified: Sun, 22 Dec 2002 17:47:59 GMT
Content-Type: text/html
Content-Length: 40

<HTML><BODY>Hello World!</BODY></HTML>

Temos, a seguir, uma tabela com alguns dos cdigos de status HTTP existentes e seus
respectivos significados:
Cdigo de Status Mensagem

Significado

200

OK

Requisio foi processada com sucesso.

302

Moved Temporarily

O documento solicitado encontra-se disponvel


em outra URL.

404

Page Not Found

O documento solicitado no foi encontrado.

500

Internal Server Error

Erro no processamento / obteno do documento


requisitado.

503

Service Unavailable

O servio no se encontra disponvel.

Assim, no caso de nosso Servlet de gerao de imagem JPEG ImageServlet, podemos modific-lo de forma que ele retorne um cdigo 404 caso o arquivo com a imagem a ser gerada no exista.

Servlet ImageServlet com possvel uso do cdigo de status HTTP 404


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

64

Captulo 4 Servlets Gerao da sada


// Servlet para gerao de sada com imagem JPEG; gera cdigo de status 404
// caso o arquivo com a imagem no exista.
public class ImageServlet extends HttpServlet {

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


FileInputStream l_imageFile = null;
try {
// Verificando se o arquivo com a imagem existe
String l_filename = getServletConfig ().getInitParameter(JpegFilename);
if(l_filename != null) {
File l_file = new File(l_filename);
if(!l_file.exists ()) l_filename = null;
}
if(l_filename == null) {
// Como o arquivo no existe, retornamos o cdigo 404
p_response.setStatus(p_response.SC_NOT_FOUND);
return;
}

// Definindo o tipo do contedo


p_response.setContentType(image/jpeg);

// Obtendo o arquivo com a imagem JPEG a partir dos parmetros


// de inicializao do Servlet
l_imageFile = new FileInputStream(l_filename);

// Lendo o contedo de um arquivo contendo uma imagem e


// retornando este contedo como resposta
ServletOutputStream l_os = p_response.getOutputStream ();
byte [] l_buffer = new byte[1024];
int l_bytes = 0;

while((l_bytes = l_imageFile.read(l_buffer)) != -1)


l_os.write(l_buffer, 0, l_bytes);

// Finalizando processo de gerao de sada e fechando o arquivo


l_os.flush ();
l_imageFile.close ();

} catch( IOException p_e ) {

65

J2EE Primeiros Passos


try {
if(l_imageFile != null) l_imageFile.close ();
} catch(Exception p_e2) {}
ServletContext l_context = getServletContext ();
l_context.log(Erro: no foi possvel ler imagem de arquivo);
}
}
}

Podemos ver, nessa implementao, que o cdigo de status definido pela constante
numrica SC_NOT_FOUND da classe HttpServletResponse.

Utilizao
de
constante
javax.servlet.HttpServletResponse

SC_NOT_FOUND

da

classe

...
p_response.setStatus(p_response.SC_NOT_FOUND);
...

Para cada cdigo de status HTTP existente, a classe HttpServletResponse define uma
constante correspondente, sendo que voc deve dar preferncia ao uso dessas constantes (em vez do nmero em si) para aumentar a legibilidade de seu cdigo.
Cdigo de Status Mensagem

Constante

200

OK

SC_OK

302

Moved Temporarily

SC_MOVED_TEMPORARILY

404

Page Not Found

SC_NOT_FOUND

500

Internal Server Error

SC_INTERNAL_SERVER_ERROR

503

Service Unavailable

SC_SERVICE_UNAVAILABLE

Vale observar tambm que, para alguns cdigos de status, existem headers auxiliares
que contm indicaes sobre o que o cliente deve fazer ao receber aquele cdigo de
status.
Assim, no caso do cdigo 503 (SC_SERVICE_UNAVAILABLE), voc pode definir o
valor do header Retry-After para indicar o tempo estimado em segundos at que o
servio volte a ficar ativo.
Outro exemplo o cdigo de status 302 (SC_MOVED_TEMPORARILY): ao definir
esse cdigo de status, voc deve definir tambm o valor do header Location para
indicar a URL onde o novo documento pode ser encontrado.
Temos a seguir o exemplo de um Servlet que, dependendo do endereo IP do cliente
que envia a requisio, redireciona o acesso para uma nova pgina contendo uma
mensagem de acesso negado.

66

Captulo 4 Servlets Gerao da sada

Servlet CheckIPAccess
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Servlet para verificao do IP do cliente que faz a requisio;


// se o prefixo do IP no for reconhecido, direciona para uma pgina
// com uma mensagem de acesso negado.
public class CheckIPAccess extends HttpServlet {

// Prefixo dos IPs permitidos (rede local)


private static final String _AllowedIPPrefix = 192.168.0.;

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


try {
// Verificando o prefixo do cliente que fez a requisio
String l_ip = p_request.getRemoteAddr ();
if((l_ip != null) && (l_ip.startsWith(_AllowedIPPrefix))) l_ip = null;
if(l_ip == null) {
p_response.setStatus(p_response.SC_MOVED_TEMPORARILY);
p_response.setHeader(Location, /accessdenied.html);
return;
}

// Acesso permitido; imprimindo pgina de sucesso


PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);
l_pw.println(Parabns, seu acesso foi permitido!);
l_pw.println(</BODY></HTML>);
l_pw.flush ();

} catch(IOException p_e) {
ServletContext l_context = getServletContext ();
l_context.log(Erro: + p_e.getMessage ());
}
}
}

Essa situao de redirecionamento do acesso mostra-se to frequente que um outro


mtodo, chamado sendRedirect (), disponibilizado pela API de Servlets para a obteno desse mesmo efeito.

67

J2EE Primeiros Passos

Assinaturas do mtodo sendRedirect()


public void sendRedirect(String p_location);

Desta forma, poderamos trocar, no Servlet anterior, o trecho de cdigo:


...
if(l_ip == null) {
p_response.setStatus(p_response.SC_MOVED_TEMPORARILY);
p_response.setHeader(Location, /accessdenied.html);
return;
}
...

Pelo cdigo:
...
if(l_ip == null) {
p_response.sendRedirect(/accessdenied.html);
return;
}
...

Veremos a seguir uma variao do ServletContador, apresentado anteriormente neste livro, que utiliza o mtodo sendRedirect() para redirecionar o milsimo acesso
para uma pgina especial:

Variao do ServletContador: redireciona milsimo acesso


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Servlet simples que retorna pgina HTML com o nmero de requisies


// recebidas at o momento; redireciona milsimo acesso
public class ServletContador extends HttpServlet {

// Contador das requisies recebidas


private int _Contador = 0;

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


throws IOException {

// Armazenando valor do contador em uma varivel local usando sincronizao


int l_contador = 0;

68

Captulo 4 Servlets Gerao da sada


synchronized(this) {
l_contador = ++ _Contador;
}

// Se este for o milsimo acesso, redireciona para uma pgina especial


if(l_contador == 1000) {
p_response.sendRedirect(/premioespecial.html);
return;
}

// ... caso contrrio, imprime nmero de requisies recebidas


PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);
l_pw.println(Requisies recebidas: + Integer.toString(l_contador));
l_pw.flush ();
}
}

4.6 Cdigo de Status de erro


Alm dos mtodos setStatus () e sendRedirect () que permitem a manipulao do
status da resposta do Servlet, possvel tambm utilizar o mtodo sendError () para
indicar erros no processamento da requisio recebida.

Assinaturas do mtodo sendError()


public void sendError(int p_statusCode);
public void sendError(int p_statusCode, java.lang.String p_statusMessage);

Esse mtodo deve ser utilizado para a definio de cdigos de status nas faixas dos
400 e 500, como por exemplo, os cdigos SC_NOT_FOUND (404) e
SC_SERVICE_UNAVAILABLE (503), sendo que, se o segundo parmetro for utilizado,
este deve conter a mensagem descritiva que acompanha o cdigo de status.
Vale lembrar que de acordo com a configurao das pginas de erro da Aplicao
Web (descrita no Deployment Descriptor, vide seo 2.2), a definio de um cdigo de status de erro pode levar apresentao de uma pgina alternativa de erro.

69

J2EE Primeiros Passos

4.7 Buffering da resposta


Um ltimo recurso interessante relacionado ao processo de gerao de resposta do
Servlet o buffering do contedo dessa resposta.
Esse buffering controlado atravs dos seguintes mtodos da classe HttpServletResponse:

Assinaturas dos mtodos relacionados ao buffering de resposta do Servlet


public int getBufferSize();
public void setBufferSize( int p_size );
public boolean isCommitted();
public void reset();
public void flushBuffer();

Ao invs de simplesmente repassar para o cliente contedos parciais a cada chamada


aos mtodos de escrita da classe HttpServletResponse (como por exemplo, os mtodos println() e write()), para otimizar o desempenho da aplicao o ServletContainer
armazena esse contedo em um buffer, sendo que esse contedo repassado para o
cliente somente quando o buffer enche ou quando encerrada a execuo do Servlet.
Dessa forma, embora tenhamos dito anteriormente que h uma ordem de definio
dos elementos HTTP de resposta de um Servlet a ser obedecida, utilizando essas funes de manipulao do buffer de resposta, possvel contornar essa regra.
No exemplo a seguir, utilizamos essa funcionalidade para, dependendo do processamento realizado, redefinir os elementos da resposta do Servlet.

Servlet com manipulao dos buffers da resposta


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Servlet que realiza um processamento qualquer, e, conforme o caso,


// manipula o buffer de resposta
public class ServletBufferResposta extends HttpServlet {

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


throws IOException {

70

Captulo 4 Servlets Gerao da sada


// Imprimindo o tamanho do buffer de resposta no log da aplicao
getServletContext ().log(O tamanho default do buffer de resposta \ +
Integer.toString(p_response.getBufferSize ()) + \);

// Definindo novo tamanho de buffer de resposta de 1k


p_response.setBufferSize(1024);

// Imprimindo cabealho HTML


PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);

// Executando um processamento qualquer


boolean l_sucessoProcessamento = ExecutaProcessamento();

// Se ocorreu um erro no processamento anterior,


// modificamos o status da resposta
if(!l_sucessoProcessamento) {

// Apesar de termos definido explicitamente o tamanho do buffer, sempre


// bom verificar se o seu contedo j no foi repassado para o cliente
// por meio do mtodo isCommited ()
if(!p_response.isCommitted ()) {

// Limpamos o contedo do buffer atravs do mtodo reset e

redefinimos

// o status da resposta para INTERNAL_SERVER_ERROR (usado para


// indicar que ocorreu um erro no processamento da requisio)
p_response.reset ();
p_response.sendError( p_response.SC_INTERNAL_SERVER_ERROR );
return;
}

// Imprimindo final da resposta HTML


l_pw.println(Sucesso no processamento!</BODY></HTML>);
l_pw.flush ();
}
}

71

J2EE Primeiros Passos

72

Captulo 5
Servlets Captura de parmetros da
requisio
Alm de gerar uma resposta para cada requisio recebida, outro trabalho importante que deve ser realizado por um Servlet o de capturar e tratar os parmetros da
requisio (gerados, por exemplo, a partir de um formulrio HTML). Conforme o
resultado desse tratamento, um Servlet pode gerar respostas diferentes.
Esse captulo explora exatamente esse processo de captura dos parmetros da requisio recebida.

5.1 Informaes sobre o servidor


No Captulo 3 Servlets caractersticas bsicas desse livro (sees 3.5 e 3.6), apresentamos algumas das funes para a obteno de parmetros e atributos do Servlet
e de seu contexto.
Alm dos mtodos apresentados anteriormente, possvel obter algumas informaes adicionais relevantes, como o nome do Servlet corrente, e os dados referentes a
verso da API de Servlets suportada pelo ServletContainer (disponvel somente para
ServletContainers que implementem a especificao de Servlets 2.1 ou superior).

Assinaturas dos mtodos getServletName (), getMajorVersion() e


getMinorVersion()
public String ServletConfig.getServletName ();
public int ServletContext.getMajorVersion ();
public int ServletContext.getMinorVersion ();

Existem tambm mtodos para a obteno de informaes sobre o servidor em si,


tais como: nome do servidor, que pode ser o prprio nome da mquina na rede (dependendo de como o servidor foi instalado).

73

J2EE Primeiros Passos


A porta onde o servidor recebe as requisies; e um texto de identificao do servidor, que normalmente contm o nome e verso do software que implementa o ServletContainer.

Assinaturas dos mtodos getServerInfo (), getServerName() e getServerPort


()
public String ServletContext.getServerInfo ();
public String HttpServletRequest.getServerName ();
public int HttpServletRequest.getServerPort ();

Em particular, os mtodos getServerName () e getServerPort () devem ser chamados


a partir do objeto da classe HttpServletRequest: como cada servidor pode definir diversos servidores virtuais, atravs de uma tcnica chamada de virtual hosts, necessrio se utilizar o prprio objeto da requisio para distinguir qual o servidor (virtual) que gerou a chamada ao servlet. Mais informaes sobre esse recurso de virtual
hosts podem ser encontradas, geralmente, na documentao de servidores Web.
No prximo exemplo, utilizamos os mtodos apresentados anteriormente para construir uma pgina HTML com todas as informaes conhecidas sobre o servidor, o
Servlet e seu contexto.

Servlet para apresentao de parmetros do servidor


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Apresenta informaes do servidor


public class ServletInfoServidor extends HttpServlet {

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


throws IOException {

// Imprimindo cabealho HTML


PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);

// Imprimindo informaes sobre o servidor


l_pw.println(Texto de Identificao do Servidor: + getServletContext
().getServerInfo () + <BR>);
l_pw.println(Nome do Servidor: + p_request.getServerName () + <BR>);
l_pw.println(Porta do Servidor: + p_request.getServerPort () + <BR>);

74

Captulo 5 Servlets Captura de parmetros da requisio


// Imprimindo informaes sobre o Servlet e seu contexto
l_pw.println(Nome do Servlet: + getServletConfig ().getServletName
() + <BR>);
l_pw.println(Verso da API suportada pelo ServletContainer :
+ Integer.toString( getServletContext ().getMajorVersion ()) +
<BR>);

. + Integer.toString(getServletContext ().getMinorVersion ()) +

// Imprimindo rodap HTML


l_pw.println(</BODY></HTML>);
l_pw.flush ();
}
}

5.2 Informaes sobre a requisio


Conforme mostramos na seo 3.2 desse livro, uma requisio HTTP recebida por
um Servlet composta de alguns elementos bsicos: mtodo, path, informaes sobre a verso do protocolo e headers.
A API de Servlets permite que o desenvolvedor acesse todas essas informaes associadas a cada requisio recebida. Assim, temos de incio as seguintes funes:

Assinaturas dos mtodos associados a captura de informaes de requisio


public String HttpServletRequest.getRemoteAddr ();
public String HttpServletRequest.getRemoteHost ();
public String HttpServletRequest.getMethod ();
public String HttpServletRequest.getRequestURI ();
public String HttpServletRequest.getScheme ();
public String HttpServletRequest.getProtocol ();

Essas funes permitem recuperar o endereo IP do cliente que gerou a requisio, o


nome da mquina associada a esse endereo IP (se for possvel obter esse nome), e o
mtodo, path, e protocolo e sua verso associados a essa requisio. O protocolo da
requisio pode tambm ser chamado de esquema (= scheme).
Temos, a seguir, um Servlet que imprime essas informaes para cada requisio recebida.

Servlet que imprime informaes sobre cada requisio recebida


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

75

J2EE Primeiros Passos


// Imprime informaes sobre cada requisio recebida
public class ServletInfoReq extends HttpServlet {

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


throws IOException {

// Imprimindo cabealho HTML


PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);

// Imprimindo informaes sobre a requisio


l_pw.println(Endereo de sua mquina: + p_request.getRemoteAddr ()
+ <BR>);
l_pw.println(Nome de sua mquina: + p_request.getRemoteHost () + <BR>);
l_pw.println(Mtodo da requisio: + p_request.getMethod () + <BR>);
l_pw.println(Path da requisio: + p_request.getRequestURI () + <BR>);
l_pw.println(Protocolo da requisio: + p_request.getScheme () + <BR>);
l_pw.println(Verso do protocolo da requisio:
+ p_request.getProtocol
() + <BR>);

// Imprimindo rodap HTML


l_pw.println(</BODY></HTML>);
l_pw.flush ();
}
// Nesse Servlet, os mtodos GET e POST so tratados da mesma maneira
// (pelo mesmo trecho de cdigo)
public void doPost(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
doGet(p_request, p_response);
}
}

Assim, uma sada possvel para esse Servlet poderia ser:

Exemplo de pgina retornada pelo Servlet ServletInfoReq


<HTML><BODY>
Endereo de sua mquina: 127.0.0.1<BR>
Nome de sua mquina: localhost<BR>
Mtodo da requisio: GET<BR>
Path da requisio: /livroservlets/ServetInfoReq/a.html<BR>
Protocolo da requisio: http<BR>
Verso do protocolo da requisio: HTTP/1.1<BR>
</BODY></HTML>

76

Captulo 5 Servlets Captura de parmetros da requisio


Alm do mtodo getRequestURI () utilizado em nosso exemplo, a API de Servlets
disponibiliza algumas funes adicionais para a obteno de informao relacionadas ao path da requisio.

Assinaturas de mtodos adicionais para a obteno de informaes de path


public String HttpServletRequest.getContextPath ();
public String HttpServletRequest.getServletPath ();
public String HttpServletRequest.getPathInfo ();
public String HttpServletRequest.getPathTranslated ();
public static StringBuffer HttpUtils.getRequestURL(HttpServletRequest p_request);

Os mtodos getContextPath (), getServletPath () e getPathInfo () retornam, respectivamente, o caminho do contexto, o caminho do Servlet abaixo do contexto, e o restante do path da requisio (se exclurmos as duas primeiras informaes).
Em particular, no ambiente apresentado no Captulo 2 Instalao e Configurao
desse livro (utilizando o Apache Tomcat), o caminho do contexto equivale ao subdiretrio criado abaixo da pasta webapps, ou seja, o subdiretrio da aplicao Web.
Por outro lado, o caminho do Servlet, corresponde ao mapeamento (servlet-mapping) que originou a chamada ao Servlet.
Se o Servlet anterior, ServletInfoReq, estivesse instalado junto a uma aplicao Web
livroservlets, por exemplo, e, no Deployment Descriptor dessa aplicao Web, houvesse um mapeamento da URL /ServletInfoReq/ para esse Servlet, teramos os seguintes resultados para cada requisio recebida:
Requisio

getContextPath ()

getServletPath ()

getPathInfo ()

/livroservlets/ServletInfoReq/

/livroservlets

/ServletInfoReq

null

/livroservlets/ServletInfoReq/abc/def.html

/livroservlets

/ServletInfoReq

/abc/def.html

A funo seguinte, getPathTranslated (), tenta traduzir a informao de path da requisio para o caminho real do recurso no disco. importante observar que essa funo s funciona caso a aplicao web no tenha sido implantada como um arquivo
WAR (explicado mais adiante no Captulo 9 Tpicos Adicionais).
A ltima funo, getRequestURL(), serve para construir a URL que gerou a requisio
ao Servlet, incluindo as informaes de esquema, protocolo, mtodo etc. Essa funo
deve ser chamada diretamente a partir da classe HttpUtils do pacote javax.servlet.http,
pois trata-se de um mtodo esttico dessa classe.
Agregando, ento, essas novas funes ao Servlet ServletInfoReq, temos o cdigo a
seguir:

77

J2EE Primeiros Passos

Servlet que imprime informaes sobre cada requisio recebida


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
// Imprime informaes sobre cada requisio recebida
public class ServletInfoReq extends HttpServlet {

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


throws IOException {

// Imprimindo cabealho HTML


PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);

// Imprimindo informaes sobre a requisio


l_pw.println(Endereo de sua mquina: + p_request.getRemoteAddr ()
+ <BR>);
l_pw.println(Nome de sua mquina: + p_request.getRemoteHost () + <BR>);
l_pw.println(Mtodo da requisio: + p_request.getMethod () + <BR>);
l_pw.println(Path da requisio: + p_request.getRequestURI () + <BR>);
l_pw.println(Protocolo da requisio: + p_request.getScheme () + <BR>);
l_pw.println(Verso do protocolo da requisio: + p_request.getProtocol ()
+ <BR>);
l_pw.println(<BR>);
l_pw.println(Caminho do contexto: + p_request.getContextPath () + <BR>);
l_pw.println(Caminho do Servlet: + p_request.getServletPath () + <BR>);
l_pw.println(Informaes adicionais de caminho: + p_request.getPathInfo ()
+ <BR>);
l_pw.println(Caminho traduzido: + p_request.getPathTranslated ()
+ <BR>);
l_pw.println(URL completa da requisio: +
HttpUtils.getRequestURL(p_request) + <BR>);
// Imprimindo rodap HTML
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}
// Nesse Servlet, os mtodos GET e POST so tratados da mesma maneira
// (pelo mesmo trecho de cdigo)
public void doPost(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
doGet(p_request, p_response);
}
}

78

Captulo 5 Servlets Captura de parmetros da requisio


Com essas novas funes, uma possvel sada para esse Servlet passaria a ser:

Exemplo de pgina retornada pelo Servlet ServletInfoReq


<HTML><BODY>
Endereo de sua mquina: 127.0.0.1<BR>
Nome de sua mquina: localhost<BR>
Mtodo da requisio: GET<BR>
Path da requisio: /livroservlets/ServetInfoReq/a.html<BR>
Esquema da requisio: http<BR>
Verso do protocolo da requisio: HTTP/1.1<BR>
<BR>
Caminho do contexto: /livroservlets<BR>
Caminho do Servlet: /ServletInfoReq<BR>
Informaes adicionais de caminho: /a.html<BR>
Caminho traduzido: C:\Program Files\Apache Tomcat
4.0\webapps\livroservlets\a.html<BR>
URL completa da requisio: http://localhost:8080/livroservlets/ServletInfoReq/
a.html<BR>
</BODY></HTML>

5.3 Formulrios HTML e parmetros da requisio


Se voc j construiu pginas HTML, ou at mesmo navegou na Internet, voc j deve
ter se deparado com formulrios HTML.
Formulrios HTML possibilitam, por exemplo, que digitemos textos ou selecionemos
valores em campos de uma pgina HTML, sendo que, ao final, normalmente clicamos em um boto para que essas informaes sejam enviadas para o servidor.
Ao fazermos isso, h, na verdade, uma requisio que gerada pelo browser, sendo
que as informaes digitadas e selecionadas por ns so anexadas como parmetros dessa requisio.
Temos, a seguir, um exemplo de pgina HTML com um formulrio de cadastro.

Exemplo de pgina HTML com formulrio de cadastro


<HTML><BODY>
<FORM METHOD=POST ACTION=/livroservlets/ServletParamsReq>
Digite seu nome:<BR><INPUT TYPE=text NAME=nome SIZE=20><BR><BR>
Selecione sua(s) cor(es) preferida(s):<BR>
<SELECT NAME=cores MULTIPLE>
<OPTION VALUE=azul>azul</OPTION><OPTION VALUE=vermelho>vermelho</OPTION>

79

J2EE Primeiros Passos


<OPTION VALUE=verde>verde</OPTION><OPTION VALUE=amarelo>amarelo</OPTION>
<OPTION VALUE=branco>branco</OPTION><OPTION VALUE=preto>preto</OPTION>
</SELECT> <BR><BR>
<INPUT TYPE=submit NAME=env VALUE=Enviar>
</FORM>
</BODY></HTML>

Nesse formulrio, existem 3 parmetros que sero enviados junto com a requisio
ao servidor quando clicamos no boto Enviar: nome, cores e env. Em particular, o
parmetro cores pode estar associado a mais de um valor, dependendo de quantas
cores forem selecionados pelo usurio que visitar essa pgina.
Uma outra forma de enviar parmetros a sua concatenao diretamente no path da
requisio, bastando para isso acrescentar o caractere ? ao final do path, seguido de
pares <nome do parmetro>=<valor do parmetro>, separados pelo caractere &. Poderiamos, por exemplo, simular um envio de informaes do formulrio anterior atravs do seguinte path de requisio:
/livroservlets/ServletParamsReq/?nome=meunome&cores=azul&cores=preto&env=Enviar

Nesse caso, todo o texto que segue o caractere ? chamado de texto da query.
importante observar que os nomes e valores dos parmetros contidos nesse texto
devem estar codificados no formato MIME x-www-form-urlencoded.
Infelizmente, um estudo mais aprofundado da linguagem HTML e do protocolo HTTP
foge ao escopo desse livro, sendo deixado para o leitor a opo de consultar a literatura especfica (como os guias de HTML e HTTP da editora Novatec) para maiores
esclarecimentos.

5.4 Captura de parmetros da requisio


A API de Servlets disponibiliza diversos mtodos para capturar os parmetros de uma
requisio:

Mtodos para a captura de parmetros de formulrios HTML


public String HttpServletRequest.getParameter(String p_parameterName);
public String [] HttpServletRequest.getParameterValues(String p_parameterName);
public java.util.Enumeration HttpServletRequest.getParameterNames ();
public String HttpServletRequest.getQueryString ();

O primeiro mtodo para a obteno de parmetros da requisio o mtodo getParameter(): ele recebe um nome de parmetro e retorna o valor associado a esse nome
de parmetro.

80

Captulo 5 Servlets Captura de parmetros da requisio


Por outro lado, conforme vimos no formulrio de exemplo da seo anterior, podem
existir campos com diversos valores associados a um mesmo nome (vide campo cores do exemplo). Nesses casos, devemos utilizar o mtodo getParameterValues (),
que ir retornar no um nico valor, mas sim um array de valores.
O mtodo seguinte, getParameterNames (), retorna uma lista enumerada com todos
os nomes de parmetros recebidos. Dessa forma, possvel iterar nessa lista e obter
os respectivos valores de parmetros.
Por fim, o ltimo mtodo, getQueryString (), retorna justamente o texto da query
explicado na seo anterior, ou seja, a parte do path de requisio que vem aps o
caractere ? (se existir).
O Servlet ServletParamsReq usa os mtodos apresentados anteriormente para capturar os parmetros enviados pelo usurio e apresent-los em sua sada

Servlet que imprime parmetros de cada requisio recebida


import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Imprime parmetros de cada requisio recebida


public class ServletParamsReq extends HttpServlet {

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


throws IOException {

// Imprimindo cabealho HTML


PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);

// Imprimindo o texto da Query


if( p_request.getQueryString () != null)
l_pw.println(Texto da Query: + p_request.getQueryString () + <BR>);

// Iterando nos nomes dos parmetros


Enumeration l_paramNames = p_request.getParameterNames ();
while(l_paramNames.hasMoreElements ()) {

// Imprimindo par nome / valor


String l_paramName = (String) l_paramNames.nextElement ();

81

J2EE Primeiros Passos


String l_paramValue = p_request.getParameter(l_paramName);
l_pw.println(Parmetro: + l_paramName + <BR>);
l_pw.println( - Valor: + l_paramValue + <BR>);

// Imprimindo todos os valores para o parmetro corrente


String [] l_paramValues = p_request.getParameterValues(l_paramName);
l_pw.print( Todos os valores: );
if(l_paramValues != null)
for(int I=0; I<l_paramValues.length; I++) {
if( I == 0 ) l_pw.print(l_paramValues[ I ]);
else l_pw.print(, + l_paramValues[ I ]);
}
l_pw.println(<BR>);
}
// Imprimindo rodap HTML
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}

// Nesse Servlet, os mtodos GET e POST so tratados da mesma maneira


// (pelo mesmo trecho de cdigo)
public void doPost(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
doGet(p_request, p_response);
}
}

Se utilizarmos o formulrio apresentado na seo anterior para enviar informaes


para esse Servlet, uma sada possvel seria:

Exemplo de pgina retornada pelo Servlet ServletInfoReq


<HTML><BODY>
Parmetro: nome<BR>
- Valor: meunome<BR>
-Todos os valores: meunome<BR>
Parmetro: cores<BR>
- Valor: azul<BR>
-Todos os valores: azul, verde<BR>
Parmetro: env<BR>
- Valor: Enviar<BR>
-Todos os valores: Enviar<BR>
</BODY></HTML>

82

Captulo 5 Servlets Captura de parmetros da requisio


Frequentemente, quando voc quiser adicionar interatividade a sua aplicao Web,
permitindo que o usurio envie dados ao servidor, voc ir utilizar formulrios HTML,
e por isso, muito importante que voc domine os mtodos apresentados nessa seo.

5.5 Headers da requisio HTTP


Assim como acontece na resposta de um Servlet, a requisio recebida tambm pode
conter headers. Esses headers podem servir para indicar, por exemplo, caractersticas sobre o cliente que gerou a requisio.

Mtodos para a captura de informaes de headers da requisio


public String HttpServletRequest.getHeader(String p_headerName);
public long HttpServletRequest.getDateHeader(String p_headerName);
public int HttpServletRequest.getIntHeader(String p_headerName);
public java.util.Enumeration HttpServletRequest.getHeaders(String p_headerName);
public java.util.Enumeration HttpServletRequest.getHeaderNames();

Os mtodos getHeader (), getDateHeader () e getIntHeader() servem para recuperar


o contedo de um header e se comportam de maneira anloga aos respectivos mtodos set...Header() apresentados na seo 4.2 desse livro: o mtodo getDateHeader ()
recupera o contedo de um header contendo uma data, e o mtodo getIntHeader ()
recupera o contedo de um header contendo um nmero inteiro.
O mtodo getHeaders (), por sua vez, permite obter todos os valores associados a um
determinado header: caso voc saiba de antemo que um header ir ter diversos
valores associados, voc deve utilizar esse mtodo para garantir a recuperao de
todos esses valores.
Por fim, o mtodo getHeaderNames () retorna uma lista enumerada de todos os nomes de headers recebidos. Com isso, voc pode usar essa funo para iterar na lista
de todos os headers recebidos.
Um uso frequente para esses mtodos o de verificao do header user-agent, que
indica o tipo e verso do software do cliente que enviou a requisio. Por meio desse
header, voc pode gerar um documento diferenciado para cada tipo de browser que
acessa a sua aplicao.
O header accept tambm bastante importante: ele indica os tipos de contedos
aceitos pelo cliente. O Servlet ServletVerAccept a seguir verifica o contedo desse
header e, dependendo de seu valor, retorna uma pgina de saudao em formato
HTML ou WML; dessa forma, ele pode ser usado tanto para atender requisies de
browsers normais da Internet, como tambm para atender requisies de browsers
de telefones celulares (vide seo 4.3).

83

J2EE Primeiros Passos

Servlet ServletVerAccept
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Verifica o valor do header accept e retorna pgina HTML


// ou WML dependendo de seu contedo
public class ServletVerAccept extends HttpServlet {

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


throws IOException {

PrintWriter l_pw = p_response.getWriter ();


// Verificando contedo do header accept
String l_acceptHeader = p_request.getHeader(accept);
if((l_acceptHeader != null) && l_acceptHeader.equals(text/vnd.wap.wml)) {
// O cliente aceita contedo WML; temos que definir o content-type
p_response.setContentType(text/vnd.wap.wml);
// Depois geramos o contedo WML
l_pw.println(<?xml version=\1.0\?>);
l_pw.println(<!DOCTYPE xml PUBLIC \-//WAPFORUM//DTD WML 1.1//EN\
\http://www.wapforum.org/DTD/wml_1.1.xml\>);
l_pw.print(<wml><card>);
l_pw.print(<p align=\center\>Ol</p>);
l_pw.print(</card></wml>);
}
else {
// O cliente no aceita contedo WML; geramos uma pgina HTML
l_pw.println(<HTML><BODY>);
l_pw.println(<P>Ol</P>);
l_pw.println(</BODY></HTML>);
}
l_pw.flush ();
}
}

5.6 Upload de arquivos


Alm dos campos normais de input, seleo e botes de um formulrio HTML, existe
um tipo de campo especial que permite o upload (ou transferncia) de arquivos da
mquina do usurio para o servidor.

84

Captulo 5 Servlets Captura de parmetros da requisio

Exemplo de pgina HTML com formulrio para upload de arquivo


<HTML><BODY>
<FORM

METHOD=POST ACTION=/livroservlets/ServletUploadArq/
ENCTYPE=multipart/form-data>

Selecione o arquivo:<BR><INPUT TYPE=file NAME=arquivo><BR><BR>


<INPUT TYPE=submit NAME=envio VALUE=Enviar>
</FORM>
</BODY></HTML>

Nesse formulrio de exemplo, o campo arquivo do tipo file; esse campo permite
que seja selecionado um arquivo do disco local que ser enviado junto com a requisio. Vale a pena observar tambm que existe um atributo adicional ENCTYPE, com
contedo multipart/form-data, que deve ser especificado junto ao elemento FORM.
A maneira mais fcil de se tratar esse tipo de parmetro de requisio em um Servlet
utilizando classes prontas de terceiros. Um exemplo de uma biblioteca que pode
ser utilizada para esse tipo de tratamento pode ser encontrada no endereo http://
sourceforge.net/projects/multpartrequest/.
O servlet ServletUploadArq a serguir utiliza essa biblioteca para tratar arquivos carregados pelo formulrio HTML do exemplo anterior.

Servlet ServletUploadArq
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import http.utils.multipartrequest.ServletMultipartRequest;
import http.utils.multipartrequest.MultipartRequest;
// Trata arquivos transferidos do cliente para o servidor
public class ServletUploadArq extends HttpServlet {
public void doPost(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
PrintWriter l_pw = p_response.getWriter ();
// Obtendo informaes sobre o arquivo carregado
// O primeiro parmetro a requisio, o segundo o nome de um diretrio
// temporrio onde devero ser armazenados os arquivos carregados no servidor,
// o terceiro o tamanho mximo em bytes permitidos, e o quarto pode
// definir o encoding a ser utilizado pelo parser (o default ISO-8859-1)
MultipartRequest l_parser = new ServletMultipartRequest(p_request,
C:\\temp, MultipartRequest.MAX_READ_BYTES, null);
String l_nomeArq = l_parser.getBaseFilename(arquivo);// Nome do arquivo
// Tamanho do arquivo
String l_tamArq = Long.toString(l_parser.getFileSize(arquivo));

85

J2EE Primeiros Passos


// Nome local do arquivo: o contedo do arquivo carregado gravado em um
// arquivo temporrio local abaixo do diretrio especificado no construtor da
// classe ServletMultipartRequest
File l_arqLocal = l_parser.getFile(arquivo);
String l_nomeArqLocal = l_arqLocal.getName ();

// Imprimindo header HTML


l_pw.println(<HTML><BODY>);

// Imprimindo informaes sobre o arquivo recebido


l_pw.println(Nome do arquivo: + l_nomeArq + <BR>);
l_pw.println(Tamanho do arquivo: + l_tamArq + <BR>);
l_pw.println(Nome do arquivo temporrio local: + l_nomeArqLocal + <BR> );

// Imprimindo rodap HTML


l_pw.println(</BODY></HTML);
l_pw.flush ();
}
}

No Servlet anterior, usamos alguns dos mtodos disponveis na biblioteca MultipartRequest. Para conhecer todos as suas funcionalidades, voc deve fazer o download
da biblioteca, e observar a documentao de sua API.

5.7 Atributos da requisio


Finalmente, alm de todos os mtodos apresentados anteriormente, existem mtodos para definir e recuperar atributos da requisio. Esses atributos funcionam como
os atributos do contexto do Servlet apresentados na seo 3.6, exceto que seu escopo
est limitado requisio.

Mtodos para definir / recuperar atributos da requisio


public String HttpServletRequest.getAttribute( String p_attributeName );
public util.Enumeration HttpServletRequest.getAttributeNames ();
public void HttpServletRequest.setAttribute( String p_attributeName, Object
p_attributeValue );

Embora estejamos falando desses mtodos pela primeira vez nesse captulo, exemplos e uma explicao mais detalhada de seu uso sero apresentados no Captulo 8
Modelo MVC.

86

Captulo 6
Servlets Cookies e Sesses
Nesse captulo so explorados os conceitos de Cookies e Sesses: atravs dessas tcnicas, veremos como possvel armazenar informaes sobre os usurios que utilizam nossas aplicaes.

6.1 Armazenando informaes do usurio


Como explicamos na seo 3.2, o HTTP um protoloco stateless, ou seja, ele no
mantm um histrico das requisies recebidas de um mesmo cliente.
Assim, imaginando uma aplicao simples como um carrinho de compras de uma
livraria virtual, por exemplo, como devemos proceder para manter o histrico dos
livros j selecionados pelo nosso cliente? Se a seleo de cada livro gera 1 ou mais
requisies, no momento do fechamento da compra, como fazemos para saber quais
foram todos os livros selecionados?
Existem algumas maneiras diferentes de resolver esse problema, de maneira a contornar essa limitao do protocolo HTTP, como veremos a seguir.

6.2 Campos escondidos de formulrios HTML


Alm dos tipos de campos de formulrios HTML apresentados na seo 5.3 desse
livro, existe tambm um tipo, chamado hidden, que pode ser usado para esconder
parmetros da requisio.
Na pgina HTML seguinte, o campo contador do tipo hidden.

87

J2EE Primeiros Passos

Exemplo de formulrio HTML com campo hidden


<HTML><BODY>
<FORM METHOD=POST ACTION=/livroservlets/ServletContadorReq/>
Contador de requisies: 0<BR>
<INPUT TYPE=hidden NAME=contador VALUE=0><BR><BR>
<INPUT TYPE=submit NAME=Atualizar VALUE=Atualizar>
</FORM>
</BODY></HTML>

Se voc tentar abrir essa pgina em um browser, voc poder observar que o campo
contador no visvel; por outro lado, o nome e valor desse campo sero recebidos
normalmente como um parmetro de requisio pelo seu Servlet.
Assim, podemos construir o Servlet a seguir para contar o nmero de requisies
recebidas de cada cliente:

Servlet ServletContadorReq
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Conta o nmero de requisies recebidas de cada cliente


public class ServletContadorReq extends HttpServlet {
public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
PrintWriter l_pw = p_response.getWriter ();

// Atualizando o contador para o cliente corrente (dessa requisio)


// Em particular, se essa for a primeira requisio recebida,
// o valor do parmetro contador nulo, e, nesse caso inicializamos
// o contador com o valor 0.
int l_contador = 0;
try {
l_contador = Integer.parseInt(p_request.getParameter(contador));
++ l_contador;
} catch(NumberFormatException p_e) {
l_contador = 0;
}

// Apresentando o valor do contador e o formulrio HTML que ir


// permitir o incremento do mesmo
l_pw.println(<HTML><BODY>);

88

Captulo 6 Servlets Cookies e Sesses


l_pw.println(<FORM METHOD=\POST\ ACTION=\/livroservlets
ServletContadorReq/\>);
l_pw.println(Contador de requisies: +Integer.toString(l_contador)
+<BR>);
l_pw.println(<INPUT TYPE=\hidden\ NAME=\contador\ VALUE=\
+ Integer.toString(l_contador) + \><BR><BR>);
l_pw.println(<INPUT TYPE=\submit\ NAME=\Atualizar\
VALUE=\Atualizar\>);
l_pw.println(</FORM>);
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}

// Nesse Servlet, os mtodos GET e POST so tratados da mesma maneira


// (pelo mesmo trecho de cdigo)
public void doPost(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
doGet(p_request, p_response);
}
}

O Servlet ServletContadorReq anterior usa o campo escondido contador para armazenar o valor do contador na ltima requisio recebida, sendo que esse valor repassado de volta para o Servlet cada vez que o cliente pressiona o boto Atualizar.
Assim como acontece nesse Servlet, voc pode utilizar campos escondidos de formulrios HTML para armazenar informaes e fazer com que sejam passadas para seus
Servlets junto com as requisies futuras recebidas.
Por outro lado, esse mtodo tem uma grande desvantagem: para utiliz-lo, voc precisa garantir que, uma vez armazenado um valor em um campo escondido, todas as
requisies recebidas carregaro esse parmetro junto.
Isso pode gerar um grande trabalho na construo de sua aplicao, alm de no
funcionar em todos os casos: se o usurio de sua aplicao sair de sua pgina, ou at
mesmo usar os botes de navegao de seu browser (como o boto de voltar, por
exemplo), ele automaticamente ir perder os ltimos parmetros definidos.

6.3 Informaes adicionais de caminho


Outra forma de armazenar / passar informaes entre requisies subsequentes de
um mesmo cliente utilizando as informaes adicionais de caminho.
O Servlet ServletContadorReq da seo anterior, por exemplo, poderia ser modificado para passar o valor atual do contador como uma informao adicional do caminho.

89

J2EE Primeiros Passos

Servlet ServletContadorReqMod
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Conta o nmero de requisies recebidas de cada cliente


public class ServletContadorReqMod extends HttpServlet {
public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
PrintWriter l_pw = p_response.getWriter ();

// Extraindo informaes adicionais de caminho


String l_infoPath = p_request.getPathInfo ();
if( (l_infoPath != null) && l_infoPath.startsWith(/) &&
(l_infoPath.length () > 1)) l_infoPath = l_infoPath.substring(1);
// Atualizando o contador para o cliente corrente (dessa requisio)
// Em particular, se essa for a primeira requisio recebida, o valor do
// parmetro contador nulo, e, nesse caso inicializamos o contador
// com o valor 0.
int l_contador = 0;
try {
l_contador = Integer.parseInt(l_infoPath);
++ l_contador;
} catch(NumberFormatException p_e) {
l_contador = 0;
}
// Apresentando o valor do contador e o formulrio HTML que ir
// permitir o incremento do mesmo
l_pw.println(<HTML><BODY>);
l_pw.println(Contador de requisies: + Integer.toString(l_contador)
+ <BR><BR>);
l_pw.println(<A HREF=\/livroservlets/ServletContadorReqMod/
+ Integer.toString(l_contador) + \>Atualizar</A>);
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}
// Nesse Servlet, os mtodos GET e POST so tratados da mesma maneira
// (pelo mesmo trecho de cdigo)
public void doPost(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
doGet(p_request, p_response);
}
}

90

Captulo 6 Servlets Cookies e Sesses


Em relao a utilizao de campos escondidos, essa tcnica possui a vantagem de
simplificar um pouco a construo de seus Servlets. Por outro lado, ela no resolve os
problemas apontados anteriormente com relao a perda dos parmetros definidos.

6.4 Cookies
Para resolver esse problema da persistncia das informaes associadas a um cliente,
necessria a utilizao de Cookies.
Cookies so pacotes de dados, gerados pelo servidor, e que so enviados junto com
a resposta de uma requisio, ficando armazenadas pelo browser do usurio. Posteriormente, a cada requisio enviada, o browser anexa tambm as informaes desses Cookies, permitindo que o servidor recupere os valores definidos anteriormente.
Um estudo completo de Cookies foge ao escopo desse livro; para obter mais detalhes
sobre eles, deve-se consultar a RFC 2109 (mais informaes no site http://
www.apps.ietf.org/rfc/rfc2109.html), que contm sua especificao.
Por outro lado, vale a pena conhecer os principais atributos de um Cookie; alm de
um nome, que identifica o Cookie para um determinado servidor e path nesse servidor, e o valor, que contm os dados em si, um Cookie possui tambm alguns atributos
adicionais:
Comentrio (Comment) Deve conter um texto descrevendo o propsito e funo do Cookie;
Perodo de expirao (MaxAge) Determina por quanto tempo (em segundos) o
Cookie ser vlido;
Domnio (Domain) Por default, uma vez definido, um Cookie s retornado
junto com requisies para o mesmo servidor que o gerou. Esse atributo permite,
por outro lado, que esse Cookie seja enviado para todos os servidores abaixo de
um mesmo domnio (conforme especificado na RFC 2109);
Caminho (Path) Por default, uma vez definido, um Cookie s passado junto
com as requisies para os recursos abaixo do diretrio virtual do recurso que
gerou o Cookie. Se esse caminho for definido, por outro lado, o Cookie passa a
ser enviado junto com as requisies para qualquer recurso abaixo caminho especificado;
A API de Servlets disponibiliza uma classe especial para representar um Cookie, a
classe javax.servlet.http.Cookie, sendo que os mtodos dessa classe permitem definir
/ recuperar os valores de seus diversos atributos.

91

J2EE Primeiros Passos

Mtodos para definir / recuperar os principais atributos do Cookie


public String getName ();
public String getValue ();
public void setValue(String p_value);
public String getComment ();
public void setComment(String p_comment);
public String getDomain ();
public void setDomain(String p_domain);
public String getPath ();
public void setPath(String p_path);
public int getMaxAge ();
public void setMaxAge(int p_maxAge);

Para usar um Cookie, primeiro devemos cri-lo, passando como parmetros de seu
construtor o nome e valor do Cookie, e, em seguida, devemos definir seus atributos.
Finalmente, o Cookie deve ser adicionado ao objeto HttpServletResponse para que
seja enviado para o browser do usurio.

Exemplo de cdigo com definio de Cookie

Cookie l_cookie = new Cookie(Contador, 0);


l_cookie.setComment(Cookie de exemplo / teste);
l_cookie.setMaxAge(60);
p_response.addCookie(l_cookie);

No cdigo anterior, estamos gerando um Cookie de nome Contador, com o valor 0, e


que ter validade de 60 segundos a partir do instante em que for recebido pelo usurio; passado esse perodo, o Cookie automaticamente descartado pelo browser. Um
valor negativo para o perodo de expirao indica que o Cookie deve ser vlido enquanto o browser no for encerrado, e o valor 0 indica que o Cookie deve ser removido imediatamente pelo browser.
importante observar tambm que, a menos que voc esteja fazendo o controle do
buffer de resposta conforme descrito na seo 4.6, esse procedimento de criao e
adio de Cookies a resposta do Servlet deve acontecer antes de gerar o contedo da
resposta propriamente dito, de forma a preservar a ordem dos elementos HTTP da
resposta do Servlet.
Aps gerarmos todos os Cookies desejados, podemos recuper-los nas requisies
seguintes atravs do mtodo getCookies() da classe HttpServletRequest. Esse mtodo
retorna null se no houver nenhum Cookie na requisio recebida, ou um Array com
os Cookies recebidos.

92

Captulo 6 Servlets Cookies e Sesses


Infelizmente, no existe um mtodo para a recuperao direta de um Cookie especfico; necessrio utilizar esse mtodo para recuperar todos os Cookies, e, ento,
iterar nessa lista at acharmos o Cookie que estamos procurando.
Assim, podemos utilizar o trecho de cdigo a seguir para obter o valor do Cookie
Contador definido anteriormente.

Exemplo de cdigo para obteno de um Cookie

Cookie [] l_cookies = p_request.getCookies ();


If(l_cookies != null)
for(int i=0; i<l_cookies.length; i++)
if((l_cookies[i].getName () != null) && (l_cookies[i].getName
().equals(Contador)))
try {
l_contador = Integer.parseInt(l_cookies[ i ].getValue ());
} catch(NumberFormatException p_e) {
l_contador = 0;
}

Com os mtodos e recursos apresentados, podemos reimplementar nosso Servlet


ServletContadorReq da seguinte forma:

Reimplementao do Servlet ServletContadorReq


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Conta o nmero de requisies recebidas de cada cliente


public class ServletContadorReq extends HttpServlet {
public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {

// Definindo headers auxiliares para evitar cacheamento da pgina


p_response.setHeader(Cache-Control, no-cache, must-revalidate);
p_response.setHeader(Pragma, no-cache);
p_response.setHeader(Expires, Mon, 26 Jul 1997 05:00:00 GMT);
p_response.setDateHeader(Last-Modified, System.currentTimeMillis ());

// Atualizando o contador para o cliente corrente (dessa requisio)


// Em particular, se essa for a primeira requisio recebida,

93

J2EE Primeiros Passos


// o valor do parmetro contador nulo, e, nesse caso inicializamos
// o contador com o valor 0.
// OBS: procuramos o valor do contador entre os cookies
// recebidos com a requisio
Cookie [] l_cookies = p_request.getCookies ();
int l_contador = 0;
if(l_cookies != null)
for(int i=0; i<l_cookies.length; i++)
if((l_cookies[i].getName () != null) && (l_cookies[i].getName
().equals(Contador)))
try {
l_contador = Integer.parseInt(l_cookies[i].getValue ());
l_contador ++;
} catch(NumberFormatException p_e) {
l_contador = 0;
}

// Guardando o valor corrente do contador em um Cookie


Cookie l_cookie = new Cookie(Contador, Integer.toString(l_contador));
l_cookie.setComment(Cookie com contador para ServletContadorReq);
l_cookie.setMaxAge(60 * 60 * 24);

// Validade=60 segs * 60 min * 24h = 1 dia

p_response.addCookie(l_cookie);

// Apresentando o valor do contador


PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);
l_pw.println(Contador de requisies: + Integer.toString(l_contador)
+ <BR><BR>);
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}

// Nesse Servlet, os mtodos GET e POST so tratados da mesma maneira


// (pelo mesmo trecho de cdigo)
public void doPost(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
doGet(p_request, p_response);
}
}

Nessa nova implementao do Servlet, vale a pena observar que no necessrio


que o usurio de nossa aplicao clique em nada para que o contador seja atualizado,
basta que ele recarregue a pgina. At mesmo se o usurio visitar outra pgina e
depois voltar para o endereo desse Servlet, o contador incrementado.

94

Captulo 6 Servlets Cookies e Sesses


Infelizmente, existem situaes em que Cookies no funcionam: geralmente isso acontece quando o browser do usurio est configurado explicitamente para no aceitar
Cookies. Com as crescentes preocupaes em torno da privacidade de quem navega
na Internet, alguns usurio passaram a bloquear o armazenamento de Cookies em
seus browsers.

6.5 Gerenciamento de sesses


A API de Servlets disponibiliza um mdulo extremamente til no controle de informaes associadas ao usurio que acessa nossa aplicao: o mdulo de gerenciamento de sesses de usurios.
Basicamente, esse mdulo funciona da seguinte forma: a primeira vez que o usurio
acessa nossa aplicao, criado para ele um identificador de sesso, ao qual associado um objeto da classe javax.servlet.http.HttpSession na memria do servidor de
aplicaes. A partir da, o servidor de aplicaes procura fazer com que todas as requisies vindas daquele usurio carreguem esse identificador de sesso, seja atravs
da definio de Cookies, ou atravs da reescrita das URLs (com informaes adicionais de caminho) para que incorporem essa informao. Recebido esse identificador,
a API automaticamente disponibiliza para o Servlet o objeto HttpSession criado anteriormente.
Dessa forma, um Servlet pode utilizar esse objeto HttpSession em memria para armazenar informaes que queira associar a um usurio especfico que acessa a aplicao. Essas informaes estaro disponveis em todas as requisies posteriores recebidas no s pelo Servlet que as armazenou, mas tambm para todos os Servlets que
compartilharem do mesmo contexto.
Para obter uma referncia ao objeto dessa classe HttpSession, um Servlet deve utilizar
o mtodo getSession () da classe HttpServletRequest; esse mtodo possui, na verdade, duas assinaturas.

Assinaturas para o mtodo getSession () da classe HttpServletRequest


public javax.servlet.http.HttpSession getSession();
public javax.servlet.http.HttpSession getSession(boolean p_createSession);

A primeira assinatura retorna sempre um objeto da sesso, sendo que esse objeto
pode ter sido criado nesse instante, ou ter sido criado em uma requisio anterior (ou
seja, j havia uma sesso criada).
A segunda assinatura, por sua vez, admite um parmetro que, se for true, faz com que
o mtodo tenha o mesmo comportamento da primeira assinatura. Caso contrrio, o
mtodo pode retornar null: se ainda no houver uma sesso criada, ao invs de criar
uma nova sesso, o mtodo retorna null.

95

J2EE Primeiros Passos


Podemos, ento, utilizar o seguinte trecho de cdigo para obter o objeto com a sesso corrente:

Primeira alternativa de cdigo para obteno do objeto HttpSession para a sesso


corrente

HttpSession l_session = p_request.getSession( false );


if(l_session != null)
{
// Tratamento do objeto com sesso

}
else
{
// Sesso ainda no foi criada, necessrio se criar uma nova sesso.

O cdigo anterior utiliza a segunda assinatura do mtodo getSession() para obter a


sesso corrente. Uma alternativa melhor de cdigo apresentada a seguir, utilizando
a primeira assinatura do mtodo getSession ():

Cdigo para obteno do objeto HttpSession para a sesso corrente

HttpSession l_session = p_request.getSession();


if(l_session.isNew ())
{
// Uma nova sesso acabou de ser criada; cdigo para tratar esse caso

}
else
{
// A sesso j havia sido criada em uma requisio anterior;
// cdigo para tratar esse outro caso

No cdigo anterior, podemos observar tambm a utilizao de um mtodo isNew()


da classe HttpSession: esse mtodo indica se o identificador da sesso j foi enviado
para o browser cliente ou no (ou seja, se a sesso acabou de ser criada). Alm desse
mtodo, a classe HttpSession oferece diversos outros mtodos:

96

Captulo 6 Servlets Cookies e Sesses

Mtodos da classe HttpSession


public void setAttribute(String p_attributeName, Object p_attributeValue);
public Object getAttribute(String p_attributeName);
public void removeAttribute(String p_attributeName);
public java.util.Enumeration getAttributeNames ();
public String getId ();
public long getCreationTime ();
public long getLastAccessedTime ();

Os primeiros quatro mtodos apresentados permitem gerenciar os objetos que queremos associar a sesso do usurio de forma similar a manipulao de uma Hashtable. Dessa forma, para cada objeto que queremos armazenar na sesso HTTP, ns
devemos associar um nome de atributo, e manipular o objeto como valor desse atributo.
Assim, se quisermos definir um atributo de sesso de nome Contador, contendo o
valor do contador de requisies usados nos Servlets ServletContadorReq, podemos
utilizar o seguinte trecho de cdigo:

Cdigo com exemplo de definio de atributo de sesso

HttpSession l_sessao = p_request.getSession(true);


l_sessao.setAttribute(Contador, new Integer(l_contador));

Para recuperar o valor desse atributo posteriormente, podemos utilizar esse outro
trecho de cdigo:

Cdigo com exemplo de recuperao de atributo de sesso

HttpSession l_sessao = p_request.getSession(true);


Integer l_contadorInt = (Integer) l_sessao.getAttribute(Contador);

Os trs mtodos seguintes, getId (), getCreationTime () e getLastAccessedTime (),


retornam, respectivamente, o identificador dessa sesso, o instante de criao da sesso e o instante de ltimo acesso do usurio com a sesso corrente (esses dois ltimos valores em milisegundos, desde 1 de janeiro de 1970 GMT).
O Servlet a seguir utiliza os mtodos apresentados anteriormente para construir uma
pgina HTML com todas as informaes sobre a sesso corrente do usurio:

97

J2EE Primeiros Passos

Servlet ServletInfoSessao
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Imprime informaes sobre a sesso corrente do usurio


public class ServletInfoSessao extends HttpServlet {
public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {

// Definindo headers auxiliares para evitar cacheamento da pgina


p_response.setHeader(Cache-Control, no-cache, must-revalidate);
p_response.setHeader(Pragma, no-cache);
p_response.setHeader(Expires, Mon, 26 Jul 1997 05:00:00 GMT);
p_response.setDateHeader(Last-Modified, System.currentTimeMillis ());

// Imprimindo header HTML


PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);
// Obtendo informaes sobre a sesso corrente do usurio
HttpSession l_sessao = p_request.getSession(true);
if(!l_sessao.isNew ())
{
l_pw.println(ID da sesso: + l_sessao.getId () + <BR>);
l_pw.println(Instante de criao da sesso (em miliseg., desde epoch):
+ Long.toString(l_sessao.getCreationTime ()) + <BR>);
l_pw.println(Instante de ltimo acesso (em milisegundos, desde epoch):
+ Long.toString( l_sessao.getLastAccessedTime ()) + <BR>);
Enumeration l_nomesAtribs = l_sessao.getAttributeNames ();
while( l_nomesAtribs.hasMoreElements ())
{
String l_nomeAtrib = (String) l_nomesAtribs.nextElement ();
Object l_objSessao = l_sessao.getAttribute(l_nomeAtrib);
if(l_objSessao instanceof java.lang.String)
l_pw.println(Nome de Atributo: ( + l_nomeAtrib + ) => Valor de
Atributo: ( + (String) l_objSessao + )<BR>);
else l_pw.println(Nome de Atributo: ( + l_nomeAtrib + )=> Valor de
Atributo (Objeto no String)<BR>);
}
}
else l_pw.println(Nova sesso criada!<BR>);

98

Captulo 6 Servlets Cookies e Sesses


// Footer HTML
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}

// Nesse Servlet, os mtodos GET e POST so tratados da mesma maneira


// (pelo mesmo trecho de cdigo)
public void doPost(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
doGet(p_request, p_response);
}
}

A outra caracterstica importante desse mdulo de gerenciamento de sesses que


ele permite que sesses criadas automaticamente expirem aps um determinado tempo de inatividade. Obviamente, o desenvolvedor tambm pode expirar uma sesso
explicitamente atravs de sua programao.
Essa funcionalidade, presente em diversas tecnologias de desenvolvimento de aplicaes para a Web, pode ser observada, por exemplo, em sites que exigem a autenticao do usurio, como por exemplo, em um site de Internet Banking.
Nesses sites, aps o login, se o usurio ficar um longo perodo de tempo sem interagir
com o site, sua sesso expirada, de forma que ele no consiga utilizar mais nenhuma funo do site antes de efetuar o login novamente. O mesmo ocorre se o usurio
clicar no boto ou link de sair / logoff.
Isso ocorre dessa maneira para reforar a segurana do sistema; uma segunda pessoa
que utilize o mesmo browser do usurio que acessou a aplicao ter que efetuar o
login para conseguir ter acesso as funes do sistema. Caso contrrio esse segundo
usurio poderia simplesmente usar o sistema em nome do primeiro usurio.
A API de Servlets oferece as seguintes funes para controlar a expirao da sesso
do usurio.

Mtodos para controle da expirao da sesso


public int getMaxInactiveInterval ();
public void setMaxInactiveInterval(int p_interval);
public void invalidate ();

As duas primeiras funes permitem, respectivamente, obter e definir o perodo mximo de inatividade em segundos antes que o ServletContainer invalide a sesso do
usurio, e o terceiro mtodo permite que essa sesso seja expirada (ou invalidada)
explicitamente pela aplicao.

99

J2EE Primeiros Passos


Para exemplificar o uso de todas as funes apresentadas nessa seo, vamos construir um esqueleto de uma aplicao que requer a autenticao de usurios. Mais
tarde, voc poder utilizar os cdigos apresentados a seguir para construir sua prpria aplicao autenticada.
Primeiro devemos construir um Servlet que apresenta a tela de login propriamente
dita:

Servlet FormLogin
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Apresenta pgina HTML com formulrio de login


public class FormLogin extends HttpServlet {
public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {

// Definindo headers auxiliares para evitar cacheamento da pgina


p_response.setHeader(Cache-Control, no-cache, must-revalidate);
p_response.setHeader(Pragma, no-cache);
p_response.setHeader(Expires, Mon, 26 Jul 1997 05:00:00 GMT);
p_response.setDateHeader(Last-Modified, System.currentTimeMillis ());

// Imprimindo header HTML


PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);

// A sesso criada nesse Servlet; se os demais Servlets da aplicao


// receberem requisies sem o objeto de sesso criado, devem redirecionar
// a requisio para esse Servlet
HttpSession l_sessao = p_request.getSession(true);
if(!l_sessao.isNew ()) {
//
//
//
//

A sesso j havia sido criada em outra requisio: devemos verificar


se h alguma mensagem a ser apresentada para o usurio e zerar a
informao de login se estiver presente na sesso (se o usurio
chegou at essa pgina, porque deseja fazer o login novamente)

String l_msg = (String) l_sessao.getAttribute(MSGLOGIN);


if(l_msg != null) l_pw.println(l_msg + <BR>);
l_sessao.removeAttribute(LOGIN);
}

100

Captulo 6 Servlets Cookies e Sesses


//

Imprimindo o restante da pgina HTML

l_pw.println(<FORM ACTION=\Login.html\ METHOD=\POST\>);


l_pw.println(Login: <INPUT TYPE=\TEXT\ NAME=\LOGIN\><BR>);
l_pw.println(Senha: <INPUT TYPE=\PASSWORD\ NAME=\SENHA\><BR>);
l_pw.println(<INPUT TYPE=\SUBMIT\ NAME=\ENTRAR\ VALUE=\Entrar\><BR>);
l_pw.println(</FORM>);
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}
// Nesse Servlet, os mtodos GET e POST so tratados da mesma maneira
// (pelo mesmo trecho de cdigo)
public void doPost(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
doGet(p_request, p_response);
}
}

Em seguida, temos um Servlet que faz, efetivamente, a autenticao. Se a autenticao


for bem sucedida, esse Servlet armazena, como atributo da sesso, o nome do usurio, e redireciona a requisio para o menu principal de nossa aplicao.

ServletLogin
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Efetua a autenticao do usurio / senha preenchidos no formulrio de login


public class Login extends HttpServlet {

// Verifica se existe usurio com o login e senha passados como parmetro


private boolean ValidaLoginSenha(String p_login, String p_senha) {
boolean l_sucesso = false;
if((p_login != null) && (p_senha != null)) {
// Voc deve implementar aqui o cdigo para validar o login e senha do
// usurio (por exemplo, consultando uma base de dados)
}
return l_sucesso;
}
public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
// Definindo headers auxiliares para evitar cacheamento da pgina
p_response.setHeader(Cache-Control, no-cache, must-revalidate);

101

J2EE Primeiros Passos


p_response.setHeader(Pragma, no-cache);
p_response.setHeader(Expires, Mon, 26 Jul 1997 05:00:00 GMT);
p_response.setDateHeader(Last-Modified, System.currentTimeMillis ());

//
//
//
//
//

Recuperando dados da sesso: se a sesso no tiver sido criada ainda,


redirecionamos a requisio para o Servlet LoginForm, que o ponto de
entrada da aplicao; caso contrrio, removemos o atributo LOGIN da
sesso, pois ele s dever estar definido caso o processo de autenticao
seja bem sucedido.

HttpSession l_sessao = p_request.getSession(false);


if(l_sessao == null) {
p_response.sendRedirect(LoginForm.html);
return;
}
l_sessao.removeAttribute( LOGIN );

// Recuperando os parmetros com login e senha e validando esses dados


String l_login = p_request.getParameter(LOGIN);
String l_senha = p_request.getParameter(SENHA);
if(ValidaLoginSenha(l_login, l_senha)) {
// Login e senha so vlidos, podemos definir o atributo de sesso LOGIN
// (contendo o login do usurio) e podemos redirecionar a requisio para
// o menu principal da aplicao
l_sessao.setAttribute(LOGIN, l_login);
p_response.sendRedirect(MenuPrincipal.html);
}
else {
// Se o login e senha no forem vlidos, colocamos uma mensagem de falha
// na autenticao junto a sesso do usurio corrente, e redirecionamos a
// requisio para o Servlet LoginForm
l_sessao.setAttribute(MSGLOGIN, Login e/ou senha invlidos!);
p_response.sendRedirect(LoginForm.html);
}

// Nesse Servlet, os mtodos GET e POST so tratados da mesma maneira


// (pelo mesmo trecho de cdigo)
public void doPost(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
doGet( p_request, p_response );
}
}

102

Captulo 6 Servlets Cookies e Sesses


Um detalhe interessante com relao ao Servlet anterior que ele no retorna nenhum contedo HTML por si, ele simplesmente efetua um processamento e, conforme seu resultado, redireciona a requisio para Servlets que apresentaro um contedo. Esse modelo de funcionamento ser explorado com mais detalhes no Captulo
8 Modelo MVC.
Finalmente, teremos o Servlet que apresenta o menu principal da aplicao (caso a
autenticao tenha sido bem sucedida).

Servlet MenuPrincipal
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Apresenta o menu principal da aplicao


public class MenuPrincipal extends HttpServlet {

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


throws IOException {

// Definindo headers auxiliares para evitar cacheamento da pgina


p_response.setHeader(Cache-Control, no-cache, must-revalidate);
p_response.setHeader(Pragma, no-cache);
p_response.setHeader(Expires, Mon, 26 Jul 1997 05:00:00 GMT);
p_response.setDateHeader(Last-Modified, System.currentTimeMillis ());

//
//
//
//

Recuperando dados da sesso: o acesso a esse Servlet s permitido se a


sesso j tiver sido criada e contiver o login do usurio como atributo de
sesso; se uma dessas condies falhar, porque o usurio corrente no
efetuou a autenticao

String l_login = null;


HttpSession l_sessao = p_request.getSession(false);
if(l_sessao != null) l_login = (String) l_sessao.getAttribute(LOGIN);
if(l_login == null) {
p_response.sendRedirect(LoginForm.html);
return;
}

//

Imprimindo o menu principal da aplicao

PrintWriter l_pw = p_response.getWriter ();


l_pw.println(<HTML><BODY>);

103

J2EE Primeiros Passos


l_pw.println(Ol, + l_login + , este o menu principal de sua
aplicao<BR>);
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}

// Nesse Servlet, os mtodos GET e POST so tratados da mesma maneira


// (pelo mesmo trecho de cdigo)
public void doPost(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
doGet(p_request, p_response);
}
}

Caso a aplicao venha a ter mais Servlets autenticados (que s podero ser acessados aps o login do usurio), pode valer a pena criar uma hierarquia de classes para
facilitar o processo de desenvolvimento.
Assim, podemos criar uma classe abstrata ServletLogado que faz a validao da sesso do usurio, verificando se o usurio j efetuou o login, e, se isso no tiver acontecido, redirecionando a requisio para o Servlet FormLogin.

Servlet ServletLogado
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Classe abstrata para verificar se usurio j efetuou o login


public abstract class ServletLogado extends HttpServlet {

// Login do usurio: se a autenticao j tiver sido feita,


// colocamos nessa varivel o login do usurio que fez a autenticao
protected String m_login = null;

// Servlets que necessitarem da autenticao devem estender


// essa classe e implementar o mtodo abaixo
public abstract void doLoggedGet(HttpServletRequest p_request,
HttpServletResponse p_response) throws IOException;

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


throws IOException {
// Definindo headers auxiliares para evitar cacheamento da pgina
p_response.setHeader(Cache-Control, no-cache, must-revalidate);
p_response.setHeader(Pragma, no-cache);

104

Captulo 6 Servlets Cookies e Sesses


p_response.setHeader(Expires, Mon, 26 Jul 1997 05:00:00 GMT);
p_response.setDateHeader(Last-Modified, System.currentTimeMillis ());
//
//
//
//

Recuperando dados da sesso: o acesso a esse Servlet s permitido se a


sesso j tiver sido criada e contiver o login do usurio como atributo de
sesso; se uma dessas condies falhar, porque o usurio corrente no
efetuou a autenticao

HttpSession l_sessao = p_request.getSession(false);


if(l_sessao != null) m_login = (String) l_sessao.getAttribute(LOGIN);
if(m_login == null) {
p_response.sendRedirect(LoginForm.html);
return;
}
doLoggedGet(p_request, p_response);
}

// Nesse Servlet, os mtodos GET e POST so tratados da mesma maneira


// (pelo mesmo trecho de cdigo)
public void doPost(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
doGet(p_request, p_response);
}
}

Utilizando a classe anterior, podemos criar tantos Servlets autenticados quanto quisermos: basta que esses Servlets estendam a classe ServletLogado e implementem o
mtodo doLoggedGet(), em vez do mtodo doGet(). Poderamos, por exemplo, implementar o Servlet MenuPrincipal da seguinte forma:

Servlet MenuPrincipal
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Apresenta o menu principal da aplicao


public class MenuPrincipal extends ServletLogado {

public void doLoggedGet(HttpServletRequest p_request, HttpServletResponse


p_response) throws IOException {

// Como esse Servlet estende a classe ServletLogado, ao chegar nesse trecho


// de cdigo j foi feita a validao e j foram definidos os headers
// principais, fica restando s imprimir a pgina com o menu
PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);

105

J2EE Primeiros Passos


l_pw.println(Ol, + m_login + , este o menu principal de sua
aplicao<BR>);
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}

// Nesse Servlet, os mtodos GET e POST so tratados da mesma maneira


// (pelo mesmo trecho de cdigo)
public void doPost(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
doGet(p_request, p_response);
}
}

106

Captulo 7
Pginas JSP
Nos quatro captulos anteriores, exploramos com detalhes como um Servlet pode
tratar uma requisio HTTP e gerar sua resposta.
Infelizmente, as aplicaes que pudemos desenvolver at agora tem uma sria limitao inerente a prpria tecnologia de Servlets: a formatao do contedo da resposta
est totalmente integrada a programao da lgica da aplicao. A tecnologia de pginas JSP, que estudaremos nesse captulo, nos ajudar a transpor essa limitao.

7.1 Formatao do contedo da resposta com Servlets


Em nossos Servlets de exemplo apresentados nos captulos anteriores, geramos, como
resposta, pginas HTML simples, sem nenhuma formatao.
O primeiro Servlet apresentado (seo 1.2), por exemplo, pode gerar a seguinte pgina HTML ao receber uma requisio:
<HTML><BODY>
O seu endereo IP 127.0.0.1
</BODY></HTML>

Essa pgina HTML no tem, praticamente, nenhuma formatao; um Webdesigner


sugeriria, com certeza, diversas alteraes no cdigo HTML para tornar o layout da
pgina mais atrativo. Assim, poderamos alterar esse cdigo minimamente para:
<HTML>
<HEAD>
<META HTTP-EQUIV=Content-Type CONTENT=text/html; charset=iso-8859-1>
<TITLE>Endereo IP</TITLE>
</HEAD>
<BODY BGCOLOR=#FFFFFF>
<IMG NAME=LOGO SRC=/icons/logopagina.jpg BORDER=0><BR>

107

J2EE Primeiros Passos


<P><FONT FACE=Arial SIZE=2 COLOR=BLUE>
<B><U>Pgina de exemplo Apresentando o endereo IP do cliente</U></B>
</FONT></P>
<P><FONT FACE=Arial SIZE=2 COLOR=BLUE>O seu endereo IP
<B>127.0.0.1</B></FONT></P>
</BODY>
</HTML>

Apesar da pgina apresentar exatamente as mesmas informaes, a formatao pode


tornar o contedo muito mais atraente para o usurio que estiver visitando nossa
aplicao.
Por outro lado, essa modificao faz com que a codificao do Servlet fique muito
mais trabalhosa, pois agora a resposta do Servlet precisa conter todos esses dados de
formatao adicionais.
Assim, se originalmente o cdigo do mtodo doGet() do Servlet era
public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML><BODY>);
l_pw.println(O seu endereo IP \ + p_request.getRemoteAddr () + \);
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}

Agora esse cdigo passa a ser


public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML>);
l_pw.println(<HEAD>);
l_pw.println(<META HTTP-EQUIV=\Content-Type\ CONTENT=\text/html;
charset=iso-8859-1\>);
l_pw.println(<TITLE>Endereo IP</TITLE>);
l_pw.println(</HEAD>);
l_pw.println(<BODY BGCOLOR=\#FFFFFF\>);
l_pw.println(<IMG NAME=\LOGO\ SRC=\/icons/logopagina.jpg\
BORDER=\0\><BR>);
l_pw.println(<P><FONT FACE=\Arial\ SIZE=\2\ COLOR=\BLUE\>);
l_pw.println(<B><U>Pgina de exemplo Apresentando o endereo IP do
cliente</U></B> );
l_pw.println(</FONT></P>);
l_pw.println(<P><FONT FACE=\Arial\ SIZE=\2\ COLOR=\BLUE\>O seu
endereo IP <B>\127.0.0.1\</B></FONT></P>);
l_pw.println( </BODY></HTML> );
}

108

Captulo 7 Pginas JSP


Alm disso, qualquer modificao na formatao dessa pgina torna necessrio o
envolvimento do programador, j que ele precisa incorporar essa modificao ao
cdigo do Servlet e recompilar seu cdigo. Por exemplo, se nosso Webdesigner
decidir que a cor do texto agora precisa ser verde, precisamos alterar o cdigo anterior para
public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
PrintWriter l_pw = p_response.getWriter ();
l_pw.println(<HTML>);
l_pw.println(<HEAD>);
l_pw.println(<META HTTP-EQUIV=\Content-Type\ CONTENT=\text/html;
charset=iso-8859-1\>);
l_pw.println(<TITLE>Endereo IP</TITLE>);
l_pw.println(</HEAD>);
l_pw.println(<BODY BGCOLOR=\#FFFFFF\>);
l_pw.println(<IMG NAME=\LOGO\ SRC=\/icons/logopagina.jpg\
BORDER=\0\><BR>);
l_pw.println(<P><FONT FACE=\Arial\ SIZE=\2\ COLOR=\BLUE\>);
l_pw.println(<B><U>Pgina de exemplo Apresentando o endereo IP do
cliente</U></B>);
l_pw.println(</FONT></P>);
l_pw.println(<P><FONT FACE=\Arial\ SIZE=\2\ COLOR=\GREEN\>O seu
endereo IP <B>\127.0.0.1\</B></FONT></P>);
l_pw.println(</BODY></HTML>);
}

Todo esse processo faz com que o desenvolvedor tenha um grande trabalho cada vez
que a formatao da pgina precise ser modificada, tornando esse processo lento e
pouco flexvel.

7.2 Formatao do contedo da resposta com pginas JSP


Se em um Servlet a incluso e a modificao da formatao da resposta precisam ser
feitas pelo desenvolvedor diretamente no cdigo da aplicao, em uma pgina JSP a
idia que esse processo possa ser feito diretamente pelo responsvel pelo
looknfeel (layout) da aplicao.
Assim, uma pgina JSP nada mais , na verdade, que uma pgina HTML, com elementos especiais onde o desenvolvedor pode programar o contedo dinmico da aplicao. Porm, ao contrrio de uma pgina HTML cujo nome de arquivo tem extenso
.htm ou .html, arquivos com pginas JSP devem ser nomeados com extenso .jsp.
A primeira verso do Servlet apresentado na seo anterior (sem nenhuma formatao), por exemplo, poderia ser reescrito como a seguinte pgina JSP PrimPag.jsp:

109

J2EE Primeiros Passos

Primeiro exemplo de pgina JSP


<HTML><BODY>
O seu endereo IP <%= request.getRemoteAddr ()

%>

</BODY></HTML>

Nessa pgina JSP, o contedo dinmico est contido no elemento


<%= request.getRemoteAddr ()

%>

Desde que esse elemento no seja alterado, podemos incluir / alterar livremente a
formatao da pgina sem afetar o funcionamento da aplicao. Podemos, portanto,
modificar essa pgina de maneira a ter a segunda verso do Servlet apresentado na
seo anterior:

Segundo exemplo de pgina JSP


<HTML>
<HEAD>
<META HTTP-EQUIV=Content-Type CONTENT=text/html; charset=iso-8859-1>
<TITLE>Endereo IP</TITLE>
</HEAD>
<BODY BGCOLOR=#FFFFFF>
<IMG NAME=LOGO SRC=/icons/logopagina.jpg BORDER=0><BR>
<P><FONT FACE=Arial SIZE=2 COLOR=BLUE>
<B><U>Pgina de exemplo Apresentando o endereo IP do cliente</U></B>
</FONT></P>
<P><FONT FACE=Arial SIZE=2 COLOR=BLUE>O seu endereo IP <B>
<%= request.getRemoteAddr () %></B></FONT></P>
</BODY></HTML>

Aps fazer essa modificao, ao contrrio do que acontece quando se trabalha diretamente com Servlets, voc no precisa recompilar a aplicao, essa modificao j
passa a ser automaticamente visvel para os usurios.

7.3 Funcionamento interno


A mgica por trs de uma pgina JSP a seguinte: existe um Servlet especial, chamado Page Compiler, que intercepta requisies direcionadas a recursos com extenso
.jsp.
No instante em que recebida uma requisio para uma pgina JSP, o Page Compiler
transforma essa pgina em um Servlet e o compila, sendo que o resultado dessa compilao carregado em memria para evitar que esse processo tenha que ser repetido para todas as requisies recebidas.

110

Captulo 7 Pginas JSP


A primeira verso de nossa pgina de exemplo PrimPag.jsp, por exemplo, transformada no seguinte Servlet

Primeira verso da pgina JSP PrimPag.jsp transformada em Servlet


package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;
public class pag1$jsp extends HttpJspBase {
static {
}
public pag1$jsp( ) {
}

private static boolean _jspx_inited = false;

public final void _jspx_init() throws org.apache.jasper.runtime.JspException {


}

public void _jspService(HttpServletRequest request, HttpServletResponse


response) throws java.io.IOException, ServletException {

JspFactory _jspxFactory = null;


PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
String

_value = null;

try {
if (_jspx_inited == false) {
synchronized (this) {
if (_jspx_inited == false) {
_jspx_init();
_jspx_inited = true;
}
}
}

111

J2EE Primeiros Passos


_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType(text/html;ISO-8859-1);
pageContext = _jspxFactory.getPageContext(this, request, response,
, true, 8192, true);
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();

// HTML // begin [file=/pag1.jsp;from=(0,0);to=(1,21)]


out.write(<HTML><BODY>\r\nO seu endereo IP \);

// end
// begin [file=/pag1.jsp;from=(1,24);to=(1,51)]
out.print(request.getRemoteAddr ());
// end
// HTML // begin [file=/pag1.jsp;from=(1,53);to=(2,14)]
out.write(\\r\n</BODY></HTML>);

// end

} catch (Throwable t) {
if (out != null && out.getBufferSize() != 0)
out.clearBuffer();
if (pageContext != null) pageContext.handlePageException(t);
} finally {
if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
}
}
}

O Page Compiler tambm verifica a data de alterao do arquivo que contm a pgina JSP: caso essa data se modifique, o processo de compilao executado novamente para garantir que modificaes feitas na pgina sejam visveis para os usurios
da aplicao.
Devido a todo esse processo de compilao / recompilao, voc poder observar
que o primeiro acesso aps a criao ou modificao de uma pgina JSP sempre
mais lento que os acessos seguintes (at que haja uma modificao no contedo da
pgina).

112

Captulo 7 Pginas JSP

7.4 Ciclo de vida


O fato de uma pgina JSP ser convertida para um Servlet faz com que ela tenha o
mesmo ciclo de vida apresentado na seo 3.4 desse livro: existe uma etapa de inicializao, uma etapa de atendimento de requisies, e finalmente, uma etapa de
finalizao.
No existem mtodos equivalentes ao doGet() ou doPost() de um Servlet para a etapa
de atendimento de requisies, j que o prprio contedo da pgina contm o cdigo a ser executado e retornado para o browser a cada requisio.
Por outro lado, existem os mtodos jspInit () e jspDestroy () que possibilitam a implementao de cdigos de inicializao e finalizao, respectivamente, da pgina JSP. A
maneira pela qual esses dois mtodos podem ser declarados para uma pgina JSP
ser apresentada na seo Declaraes mais adiante nesse mesmo captulo.

7.5 Elementos dinmicos


J vimos nas pginas JSP apresentadas at agora um exemplo de um elemento dinmico; na pgina PrimPag.jsp apresentada na seo 7.2 desse captulo, por exemplo,
temos a seguinte linha contendo um elemento dinmico:
O seu endereo IP <%= request.getRemoteAddr ()

%>

Onde o contedo do elemento dinmico est delimitado pelos caracteres <%= e %>.
Este apenas um tipo de elemento dinmico, chamado comumente de expresso.
Alm desse, existem outros 4 tipos principais de elementos dinmicos que podem
estar presentes em uma pgina JSP: diretivas, scriptlets, declaraes e JavaBeans.
As sees seguintes iro apresentar, de maneira mais detalhada, cada um desses tipos
de elementos dinmicos que podero ser utilizados por voc em suas pginas JSP.

7.6 Diretivas
O primeiro tipo de elemento dinmico que iremos estudar ser a diretiva.
O formato bsico de uma diretiva o seguinte:

Formato bsico de uma diretiva de uma pgina JSP


<%@ diretiva nomeAtributo1=valorAtributo1 nomeAtributo2=valorAtributo2 %>

Onde a palavra diretiva deve ser substituda por page, include ou taglib. Para cada um
desses tipos de diretivas, existem conjuntos de atributos especficos utilizados para
parametrizar a diretiva.

113

J2EE Primeiros Passos


Conforme o prprio nome indica, a diretiva page serve para se definir diretivas da
pgina; embora existam diversos atributos possveis para essa diretiva, os atributos
mais comuns so os seguintes: info, contentType, import, errorPage e isErrorPage.
O atributo info deve ser utilizado para se definir um texto informativo sobre a pgina sendo construda; seu valor retornado pelo mtodo getServletInfo() do Servlet
(veja seo 3.10).

Exemplo de diretiva page com atributo info


<%@ page info=Escrito por nome_do_autor %>

Da mesma forma que o mtodo setContentType () apresentado na seo 4.2 desse


livro, o atributo contentType serve para indicar o tipo de contedo sendo gerado
pela pgina JSP. Assim, podemos utilizar a seguinte diretiva no incio de uma pgina
JSP para indicar que seu contedo uma pgina HTML.

Exemplo de diretiva page com atributo contentType


<%@ page contentType=text/html %>

O atributo seguinte, import deve ser utilizado para indicar pacotes a serem importados no Servlet que ser gerado (via declarao import). Assim, devemos indicar por
meio desse atributo todos os pacotes que estaremos utilizando na programao de
nossa pgina JSP. Se quisermos utilizar a classe Vector do pacote java.util, e as classes
que esto no pacote java.io, por exemplo, poderamos declarar a diretiva page com
os seguintes atributos:

Exemplo de diretiva page com atributo import


<%@ page import=java.io.* %>
<%@ page import=java.util.Vector %>

Finalmente, o atributo errorPage serve para indicar a pgina JSP a ser exibida em caso
de erro no processamento da pgina corrente. A pgina JSP que for exibir o erro
deve, por sua vez, declarar a diretiva page com o atributo isErrorPage definido explicitamente como true.
Usando todos esses atributos da diretiva page, poderamos implementar uma pgina
JSP simples de impresso da data corrente da seguinte forma:

Pgina JSP que imprime data corrente (datacorrente.jsp)


<%@ page errorPage=ErroPag.jsp %>
<%@ page info=Escrito por nome_do_autor %>
<%@ page contentType=text/html %>
<%@ page import=java.util.* %>

114

Captulo 7 Pginas JSP


<%@ page import=java.text.SimpleDateFormat %>
<HTML>
<BODY BGCOLOR=#FFFFFF>
A data corrente <%= new SimpleDateFormat(dd/MM/yyyy).format(new Date ()) %>
</BODY></HTML>

Alm do tipo de diretiva page ao qual todos os atributos apresentados anteriormente


se referem, existe tambm um outro tipo de diretiva, a diretiva include. Essa diretiva
admite um nico atributo file.
Essa diretiva deve ser utilizada para incluir o contedo de outro arquivo na pgina
JSP corrente, sendo que esse arquivo tanto pode conter um contedo esttico, como
uma pgina HTML (ou pedao de uma pgina HTML), como um contedo dinmico,
ou seja, uma outra pgina JSP.
Sendo assim, podemos reescrever a pgina JSP anterior da seguinte forma

Segunda verso da pgina JSP que imprime data corrente


<%@ include file=cabecalho.jsp %>
A data corrente <%= new SimpleDateFormat(dd/MM/yyyy).format(new Date ()) %>
<%@ include file=rodape.html %>

Sendo que o contedo do arquivo cabecalho.jsp

Cabealho para pgina JSP que imprime data corrente (cabecalho.jsp)


<%@ page errorPage=ErroPag.jsp %>
<%@ page info=Escrito por nome_do_autor %>
<%@ page contentType=text/html %>
<%@ page import=java.util.* %>
<%@ page import=java.text.SimpleDateFormat %>
<HTML>
<BODY BGCOLOR=#FFFFFF>

E o contedo do arquivo rodape.html

Rodap para pgina JSP que imprime data corrente (rodape.html)


</BODY></HTML>

A vantagem de utilizar essa diretiva est no fato de que voc pode manter contedo
esttico ou dinmico comum a diversas pginas JSP em arquivos separados, includos, atravs dessa diretiva, conforme a necessidade. Podemos, por exemplo, construir novas pginas JSP que incluem o arquivo de cabealho cabecalho.jsp e
rodape.html: se for necessrio mudar o contedo do cabealho ou do rodap, no
precisaremos editar todas as nossas pginas, apenas o contedo desses arquivos.

115

J2EE Primeiros Passos

7.7 Expresses
Em todas as pginas JSP construdas at agora utilizamos um elemento dinmico chamado de Expresso: esse elemento serve para imprimir o resultado String de uma
expresso Java.
Sua sintaxe bsica a seguinte:

Sintaxe de uma expresso JSP


<%= <expresso Java> %>

Obviamente, esse elemento pode ser utilizado para imprimir o contedo de uma
varivel do tipo String, ou at mesmo de uma constante String. Supondo que l_texto
seja uma varivel String, por exemplo, poderamos incluir o seguinte elemento em
uma pgina JSP para imprimir o contedo da varivel:

Exemplo de incluso de uma expresso JSP para a impresso de uma varivel do


tipo String
<%= l_texto %>

Por outro lado, podemos formar expresses mais complexas, como na pgina JSP
que imprime a data corrente, desde que o resultado dessas expresses sejam Strings.

Expresso que imprime a data corrente na pgina JSP datacorrente.jsp


<%= new SimpleDateFormat(dd/MM/yyyy).format(new Date ()) %>

7.8 Scriptlets
Uma expresso JSP possibilita o processamento de uma expresso Java, e a impresso de seu resultado junto com o contedo da pgina JSP. Embora esse recurso seja
bastante poderoso, ele no serve para situaes quando precisamos efetuar um processamento mais complexo, utilizando, por exemplo, diversos blocos de cdigo Java.
Um Scriptlet permite a insero de um bloco de cdigo Java diretamente no corpo
da pgina JSP. Sua sintaxe a seguinte:

Sintaxe de um Scriptlet JSP


<% <bloco de cdigo Java> %>

Ns podemos utilizar um Scriptlet para incrementar um pouco nossa pgina JSP


datacorrente.jsp:

116

Captulo 7 Pginas JSP

Terceira verso da pgina JSP que imprime data corrente


<%@ include file=cabecalho.jsp %>
<%
String l_textoSaudacao = ;
String l_data = new SimpleDateFormat( dd/MM/yyyy ).format( new Date ());
if( l_data.startsWith( 01/01 )) l_textoSaudacao = Feliz Ano Novo!;
else if( l_data.startsWith( 25/12 )) l_textoSaudacao = Feliz Natal!;
%>
A data corrente <%= l_data %><BR><%= l_textoSaudacao %>
<%@ include file=rodape.html %>

Nesse exemplo de pgina JSP, utilizamos um Scriptlet para definir variveis cujos
contedos so posteriormente impressos por expresses JSP. De fato, podemos combinar o uso de Scriptlets e expresses, desde que, obviamente, seja preservada a semntica Java (ou seja, variveis sejam utilizadas somente aps serem declaradas, por
exemplo).
Construmos, a seguir, um exemplo um pouco mais elaborado de pgina JSP utilizando Scriptlets: trata-se de um formulrio HTML para input do ms do aniversrio do
usurio, sendo que Scriptlets so utilizados para construir os meses possveis da caixa de seleo do formulrio.

Pgina JSP com formulrio HTML de input do ms de aniversrio do usurio


(formmesaniv.jsp)
<%@ include file=cabecalho.jsp %>
<FORM ACTION=procmesaniv.jsp METHOD=POST>
Entre com o ms de seu aniversrio:
<SELECT NAME=MES>
<%
// Scriptlet: fazendo um for para iterar sobre os 12 meses do ano, ...
for( int i=1; i<=12; i++ )
{
// ... saindo do Scriptlet para imprimir os elementos estticos
// da pgina e as expresses JSP
%>
<OPTION VALUE=<%= Integer.toString(i) %>><%= Integer.toString(i) %></OPTION>
<%
// e voltando para um Scriptlet para fechar o for
}
// Finalizando o for; saindo do scriptlet para imprimir elementos
// estticos da pgina
%>

117

J2EE Primeiros Passos


</SELECT><BR>
<INPUT TYPE=SUBMIT NAME=ENVIAR VALUE=Enviar>
</FORM>
<%@ include file=rodape.html %>

interessante observar nesse exemplo a combinao de Scriptlets, expresses e elementos estticos da pgina: o bloco de cdigo Java iniciado no primeiro Scriptlet da
pgina no finalizado nesse prprio Scriptlet, mas sim em um outro Scriptlet, inserido aps a impresso de um contedo esttico e de 2 expresses JSP.

7.9 Objetos implcitos


No nosso primeiro exemplo de pgina JSP (veja seo 7.2), fizemos referncia a um
objeto que no foi declarado em nenhum ponto da pgina: na expresso JSP dessa
pgina, existe uma referncia a um objeto request.

Primeiro exemplo de pgina JSP


<HTML><BODY>
O seu endereo IP <%= request.getRemoteAddr ()

%>

</BODY></HTML>

Esse objeto equivale, na verdade, a instncia da classe HttpServletRequest passada


como parmetro para o Servlet quando esse recebe uma requisio, conforme estudamos no Captulo 5 Captura de parmetros da requisio desse livro.
Alm desse objeto, que representa a requisio recebida pela pgina, a API de pginas JSP disponibiliza outros objetos implcitos que podem ser utilizados nos elementos dinmicos programados pelo desenvolvedor.
Segue uma lista dos principais objetos implcitos, com suas respectivas classes:
Objeto

Classe

request

javax.servlet.http.HttpServletRequest

response

javax.servlet.http.HttpServletResponse

out

javax.servlet.jsp.JspWriter

session

javax.servlet.http.HttpSession

application javax.servlet.ServletContext
config

javax.servlet.ServletConfig

Voc deve utilizar esses objetos implcitos da mesma maneira como voc utilizaria os
objetos das respectivas classes na programao de seus Servlets. Em particular, o objeto implcito out, da classe JspWriter, prov funcionalidade semelhante a da classe
PrintWriter que utilizamos na maior parte dos exemplos com Servlets desse livro.

118

Captulo 7 Pginas JSP


No exemplo seguinte, reescrevemos o formulrio de input do ms de aniversrio do
usurio utilizando o objeto implcito out:

Segunda verso para pgina JSP de input do ms de aniversrio do usurio


(formmesaniv.jsp)
<%@ include file=cabecalho.jsp %>
<FORM ACTION=procmesaniv.jsp METHOD=POST>
Entre com o ms de seu aniversrio:
<SELECT NAME=MES>
<%
// Scriptlet: fazendo um for para iterar sobre os 12 meses do ano
for( int i=1; i<=12; i++ )
out.println( <OPTION VALUE=\ + Integer.toString( i ) + \>
+ Integer.toString( i ) + </OPTION> );
%>
</SELECT><BR>
<INPUT TYPE=SUBMIT NAME=ENVIAR VALUE=Enviar>
</FORM>
<%@ include file=rodape.html %>

Podemos tambm construir a pgina JSP procmesaniv.jsp que far o tratamento dos
dados submetidos pelo formulrio da pgina formmesaniv.jsp, utilizando os objetos
implcitos request e response:

Pgina JSP que faz o tratamento dos dados submetidos pelo formulrio
formmesaniv.jsp (procmesaniv.jsp)
<%
Integer l_mes = null;
try {
l_mes = new Integer(request.getParameter(MES));
} catch(Exception p_e) {
l_mes = null;
}
if((l_mes == null) || (l_mes.intValue () < 1) || (l_mes.intValue () > 12))
response.sendRedirect(formmesaniv.jsp);
%><%@ include file=cabecalho.jsp %>
<%
if(l_mes.intValue () == Calendar.getInstance ().get(Calendar.MONTH) + 1)
out.println(Parabns, esse o ms de seu aniversrio!);
else out.println(Infelizmente, esse no o ms de seu aniversrio; seu
aniversrio no ms \ + l_mes.toString () + \.);
%>
<%@ include file=rodape.html %>

119

J2EE Primeiros Passos


Nesse exemplo, tomamos o cuidado de tratar o parmetro recebido e, conforme o
caso, gerar o redirecionamento da requisio logo no incio da pgina, antes de escrever qualquer outro contedo esttico ou dinmico: da mesma forma que no desenvolvimento de Servlets, precisamos obedecer a ordem de gerao dos elementos
da resposta HTTP, ou seja, os headers do redirecionamento devem ser gerados antes
da escrita de qualquer elemento do contedo da resposta (veja seo 4.2).

7.10 Declaraes
Esse tipo de elemento dinmico especial de uma pgina JSP serve para definir cdigos Java que devero ficar fora do mtodo de atendimento das requisies (o mtodo
service (), no mais alto nvel). Assim, esse elemento serve para declarar variveis de
classe (estticas), variveis de instncia, ou at mesmo novos mtodos.
Sua sintaxe a seguinte:

Sintaxe de uma declarao JSP


<%! <declaraes

da pgina> %>

Em particular, esse elemento deve ser utilizado para definir os mtodos jspInit () e
jspDestroy () (mencionados na seo 7.4) caso voc opte por incluir um cdigo de
inicializao ou finalizao da pgina JSP.
A pgina JSP seguinte aperfeioa um pouco mais nossa pgina input do ms de aniversrio do usurio, imprimindo o nome do ms por extenso na caixa de seleo do
formulrio. O array de mapeamento do nome do ms declarado em um elemento
de declarao JSP, para evitar a alocao de memria adicional a cada atendimento
de requisio.

Terceira verso para pgina JSP de input do ms de aniversrio do usurio


(formmesaniv.jsp)
<%@ include file=cabecalho.jsp %>
<%!
// Array com os nomes dos meses
private static String [] c_nomesMeses = { Janeiro, Fevereiro, Maro,
Abril, Maio, Junho, Julho, Agosto, Setembro, Outubro,
Novembro, Dezembro };

// Funo para retornar o nome do ms associado ao nmero passado como parmetro


private String obtemNomeMes(int p_numMes) {
if((p_numMes >= 1) && (p_numMes <= 12))
return c_nomesMeses[p_numMes 1];

120

Captulo 7 Pginas JSP


else return null;
}
%>
<FORM ACTION=procmesaniv.jsp METHOD=POST>
Entre com o ms de seu aniversrio:
<SELECT NAME=MES>
<%
// Scriptlet: fazendo um for para iterar sobre os 12 meses do ano
for( int i=1; i<=12; i++ )
out.println(<OPTION VALUE=\ + Integer.toString( i ) + \>
+ obtemNomeMes( i ) + </OPTION>);
%>
</SELECT><BR>
<INPUT TYPE=SUBMIT NAME=ENVIAR VALUE=Enviar>
</FORM>
<%@ include file=rodape.html %>

7.11 Comentrios
Existem, na verdade, dois tipos de comentrios que voc poder utilizar em sua pgina JSP.
Um primeiro tipo o comentrio HTML: independente de ser uma pgina JSP (ou
seja, mesmo sendo uma pgina HTML esttica), voc pode utilizar esse elemento
para incluir um texto que no aparecer diretamente para o usurio que estiver visualizando sua pgina. O usurio poder, por outro lado, ler o comentrio caso visualize o fonte da pgina.
A sintaxe de um comentrio HTML a seguinte:
<! <comentrio> >

O outro tipo de comentrio que voc poder utilizar um comentrio JSP: ao contrrio de um comentrio HTML, o texto escrito por voc no aparecer para o usurio
mesmo que ele visualize o fonte da pgina. A sintaxe de um comentrio JSP a seguinte:
<% <comentrio> %>

121

J2EE Primeiros Passos


Exemplificando o uso dos dois tipos de comentrios:

Pgina JSP com exemplo de uso dos dois tipos de comentrios (HTML e JSP)
<HTML><BODY>
Exemplo de uso dos tipos de comentrios de uma pgina JSP
<!Esse comentrio ir aparecer no fonte da pgina >
<% Esse comentrio no ir aparecer no fonte da pgina %>
</BODY></HTML>

7.12 JavaBeans
JavaBeans so, na verdade, classes Java reutilizveis que seguem algumas regras bem
definidas para nomeao de seus mtodos e variveis. A idia por trs do uso desses
JavaBeans em nossas pginas JSP, que eles encapsulem a lgica de nossa aplicao,
separando-a do restante da pgina.
Embora a definio exata de JavaBeans fuja ao escopo desse livro, para efeitos de uso
do uso dessas classes em pginas JSP, necessrio que se siga algumas regras bsicas
no seu desenvolvimento:
1) O construtor da classe, se declarado, no deve receber nenhum argumento.
2) Podem existir um ou mais mtodos pblicos para a definio de valores de propriedades do bean; esses mtodos so chamados de mtodos setter.
3) Podem existir um ou mais mtodos pblicos para a obteno de valores de propriedades do bean; esses mtodos so chamados de mtodos getter.
Temos, a seguir, uma exemplo de classe JavaBean que implementa uma lgica bsica
de nossa aplicao:

Primeiro exemplo de JavaBean: encapsula lgica de clculo de preos de um


produto
package com.minhaempresa;

// JavaBean simples para clculo de preo de um produto


public class PrecoProdBean {

// Valor unitrio
private int m_PrecoUnid = 10;

122

Captulo 7 Pginas JSP


// Mtodo para clculo do valor total de um lote: recebe como parmetro a
quantidade de produtos no lote
public int calcPrecoLote( int p_quantProds ) {
return p_quantProds * m_PrecoUnid;
}

Uma vez construdo o JavaBean, para referenci-lo em nossa pgina JSP, devemos
utilizar o elemento dinmico <jsp:useBean>, que tem a seguinte sintaxe:
<jsp:useBean id=<id do Bean> scope=<escopo do Bean> class=<classe do Bean>/>

Na sintaxe anterior, <id do Bean> deve conter o nome do JavaBean como ele ser
referenciado na pgina e <classe do Bean> deve conter o nome da classe incluindo
informaes
sobre
seu
pacote
(como
por
exemplo,
com.minhaempresa.PrecoProdBean).
O atributo scope, por outro lado, deve conter um dos seguintes valores: page (pgina; o valor default caso esse atributo no seja explicitamente definido), request
(requisio), session (sesso) ou application (aplicao); esse valor indica o escopo
dentro do qual o JavaBean ser visvel. Assim, se o escopo de um JavaBean for de
sesso, ele ser armazenado como um atributo de sesso, podendo ser referenciado
em todas as requisies dessa mesma sesso.
Se quisssemos utilizar o JavaBean PrecoProdBean em uma pgina JSP, por exemplo,
poderamos incluir as seguintes linhas de cdigo:

Exemplo de pgina JSP utilizando o JavaBean PrecoProdBean


<HTML>
<BODY>
<jsp:useBean id=PrecoProduto class=com.minhaempresa.PrecoProdBean/>
<%= O preo total do lote de 10 produtos :
+ Integer.toString(PrecoProduto.calcPrecoLote(10)) %>
</BODY>
</HTML>

Esse elemento <jsp:useBean> no o nico elemento disponibilizado pela API de


pginas JSP para trabalhar com JavaBeans: existem elementos para referenciar diretamente os mtodos getter e setter dos JavaBeans desenvolvidos.
Ainda no exemplo de JavaBean anterior (PrecoProdBean), vamos acrescentar mtodos getter e setter para a propriedade com o preo de unidade do produto:

123

J2EE Primeiros Passos

Segundo exemplo de JavaBean: aperfeioa PrecoProdBean com mtodos getter


e setter para o preo de unidade
package com.minhaempresa;

// JavaBean simples para clculo de preo de um produto


public class PrecoProdBean {

// Valor unitrio default


private int m_PrecoUnid = 10;

// Mtodo getter para o preo da unidade do produto


public int getPrecoUnid() {
return m_PrecoUnid;
}

// Mtodo setter para o preo da unidade do produto


public void setPrecoUnid(int p_precoUnid) {
m_PrecoUnid = p_precoUnid;
}

// Mtodo para clculo do valor total de um lote: recebe como


// parmetro a quantidade de produtos no lote
public int calcPrecoLote(int p_quantProds) {
return p_quantProds * m_PrecoUnid;
}

Para referenciar o mtodo getter de um JavaBean, a API de pginas JSP disponibiliza


o elemento <jsp:getProperty>, cuja sintaxe :
<jsp:getProperty name=<nome do JavaBean> property=<nome da propriedade>/>

Para imprimir o valor do preo unitrio de um produto, por exemplo, poderamos


acrescentar as seguintes linhas em nossa pgina JSP:

124

Captulo 7 Pginas JSP

Segundo exemplo de pgina JSP utilizando o JavaBean PrecoProdBean


<HTML>
<BODY>
<jsp:useBean id=PrecoProduto class=com.minhaempresa.PrecoProdBean/>
O preo unitrio do produto <jsp:getProperty name=PrecoProduto
property=precoUnid/>
</BODY>
</HTML>

Da mesma forma como existe um elemento dinmico para referenciar mtodos getter
de JavaBeans, tambm existe um elemento dinmico para os mtodos setter. A sintaxe desse elemento :
<jsp:setProperty name=<nome do JavaBean> property=<nome da propriedade>
value=<valor da propriedade> />

Podemos, ento, modificar o exemplo de pgina JSP anterior para definir o valor do
preo unitrio do produto antes de exibi-lo:

Terceiro exemplo de pgina JSP utilizando o JavaBean PrecoProdBean


<HTML>
<BODY>
<jsp:useBean id=PrecoProduto class=com.minhaempresa.PrecoProdBean/>
<jsp:setProperty name=PrecoProduto property=precoUnid value=3 />
O preo unitrio do produto <jsp:getProperty name=PrecoProduto
property=precoUnid/>
</BODY>
</HTML>

Esse elemento de referncia a mtodos setter de JavaBeans admite, ainda, outra sintaxe de uso:
<jsp:setProperty name=<nome do JavaBean> property=<nome da propriedade>
param=<nome do parmetro> />

Nessa sintaxe, o valor que ser recebido pelo JavaBean para a propriedade em questo, ser o valor do parmetro <nome do parmetro>, conforme recebido pela requisio HTTP.

125

J2EE Primeiros Passos

7.13 Bibliotecas de Tags (Tag Libraries)


Existe um ltimo tipo de elemento dinmico que pode ser utilizado em uma pgina
JSP: um elemento de referncia a uma biblioteca de Tags.
Uma biblioteca de Tags permite que voc tambm separe a lgica de programao
de sua aplicao do contedo da pgina JSP, assim como JavaBeans se prope a
fazer.
No entanto, ao contrrio de JavaBeans, uma biblioteca de Tags oferece um acesso
nativo aos objetos da pgina JSP, como por exemplo, o objeto que encapsula a resposta do Servlet correspondente a pgina JSP.
Nessa seo estaremos explorando algumas caractersticas bsicas de biblioteca de
Tags. Uma explicao mais detalhada e aprofundada sobre TagLibs pode ser obtida
em http://java.sun.com/products/jsp/tutorial/TagLibrariesTOC.html.
Existem 4 componentes principais por trs do uso de uma biblioteca de Tags.
O primeiro componente um arquivo chamado de Descritor de Bibliotecas de Tags
(Tag Library Descriptor): esse arquivo, nomeado com extenso .tld e colocado no
diretrio WEB-INF, contm as configuraes das bibliotecas de Tags utilizadas pela
aplicao.

Exemplo de um Descritor de Bibliotecas de Tags (minhabibliotags.tld)


<?xml version=1.0 encoding=ISO-8859-1 ?>
<!DOCTYPE taglib PUBLIC -//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN
http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd>
<taglib>
<tlibversion>1.0</tlibversion>
<shortname>exemplotag</shortname>
<info>Exemplo de biblioteca de Tags</info>
<tag>
<name>TagOlaMundo</name>
<tagclass>com.minhaempresa.TagOlaMundo</tagclass>
<bodycontent>empty</bodycontent>
</tag>
</taglib>

Nesse exemplo de Descritor de Biblioteca de Tags, podemos observar diversos elementos: os elementos tlibversion, shortname e info contm, respectivamente, a verso da biblioteca de Tags, seu nome (conforme referenciado posteriormente na pgina JSP) e um texto informativo sobre a biblioteca.

126

Captulo 7 Pginas JSP


O ltimo elemento no descritor de nosso exemplo um elemento tag: esse elemento
serve para especificar um nome de uma Tag (TagOlaMundo) e a respectiva classe
que
ir
tratar
essa
Tag
quando
utilizada
na
pgina
JSP
(com.minhaempresa.TagOlaMundo). O elemento bodycontent especifica o tipo de
tratamento que o contedo da Tag dever receber: no nosso exemplo, esse contedo
dever ser vazio, ou seja, no dever haver texto nenhum entre o elemento de incio
e fim da Tag; outros valores possveis para esse elemento so JSP e tagdependent.
Embora em nosso exemplo haja somente um elemento do tipo tag, pode haver mais
de um elemento desse tipo no mesmo Descritor de Biblioteca de Tags.
O componente seguinte por trs do uso de uma biblioteca de Tags, o Deployment
Descriptor, j apresentado no Captulo 2 Instalao e Configurao desse livro.
Para que se possa utilizar uma biblioteca de Tags, necessrio incluir um mapeamento de uma URI, referenciada na pgina JSP, ao arquivo .tld com a biblioteca de Tags
correspondente.
Assim, poderamos incluir as seguintes linhas no Deployment Descriptor de nossa
aplicao:

Exemplo de linhas includas no Deployment Descriptor para utilizao de uma


biblioteca de Tags
<!DOCTYPE web-app
PUBLIC -//Sun Microsystems, Inc.//DTD Web Application 2.3//EN
http://java.sun.com/dtd/web-app_2_3.dtd>

<web-app>

<taglib>
<taglib-uri>/minhabibliotags</taglib-uri>
<taglib-location>/WEB-INF/minhabibliotags.tld</taglib-location>
</taglib>

</web-app>

O componente seguinte de uma biblioteca de Tags a classe que ir gerenciar a Tag


(Tag Handler). Essa classe, especificada pelo elemento tagclass do Descritor da Biblioteca de Tags, responsvel por executar as rotinas pertinentes quando a Tag encontrada na pgina JSP.

127

J2EE Primeiros Passos


Essa classe que gerencia a Tag deve implementar a interface Tag ou BodyTag: a diferena bsica entre essas duas interfaces diz respeito ao tratamento do contedo da
Tag. Como em nosso exemplo no estamos interessandos no contedo da Tag, a
classe que apresentamos implementa a interface Tag.

Exemplo de classe para gerenciar uma Tag (Tag Handler)


package com.minhaempresa;

import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;

// Classe que gerencia Tag TagOlaMundo, utilizada em pginas JSP de nossa aplicao
public class TagOlaMundo implements Tag {
PageContext m_PageContext;
// Implementao default
public void setParent(Tag p_tag) {
}

// Implementao default
public void setPageContext(PageContext p_pageContext) {
m_PageContext = p_pageContext;
}

// Implementao default
public void release () {
}

// Implementao default
public Tag getParent () {
return null;
}

// Imprimimos o texto Ola Mundo! quando a Tag encontrada;


// a funo retorna SKIP_BODY de maneira que o contedo da Tag
// no seja processado (no nosso caso, a Tag vazia).
public int doStartTag (){
try {
m_PageContext.getOut ().println(Ola Mundo!);
} catch (Exception p_e) {}
return SKIP_BODY;
}

128

Captulo 7 Pginas JSP


// Implementao default; a funo retorna EVAL_PAGE de maneira que o
// restante da pgina JSP seja processado
public int doEndTag () {
return EVAL_PAGE;
}
}

Os mtodos mais importantes dessa classe so os mtodos doStartTag (), chamado


quando a Tag encontrada, doEndTag (), chamado aps o processamento do contedo da Tag, e release (), chamado ao trmino de todo o processamento devendo
liberar quaisquer recursos alocados durante o processo. interessante observar que
no mtodo doStartTag () obtemos uma referncia ao stream de sada da pgina, e
utilizamos esse stream para imprimir nosso texto Ola Mundo!.
Finalmente, o componente final de nossa biblioteca de Tags a pgina JSP em si. Para
utilizar a biblioteca de Tags minhabibliotags.tld, podemos elaborar a seguinte pgina
JSP de exemplo:

Exemplo de pgina JSP que utiliza a biblioteca de Tags minhabibliotags.tld


(exemplotags.jsp)
<HTML>
<BODY>
Processando TagOlaMundo ...<BR>
<%@ taglib uri=/minhabibliotags prefix=minhaLib%>
<minhaLib:TagOlaMundo/>
</BODY>
</HTML>

Nessa pgina, primeiro inclumos um elemento taglib, cujo atributo uri contm a URI
especificada no Deployment Descriptor (que por sua vez faz o mapeamento com o
arquivo .tld correto), e cujo atributo prefix especifica o prefixo a ser utilizado
antes de cada Tag.
Na linha seguinte, temos a utilizao da Tag em si: h um prefixo, conforme especificado pelo atributo prefix do elemento taglib, seguido da Tag, que dever ter sido
declarada no descritor de bibliotecas de Tags. Ao encontrar esse elemento, o container ir carregar a classe que gerencia esse Tag, e chamar os mtodos pertinentes.
importante observar que no existe nenhum contedo para a tag
minhaLib:TagOlaMundo; a notao abreviada <minhaLib:TagOlaMundo/> equivalente se escrever <minhaLib:TagOlaMundo></minhaLib:TagOlaMundo>. Caso houvesse algum contedo para essa tag, teramos que utilizar um valor diferente para o
atributo bodyContent no descritor de bibliotecas de Tags, e poderamos considerar a
implementao da interface BodyTag em vez de Tag para a classe TagOlaMundo.

129

J2EE Primeiros Passos


A pgina HTML resultante do processamento da pgina JSP apresentada anteriormente ser ento:

Resultado do processamento da pgina exemplotags.jsp


<HTML>
<BODY>
Processando TagOlaMundo ...<BR>
Ola Mundo!
</BODY>
</HTML>

Embora voc possa construir suas prprias bibliotecas de Tags, normalmente mais
prtico e fcil utilizar uma biblioteca j pronta, como o Apache Jakarta Struts, disponvel no site http://jakarta.apache.org/struts/.

130

Captulo 8
Modelo MVC
Nesse captulo apresentamos o modelo MVC: atravs desse modelo, procuramos
mostrar como podemos separar o trabalho de desenvolvimento do trabalho de formatao e layout da aplicao.

8.1 Programao e layout


Normalmente, o desenvolvimento de uma aplicao Web envolve o trabalho de duas
equipes distintas: os desenvolvedores so responsveis pela programao, e os webdesigners so responsveis pela formatao e layout do front-end da aplicao.
Pelo que vimos at agora, existe uma interseco entre esses dois mundos: na verdade, qualquer que seja a tecnologia que se utilize para desenvolver aplicaes Web,
sempre existe um ponto em que se mistura os trabalhos dessas duas equipes.
Agora imagine uma situao onde o incio do trabalho de uma equipe dependa da
outra equipe finalizar a sua parte; imagine tambm que, qualquer alterao feita por
uma equipe precise necessariamente envolver o trabalho da outra equipe. Essas situaes podem onerar tanto o cronograma quanto o custo de um projeto.
Assim, tanto para efeitos de construo, quanto da manuteno da aplicao desenvolvida, muito importante que haja a maior separao possvel entre esses dois
trabalhos, de maneira que as duas equipes possam trabalhar de forma independente,
sem dependerem uma da outra.
Embora j tenhamos visto nesse livro algumas tcnicas que auxiliam na separao
entre lgica da aplicao e apresentao, apresentaremos nesse captulo uma tcnica
muito mais eficaz e que pode ser utilizada de maneira complementar as apresentadas
anteriormente.

131

J2EE Primeiros Passos

8.2 Arquitetura bsica


A arquitetura bsica do modelo MVC, ou Model-View-Controller, se vale do uso de
Servlets, JavaBeans e pginas JSP: os Servlets controlam as requisies recebidas (Controller), os JavaBeans implementam a lgica da aplicao (Model), e as pginas JSP se
encarregam da apresentao do resultado (View).
Podemos representar melhor essa arquitetura atravs da seguinte figura:

Figura 8.1 Arquitetura bsica MVC.


Toda vez que uma requisio recebida, o Servlet de controle repassa a requisio
para a pgina JSP responsvel pela apresentao da resposta, sendo que JavaBeans
so utilizados pela pgina JSP para obter os dados dinmicos da aplicao.

8.3 Forward de requisies


Para que um Servlet Controller possa repassar a requisio recebida para uma pgina
JSP, necessrio utilizar um mtodo especfico da classe
javax.servlet.http.HttpServletRequest.

Assinatura do mtodo getRequestDispatcher () da classe HttpServletRequest


public javax.servlet.RequestDispatcher getRequestDispatcher(java.lang.String
p_path);

Esses mtodo retorna uma referncia para um objeto que implementa a interface
javax.servlet.RequestDispatcher e que atua como um wrapper para o recurso indicado no path passado como parmetro para a funo. Assim, se voc passar como
parmetro, por exemplo, o caminho relativo de uma pgina JSP, esse mtodo retornar uma referncia a um wrapper dessa pgina JSP.
Esse wrapper, por sua vez, disponibiliza um mtodo forward () que permite que
voc repasse a requisio para o recurso encapsulado pelo wrapper.

132

Captulo 8 Modelo MVC

Assinatura do mtodo forward () da interface RequestDispatcher


public void forward(HttpServletRequest p_request, HttpServletResponse, p_response);

Podemos, dessa forma, implementar um Servlet de exemplo que no faz nada, apenas repassa todas as requisies recebidas para uma pgina JSP.

Exemplo de Servlet que repassa requisies para uma pgina JSP


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
// Servlet simples que repassa requisies recebidas para a
// pgina JSP OlaMundo.jsp
public class ServletRepassaReqs extends HttpServlet {
public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
// Repassando a requisio para a pgina JSP OlaMundo.jsp
try {
p_request.getRequestDispatcher(/OlaMundo.jsp).forward(p_request,
p_response);
} catch(ServletException p_e) {}
}
}

No Servlet anterior, existe um ponto importante que deve ser observado: o path passado como parmetro para a funo getRequestDispatcher () referencia um recurso
contido na mesma aplicao Web do Servlet, e, dessa forma, deve excluir a parte
referente ao diretrio virtual da aplicao (ou seja, esse path no deve ser escrito
como /livroservlets/OlaMundo.jsp). Alm disso, importante observar que o mtodo
forward poder lanar uma exceo: uma das causas pode ser uma exceo lanada
pelo prprio recurso referenciado pelo RequestDispatcher.
Podemos tambm implementar a pgina JSP referenciada no Servlet anterior como:

Exemplo de pgina JSP OlaMundo.jsp


<HTML>
<BODY>
<% out.println(Ola Mundo!); %>
</BODY>
</HTML>

Assim, a cada requisio recebida, o Servlet ServletRepassaReqs repassa a requisio


para a pgina JSP OlaMundo.jsp, que por sua vez retorna para o Browser a seguinte
pgina HTML

133

J2EE Primeiros Passos

Resposta do Servlet ServletRepassaReqs


<HTML>
<BODY>
Ola Mundo!
</BODY>
</HTML>

8.4 Atributos de requisies


Existe ainda um outro recurso da API de Servlets que iremos utilizar no desenvolvimento de nossas aplicaes Web no modelo MVC: esse recurso a definio / obteno de atributos da requisio.
A classe HttpServletRequest possui quatro mtodos que podem ser utilizados para
gerenciar os atributos de uma requisio.

Assinatura dos mtodos da classe HttpServletRequest que gerenciam os


atributos de uma requisio
public java.lang.Object getAttribute(java.lang.String p_attributeName);
public java.util.Enumeration getAttributeNames ();
public void

removeAttribute(java.lang.String p_attributeName);

public void setAttribute(java.lang.String p_attributeName, java.lang.Object


p_attributeValue);

Esses mtodos funcionam de maneira semelhante aos mtodos da classe ServletContext apresentada na seo 3.6: eles permitem definir, remover ou obter valores de
atributos de uma requisio. Esses valores de atributos no precisam necessariamente ser objetos String, eles podem ser objetos quaisquer Java.
Para exemplificar o uso dessas funes, vamos implementar novamente nosso Servlet ServletRepassaReqs da seguinte forma:

Segunda verso para Servlet que repassa requisies para uma pgina JSP
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Servlet simples que repassa requisies recebidas para a pgina JSP


public class ServletRepassaReqs extends HttpServlet {

134

Captulo 8 Modelo MVC


public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
// Definimos um atributo da requisio chamado Mensagem
p_request.setAttribute(Mensagem, Ola Mundo!);

// Repassando a requisio para a pgina JSP ApresentaMensagem.jsp


try {
p_request.getRequestDispatcher(/livroservlets/
ApresentaMensagem.jsp).forward(p_request, p_response);
} catch(ServletException p_e) {}
}
}

A pgina JSP ApresentaMensagem.jsp, por sua vez, pode ser implementada como:

Pgina JSP ApresentaMensagem.jsp


<HTML>
<BODY>
<%
String l_mensagem = (String) request.getAttribute(Mensagem);
if(l_mensagem != null) out.println(l_mensagem);
%>
</BODY>
</HTML>

Dessa forma, alm de repassar a requisio do Servlet para a pgina JSP, estamos
tambm passando objetos, definidos no Servlet, para a pgina JSP. Esse mecanismo
funciona graas aos atributos de requisio.

8.5 Juntando as partes


Juntando os recursos apresentados nas sees anteriores, podemos finalmente apresentar o modelo MVC com todos os seus componentes.
Para fazer essa apresentao, reimplementaremos e estenderemos a aplicao de login da seo 6.4 desse livro. Agora, a aplicao de login passar a prever tambm um
nvel de acesso associado a cada usurio que efetua a autenticao: se o usurio tiver
nvel de acesso administrativo, ser apresentada a interface do administrador, caso
contrrio ser apresentada a interface do usurio comum.

135

J2EE Primeiros Passos


Assim, o Servlet de Login ser:

ServletLogin
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// Apresenta o formulrio de login e faz a autenticao da aplicao


public class Login extends HttpServlet {

1.

// Verifica se existe usurio com o login e senha passados como parmetro: se


// existir, retorna nvel de acesso do usurio em questo (1 para nvel de
// usurio comum, 2 para nvel de administrador); caso contrrio, retorna private int NivelAcessoUsuario(String p_login, String p_senha) {
int l_nivelAcesso = -1;
if((p_login != null) && (p_senha != null)) {
// Voc deve implementar aqui o cdigo para validar o login
// e senha do usurio e definir a varivel l_nivelAcesso
// (por exemplo, consultando uma base de dados)
}
return l_nivelAcesso;
}

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


throws IOException {

// Definindo headers auxiliares para evitar cacheamento de pgina


p_response.setHeader(Cache-Control, no-cache, must-revalidate);
p_response.setHeader(Pragma, no-cache);
p_response.setHeader(Expires, Mon, 26 Jul 1997 05:00:00 GMT);
p_response.setDateHeader(Last-Modified, System.currentTimeMillis ());

// Fazendo autenticao do usurio e obtendo seu nvel de acesso


String l_login = p_request.getParameter(LOGIN), l_senha =
p_request.getParameter(SENHA);
int l_nivelAcesso = NivelAcessoUsuario(l_login, l_senha);

// Definindo atributos de sesso (se o usurio for vlido)


HttpSession l_sessao = p_request.getSession(true);
if(l_nivelAcesso != -1) l_sessao.setAttribute(LOGIN, l_login);
else l_sessao.removeAttribute(LOGIN);

136

Captulo 8 Modelo MVC


try {
if(l_nivelAcesso == -1) {
// Usurio no conseguiu se autenticar; existem duas possibilidades:
// login / senha incorretos ou usurio ainda no enviou os dados do
// formulrio (simplesmente acessou a pgina); em ambos os casos,
// fazemos um forward para a pgina JSP FormLogin.jsp
p_request.setAttribute(Mensagem, );
if((l_login != null) || (l_senha != null))p_request.setAttribute
(Mensagem, Erro: login e/ou senha invlido(s)! );
p_request.getRequestDispatcher(/FormLogin.jsp).forward(p_request,
p_response);
}
else {
// Usurio conseguiu efetuar autenticao; apresentando a interface
// correspondente ao seu nvel de acesso
p_request.setAttribute(Login, l_login);
if(l_nivelAcesso == 1) p_request.getRequestDispatcher
(/UsuarioComum.jsp).forward(p_request, p_response);
else p_request.getRequestDispatcher
(/Administrador.jsp).forward(p_request, p_response);
}
} catch( ServletException p_e ) {}
}
// Nesse Servlet, os mtodos GET e POST so tratados da mesma maneira
// (pelo mesmo trecho de cdigo)
public void doPost(HttpServletRequest p_request, HttpServletResponse p_response)
throws IOException {
doGet(p_request, p_response);
}
}

Conforme voc pode observar no Servlet anterior, no existe nenhuma codificao


feita que se relaciona a apresentao da interface para o usurio da aplicao. O Servlet simplesmente trata os parmetros recebidos, repassando a requisio para as
diversas pginas JSP da aplicao, que devero ser responsveis pela interface em si.

Pgina JSP FormLogin.jsp


<HTML>
<BODY>
<%= (String) request.getAttribute(Mensagem) %><BR>
<FORM ACTION=Login METHOD=POST>
Login: <INPUT TYPE=TEXT NAME=LOGIN><BR>
Senha: <INPUT TYPE=PASSWORD NAME=SENHA><BR>
<INPUT TYPE=SUBMIT NAME=ENTRAR VALUE=Entrar><BR>
</FORM>
</BODY></HTML>

137

J2EE Primeiros Passos

Pgina JSP UsuarioComum.jsp


<HTML>
<BODY>
Ol, <%= request.getAttribute(Login) %>, voc tem acesso como usurio comum!
</BODY>
</HTML>

Pgina JSP Administrador.jsp


<HTML>
<BODY>
Ol, <%= request.getAttribute(Login) %>, voc tem acesso como administrador!
</BODY>
</HTML>

Essas pginas JSP podero ser trabalhadas pelos responsveis pelo layout e formatao de nossa aplicao, sem afetar a lgica e o trabalho de desenvolvimento.

138

Captulo 9
Tpicos adicionais
J apresentamos nos captulos anteriores as principais caractersticas e funcionalidades referentes ao desenvolvimento de aplicaes Web com Servlets e pginas JSP.
Estaremos, nesse captulo, apresentando alguns tpicos adicionais que complementaro todo o conhecimento que voc obteve at agora: voc ir conhecer arquivos
WAR, mecanismos de autenticao HTTP e pools de conexes a uma base de dados.

9.1 Arquivos WAR


J apresentamos, na seo 2.2, uma maneira atravs da qual voc pode instalar uma
aplicao Web em um servidor de aplicaes: voc pode fazer essa instalao criando, abaixo do diretrio webapps, uma pasta com o nome de sua aplicao, com o
contedo dessa pasta obedecendo a um formato especfico (veja seo 2.2).
Embora essa forma de instalar a aplicao funcione, considerado mais elegante
distribuir sua aplicao no formato de um arquivo WAR, ou Web Application Archive.
Um arquivo WAR nada mais que um arquivo .jar, nomeado com a extenso .war.
Assim, voc deve gerar o arquivo WAR utilizando o aplicativo jar para juntar todo o
contedo do diretrio de sua aplicao (retirando, obviamente, os arquivos fontes
.java).
Assim, poderamos, por exemplo, remover os arquivos .java de dentro do diretrio
livroservlets (que contm a nossa aplicao), e, a partir de um PROMPT DOS e de
dentro desse diretrio, digitar a linha de comando jar cvf ..\livroservlets.war *.
Com um arquivo .war, podemos instalar nossa aplicao Web em qualquer servidor de aplicaes: basta copiar esse arquivo para a pasta webapps do servidor. Obviamente, devemos tomar cuidado para no instalar o arquivo .war mais o diretrio
com toda a nossa aplicao juntos em um mesmo servidor de aplicaes.

139

J2EE Primeiros Passos

9.2 Autenticao HTTP


Na seo 6.4 desse livro, apresentamos um exemplo de aplicao contendo uma autenticao baseada em formulrios HTML. Essa no a nica forma de fazer a autenticao de usurios de uma aplicao.
O protocolo HTTP incorpora uma funcionalidade que pode auxiliar na implementao de um mecanismo de autenticao. Estaremos, nessa seo, mostrando o funcionamento de um tipo especial de autenticao, a partir do protocolo HTTP, chamada
de Basic Authentication (autenticao bsica).
Para implementar esse tipo de autenticao, precisamos utilizar o cdigo de status de
resposta HTTP 401 (HttpServletResponse.SC_UNAUTHORIZED) e o header de resposta WWW-Authenticate.
Ao retornar uma resposta com esse cdigo de status e esse header de resposta contendo um valor BASIC REALM=<domnio>, onde <domnio> deve ser substitudo por
um nome do domnio no qual estamos fazendo a autenticao (cada domnio deve
proteger um conjunto de recursos de sua aplicao), faremos com que o browser do
usurio de nossa aplicao mostre uma caixa de dilogo pedindo um usurio e senha
de acesso.
O usurio e senha digitados nessa caixa pelo usurio sero enviados, por outro lado,
junto com uma nova requisio a nossa aplicao, atravs do header Authorization.
O valor desse header estar codificado no formato Base64, sendo necessrio utilizar
um decodificador para ler, efetivamente, seu contedo: esse contedo ser um texto
no formato <usurio digitado>:<senha digitada>.
O Servlet a seguir exemplifica o uso desse tipo de autenticao HTTP:

Exemplo de Servlet que utiliza autenticao HTTP para controlar acesso


import java.io.*;
import javax.servlet.http.*;

// Servlet que utiliza autenticao HTTP para controlar acesso de usurios da


aplicao
public class ServletAutenticacaoHTTP extends HttpServlet {

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


throws IOException {

// Definindo headers auxiliares para evitar cacheamento de pgina


p_response.setHeader(Cache-Control, no-cache, must-revalidate);
p_response.setHeader(Pragma, no-cache);

140

Captulo 9 Tpicos adicionais


p_response.setHeader(Expires, Mon, 26 Jul 1997 05:00:00 GMT);
p_response.setDateHeader(Last-Modified, System.currentTimeMillis ());

//
//
//
//

Obtendo o valor do header Authorization; se esse valor for nulo,


definimos o cdigo de resposta HTTP SC_UNAUTHORIZED e o header
WWW-Authenticated para que o browser do usurio apresente a caixa de
dilogo solicitando o preenchimento de login e senha

String l_headerAuth = p_request.getHeader(Authorization);


if(l_headerAuth == null)
{
p_response.setHeader(WWW-Authenticate,
BASIC REALM=\Dominio de Autenticacao\);
p_response.sendError(p_response.SC_UNAUTHORIZED);
return;
}

// Decodificando o contedo do header: para isso utilizamos a classe


// Base64.Java disponvel em http://iharder.sourceforge.net/base64/
// OBS: necessrio desconsiderar os 6 primeiros caracteres do header
// (eles contm o String Basic )
)));

String l_headerAuthDec = new String(Base64.decode(l_headerAuth.substring(6

// O login separado da senha pelo caractere :


String l_login = l_headerAuthDec.substring(0, l_headerAuthDec.indexOf(:));
String l_senha = l_headerAuthDec.substring(l_headerAuthDec.indexOf(:) + 1);

PrintWriter l_pw = p_response.getWriter ();


l_pw.println(<HTML><BODY>);
l_pw.println(Login: \ + l_login + \<BR>);
l_pw.println(Senha: \ + l_senha + \<BR>);
l_pw.println(</BODY></HTML>);
l_pw.flush ();
}
}

Existe tambm uma maneira de implementar a autenticao de usurios que esto


acessando nossa aplicao baseada em elementos de segurana configurados no
Deployment Descriptor de nossa aplicao (veja seo 2.2).
Para implementar essa autenticao dessa forma, voc deve adicionar elementos security-constraint e um elemento login-config ao Deployment Descriptor de sua
aplicao.

141

J2EE Primeiros Passos

Exemplo de configurao de segurana no Deployment Descriptor da aplicao


<security-constraint>
<web-resource-collection>
<web-resource-name>Area Restrita</web-resource-name>
<url-pattern>/ServletAutenticacaoHTTP</url-pattern>
</web-resource-collection>
<auth-constraint><role-name>tomcat</role-name></auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Dominio de Autenticacao</realm-name>
</login-config>

Os elementos apresentados na listagem anterior, por exemplo, definem que os acessos a URL /livroservlets/ServletAutenticacaoHTTP devem ser autenticados. Em particular, o elemento role-name define o grupo de usurios que deve ter acesso a URL
em questo: os diversos grupos, com seus respectivos usurios / senhas, devem, nesse caso, ser configurados no arquivo conf\tomcat-users.xml abaixo do diretrio de
instalao do Apache Tomcat.
Se voc optar por utilizar esse mtodo de autenticao, voc deve chamar em seu
cdigo os mtodos getRemoteUser () e getUserPrincipal (), da classe HttpServletRequest, para obter o nome do usurio e seu grupo.
Mais detalhes com relao a autenticao baseada em elementos de segurana do
Deployment Descriptor da aplicao podem ser encontrados na especificao de
Servlets.

9.3 Pools de conexes a base de dados


Uma das grandes vantagens no desenvolvimento de aplicaes Web com Servlets e
pginas JSP a performance obtida em funo da persistncia dos objetos carregados em memria. Em particular, conforme mostramos em diversos exemplos ao longo desse livro, o estado de uma varivel esttica pode ser mantido ao longo das diversas requisies recebidas pela aplicao.
Um dos recursos que mais se beneficiam dessa persistncia em memria so as conexes com o banco de dados: como o processo de abrir uma nova conexo com o
banco de dados pode pesar significativamente na performance da aplicao, vale a
pena manter as conexes abertas, em vez de abrir uma nova conexo a cada requisio recebida.

142

Captulo 9 Tpicos adicionais


Esse tipo de persistncia , normalmente, implementado por meio de um gerenciador de conexes a base de dados: a cada requisio recebida, um Servlet chama um
mtodo desse gerenciador para alocar uma conexo; ao trmino de seu processamento, o Servlet chama outro mtodo para liberar a conexo previamente alocada. O
gerenciador, por sua vez, responsvel por estabelecer efetivamente novas conexes quando necessrio, e armazenar essas conexes abertas.
A classe PoolConBD, a seguir, implementa um gerenciador de conexes a base de
dados:

Classe PoolConBD: implementa gerenciador de pool de conexes com a base de


dados
package com.livroservlets;

import java.io.*;
import java.sql.*;
import java.util.*;
import java.util.Date;

// Gerenciador de conexes ao banco de dados


// Mantm um pool de conexes ativas com o banco de dados de maneira que no
// seja necessrio se estabelecer uma nova conexo a cada requisio recebida
public class PoolConBD
{

// Pool de conexes de uma aplicao especfica


// Assim, cada aplicao Web pode manter um conjunto distinto de conexes
// (caso contrrio, todas as aplicaes que forem executadas em uma mesma
// instncia da mquina virtual tero que compartilhar o mesmo Pool).
private static class PoolConBDAplic
{
private String m_Aplic = null;

// Nome da aplicao

private Vector m_Pool

// Pool de conexes dessa aplicao

= null;

// Url, usuario e senha para abrir novas conexes


private String m_Url = null, m_Usuario = null, m_Senha = null;

// Tamanho mximo desse pool: dessa forma evitamos que, caso haja
// um erro na aplicao, novas conexes sejam abertas indefinidamente
// at derrubar o servidor de banco de dados.
private int m_TamMaxPool = 0;

143

J2EE Primeiros Passos


// Timeout para o estabelecimento de novas conexes
private int m_Timeout = 0;

private Driver m_DriverJdbc = null;

// Driver jdbc

private int m_NumConsAlocadas = 0;

// Nmero corrente de conexes alocadas

// Inicializa estruturas locais: cadastra driver jdbc e


// abre a primeira conexo com a base de dados
public PoolConBDAplic(String p_aplic, String p_driverJdbc, String p_nomeBD,
String p_url, String p_usuario, String p_senha, int p_tamMaxPool, int
p_timeout) throws PoolConBDException
{
if(p_aplic != null) {
if((p_driverJdbc != null) && (p_nomeBD != null) && (p_url != null) &&
(p_usuario != null) && (p_senha != null) && (p_tamMaxPool > 0)
&& (p_timeout > 0)) {
m_Aplic = p_aplic;
m_Pool = new Vector ();

m_Url = p_url;
m_Usuario = p_usuario;
m_Senha = p_senha;
m_TamMaxPool = p_tamMaxPool;
m_Timeout = p_timeout;

// Carregando / cadastrando o driver Jdbc


try {
m_DriverJdbc = (Driver)
Class.forName(p_driverJdbc).newInstance ();
DriverManager.registerDriver(m_DriverJdbc);
} catch(Exception p_e) {
throw new PoolConBDException(p_aplic, no foi possvel
carregar/cadastrar driver jdbc);
}

// Inicializando pool com uma conexo


try {
m_Pool.addElement(alocaNovaConexao ());
m_NumConsAlocadas = 1;
} catch(Exception p_e) {
destroiPool ();
throw new PoolConBDException(p_aplic, no foi possvel
criar a primeira conexo; + p_e.getMessage ());
}

144

Captulo 9 Tpicos adicionais


}
else throw new PoolConBDException(p_aplic,
parmetros de criao do pool invlidos);
}
}

// Aloca uma nova conexao com a base de dados


// OBS: esse mtodo precisa ser synchronized para evitar
// problemas de concorrncia no acesso ao Pool
{

private synchronized Connection alocaNovaConexao () throws PoolConBDException


Connection l_con = null;
try {
l_con = DriverManager.getConnection(m_Url, m_Usuario, m_Senha);
} catch (Exception p_e) {
throw new PoolConBDException(m_Aplic, no foi possvel abrir nova
conexo; + a razo foi \ + p_e.getMessage () + \);
}
return l_con;
}

// Retorna, se possvel, uma conexo com a base de dados


// (ou diretamente do pool ou uma nova conexo)
// OBS: esse mtodo precisa ser synchronized para evitar
// problemas de concorrncia no acesso ao Pool
public synchronized Connection alocaConexao () throws PoolConBDException
{
Connection l_con = null;
if(m_Pool != null)
{
if(m_Pool.size () > 0)
{
// Se o pool de conexes no estiver vazio, podemos
// retirar dele uma conexo previamente estabelecida
l_con = (Connection) m_Pool.firstElement ();
m_Pool.removeElementAt(0);

try {
if (l_con.isClosed ()) l_con = null;
} catch (Exception p_e) { l_con = null; }

if(l_con == null) l_con = alocaConexao ();


}

145

J2EE Primeiros Passos


else if (m_NumConsAlocadas < m_TamMaxPool)
{
// ... caso contrrio, se ainda no tivermos atingido o tamanho
// mximo do pool, podemos estabelecer uma nova conexo
l_con = alocaNovaConexao ();
}
else throw new PoolConBDException(m_Aplic, nmero mximo
de conexes atingido);
}

if(l_con != null) m_NumConsAlocadas ++;


return l_con;
}

// Libera uma conexo previamente alocada (retorna essa conexo para o pool)
// OBS: esse mtodo precisa ser synchronized para evitar problemas de
// concorrncia no acesso ao Pool
public synchronized void liberaConexao(Connection p_con) {
if(m_Pool != null)
{
try {
if(!p_con.isClosed ()) m_Pool.addElement(p_con);
} catch (Exception p_e) {}
m_NumConsAlocadas -;
}
}

// Retorna o nmero corrente de conexes alocadas


public synchronized int obtemNumConsAlocadas ()
{
return m_NumConsAlocadas;
}

// Destroi pool de conexes (fechando todas as conexes abertas)


public synchronized void destroiPool () throws PoolConBDException
{
if(m_Pool != null)
{
for (int i = 0; i < m_Pool.size (); i++)
{
Connection l_con = (Connection) m_Pool.elementAt(i);

146

Captulo 9 Tpicos adicionais


try {
if(l_con != null) l_con.close ();
} catch (Exception p_e) {}
}

m_Pool.removeAllElements ();

try {
DriverManager.deregisterDriver(m_DriverJdbc);
} catch(Exception p_e) {
throw new PoolConBDException(m_Aplic, no foi possvel
descadastrar driver jdbc);
}
}
}
}

// Hashtable com mapeamento entre nomes das aplicaes e seus respectivos pools
private static Hashtable m_PoolsAplics = new Hashtable ();

// Cria um novo pool a partir dos seguintes dados: nome da aplicao,


// nome do driver de conexo a base de dados, nome da base, url / usurio /
senha
// de conexo, tamanho mximo do pool e timeout de conexo a base de dados.
public static synchronized void criaPoolAplic(String p_aplic, String
p_driverJdbc, String p_nomeBD, String p_url, String p_usuario, String
p_senha, int p_tamMaxPool, int p_timeout) throws PoolConBDException {
if(p_aplic != null) {
PoolConBDAplic l_pool = (PoolConBDAplic) m_PoolsAplics.get(p_aplic);
if(l_pool != null) l_pool.destroiPool ();

l_pool = new PoolConBDAplic(p_aplic, p_driverJdbc, p_nomeBD, p_url,


p_usuario, p_senha, p_tamMaxPool, p_timeout);
m_PoolsAplics.put(p_aplic, l_pool);
}
}

// Veja PoolConBDAplic.alocaConexao
public static Connection alocaConexao(String p_aplic) throws PoolConBDException
{
PoolConBDAplic l_pool = (PoolConBDAplic) m_PoolsAplics.get(p_aplic);
if(l_pool != null) return l_pool.alocaConexao ();

147

J2EE Primeiros Passos


else return null;
}

// Veja PoolConBDAplic.obtemNumConsAlocadas
public static int obtemNumConsAlocadas(String p_aplic)
{
PoolConBDAplic l_pool = (PoolConBDAplic) m_PoolsAplics.get(p_aplic);

if(l_pool != null) return l_pool.obtemNumConsAlocadas ();


else return -1;
}

// Veja PoolConBDAplic.liberaConexao
public static void liberaConexao(String p_aplic, Connection p_con)
{
PoolConBDAplic l_pool = (PoolConBDAplic) m_PoolsAplics.get(p_aplic);
if(l_pool != null) l_pool.liberaConexao(p_con);
}

// Vide PoolConDBAplic.destroiPool
public static synchronized void destroiPool(String p_aplic)
throws PoolConBDException
{
PoolConBDAplic l_pool = (PoolConBDAplic) m_PoolsAplics.get(p_aplic);

if (l_pool != null)
{
l_pool.destroiPool();
m_PoolsAplics.remove(p_aplic);
}
}
}

interessante observar que a classe anterior permite que sejam configurados / utilizados no apenas um nico pool de conexes a base de dados, mas sim diversos
pools: como so declaradas variveis estticas, todas as aplicaes Web sendo executadas na mesma instncia da mquina virtual Java iro compartilhar esses mesmos
objetos. Sendo assim, necessrio prever a alocao e liberao de conexes por
aplicao, de forma que o funcionamento de uma aplicao no interfira no funcionamento de outra.

148

Captulo 9 Tpicos adicionais


Esse gerenciador de conexes ao banco de dados utiliza tambm uma classe do tipo
Exception para indicar falhas em seu funcionamento. Segue a implementao dessa
classe PoolConBDException:

Classe PoolConBDException: excees associadas a classe PoolConBD


package com.livroservlets;
package com.livroservlets;

// Exceo para gerenciador de conexes a base de dados PoolConBD


public class PoolConBDException extends Exception {

public PoolConBDException(String p_msg) { super(p_msg); }

public PoolConBDException(String p_aplic, String p_msg) {


super(( + p_aplic + ) + p_msg);
}
}

Finalmente, temos a seguir um Servlet para exemplificar o uso de nosso gerenciador


de pool de conexes:

Servlet ServletTestePool: exemplifica o uso de nosso gerenciado de pool de


conexes a base de dados
package com.livroservlets;
import java.io.*;
import java.sql.*;

import javax.servlet.*;
import javax.servlet.http.*;

import com.livroservlets.*;

// Servlet para teste do pool de conexes a base de dados


public class ServletTestePool extends HttpServlet {

// Inicializa pool de conexes


public void init(ServletConfig p_servletConfig)
throws UnavailableException, ServletException {
super.init(p_servletConfig);

149

J2EE Primeiros Passos


if (p_servletConfig != null)
try {
PoolConBD.criaPoolAplic(LivroServlets, com.mysql.jdbc.Driver,
livroservlets, jdbc:mysql://127.0.0.1:3306/livroservlets,
admin, 321, 10, 60);
} catch(Exception p_e) {
throw new UnavailableException(Erro: no foi possvel criar pool;

+ p_e.getMessage () + \);
}
}

public void doGet(HttpServletRequest p_request, HttpServletResponse p_response)


throws IOException {

// Definindo headers auxiliares para evitar cacheamento de pgina


p_response.setHeader(Cache-Control, no-cache, must-revalidate);
p_response.setHeader(Pragma, no-cache);
p_response.setHeader(Expires, Mon, 26 Jul 1997 05:00:00 GMT);
p_response.setDateHeader(Last-Modified, System.currentTimeMillis ());

PrintWriter l_pw = p_response.getWriter ();


l_pw.println(<HTML><BODY>);

try {
l_pw.println(Alocando conexo com a base de dados ... <BR>);
Connection l_con = PoolConBD.alocaConexao(LivroServlets);

// ... executa queries SQL com conexo alocada ...

l_pw.println(Liberando conexo com a base de dados ... <BR>);


PoolConBD.liberaConexao(LivroServlets, l_con);
} catch(Exception p_e) {
l_pw.println(Erro na alocao / liberao de conexo a base de dados!);
}

l_pw.println(</BODY></HTML>);
l_pw.flush ();
}
}

150

Parte II
Desenvolvimento de Aplicaes
Distribudas Utilizando EJB
Esta parte foca no paradigma de desenvolvimento de aplicaes distribudas, destacando a evoluo das tcnicas de desenvolvimento, desde a programao estrutural
at o atual uso de sistemas distribudos. So detalhados os componentes de negcio
Enterprise JavaBeans e os recursos oferecidos no uso desta tecnologia.

151

J2EE Primeiros Passos

152

Captulo 10
Novas Tcnicas de Desenvolvimento
Este captulo apresenta um histrico evolutivo das tcnicas de desenvolvimento de
sistemas. Destacando, principalmente, o paradigma baseado no desenvolvimento de
aplicaes distribudas.

10.1 Desenvolvimento de Clssico de Aplicaes


O mercado de desenvolvimento de aplicaes na dcada de setenta e oitenta era
baseado em sistemas centralizados executando sobre um nico computador. O desenvolvimento contnuo da tecnologia diminuiu o preo de componentes de hardware. Com a queda no preo de componentes de hardware tornou-se vivel a aquisio de computadores, agilizando, principalmente, o processo produtivo de empresas.
As empresas, que adquiriram muitos computadores, comearam a perceber a utilidade de criar canais de comunicao entre estas mquinas, desenvolvendo muito as
redes de computadores. As redes partiram para o cotidiano do mercado. A vantagem
das redes de computadores estava ligada, principalmente, possibilidade de acesso
compartilhado de recursos, tais como impressoras e arquivos.
Com o desenvolvimento das redes de computadores diversas empresas comearam
a oferecer sistemas operacionais que suportassem esta interconexo. Desenvolveram-se, ento, sistemas como o Novell, Windows for Workgroups, Linux que mais
tarde foram evoluindo para os sistemas mais utilizados atualmente.
Com o desenvolvimento dos sistemas operacionais de rede, que tinham como objetivo o compartilhamento de recursos, os desenvolvedores se depararam com clientes
desejando softwares capazes de executar em todos seus computadores, atualizando
um mesmo banco de dados. Neste momento da hitria houve o desenvolvimento da
tecnologia cliente-servidor, utilizando linguagens tais como Clipper, Visual Basic e
Delphi.

153

J2EE Primeiros Passos


Nas implementaes da tecnologia cliente-servidor era utilizado um computador central com o banco de dados. Cada um dos computadores que participavam da rede
tinha instalado um software que acessava remotamente este banco de dados. Esta foi
a forma encontrada para que todos pudessem executar o software com desempenho
desejvel.
Nos anos noventa, com o desenvolvimento da Internet, um novo mercado foi criado.
Este mercado exigiria mais conhecimentos dos desenvolvedores, e especializao
at mesmos dos vendedores de tecnologia. Estes sistemas de Internet executavam
sobre um computador com um Web Server (tal como Apache, Microsoft IIS, etc) e um
banco de dados (PostgreSQL, Oracle, etc). Quando um usurio acessasse um servidor
atravs de um navegador (Netscape, Opera, Microsoft Internet Explorer, etc), este
servidor retornaria uma pgina HTML.
No incio os servidores de pginas na Internet, hospedavam apenas pginas em HTML
com figuras (gifs, jpegs, etc). Pginas HTML no poderiam gerar dinamicamente dados, tal como obter, inserir e alterar informaes em um banco de dados. Neste momento houve o desenvolvimento de CGIs (Common Gateway Interfaces). Os CGIs
eram pequenos programas em linguagens como por exemplo C. Estes CGIs eram
chamados pelo servidor Web para acessar um banco de dados ou executar qualquer
tipo de tarefa que deveria ser dinmica, e no esttica, tal como so as pginas HTML.

Servidor Web
CGI

Servidor

Figura 10.1 Arquitetura de um Servidor WEB com suporte a CGI.


Devido ao fato de que os CGIs eram difceis de desenvolver (nesta poca se utilizava
linguagem C), iniciaram estudos e implementaes de suportes modulares nos sevidores Web para permitir a integrao direta com linguagens de desenvolvimento mais
simples. Os CGIs eram executados como processos parte do Web Server, o que
necessitava a alocao de mais memria e sobrecarregava o sistema.
Diversas linguagens de script se desenvolveram aps os CGIs, tais como PHP, ASP,
Perl, Phyton e JSP. A execuo de scripts (pequenos programas) criados nestas linguagens era feita como observado na figura X, o que diminuia o consumo de memria do servidor, gerava menor atraso no tempo de resposta do cliente e minimizava a
sobrecarga do servidor.

154

Captulo 10 Novas Tcnicas de Desenvolvimento

Servidor Web

Script

Servidor

Figura 10.2 Arquitetura de um Servidor WEB com suporte modular de uma


linguagem de script.
O desenvolvimento nas linguagens de script o mais comum, at hoje, para sistemas
na Internet. Contudo, este modelo apresenta limitaes tais como escalabilidade,
comunicao entre processos, acesso simultneo a bancos de dados, transaes entre bancos de dados que esto localizados em diferentes computadores e distribuio de carga.
Para solucionar as limitaes das linguagens de script diversos trabalhos foram iniciados. Estes projetos visavam a construo de suportes para a construo de aplicaes distribudas. A principal caracterstica destas aplicaes que os computadores
executam, de forma cooperativa, a mesma operao computacional, e oferecem um
grau de transparncia para o usurio final.
O desenvolvimento de suportes para a construo de aplicaes distribudas ainda
tinha um problema: era complexo. Mais tarde algumas empresas, incluindo a Sun
Microsystems se uniram em torno de um padro chamado J2EE (Java 2 Enterprise
Edition). Estre padro foi criado para a construo de um suporte consistente e de
fcil desenvolvimento de aplicaes distribudas.

10.2 Sistemas Distribudos


Antes de aprofundar em qualquer arquitetura para a construo de aplicaes distribudas, deve-se aprender entender mais sobre sistemas distribudos. A definio mais
simples de sistemas distribudos : um conjunto de computadores interligados em
rede, que executam operaes computacionais de forma cooperativa e oferecem transparncia para o usurio final. Ter uma rede o primeiro passo para a construo
destes sistemas, o prximo passo criar um sistema que seja modular, onde cada
mdulo execute em um computador distinto. Estes mdulos trocam informaes entre
si para executar determinada operao computacional.

155

J2EE Primeiros Passos


Transparncia trata-se de criar um nvel de abstrao entre o usurio e o sistema, para
que o usurio no se preocupe e nem tenha que gerenciar sua apliucao que executa parte em cada computador. Este usurio enxerga o conjunto de computadores
interligados em rede como um nico computador virtual (obtenha mais informaes
no livro Distributed Operating Systems, Prentice Hall, Andrew S. Tanembaum).

Computador
Virtualmente nico

Computador Computador Computador

Servidor

Figura 10.3 Computadores interligados em rede executando um Sistema


Distribudo.
Os benefcios de um Sistema Distribudo sobre sistemas que executa sobre um nico
computador incluem: a economia, a velocidade, o desenvolvimento de aplicaes
naturalmente distribudas, a confiabilidade, o crescimento incremental (ou escalabilidade).
Um caso prtico da economia encontra-se, por exemplo, numa situao vivenciada
por um dos autores que desenvolvia sistemas para a Internet. Havia um sistema contrudo em PHP, uma linguagem de script, que acessava um banco de dados e realizava outras operaes. Aps certo tempo este sistema tornou-se um dos sites mais acessados do pas, e o servidor que o executava ficou cada vez mais carregado. Havia
ento dois caminhos a se tomar: o primeiro seria comprar um computador maior e
com mais capacidade, o outro seria desenvolver a aplicao novamente para executar como uma aplicao distribuda.
Para tratar a aplicao em PHP foram realizados diversos estudos comparando custos
e desempenho computacional. Observou-se que seria necessrio adquirir uma workstation da Sun Microsystems para atender a aplicao, caso contrrio seria necessrio
desenvolv-la novamente como uma aplicao distribuda. Testes comprovaram que
desenvolvendo novamente a aplicao trs computadores pessoais poderiam atend-la, o que diminua os custos de aquisio de hardware em 12 vezes.

156

Captulo 10 Novas Tcnicas de Desenvolvimento

Sistema
Centralizado

Sistema
Distribudo

X
PC

Workstation

PC

PC

Figura 10.4 Custo de um Sistema Centralizado x Sistema Distribudo.


Utilizar um ambiente distribudo pode colaborar para aumento do desempenho computacional, pois h a possibilidade de subdividir uma aplicao em mdulos, que executem em paralelo, cada um em um computador distinto. Cada computador manipula
parte da carga e permite que a aplicao tenha maior desempenho final. Um exemplo
prtico de aplicao que busca alto desempenho o site Google (www.google.com).
Suponha uma situao onde buscas muito complexas devem ser realizadas, existe um
nico computador que s suportaria? No. Construir um hardware para isto seria vivel?
No, pois o custo seria proibitivo. Para resolver este tipo de problema, os envolvidos no
Google criaram uma aplicao que executa sobre diversos computadores, particionando as operaes de busca e indexao das informaes.
Google (Sistema Distribudo)

...
Workstation

Workstation

Workstation

...
Servidor

Servidor

Servidor

Figura 10.5 Exemplo de um Sistema Distribudo (Site de Buscas Google).


H aplicaes que so naturalmente distribudas, onde mdulos precisam executar
tarefas distintas. Este outro tipo de aplicao altamente privilegiada pelos sistemas
distribudos.
A confiabilidade de um sistema pode ser atingida de duas formas: atravs da replicao de hardware e da replicao de software.

157

J2EE Primeiros Passos


Replicar hardware tem o intuito de no deixar o sistema falhar em casos onde um dos
componentes fsicos apresente problemas, esta soluo conhecida como tolerncia a falhas. A rplica de software tem o intuito de copiar softwares para diferentes
computadores, caso destes falhe, outro computador poder reiniciar a aplicao e o
sistema continua disponvel, este tipo de soluo conhecida como alta disponibilidade.
A alta disponibilidade algo inerente de um sistema distribudo, pois a existncia de
vrios computadores em rede simplifica este processo. Mdulos de uma aplicao
distribuda podem ser replicados em diversos computadores. Caso um dos computadores tenha problemas, outro poder assumir a execuo.

Mdulo A

Mdulo B

Servidor

Servidor

Mdulo C

Servidor

Figura 10.6 Rplica e distribuio de mdulos para alta disponibilidade.


O crescimento incremental est relacionado necessidade do sistema de suportar
maiores cargas. Em um sistema centralizado, quando a carga torna-se alta demais
deve-se adquirir novo hardware. Em um sistema distribudo pode-se adicionar novos
computadores ao sistema, e redistribuir os mdulos da aplicao entre estes computadores. Permitinado, assim, que a aplicao tenha maior desempenho e atenda seus
requisitos.

Mdulo A

Servidor

Mdulo B

Mdulo C

Servidor

Figura 10.7 Mdulos de um Sistema Distribudo executando sobre dois


computadores.
As desvantagens dos Sistemas Distribudos compreendem a complexidade no desenvolvimento de aplicaes, sobrecarga no meio de comunicao e segurana.

158

Captulo 10 Novas Tcnicas de Desenvolvimento


Para projetar um sistema distribudo o desenvolvedor precisa de conceitos adicionais
e sempre ter em mente aspectos tais como multithreading, acesso compartilhado a
recursos, comunicao em rede de computadores, acesso simultneo a recursos e
outros conceitos. Isto tona o desenvolvimento de aplicaes distribudas algo complexo para os desenvolvedores mais comuns.
Subdividir uma aplicao em mdulos tambm no uma tarefa simples. Para isto
deve-se ter em mente a necessidade de criar mdulos que tenham pouca comunicao entre si, sobrecarregando o mnimo possvel o meio de comunicao. Considere,
por exemplo, cinco objetos, sendo que trs deles comunicam-se em demasia. Uma
forma de subdividir esta aplicao em mdulos seria criando um mdulo para os trs
objetos com maior comunicao. Os outros objetos podem ser alocados em mdulos
distintos. Cada mdulo pode ser submetido a um computador distinto.

Mdulo A

Servidor

Mdulo B

Servidor

Mdulo C

Servidor

Figura 10.8 Redistribuio dos mdulos da figura 10.7, gerada pela adio de
um novo computador no ambiente.
Caso a aplicao fique muito carregada podemos redistribuir seus mdulos B e C,
conforme a figura 10.9.
Sistema Distribudo

Mdulo A

Servidor

Mdulo B

Mdulo C

Servidor

Figura 10.9 Comunicao entre mdulos de um Sistema Distribudo.


Contudo, se o mdulo A tornar seu computador muito carregado como resolver tal
questo? Pode-se tentar subdivid-lo, mas se a rede ficar muito sobrecarregada com
tal diviso pode ser necessrio comprar um computador de alto desempenho somente para executar este mdulo.

159

J2EE Primeiros Passos


Os sistemas distribudos minimizam em cerca de 95% dos casos que envolvem aquisio de hardware, contudo h problemas que, se resolvidos de forma distribuda,
podem sobrecarregar a rede e gerar queda de desempenho.

Deixando de Confundir um Sistema Operacional de Rede com um Sistema


Distribudo
O principal objetivo de um sistema operacional de rede o compartilhamento de
recursos em uma rede de computadores. Suponha uma rede onde existe apenas uma
impressora. Neste caso mais fcil compartilh-la para todos os usurios do sistema
do que comprar uma impressora para cada computador. Para solucionar este tipo de
problema foram desenvolvidos sistemas operacionais de rede, tais como: Linux e
Windows 95/98/NT/2000.
Em um sistema operacional de rede, os computadores so enxergados pelos usurios como mquinas distintas. Desta forma, para acessar um determinado recurso,
deve-se saber em qual computador ele se localiza. Em um sistema operacional de
rede a comunicao entre computadores realizada atravs de arquivos compartilhados, isto ocorre tanto no acesso a diretrios (ou pastas) compartilhados, quanto
no uso da impressora, que cria uma fila de impresso para recepo de arquivos
compartilhados.
Um sistema distribudo oferece ao usurio a imagem de um nico recurso computacional. O usurio final no sabe se parte de sua aplicao executa nos computadores
A, B e C. Estas partes comunicam-se entre si para sincronizar informaes e, portanto,
executar uma mesma operao computacional.
Suponha uma aplicao que necessita realizar muitos clculos, enquanto outra parte
da aplicao utiliza os resultados destes clculos. Pode-se subdividir esta aplicao
em dois mdulos. Cada um deles executando em um computador diferente. O projetista do sistema conhece estes aspectos do sistema, contudo o usurio final acredita
que o sistema est executando em apenas um computador, pois ele desconhece o
funcionamento do sistema e suas operaes.
A comunicao em um sistema distribudo feita atravs de mensagens que trafegam
sobre a rede. Ao contrrio dos sistemas operacionais de rede que podem trafegar
arquivos completos.
Podemos concluir que executar um sistema operacional tal como Linux ou Windows
em uma rede no ter um sistema distribudo.
Ter um sistema distribudo construir uma aplicao que seja subdividida em mdulos. Cada mdulo executado em um computador distinto. Os mdulos comunicamse para sincronizar operaes que esto sendo executadas.

160

Captulo 10 Novas Tcnicas de Desenvolvimento

10.3 Primeiros Ensaios de Arquiteturas para Sistemas


Distribudos
Corba
CORBA (Common Object Request Broker Architecture) um padro que definido
pela OMG (Object Management Group), organizao que rene cerca de 800 empresas do mundo todo. Este padro foi desenvolvido para a construo de aplicaes
distribudas. Por ser um padro, para aplic-lo, deve-se ter acesso a um suporte ou
ferramenta que o implemente. Diversas empresas e interessados desenvolveram suas
prprias verses seguindo o padro Corba, dentre estas pode-se destacar o Mico,
OmniOrb, Visibroker, Jacorb entre outros.
Segundo o padro Corba, aplicaes para um ambiente distribudo podem estar sendo executadas em diferentes plataformas de hardware e sistemas operacionais. Alm
disto, podem ter sido construdas em diferentes linguagens de programao tais como
C, C++, Java ou Delphi.
Uma das vantagens do padro Corba ser aberto, isto permitiu que vrias empresas
implementassem suas prprias verses, deixando de limitar o desenvolvedor tal como
ocorre com solues proprietrias. E o mais importante, que fossem interoperveis.
Isto de fato o objetivo, contudo fazer duas verses diferentes de Corba interoperarem no to simples quanto parece.
Um desenvolvedor contri sua aplicao sobre uma verso do Corba, e desta forma,
pode distribuir os objetos desta aplicao em uma rede. Assim a aplicao ir funcionar como um sistema distribudo.
Sistema Distribudo

Mdulo A

Servidor

Mdulo B

Servidor

Mdulo C

Servidor

Figura 10.10 Redistribuio dos mdulos da figura 10.9, segundo o nvel de


comunicao entre os mesmos.
A principal limitao de Corba sua complexidade de uso. H muitas exigncias para
os desenvolvedores, que necessitando de produtividade, acabam deixando esta arquitetura.

161

J2EE Primeiros Passos

Java/RMI
Com o desenvolvimento da plataforma Java, a Sun Microsystems observou um novo
horizonte no desenvolvimento de aplicaes em rede de computadores e iniciou o
desenvolvimento de um suporte para objetos distribudos chamado Java/RMI. RMI
significa Remote Method Invocation, ou seja, a invocao de mtodos remotos. Este
suporte simplificou a construo de aplicaes distribudas, contudo funciona apenas para a linguagem Java, ao contrrio de Corba.

Aplicao Distribuda

Middleware CORBA

Servidor

Servidor

Servidor

Figura 10.11 Middleware CORBA oferecendo suporte a uma aplicao


distribuda.
RMI contou com o apoio de diversas empresas, que interessadas na plataforma Java,
desenvolveram uma srie de IDEs (Integrated Development Environments), prontas
para implementar usando a nova tecnologia. Esta fato chamou a ateno de diversos
desenvolvedores para Java.
RMI possibilita as mesmas funcionalidades de Corba e mais simples de se desenvolver aplicaes. O apoio de fabricantes disseminou esta tecnologia e para no limitar
seu crescimento a Sun Microsystems criou um suporte, chamado Java/IDL, para interoperar aplicaes Java com Corba. Este suporte pertmitu que desenvolvedores que
j estivessem utilizando Corba pudessem migrar para Java e continuar o desenvolvimento em RMI.

J2EE
Observando o lado promissor da tecnologia Java/RMI a Sun Microsystems desenvolveu um padro chamado J2EE (Java 2 Enterprise Edition). Com isto, a empresa segmentou a tecnologia Java e comeou cada vez mais a se preocupar com o mercado
de aplicaes distribudas.

162

Captulo 10 Novas Tcnicas de Desenvolvimento


J2EE uma arquitetura que utiliza a mesma pilha de protocolos de Java/RMI o que
permite comunicao com Corba, e alm disto, permite continuidade aos desenvolvedores Java/RMI. Nesta tecnologia uma srie de suportes foram oferecidos. Programar para um ambiente distribudo tornou-se mais simples, pois uma base slida de
componentes haviam sido desenvolvidos para isto.
Diversos fabricantes se interessaram pela arquitetura J2EE, mais ferramentas de desenvolvimento foram lanadas e o mercado aumentou sua aceitao para esta tecnologia. Dentre os principais fabricantes destacam-se a Oracle, IBM, Sun Microsystems,
Bea Systems, etc.

Microsoft .NET
Observando a conquista do mercado pelo J2EE, a Microsoft lanou sua prpria tecnologia para o desenvolvimento de aplicaes distribudas, a .NET. A .NET no um
padro aberto tal como Corba e J2EE, por isto, somente a Microsoft a oferece.

10.4 Mercado Atual para Sistemas Distribudos


O mercado atual tem se voltado cada vez mais para a tecnologia Java, e dentro deste
enfoque a arquitetura para sistemas distribudos a J2EE. Apesar da grande evoluo
desta arquitetura, o projeto de aplicaes distribudas ainda exige conhecimentos
adicionais dos desenvolvedores. Cada vez mais desenvolver torna-se uma tarefa que
exige estudos sobre conceitos e novas tecnologias, ao contrrio de estudar uma linguagem comum.
O mercado tem optado por tecnologias baseadas em padres abertos. Neste ponto
pode-se destacar empresas como a IBM e a Oracle que, nos ltimos anos, se voltaram
muito para este segmento de mercado, suportando sistemas operacionais livres tal
como o Linux, e partindo para a tecnologia Java. Aos poucos as empresas notam que
tecnologias fechadas, tais como o Microsoft .NET, limitam o cliente, pois h a dependncia nica e exclusiva da Microsoft.
No se encontrar neste mercado promissor algo que preocupa muitos projetistas e
desenvolvedores. Portanto, conhecer uma tecnologia como J2EE necessrio e abre
caminhos, no s no cotidiano de escrita de cdigo, mas sim nas tcnicas e escolha
das melhores arquiteturas e opes para desenvolvimento.

163

J2EE Primeiros Passos

164

Captulo 11
J2EE e Enterprise JavaBeans
Este captulo apresenta os principais conceitos da plataforma J2EE (Java 2 Enterprise
Edition), que foi desenvolvida para suportar aplicaes distribudas construdas na
linguagem Java.

11.1 O que J2EE?


J2EE, ou Java 2 Enterprise Edition, uma plataforma para desenvolvimento de aplicaes distribudas. Apresenta facilidades para a utilizao dos recursos computacionais e distribudos tais como acesso banco de dados, componentes Web, utilizao
de mensagens assncronas, execuo de processos transacionais, persistentes ou no
etc.
Apresenta uma API, especificada pela Sun MicroSystems Inc., que proporciona um
padro para a implementao dos diversos servios que oferece, sendo que isto pode
ser feito diferentemente por vrias empresas, de formas distintas mas ainda assim
oferecendo as mesmas facilidades, por estarem de acordo com as especificaes impostas para a sua construo.
Para um programador que j tenha tido contato com a linguagem Java e suas APIs na
J2SE (Java 2 Standart Edition), este no ter muitas dificuldades no entendimento e na
utilizao de J2EE. O que precisa-se entender os detalhes da arquitetura e onde se
encontram cada componente e seus recursos, isto , se faz necessrio se ambientar
neste contexto para se fazer o uso correto da plataforma.

11.2 Viso da plataforma


A arquitetura J2EE se apresenta em camadas, sendo que cada camada composta por
componentes e servios que so providos por um container. A idia de container e
componentes pode ser facilmente entendida por meio do uso de pginas HTML em
um Web Browser em uma simples navegao em um site qualquer.

165

J2EE Primeiros Passos


Podemos entender como container, o prprio navegador que fornece recursos e facilidades para o componente, neste caso as pginas HTML. O componente por sua vez,
pode oferecer diversos servios ao usurio, atravs do suporte do container, tais como
facilidades visuais como botes, hiperlinks, figuras e tabelas, e o prprio servio de
navegao.
Em um servidor J2EE, podemos ter diversos containers interagindo entre si.
Veremos a seguir uma breve explicao de cada camada da arquitetura e de seus
componentes.
Camada cliente: acesso por meio de interfaces stand-alone (aplicaes Java), pginas HTML ou Applets. Nesta camada os componentes residem em um Applet
Container, em um HTML container (Web browser) ou em um Application Client
Container. O Applet container, fornece recursos para um componente Applet executar e se tornar funcional para o usurio. O Web Browser apresenta recursos e
funcionalidades para o uso de pginas HTML e por fim o Application Client container fornece recursos para a execuo das classe stand-alone utilizadas pelos
usurios para interagirem no sistema.
Camada Web: esta camada implementada por JSPs e Servlets, que fornecem a
lgica para a camada cliente ( ou de apresentao ) do negcio. JSPs e Servlets
residem no Web Container. JSPs oferecem a facilidade de utilizar algumas lgicas
de apresentao em uma pgina web sem muitas dificuldades tecnolgicas. O
Servlet apresenta-se como um controlador das aes executadas pelos usurios,
atravs de requisies http, nas pginas de apresentao, e fornece recursos para
obtr dados dessas aes e realizar as operaes desejadas. Os componentes Web
residem no Web Container que pode ser um servidor TomCat ou outro similar.
Camada de Negcios: esta camada trata da lgica de negcio da aplicao. nela
que implementa-se todas as regras de negcio, alocao de recursos, persistncia
de dados, validao de dados, gerencia de transaes e segurana, providos por
componentes conhecidos por Enterprise JavaBeans. Este por sua vez residem no
EJB Container.
Camada EIS - Enterprise Information System: nesta camada que se encontram os
sistemas de banco de dados, sistemas legados, integrao com outros sistemas
no J2EE etc.

166

Captulo 11 J2EE e Enterprise JavaBeans

Cliente

HTML
Container

Pgina
Html

Servidor J2EE

Servlet

JSP

Container Web
App-Client
Container

EIS

Stand
Alone

EJB

Applet
Container

Container EJB
Applet

Figura 11.1 Figura das 3 camadas, seus respectivos componentes e containers


e a interao entre eles.

11.3 Instalando o J2SDKEE


Para obter o kit de desenvolvimento para J2EE, acesse o site da Sun MicroSystems em
J2EE - java.sun.com/j2ee e faa o download do J2SDKEE e de suas documentaes. A
sua instalao segue praticamente o mesmo esquema da verso J2SE. Por fim se faz
necessrio a criao da varivel de ambiente J2EE_HOME. Inclua tambm o diretrio
J2EE_HOME/bin na varivel de ambiente PATH. Para acessar a biblioteca J2EE, aponte o classpath da sua aplicao para o diretrio J2EE_HOME/lib/j2ee.jar. Os pacotes
desta API tem o prefico javax e nele podem ser encontrados todos os recursos disponveis para a especificao J2EE.
Utilizaremos para a execuo dos nossos exemplos, o servidor de aplicaes JBoss
(www.jboss.org), que pode ser inicializado pelo arquivo JBOSS_HOME/bin/run.bat.

11.4 O que so Enterprise JavaBeans?


Enterprise JavaBeans so objetos distribudos que apresentam uma estrutura bem
definida, isto , implementam interfaces especficas e que rodam no lado do servidor.
Tambm so conhecidos como EJBs (Enterprise JavaBeans) e sero tratados dessa
forma neste livro.
So nada mais do que simples objetos que devem seguir algumas regras. Estas regras
foram definidas pela Sun MicroSystems atravs da especificao de EJBs na arquitetura J2EE.

167

J2EE Primeiros Passos


Apresentam mtodos para a lgica de negcio e mtodos que tratam da criao (instanciao), remoo, atualizao do EJB entre outros, dentro do ambiente aonde sobrevive. (Isto ser abordado durante o livro no tema ciclo de vida do EJB).
Conforme definido pela Sun MicroSystems Enterprise JavaBean uma arquitetura
para computao distribuda baseada em componentes ...
Devemos entender que EJBs, no so simples classes Java, mas sim componentes
distribudos que fornecem servios e persistncia de dados, alm de processamento
assncrono e que podem ser invocados remotamente.

11.5 Para que servem e por que utiliz-los?


EJBs so normalmente utilizados para executarem a lgica de negcio do lado do
servidor de forma distribuda. Podemos ter EJBs sobrevivendo em ambientes distintos, em mquinas diferentes, em locais geograficamente diversos e ainda assim utilizando de servios eficientes.
Utilizando EJBs, sua aplicao ir se beneficiar de servios como transaes, segurana, tolerncia a falhas, clustering, distribuio, controle de sesso entre outros.
Estes servios so fornecidos pelo ambiente que o EJB sobrevive, o container EJB.
O container EJB conhece muito bem a interface implementada pelos EJBs e sendo
assim, consegue tratar cada tipo de EJB diferente um do outro e de forma correta.
Veremos mais adiante que o cliente que deseja utilizar um EJB, no acessa-o diretamente, mas sim utiliza-o atravs do container, que encaminha as chamadas de mtodo ao EJB e retorna a chamada ao cliente quando for necessrio.
Vejamos a seguir como isto feito pelo container.

Servidor
Cliente
RMI

Skeleton

Stub
RMI

Objeto

Figura 11.2 Exemplo de servio e troca de objetos utilizando Sockets e


Serializao.
168

Captulo 11 J2EE e Enterprise JavaBeans

11.6 Componentes EJB


Os tipos de Enterprise JavaBeans especificados na verso 2.0:
Session Bean : Stateless e Stateful
Entity Bean : Bean-Managed Persistence e Container-Managed Persistence
Message-Driven Bean
Um EJB Session Bean prov servios, isto , define mtodos de negcio que podem
ser acessados remotamente e que disponibilizam operaes relevantes aplicao.
O tipo Session Bean Stateless no apresenta um estado, como o prprio nome j diz,
e fornece servios para clientes locais e remotos. O EJB Session Bean Stateful, tambm fornece servios localmente ou remotamente, mas apresenta uma relao forte
com um cliente, isto , mantm o estado que um cliente define, assim este cliente
pode configurar e recuperar dados deste EJB.
Os EJBs Entity Beans representam entidades, componentes persistentes. Podem apresentar a manipulao e persistncia do componente de duas formas: BMP ou CMP.
No tipo BMP (Bean-Managed-Persistence), o cdigo de persistncia e manipulao
do objeto deve ser fornecido pelo Bean, isto , deve ser programado. J o tipo CMP
(Container-Bean-Managed) provido pelo prprio container, no tendo a necessidade de escrever linhas de cdigo para estas operaes.
Message-Driven Beans so EJBs que fornecem servios assncronos e podem ser comparados a Session Beans Stateless, que tambm fornecem servios aos clientes locais
e remotos, mas de forma assncrona. Um EJB do tipo Message-Driven Bean se comporta como um listener que aguarda o recebimento de mensagens atravs de um
MOM (Middleware Oriented Message). Neste caso, diferente o EJB Session Bean Stateless, o cliente no precisa aguardar o fim da execuo do mtodo de negcio, por
se tratar de uma chamada assncrona.

11.7 Classes e interfaces


Cada tipo de EJB deve implementar interfaces diferentes e definidas pela API J2EE.
Estas interfaces definem o comportamento que o EJB deve apresentar.
Alm de implementar uma interface definida pela API, devemos criar pelo menos
duas interfaces que sero utilizadas pelos clientes para acessarem os EJBs. Estas interfaces so conhecidas como Local e Remote e devem ser definidas para os EJBs do
tipo Session Bean (Stateless e Stateful) e Entity Bean (BMP e CMP).
Para EJBs do tipo Message-Driven Bean no precisamos definir nenhuma interface e
veremos o porqu disto mais adiante.

169

J2EE Primeiros Passos


No se preocupe com detalhes destas classes e interfaces neste momento, pois logo
adiante detalharemos cada uma delas, nos tipos especficos de EJB.

11.8 Acesso local e/ou remoto


O acesso remoto utilizado quando o EJB e o cliente esto em mquinas diferentes.
Se o cliente e o EJB estiverem na mesma mquina o acesso remoto ser realizado
igualmente. Acessamos um Enterprise JavaBean na mesma mquina ou em outra
mquina da mesma forma (transparncia).
Para criarmos um Enterprise JavaBean com acesso remoto, devemos implementar a
interface Remote e a interface Home. A interface Remote define os mtodos de negcio especficos do EJB e a interface Home define os mtodos do ciclo de vida do EJB.
Para os Entity Beans a interface Home tambm define os mtodos de busca (create e
finders).

java.rmi.Remote

<<Interface>>
javax.ejb.EJBHome
getEJBMetaDat a()
getHomeHandle()
remove()
remove()

Figura 11.3 Diagrama de Classes UML da Interface Home.

java.rmi.Remote

<<Interface>>
javax.ejb.EJBObject
getEJBHome()
getHandle()
getPrimaryKey()
is Ident ical()
remove()

Figura 11.4 Diagrama de Classes UML da Interface Remote.


No acesso local, o cliente e o EJB devem estar na mesma JVM. O acesso ao EJB no
transparente, dessa forma devemos especificar que o acesso local. O acesso local
pode ser usado em vez do remoto para melhora no desempenho do negcio, mas
deve-se fazer isto com cautela, pois um EJB definido como acesso local no pode ser
executado em container em forma de cluster, isto , no pode ser acessado remotamente de forma alguma.

170

Captulo 11 J2EE e Enterprise JavaBeans


Para criarmos um Enterprise JavaBean com acesso local, devemos implementar a
interface Local e a interface LocalHome. A interface Local define os mtodos de negcio especficos do EJB (assim como a interface Remote) e a interface LocalHome define os mtodos do ciclo de vida do EJB (assim como a interface Home). Para os Entity
Beans a interface LocalHome tambm define os mtodos de busca (finders).

<<Interface>>
javax.ejb.EJBLocalHome
remove()
Figura 11.5 - Diagrama de Classes UML da Interface LocalHome

<<Interface>>
javax.ejb.EJBLocalObject
getEJBLocalHome()
getPrimaryKey()
remove()
isIdent ical()
Figura 11.6 - Diagrama de Classes UML da Interface Local
Para um EJB do tipo Message-Driven Bean, no precisamos implementar nenhuma
dessas interfaces porque, este tipo de Enterprise JavaBean apresenta um comportamento diferente de um Session Bean e um Entity Bean, proporcionando processamento assncrono. O que precisamos fazer implementar uma interface de Listener
que ser associado ao MOM.

<<Interface>>
javax.jms.MessageListener
onMessage()
Figura 11.7 Diagrama de Classes UML da Interface Listener.

11.9 EJBObject e EJBHome


Os componentes EJB no so acessados diretamente, isto , no acessamos a instncia do bean diretamente, mas fazemos o acesso aos servios disponveis por eles
atravs de interfaces que so disponibilizadas para acesso remoto ou local.

171

J2EE Primeiros Passos


Apesar de utilizarmos as interfaces de um componente EJB para acessar seu mtodos, vimos que a implementao dos seus servios, isto , o bean, no implementa as
interfaces oferecidas por ele (locais e remotas). Conhecendo a definio de interfaces
e herana devemos nos perguntar:
Por que o bean no implementa as interfaces locais e remotas? E no implementando
estas interfaces, como possvel acessar os mtodos contidos no bean?
Esta pergunta pode ser respondida simplesmente pela explicao de como o container se comporta em relao aos componentes EJB. Cada fabricante de servidores de
aplicao prov a implementao para as interfaces remote e home definidas para o
componente e que so respectivamente as classes EJBObject e EJBHome.
A classe EJBObject implementa a interface remote para os acessos remotos e locais e
encapsula (wrap) a instncia do EJB que foi solicitada pelo cliente. O EJBObject
criado baseado nas informaes contidas nos arquivos de deploy e na classe de bean.
No caso da classe EJBHome, esta se comporta da mesma forma que a classe EJBObject. Ela implementa todos os mtodos da interface home para os acessos remotos e
locais e ajuda o container a gerenciar o ciclo de vida do bean, tais como sua criao,
remoo etc.
Quando um cliente solicita uma instncia de um EJB atravs da interface home pelo
mtodo create(), a classe EJBHome cria uma instncia da classe EJBObject que faz
referncia instncia do EJB solicitado. A instncia do EJB associada com a classe
EJBObject e o mtodo ejbCreate() implementado no bean chamado. Depois que a
instncia criada, a classe EJBHome retorna uma referncia para a interface remota
ou local (o stub) da classe EJBObject para o cliente.
Com a referncia da interface remota ou local, o cliente pode executar os mtodos de
negcio do bean. Estas chamadas so enviadas do stub para a classe EJBObject que
repassa as chamadas para os mtodos corretos na instncia do bean. No caso de
retorno de valores nos mtodos, o mesmo faz o caminho de volta pelo mesmo caminho utilizado na chamada do mtodo, retornando os valores para o cliente.

172

Captulo 11 J2EE e Enterprise JavaBeans

Servidor J2EE
Cliente
EJBHome stub
Home Interface

Container EJB
Home Interface
EJB
Home

EJBObject stub
Remote Interface

Remote Interface
Bean
EJB
Object

Figura 11.8 Figura do cliente acessando o servidor EJB, com as classe EJB
Home e EJB Object (encapsulando o EJB).

11.10 Como construir, executar e acessar os componentes


Construir um EJB pode parecer difcil, mas apesar de ser uma tarefa custoza, no
apresenta uma complexidade muito elevada. Esta demora pode ser diminuda utilizando de ferramentas que propiciam a sua criao de uma forma automatizada.
Primeiro se faz necessrio identificar qual tipo de EJB, ou quais tipos de EJB sero
necessrios para uma determinada aplicao. Definido os EJBs que faro parte da
aplicao, deve-se definir os mtodos de negcio de cada um deles, ou seja, definir o
comportamento de cada um. Aps isso, comeamos o desenvolvimento do EJB.
Com os EJBs definidos, e assim, com seus mtodos de negcio definidos, devemos
criar as interfaces necessrias que sero usadas pelos clientes para o acessarem. No
caso de Session Beans ou Entity Beans, devemos definir a interface Remote (ou Local
caso o acesso seja somente local) com os mtodos de negcio do EJB. Logo aps,
definimos a interface Home (ou LocaHome para acesso local) com os mtodos do
ciclo de vida do EJB, isto , normalmente com os mtodos de criao do EJB e mtodos de busca (utilizados em Entity Beans e conhecidos como finders).
Como j foi dito, para o EJB Message-Driven Bean no precisamos definir as interfaces Home (ou LocalHome) e Remote (ou Local), pois o mesmo se comporta diferentemente dos outros EJBs.
Por fim, devemos criar o EJB propriamente dito, implementando a interface especfica de cada tipo de EJB e codificando cada mtodo de negcio.

173

J2EE Primeiros Passos


Depois de ter construdo os EJBs necessrios para uma aplicao, devemos empacotar os mesmo em um arquivo, ou em arquivos separados.
Para empacotar um Enterprise JavaBeans, devemos utilizar do utilitrio jar, que
fornecido juntamente com o JSDK e que facilita a criao do Java Archive (JAR). Com
uma linha de comando e alguns argumentos, empacotamos os EJBs em arquivos JAR.
Observe que um arquivo JAR pode ser instalado tranqilamente em um servidor de
aplicao, mas h um outro tipo de arquivo, que empacota todos os recursos da aplicao alm dos EJBs, em um mesmo arquivo. Este arquivo conhecido como EAR
(Enterprise Archive) e contempla arquivos JAR, arquivos WAR (Web Archive), arquivos RAR (Resource Adapters Archive), arquivos de configurao, figuras entre outros
recursos.
Aps ter feito isso, podemos instal-los em um servidor de aplicao. Note que o
processo de instalao de um EJB nos servidores de aplicao variam de acordo com
cada fabricante, ento sugerido uma leitura da documentao do servidor de aplicao especfico.
Para acessar um EJB, precisamos criar um cliente que consiga localizar o EJB onde ele
est residindo (servidor de aplicao - container), obtr uma referncia ao EJB remoto ou local e obtr uma instncia para acessarmos os mtodos de negcio do EJB.
Claro que para o EJB do tipo Message-Driven Bean, como apresenta um comportamento diferente e se prope a solucionar um problema diferente, utilizamos seus
servios de forma diferente tambm.
No caso mais comum devemos realizar um lookup, isto , procurar pelo EJB no servidor de aplicao que ele est instalado. Quando criamos um EJB, definimos um nome
para ele JNDI (Java Naming and Directory Interface) - e este nome ser utilizado
pelo cliente para localizar o EJB. Com a referncia do EJB em mos, podemos acesslo pela sua interface Home (ou LocalHome), obtr uma referncia para a interface
Remote (ou Local) e executar os mtodos de negcio desejados.
Lembre-se que o acesso ao EJB pelo cliente realizado atravs das interfaces remotas
ou locais, sendo que o acesso diretamente instncia do EJB propriamente dito de
responsabilidade do container, que opera sobre o Enterprise JavaBean e executa seus
mtodos e retorna valores, atravs das solicitaes dos clientes, por meio das interfaces (stubs e skeletons).

174

Captulo 12
Session Beans
Este captulo apresenta os Session Beans. Estes so componentes, da plataforma J2EE,
responsveis por implementar a lgica das aplicaes. Contudo, eles apresentam
caractersticas e funcionalidades prprias, voltadas para a construo de sistemas de
alta escala.

12.1 O que so Session Beans?


Resumidamente, Session Beans so componentes que executam servios para seus
clientes. Estes servios so fornecidos para o cliente pelas interfaces do EJB Session
Bean e implementadas pelos mtodos de negcio no prprio bean. O estado do objeto Session Bean consiste no valor da instncia de seus atributos, sendo que estes
no so persistidos.
Imagine que uma aplicao necessite realizar alguns clculos e retornar este valor
para o cliente. Isto pode ser implementado por um EJB do tipo Session Bean e disponiblizado em um servidor de aplicaes para todos os clientes. Este um exemplo de
utilizao de um Session Bean.
Mais adiante veremos os cdigos fonte de Session Bean exemplo.
Analisando o diagrama de classes na Figura 12.1 temos uma classe e duas interfaces. A
classe do EJB Session Bean SBExampleBean (EJBSession) e as interfaces SBExample
(Remote) e SBExampleHome (Home). Para cada classe do bean devemos definir as
interfaces (Remote e/ou Local e Home e/ou LocalHome). No exemplo acima, foram
definidas somente as interfaces Remote e Home, mas poderiam ter sido definidas as
interfaces Local e LocalHome ou todas elas (com isto teramos acesso local e remoto
ao mesmo EJB).

175

J2EE Primeiros Passos

H om e

R em ote

SBExampleHome

SBExample
<<instantiate>>

c reat e()

<<EJBRealizeHome>>

<<EJBReali zeRemote>>

<<EJBSess ion>>
SBExam pleBean
EJB_Context : SessionCont ext = null
SBExam pleBean()
ejbCreate()
ejbRem ove()
ejbAct ivate()
ejbPassivate()
setSessionCont ext()

Figura 12.1 Diagrama de Classes UML do Session Bean.


O bean deve implementar todos os mtodos definidos para um EJB Session Bean
conforme as interface javax.ejb.SessionBean que so: ejbCreate(), ejbRemove(), ejbActivate(), ejbPassivate() e setSessionContext(). Tambm devem apresentar os mtodos de negcio com suas devidas implementaes que sero os servios disponibilizados pelo EJB.
Na interface Home do EJB devemos definir o mtodo create(), que ser utilizado pelo
cliente para solicitar ao container que crie uma instncia do bean e fornea uma referncia para acessar os seus servios ou os mtodos de negcio atravs da interface
Remote.

Interface Home : SBExampleHome


package com.novatec.book.example.ejb.session;

import javax.ejb.*;
import java.util.*;
import java.rmi.*;

public interface SBExampleHome extends javax.ejb.EJBHome {


public SBExample create() throws CreateException, RemoteException;
}

176

Captulo 12 Session Beans


Na interface Remote do EJB devemos definir os mtodos de negcio que fornecero
ao cliente os servios disponibilizados pelo bean. Estes mtodos tem a mesma assinatura tanto na interface Remote quanto na prpria implementao do bean.
A seguir veremos como poderia ser definido esta interface, com um exemplo de servio fornecido pelo bean, para calcular o valor de um desconto informando alguns
parmetros.

Interface Remote: SBExample.


package com.novatec.book.example.ejb.session;

import javax.ejb.*;
import java.util.*;
import java.rmi.*;

public interface SBExample extends javax.ejb.EJBObject {


public Integer calcDiscount(Integer value, Integer range) throws
RemoteException;
}

A seguir apresentamos a implementao do bean deste exemplo.

Bean: SBExampleBean.
package com.novatec.book.example.ejb.session;

import javax.ejb.*;

public class SBExampleBean implements SessionBean {

private SessionContext sessionContext;

public void ejbCreate() throws CreateException {


}

public void ejbRemove() {


}

public void ejbActivate() {


}

public void ejbPassivate() {


}

177

J2EE Primeiros Passos

public void setSessionContext(SessionContext sessionContext) {


this.sessionContext = sessionContext;
}

public Integer calcDiscount(Integer value, Integer range) {


// implementao deste mtodo de negcio.
}
}

Para obter este servio, o cliente deve realizar a localizao do EJB no servidor de
aplicao utilizando o seu nome JNDI, solicitar uma referncia para a interface Home
do EJB e com ela executar o mtodo de ciclo de vida: create(). Assim, o cliente ter
acesso interface Remote que apresenta os mtodos de negcio, isto , os servios
disponveis para o EJB e dessa forma, poder execut-los para as operaes desejadas.
Maiores detalhes de localizao e obteno das referncias para as interfaces sero
vistos nos exemplos mais detalhados de EJB e a utilizao de cada servio, alm de
especificar os arquivos de instalao (deployment descriptors).
At aqui introduzimos o EJB Session Bean, mas ainda no detalhamos os dois tipos
de Session Bean que sero vistos nos prximos tpicos e que so:
Session Bean Stateless
Session Bean Stateful

12.2 Quando usar um Session Bean?


Deve-se utilizar um Session Bean quando deseja-se prover servios a seus clientes,
sendo que estes servios sejam transacionais e seguros, rpidos e eficientes. Session
Beans apresentam uma forma de executar a lgica de negcio do lado do servidor.

12.3 Session Bean Stateless


Um Session Bean Stateless no mantm o estado para um cliente em particular. Quando invocamos um mtodo, o estado de suas variveis se mantm apenas durante a
invocao deste mtodo. Quando o mtodo finalizado o estado no retido. So
componentes que no esto associados a um cliente especfico e, portanto, implementam comportamentos que atendem a necessidade de muitos clientes.

178

Captulo 12 Session Beans

Session Bean Stateless: SBStatelessExampleBean.


package com.novatec.book.example.ejb.session;

import javax.ejb.*;

/**
* Exemplo de Session Bean que apresenta os servios aos seus clientes.
* Estes servios so implementados atravs de mtodos de negcio.
* EJB do tipo Session Bean apresentam os mtodos ejbCreate() e ejbRemove(), alm
* dos mtodos ejbActivate() e ejbPassivate() para Session Beans do tipo Stateful.
*/
public class SBStatelessExampleBean implements SessionBean {

/**
* Contexto do Session Bean.
*/
private SessionContext sessionContext;

/**
* Executado pelo container aps a criao da instncia do EJB.
* @throws CreateException exceo na criao de uma entidade do EJB.
*/
public void ejbCreate() throws CreateException {
}

/**
* Utilizado pelo container para destruir a instncia do EJB.
* Para o EJB Session Bean Stateless, deve-se liberar os recursos alocados
* para este EJB neste mtodo.
*/
public void ejbRemove() {
}

/**
* Utilizado pelo container para ativar o objeto do pool de EJBs.
* Neste momento devem ser recuperados todos os recursos utilizados pelo EJB.
* Isto feito somente para Session Bean do tipo Stateful.
* Este mtodo deve ser definido para o EJB Session Bean Stateless tambm,
* apesar de no ser utilizado, pois este tipo de EJB no fica passivo.
*/

179

J2EE Primeiros Passos


public void ejbActivate() {
}

/**
* Utilizado pelo container para devolver o objeto ao pool de EJBs.
* Neste mtodo devem ser liberados todos os recursos alocados pelo EJB.
* Isto feito somente para Session Bean do tipo Stateful.
* Este mtodo deve ser definido para o EJB Session Bean Stateless tambm,
* apesar de no ser utilizado, pois este tipo de EJB no fica passivo.
*/
public void ejbPassivate() {
}

/**
* Configura o contexto do Session Bean.
* @param sessionContext contexto do SB.
*/
public void setSessionContext(SessionContext sessionContext) {
this.sessionContext = sessionContext;
}

// ... abaixo defina os mtodos de negcio, isto , os servios


// que o Session Bean ir fornecer aos seus clientes.

12.4 Ciclo de vida - Session Bean Stateless


A figura 12.2 representa o ciclo de vida de um Session Bean Stateless.

Instncia do EJB
Session Bean
Stateless ainda no
existe

1. Class.newInstance()
2. setSessionContext()
3. ejbCreate()

ejbRemove()

Session Bean
Stateless pronto ou
mantido no pool de
objetos

Execuo dos
mtodos de negcio

Figura 12.2 Ciclo de vida de um Session Bean Stateless.


180

Captulo 12 Session Beans


Assim que o servidor de aplicaes inicializado, no existem beans instanciados,
ento, dependendo das polticas de pooling adotadas, o container instancia o nmero definido de beans. Caso o container decida que precisa de mais instncias no pool,
instancia outros beans. Os beans no pool devem ser equivalentes (porque so Stateless), pois eles podem ser reutilizados por diferentes clientes. Quando o container
decide que no precisa mais de instancias no pool, ele as remove.

12.5 Session Bean Stateful


EJB Session Bean Stateful so componentes que mantm o estado dos seus atributos
e um relacionamento forte com o cliente que o utiliza. Se a execuo termina ou se o
cliente solicita a remoo da instncia deste EJB para o container, a sesso finalizada e o estado perdido, isto , o valor dos atributos configurados pelo cliente para
este EJB so perdidos e em uma prxima utilizao estaro com seus valores nulos.
Este tipo de Session Bean, diferente do Session Bean Stateless, mantm os valores dos
atributos entre vrias chamadas aos seus mtodos de negcio (ou servios), sendo
assim, o cliente pode configurar os valores dos atributos do bean atravs dos mtodos setters e assim o EJB pode utilizar estes valores para os mtodos de negcio.

Session Bean Stateful : SBStatefulExampleBean.


package com.novatec.book.example.ejb.session;

import javax.ejb.*;

* Exemplo de Session Bean que apresenta os servios aos seus clientes.


* Estes servios so implementados atravs de mtodos de negcio.
* EJB do tipo Session Bean apresentam os mtodos ejbCreate() e ejbRemove(),
* alm dos mtodos ejbActivate() e ejbPassivate() para Session Beans
* do tipo Stateful.
public class SBStatefulExampleBean implements SessionBean {

/**
* Contexto do Session Bean.
*/
private SessionContext sessionContext;

* ... defina os atributos que sero mantidos enquanto


* a sesso de um cliente especfico estiver aberta
*/
private String name;

181

J2EE Primeiros Passos


/**
* Executado pelo container aps a criao da instncia do EJB.
* @throws CreateException exceo na criao de uma entidade do EJB.
*/
public void ejbCreate() throws CreateException {
}

/**
* Utilizado pelo container para destruir a instncia do EJB.
*/
public void ejbRemove() {
}

/**
* Utilizado pelo container para ativar o objeto do pool de EJBs.
* Neste momento devem ser recuperados todos os recursos utilizados pelo EJB.
* Isto feito somente para Session Bean do tipo Stateful.
*/
public void ejbActivate() {
}

/**
* Utilizado pelo container para devolver o objeto ao pool de EJBs.
* Neste mtodo devem ser liberados todos os recursos alocados pelo EJB.
* Isto feito somente para Session Bean do tipo Stateful.
*/
public void ejbPassivate() {
}

/**
* Configura o contexto do Session Bean.
* @param sessionContext contexto do SB.
*/
public void setSessionContext(SessionContext sessionContext) {
this.sessionContext = sessionContext;
}

182

Captulo 12 Session Beans


/**
* Configura o valor atributo name.
* @param name valor do atributo a ser configurado.
*/
public void setName(String name){
this.name = name;
}

/**
* Obtm o valor do atributo name.
* @return valor do atributo name.
*/
public String getName(){
return name;
}

// ... abaixo defina os mtodos de negcio, isto , os servios


// que o Session Bean ir fornecer aos seus clientes.
}

12.6 Ciclo de vida - Session Bean Stateful


A figura 12.3 representa o ciclo de vida de um Session Bean Stateful. Temos as transies entre estado ativo e passivo, nos quais o bean deixa de ser utilizado por um
tempo e fica aguardando novas chamadas do cliente quando esta passivo, e ativo
quando volta a ser utilizado pelo cliente. Nestes dois momentos, pode-se liberar os
recursos alocados para determinado bean que se tornar passivo, e obter estes recursos quando o bean se tornar ativo.

Instncia do EJB
Session Bean Stateful
ainda no existe

1. Class.newInstance()
2. setSessionContext()
3. ejbCreate()

ejbRemove()

ejbPassivate()
Execuo dos
mtodos de negcio

Session Bean Stateful


pronto

Session Bean Stateful


Passivo

ejbActivate()

Figura 12.3 Ciclo de vida de um Session Bean Stateful.


183

J2EE Primeiros Passos

184

Captulo 13
Entity Beans
Este captulo apresenta os componentes da plataforma J2EE responsveis por oferecer persistncia aos dados das aplicaes. A persistncia a capacidade de armazenar e recuperar informaes de bancos de dados. Esta torna-se transparente atravs
dos Entity Beans.

13.1 O que so Entity Beans?


Entity Bean so beans de entidade, isto , representam entidades persistentes. Em
outras palavras, so componentes de negcio com mecanismo de persistncia de
dados.
O estado do Entity Bean pode ser persistido em um banco de dados relacional, banco
de dados orientado objetos, arquivo XML alm de outros tipos de repositrios de
dados. Isto quer dizer que o estado do Entity Bean mantido alm do tempo de vida
da aplicao ou do servidor J2EE. Esta uma caracterstica muito til em situaes
onde deseja-se utilizar os dados desta entidade em momentos que seria invivel mantlos em memria.
Existem dois tipos de Entity Beans:
Bean-Managed Persistence.
Container-Managed Persistence.

185

J2EE Primeiros Passos

H ome
Remote

EBExampleHome

EBExample
<<inst antiate>>

create()
findByPrimaryKey()

<<EJBRealizeHome>>
<<EJBRealizeRemote>>

<<EJBEntity>>
EBExampleBean
EJB_Contex t : E nt ityContext
<<EJBPrimaryKey>>
EBExampleBean()
ejbCreate()
ejbPostCreate()
ejbAc tivate()
ejbPassivate()
ejbLoad()
ejbSt ore()
ejbRemove()
setEnt ityContext()
unsetEntityCont ext()

<<EJBPrimaryKey>>
EBExamplePK
hashCode()
equals()
toString()

Figura 13.1 Diagrama de Classes UML do Entity Bean.

13.2 Quando usar um Entity Bean?


Deve-se utilizar o EJB do tipo Entity Bean quando seu estado precisa ser persistido.
Se a instncia do EJB no estiver ativa ou se o servidor de aplicaes for derrubado,
pode-se recuperar o estado do mesmo, pois estar persistido no banco de dados. O
que torna os Entity Beans diferentes dos Sessions Beans que primeiramente o estado do Entity Bean salvo atravs de um mecanismo de persistncia, alm disso possui uma chave primria que o identifica.

13.3 Entity Bean Bean-Managed-Persistence


Utilizando Entity Bean BMP, a codificao das chamadas de acesso ao banco de dados est nas classes de negcio do EJB e so de responsabilidade do desenvolvedor
implement-las. Ento, para os mtodos de busca (mtodos utilizados para localizar
Entity Beans no banco de dados) e para os mtodos de criao, remoo e atualizao dos Entity Beans, deve-se codificar os comandos responsveis por realizar estas
operaes.
O Entity Bean BMP - Bean de Entidade com Persistncia Gerenciada pelo prprio
Bean - oferece ao desenvolvedor a flexibilidade de desenvolver as operaes de persistncia de dados que em alguns casos, podem ser complexas de serem implementadas pelo container.

186

Captulo 13 Entity Beans


Esta estratgia demanda mais tempo de desenvolvimento e s vezes pode no apresentar cdigos to performticos comparados aos implementados pelo prprio
container (CMP). Assim, alguns autores sugerem que se utilize a estratgia de persistncia CMP (Container-Managed-Persistence) sempre que possvel.
Detalhes de implementao de um EJB Entity Bean BMP, assim como os deployment
descriptors sero vistos posteriormente no captulo com exemplos.

Entity Bean BMP: EBBMPExampleBean.


package com.novatec.book.example.ejb.entity;

import javax.ejb.*;

/**
* Exemplo de Entity Bean BMP utilizado para mantr os dados em um meio
* persistente e apresentar as operaes sobre os atributos deste EJB.
* Observe que no Entity Bean BMP, todo o cdigo de criao (persistncia do
* objeto), remoo, atualizao etc. deve ser implementado nestes mtodos,
* ficando a cargo do programador definir a melhor forma de fazer isso.
*/
public class EBBMPExampleBean implements EntityBean {

/**
* Contexto do Entity Bean.
*/
EntityContext entityContext;

/**
* Atributo 1 a ser persistido.
*/
java.lang.String field1;

/**
* Atributo 2 a ser persistido.
*/
java.lang.String field2;

187

J2EE Primeiros Passos


/**
* Cria uma instncia do objeto em memria e persiste seus dados.
* @param field1 campo a ser persistido.
* @param field1 campo a ser persistido.
* @return chave nica que identifica o objeto persistido. pode ser null.
* @throws CreateException exceo na criao do objeto.
*/
public java.lang.String ejbCreate(java.lang.String field1,
java.lang.String field2) throws CreateException {

// deve conter o cdigo de persistncia dos atributos do EJB.


setField1(field1);
setField2(field2);
return null;
}

/**
* Executado pelo container aps a criao do EJB.
* @param untitledField1 campo persistido.
* @throws CreateException exceo na criao do objeto.
*/
public void ejbPostCreate(java.lang.String field1, java.lang.String field2)
throws CreateException {
}

/**
* Executado pelo container para remover o objeto persistido.
* @throws RemoveException
*/
public void ejbRemove() throws RemoveException {
// Deve conter o cdigo de remoo do EJB no meio de persistncia.
}

/**
* Configura o valor do atributo field1.
* @param field1 valor do atributo a ser configurado.
*/
public void setField1(java.lang.String field1) {
this.field1 = field1;
}

188

Captulo 13 Entity Beans


/**
* Configura o valor do atributo field2.
* @param field2 valor do atributo a ser configurado.
*/
public void setField2(java.lang.String field2) {
this.field2 = field2;
}

/**
* Obtm o valor do atributo field1.
* @return valor do atributo field1.
*/
public java.lang.String getField1() {
return field1;
}

/**
* Obtm o valor do atributo field2.
* @return valor do atributo field2.
*/
public java.lang.String getField2() {
return field2;
}

/**
* Implementao do mtodo de seleo do objeto pela sua chave-primria.
* @param field1 chave-primria do EJB.
* @return chave primria do EJB.
* @throws FinderException erro ao localizar o EJB.
*/
public java.lang.String ejbFindByPrimaryKey(java.lang.String field1)
throws FinderException {

// Deve conter a implementao da operao de localizao


// do objeto no meio persistente.
return null;
}

/**
* Utilizado para carregar o objeto persistente do meio de persistncia
* e atualizar os dados de sua instncia.

189

J2EE Primeiros Passos


*/
public void ejbLoad() {
}

/**
* Utilizado pelo container para atualizar os dados do objeto
* no meio de persistncia.
*/
public void ejbStore() {
}

/**
* Utilizado pelo container quando ativa o objeto do pool.
*/
public void ejbActivate() {
}

/**
* Utilizado pelo container quando devolve o objeto ao pool.
*/
public void ejbPassivate() {
}

/**
* Desconfigura o contexto do Entity Bean.
*/
public void unsetEntityContext() {
this.entityContext = null;
}

/**
* Configura o contexto do Entity Bean.
* @param entityContext contexto do Entity Bean.
*/
public void setEntityContext(EntityContext entityContext) {
this.entityContext = entityContext;
}
}

190

Captulo 13 Entity Beans

13.4 Ciclo de vida Entity Bean BMP


A figura 13.2, representa o ciclo de vida dos Entity Beans BMP. Todos os mtodos so
chamados pelo container para o bean. Para criar um novo Entity Bean utilizado o
mtodo create() e para remov-lo necessrio executar o mtodo remove(). Pode-se
carregar um Entity Bean usando os mtodos de busca do Entity Bean (finders). Quando o bean ativado, ele carrega o dado do meio de persistncia e quando desativado, persiste o dado no meio de persistncia.

Instncia do EJB
Entity Bean BMP
ainda no existe

1. Class.newInstance()
2. setEntityContext()

unsetEntityContext()

ejbHome()

1. ejbCreate()
2. ejbPostCreate()

1. ejbPassivate()
2. ejbLoad()

ejbLoad()

ejbFind()

EJB Entity Bean


BMP no pool de
objetos

1. ejbStore()
2. ejbActivate()

EJB Entity Bean


BMP pronto

ejbRemove()

ejbStore()

Executa os mtodos
de negcio ou
ejbFind()

Figura 13.2 Ciclo de vida BMP Entity Bean.

13.5 Entity Bean Container-Managed-Persistence


Entity Beans CMP (Bean de Entidade com Persistncia Gerenciada pelo Container)
oferecem mais rapidez e facilidade no desenvolvimento de objetos persistentes pois
o desenvolvedor no precisa escrever os comandos para persistir e manipular os
dados. O container se encarrega de realizar estas operaes e retornar os valores
desejados. Ele faz isso para as operaes triviais tais como insero do objeto, remoo, atualizao e seleo pela chave- primria (create, remove, store e findByPrimaryKey respectivamente).

191

J2EE Primeiros Passos


Para as operaes especficas de consulta a objetos persistidos, se faz necessrio o
uso de uma linguagem de consulta conhecida como EQL (EJB Query Language). Os
detalhes desta linguagem sero vistos adiante.
Estas operaes devem ser definidas no arquivo de deploy do componente (ejbjar.xml) utilizando-se de EQL para cada operao desejada. Neste arquivo define-se
os campos que sero persistidos e os relacionamentos entre Entity Beans.
Detalhes de implementao de um EJB Entity Bean CMP, assim como os deployment
descriptors sero vistos no captulo com os exemplos.

Entity Bean CMP: EBCMPExampleBean.


package com.novatec.book.example.ejb.entity;

import javax.ejb.*;

/**
* Exemplo de Entity Bean utilizado para mantr os dados em um meio persistente
* e apresentar as operaes sobre os atributos deste EJB.
* No caso do uso de Entity Bean CMP, as operaes de persistncia so
* implementadas pelo prprio container, sendo que o programador no precisa
* se precocupar com estas operaes triviais.
* Para as operaes especficas, como uma consulta com outros parmetros por
* exemplo, esta pode ser definida atravs de EQL no deployment descriptor do
* Entity Bean CMP.
*/
abstract public class EBCMPExampleBean implements EntityBean {

/**
* Contexto do Entity Bean.
*/
private EntityContext entityContext;

/**
* Cria uma instncia do objeto em memria e persiste seus dados.
* @param field1 campo a ser persistido.
* @param field1 campo a ser persistido.
* @return chave nica que identifica o objeto persistido. pode ser null.
* @throws CreateException exceo na criao do objeto.
*/

192

Captulo 13 Entity Beans


public java.lang.String ejbCreate(java.lang.String field1,
java.lang.String field2) throws CreateException {
setField1(field1);
setField2(field2);
return null;
}
/**
* Executado pelo container aps a criao do EJB.
* @param untitledField1 campo persistido.
* @throws CreateException exceo na criao do objeto.
*/
public void ejbPostCreate(java.lang.String field1, java.lang.String field2)
throws CreateException {
}

/**
* Executado pelo container para remover o objeto persistido.
* @throws RemoveException
*/
public void ejbRemove() throws RemoveException {
}

/**
* Configura o valor do atributo field1.
* Observe que na especificao EJB2.0, estes mtodos so implementados
* pelo prprio container.
* @param field1 valor do atributo a ser configurado.
*/
public abstract void setField1(java.lang.String field1);

/**
* Configura o valor do atributo field2.
* Observe que na especificao EJB2.0, estes mtodos so implementados
* pelo prprio container.
* @param field2 valor do atributo a ser configurado.
*/
public abstract void setField2(java.lang.String field2);

/**
* Obtm o valor do atributo field1.
* @return valor do atributo field1.
*/

193

J2EE Primeiros Passos


public abstract java.lang.String getField1();

/**
* Obtm o valor do atributo field2.
* @return valor do atributo field2.
*/
public abstract java.lang.String getField2();

/**
* Utilizado para carregar o objeto persistente do meio de persistncia
* e atualizar os dados de sua instncia.
*/
public void ejbLoad() {
}

/**
* Utilizado pelo container para atualizar os dados do objeto
* no meio de persistncia.
*/
public void ejbStore() {
}

/**
* Utilizado pelo container quando ativa o objeto do pool.
*/
public void ejbActivate() {
}

/**
* Utilizado pelo container quando devolve o objeto ao pool.
*/
public void ejbPassivate() {
}

/**
* Desconfigura o contexto do Entity Bean.
*/
public void unsetEntityContext() {
this.entityContext = null;
}

194

Captulo 13 Entity Beans


/**
* Configura o contexto do Entity Bean.
* @param entityContext contexto do Entity Bean.
*/
public void setEntityContext(EntityContext entityContext) {
this.entityContext = entityContext;
}
}

13.6 Ciclo de vida Entity Bean CMP


A Figura 13.3, representa o ciclo de vida do Entity Bean CMP. Ele praticamente o
mesmo de um Entity Bean BMP, sendo que a nica diferena que pode-se chamar o
mtodo ejbSelect(), tanto nos beans que esto no pool quanto nos que esto ativos.

Instncia do EJB
Entity Bean CMP
ainda no existe

1. Class.newInstance()
2. setEntityContext()

unsetEntityContext()

ejbHome()

1. ejbCreate()
2. ejbPostCreate()

1. ejbPassivate()
2. ejbLoad()

ejbLoad()

ejbFind()
ejbSelect()

EJB Entity Bean


CMP no pool de
objetos

1. ejbStore()
2. ejbActivate()

EJB Entity Bean


CMP pronto

ejbRemove()

ejbStore()

Executa os mtodos
de negcio ou
ejbFind() e ejbSelect()

Figura 13.3 Ciclo de vida CMP Entity Bean.

195

J2EE Primeiros Passos

13.7 Relacionamento EJB Entity Bean CMP


Um Entity Bean pode se relacionar com outro, como um relacionamento entre duas
tabelas de um banco de dados relacional. A implementao de um relacionamento
para Entity Beans BMP feita por meio da codificao na classe de negcio do EJB,
enquanto para os Entity Beans CMP o container se encarrega de oferecer os mecanismos de relacionamento atravs dos elementos de relacionamento definidos no deployment descriptor.
Um relationship field equivalente a uma chave estrangeira em uma tabela de um
banco de dados relacional e identifica um Entity Bean atravs do relacionamento.
Existem quatro tipos de multiplicidades:
1 1: Cada instncia de um Entity Bean pode se relacionar com uma nica instncia de outro Entity Bean. Por exemplo, um Entity Bean marido tem um relacionamento 1 - 1 com o Entity Bean esposa, supondo que esta relao ocorra numa
sociedade onde no permitido a poligamia.
1 N: Uma instncia de um Entity Bean pode se relacionar com mltiplas instncias de outro Entity Bean. O Entity Bean gerente, por exemplo, tem um relacionamento 1 - N com o Entity Bean empregado, ou seja, um gerente pode ter vrios
empregados sob seu comando.
N 1: Mltiplas instncias de um Entity Bean podem se relacionar com apenas
uma instncia de outro Entity Bean. Este caso o contrrio do relacionamento 1
N, ou seja, o Entity Bean empregado tem um relacionamento N 1 com o Entity
Bean gerente.
N M: Instncias de Entity Beans podem se relacionar com mltiplas instncias de
outro Entity Bean. Por exemplo, em um colgio cada disciplina tem vrios estudantes e todo estudante pode estar matriculado em vrias disciplinas, ento o
relacionamento entre os Entity Beans disciplina e estudante N M.
Um relacionamento entre Entity Beans pode ser bidirecional ou unidirecional. Num
relacionamento bidirecional cada Entity Bean tem um campo (relationship field) que
referencia outro Entity Bean. Atravs deste campo um Entity Bean pode acessar o
objeto relacionado. Em um relacionamento unidirecional, apenas um Entity Bean
tem o campo referenciando outro Entity Bean. Consultas em EJB-QL podem navegar
atravs destes relacionamentos. A direo dos relacionamentos determina quando a
consulta pode navegar de um Entity Bean para outro.
Sendo um relacionamento bidirecional as consultas EJB-QL podem navegar nas duas
direes acessando outros Entity Beans atravs dos campos de relacionamento. A tag
cmr-field-name no arquivo ejb-jar.xml define o nome do campo do relacionamento e
na classe abstrata do entity CMP teremos os respectivos mtodos abstratos get e set

196

Captulo 13 Entity Beans


relacionados a este campo. O tipo que um mtodo get retorna o tipo da interface
local do objeto relecionado sendo um relacionamento N - 1, caso o relacionamento
seja N M o tipo retornado pode ser ou java.util.Collection ou java.util.Set.
Sempre que tivermos campos de relacionamento no Entity Bean no devemos invocar o seu mtodo set no ejbCreate, ele deve ser invocado no mtodo ejbPostCreate
ou atravs dos mtodos set e get que estiverem disponveis na interface local. Exemplos:
Relacionamento bidirecinal:
Esposa
marido

Marido
esposa

Figura 13.4 Relacionamento Bidirecional Entity Bean CMP.


Neste caso podemos ver que os dois Entity Beans podem navegar e acessar as informaes sobre o Entity Bean relacionado. Iremos agora mostrar como ficariam as configuraes no deployment descriptor.
<ejb-relation>
<ejb-relation-name>esposa-marido</ejb-relation-name>
<ejb-relationship-role>
<description>esposa</description>
name>

<ejb-relationship-role-name>EsposaRelationshipRole</ejb-relationship-role<multiplicity>One</multiplicity>
<relationship-role-source>
<description>esposa</description>
<ejb-name>Esposa</ejb-name>
</relationship-role-source>
<cmr-field>
<description>marido</description>
<cmr-field-name>marido</cmr-field-name>
</cmr-field>

</ejb-relationship-role>
<ejb-relationship-role>
<description>marido</description>
name>

<ejb-relationship-role-name>MaridoRelationshipRole</ejb-relationship-role<multiplicity>One</multiplicity>
<relationship-role-source>

197

J2EE Primeiros Passos


<description>marido</description>
<ejb-name>Marido</ejb-name>
</relationship-role-source>
<cmr-field>
<description>esposa</description>
<cmr-field-name>esposa</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
</ejb-relation>

A tag cmr-field-name configura o nome do campo do EJB nos quais sero criados os
mtodos get e set que estaro disponveis na interface local, caso configuramos a
multiplicidade 1 1. Se fossemos configurar um relacionamento 1 N por exemplo,
deveramos trocar a tag multiplicity para many e acrescentar a tag cmr-field-type como
o exemlo mostra a seguir:
<cmr-field>
<description>esposa</description>
<cmr-field-name>esposa</cmr-field-name>
<cmr-field-type>java.util.Collection</cmr-field-type>
</cmr-field>

Neste caso voc pode escolher se o tipo retornado ser java.util.Collection ou


java.util.Set.

Esposa

Marido

marido

Figura 13.5 Relacionamento Unidirecional Entity Bean CMP.


Aqui temos um relacionamento unidirecional onde apenas a esposa pode encontrar
o marido, o marido no capaz de recuperar informaes das mulheres por meio do
relacionamento. Neste caso a tag cmr-field no deployment descriptor ejb-jar.xml no
estar configurada no lado em que definimos o relacionamento do lado do EJB marido.
<ejb-relation-name>esposa-marido</ejb-relation-name>
<ejb-relationship-role>
<description>esposa</description>
<ejb-relationship-role-name>EsposaRelationshipRole</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<relationship-role-source>

198

Captulo 13 Entity Beans


<description>esposa</description>
<ejb-name>Esposa</ejb-name>
</relationship-role-source>
<cmr-field>
<description>marido</description>
<cmr-field-name>marido</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<description>marido</description>
<ejb-relationship-role-name>MaridoRelationshipRole</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<relationship-role-source>
<description>marido</description>
<ejb-name>Marido</ejb-name>
</relationship-role-source>
</ejb-relationship-role>
</ejb-relation>

13.8 EJB-QL
EJB-QL EJB Query Language - ou simplesmente EQL a linguagem portvel utilizada para construir os mtodos de consulta dos componentes EJB Entity Bean CMP de
acordo com a especificao 2.x. Esta linguagem no utilizada para os componentes
EJB Entity Bean BMP, pois os mesmos utilizam a API JDBC, ou outro mecanismo de
persistncia para acesso base de dados.

Como e quando utilizar EQL?


Devemos utilizar EQL para implementar os mtodos de busca de seus Entity Beans
CMP que no seja a partir de sua chave-primria (findByPrimaryKey), pois este j
oferecido automaticamente pelo container.

EQL Queries
Um comando EJB-QL contm trs partes:
Uma clusula SELECT
Uma clusula FROM
Uma clusula opcional WHERE

199

J2EE Primeiros Passos

A clusula FROM
A clusula FROM define o domnio de uma consulta. No caso de uma base de dados
relacional, a clusula FROM tipicamente restringe quais tabelas sero consultadas.
Por exemplo:
SELECT OBJECT(o)
FROM X AS o

Aqui estamos declarando uma varivel na clusula FROM. A varivel o pode ser
usada posteriormente em outras clusulas desta mesma consulta. Neste caso estamos
reusando a varivel na clusula SELECT.
Algumas vezes precisamos declarar variveis na clusula FROM que representa um
conjunto de valores:
SELECT OBJECT(a)
FROM X AS o, IN (o.items) a

A frase X AS o declara a varivel o que representa os Entity Beans X , e a frase


IN(o.items) a declara a varivel a que representa uma coleo de items do Entity
Bean X . Ento AS usado quando a varivel declarada representa um nico
valor e IN usado quando a varivel representa uma coleo de valores.

A clusula WHERE
A clusula WHERE restringe o resultado da consulta, escolhe-se os valores desejados
a partir das variveis declaradas na clusula FROM:
SELECT OBJECT(p)
FROM Pessoa p
WHERE p.nome = ?1

Esta consulta recupera todas as pessoas que possuem o atributo nome igual ao parmetro que ser passado no mtodo. Por exemplo, o mtodo poderia ser construdo
da seguinte forma:
findByNome(String nome)

Para utilizar java.util.Collection na clusula WHERE precisa-se declarar primeiramente na clusula FROM:
SELECT OBJECT(a)
FROM Pessoa AS p, IN(p.parentes a)
WHERE a.filho.name = Pedro

Algumas vezes pode-se declarar mais de uma varavel que representa o mesmo Entity
Bean. Quando fazemos comparaes este artifcio muito til:

200

Captulo 13 Entity Beans


SELECT OBJECT(o1)
FROM Pessoa o1, Pessoa o2
WHERE o1.idade > o2.idade AND o2.nome = Joo

A clusula SELECT
A clusula SELECT especifica o resultado retornado pela consulta. Por exemplo:
SELECT OBJECT(p)
FROM Pessoa p, IN(o.parentes) a

Na consulta so definidas duas variveis p e a , a clusula SELECT determina qual


deve ser selecionada.
Neste exemplo a consulta retorna todos os produtos em todas as regras que contm
tens:
SELECT l.produtos FROM REGRA as r, IN(r.items) l

Como pode-se ver, podemos utlizar o ponto para acessar relacionamentos na clusula SELECT. Este cdigo interpretado para um SQL-padro onde um JOIN feito para
recuperar os dados desejados.
Perceba que neste exemplo no utilizamos a notao Object(), ele apenas utilizado
quando se trata de uma varivel simples que no faz uso do ponto para acessar informaes por meio dos relacionamentos entre Entity Beans.
Outra informao importante que a clusula SELECT no trabalha com
java.util.collection, apenas aceita variveis simples, ou seja:
SELECT r.items
FROM Regra AS r

Esta query no est correta, a forma correta :


SELECT Object(a)
FROM Regra AS r, IN(r.items) a

Para filtrar as informaes, ou seja, no recuperar informaes repetidas utlizado o


filtro DISTINCT:
SELECT DISTINCT l.produtos FROM REGRA AS r, IN(r.items)

Voc pode tambm fazer que seu mtodo de busca retorne um java.util.Set que no
permite que valores repetidos sejam inseridos, ao invs do uso de DISTINCT.
A seguir temos um exemplo de como um mtodo definido no arquivo ejb-jar.xml e
pode ser acessado por meio das interfaces Home e/ou LocalHome do EJB. Na interface o mtodo estaria assim:

201

J2EE Primeiros Passos


public java.util.Collection findByNome(String nome) throws FinderException,
RemoteException ;

Este mtodo vai retornar todas as pessoas que tem o nome passado como parmetro.
No arquivo ejb-jar-xml temos:
. . .
<query>
<query-method>
<method-name>findByNome</method-name>
<method-params>
<method-param>java.lang.String</method-param>
</method-params>
</query-method>
<ejb-ql>
<![CDATA[SELECT OBJECT(a) FROM Pessoa AS a WHERE nome = ?1]]>
</ejb-ql>
<query>
. . .

202

Captulo 14
Message-Driven Beans
A comunicao entre objetos , em geral, sncrona. Neste tipo de comunicao um
objeto somente pode enviar mensagens para outro que esteja ativo. Os componentes
Message-Driven permitem que objetos comuniquem-se de forma assncrona, utilizando filas ou tpicos. Estas filas ou tpicos permitem que objetos emissores enviem
informaes sem que os objetos destino estejam ativos.

14.1 O que so Message-Driven Beans?


Message-Driven Bean um tipo de componente EJB que recebe mensagens por meio
de um JMS (Java Message Service) e executam alguma lgica de negcio definida.
Enquanto tradicionalmente os outros beans so acessados atravs de interfaces (RMIIIOP) com acesso sncrono, os Message-Driven Beans, tambm conhecidos como
MDB, so utilizados por meio de mensagens, com acesso assncrono.
Isso ocorre por meio de um middleware orientado a mensagens (MOM Message
Oriented Middleware), localizado entre o cliente, Message Producer, e o bean, Message Consumer. Este middleware recebe mensagens de um ou mais clientes e envia
as mensagens para os beans destino.
JMS a API utilizada para receber as mensagens dos clientes e enviar as mensagens
aos Message-Driven Beans.
O estado do objeto muito simples e semelhante a um EJB Session Bean Stateless
que no mantm o estado para um cliente em particular. Quando enviamos uma
mensagem para invocamos um Message-Driven Bean, o estado de suas variveis se
mantm apenas durante a invocao. Quando o processamento requerido finalizado o estado no retido. So componentes que no esto associados a um cliente
especfico e, portanto, implementam comportamentos que atendem a necessidade
de muitos clientes.

203

J2EE Primeiros Passos

<<EJBMessage>>
MDBExampleBean
EJB_Context : MessageDrivenContext = null
MDBExampleBean()
ejbCreate()
onMessage()
ejbRemove()
setMessageDrivenContext()

Figura 14.1 Diagrama de Classes UML do Message-Driven Bean

Message-Driven Bean : MDBExampleBean.


package com.novatec.book.example.ejb.mdb;

import javax.ejb.*;
import javax.jms.*;
import javax.naming.*;

/**
* Este EJB exemplo do tipo Message-Driven Bean, apresenta os mtodos-padro
* de ciclo de vida ejbCreate() e ejbRemove() e o mtodo onMessage()
* executado no recebimento de uma mensagem.
*/
public class MDBExampleBean implements MessageDrivenBean, MessageListener {

/**
* Contexto do MDB.
*/
private MessageDrivenContext messageDrivenContext;

/**
* Utilizado pelo container para instanciar o EJB.
* @throws CreateException exceo na instanciao do objeto.
*/
public void ejbCreate() throws CreateException {
}

/**
* Utilizado pelo container para remover o EJB.
*/
public void ejbRemove() {
}

204

Captulo 14 Message-Driven Beans

/**
* Executado no recebimento de uma mensagem para este MDB.
* @param msg mensagem recebida atravs do MOM.
*/
public void onMessage(Message msg) {
try {
// imprime a mensagem recebida
System.out.println(Mensagem recebida: + ((TextMessage)
msg).getText());
} catch (JMSException ex) {
ex.printStackTrace();
System.err.println(Erro ao obter o texto da mensagem: + ex);
}
}

/**
* Configura o contexto do MessageDriven Bean.
* @param messageDrivenContext contexto do MDB.
*/
public void setMessageDrivenContext(MessageDrivenContext messageDrivenContext) {
this.messageDrivenContext = messageDrivenContext;
}
}

14.2 Quando usar um Message-Driven Bean?


Deve-se utilizar EJB Message-Driven Bean quando necessita-se de operaes assncronas sendo executadas no lado do servidor (container EJB).
Observe que para realizarmos um processamento em paralelo no servidor sem o uso
de Message-Driven Bean, era necessrio o uso de Threads em EJB Session Bean Stateless. Esta prtica desaconselhada pela prpria Sun MicroSystems Inc., pois recai
em vrios problemas, um deles a falta de controle dessas execues por parte do
container, perdendo assim as facilidades e ganhos que o container oferece.
Para sanar este problema, foi criado o EJB Message-Drive Bean que pode ter vrias
instncias de um mesmo componente sendo executados em paralelo, para realizar a
mesma operao.

205

J2EE Primeiros Passos

14.3 Ciclo de vida - Message-Driven Bean


A Figura 14.2, representa o ciclo de vida do Message-Driven Bean. Ele bem simples
comparado aos outros beans, pois o container instancia um determinado nmero de
beans e os mantm no pool de acordo com as necessidades e removidas quando o
container decidir, da mesma forma que o Session Bean Stateless. Assim que uma mensagem recebida pelo JMS, ela redirecionada para um bean especfico, para que
seja tratada.

Instncia do EJB
Message-Driven Bean
ainda no existe

1. Class.newInstance()
2. setMessageDrivenContext()
3. ejbCreate()

ejbRemove()

Message-Driven Bean
no pool de objetos

onMessage()

Figura 14.2 Ciclo de vida Message-Driven Bean.

14.4 O que e para que serve o JMS?


Antes de falarmos a respeito de JMS, devemos enteder o conceito de Messaging (envio de mensagens). Messaging pode ser entendido pela troca de mensagens entre
duas aplicaes, programas ou componentes. Um cliente pode enviar mensagens
para um ou mais receptores, que tambm pode retornar um outra mensagem, ou
executar algum mtodo de negcio. Utilizando este recurso, o receptor de mensagens no precisa estar disponvel no mesmo momento que o cliente enviou a mensagem, podendo consum-la, ou receb-la posteriormente, isto , no momento em que
seu servio estiver ativo. Assim, o cliente que envia a mensagem e o receptor da mensagem devem somente conhecer bem o formato da mensagem, com os dados que ela
carrega.
Para fazer uso destes recursos na linguagem Java, foi criada uma API conhecida como
JMS Java Messaging Service. Esta API fornece servios que permitem a criao, envio, recebimento e leitura de mensagens.

206

Captulo 14 Message-Driven Beans


O importante a saber que um cliente cria uma mensagem e a envia utilizando esta
API. Um receptor de mensagens, receber esta mensagem atravs de um MessageOriented-Middleware ou MOM. Alguns conceitos muitos usados nas referncias a
JMS so produtores e consumidores de mensagem (producers / consumers), para
designar um cliente como um produtor de mensagens e um componente EJB Message-Driven Bean por exemplo, como um consumidor de mensagens.
O caminho percorrido pela mensagem bem simples. Vamos ver isso na figura abaixo, na qual o produtor envia a mensagem, que recepcionada pelo MOM e a seguir
redirecionada para o consumidor correto. Observe na figura, que o produtor tambm
pode ser um consumidor de mensagens e que o consumidor de mensagens tambm
pode ser um produtor.

P1

MOM

P2

Figura 14.3 MOM.


A arquitetura JMS composta por cinco partes que so: Provedor JMS, que implementa as interfaces definidas na API JMS e prov recursos para administrar esse servio; os clientes JMS que podem ser programas ou componentes que agem como produtores e consumidores de mensagens; as mensagens propriamente ditas que so
objetos que transportam os dados do cliente para o receptor; os objetos de administrao do servio JMS que so utilizados pelos clientes para enviar as mensagens; e os
clientes nativos que so clientes que usam produtos de Messaging nativos e no da
API JMS.
A seguir vamos detalhar os dois tipos de postagem de mensagens e entender as diferenas entre eles.
Point-to-Point
Publish/Subscribe.

Mensagens Point-To-Point (Queue)


O conceito de mensagens Point-To-Point PTP de enfileirar as mensagens para
serem consumidas. Os produtores enviam as mensagens para uma determinada fila
(Queue), que so consumidas por um destinatrio. Assim que receber a mensagem, o
destinatrio avisa ao MOM que a mensagem foi recebida e processada corretamente
(sinal de acknowledge). A fila armazena todas as mensagens que so enviadas, at o
momento que so consumidas pelos receptores, ou at o momento que forem expiradas.

207

J2EE Primeiros Passos


Observe ainda, que vrios consumidores de mensagens (muitas instncias do mesmo
consumidor) podem consumir mensagens do MOM. Este recurso normalmente disponibilizado e gerenciado pelo servidor de aplicaes para processamento de mensagens em paralelo.
O cliente pode enviar mensagens para o MOM, mesmo sem existir nenhum consumidor de mensagens ativo naquele momento.

Producer

QUEUE

Consumer

MOM

Figura 14.4 Point-To-Point (Queue).

Mensagens Publish/Subscribe (Topic)


No uso de publish/subscribe Publica/Inscreve os clientes enviam a mensagem
para um tpico (topic). Os consumidores registram-se nos tpicos que lhes so convenientes e so notificados da chegada de uma nova mensagem.
Os consumidores podem somente consumir mensagens que foro postadas depois
de terem se registrado (inscrito) no MOM, isto , as mensagens enviadas pelos clientes antes disto, no podem ser consumidas por eles. Observe que neste caso, cada
mensagem pode ter mais de um tipo de consumidor.
Se algum cliente emviar uma mensagem para um tpico que no possue nenhum
consumidor registrado, esta mensagem no ser entregue. Aps o consumidor se
registrar, as mensagens que chegam ao MOM so notificadas aos consumidores, que
fornece estas mensagens a eles.
Por haver uma dependncia muito grande do tempo em que o consumidor deve
estar ativo enquanto o cliente envia a mensagem, os consumidores podem fazer registros durveis (DURABLE) e receber mensagens enviadas enquanto eles no estam
ativos. Isto permite a facilidade de uma fila, com a diferena de consumo de mensagens por diversos tipos de consumidores.

208

Captulo 14 Message-Driven Beans

Consumer 1

Producer

TOPIC

Consumer 2

MOM
Consumer 3

Figura 14.5 Publish/Subscribe (Topic).


A seguir apresentamos um exemplo simples do envio de mensagens por um cliente
TextClient e o recebimento das mensagens por um Message-Driven Bean TestMDB.

Teste de envio de mensagens: TestClient


import javax.jms.*;
import javax.naming.*;

/**
* Esta classe exemplo, envia mensagens para um fila (queue)
* para ser consumida por um MDB.
*/
public class TestClient {

public static void main(String[] args) {


QueueConnection queueConnection = null;
try {
// cria o contexto
Context ctx = new InitialContext();

// localiza a connection factory


QueueConnectionFactory queueConnectionFactory =
(QueueConnectionFactory) ctx.lookup(java:comp/env/jms/
MyQueueConnectionFactory);

// localiza a queue (fila)


Queue queue = (Queue) ctx.lookup(java:comp/env/jms/QueueName);

// cria a conexo
queueConnection =

queueConnectionFactory.createQueueConnection();

209

J2EE Primeiros Passos


// cria a sesso da conexo
QueueSession queueSession = queueConnection.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);

// cria o sender
QueueSender queueSender = queueSession.createSender(queue);

// cria a mensagem e as envia


TextMessage message = queueSession.createTextMessage();
for (int i = 0; i < 3; i++) {
message.setText(Mensagem nr: + (i+1));
System.out.println(message.getText());
queueSender.send(message);
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
} finally {
// fecha a conexo
if (queueConnection != null) {
try {
queueConnection.close();
} catch (JMSException e) {}
}
System.exit(0);
}
}
}

Message-Driven Bean : TestMDB


import javax.ejb.*;
import javax.naming.*;
import javax.jms.*;

/**
* Teste de recebimento de mensagens pelo MDB.
* Recebe uma mensagem do tipo <code>TextMessage</code> e a imprime no console.
*/
public class TestMDB implements MessageDrivenBean, MessageListener {

/**

210

* Contexto do Message-Drive Bean.


*/
private transient MessageDrivenContext ctx = null;

/**
* Instncia o objeto no servidor pelo container.
*/
public void ejbCreate() {
}
/**
* Remove a instncia do objeto no servidor.
*/
public void ejbRemove() {
}
/**
* Configura o contexto do EJB MDB.
* @param ctx contexto do MDB.
*/
public void setMessageDrivenContext(MessageDrivenContext ctx) {
this.ctx = ctx;
}

/**
* Valida a mensagem recebida e a imprime no console.
* @param message mensagem a ser notificada.
*/
public void onMessage(Message message) {
try {
if (message instanceof TextMessage) {
System.out.println(Mensagem recebida pelo MDB =
+ ((TextMessage) message).getText());
}
else {
System.err.println(Mensagem com tipo errado :
+ message.getClass().getName());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

211

J2EE Primeiros Passos

Captulo 15
Transaes e Segurana
A proposta inicial da API desenvolvida para a plataforma Java a de prover aos desenvolvedores os recursos bsicos de infra-estrutura e permitir que eles pudessem se
concentrar na implementao das regras de negcio de suas aplicaes. Assim, foram
disponibilizadas bibliotecas para trabalhar com colees, com entrada e sada de dados, com recursos de internacionalizao, entre outras.
Esta idia foi utilizada novamente na especificao da plataforma J2EE, com o objetivo de prover implementaes para problemas recorrentes de aplicaes distribudas, agilizando seus tempos de desenvolvimento e permitindo que o foco do desenvolvimento fique nas regras de negcio a serem atendidas, deixando os recursos de
infra-estrutura complexos a cargo dos fabricantes dos containers. Desta forma, h um
aumento significativo nas chances das necessidades dos clientes serem atendidas e,
por consequncia, os sistemas construdos serem bem sucedidos.
Entre a gama de servios previstos na especificao da plataforma J2EE ligados aos
Enterprise JavaBeans, sero abordados dois dos mais usados: transaes e segurana.
O primeiro servio serve para garantir a integridade dos dados, permitindo que falhas
e execues concorrentes no tornem as informaes gerenciadas pela aplicao
inconsistentes. O segundo servio trata da proteo da aplicao com relao ao acesso
no autorizado s funcionalidades disponibilizadas por ela. Ambos so apresentados
neste captulo.

15.1 Transaes
Tipicamente os sistemas provm funcionalidades para seus clientes baseados em uma
massa de dados armazenados em um meio peristente. A integridade das informaes
armazenadas neste repositrio fundamental para o correto funcinamento do sistema e muitas vezes a perda de informaes pode causar prejuzos para seus usurios.
Os problemas relacionados a manuteno da integridade das informaes armazenadas em um meio persistente podem ser causados por fatores fsicos ou lgicos.

212

Dentre os fatores fsicos podemos destacar a falta de energia eltrica durante o processamento de uma funcionalidade que envolva vrias operaes sobre os dados. J
fatores lgicos esto relacionados com erros na programao do acesso concorrente
aos dados, onde alteraes realizadas por um processo podem ser sobrepostas por
outros processos executando de forma concorrente.
Estes problemas so significativamente agravados quando estamos desenvolvendo
em um ambiente distribudo. Uma vez que partes de nossas aplicaes podem ser
executadas em mquinas diferentes, h a chance de uma delas quebrar sem que o
restante da aplicao tenha conhecimento disto, fazendo com que uma operao
realizada pela aplicao seja executada parcialmente, o que pode corromper os dados sendo manipulados. Tambm h a chance de uma infomao ser alterada por
uma parte da aplicao sem que a outra seja notificada, o que tambm ocasiona resultados errneos.
Como soluo a estes problemas, foi desenvolvido o conceito de transaes. Para
tanto feito um agrupamento das operaes realizadas em uma determinada poro
do software em uma unidade denominada transao, que apresenta quatro propriedades fundamentais, chamadas de ACID:
Atomicidade garante a completude da execuo das operaes de uma transao, ou seja, ou todas as operaes de uma transao so executadas ou nenhuma
operao realizada. Caso no seja possvel completar uma operao aps outras
terem sido executadas, deve ser possvel anular o efeito destas ltimas para atender a esta propriedade.
Consistncia garante que o conjunto de operaes que compem uma transao nunca deixem o sistema em um estado inconsistente.
Isolamento garante que a execuo de uma transao no seja afetada pela execuo de outra transao. Esta propriedade especialmente importante quando
h aplicaes concorrentes que acessam os mesmos dados, uma vez que durante
a execuo de uma transao os dados podem ficar temporariamente inconsistentes, levando outras transaes que utilizam estes dados a produzirem resultados incorretos e possivelmente violarem a propriedade de consistncia.
Durabilidade garante que os resultados obtidos em uma transao sejam armazenados em um meio persistente.
Para ilustrar estas propriedades, vamos utilizar como exemplo uma transao bancria de transferncia de fundos de uma conta corrente para outra. Suponha a existncia da seguinte classe responsvel por realizar a transferncia:

213

J2EE Primeiros Passos

Classe usada para demonstar propriedades transacionais.


public class Banco

// ...
public void transferenciaEntreCC(ContaCorrente origem, ContaCorrente destino,
double montante) {
// verifica se h saldo suficiente na conta a ser debitada
if (origem.getSaldo() < montante)
throw

new SaldoInsuficienteException(A conta + origem + deve ter


saldo igual ou superior a + montante);

origem.debitar(montante);
destino.creditar(montante);
}
// ...
}

A necessidade da primeira propriedade pode ser logo vista nas duas ltimas operaes do mtodo de transferncia entre contas correntes. Caso logo aps a primeira
operao ser processada ocorra uma queda do sistema, por falta de energia eltrica,
por exemplo, o montante ser reduzido da primeira conta mas no ser creditado na
segunda. Isto significa que o montante iria simplesmente desaparecer, tornando a
base de dados do sistema bancrio inconsistente.
A segunda propriedade diz respeito demarcao dos limites da transao. Ela garante que uma transao conter um mtodo de negcio completo. Assim, no caso
do mtodo de transferncia entre contas correntes, no seria possvel incluir a operao de dbito em uma transao e a de crdito em outra, pois neste caso ao final da
primeira transao o sistema estaria inconsistente.
O isolamento diz respeito a tornar a execuo em paralelo de transaes independentes. Como a consistncia s garantida no trmino de uma transao, possvel
que durante sua execuo o sistema esteja num estado inconsistente (no exemplo
esta situao seria atingida no momento aps a operao de dbito e antes da operao de crdito). Assim, caso uma outra transao seja iniciada enquanto uma primeira
ainda no terminou, possvel que seus resultados no sejam corretos, uma vez que
a premissa da consistncia que o sistema estaria inicialmente consistente.
A ltima propriedade trata da confirmao dos resultados efetuados pelas transaes.
Neste caso, aps a confirmao das operaes, seus resultados so efetivamente armazenados em meios persistentes. Assim, garantido que em caso de falhas no sistema aps o encerramento da transao, seus resultados ainda podero ser vistos aps
o restabelecimento do sistema.

214

Captulo 15 Transaes e Segurana

Delimitao das Transaes


O uso de transaes traz muitas vantagens e garante a integridade dos dados, mas h
um custo alto em utiliz-las. Os controles que so utilizados para garantir as propriedades ACID podem tornar uma aplicao lenta de tal forma que se torne sua utilizao invivel. Assim, este recurso deve ser usado de forma consciente, ficando a cargo
dos desenvolvedores determinar as operaes de negcio que necessitam de transaes e as que no. Ele tambm deve determinar a melhor forma de agrupar as operaes em transaes.
Na especificao J2EE h duas formas do desenvolvedor informar aos containers EJB
quais so as operaes transacionais e como elas devem se comportar com relao s
outras: uma forma programtica e outra declarativa. A primeira forma consiste na incluso de instrues, no cdigo fonte dos EJBs, para que as transaes sejam iniciadas e terminadas. Uma vez que o controle todo de quando as transaes iniciam e so
concludas faz parte da especificao do bean, este tipo de delimitao chamada de
BMT (Bean Managed Transaction).
A forma declarativa de determinar os limites das transaes feita atravs de instrues nos arquivos descritores dos EJBs. Desta forma, o prprio container fica a par da
existncia das transaes no momento do deploy e capaz de controlar sua execuo. Este tipo de transao chamado de CMT (Container Managed Transaction) e
permite um elevado grau de flexibilidade para mudanas na poltica de controle de
transaes da aplicao. Os dois tipos de transaes sero discutidos com detalhes
nas prximas sees.

Transaes BMT
Transaes BMT (Bean Managed Transactions) ou programadas permitem maior controle por parte do desenvolvedor, pois ele que insere em seu cdigo instrues que
indicam o momento em que a transao foi iniciada, o momento em que ela foi concluda com sucesso ou que ocorreu um erro e a transao deve ser abortada.
As instrues para o controle das transaes so disponibilizadas numa API chamada
JTA (Java Transaction API). Ela permite o acesso transparente aos mais variados gerenciadores de transaes disponveis nos containers. A implementao da Sun para
tal API o JTS (Java Transaction Service).
A comunicao com um gerenciador de transaes se inicia com a obteno de uma
referncia para a interface javax.transaction.UserTransaction, que feita atravs do
contexto do EJB. Esta interface permite enviar comandos para delimitar o incio de
uma transao (begin), concluso com sucesso (commit) ou solicitar que as operaes realizadas sejam descartadas pela ocorrncia de falhas (rollback). Abaixo um
exemplo de uso de uma transao gerenciada pelo bean em um mtodo que realiza a
transferncia de um montante de uma conta corrente para outra.

215

J2EE Primeiros Passos

Exemplo do uso de JTA


public void transferenciaEntreContasCorrentes(ContaCorrente origem,
ContaCorrente destino, double montante) {
javax.transaction.UserTransaction ut = sessionContext.getUserTransaction();
try {
ut.begin();
origem.debitar(montante);
destino.creditar(montante);
ut.commit();
} catch (Exception ex) {
try {
ut.rollback();
} catch (Exception rbex) {
rbex.printStackTrace();
}
throw new RuntimeException(ex);
}
}

Este tipo de transaes pode ser utilizado apenas Session Beans e Message Driven
Beans. Os Entity Beans exigem um maior controle do container sobre suas aes e
portanto no tem disponvel o gerenciamento de transaes feito por ele prprio.

Transaes CMT
Transaes CMT (Container Managed Transactions) ou declarativas podem ser utilizadas com qualquer tipo de EJB. Neste tipo de transao no h a necessidade de
programao explcita das delimitaes das transaes, esta tarefa efetuada automaticamente pelo prprio container. Para tanto, necessrio informar nos descritores dos EJBs a necessidade de suporte transacional s operaes e como ele deve
gerenci-lo.
Uma vez que no h a necessidade de incluso de cgido especfico para gerncia de
transaes, a flexibilidade de mudana da estratgia de emprego deste recurso muito
maior, pois basta alterar os descritores dos EJBs para atingir este objetivo.
Abaixo est um exemplo de descritor que define a incluso de suporte transacional
num EJB pra gerenciamento de contas bancrias:

Exemplo de descritor - ejb-jar.xml:


.....

216

Captulo 15 Transaes e Segurana


<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>Banco</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>Banco</ejb-name>
<method-name>transferenciaEntreCC</method-name>
</method>
<trans-attribute>Mandatory</trans-attribute>
</container-transaction>
</assembly-descriptor>
.....

O suporte a transaes definido dentro do assembly-descriptor. Nele so definidos,


para cada mtodo do EJB, qual o seu atributo transacional. Observando o exemplo,
verifica-se que para o EJB chamado Banco so definidas dois blocos de transaes.
No primeiro definido o atributo Required para todos os seus mtodos atravs do
uso do wildcard *. Logo em seguida este atributo sobreposto para o mtodo transferenciaEntreCC, modificando o atributo para Mandatory.
O atributo transacional, citado acima, usado para dizer ao container como as transaes devem ser efetuadas quando os mtodos especificados so chamados. Deve-se
levar em conta que o cliente do EJB, que pode uma aplicao Swing, um Servlet ou
mesmo outro EJB, tambm pode estar usando transaes para efetuar suas tarefas e a
chamada a um mtodo do EJB deve levar isto em conta. Tendo isto em mente, a
seguir sero mostrados os possveis atributos transacionais definidos na especificao EJB 2.0 e o comportamento do container para cada um deles.
Required (Requerido) Configura o bean (ou mtodo) para sempre executar em
uma transao. Se a chamada for feita dentro de uma transao no cliente, a chamada de mtodo passar a fazer parte desta transao. Caso contrrio, uma nova
transao criada.
RequiresNew (Requer novo) Utilizada para que o mtodo do EJB sempre execute dentro de uma transao nova. Assim, o mtodo executar dentro de uma transao prpria que ser encerrada quando o mtodo termina sua execuo. Caso
o mtodo seja chamado dentro de uma transao do cliente, esta suspensa,
criada uma nova transao para o EJB, executada e finalizada, e s ento a transao do Cliente retomada.

217

J2EE Primeiros Passos


Mandatory (Mandatrio) Indica que o mtodo somente pode ser chamado dentro de uma transao do cliente. Diferente do Required, que caso o cliente no
esteja numa transao cria uma nova, este atributo gera uma exceo se sua chamada no for dentro de uma transao.
NotSupported (No Suportado) Usado para indicar que o mtodo no ir executar dentro de uma transao. o complementar do Required, ou seja, caso o
cliente esteja ou no dentro de uma transao o mtodo ser executado sempre
fora de uma transao.
Supports (Suportado) Nesta modalidade, o mtodo do EJB ser executado em
uma transao caso o cliente esteja em uma transao. Caso contrrio, o EJB ser
executado sem nenhuma transao. Este o caso menos recomendvel para uso
de transaes, uma vez que os resultados da execuo so inesperados, devido
dependncia do suporte transacional do cliente.
Never (Nunca) Utiliza-se este atributo quando o EJB (ou mtodo) no pode ser
chamado por um cliente que esteja dentro de uma transao. Caso isto ocorra
lanada uma exceo. Normalmente usado quando o mtodo acessa algum recurso que no transacional e portanto no capaz de prover as garantias definidas para as transaes.
A seguir apresentamos uma tabela que demonstra os efeitos do uso de cada atributo
de transao. No exemplo, temos um cliente e um EJB, os quais apresentam transao ou no. Temos duas transaes, a transao 1 - T1 - e a transao 2 - T2. Observe
os efeitos de cada atributo de transao, quando o cliente define e no define uma
transao.

Tabela 15.1 Resumo do comportamento dos atributos transacionais.

Atributo Transacional
Required
Requires New
Mandatory
NotSupported
Supports
Never

218

Transao do Cliente
Nenhuma
T1
Nenhuma
T1
Nenhuma
T1
Nenhuma
T1
Nenhuma
T1
Nenhuma
T1

Transao do Bean
T2
T1
T2
T2
Exceo
T1
Nenhuma
Nenhuma
Nenhuma
T1
Nenhuma
Exceo

Captulo 15 Transaes e Segurana

15.2 Segurana
Em uma aplicao J2EE, h duas formas que os clientes devem ser avaliados no acesso ao sistema e aos componentes que ele utiliza. Para um cliente acessar um sistema,
inicialmente ele dever estar autenticado no mesmo. Autenticar um cliente significa
que o sistema deve verificar se o cliente quem ele diz que . Para isso o mesmo
dever fornecer algumas informaes como usurio e senha, ou algum cdigo de
acesso ou algo parecido. O sistema autenticar o usurio e sendo assim, associar o
mesmo a uma identidade de segurana pr estabelecida, tal como um perfil de administrador, coordenador ou atendente por exemplo.
Assim que o usurio autenticado e acessa o sistema, este ltimo dever apresentar
formas de autorizar o usurio a acessar operaes do sistema vlidas para o seu perfil
de usurio. Por exemplo, se o perfil do usurio de atendente, o mesmo no poderia
acessar a operao de relatrios gerenciais.
A autenticao feita antes de realizar as operaes nos EJBs e veremos mais adiante
as formas que podem ser utilizadas para tal. J a autorizao realizada durante a
chamada de mtodos dos EJBs, que permitem ou negam o acesso de determinado
perfil de usurio.
Veremos a seguir uma breve explicao da API JAAS e como utiliz-la

JAAS
JAAS (Java Authenticated and Autorizated Service) apresenta interfaces que possibilitam que usurio sejam autenticados e autorizados em aplicaes J2EE. Com isso, permite que o usurio acesse o sistema e as operaes dele, no importando como
implementado pelo fabricante do servidor J2EE. E assim, o servidor J2EE se encarrega de localizar os dados dos usurios que esto aptos a acessar o sistema, o perfil de
cada um, possibilitando os mesmos de acessarem operaes especficas oferecidas
pela aplicao em questo.
Um usurio poder acessar um sistema e estar autenticado para o mesmo, sendo ele
uma aplicao Web ou uma aplicao standalone. Isso dever ser transparente para o
usurio, sendo que a aplicao J2EE poderia prover as duas interfaces para o usurio
com as mesmas funcionalidades.

Autenticao
Em verses mais antigas da especificao EJB no havia uma API que definia os servios necessrios para operaes de segurana. Com a criao da API JAAS isto foi
possvel e autenticar um usurio ficou mais simples e portvel.

219

J2EE Primeiros Passos


Como foi dito anteriormente, um usurio poder acessar um sistema por uma interface Web ou standalone, sendo que a aplicao dever prover os mesmos recursos
para o usurio. Em interfaces standalone, a autenticao parece ser mais simplista,
tendo a aplicao que utilizar a API JAAS para autenticar o usurio, a partir das informaes fornecidas pelo mesmo.
Em interfaces Web isto tambm necessrio, sendo que o usurio tambm dever
fornecer informaes como usurio e senha para o servidor Web que ir verificar a
autenticidade da informao. Para fazer isso, o navegador poder apresentar quatro
formas de realizar uma autenticao que so: Basic Authentication (Autenticao Bsica), Form-Based Authentication (Autenticao baseada em Formulrios), Digest
Authentication (Autenticao com Mensagem Alterada) e Certificate Authentication
(Autenticao com Certificado Digital).
Iremos a seguir detalhar cada uma delas.
Basic Authentication o navegador apresenta uma tela de login e fornece ao servidor o usurio e senha para a autenticao. Esta tela depende do navegador que
est sendo utilizado.
Form-Based Authentication a aplicao fornece uma pgina HTML (que poder
ser gerada por um JSP, por exemplo) com um formulrio no qual o cliente informaria o usurio e senha. Para isso, h um padro utilizado pela API JAAS.
...
<form method=post action=j_security_check>
Usurio:<input type=text name=j_username>
Senha:

<input type=password name=j_password>

</form>
...

Digest Authentication para este tipo de autenticao usado um algoritmo para


converter o usurio e senha em um texto ilegvel leitura, dificultando que usurios mal intencionados descubram estas informaes. Esta informao passada
ao servidor que utilizando do mesmo algoritmo, autentica o cliente em questo.
Certificate Authentication o servidor recebe do cliente um certificado digital
pelo qual ser autenticado.
Assim que o cliente autenticado pela aplicao, o mesmo estar associado a uma
identidade ou perfil, que ser propagado por toda a aplicao e utilizado pelo servidor para a execuo dos mtodos dos EJBs, isto , o seu perfil ser utilizado na sua
autorizao.

220

Captulo 15 Transaes e Segurana

Autorizao
Estando o cliente autenticado, ele dever ser autorizado a realizar certas operaes
fornecidas pelo sistema, de acordo com o seu perfil de usurio. Para isso, a aplicao
deve estar configurada com security policies ou regras de segurana para cada servio fornecido por seus componentes, isto , para cada mtodo de cada EJB.
A autorizao pode ser apresentada de duas formas: Autorizao Programtica ou
Declarativa. Na Autorizao Programtica o programador deve implementar a verificao de segurana no EJB, isto , deve verificar qual usurio est acessando o servio e validar o mesmo. Na Autorizao Declarativa o container realiza toda a validao
de segurana, no sendo preciso implement-la. Para isso, deve-se configurar no deployment descriptor as propriedades de segurana para cada EJB e para cada mtodo do mesmo.
Em um mundo perfeito, o melhor forma a utilizar a Autorizao Declarativa. Haver
casos que ser necessrio mesclar as duas formas de autorizao, sendo que somente
a declarativa no ser suficiente. Por exemplo, se em uma rede de lojas um usurio
com perfil de gerente pode acessar o servios de obteno de relatrios gerenciais,
sendo somente permitido acessar esses dados das redes de uma determinada praa
(regio de So Paulo, por exemplo), se faz necessrio incluir uma validao programtica da regio da rede de lojas que o gerente em questo atua.

Security Roles
O conceito de security roles simples, mas necessrio para o entendimento do uso
de autorizao. Uma security role um conjunto de identidades de usurios (identity). Para um usurio ser autorizado a realizar uma operao por exemplo, sua identidade dever estar na correta security role (perfil) para a operao em questo. O uso
de security roles interessante, pois o desenvolvedor no precisa especificar o perfil
do usurio no cdigo do EJB.

Autorizao Programtica
Para realizar a autorizao de forma programtica, se faz necessrio obter as informaes do usurio autenticado na implementao do EJB. Isto deve ser feito utilizando
a interface javax.ejb.EJBContext que fornece os mtodos getCallerPrincipal() e isCallerInRole(). Vejamos a seguir os mtodos desta interface.
public interface javax.ejb.EJBContext {
...
public java.security.Principal getCallerPrincipal();
public Boolean isCallerInRole(String roleName);
...
}

221

J2EE Primeiros Passos


O mtodo getCallerPrincipal() fornece informaes do usurio atual, autenticado no
sistema. Este mtodo retorna o objeto java.security.Principal no qual pode-se obter
informaes importantes do usurio, utilizadas para a sua autorizao.
O mtodo isCallerInRole(String roleName) verifica se o usurio atual est dentro de
uma security role especfica. Dessa forma, pode-se realizar a autorizao para um
determinado servio do EJB de forma programtica.
Vejamos a seguir um exemplo de deployment descriptor, configurando security roles
e links para as security roles reais. Esta ltima propriedade pode ser configurada, pois
em tempo de desenvolvimento o programador pode definir uma security role dentro
do seu cdigo e depois no momento da instalao do sistema, a security role real tem
um nome diferente, ento cria-se um link para o nome correto.
...
<enterprise-beans>
<session>

...
<security-role-ref>
<description>Perfil do usurio=gerente</description>
<role-name>gerente</role-name>
<role-link>manager</role-link>
</security-role-ref>
...

</session>
<assembly-descriptor>

...
<security-role>
<description>Perfil de usurio=gerente</description>
<role-name>manager</role-name>
</security-role>
...

</assembly-descriptor>
</enterprise-beans>
...

222

Captulo 15 Transaes e Segurana

Autorizao Declarativa
A diferena de utilizar autorizao declarativa ao invs da declarao programtica
que no h a necessidade de programar a autorizao, necessitando somente de configurar o deployment descriptor, definindo para cada EJB a security role a ser utilizada. Pode-se definir uma security role para todos os mtodos do EJB, ou definir uma
especfica para cada mtodo. H a possibilidade de excluir mtodos que no desejase que seja acessado por nenhum perfil de usurio, e isto tambm deve ser feito no
deployment descriptor.
Observe que se alguma operao realizar uma chamada a algum mtodo com um
perfil inadequado, isto , com um perfil que no foi configurado ou definido para o
mtodo, o container lanar um exceo do tipo java.lang.SecurityException.
Vejamos a seguir um exemplo de deployment descriptor, configurando security roles
e as permisses para os mtodos dos EJBs.
...
<enterprise-beans>
<session>

...
<security-role-ref>
<description>Perfil do usurio=gerente</description>
<role-name>gerente</role-name>
</security-role-ref>
...

</session>
<assembly-descriptor>

...
<method-permission>
<role-name>gerente</role-name>
<method>
<ejb-name>EJBTestX</ejb-name>
<method-name>*</method-name>
</method>
</method-permission>
...
...
<method-permission>
<role-name>gerente</role-name>

223

J2EE Primeiros Passos


<method>
<ejb-name>EJBTestY</ejb-name>
<method-name>calc</method-name>
</method>
<method>
<ejb-name>EJBTestY</ejb-name>
<method-name>go</method-name>
</method>
<method>
<ejb-name>EJBTestY</ejb-name>
<method-name>getAccount</method-name>
</method>
<method>
<ejb-name>EJBTestY</ejb-name>
<method-name>doTransfer</method-name>
<method-params>Integer</method-params>
<method-params>Integer</method-params>
<method-params>Integer</method-params>
</method>
...
</method-permission>
<description>Este mtodo no sera executado</description>
<method>
<ejb-name>EJBTestY</ejb-name>
<method-name>cleanFunds</method-name>
</method>
<exclude-list>

</exclude-list>
...
</assembly-descriptor>
</enterprise-beans>
...

Propagao de Segurana
Em uma aplicao J2EE, teremos com certeza casos em que servios de alguns EJBs
utilizam servios de outros. Dependendo da aplicao, poderamos querer que a identidade do usurio (perfil) seja propagado para os mtodos que esto sendo chamados pelos prprios EJB para outros EJBs, ou em vez disso, definir um perfil para executar um determinado mtodo em um EJB especfico.

224

Captulo 15 Transaes e Segurana


Imagine uma situao em que um cliente acessa um servio de clculo de um certo
imposto para a venda de um produto. Chamaremos este como servio doXXX do EJB
A. Este mtodo chamaria outro mtodo do EJB B, o mtodo doYYY. Podemos definir
na aplicao, que este ltimo mtodo execute com a identidade do chamador, isto ,
utilize a mesma identidade do cliente que chamou o mtodo doXXX do EJB A. Ou
ainda poderamos definir que o mtodo doYYY do EJB B rodasse com uma nova
identidade, definida pela aplicao. Essas duas opes podem ser configuradas no
deployment descriptor da aplicao. Vejamos um exemplo a seguir:
<enterprise-beans>
<session>
<ejb-name>A</ejb-name>
...
<security-identity>
<use-caller-identity/>
</security-identity >
...
</session>
<session>
<ejb-name>B</ejb-name>

...
<security-identity>
<run-as>
<role-name>gerente</role-name>
</run-as>
</security-identity >
...

</session>

<assembly-descriptor>

...
<security-role>
<description>Perfil de usurio=gerente</description>
<role-name>gerente</role-name>
</security-role>
...
</assembly-descriptor>
</enterprise-beans>

225

J2EE Primeiros Passos

Exemplo
Veremos a seguir, um exemplo de mdulo de segurana utilizando a API JAAS. Observe que no provemos uma implementao especfica para o mdulo, sendo o
intuito mostrar somente um esqueleto com os mtodos principais que devem ser
implementados conforme o contrato estabelecido pelas interfaces. Fica a cargo do
leitor implementar os mtodos se desejado.

ExampleLoginModule.java
package com.novatec.book.example.security;
import java.util.*;
import javax.security.auth.*;
import javax.security.auth.spi.*;
import javax.security.auth.login.*;
import javax.security.auth.callback.*;
/**
* Exemplo do mdulo de login para realizar a autenticao do usurio.
* Esta classe no apresenta implementao, somente sendo um ponto de partida
* para a criao de um mdulo de login.
*/
public class ExampleLoginModule implements LoginModule {
/**
* Representa um gurpo de informaes relacionados a uma entidade (cliente).
*/
private Subject subject = null;

/**
* Inicializa o mdulo de login.
* Este mtodo executado pelo contexto de login, aps a sua instanciao,
* com o propsito de inicializar este mdulo com informaes relevantes ao
* seu uso.
* @param subject subject a ser autenticado.
* @param callbackhandler handler utilizado para se comunicar com o cliente.
* @param sharedState estado compartilhado com outros mdulos.
* @param options opes especificadas na configurao do login.
*/
public void initialize(Subject subject, CallbackHandler callbackhandler,
Map sharedState,
Map options) {
this.subject = subject;
}

226

Captulo 15 Transaes e Segurana


/**
* Este mtodo utilizado para autenticar o usurio.
* @return verdadeiro se a autenticao se realizar com sucesso, falso caso
contrrio.
* @throws LoginException exceo ao tentar autenticar o usurio.
*/
public boolean login() throws LoginException {
/*
Deve autenticar o usurio e senha do cliente que est tentando acesso
Isso pode ser feito por arquivo de properties, LDAP, banco etc.
*/
}
/**
* Utilizado para realizar o commit da autenticao.
* @return verdadeiro se obtiver sucesso no commit, falso caso contrrio.
* @throws LoginException caso falhe o commit.
*/
public boolean commit() throws LoginException {
return true;
}
/**
* Utilizado par abortar o processo de autenticao.
* Chamado pelo contexto de login se a autenticao falhar.
* @return verdadeiro caso haja sucesso no abort, falso caso contrrio.
* @throws LoginException caso falhe no abort.
*/
public boolean abort() throws LoginException {
return true;
}

/**
* Utilizado para efetuar o logout do usurio autenticado.
* A sua implementao dever destruir o Principal e Credenciais do subject
(cliente).
* @return veradeiro caso o logout efetue com sucesso, falso caso contrrio.
* @throws LoginException exceo caso o logout falhe.
*/
public boolean logout() throws LoginException {
return true;
}
}

227

J2EE Primeiros Passos

ExamplePrincipal.java
package com.novatec.book.example.security;

import java.security.*;

/**
* Representa o usurio a ser autenticado.
*/
public class ExamplePrincipal implements Principal {

/**
* Nome do usurio.
*/
private String name = null;

/**
* Construtor customizado.
* @param name nome do usurio.
*/
public ExamplePrincipal(String name) {
this.name = name;
}

/**
* Obtm o nome do usurio.
* @return nome do usurio.
*/
public String getName() {
return name;
}
/**
* Implementao do mtodo equals.
* Verifica se um objeto igual a este.
* @param obj objeto a ser comparado.
* @return verdadeiro caso o objeto seja igual a este, falso caso contrrio.
*/
public boolean equals(Object obj) {
if ( obj == this )
return true;

228

Captulo 15 Transaes e Segurana


if ( ! (obj instanceof ExamplePrincipal) )
return false;
return name.equals(((ExamplePrincipal) obj).getName());
}

/**
* Implementao do mtodo hashCode.
* Informa uma chave de hash utilizada para este objeto.
* @return chave de hash.
*/
public int hashCode() {
return name.hashCode();
}

/**
* Retorna uma string com informaes do usurio.
* @return string com informaes do usurio.
*/
public String toString() {
return name;
}
}

ExampleRoleGroup.java
package com.novatec.book.example.security;

import java.util.*;
import java.security.*;
import java.security.acl.*;

/**
* Apresenta o esqueleto para a implementao de um grupo de usurios.
*/
public class ExampleRoleGroup extends ExamplePrincipal implements Group {

/**
* Construtor customizado.
* @param name nome do usurio.
*/

229

J2EE Primeiros Passos


public ExampleRoleGroup(String name) {
// implementao do construtor...
}

/**
* Adiciona o usurio em questo ao grupo.
* @param user usurio a ser adicionado ao grupo.
* @return veradeiro se o usurio foi adicionado com sucesso, falso caso
contrrio.
*/
public boolean addMember(Principal user) {
return true;
}

/**
* Remove o usurio do grupo.
* @param user usurio a ser adicionado ao grupo.
* @return veradeiro se o usurio foi removido com sucesso, falso caso contrrio.
*/
public boolean removeMember(Principal user) {
Object prev = members.remove(user);
return prev != null;
}

/**
* Verifica se o usurio membro do grupo.
* @param member usurio que dever ser verificado se membro.
* @return verdadeiro se o usurio membro, falso caso contrrio.
*/
public boolean isMember(Principal member) {
return true;
}

/**
* Retorna uma lista com os membros do grupo.
* @return lista com os membros do grupo.
*/
public Enumeration members() {
return Collections.enumeration(members.values());
}
}

230

Captulo 15 Transaes e Segurana

ExampleTest.java
package com.novatec.book.example.security;

import java.util.*;
import javax.rmi.*;
import javax.naming.*;
import java.security.*;

/**
* Implementao de uma ao privilegiada.
* Executada com segurana.
*/
public class ExampleTest implements PrivilegedAction {

/**
* Executa a ao com segurana.
* @return informao retornada pelo mtodo do EJB.
*/
public Object run() {
try {
Context ctx = new InitialContext();
Object obj = ctx.lookup(SecurityExampleTest);
SecurityExampleTestHome home =
(SecurityExampleTestHome) PortableRemoteObject.narrow(obj,
SecurityExampleTestHome.class);
SecurityExampleTest test = home.create();

return test.doIt();

}
catch (Exception ex) {
ex.printStackTrace();
}
}
}

231

J2EE Primeiros Passos

ExampleMain.java
package com.novatec.book.example.security;

import javax.naming.*;
import javax.security.auth.*;
import javax.security.auth.login.*;

public class ExampleMain {

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

LoginContext loginContext = new LoginContext(ExampleTest);


loginContext.login();

Subject subject = loginContext.getSubject();

ExampleTest exampleTest = new ExampleTest();


Subject.doAs(subject, action);

}
}

Observamos que o uso de transaes inevitvel para que a aplicao apresente


eficincia e robustez. Agora sabemos que a arquitetura J2EE prov transaes do tipo
Flat e que podemos utiliz-las, tanto como Container-Managed como Bean-Managed, para gerenciar as transaes de nossa aplicao.

232

Captulo 16
Descobrindo Enterprise JavaBeans
O objetivo deste captulo iniciar o leitor nos aspectos prticos que envolvem a construo de uma aplicao distribuda utilizando os componentes da plataforma J2EE.
Os cdigos-fonte completos se encontram no Captulo 19.

16.1 Qual servidor J2EE utilizar?


A quantidade de servidores de aplicao J2EE encontrados no mercado hoje grande. Existem servidores de aplicao de uso livre e outros proprietrios, alguns dispondo de alguns servios como diferenciais, outros dispondo de um desempenho
melhor.
Quando decidimos em usar a tecnologia J2EE e precisamos escolher qual servidor de
aplicaes utilizar, devemos levar em considerao aspectos como desempenho, tamanho da aplicao, recursos que sero utilizados, custos entre outros.
Para executar e exemplificar a aplicao J2EE que iremos apresentar neste captulo,
utilizaremos o servidor de aplicaes livre JBoss na verso 3.x.x. A escolha deste servidor de aplicaes, se deve ao seu grande uso em aplicaes J2EE que no necessitam de um servidor proprietrio. Apresenta uma soluo tima e de alto desempenho para os custos envolvidos.

16.2 Instalando, configurando e executando um Servidor J2EE


No existem muitos segredos para instalar, configurar e executar o servidor de aplicaes JBoss.
O que devemos fazer copiar o binrio do servidor de aplicaes JBoss na verso
3.x.x, do site do prprio JBoss (http://www.jboss.org). O arquivo que foi copiado
deve ter sido um arquivo compactado. Este arquivo deve ser descompactado em um
diretrio ou sub-diretrio no qual deseja-se ter a instalao do servidor de aplicaes
JBoss. Aps esta fase a instalao est completa.

233

J2EE Primeiros Passos


O interessante que no precisaremos realizar nenhuma configurao para executar
os exemplos contidos neste livro. A configurao padro da instalao do JBoss j
nos proporciona todos os servios necessrios para a nossa aplicao exemplo. Veremos que necessitaremos de utilizar um banco de dados, mas isto no ser problema e nem precisaremos nos precocupar em instalar um. O JBoss oferece um banco
de dados HyperSonic SQL - para realizar testes e executar exemplos. Assim, a fase
de configurao tambm est completa sem muita dificuldade.
Executar o servidor de aplicaes JBoss tambm uma operao muito simples. Abra
o prompt de comando do seu sistema operacional e acesse o diretrio de instalao
do JBoss. Entre no diretrio <Instalao_JBoss>/bin, e execute o comando para iniciar o servidor. Se estiver no sistema operacional Windows utilize o run.bat ou run.sh se
estiver em um ambiente Linux ou Unix. Ento deve-se ter o seguinte:
<Instalao_JBoss>/bin/run. Com isto, o servidor de aplicaes inicializar, mostrando vrias mensagens no console, at aparecer a ltima mensagem informando que o
servidor foi inicializado com sucesso. Assim, poderemos realizar a instalao da aplicao exemplo que veremos logo a seguir, que tambm no apresentar muita dificuldade.
Um outro detalhe que no pode ser deixado de lado a configurao do CLASSPATH
da aplicao que utilizar dos servios do container J2EE. Deve-se incluir um arquivo
informando qual mquina e porta encontra-se o servio JNDI para a sua aplicao
solicitar para o servidor a localizao dos componentes no container. Este arquivo
normalmente conhecido como jndi.properties, mas as propriedades JNDI tambm
podem ser definidas em tempo de execuo, utilizando-se do servio
System.setProperty(). No JBoss este arquivo encontra-se em <Instalao_JBoss>/server/default/conf/jndi.properties.
Observe que no o intuito deste captulo, explorar os recursos e detalhes de configurao do servidor de apliaes JBoss. Para maiores detalhes consulte a documentao oferecida e disponvel no site do JBoss. Se no for suficiente, o JBoss fornece
uma documentao mais completa para pessoas que desejam utilizar o servidor JBoss
em aplicaes comerciais a baixo custo.
Veremos a seguir, tpicos que exemplificam na forma de uma aplicao, os tipos de
EJB apresentados nos captulos anteriores deste livro. A aplicao completa se encontra no captulo 19. Ento, cada tpico seguinte trar explicaes detalhadas do
que foi implementado em cada EJB. No fim, poderemos juntar todos os EJBs e outras
classes auxiliares em uma nica aplicao e fazermos a instalao e acesso aplicao exemplo.
A aplicao exemplo apresentada nos prximos tpicos se trata de uma aplicao de
venda de produtos, no qual um usurio poder escolher alguns produtos, calcular
algumas informaes pertinentes a estes produtos e incluir estes produtos em uma
cesta de compras. Poder ainda excluir, alterar ou remover todos os produtos de sua

234

Captulo 16 Descobrindo Enterprise JavaBeans


cesta. Na finalizao da compra, os dados dos produtos escolhidos sero persistidos
e o usurio ser avisado do trmino da compra, com os dados dos produtos vendidos.

16.3 Criando um Session Bean Stateless


Neste tpico sero analisadas as partes da codificao do EJB Session Bean Stateless,
que faz parte da aplicao exemplo. No detalharemos as interfaces, pois elas s
apresentam o contrato dos mtodos de negcio e ciclo de vida. Os mtodos de negcio sero brevemente explicados.
O EJB Session Bean utilizado como exemplo, apresenta servios de clculo do desconto concedido ao usurio e clculo de parcelas para um produto em venda. O
nome deste EJB SalesSupportBean.
O cdigo a seguir, que pertencente a interface Home do EJB SalesSupportBean, apresenta o mtodo que solicita a criao do EJB e retorna a referncia para a execuo
dos mtodos de negcio.

public SalesSupport create() throws CreateException, RemoteException;

Observe que o mtodo create() ao ser executado, solicita ao container que crie uma
instncia do EJB SalesSuuportBean. Dessa forma o container cria a instncia do objeto, do tipo EJBObject que encapsula o EJB SalesSupportBean e retorna ao cliente
chamador uma referncia da interface Remote, na qual se tem acesso aos mtodos de
negcios ou servios disponveis para o EJB em questo.
A seguir, observe os mtodos da interface Remote do EJB SalesSupportBean, mtodos de negcio utilizados pelo cliente para calcular o desconto concedido ao produto vendido e clculo das parcelas a serem pagas.

Double calcDiscount(Double value, Double perc) throws RemoteException;


Double calcPiece(Double value, Integer times) throws RemoteException;

A seguir vamos analisar a implementao do EJB SalesSupportBean. Iremos somente


comentar os mtodos de negcio deste EJB que so muito simples. Os mtodos de
ciclo de vida do EJB sero somente citados.
No mtodo de ciclo de vida ejbCreate() que apresenta a mesma assinatura da interface Home SalesSupportHome, no foi necessrio nenhuma implementao, sendo
assim, este mtodo no contm lgica.

235

J2EE Primeiros Passos


Isto tambm ocorreu para os mtodos ejbRemove(), ejbActivate() e ejbPassivate(),
por no necessitar de executar operaes nos momentos de criao e remoo da
instncia do EJB, e na ativao e passivao quando ocorre a liberao de recursos
alocados, mas que no o caso.
Os mtodos de negcio calcDiscount() e calcPiece() apresentam operaes simples
para o clculo do desconto concedido na venda do produto e clculo do valor de
parcelas de acordo com o valor da venda.

public Double calcDiscount(Double value, Double perc) {


return new Double((value.doubleValue() * perc.doubleValue()) / 100);
}
public Double calcPiece(Double value, Integer times) {
return new Double(value.doubleValue() / times.intValue());
}

Observe que o mtodo calcDiscount() retorna o resultado da operao do valor de


venda diminuido do valor de desconto concedido de acordo com o percentual informado. O mtodo calcPiece() somente divide o valor total da venda pela quantidade
de vezes tambm informada para o mtodo.
Veja que as operaes implementadas so bem simples e tambm no o escopo
deste livro, detalhar demasiadamente as operaes, sendo que estas servem somente
de exemplo e apresentam uma idia de como deve-se implementar os servios oferecidos pelo EJB Session Bean Stateless.
Abaixo veremos o deployment descriptor do EJB SalesSupportBean, arquivo que deve
ser criado juntamente com o EJB e utilizado pelo servidor de aplicaes para obter
informaes adicionais do EJB e realizar o deploy do mesmo. Este arquivo tende a ser
simples para EJBs Session Bean. Iremos somente comentar algumas linhas.
As linhas iniciais apresentam o nome de exibio e o nome propriamente dito do
EJB, utilizados pelo servidor de aplicaes. A seguir seguem os nomes das interfaces
Home e Remote e o nome da classe que implementa o EJB em questo. Depois
informado o tipo de EJB Session Bean, que pode ser Stateless ou Stateful e por fim o
tipo de transao, isto , se ser gerenciada pelo Container ou pelo Bean. Por fim
definido o tipo de transao utilizada para cada mtodo especfico do EJB. Deve-se
fazer referncia ao EJB que se est definindo as propriedades de transao, pelo seu
nome anteriormente definido e a seguir, definir para cada mtodo o tipo de transao
que este se enquadrar. No nosso caso utilizamos um asterstico, com isso todos os
mtodos do EJB informado utilizaro o mesmo tipo de transao que foi definida
como Required.

236

Captulo 16 Descobrindo Enterprise JavaBeans


<session>
<display-name>SalesSupport</display-name>
<ejb-name>SalesSupport</ejb-name>
<home>com.novatec.book.project.ejb.session.SalesSupportHome</home>
<remote>com.novatec.book.project.ejb.session.SalesSupport</remote>
<ejb-class>com.novatec.book.project.ejb.session.SalesSupportBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>SalesSupport</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>

16.4 Criando um Session Bean Stateful


Iremos agora detalhar um exemplo de EJB Session Bean Stateful, utilizado na aplicao exemplo. No sero detalhados os mtodos de ciclo de vida da interface Home
SalesBasketHome neste tpico, pois o mesmo j foi abordado no tpico anterior e o
seu comportamento o mesmo. A nica exceo se faz para o mtodo ejbCreate(),
por um pequeno detalhe que ser mostrado.
Este EJB, chamado de SalesBasketBean, ser encarregado de prover todos os servios de venda dos produtos escolhidos. Para isso, fornece mtodos de negcio tais
como adicionar produtos na cesta de compras, remov-los, limpar a cesta, calcular o
preo total dos produtos etc. Assim, vamos analisar cada mtodo de negcio deste
EJB. A seguir segue a assinatura dos mtodos de negcio constantes na interface Remote SalesBasket.

void initSales(UserTO user) throws RemoteException;


Boolean finalizeSale() throws Exception, RemoteException;
void addProduct(ProductTO product) throws RemoteException;
Boolean removeProduct(ProductTO product) throws RemoteException;
Double calcBasketPrice() throws RemoteException;
void freeBasket() throws RemoteException;

237

J2EE Primeiros Passos


Na classe de implementao do EJB SalesBasketBean, criamos um atributo chamado
basket, que uma Map que mantm os produtos adicionados na cesta de compras.
Com isto, entendemos a diferena do EJB Session Bean Stateless do EJB Session Bean
Stateful, no qual este ltimo mantm os dados de um cliente especfico, isto , mantm os produtos na cesta de um determinado cliente e no compartilha estes dados
com outros usurios.

private Map basket;

Tambm mantemos no EJB SalesBasketBean os dados do usurio que iniciou a compra, para no final desta, validarmos seus dados e relacionarmos os produtos comprados para um determinado usurio. Observe que existe um objeto do tipo UserVO.
Este objeto utilizado para carregar informaes do usurio em questo.

private UserVO user;

O mtodo ejbCreate() do EJB SalesBasketBean somente inicializa a Map que contm


os produtos comprados por um determinado usurio.

public void ejbCreate() throws CreateException {


this.basket = new HashMap();
}

O EJB SalesBasketBean dispe de um mtodo utilizado para inicializar a venda. Para


isso, configura o usurio que estar realizando a compra. Observe que esta operao
poderia ser executada no mtodo ejbCreate(), passando o objeto UserVO como parmetro no momento da criao da instncia do EJB.

public void initSales(UserVO user) {


this.user = user;
}

O trecho a seguir implementa o mtodo de finalizao da compra. Esta operao


um pouco mais complexa que as apresentadas at o momento, ento atente para os
detalhes. Inicialmente solicitado uma classe chamada de SalesServiceLocator, uma
referncia para a instncia do EJB Entity Bean ProductBean, utilizado para persistir os
dados dos produtos vendidos para determinado usurio. A operao de obter a referncia para o EJB ProductBean est implementada na classe SalesServiceLocator
como pode-se notar.

238

Captulo 16 Descobrindo Enterprise JavaBeans


Esta classe implementa um Design Pattern bastante conhecido, no qual oculta a implementao da localizao do EJB e facilita esta operao para as classes que a utilizaro. No o intuito deste livro detalhar Design Patterns utilizados nos cdigos. Para
maiores detalhes consulte as referncias bibliogrficas.
Aps os detalhes deste mtodo, apresentamos a implementao do mtodo do SalesServiceLocator que localiza o EJB e retorna a referncia para os seus clientes.
Com a referncia da interface Home ProcuctLocalHome, podemos realizar a execuo do mtodo create() para cada produto contido na cesta de produtos. Persistimos
cada produto da cesta do usurio, fazendo isso por meio de um iterador. Este iterador
ir obter cada produto contido na Map e criar uma instncia do EJB ProductBean.

public Boolean finalizeSale() throws Exception {


final String FACADE_NAME = java:comp/env/ejb/productfacade;
ProductSessionFacadeHome localHome = (ProductSessionFacadeHome)
ServiceLocator.getInstance().
ProductSessionFacadeHome.class);

getEjbHome(FACADE_NAME,

ProductSessionFacade local = localHome.create();


try {
for (Iterator i = basket.entrySet().iterator(); i.hasNext(); ) {
Map.Entry product = (Map.Entry) i.next();
ProductTO to = (ProductTO) product.getValue();
local.createProduct(to);
}
return new Boolean(true);
} catch (Exception ex) {
throw new Exception(Error while trying to finalize Sale. + ex);
}
}

A seguir vemos a implementao do mtodo getLocalHome, da classe ServiceLocator, na qual obtido referncia para as interfaces dos EJBs contidos no servidor de
aplicao. Veja que a operao simples, somente realizando um lookup (localizao) do EJB solicitado pelo seu nome JNDI. Para efeito de melhora de desempenho, a
referncia para as interfaces Home solicitadas so armazenadas em um cache e podendo ser utilizadas futuramente em outras chamadas a este mtodo.

public static EJBLocalHome getEjbLocalHome(String ejbName) throws


ServiceLocatorException {

239

J2EE Primeiros Passos


try {
Object object = context.lookup(ejbName);
EJBLocalHome ejbLocalHome = null;
ejbLocalHome = (EJBLocalHome) object;
if (ejbLocalHome == null) {
throw new ServiceLocatorException(
Could not get local home for + ejbName);
}
return ejbLocalHome;
} catch (NamingException ne) {
throw new ServiceLocatorException(ne.getMessage());
}
}

A seguir continuamos com os mtodos do EJB SalesBasketBean.


A implementao dos mtodos addProduct() e removeProduct() que adicionam e
removem produtos da cesta simples. Utilizamos os mtodos de adio e remoo
de objetos do tipo ProductVO na Map. Tambm h a implementao de um servio
para limpar todos os produtos da cesta. Este mtodo tambm aproveita o mtodo
clear() da Map e executa-o.

public void addProduct(ProductTO product) {


this.basket.put(product.getId(), product);
}

public Boolean removeProduct(ProductTO product) {


if (this.basket.remove(product.getId()) != null)
return new Boolean(true);
return new Boolean(false);
}

O EJB tambm apresenta o mtodo de clculo do preo total dos produtos contidos
na cesta. Esta tambm uma operao simples, que consiste em iterar todos os produtos contidos na cesta, acumulando os valores dos produtos e retornando este valor.

public Double calcBasketPrice() {


double value = 0;
for (Iterator i = basket.entrySet().iterator(); i.hasNext(); ) {

240

Captulo 16 Descobrindo Enterprise JavaBeans


Map.Entry entry = (Map.Entry) i.next();
value += ((ProductTO) entry.getValue()).getPrice().doubleValue();
}
return new Double(value);
}

Observe que este EJB tambm no apresenta complexidade de implementao de


cdigo, mas como j foi dito, este no o intuito do livro. O enfoque desta aplicao
exemplo de somente validar os conhecimentos de EJBs..
A seguir segue o deployment descriptor do EJB SalesBasketBean. Tambm no apresenta muitos segredos e a nica diferena para o deployment descriptor do EJB Session Bean Stateless visto no tpico anterior, na tag tipo de EJB Session Bean. Nesta
configurado o nome Stateful, para informar que o EJB a qual est se referenciando,
se trata de um EJB Session Bean Stateful. Tambm no houve alteraes na configurao do tipo de transao para cada mtodo, utilizando o mesmo tipo de transao
para todos os mtodos do EJB SalesBasketBean, conforme explicado no tpico anterior.

<ejb-jar>
<enterprise-beans>
<session>
<display-name>SalesBasket</display-name>
<ejb-name>SalesBasket</ejb-name>
<home>com.novatec.book.project.ejb.session.SalesBasketHome</home>
<remote>com.novatec.book.project.ejb.session.SalesBasket</remote>
class>

<ejb-class>com.novatec.book.project.ejb.session.SalesBasketBean</ejb<session-type>Stateful</session-type>
<transaction-type>Container</transaction-type>
</session>

16. 5 Criando um Entity Bean BMP


O prximo EJB a ser comentado ser o EJB Entity Bean BMP UserBean. Neste EJB foi
implementado toda a lgica de persistncia e manipulao do objeto. Para realizar a
persistncia em um banco de dados, no precisaremos instalar e configurar um. O
prprio servidor de aplicaes JBoss fornece um banco de dados como padro, o
HyperSonic SQL, que pode ser utilizado para executar exemplo de aplicaes J2EE.
Ento utilizaremos esse recurso para manter os EJB Entity Beans.

241

J2EE Primeiros Passos


No caso do EJB Entity Bean BMP, as tabelas que esse tipo de componente utiliza no
so criadas pelo container, ento definimos um EJB Session Bean ProjecSupportBean
para realizar tais operaes de configurao do meio de persistncia. Este EJB no
detalhado neste captulo, mas sua implementao completa se encontra no captulo
19.
Ao usar um EJB Entity Bean, o correto a se fazer no acess-lo diretamente, e sim
provr um outro componente do tipo EJB Session Bean que fornece seus servios
para as outras camadas ou mdulos EJB, sendo o acesso ao EJB Entity Bean restrito
esse tipo de componente. Neste caso, utilizamos um Design Pattern chamado de Facade para tal operao.
Veremos as interfaces Local e LocalHome que so respectivamente UserLocal e UserLocalHome.
A seguir, temos o contrato da interface Local UserLocalHome que apresenta os mtodos de ciclo de vida do EJB. O mtodo create() utilizado para solicitar uma instncia
do EJB para o container. Neste mtodo so informados os valores do objeto que sero
persistidos. Este mtodo declara as excees CreateException utilizada em caso de
erro na persistncia do objeto, sendo uma exceo de Runtime. Veremos mais detalhes deste mtodo, isto , da sua implementao no prprio EJB UserBean.
O outro mtodo de ciclo de vida definido nesta interface o mtodo findByPrimaryKey(). Este mtodo utilizado para localizar um objeto persistido atravs de sua
chave primria, que no nosso caso ser o CPF do usurio. Na execuo deste mtodo,
no necessrio utilizar o mtodo create(), pois no iremos criar um novo objeto e
sim localizar um objeto anteriormente persistido. Com isso, o mtodo findByPrimaryKey() tambm retorna uma referncia para a instncia do EJB. Declara as excees
FinderException utilizada caso no consiga localizar o objeto atravs da chave primria informada.

public interface UserLocalHome extends javax.ejb.EJBLocalHome {


UserLocal create(String name, String cpf, String address, String email)
throws CreateException;
UserLocal findByPrimaryKey(String cpf) throws FinderException;
}

O cdigo a seguir apresenta os mtodos de negcio do EJB. Estes mtodos so definidos na interface Local. Iremos detalhar a interface Local UserLocal. So definidos
nesta interface os mtodos getters e setters para o objeto em questo.

public interface UserLocal extends javax.ejb.EJBLocalObject {


String getName() throws RemoteException;

242

Captulo 16 Descobrindo Enterprise JavaBeans


String getCpf() throws RemoteException;
String getAddress() throws RemoteException;
String getEmail() throws RemoteException;
void setName(String name) throws RemoteException;
void setAddress(String address) throws RemoteException;
void setEmail(String email) throws RemoteException;
}

Veremos em seguida o detalhamento da implementao do EJB Entity Bean BMP


UserBean.
Definimos um atributo chamado connection, utilizado para manter a conexo com o
banco de dados responsvel por manter os dados do objeto. Essa conexo obtida
por meio de um nome JNDI definido pelo servidor de aplicaes JBoss como DataSource padro configurado neste servidor. Usaremos este para persistirmos os objetos. Veremos que definimos um mtodo para obter a conexo, o mtodo getConnection() utilizado em alguns mtodos de persistncia do objeto.
Seguem tambm alguns atributos definidos como constantes que apresentam as operaes de seleo, remoo, atualizao e localizao dos objetos em SQL. Estes atributos so utilizados em determinados mtodos que sero vistos posteriormente, para
realizar as operaes respectivas. Observe que essas operaes no banco de dados
poderiam no ser definidas como constantes do EJB, mas serem criadas somente em
cada mtodo. Esta uma deciso do programador e aqui segue somente como exemplo.

private transient Connection connection = null;

// Query de insero do objeto no BD.


private final String INSERT_QUERY =
INSERT INTO USER(Name, Cpf, Address, Email) VALUES(?, ?, ?, ?);

// Query de atualizao do objeto no BD.


private final String UPDATE_QUERY =
UPDATE USER SET Name = ?, Address = ?, Email = ? WHERE Cpf = ?;

// Query de remoo do objeto no BD.


private final String DELETE_QUERY = DELETE FROM USER WHERE Cpf = ?;

// Query de obteno do objeto do BD.


private final String SELECT_QUERY = SELECT Name, Cpf, Address, Email FROM USER
WHERE Cpf = ?;

243

J2EE Primeiros Passos


// Query utilizada para obter os objetos dado sua chave primria.
private final String FIND_BY_PK = SELECT Name, Cpf, Address, Email FROM USER WHERE
Cpf = ?;

/**
* Cria uma conexo com o banco de dados padro.
* @return conexo do banco de dados.
*/
private Connection getConnection() {
Connection conn = null;
try {
InitialContext ctx = new InitialContext();
conn = (Connection) ctx.lookup(java:/DefaultDS);
} catch (Exception e){
throw new RuntimeException(e.getMessage());
}
return conn;
}

Vemos a seguir a implementao do mtodo ejbCreate() definido na interface Home


e LocalHome. Neste mtodo so informados os atributos do objeto a serem persistidos e nele implementado a operao de gravao dos dados em um banco de dados. Observe que obtemos uma conexo com o banco de dados, preparamos a operao a ser executada, realizamos o bind dos atributos e em seguida executamos o
comando. Por fim, so configurados todos os atributos do objeto e retornado o seu
atributo chave-primria para o container. Este tratar essa informao e retornar ao
objeto chamador uma referncia para a interface Remote ou Local, disponibilizando
assim a execuo dos mtodos de negcio.
No mostramos detalhes do mtodo ejbPostCreate(), pois no h implementao.
Somente importante salientar que este mtodo deve ter a mesma assinatura do mtodo create(). Normalmente ele utilizado para configurar relacionamentos entre
EJB Entity Beans.

public String ejbCreate(String name, String cpf, String address, String email)
throws CreateException {
try {
connection = getConnection();
try {
PreparedStatement stmt = connection.prepareStatement(
INSERT_QUERY);

244

Captulo 16 Descobrindo Enterprise JavaBeans


try {
stmt.setString(1, name);
stmt.setString(2, cpf);
stmt.setString(3, address);
stmt.setString(4, email);
stmt.execute();
} finally {
stmt.close();
}
} finally {
connection.close();
}
} catch (Exception e) {
throw new CreateException();
}
setName(name);
setCpf(cpf);
setAddress(address);
setEmail(email);
return null;
}

O mtodo a seguir trata da remoo do objeto do meio persistente. Como no mtodo


ejbCreate(), o mtodo ejbRemove() tambm obtm uma conexo com o meio de
persistncia, prepara a execuo do comando SQL, realiza o bind da varivel pelo
chave primria e executa o comando. Assim, o registro definido com a chave primria informada removido do banco de dados. Esse mtodo no retorna nenhum valor, mas em caso de erro na execuo do mtodo, a exceo RemoveException
lanada.

public void ejbRemove() throws RemoveException {


try {
connection = getConnection();
try {
PreparedStatement stmt = connection.prepareStatement(
DELETE_QUERY);
try {
stmt.setString(1, this.cpf);
stmt.execute();
} finally {

245

J2EE Primeiros Passos


stmt.close();
}
} finally {
connection.close();
}
} catch (Exception e) {
throw new RemoveException(Error removing element.);
}
}

O prximo mtodo ejbFindByPrimaryKey() apresenta a localizao do objeto por


meio de sua chave primria. A chave deve ser informada para o mtodo. O objeto
localizado no meio persistente e uma instncia sua criada no container do servidor
de aplicao. ento retornado sua chave primria que ser tratada pelo container
que disponibilizar para o objeto chamador a referncia para interface Remote ou
Local, para a execuo dos mtodos de negcio. A implementao deste mtodo
tambm muito parecida com os anteriores, obtendo uma conexo, preparando o
comando SQL, realizando o bind da varivel tida como chave primria, executando o
comando, configurando cada atributo com os valores localizados no meio persistente e por fim, retornando para o container a chave primria do objeto. Em caso de
erros na localizao do objeto, uma exceo FinderException lanada.

public String ejbFindByPrimaryKey(String cpf) throws FinderException {


try {
connection = getConnection();
try {
PreparedStatement stmt = connection.prepareStatement(FIND_BY_PK);
try {
stmt.setString(1, cpf);
ResultSet rs = stmt.executeQuery();
try {
if (rs.next()) {
this.setName(rs.getString(1));
this.setAddress(rs.getString(2));
this.setEmail(rs.getString(3));
this.setCpf(rs.getString(4));
}
} finally {
rs.close();
}

246

Captulo 16 Descobrindo Enterprise JavaBeans


} finally {
stmt.close();
}
} finally {
connection.close();
}
} catch (Exception e) {
throw new FinderException(Error finding object by id: + cpf);
}
return this.cpf;
}

O mtodo ejbLoad() executado pelo container quando este deseja carregar os dados do objeto do meio persistente e mant-lo em memria. Tambm no retorna
nenhum valor, somente atualiza os dados do objeto atual. A implementao tambm
trivial realizando as mesmas operaes dos mtodos de persistncia anteriores.

public void ejbLoad() {


try {
connection = getConnection();
try {
PreparedStatement stmt = connection.prepareStatement(
SELECT_QUERY);
try {
stmt.setString(1, this.cpf);
ResultSet rs = stmt.executeQuery();
try {
if (rs.next()) {
this.setName(rs.getString(1));
this.setAddress(rs.getString(2));
this.setEmail(rs.getString(3));
}
} finally {
rs.close();
}
} finally {
stmt.close();
}
} finally {
connection.close();

247

J2EE Primeiros Passos


}
} catch (Exception e) {
throw new EJBException(Error loading objects.);
}
}

O mtodo ejbStore() tambm no apresenta nenhuma complexidade e muito parecido com o mtodo anterior. Este mtodo responsvel por atualizar os dados do
objeto em memria no meio persistente, isto , para cada atributo configurado no
objeto em memria, este objeto executado para manter o sincronismo com os dados persistentes. Observe que este mtodo executa a operao contrria do mtodo
ejbLoad().

public void ejbStore() {


try {
connection = getConnection();
try {
PreparedStatement stmt = connection.prepareStatement(
UPDATE_QUERY);
try {
stmt.setString(1, this.name);
stmt.setString(2, this.address);
stmt.setString(3, this.email);
stmt.setString(4, this.cpf);
stmt.execute();
} finally {
stmt.close();
}
} finally {
connection.close();
}
} catch (Exception e) {
throw new EJBException(Error persisting objects.);
}
}

No iremos detalhar os mtodos ejbActivate() e ejbPassivate(), pois os mesmos no


apresentam implementao. Os mtodos setters e getters tambm no sero explorados por no apresentarem nenhuma dificuldade. Tambm suprimimos os mtodos
setEntityContext() e unsetEntityContext() pelos mesmos motivos.

248

Captulo 16 Descobrindo Enterprise JavaBeans


Por fim observamos o deployment descriptor do EJB Entity Bean BMP User Bean, o
qual apresenta algumas particularidades e diferenas em relao aos anteriores EJB
Session Bean.
Observe que a tag posterior a <enterprise-beans> a tag <entity>, informando que os
dados que seguem iro informar detalhes de um EJB Entity Bean. As linhas iniciais
so as mesmas, definindo o nome do EJB a ser mostrado e o nome utilizado pelo
container para referenciar o EJB.
Aps so informados os nomes das interfaces Home, Remote, LocalHome e Local e o
nome da classe que implementa o EJB. A seguir o tipo de persistncia utilizado para
um EJB Entity Bean que podem ser Bean ou Container. No nosso caso, como implementamos os mtodos de persistncia do EJB, esta deve ser configurada como Bean.
Depois devemos informar qual a classe da chave primria do EJB. Vemos que neste
caso a classe uma classe da API Java, mas poderia ser uma classe definida para a
aplicao. Por fim, a tag <reentrant> define se o EJB pode chamar outro EJB.
Os atributos de transao no mudaram, sendo iguais aos dos EJB Session Beans.

<?xml version=1.0" encoding=UTF-8"?>


<!DOCTYPE ejb-jar PUBLIC -//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//
EN http://java.sun.com/dtd/ejb-jar_2_0.dtd>
<ejb-jar>
<enterprise-beans>
<entity>
<display-name>User</display-name>
<ejb-name>User</ejb-name>
local-home>

<local-home>com.novatec.book.project.ejb.entity.impl.UserLocalHome</
<local>com.novatec.book.project.ejb.entity.impl.UserLocal</local>
<ejb-class>com.novatec.book.project.ejb.entity.impl.UserBean</ejb-class>
<persistence-type>Bean</persistence-type>
<prim-key-class>java.lang.String</prim-key-class>
<reentrant>False</reentrant>

</entity>
</enterprise-beans>

249

J2EE Primeiros Passos

16.6 Criando um Entity Bean CMP


Vamos agora analisar os detalhes da implementao do EJB Entity Bean CMP ProductBean. Este EJB apresenta as interfaces LocalHome e Local que so ProductLocalHome e ProductLocal, alm da classe de implementao do EJB ProductBean e seu deployment descriptor. H uma novidade para este EJB. Implementamos a classe da
chave primria que se chamada ProductPK.
A seguir vemos um trecho do cdigo da interface LocalHome - ProductLocalHome.
Ela define os mtodos de ciclo de vida do EJB tais como o create(), que recebe como
parmetros os valores a serem persistidos no banco de dados e tambm declara as
excees CreateException, quando ocorre algum erro na criao do objeto. Define
tambm os mtodos conhecidos como finders, utilizados para localizar objetos j
persistidos. Neste caso, definimos o mtodo padro findByPrimaryKey() e o mtodo
findAll() informando qual o valor da chave primria do objeto que deseja-se localizar.
Este mtodo tambm declara as excees FinderException, para erros na localizao
do objeto no meio persistente.
public interface ProductLocalHome extends javax.ejb.EJBLocalHome {
ProductLocal create(String name, String description, Double price, Integer id)
throws CreateException;
ProductLocal findByPrimaryKey(Integer id) throws FinderException;
}

A interface Local ProductLocal apresenta os mtodos de negcio do EJB. Neste somente declaramos os mtodos getters e setters para o EJB Entity Bean CMP ProductBean. No iremos detalh-los, pois so muito simples.
Logo a seguir apresentamos a implementao da classe de chave primria, utilizada
para o EJB ProductBean. Esta classe tambm no apresenta nenhuma complexidade,
somente apresentando os atributos de chave primria que no caso somente um
identificador.

public class ProductPK implements Serializable {

O prximo cdigo apresenta a implementao do EJB Entity Bean CMP - Product


Bean - propriamente dito. Veremos que tambm no apresenta muita complexidade,
pois os mtodos de persistncia e manuteno do objeto so implementadas pelo
container do servidor de aplicaes, tirando essa responsabilidade do implementador, assim no havendo cdigos para estes mtodos.
A classe deve ser declarada como abstrata, pois o container ir implement-la quando esta for instalada no servidor de aplicaes.

250

Captulo 16 Descobrindo Enterprise JavaBeans

abstract public class ProductBean implements EntityBean {

Observe que o mtodo ejbCreate() somente configura os atributos do objeto. A persistncia dos seus dados fica a cargo do container.

id)

public Integer ejbCreate(String name, String description, Double price, Integer


throws CreateException {
setName(name);
setDescription(description);
setPrice(price);
setId(id);
return null;
}

Veja tambm que os mtodos de manipulao do objeto tais como ejbRemove(), ejbLoad() e ejbStore() so desprovidos de implementao, ficando tambm a cargo do
container esta tarefa. Os mtodos de negcio tambm no apresentam implementao, mas a diferena para os mtodos de ciclo de vida que devem ser declarados
como abstratos, pois sero implementados pelo prprio container.

public void ejbRemove() throws RemoveException {


}

public void ejbLoad() {


}

public void ejbStore() {


}

public abstract void setName(String name);


public abstract void setDescription(String description);
public abstract void setPrice(Double price);
public abstract void setId(Integer id);
public abstract String getName();
public abstract String getDescription();
public abstract Double getPrice();
public abstract Integer getId();

251

J2EE Primeiros Passos


O deployment descriptor do EJB Entity Bean CMP Product Bean no traz muitas novidades em relao ao EJB Entity Bean BMP UserBean. Uma das poucas diferenas
deste que o tipo de persistncia do EJB deve ser configurado como Container, pois
ficar a cargo deste realizar a persistncia. Informamos tambm a classe da chave
primria, que neste caso ser a classe que implementamos exclusivamente para esse
propsito. A seguir vemos a definio da verso de CMP que no nosso caso utilizamos a verso 2.x e a seguir o nome abstrato do esquema, utilizado para as consultas
EQL. Por fim definimos cada campo CMP. Estes campos devem ter os mesmos nomes
dos contidos na implementao do EJB. A ltima linha define qual o nome do atributo que ser utilizado como chave para a persistncia do objeto.
A configurao dos tipos de transao para cada mtodo, segue a mesma configurao utilizada para os outros EJBs anteriores.

<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.Integer</prim-key-class>
<reentrant>False</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>Product</abstract-schema-name>
<cmp-field>
<field-name>name</field-name>
</cmp-field>
<cmp-field>
<field-name>description</field-name>
</cmp-field>
<cmp-field>
<field-name>price</field-name>
</cmp-field>
<cmp-field>
<field-name>id</field-name>
</cmp-field>
<primkey-field>id</primkey-field>
<query>
<query-method>
<method-name>findAll</method-name>
<method-params/>
</query-method>
<ejb-ql>SELECT OBJECT(p) FROM Product p</ejb-ql>
</query>
</entity>

252

Captulo 16 Descobrindo Enterprise JavaBeans

16.7 Criando um Message-Driven Bean


O prximo EJB a ser comentado ser o EJB Message-Driven Bean UserNotifierBean.
Como vimos nos tpicos tericos deste tipo de EJB, o mesmo no necessita da definio de interfaces como nos EJB Session Bean e EJB Entity Bean. O que devemos fazer
implementar a classe do EJB que servir como consumidor de mensagens e a mensagem propriamente dita, sendo que esta ltima pode ser utilizada como uma das
implementaes definidas pela API Java.
Vamos analisar o EJB UserNotifierBean, que nos apresentar algumas diferenas dos
outros exemplos apresentados anteriormente.
Vemos inicialmente que a classe deve implementar a interface MessageDrivenBean e
a interface MessageListener. A primeira interface utilizada pelo container para tratar
do ciclo de vida do EJB, tais como as interfaces SessionBean e EntityBean. A segunda
interface utilizada para definir a classe como um consumidor de mensagens. Nesta
interface est declarado o mtodo onMessage(), o qual veremos sua implementao
logo a seguir.

public class UserNotifierBean implements MessageDrivenBean, MessageListener {

Os EJBs do tipo Message-Driven Bean somente definem os mtodos de ciclo de vida


ejbCreate() e ejbRemove(). Os mesmos, neste exemplo, esto desprovidos de implementao, por isso no sero detalhados.
O mtodo de negcio importante para a execuo deste tipo de EJB o mtodo
onMessage(). Este mtodo executado assim que mensagens so enviadas pelos produtores de mensagens, isto , os clientes que realizam as chamadas assncronas ao
EJB. Estas mensagens so postadas em um MOM e logo em seguida consumidas pelo
EJB Message-Driven Bean. Para isto, a mensagem enviada como parmetro para o
mtodo onMessage(), que valida a mensagem, recupera os dados contidos nela e
realiza a lgica de negcio necessria.
No nosso exemplo, a mensagem validada verificando se a mesma uma instncia
do tipo de mensagem que estamos esperando receber. Caso isto ocorra, obtemos a
mensagem atravs do mtodo getMessage() da interface Message e realizamos a lgica de negcio, que neste caso ser enviar um email para o usurio que efetuou a
compra dos produtos. Observe que todas as mensagens customizadas, isto , definidas para uma determinada aplicao, devem implementar a interface Message.

public void onMessage(javax.jms.Message msg) {


try {
if (msg instanceof ObjectMessage) {

253

J2EE Primeiros Passos


UserMessage message = (UserMessage) ((ObjectMessage)
msg).getObject();
UserTO user = message.getUser();
this.sendEmail(HOST, user.getEmail(),
Sales Notification, message.getMessage());
}
} catch (Exception ex) {
System.err.println(Error sending email for user. + ex);
}
}

Este EJB tambm apresenta um mtodo privado chamado sendEmail(), no qual


implementado a lgica de envio de emails. Ele no ser detalhado.
A classe que implementa a mensagem UserMessage tambm no ser detalhada, pois
no apresenta uma complexida alta. Somente define atributos que sero utilizados
para carregar os dados da mensagem do produtor para o consumidor, isto , do cliente que est efetuando a chamada assncrona, para o EJB Message-Driven Bean que
executar a operao.
A seguir vemos o deployment descriptor do EJB Message-Driven Bean UserNotifierBean. Nele podemos observar algumas particularidades para este tipo de EJB. Como
define somente a classe de implementao do EJB, nele definimos somente este atributo, alm do nome de visualizao e do nome utilizado pelo container para referenciar o EJB. O tipo de transao tambm definida como nos outros tipos de EJB. A
particularidade do EJB Message-Driven Bean est em definir o destino da mensagem.
Devemos informar qual o tipo de destino utilizado para receber a mensagem, se
Queue ou Topic.

<message-driven>
<display-name>UserNotifier</display-name>
<ejb-name>UserNotifier</ejb-name>
<ejb-class>com.novatec.book.project.ejb.mdb.UserNotifierBean</ejb-class>
<transaction-type>Container</transaction-type>
<message-driven-destination>
<destination-type>javax.jms.Queue</destination-type>
</message-driven-destination>
</message-driven>

254

Captulo 16 Descobrindo Enterprise JavaBeans

16.8 Empacotando a aplicao


Para empacotar a aplicao, podemos faz-la de vrias formas. Podemos utilizar os
empacotadores do prprio J2SDK e J2SDKEE que so o jar e o packager respectivamente ou utilizar do ANT (jakarta.apache.org/ant), ferramenta de build muito utilizada no meio Java para criar makefiles.
Utilizaremos um arquivo de build do ANT para realizar tal operao. Instale o ANT
em sua mquina e configure a varivel de ambiente ANT_HOME e a varivel PATH
com ANT_HOME/bin. Execute os targets definidos no build abaixo para as operaes desejadas. Observe que o intuito deste tpico no de explicar as particularidades dessa ferramenta. Para maiores detalhes acesse o site do projeto Ant.
.A seguir apresentamos o arquivo build.xml, utilizado como makefile para compilar a
aplicao, gerar documentao, criar os pacotes (jar) e a aplicao Enterprise (ear).

Build File : build.xml


<?xml version=1.0" encoding=ISO-8859-1"?>
<project name=book-project default=help basedir=..>
<property name=debug

value=off/>

<property name=output

location=build/output/>

<property name=out-classes

location=${output}/classes/>

<property name=out-lib

location=${output}/lib/>

<property name=javadoc

location=${output}/doc/api/>

<property name=packages

location=${output}/packages/>

<property name=lib

location=lib/>

<property name=src

location=src/java/>

<property name=descriptors

location=etc/descriptors/>

<! Targets utilizados neste build.xml >


<target name=help>
<echo message=*** Build File ***/>
<echo message=Use um dos seguintes targets (alvos):/>
<echo message=/>
<echo message=help ____________ Mostra esta mensagem!/>
<echo message=clean ___________ Remove estrutura antiga de deploy/>
<echo message=compile _________ Compila as classes do projeto/>
<echo message=build ___________ Gera os pacotes da aplicao/>
>

<echo message=doc _____________ Gera javadoc e empacota em arquivo compactado/


<echo message=/>
</target>

255

J2EE Primeiros Passos


<! Define o Classpath padro >
<path id=classpath>
<fileset dir=${lib} includes=**/*.jar/>
</path>

<! Limpa o build anterior >


<target name=clean>
<delete dir=${output}/>
<delete dir=${package}/>
<delete dir=${project}/>
</target>

<! Compila as classes do projeto >


<target name=compile depends=clean>
<mkdir dir=${out-classes}/>
<javac srcdir=${src} classpathref=classpath destdir=${out-classes}
debug=${debug}
encoding=ISO8859-1"/>
</target>

<! Cria os arquivos JAR e EAR do sistema >


<target name=build depends=compile>
<mkdir dir=${out-lib}/>
<jar jarfile=${out-lib}/book-project.jar>
<fileset dir=${out-classes}/>
</jar>

<jar jarfile=${out-lib}/book-project-ejb.jar
manifest=${descriptors}/book-project-ejb.jar/META-INF/MANIFEST.MF>
<fileset dir=${descriptors}/book-project-ejb.jar/>
<fileset dir=${out-classes}>
<exclude name=**/delegate/**/>
<exclude name=**/client/**/>
</fileset>
</jar>

<copy todir=${out-lib}>
<fileset dir=${lib}/>
</copy>

<mkdir dir=${packages}/>

256

Captulo 16 Descobrindo Enterprise JavaBeans


<ear destfile=${packages}/book-project-ear.ear
appxml=${descriptors}/book-project-ear.ear/META-INF/
application.xml>
<fileset dir=${out-lib} includes=*.jar excludes=j2ee.jar/>
</ear>

<zip zipfile=${output}/book-project-bin.zip
basedir=${packages}
excludes=${javadoc}/**
encoding=ASCII/>

</target>

<! Cria a documentao Javadoc do sistema >


<target name=doc>
<mkdir dir=${javadoc}/>
<javadoc packagenames=com.*
sourcepath=src/java
defaultexcludes=yes
destdir=${javadoc}
author=true
version=false
use=false
classpathref=classpath
windowtitle=Book Project>
</javadoc>

<zip zipfile=${output}/Book-project-javadoc.zip
basedir=${javadoc}
encoding=ASCII/>
</target>

</project>

16.9 Instalando a aplicao no servidor J2EE


A instalao de uma aplicao J2EE no servidor de aplicao JBoss no uma tarefa
muito difcil nem complexa. Configuraes adicionais no prprio servidor de aplicao no sero necessrias, pois no utilizamos recursos adicionais, mas se isso fosse
preciso tambm no seria uma operao muito complexa. Caso ocorra algum problema na instalao da aplicao no servidor de aplicaes JBoss, consulte a sua documentao no site (www.jboss.org).

257

J2EE Primeiros Passos


Tendo em mos o arquivo EAR, a nica tarefa que devemos realizar a cpia do
Enterprise Archive no diretrio de deploy do JBoss. Devemos nos certificar de executar o JBoss com as configuraes padres, isto , executar o comando
<Dir_Instalao_JBoss>/bin/run ou <Dir_Instalao_JBoss>/bin/run - c default, que
inicializar o servidor em seu modo de configurao padro. Sendo assim, podemos
realizar o deploy da aplicao, somente copiando o arquivo para o diretrio
<Dir_Instalao_JBoss>/server/default/deploy.
Algumas informaes sobre o deploy sero impressas no console do JBoss, detalhando a instalao do pacote. Por fim, se nenhum problema no arquivo EAR for detectado pelo servidor de aplicao, a mensagem de deploy realizado com sucesso ser
impressa no console.
Observe que o servidor de aplicaes JBoss pode ser configurado para inicializar
com servios e recursos a mais ou a menos. A instalao padro sem configuraes
adicionais, nos apresenta trs modos de configurao fornecidos pelo servidor de
aplicao. A configurao recomendvel a ser utilizada para a execuo da aplicao
exemplo deste livro a configurao default. Para maiores detalhes sobre as outras
configuraes ou configuraes customizadas, consulte a documentao do servidor
de aplicao.

258

Captulo 17
Deployment Descriptor
Neste captulo faremos uma breve explicao dos elementos do descritor utilizado
para os mdulos de componentes EJB ejb-jar.xml. Para maiores detalhes sobre este
descritor, consulte a especificao EJB 2.x.

17.1 O que um deployment descriptor?


Deployment descriptors ou arquivos descritores so utilizados pelos componentes
da arquitetura J2EE para definir seus detalhes, informaes que so usadas pelo container para gerenciar esses objetos.
Existem vrios tipos de descritores, um diferente do outro e especficos para cada
tipo de componente.
So alguns exemplos de descritores:
web.xml para componentes Web;
ejb-jar.xml para componentes EJB;
application.xml para o empacotamente de aplicaes enterprise etc.
Para componentes EJB por exemplo, se faz necessrio o uso de um arquivo denominado ejb-jar.xml, especificado pela Sun MicroSystems Inc. para aplicaes enterprise
e que apresenta informaes dos componentes EJB tais como Session Bean, Entity
Bean e Message-Driven Bean. Alm disso, apresenta formas de definir o escopo da
transao na qual ir sobreviver o EJB, segurana e autenticao, relacionamentos
entre Entity Beans, tipo de sesso, persistncia dos Entity Beans, consultas em EQL
para Entity Beans, tipos de Session Bean, recursos remotos ou locais localizados atravs de JNDI, referncias para EJBs entre outros.
A seguir veremos mais detalhes do deployment descriptor ejb-jar.xml.

259

J2EE Primeiros Passos

17.2 Elementos do deployment descriptor ejb-jar.xml


O deployment descriptor de um pacote de componentes EJB, deve ter o nome de
ejb-jar.xml e estar no diretrio META-INF da aplicao. Este arquivo ser empacotado
juntamente com componentes EJB e suas classes auxiliares..
Este arquivo tem sua estrutura definida por um DTD (Document Type Definition).
Iremos apresentar uma breve explicao de cada elemento e atributo do deployment
descriptor ejb-jar.xml. Para maiores detalhes, consulte o DTD ejb-jar_2_0.dtd.
O arquivo em questo, deve ter como linha inicial com a seguinte declarao:
<!DOCTYPE ejb-jar PUBLIC -//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0
//EN http://java.sun.com/dtd/ejb-jar_2_0.dtd>

Elemento ejb-jar
O elemento raiz do deployment descriptor ejb-jar.xml o elemento <ejb-jar>. A seguir
iremos detalhar seus atributos e elementos.
<ejb-jar>
<description></description>
<display-name></display-name>
<small-icon></small-icon>
<large-icon></large-icon>
<enterprise-beans></enterprise-beans>
<relationships></relationships>
<assembly-descriptor></assembly-descriptor>
<ejb-client-jar></ejb-client-jar>
</ejb-jar>

260

Item

Descrio

<description>

Atributo que apresenta a descrio do pacote EJB.

<display-name>

Atributo com nome do mdulo de EJB a ser utilizado por outras


ferramentas para referenciar este pacote.

<small-icon>

Atributo com o caminho completo de uma figura que ser utilizada


como um cone pelas ferramentas que manipularo este mdulo.
16x16 pixels.

<large-icon>

Atributo como o small-icon, sendo que o tamanho da cone maior.


32x32 pixels.

<enterprise-beans>

Elemento que define as informaes dos EJBs contidos no mdulo.


Neste elemento constam as informaes de cada EJB Session Bean,
Entity Bean e Message-Driven Bean.

Captulo 17 Deployment Descriptor


<relationships>

Elemento que apresenta os relacionamentos entre os EJB Entity


Bean CMP.

<assembly-descriptor>

Elemento que define as informaes de segurana e transaes.

<ejb-client-jar>

Elemento usado para contr o nome do pacote com as classe para


acesso remoto aos EJBs.

Elemento enterprise-beans
O elemento <enterprise-beans> define informaes de cada tipo de EJB, tais como,
Session Bean, Entity Bean e Message-Driven Bean, e no possui atributos. A seguir
iremos detalhar seus elementos.
<enterprise-beans>
<session></session>
<entity></entity>
<message-driven></message-driven>
</enterprise-beans>

Sub-elemento session
O sub-elemento <session> define informaes para os EJBs Session Bean contidos no
arquivo de deploy, sendo assim, podemos ter vrias ocorrncias deste elemento. A
sua declarao apresenta alguns atributos e elementos.
<session>
<description></description>
<display-name></display-name>
<small-icon></small-icon>
<large-icon></large-icon>
<ejb-name></ejb-name>
<home></home>
<remote></remote>
<local-home></local-home>
<local></local>
<ejb-class></ejb-class>
<session-type></session-type>
<transaction-type></transaction-type>
<env-entry></env-entry>
<ejb-ref></ejb-ref>
<ejb-local-ref></ejb-local-ref>
<security-role-ref></security-role-ref>
<security-identity></security-identity>

261

J2EE Primeiros Passos


<resource-ref></resource-ref>
<resource-env-entry></resource-env-entry>
</session>

Item

Descri0

<description>

Descrio do EJB Session Bean.

<display-name>

Nome utilizado pelo container para se referir ao EJB.

<small-icon>

Caminho completo de uma figura que ser utilizada como um cone pelas
ferramentas, para este EJB.

<large-icon>

Caminho completo de uma figura que ser utilizada como um cone pelas
ferramentas, para este EJB.

<ejb-name>

Nome do EJB, utilizado posteriormente dentro do prprio deployment


descriptor para referenciar este EJB.

<home>

Nome completo da interface Home do EJB.

<remote>

Nome completo da interface Remote do EJB.

<local-home>

Nome completo da interface LocalHome do EJB.

<local>

Nome completo da interface Local do EJB.

<ejb-class>

Nome completo da classe que implementa o EJB.

<session-type>

Tipo de EJB Session Bean. Pode ser Stateless ou Stateful.

<transaction-type>

Define quem gerenciar a transao. Pode ser Bean ou Container.

<env-entry>

Define propriedades de ambiente para o EJB.

<ejb-ref>

Declara referncias para outros EJBs.

<ejb-local-ref>

Declara referncias locais para outros EJBs.

<security-role-ref>

Declara referncia para regras de segurana para este EJB.

<security-identity>

Informa como propagar o contexto de segurana.

<resource-ref>

Declara referncia para recursos que podem ser utilizados pelos EJBs.

<resource-env-entry> Associa os recursos com nome JNDI.

Sub-elemento entity
O sub-elemento <entity> apresenta informaes do EJB Entity Bean e tambm pode
ocorrer mais de uma vez no arquivo de deploy. Alm de apresentar informaes do
EJB, pode definir as querys utilizadas pelo container para um EJB CMP.
<entity>
<description></description>
<display-name></display-name>

262

Captulo 17 Deployment Descriptor


<small-icon></small-icon>
<large-icon></large-icon>
<ejb-name></ejb-name>
<home></home>
<remote></remote>
<local-home></local-home>
<local></local>
<ejb-class></ejb-class>
<persistence-type></persistence-type>
<prim-key-class></prim-key-class>
<reentrant></reentrant>
<cmp-version></cmp-version>
<abstract-schema-name></abstract-schema-name>
<cmp-field></cmp-field>
<primkey-field></primkey-field>
<env-entry></env-entry>
<ejb-ref></ejb-ref>
<ejb-local-ref></ejb-local-ref>
<security-role-ref></security-role-ref>
<security-identity></security-identity>
<resource-ref></resource-ref>
<resource-env-entry></resource-env-entry>
<query></query>
</entity>

Item

Descrio

<description>

Descrio do EJB Entity Bean.

<display-name>

Nome utilizado pelo container para se referir ao EJB em questo.

<small-icon>

Caminho completo de uma figura que ser utilizada como um cone


pelas ferramentas, para este EJB.

<large-icon>

Caminho completo de uma figura que ser utilizada como um cone


pelas ferramentas, para este EJB.

<ejb-name>

Nome do EJB, utilizado posteriormente dentro do prprio deployment


descriptor para referenciar este EJB.

<home>

Nome completo da interface Home do EJB.

<remote>

Nome completo da interface Remote do EJB.

<local-home>

Nome completo da interface LocalHome do EJB.

<local>

Nome completo da interface Local do EJB.

<ejb-class>

Nome completo da classe que implementa o EJB.

263

J2EE Primeiros Passos


<persistence-type>

Tipo de persistncia do objeto. Pode ser BMP ou CMP.

<prim-key-class>

Nome completo da classe que define a chave primria da entidade.

<reentrant>

Pode ser True ou False.

<cmp-version>

Verso de CMP. Depende da implementao do servidor de aplicao.


Pode ser 1.x ou 2.x.

<abstract-schema-name> Nome do objeto utilizado adiante para criar em EQL, formas de


consulta e manipulao do objeto em questo.
<cmp-field>

Apresenta todos os campos de um EJB Entity Bean CMP que sero


persistidos.

<primkey-field>

Campo de um EJB Entity Bean CMP que ser considerado como


chave primria.

<env-entry>

Define propriedades de ambiente para o EJB.

<ejb-ref>

Declara referncias para outros EJBs.

<ejb-local-ref>

Declara referncias locais para outros EJBs.

<security-role-ref>

Declara referncia para regras de segurana para este EJB.

<security-identity>

Informa como propagar o contexto de segurana.

<resource-ref>

Declara referncia para recursos que podem ser utilizados pelos


EJBs.

<resource-env-entry>

Associa os recursos com nome JNDI.

<query>

Apresenta uma lista de cdigos de manipulao de objetos, utilizado


para EJB Entity Bean CMP, utilizando a linguagem EQL (EJB Query
Language).

Sub-elemento message-driven
O sub-elemento <message-driven> define as informaes do EJB Message-Driven
Bean. Como nos outros casos, o arquivo de deploy pode conter mais de uma ocorrncia deste elemento, isto , no caso de deploy de mais de um EJB. A seguir os seus
atributos e elementos.
<message-driven>
<description></description>
<display-name></display-name>
<small-icon></small-icon>
<large-icon></large-icon>
<ejb-name></ejb-name>
<ejb-class></ejb-class>
<transaction-type></transaction-type>

264

Captulo 17 Deployment Descriptor


<message-selector></message-selector>
<acknowledge-mode></acknowledge-mode>
<message-driven-destination></message-driven-destination>
<env-entry></env-entry>
<ejb-ref></ejb-ref>
<ejb-local-ref></ejb-local-ref>
<security-identity></security-identity>
<resource-ref></resource-ref>
<resource-env-entry></resource-env-entry>
</message-driven>

Item

Descrio

<description>

Descrio do EJB Message-Driven Bean.

<display-name>

Nome utilizado pelo container para se referir ao EJB.

<small-icon>

Caminho completo de uma figura que ser utilizada como um cone


pelas ferramentas, para este EJB.

<large-icon>

Caminho completo de uma figura que ser utilizada como um cone


pelas ferramentas, para este EJB.

<ejb-name>

Nome do EJB, utilizado posteriomente dentro do prrprio deployment


descriptor para referenciar este EJB.

<ejb-class>

Nome completo da classe que implmenta o EJB em questo.

<transaction-type>

Define quem gerenciar a transao. Pode ser Bean ou Container.

<message-selector>

Filtra mensagens baseadas no seletor de strings do JMS.

<acknowledge-mode>

Especifica como sero as mensagens de confirmao (acknowledge).


Pode ser Auto-acknowledge ou Dups-ok-acknowledge.

<message-driven-destination>
Define o tipo de destino da mensagem que pode ser javax.jms.Queue
ou javax.jms.Topic. Alm de definir a durabilidade do envio da
mensagem que pode ser Durable ou NonDurable.
<env-entry>

Define propriedades de ambiente para o EJB em questo.

<ejb-ref>

Declara referncias para outros EJBs.

<ejb-local-ref>

Declara referncias locais para outros EJBs.

<security-identity>

Informa como propagar o contexto de segurana.

<resource-ref>

Declara referncia para recursos que podem ser utilizados pelos


EJBs.

<resource-env-entry>

Associa os recursos com nome JNDI.

265

J2EE Primeiros Passos

Elemento relationships
O elemento <relationships> apresenta o relacionamento entre EJBs Entity Bean CMP,
sendo que podem ocorrer nenhum, um ou mais relacionamentos entre EJBs deste
tipo. Define outro elemento, <ejb-relation> no qual so configurados cada relacionamento entre dois EJBs.
<relationships>
<description></description>
<ejb-relation>
<description></description>
<ejb-relation-name></ejb-relation-name>
<ejb-relationship-role>
<description></description>
<ejb-relationship-role-name></ejb-relationship-role-name>
<multiplicity></multiplicity>
<relationship-role-source>
<description></description>
<ejb-name></ejb-name>
</relationship-role-source>
<cmr-field>
<description></description>
<cmr-field-name></cmr-field-name>
<cmr-field-type></cmr-field-type>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<description></description>
<ejb-relationship-role-name></ejb-relationship-role-name>
<multiplicity></multiplicity>
<cascade-delete></cascade-delete>
<relationship-role-source>
<description></description>
<ejb-name></ejb-name>
</relationship-role-source>
<cmr-field>
<description></description>
<cmr-field-name></cmr-field-name>
<cmr-field-type></cmr-field-type>
</cmr-field>
</ejb-relationship-role>

266

Captulo 17 Deployment Descriptor


</ejb-relation>
<relationships>

A seguir vemos uma breve explicao dos atributos do elemento <relationships>.


<description>

Descrio do relacionamento entre EJB Entity Bean CMP.

<ejb-relation>

Define o relacionamento entre dois EJB Entity Bean CMP.

Sub-elemento <ejb-relation> do elemento <relationships> que define define o relacionamento entre dois EJB Entity Bean CMP.
<description>

Descrio do relacionamento entre dois EJB Entity Bean CMP.

<ejb-relation-name>

Nome do relacionamento.

<ejb-relationship-role>

Elemento que deve ser configurado para cada um dos dois EJBs que
possuem o relacionamento.

Sub-elemento ejb-relationship-role
Sub-elemento <ejb-relationship-role> do elemento <ejb-relation> que descreve um regra de
relacionamento dentre dois EJBs.
<description>

Descrio da regra de relacionamento.

<ejb-relationship-role-name> Nome da regra de relacionamento.


<multiplicity>

Multiplicidade do relacionamento. Pode ser One ou Many.

<cascade-delete>

Define se o relacionamento de um para muitos de um EJB Entity


Bean CMP dependente da vida do outro EJB. Sendo assim, s
pode ser configurado para o EJB Entity Bean com multiplicidade
um (One) no relacionamento.

<relationship-role-source>

Define qual EJB estar relacionando com este.

<cmr-field>

Define qual o campo utilizado para o relacionamento. Apresenta


atributos que definem a descrio do campo de relaciomento, o
nome do campo propriamente dito e o tipo do campo.

Elemento assembly-descriptor
O elemento <assembly-descriptor> define as regras de segurana, a permisso de
acesso (execuo) dos mtodos dos EJBs, atributos de transao para cada mtodo
de cada EJB e a lista dos mtodos excludos do deploy.
<assembly-descriptor>
<security-role>
<description/>
<role-name></role-name>

267

J2EE Primeiros Passos


</security-role>
<method-permission>
<role-name></role-name>
<method>
<description/>
<ejb-name></ejb-name>
<method-intf></method-intf>
<method-name></method-name>
<method-params></method-params>
</method>
</method-permission>
<container-transaction>
<description/>
<method>
<ejb-name></ejb-name>
<method-name></method-name>
</method>
<trans-attribute></trans-attribute>
</container-transaction>
</assembly-descriptor>

Item

Descrio

<security-role>

Define a regra de segurana utilizada para acesso aos EJBs. Como


atributos define uma descrio da regra de segurana e o nome da
regra propriamente dita.

<method-permission>

Quais mtodos podem ser acessados por quem a partir da regra de


segurana definida em <security-role>. Para cada mtodo, informase o nome do EJB que o contm, alm de informar se este mtodo
acessado para alguma interface, o seu nome e os parmetros que ele
recebe. Pode-se definir uma regra para todos os mtodos de um EJB,
utilizando o asterisco (*) no elemento <method-name>, por exemplo.
Este elemento pode aparecer quantas vezes for necessrio, para
configurar uma regra de segurana para um mtodo de um EJB.

<container-transaction> Define atributos de transao para cada mtodo de cada EJB. Pode
conter um atributo que descreve a transao e deve conter para cada
mtodo o nome do EJB e o nome do mtodo que ser utilizado um tipo
de transao, configurada no elemento <trans-attribute>.

<exclude-list>

268

Lista dos mtodos excludos do deploy. Apresenta um atributo com a


descrio da lista de excluso e um elemento que contm o nome de
cada mtodo de cada EJB que ser excludo do deploy.

Captulo 18
API Enterprise JavaBeans
Este captulo apresenta um guia de referncia rpida para a API Enterprise JavaBeans.
Observe que a API da plataforma J2EE muita mais extensa, sendo que esta apresentada neste tpico somente uma parte dela. No visamos tambm explicar em detalhes a API EJB. Para detalhes consulte a documentao oficial da API e a especificao
EJB 2.0.
Iremos apresentar o pacote javax.ejb explicando as suas interfaces e excees.

18.1 Interfaces
EJBContext
A interface EJBContext extendida pelos contextos de cada tipo de EJB, isto , pelas
interfaces SessionContext, EntityContext e MessageDrivenContext. Fornece informaes de segurana, transao e dados sobre as interfaces Home (Local e Remote) do
EJB, sendo possvel utiliz-la para criar, destruir ou localizar um objeto EJB por exemplo.
public interface EJBContext {
EJBHome getEJBHome();
EJBLocalHome getEJBLocalHome();
Properties getEnvironment();
Identity getCallerIdentity();
Principal getCallerPrincipal();
boolean isCallerInRole(Identity role);
boolean isCallerInRole(String roleName);
UserTransaction getUserTransaction() throws IllegalStateException;
void setRollbackOnly() throws IllegalStateException;
boolean getRollbackOnly() throws IllegalStateException;
}

269

J2EE Primeiros Passos

EJBHome
Esta interface deve ser extendida pelas interfaces Home (acesso Remoto - Home) dos
componentes EJBs implementados. Ela oferece servios para criao, remoo e localizao de objetos EJB. Oferece informaes sobre o meta-dados do EJB e o handle
do EJB, que pode ser utilizado para futuras chamadas de mtodos ao objeto, sem a
necessidade de realizar a sua localizao por exemplo.
public interface EJBHome extends Remote {
void remove(Handle handle) throws RemoteException, RemoveException;
void remove(Object primaryKey) throws RemoteException, RemoveException;
EJBMetaData getEJBMetaData() throws RemoteException;
HomeHandle getHomeHandle() throws RemoteException;
}

EJBLocalHome
Deve ser extendida pelas interfaces Home (acesso Local - LocalHome) dos componentes EJBs. Apresenta servios de criao, remoo e localizao dos objetos EJB.
public interface EJBLocalHome {
void remove(Object primaryKey) throws RemoveException, EJBException;
}

EJBLocalObject
A interface EJBLocalObject deve ser extendida pela interface Local (acesso Local Remote) para os EJBs que provm acessos locais. Apresenta mtodos para obter referncia para a interface LocalHome e obter a chave-primria (Primary Key) do objeto
caso o mesmo seja um EJB Entity Bean. Alm de prover um mtodo para destruir a
instncia do objeto e um servio que avalia se o objeto atual, isto , o EJBLocalObject
idntico a outro informado.
Quando definir a interface Local para um componente EJB, a mesma deve conter os
mtodos de negcio que estaro disponveis para o cliente local.
public interface EJBLocalObject {
public EJBLocalHome getEJBLocalHome() throws EJBException;
public Object getPrimaryKey() throws EJBException;
public void remove() throws RemoveException, EJBException;
boolean isIdentical(EJBLocalObject obj) throws EJBException;
}

270

Captulo 18 API Enterprise JavaBeans

EJBMetaData
Permite que o cliente acesse informaes dos metadados do EJB. Esta interface no
muito utilizada, mas pode ser obtida atravs da chamada ao mtodo
ejbHome.getEJBMetaData(). As informaes contidas nesta interface e fornecidas ao
cliente remoto em forma de um objeto serializado, pode ser utilizado para obter dinamicamente informaes sobre o EJB.
public interface EJBMetaData {
EJBHome getEJBHome();
Class getHomeInterfaceClass();
Class getRemoteInterfaceClass();
Class getPrimaryKeyClass();
boolean isSession();
boolean isStatelessSession();
}

EJBObject
Esta interface deve ser extendida pela interface Remote (acesso remoto) dos componentes EJBs. Apresenta uma viso dos servios oferecidos pelo EJB para o cliente
remoto. A interface Remote definida para cada EJB, deve conter as assinaturas dos
mtodos de negcio que o EJB implementa e as quais o cliente remoto ter acesso.
Por esta interface, o cliente pode ter acesso a referncia para a interface Home do
EJB, obter a chave-primria no caso de EJB Entity Bean, remover a instncia do objeto, obter o Handler deste objeto que contm informaes sobre ele e verificar se
algum objeto idntico ao objeto atual.
public interface EJBObject extends Remote {
public EJBHome getEJBHome() throws RemoteException;
public Object getPrimaryKey() throws RemoteException;
public void remove() throws RemoteException, RemoveException;
public Handle getHandle() throws RemoteException;
boolean isIdentical(EJBObject obj) throws RemoteException;
}

271

J2EE Primeiros Passos

EnterpriseBean
A interface EnterpriseBean a interface genrica de cada tipo de EJB. Ela extendida
pelas interfaces SessionBean, EntityBean e MessageDrivenBean. Alm de ser serializada utilizada como uma interface marker, isto , informa que a interface realmente um EJB.
public interface EnterpriseBean extends java.io.Serializable {
}

EntityBean
Quando implementamos um EJB EntityBean, devemos implementar esta interface.
Apresenta os mtodos de ciclo de vida do EJB, executados pelo container nos momentos apropriados.
Define os mtodos para configurar e desconfigurar o contexto associado ao EJB Entity Bean, mtodo de remoo da entidade persistente, ativao da entidade caso
tenha sido passivada pelo container, passivao da entidade em caso de falta de recursos ou porque muitos EJBs esto instanciados por exemplo, carrega uma entidade
do meio persistente para a memria quando o container precisa atualizar os dados
do objeto, ou atualiza os dados no meio persistente de acordo com os valores dos
atributos constantes em memria.
Alm destes mtodos, se faz necessrio a implementao do mtodo ejbCreate() j
mencionado anteriormente, o qual ir criar a instncia do objeto em memria e persistir o mesmo.
public interface EntityBean extends EnterpriseBean {
public void setEntityContext(EntityContext ctx) throws EJBException,
RemoteException;
public void unsetEntityContext() throws EJBException, RemoteException;
public void ejbRemove() throws RemoveException, EJBException, RemoteException;
public void ejbActivate() throws EJBException, RemoteException;
public void ejbPassivate() throws EJBException, RemoteException;
public void ejbLoad() throws EJBException, RemoteException;
public void ejbStore() throws EJBException, RemoteException;
}

272

Captulo 18 API Enterprise JavaBeans

EntityContext
Apresenta a interface especfica do EJBContext para um EJB Entity Bean. Ela associada ao objeto aps a criao da sua instncia.
public interface EntityContext extends EJBContext {
EJBLocalObject getEJBLocalObject() throws IllegalStateException;
EJBObject getEJBObject() throws IllegalStateException;
Object getPrimaryKey() throws IllegalStateException;
}

Handle
Um Handle uma referncia persistente de um componente EJB. Ela implementada
por todos os EJB Handles. Muito til quando a aplicao necessita persistir a referncia para um objeto EJB e recuper-la posteriormente.
public interface Handle extends java.io.Serializable {
public EJBObject getEJBObject() throws RemoteException;
}

HomeHandle
Tal como o Handle uma referncia persistente para a interface Remote de um EJB, a
HomeHandle uma referncia persistente para interface Home de um EJB. Tambm
til para manter a referncia da interface Home de um EJB, persistente em algum
meio e recuper-la posteriomente para acessar a interface Home.
public interface HomeHandle extends java.io.Serializable {
public EJBHome getEJBHome() throws RemoteException;
}

MessageDrivenBean
Esta interface deve ser implementada por cada EJB Message-Driven Bean. Define os
mtodos de ciclo de vida deste tipo de EJB. Observe que estes mtodos no so executados pelos clientes, pois como este componente tem um comportamento de execuo assncrona por meio de mensagens (JMS), os mtodos so executados pelo
container no recebimento de mensagens dos clientes.

273

J2EE Primeiros Passos


Observe que o nico mtodo de negcio que a implementao de um EJB MessageDriven Bean deve oferecer o mtodo onMessage(), implementado da API JMS. Este
mtodo ser invocado pelo container no recebimento de mensagens dos clientes e
deve executar a lgica de negcio para o EJB em questo.
public interface MessageDrivenBean extends EnterpriseBean {
void setMessageDrivenContext(MessageDrivenContext ctx) throws EJBException;
void ejbRemove() throws EJBException;
}

MessageDrivenContext
Apresenta a interface especfica de EJBContext para um EJB Message-Driven Bean.
Tambm associa o contexto ao EJB, depois que sua instncia criada.
public interface MessageDrivenContext extends EJBContext {
}

SessionBean
Deve ser implementada por todo EJB Session Bean. Apresenta os mtodos do ciclo
de vida do EJB, tais como associao do contexto ao EJB, remoo da instncia do
objeto, ativao e passivao do objeto pelo container, alm de definir o mtodo
ejbCreate() que criar uma instncia do objeto pelo container.
public interface SessionBean extends EnterpriseBean {
void setSessionContext(SessionContext ctx) throws EJBException, RemoteException;
void ejbRemove() throws EJBException, RemoteException;
void ejbActivate() throws EJBException, RemoteException;
void ejbPassivate() throws EJBException, RemoteException;
}

SessionContext
Esta a interface especfica de EJBContext para um EJB Session Bean. Tambm
associada a instncia do objeto aps a sua criao.
public interface SessionContext extends EJBContext {
EJBLocalObject getEJBLocalObject() throws IllegalStateException;
EJBObject getEJBObject() throws IllegalStateException;
}

274

SessionSyncronization
Esta interface pode ser implementada por EJB Session Bean Stateful, quando desejase sincronizar o estado transacional do objeto. Cada mtodo executado a cada etapa das fases de transao.
public interface SessionSynchronization {
public void afterBegin() throws EJBException, RemoteException;
public void beforeCompletion() throws EJBException, RemoteException;
public void afterCompletion(boolean committed) throws EJBException,
RemoteException;
}

18.2 Excees
AccessLocalException
Exceo lanada caso o chamador no possuir acesso para executar o mtodo. Utilizado para objetos locais.

CreateException
Deve ser definida no mtodo de criao da instncia de cada EJB. Ela lanada quando ocorrer uma falha na criao da instncia de um objeto EJB.

DuplicateKeyException
Esta exceo lanada quando no pode-se criar um objeto, pois a sua chave j
existe e est sendo utilizada por outro objeto. Normalmente utilizada no mtodo
create() do EJB Entity Bean.

EJBException
Informa ao objeto chamador que ocorreu uma falha no recupervel, ou um erro
inesperado. lanada quando ocorre erros deste tipo nos mtodos de ciclo de vida
ou nos mtodos de negcio. a nica exceo do pacote javax.ejb que extende a
exceo de runtime - RuntimeException - e no permite ao chamador se recuperar
do erro. As excees NoSuchEntityException, NoSuchObjectLocalException, AccessLocalException, TransactionRequiredLocalException e TransactionRolledbackLocalException extendem esta exceo.

275

J2EE Primeiros Passos

FinderException
Deve ser utilizada em todos os mtodos finders nos EJBs Entity Bean. So lanadas
quando um erro de localizao do objeto ocorre.

NoSuchEntityException
lanada pelo container quando em um EJB Entity Bean executado um mtodo,
para o qual no existe o objeto em questo. Pode ser utilizada pelos mtodos de
negcio do EJB e pelos mtodos de ciclo de vida ejbLoad() e ejbStore() de um EJB
Entity Bean.

NoSuchObjectLocalException
Parecida com a exceo NoSuchEntityException, diferindo que esta lanada para
objetos locais que no existem mais.

ObjectNotFoundException
lanada por um mtodo finder, para avisar que um objeto no existe. Deve-se utilizar esta exceo quando um mtodo finder retornar somente um objeto. No caso de
vrios objetos, deve-se retornar uma coleo nula.

RemoveException
A exceo RemoveException lanada quando o container no pode remover a instncia do objeto. utilizada no mtodo ejbRemove().

TransactionRequiredLocalException
Informa que a requisio no encontrou uma transao e a mesma era requerida.

TransactionRolledbackLocalException
Indica que a transao foi marcada com rollback ou estava sendo executado o rollback, mas ocorreu algum erro nesta operao.

276

Captulo 19
Aplicao J2EE Exemplo
A seguir apresentamos o cdigo completo da aplicao exemplo. Esta aplicao consiste de sete EJBs, sendo um para cada tipo de EJB definido pela especificao EJB
2.0. Ento sero:
EJB Session Bean Stateless SalesSupportBean
EJB Session Bean Stateful SalesBasketBean
EJB Entity Bean BMP UserBean
EJB Session Bean Stateless UserSessionFacade
EJB Entity Bean CMP ProductBean
EJB Sesison Bean Stateless - ProductSessionFacade
Message-Driven Bean UserNotifierBean
Alm dos EJBs, tambm fazem parte da aplicao exemplo os objetos que implementam o Design Pattern TransferObjects ProductTO e UserTO e seus respectivos Assewblers ProductTOAssembler e UserTOAssembler, utilizados pelos componentes,
os Business Delegates ProductDelegate e UserDelegate e o ServiceLocator.
Observe que existe um deployment descriptor ejb-jar.xml para cada EJB nesta aplicao exemplo. Isto no necessrio em uma aplicao J2EE no mdulo EJB. Para realizar o deploy desta aplicao em um servidor de aplicao preciso criar um nico
deployment descritor ejb-jar.xml, no qual inclumos todas as informaes de todos os
EJBs contidos em um mdulo da aplicao J2EE em questo. Este arquivo mostrado
no final deste captulo.
Iremos apresentar tambm o arquivo especfico para o servidor de aplicaes JBoss,
utilizado para criar as tabelas do banco de dados utilizado para persistir os objetos da
aplicao. Este arquivo, chamado de jbosscmp-jdbc.xml est mostrado no final deste
captulo tambm. Salientamos que este arquivo no faz parte da especificao J2EE e
um arquivo complementar e de uso exclusivo para o servidor de aplicaes JBoss.

277

J2EE Primeiros Passos

EJB Session Bean Stateless - SalesSupport


Vejamos o cdigo completo do EJB Session Bean Stateless SalesSupportBean. Apresentamos as interfaces Home e Remote, SalesSupportHome e SalesSupport respectivamente, a implementao do EJB SalesSupportBean e por fim o deployment descriptor ejb-jar.xml deste EJB.

Interface Home : SalesSupportHome.


package com.novatec.book.project.ejb.session;

import javax.ejb.*;
import java.util.*;
import java.rmi.*;

/**
* Inteface Home, obtm uma referncia para a interface Remote, esta
* ultima que fornece os servios de suporte a venda dos produtos.
*/
public interface SalesSupportHome extends javax.ejb.EJBHome {

/**
* Cria uma referncia remota para o componente <code>SalesSupport</code>.
* @return referncia remota para o componente <code>SalesSupport</code>.
* @throws CreateException se ocorrer erro ao criar a instncia.
* @throws RemoteException outros erros na criao da instncia.
*/
SalesSupport create() throws CreateException, RemoteException;
}

Interface Remote : SalesSupport.


package com.novatec.book.project.ejb.session;

import javax.ejb.*;
import java.util.*;
import java.rmi.*;
/**
* Interface Remote do EJB <code>SalesSupport</code>.
* Apresenta servios de clculo de desconto e parcelas
* para um produto em venda.
*/

278

Captulo 19 Aplicao J2EE Exemplo


public interface SalesSupport extends javax.ejb.EJBObject {

/**
* Calcula um desconto para o valor informado, de acordo com a percentual
* informada.
* @param value valor a ser calculado o desconto.
* @param perc percentual utilizado para clculo do desconto.
* @return valor do desconto concedido.
* @throws RemoteException se ocorrer erro ao executar o mtodo.
*/
Double calcDiscount(Double value, Double perc) throws RemoteException;

/**
* Clculo o valor das parcelas, de acordo com o valor total informado e com
* a quantidade de vezes tambm informada.
* @param value valor total da venda.
* @param times quantidade de parcelas desejada.
* @return valor de cada parcela.
* @throws RemoteException se ocorrer erro ao executar o mtodo.
*/
Double calcPiece(Double value, Integer times) throws RemoteException;
}

Session Bean Stateless : SalesSupportBean.


package com.novatec.book.project.ejb.session;

import javax.ejb.*;

/**
* Apresenta os servios para clculo de frete, desconto, valores de parcela
* dependendo da quantidade de vezes que o valor vai ser pago.
* Estes servios so utilizados enquanto estiver sendo realizada a venda
* dos produtos.
*/
public class SalesSupportBean implements SessionBean {

/**
* Contexto do Session Bean.
*/
private SessionContext sessionContext;

279

J2EE Primeiros Passos


/**
* Cria uma instncia do objeto pelo container.
* @throws CreateException exceo na criao da instncia do objeto.
*/
public void ejbCreate() throws CreateException {
}

/**
* Remoo da instncia do objeto pelo container.
*/
public void ejbRemove() {
}

/**
* Utilizado pelo container para ativar o objeto que est passivo.
*/
public void ejbActivate() {
}

/**
* Utilizado pelo container para tornar passivo um objeto ativo.
*/
public void ejbPassivate() {
}

/**
* Configura o contexto do EJB Session Bean.
* @param sessionContext contexto do EJB Session Bean.
*/
public void setSessionContext(SessionContext sessionContext) {
this.sessionContext = sessionContext;
}

/**
* Calcula um desconto para o valor informado, de acordo com a percentual
* informada.
* @param value valor a ser calculado o desconto.
* @param perc percentual utilizado para clculo do desconto.
* @return valor do desconto concedido.
*/

280

Captulo 19 Aplicao J2EE Exemplo


public Double calcDiscount(Double value, Double perc) {
return new Double((value.doubleValue() * perc.doubleValue()) / 100);
}
/**
* Clculo o valor das parcelas, de acordo com o valor total informado e com
* a quantidade de vezes tambm informada.
* @param value valor total da venda.
* @param times quantidade de parcelas desejada.
* @return valor de cada parcela.
*/
public Double calcPiece(Double value, Integer times) {
return new Double(value.doubleValue() / times.intValue());
}
}

Deployment Descriptor : SalesSupportBean.


<?xml version=1.0" encoding=UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC -//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//
EN http://java.sun.com/dtd/ejb-jar_2_0.dtd>
<ejb-jar>
<enterprise-beans>
<session>
<display-name>SalesSupport</display-name>
<ejb-name>SalesSupport</ejb-name>
<home>com.novatec.book.project.ejb.session.SalesSupportHome</home>
<remote>com.novatec.book.project.ejb.session.SalesSupport</remote>
<ejb-class>com.novatec.book.project.ejb.session.SalesSupportBean</ejb-

class>

<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>SalesSupport</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>

281

J2EE Primeiros Passos

EJB Session Bean Stateful - SalesBasket


No prximo cdigo, apresentamos o EJB Session Bean Stateful SalesBasketBean. Inicialmente seguem as interfaces Home e Remote, SalesBasketHome e SalesBasket respectivamente, a implementao do EJB SalesBasketBean e por fim o deployment
descriptor deste EJB.

Interface Home : SalesBasketHome.


package com.novatec.book.project.ejb.session;

import javax.ejb.*;
import java.util.*;
import java.rmi.*;

/**
* Inteface Home, obtm uma referncia para a interface Remote, esta
* ultima que fornece os servios para o carrinho de compras.
*/
public interface SalesBasketHome extends javax.ejb.EJBHome {

/**
* Cria uma referncia remota para o componente <code>SalesBasket</code>.
* @return referncia remota para o componente <code>SalesBasket</code>.
* @throws CreateException se ocorrer erro ao criar a instncia.
* @throws RemoteException outros erros na criao da instncia.
*/
SalesBasket create() throws CreateException, RemoteException;
}

Interface Remote : SalesBasket.


package com.novatec.book.project.ejb.session;

import javax.ejb.*;
import java.util.*;
import java.rmi.*;
import com.novatec.book.project.ejb.to.*;

/**
* Interface Remota da cesta de produtos, apresenta servios que sero utilizados
* na venda dos produtos ao usurio.

282

Captulo 19 Aplicao J2EE Exemplo


* Estes servios so: iniciar e finalizar venda, adicionar e remover produto
* da cesta de produtos, limpar a cesta, calcular o valor total dos produtos etc.
*/
public interface SalesBasket extends javax.ejb.EJBObject {

/**
* Inicia a compra dos produtos para o usurio informado.
* @param user usurio que iniciar a compra dos produtos.
* @throws RemoteException se ocorrer erro ao executar o mtodo.
*/
void initSales(UserTO user) throws RemoteException;

/**
* Finaliza a compra.
* Esta operao persiste os dados da venda, atravs do uso de EJB Entity
* Bean com acesso local e notifica o usurio do sucesso da sua compra.
* @return verdadeiro caso a compra tenha sido realizada com sucesso.
* @throws RemoteException se ocorrer erro ao executar o mtodo.
* @throws Exception exceo na criao do Entity Bean de Produtos.
*/
Boolean finalizeSale() throws Exception, RemoteException;

/**
* Adiciona um produto no carrinho de compras.
* @param product produto a ser inserido no carrinho de compras.
* @throws RemoteException se ocorrer erro ao executar o mtodo.
*/
void addProduct(ProductTO product) throws RemoteException;

/**
* Remove um produto do carrinho de compras.
* @param product produto a ser removido do carrinho de compras.
* @return verdadeiro caso a remoo seja efetivada, falso caso contrrio.
* @throws RemoteException se ocorrer erro ao executar o mtodo.
*/
Boolean removeProduct(ProductTO product) throws RemoteException;

/**
* Calcula o valor dos produtos contidos na cesta e retorna este valor.
* @return valor total do produtos contidos na cesta.

283

J2EE Primeiros Passos


* @throws RemoteException se ocorrer erro ao executar o mtodo.
*/
Double calcBasketPrice() throws RemoteException;

/**
* Remove os produtos da cesta de compras.
* @throws RemoteException se ocorrer erro ao executar o mtodo.
*/
void freeBasket() throws RemoteException;
}

Session Bean Stateful : SalesBasketBean.


package com.novatec.book.project.ejb.session;

import javax.ejb.*;
import java.util.*;

import com.novatec.book.project.ejb.*;
import com.novatec.book.project.ejb.to.*;
import com.novatec.book.project.ejb.entity.*;
import com.novatec.book.project.ejb.entity.impl.ProductPK;

/**
* Apresenta o servio de carrinho, que mantm os produto em venda
* de um determinado usurio.
* Estes produtos so mantidos em uma Map, e podem ser atualizados,
* removidos ou inseridos no carrinho de compras.
* O usurio tambm registrado como proprietrio desta compra.
*/
public class SalesBasketBean implements SessionBean {

/**
* Contexto do Session Bean.
*/
private SessionContext sessionContext;

/**
* Cesta de produtos.
*/
private Map basket;

284

Captulo 19 Aplicao J2EE Exemplo

/**
* Usurio dono desta compra.
*/
private UserTO user;

/**
* Criao da instncia deste objeto pelo container.
* @throws CreateException exceo na criao da instncia do EJB.
*/
public void ejbCreate() throws CreateException {
this.basket = new HashMap();
}

/**
* Remoo da instncia do EJB, pelo container.
*/
public void ejbRemove() {
}

/**
* Utilizado pelo container para ativar o objeto que est passivo.
*/
public void ejbActivate() {
}

/**
* Utilizado pelo container para tornar passivo um objeto ativo.
*/
public void ejbPassivate() {
}

/**
* Configura o contexto do EJB Session Bean.
* @param sessionContext contexto do EJB Session Bean.
*/
public void setSessionContext(SessionContext sessionContext) {
this.sessionContext = sessionContext;
}

285

J2EE Primeiros Passos


/**
* Inicia a compra dos produtos para o usurio informado.
* @param user usurio que iniciar a compra dos produtos.
*/
public void initSales(UserTO user) {
this.user = user;
}

/**
* Finaliza a compra.
* Esta operao persiste os dados da venda, atravs do uso de EJB Entity
* Bean com acesso local e notifica o usurio do sucesso da sua compra.
* @return verdadeiro caso a compra tenha sido realizada com sucesso.
* @throws Exception exceo na criao do Entity Bean de Produtos.
*/
public Boolean finalizeSale() throws Exception {
final String FACADE_NAME = java:comp/env/ejb/productfacade;
ProductSessionFacadeHome localHome = (ProductSessionFacadeHome)
ServiceLocator.getInstance().
ProductSessionFacadeHome.class);

getEjbHome(FACADE_NAME,

ProductSessionFacade local = localHome.create();


try {
for (Iterator i = basket.entrySet().iterator(); i.hasNext(); ) {
Map.Entry product = (Map.Entry) i.next();
ProductTO to = (ProductTO) product.getValue();
local.createProduct(to);
}
return new Boolean(true);
} catch (Exception ex) {
throw new Exception(Error while trying to finalize Sale. + ex);
}
}

/**
* Adiciona um produto no carrinho de compras.
* @param product produto a ser inserido no carrinho de compras.
*/
public void addProduct(ProductTO product) {
this.basket.put(product.getId(), product);
}

286

Captulo 19 Aplicao J2EE Exemplo

/**
* Remove um produto do carrinho de compras.
* @param product produto a ser removido do carrinho de compras.
* @return verdadeiro caso a remoo seja efetivada, falso caso contrrio.
*/
public Boolean removeProduct(ProductTO product) {
if (this.basket.remove(product.getId()) != null)
return new Boolean(true);
return new Boolean(false);
}

/**
* Calcula o valor dos produtos contidos na cesta e retorna este valor.
* @return valor total do produtos contidos na cesta.
*/
public Double calcBasketPrice() {
double value = 0;
for (Iterator i = basket.entrySet().iterator(); i.hasNext(); ) {
Map.Entry entry = (Map.Entry) i.next();
value += ((ProductTO) entry.getValue()).getPrice().doubleValue();
}
return new Double(value);
}

/**
* Remove os produtos da cesta de compras.
*/
public void freeBasket() {
this.basket.clear();
}
}

Deployment Descriptor : SalesBasketBean.


<?xml version=1.0" encoding=UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC -//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//
EN http://java.sun.com/dtd/ejb-jar_2_0.dtd>
<ejb-jar>
<enterprise-beans>
<session>

287

J2EE Primeiros Passos


<display-name>SalesBasket</display-name>
<ejb-name>SalesBasket</ejb-name>
<home>com.novatec.book.project.ejb.session.SalesBasketHome</home>
<remote>com.novatec.book.project.ejb.session.SalesBasket</remote>
<ejb-class>com.novatec.book.project.ejb.session.SalesBasketBean</ejb-

class>

<session-type>Stateful</session-type>
<transaction-type>Container</transaction-type>
<ejb-ref>
<description />
<ejb-ref-name>ejb/productfacade</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home>com.novatec.book.project.ejb.entity.ProductSessionFacadeHome</

home>

<remote>com.novatec.book.project.ejb.entity.ProductSessionFacade</

remote>

<ejb-link>ProductSessionFacade</ejb-link>
</ejb-ref>
</session>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>SalesBasket</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>

EJB Entity Bean BMP UserBean e EJB Session Bean Stateless


UserSessionFacade
Vemos a seguir os cdigos do EJB Entity Bean BMP UserBean e do seu SessionFacade
- UserSessionFacade. Seguem as interfaces UserLocalHome e UserLocal. Depois a
implementao do EJB UserBean e por fim o seu deployment descriptor.

Interface LocalHome : UserLocalHome.


package com.novatec.book.project.ejb.entity.impl;

288

Captulo 19 Aplicao J2EE Exemplo


import javax.ejb.*;
import java.util.*;

/**
* Interface <code>Home</code> utilizada para acesso local.
* Prov os mtodos de criao da entidade usurio e localizao
* do objeto atravs de sua chave primria.
*/
public interface UserLocalHome extends javax.ejb.EJBLocalHome {

/**
* Cria uma referncia local para o componente <code>UserLocal</code>.
* @param name nome do usurio.
* @param cpf cpf do usurio.
* @param address endereo do usurio.
* @param email email do usurio.
* @return referncia local para o componente <code>UserLocal</code>.
* @throws CreateException se ocorrer erro ao criar a instncia.
*/
UserLocal create(String name, String cpf, String address, String email)
throws CreateException;

/**
* Realiza a localizao do objeto pela sua chave primria.
* @param cpf cpf do usurio.
* @return referncia local para o componente <code>UserLocal</code>.
* @throws FinderException exceo em caso de erro ao localizar objeto.
*/
UserLocal findByPrimaryKey(String cpf) throws FinderException;
}

Interface Local : UserLocal.


package com.novatec.book.project.ejb.entity.impl;

import javax.ejb.*;
import java.util.*;

/**
* Interface <code>Remote</code> utilizada para acesso local e que prov os
* mtodos para configurar e obter os valores dos atributos do usurio.

289

J2EE Primeiros Passos


*/
public interface UserLocal extends javax.ejb.EJBLocalObject {

/**
* Obtm o nome do usurio.
* @return nome do usurio.
*/
String getName();

/**
* Obtm o cpf do usurio.
* @return cpf do usurio.
*/
String getCpf();

/**
* Obtm o endereo do usurio.
* @return endereo do usurio.
*/
String getAddress();

/**
* Obtm o email do usurio.
* @return email do usurio.
*/
String getEmail();

/**
* Configura o nome do usurio.
* @param name nome do usurio.
*/
void setName(String name);

/**
* Configura o endereo do usurio.
* @param address endereo do usurio.
*/
void setAddress(String address);

/**

290

Captulo 19 Aplicao J2EE Exemplo


* Configura o email do usurio.
* @param email email do usurio.
*/
void setEmail(String email);
}

Entity Bean BMP : UserBean.


package com.novatec.book.project.ejb.entity.impl;

import java.rmi.*;
import java.sql.*;
import javax.ejb.*;
import javax.naming.*;

/**
* EJB Entity Bean BMP, responsvel por mantr os dados de usurio
* em um meio persistente.
* <p>
* Apresenta os mtodos de configurao e obteno dos valores dos atributos
* da entidade, criao, remoo, atualizao e localizao da entidade
* no meio de persistncia.
*/
public class UserBean implements EntityBean {

/**
* Contexto do EJB Entity Bean.
*/
private EntityContext entityContext;

/**
* Conexo com o BD.
*/
private transient Connection connection = null;

/**
* Query de insero do objeto no BD.
*/
private final String INSERT_QUERY =
INSERT INTO USER(Name, Cpf, Address, Email) VALUES(?, ?, ?, ?);

291

J2EE Primeiros Passos


/**
* Query de atualizao do objeto no BD.
*/
private final String UPDATE_QUERY =
UPDATE USER SET Name = ?, Address = ?, Email = ? WHERE Cpf = ?;

/**
* Query de remoo do objeto no BD.
*/
private final String DELETE_QUERY = DELETE FROM USER WHERE Cpf = ?;

/**
* Query de obteno do objeto do BD.
*/
private final String SELECT_QUERY =
SELECT Name, Cpf, Address, Email FROM USER WHERE Cpf = ?;

/**
* Query utilizada para obter os objetos dado sua chave primria.
*/
private final String FIND_BY_PK =
SELECT Name, Cpf, Address, Email FROM USER WHERE Cpf = ?;

/**
* Nome do usurio.
*/
private String name;

/**
* CPF do usurio.
*/
private String cpf;

/**
* Endereo do usurio.
*/
private String address;

/**
* Email do usurio.

292

Captulo 19 Aplicao J2EE Exemplo


*/
private String email;

/**
* Utilizado pelo container para criar o objeto usurio.
* @param name nome do usurio.
* @param cpf cpf do usurio.
* @param address endereo do usurio.
* @param email email do usurio.
* @return chave primria da entidade usurio.
* @throws CreateException exceo na criao desta instncia.
*/
public String ejbCreate(String name, String cpf, String address, String email)
throws CreateException {
try {
connection = getConnection();
try {
PreparedStatement stmt = connection.prepareStatement(
INSERT_QUERY);
try {
stmt.setString(1, name);
stmt.setString(2, cpf);
stmt.setString(3, address);
stmt.setString(4, email);
stmt.execute();
} finally {
stmt.close();
}
} finally {
connection.close();
}
} catch (Exception e) {
throw new CreateException();
}
setName(name);
setCpf(cpf);
setAddress(address);
setEmail(email);
return null;
}

293

J2EE Primeiros Passos

/**
* Executado aps a criao da instncia.
* Pode ser utilizado para realizar alguma operao neste momento.
* Utilizado para configurar os relacionamentos para o EJB Entity Bean CMP.
* @param name nome do usurio.
* @param cpf cpf do usurio.
* @param address endereo do usurio.
* @param email email do usurio.
* @throws CreateException exceo na criao desta instncia.
*/
public void ejbPostCreate(String name, String cpf, String address, String email)
throws CreateException {
}

/**
* Remoo da instncia do EJB, pelo container.
* @throws RemoveException exceo na remoo do objeto.
*/
public void ejbRemove() throws RemoveException {
try {
connection = getConnection();
try {
PreparedStatement stmt = connection.prepareStatement(
DELETE_QUERY);
try {
stmt.setString(1, this.cpf);
stmt.execute();
} finally {
stmt.close();
}
} finally {
connection.close();
}
} catch (Exception e) {
throw new RemoveException(Error removing element.);
}
}

/**

294

Captulo 19 Aplicao J2EE Exemplo


* Configura o nome do usurio.
* @param name nome do usurio.
*/
public void setName(String name) {
this.name = name;
}

/**
* Configura o cpf do usurio.
* @param cpf cpf do usurio.
*/
public void setCpf(String cpf) {
this.cpf = cpf;
}

/**
* Configura o endereo do usurio.
* @param address endereo do usurio.
*/
public void setAddress(String address) {
this.address = address;
}

/**
* Configura o email do usurio.
* @param email email do usurio.
*/
public void setEmail(String email) {
this.email = email;
}

/**
* Obtm o nome do usurio.
* @return nome do usurio.
*/
public String getName() {
return name;
}

/**

295

J2EE Primeiros Passos


* Obtm o cpf do usurio.
* @return cpf do usurio.
*/
public String getCpf() {
return cpf;
}

/**
* Obtm o endereo do usurio.
* @return endereo do usurio.
*/
public String getAddress() {
return address;
}

/**
* Obtm o email do usurio.
* @return email do usurio.
*/
public String getEmail() {
return email;
}

/**
* Realiza a localizao do objeto pela sua chave primria.
* @param cpf cpf do usurio.
* @return chave primria do objeto em memria.
* @throws FinderException exceo em caso de erro ao localizar objeto.
*/
public String ejbFindByPrimaryKey(String cpf) throws FinderException {
try {
connection = getConnection();
try {
PreparedStatement stmt = connection.prepareStatement(FIND_BY_PK);
try {
stmt.setString(1, cpf);
ResultSet rs = stmt.executeQuery();

296

Captulo 19 Aplicao J2EE Exemplo


try {
if (rs.next()) {
this.setName(rs.getString(1));
this.setAddress(rs.getString(2));
this.setEmail(rs.getString(3));
this.setCpf(rs.getString(4));
}
} finally {
rs.close();
}
} finally {
stmt.close();
}
} finally {
connection.close();
}
} catch (Exception e) {
throw new FinderException(Error finding object by id: + cpf);
}
return this.cpf;
}

/**
* Utilizado pelo container para carregar os dados do objeto do meio
* de persistncia para a memria.
*/
public void ejbLoad() {
try {
connection = getConnection();
try {
PreparedStatement stmt = connection.prepareStatement(
SELECT_QUERY);
try {
stmt.setString(1, this.cpf);
ResultSet rs = stmt.executeQuery();
try {
if (rs.next()) {
this.setName(rs.getString(1));
this.setAddress(rs.getString(2));
this.setEmail(rs.getString(3));

297

J2EE Primeiros Passos


}
} finally {
rs.close();
}
} finally {
stmt.close();
}
} finally {
connection.close();
}
} catch (Exception e) {
throw new EJBException(Error loading objects.);
}
}

/**
* Utilizado pelo container para persistir os dados constantes em memria
* para um meio de persistncia.
*/
public void ejbStore() {
try {
connection = getConnection();
try {
PreparedStatement stmt = connection.prepareStatement(
UPDATE_QUERY);
try {
stmt.setString(1, this.name);
stmt.setString(2, this.address);
stmt.setString(3, this.email);
stmt.setString(4, this.cpf);
stmt.execute();
} finally {
stmt.close();
}
} finally {
connection.close();
}
} catch (Exception e) {
throw new EJBException(Error persisting objects.);
}

298

Captulo 19 Aplicao J2EE Exemplo


}

/**
* Utilizado pelo container para ativar o objeto que est passivo.
*/
public void ejbActivate() {
}

/**
* Utilizado pelo container para tornar passivo um objeto ativo.
*/
public void ejbPassivate() {
}

/**
* Desconfigura o contexto do EJB Entity Bean.
*/
public void unsetEntityContext() {
this.entityContext = null;
}

/**
* Configura o contexto do EJB Entity Bean.
* @param entityContext contexto do EJB Entity Bean.
*/
public void setEntityContext(EntityContext entityContext) {
this.entityContext = entityContext;
}

/**
* Cria uma conexo com o banco de dados padro.
* @return conexo do banco de dados.
*/
private Connection getConnection() {
Connection conn = null;
try {
InitialContext ctx = new InitialContext();
javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup(
java:/DefaultDS);
conn = ds.getConnection();

299

J2EE Primeiros Passos


} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
return conn;
}
}

Interface Home : UserSessionFacadeHome


package com.novatec.book.project.ejb.entity;

import javax.ejb.*;
import java.util.*;
import java.rmi.*;

/**
* Intefarce Home, obtm uma referncia para a interface Remote, esta
* ultima que fornece os servios do facade para acesso aos mtodos da
* entidade <code>UserSession</code>.
*/
public interface UserSessionFacadeHome extends javax.ejb.EJBHome {

/**
* Cria uma referncia remota para o componente
* <code>UserSessionFacade</code>.
* @return referncia remota para o componente
* <code>UserSessionFacade</code>.
* @throws CreateException se ocorrer erro ao criar a instncia.
* @throws RemoteException outros erros na criao da instncia.
*/
UserSessionFacade create() throws CreateException, RemoteException;
}

Interface Remote : UserSessionFacade


package com.novatec.book.project.ejb.entity;

import javax.ejb.*;
import java.util.*;
import java.rmi.*;
import com.novatec.book.project.ejb.to.UserTO;
import java.rmi.RemoteException;

300

Captulo 19 Aplicao J2EE Exemplo

/**
* Fornece o servio de Facade para os mtodos da entidade usurio.
*/
public interface UserSessionFacade extends javax.ejb.EJBObject {

/**
* Cria uma entidade usurio dado o seu <code>TransferObject</code>.
* @param userTO <code>TransferObject</code> de usurio.
* @throws RemoteException se ocorrer erro na criao da entidade.
*/
void createUser(UserTO userTO) throws RemoteException;

/**
* Remove a entidade associada chave primria informada.
* @param cpf cpf do usurio.
* @throws RemoteException se ocorrer erro na remoo da entidade.
*/
void removeUser(String cpf) throws RemoteException;

/**
* Remove a entidade cujo <code>TransferObject</code> representa.
* @param userTO <code>TransferObject</code> do usurio.
* @throws RemoteException se ocorrer erro na remoo da entidade.
*/
void removeUser(UserTO userTO) throws RemoteException;

/**
* Atualiza os dados da entidade usurio pelo <code>TransferObject</code>.
* @param userTO <code>TransferObject</code> do usurio.
* @throws RemoteException se ocorrer erro na atualizao da entidade.
*/
void updateUser(UserTO userTO) throws RemoteException;

/**
* Atualiza os dados das entidades contidas na coleo de usurios.
* @param userTOs coleo de <code>TransferObject</code> de usurio.
* @throws RemoteException se ocorrer erro ao atualizar as entidades.
*/
void updateUsers(UserTO[] userTOs) throws RemoteException;

301

J2EE Primeiros Passos

/**
* Localiza um usurio dado a sua chave primria.
* @param cpf cpf do usurio.
* @return <code>TransferObject</code> do usurio.
* @throws RemoteException se ocorrer erro ao localizar o produto.
*/
UserTO userFindByPrimaryKey(String cpf) throws RemoteException;
}

Session Bean Stateless : UserSessionFacadeBean


package com.novatec.book.project.ejb.entity;

import com.novatec.book.project.ejb.ServiceLocator;
import com.novatec.book.project.ejb.entity.impl.UserLocalHome;
import com.novatec.book.project.ejb.ServiceLocatorException;
import com.novatec.book.project.ejb.to.UserTOAssembler;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

import javax.ejb.*;
import com.novatec.book.project.ejb.to.UserTO;
import java.rmi.RemoteException;
import com.novatec.book.project.ejb.entity.impl.UserLocal;
import java.util.Collection;

/**
* EJB Session Bean Stateless utilizado como Facade para a entidade usurio.
*/
public class UserSessionFacadeBean implements SessionBean {

/**
* Contexto do Session Bean.
*/
SessionContext sessionContext;

/**
* Referncia local para a interface <code>Home</code> da entidade usurio.
*/

302

Captulo 19 Aplicao J2EE Exemplo


private UserLocalHome userLocalHome;

/**
* Criao da instncia deste objeto pelo container.
* @throws CreateException exceo na criao da instncia do EJB.
*/
public void ejbCreate() throws CreateException {
}

/**
* Remoo da instncia do EJB, pelo container.
*/
public void ejbRemove() {
}

/**
* Utilizado pelo container para ativar o objeto que est passivo.
*/
public void ejbActivate() {
}

/**
* Utilizado pelo container para tornar passivo um objeto ativo.
*/
public void ejbPassivate() {
}

/**
* Configura o contexto do EJB Session Bean.
* @param sessionContext contexto do EJB Session Bean.
*/
public void setSessionContext(SessionContext sessionContext) {
try {
findUserHome();
} catch (Exception e) {
throw new EJBException(e.getMessage());
}
this.sessionContext = sessionContext;
}

303

J2EE Primeiros Passos


/**
* Cria uma entidade usurio dado o seu <code>TransferObject</code>.
* @param userTO <code>TransferObject</code> de usurio.
* @throws RemoteException se ocorrer erro na criao da entidade.
*/
public void createUser(UserTO userTO) throws RemoteException {
if (userTO == null) {
return;
}
try {
UserLocal userLocal = userLocalHome.create(
userTO.getName(),
userTO.getCpf(),
userTO.getAddress(),
userTO.getEmail());
} catch (CreateException e) {
throw new RemoteException(e.getMessage());
}
}

/**
* Remove a entidade associada chave primria informada.
* @param cpf cpf do usurio.
* @throws RemoteException se ocorrer erro na remoo da entidade.
*/
public void removeUser(String cpf) throws RemoteException {
try {
UserLocal user = userLocalHome.findByPrimaryKey(cpf);
userLocalHome.remove(user);
} catch (Exception e) {
throw new RemoteException(e.getMessage());
}
}

/**
* Remove a entidade cujo <code>TransferObject</code> representa.
* @param userTO <code>TransferObject</code> do usurio.
* @throws RemoteException se ocorrer erro na remoo da entidade.
*/
public void removeUser(UserTO userTO) throws RemoteException {

304

Captulo 19 Aplicao J2EE Exemplo


if (userTO != null) {
String cpf = userTO.getCpf();
removeUser(cpf);
}
}

/**
* Atualiza os dados da entidade usurio pelo <code>TransferObject</code>.
* @param userTO <code>TransferObject</code> do usurio.
* @throws RemoteException se ocorrer erro na atualizao da entidade.
*/
public void updateUser(UserTO userTO) throws RemoteException {
if (userTO != null) {
String cpf = userTO.getCpf();
try {
UserLocal user = userLocalHome.findByPrimaryKey(cpf);
setUserFromUserTO(user, userTO);
} catch (FinderException e) {
throw new RemoteException(e.getMessage());
}
}
}

/**
* Atualiza os dados das entidades contidas na coleo de usurios.
* @param userTOs coleo de <code>TransferObject</code> de usurio.
* @throws RemoteException se ocorrer erro ao atualizar as entidades.
*/
public void updateUsers(UserTO[] userTOs) throws RemoteException {
if (userTOs != null) {
for (int i = 0; i < userTOs.length; i++) {
updateUser(userTOs[i]);
}
}
}

/**
* Localiza um usurio dado a sua chave primria.
* @param cpf cpf do usurio.
* @return <code>TransferObject</code> do usurio.

305

J2EE Primeiros Passos


* @throws RemoteException se ocorrer erro ao localizar o produto.
*/
public UserTO userFindByPrimaryKey(String cpf) throws RemoteException {
try {
return assembleUserTO(userLocalHome.findByPrimaryKey(cpf));
} catch (FinderException e) {
throw new RemoteException(e.getMessage());
}
}

/**
* Configura os atributos do usurio.
* @param userLocal referncia local para a entidade usurio.
* @param userTO <code>TransferObject</code> do usurio.
*/
private void setUserFromUserTO(UserLocal userLocal, UserTO userTO) {
userLocal.setName(userTO.getName());
userLocal.setAddress(userTO.getAddress());
userLocal.setEmail(userTO.getEmail());
}

/**
* Localiza a entidade usurio e configura sua interface home.
* @throws RemoteException se ocorrer erro ao localizar o componente.
*/
private void findUserHome() throws RemoteException {
final String ENTITY_NAME = java:comp/env/ejb/user;
if (userLocalHome == null) {
try {
ServiceLocator locator = ServiceLocator.getInstance();
userLocalHome = (UserLocalHome) locator.getEjbLocalHome(
ENTITY_NAME);
} catch (ServiceLocatorException e) {
throw new RemoteException(e.getMessage());
}
}
}

/**
* Cria um objeto <code>TransferObject</code> do usurio a partir da

306

Captulo 19 Aplicao J2EE Exemplo


* sua entiade.
* @param userLocal entidade de usurio.
* @return <code>TransferObject</code> do usurio.
*/
private UserTO assembleUserTO(UserLocal userLocal) {
return UserTOAssembler.createTO(userLocal);
}

/**
* Cria uma coleo de <code>TransferObject</code> do usurio a partir da
* coleo das entidades de usurio.
* @param userLocals coleo das entidades de usurio.
* @return coleo de <code>TransferObject</code> do usurio.
*/
private UserTO[] assembleUserTOs(Collection userLocals) {
List list = new ArrayList();
if (userLocals != null) {
Iterator iterator = userLocals.iterator();
while (iterator.hasNext()) {
UserLocal userLocal = (UserLocal) iterator.next();
list.add(assembleUserTO(userLocal));
}
}
UserTO[] returnArray = new UserTO[list.size()];
return (UserTO[]) list.toArray(returnArray);
}
}

Deployment Descriptor : UserSessionFacade e UserBean.


<?xml version=1.0" encoding=UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC -//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//
EN http://java.sun.com/dtd/ejb-jar_2_0.dtd>
<ejb-jar>
<enterprise-beans>
<session>
<display-name>UserSessionFacade</display-name>
<ejb-name>UserSessionFacade</ejb-name>
<home>com.novatec.book.project.ejb.entity.UserSessionFacadeHome</home>
<remote>com.novatec.book.project.ejb.entity.UserSessionFacade</remote>
ejb-class>

<ejb-class>com.novatec.book.project.ejb.entity.UserSessionFacadeBean</

307

J2EE Primeiros Passos


<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
<ejb-local-ref>
<description />
<ejb-ref-name>ejb/user</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<local-home>com.novatec.book.project.ejb.entity.impl.UserLocalHome</

local-home>

<local>com.novatec.book.project.ejb.entity.impl.UserLocal</local>
<ejb-link>User</ejb-link>
</ejb-local-ref>
</session>
<entity>
<display-name>User</display-name>
<ejb-name>User</ejb-name>
local-home>

<local-home>com.novatec.book.project.ejb.entity.impl.UserLocalHome</
<local>com.novatec.book.project.ejb.entity.impl.UserLocal</local>
<ejb-class>com.novatec.book.project.ejb.entity.impl.UserBean</ejb-class>
<persistence-type>Bean</persistence-type>
<prim-key-class>java.lang.String</prim-key-class>
<reentrant>False</reentrant>

</entity>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>UserSessionFacade</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>User</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>

308

Captulo 19 Aplicao J2EE Exemplo

EJB Entity Bean CMP ProductBean e EJB Session Bean Stateless ProductSessionFacade
O prximo cdigo apresenta o EJB Entity Bean CMP ProductBean. Este EJB apresenta
tambm as interfaces Local e LocalHome que so respectivamente, ProductLocal e
ProductLocalHome. Em seguida temos a implementao do EJB ProductBean e de
sua chave primria ProductPK. Observe que como definimos este EJB como Entity
Bean CMP, a implementao do EJB ProductBean no apresenta codificao para os
mtodos de persistncia do objeto. Como sabemos, isto feito pelo prprio container do servidor de aplicaes. Alm deste, temos o SessionFacade ProductSessionFacade e por fim apresentamos o deployment descriptor deste EJB.

Interface Home : ProductLocalHome.


package com.novatec.book.project.ejb.entity.impl;

import javax.ejb.*;
import java.util.*;

/**
* Interface <code>Home</code> utilizada para acesso local.
* Prov os mtodos de criao da entidade produto e localizao
* do objeto atravs de sua chave primria.
*/
public interface ProductLocalHome extends javax.ejb.EJBLocalHome {

/**
* Cria uma referncia local para o componente <code>ProductLocal</code>.
* @param name nome do produto.
* @param description descrio do produto.
* @param price preo do produto.
* @param id chave primria do produto.
* @return chave primria do produto.
* @return referncia local para o componente <code>ProductLocal</code>.
* @throws CreateException se ocorrer erro ao criar a instncia.
*/
ProductLocal create(String name, String description, Double price, Integer id)
throws CreateException;

/**
* Realiza a localizao do objeto pela sua chave primria.

309

J2EE Primeiros Passos


* @param pk chave primria do produto.
* @return referncia local para o componente <code>ProductLocal</code>.
* @throws FinderException exceo em caso de erro ao localizar objeto.
*/
ProductLocal findByPrimaryKey(ProductPK pk) throws FinderException;

/**
* Localiza todos os objetos.
* @return coleo de referncias locais para os componentes do tipo
* <code>ProductLocal</code>.
* @throws FinderException exceo em caso de erro ao localizar os objetos.
*/
Collection findAll() throws FinderException;
}

Interface Remote : ProductLocal


package com.novatec.book.project.ejb.entity.impl;

import javax.ejb.*;
import java.util.*;

/**
* Interface <code>Remote</code> utilizada para acesso local e que prov os
* mtodos para configurar e obter os valores dos atributos do produto.
*/
public interface ProductLocal extends javax.ejb.EJBLocalObject {

/**
* Configura o nome do produto.
* Implementado pelo container para o Entity Bean CMP.
* @param name nome do produto.
*/
void setName(String name);

/**
* Obtm o nome do produto.
* Implementado pelo container para o Entity Bean CMP.
* @return nome do produto.
*/
String getName();

310

Captulo 19 Aplicao J2EE Exemplo

/**
* Configura a descrio do produto.
* Implementado pelo container para o Entity Bean CMP.
* @param description descrio do produto.
*/
void setDescription(String description);

/**
* Obtm a descrio do produto.
* Implementado pelo container para o Entity Bean CMP.
* @return descrio do produto.
*/
String getDescription();

/**
* Configura o preo do produto.
* Implementado pelo container para o Entity Bean CMP.
* @param price preo do produto.
*/
void setPrice(Double price);

/**
* Obtm o preo do produto.
* @return preo do produto.
*/
Double getPrice();

/**
* Obtm a chave primria do produto.
* @return chave primria do produto.
*/
Integer getId();
}

Entity Bean CMP : ProductBean.


package com.novatec.book.project.ejb.entity.impl;

import javax.ejb.*;

311

J2EE Primeiros Passos


/**
* Entity Bean CMP, responsvel por mantr os dados dos produtos
* em um meio persistente.
* <p>
* Os mtodos de negcio deste EJB so implementados pelo prprio
* container e os mtodos finders e select devem ser definidos
* atravs de EQL no deployment descriptor.
* Observe que o mtodo findByPrimaryKey definido como padro.
* <p>
* Podemos definir em um Entity Bean, tanto CMP quanto BMP, uma classe
* que define a chave primria do EJB.
* Faremos isto para este EJB para exemplificarmos o seu uso.
* A classe de chave primria do produto ser ProductPK.
*/
abstract public class ProductBean implements EntityBean {

/**
* Contexto do EJB Entity Bean.
*/
private EntityContext entityContext;

/**
* Utilizado pelo container para criar o objeto produto.
* @param name nome do produto.
* @param description descrio do produto.
* @param price preo do produto.
* @param id chave primria do produto.
* @return chave primria do produto.
* @throws CreateException exceo na criao desta instncia.
*/
public ProductPK ejbCreate(String name, String description, Double price,
Integer id)
throws CreateException {
setName(name);
setDescription(description);
setPrice(price);
setId(id);
return null;
}

/**

312

Captulo 19 Aplicao J2EE Exemplo


* Executado aps a criao da instncia.
* Pode ser utilizado para realizar alguma operao neste momento.
* Utilizado para configurar os relacionamentos para o EJB Entity Bean CMP.
* @param name nome do produto.
* @param description descrio do produto.
* @param price preo do produto.
* @param id chave primria do produto.
* @throws CreateException exceo na criao desta instncia.
*/
id)

public void ejbPostCreate(String name, String description, Double price, Integer


throws CreateException {
}

/**
* Remoo da instncia do EJB, pelo container.
* @throws RemoveException exceo na remoo do objeto.
*/
public void ejbRemove() throws RemoveException {
}

/**
* Utilizado pelo container para carregar os dados do objeto do meio
* de persistncia para a memria.
*/
public void ejbLoad() {
}

/**
* Utilizado pelo container para persistir os dados constantes em memria
* para um meio de persistncia.
*/
public void ejbStore() {
}

/**
* Utilizado pelo container para ativar o objeto que est passivo.
*/
public void ejbActivate() {
}

313

J2EE Primeiros Passos


/**
* Utilizado pelo container para tornar passivo um objeto ativo.
*/
public void ejbPassivate() {
}

/**
* Desconfigura o contexto do EJB Entity Bean.
*/
public void unsetEntityContext() {
this.entityContext = null;
}

/**
* Configura o contexto do EJB Entity Bean.
* @param entityContext contexto do EJB Entity Bean.
*/
public void setEntityContext(EntityContext entityContext) {
this.entityContext = entityContext;
}

/**
* Configura o nome do produto.
* Implementado pelo container para o Entity Bean CMP.
* @param name nome do produto.
*/
public abstract void setName(String name);

/**
* Configura a descrio do produto.
* Implementado pelo container para o Entity Bean CMP.
* @param description descrio do produto.
*/
public abstract void setDescription(String description);

/**
* Configura o preo do produto.
* Implementado pelo container para o Entity Bean CMP.
* @param price preo do produto.
*/

314

Captulo 19 Aplicao J2EE Exemplo


public abstract void setPrice(Double price);

/**
* Configura a chave primria do produto.
* @param id chave primria do produto.
*/
public abstract void setId(Integer id);

/**
* Obtm o nome do produto.
* Implementado pelo container para o Entity Bean CMP.
* @return nome do produto.
*/
public abstract String getName();

/**
* Obtm a descrio do produto.
* Implementado pelo container para o Entity Bean CMP.
* @return descrio do produto.
*/
public abstract String getDescription();

/**
* Obtm o preo do produto.
* Implementado pelo container para o Entity Bean CMP.
* @return preo do produto.
*/
public abstract Double getPrice();

/**
* Obtm a chave primria do produto.
* @return chave primria do produto.
*/
public abstract Integer getId();
}

Chave Primria: ProductPK


package com.novatec.book.project.ejb.entity.impl;

import java.io.*;

315

J2EE Primeiros Passos

/**
* Classe que define uma chave primria para a entidade produto.
*/
public class ProductPK implements Serializable {

/**
* Identificador nico do objeto produto.
*/
private Integer id;

/**
* Construtor padro.
*/
public ProductPK() {
}

/**
* Construtor customizado.
* @param id identificador do produto.
*/
public ProductPK(Integer id) {
this.id = id;
}

/**
* Obtm a chave primria Id da entidade produto.
* @return chave primria Id da entidade produto.
*/
public Integer getId() {
return this.id;
}

/**
* Avalia se o objeto informado, igual a este objeto.
* @param obj objeto a ser comparado.
* @return verdadeiro caso o objeto seja igual, falso caso contrrio.
*/
public boolean equals(Object obj) {
if ( this == obj ) {

316

Captulo 19 Aplicao J2EE Exemplo


return true;
}

if (!(obj instanceof ProductPK)) {


return false;
}

ProductPK that = (ProductPK) obj;

return this.id == that.id;


}

/**
* Chave de Hash, utilizada pelas Maps, para manter este objeto.
* @return chave de hash para este objeto.
*/
public int hashCode() {
int result = 17;
result = 37 * result + id.hashCode();
return result;
}

/**
* Obtm uma descrio textual do objeto.
* @return descrio textual do objeto.
*/
public String toString() {
StringBuffer sb = new StringBuffer(1024);
sb.append([ + id + ]);
return sb.toString();
}
}

Interface Home : ProductSessionFacadeHome


package com.novatec.book.project.ejb.entity;

import javax.ejb.*;
import java.util.*;
import java.rmi.*;

317

J2EE Primeiros Passos


import com.novatec.book.project.ejb.entity.impl.ProductPK;

/**
* Interface Home, obtm uma referncia para a interface Remote, esta
* ultima que fornece os servios do facade para acesso aos mtodos da
* entidade <code>ProductSession</code>.
*/
public interface ProductSessionFacadeHome extends javax.ejb.EJBHome {

/**
* Cria uma referncia remota para o componente
* <code>ProductSessionFacade</code>.
* @return referncia remota para o componente
* <code>ProductSessionFacade</code>.
* @throws CreateException se ocorrer erro ao criar a instncia.
* @throws RemoteException outros erros na criao da instncia.
*/
ProductSessionFacade create() throws CreateException, RemoteException;
}

Interface Remote : ProductSessionFacade


package com.novatec.book.project.ejb.entity;

import javax.ejb.*;
import java.util.*;
import java.rmi.*;
import com.novatec.book.project.ejb.to.*;
import com.novatec.book.project.ejb.entity.impl.ProductPK;

import java.rmi.RemoteException;
import com.novatec.book.project.ejb.to.ProductTO;

/**
* Apresenta o Facade para acesso aos mtodos da entidade Produto.
*/
public interface ProductSessionFacade extends javax.ejb.EJBObject {

/**
* Cria uma entidade produto dado o seu <code>TransferObject</code>.
* @param productTO <code>TransferObject</code> de produto.

318

Captulo 19 Aplicao J2EE Exemplo


* @throws RemoteException se ocorrer erro na criao da entidade.
*/
void createProduct(ProductTO productTO) throws RemoteException;

/**
* Remove a entidade associada chave primria informada.
* @param productPK chave primria do produto.
* @throws RemoteException se ocorrer erro na remoo da entidade.
*/
void removeProduct(ProductPK productPK) throws RemoteException;

/**
* Remove a entidade cujo <code>TransferObject</code> representa.
* @param productTO <code>TransferObject</code> do produto.
* @throws RemoteException se ocorrer erro na remoo da entidade.
*/
void removeProduct(ProductTO productTO) throws RemoteException;

/**
* Atualiza os dados da entidade produto pelo <code>TransferObject</code>.
* @param productTO <code>TransferObject</code> do produto.
* @throws RemoteException se ocorrer erro na atualizao da entidade.
*/
void updateProduct(ProductTO productTO) throws RemoteException;

/**
* Atualiza os dados das entidades contidas na coleo de produtos.
* @param productTOs coleo de <code>TransferObject</code> de produto.
* @throws RemoteException se ocorrer erro ao atualizar as entidades.
*/
void updateProducts(ProductTO[] productTOs) throws RemoteException;

/**
* Localiza um produto dado a sua chave primria.
* @param productPK chave primria do produto.
* @return <code>TransferObject</code> do produto.
* @throws RemoteException se ocorrer erro ao localizar o produto.
*/
ProductTO productFindByPrimaryKey(ProductPK productPK) throws RemoteException;

319

J2EE Primeiros Passos


/**
* Localiza todos os produtos.
* @return coleo de <code>TransferObject</code> do produto.
* @throws FinderException exceo em caso de erro ao localizar os produtos.
*/
Collection productFindAll() throws RemoteException;
}

Session Bean Stateless : ProductSessionFacadeBean


package com.novatec.book.project.ejb.entity;

import

com.novatec.book.project.ejb.entity.impl.ProductLocalHome;

import com.novatec.book.project.ejb.ServiceLocator;
import com.novatec.book.project.ejb.ServiceLocatorException;
import com.novatec.book.project.ejb.to.ProductTOAssembler;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

import javax.ejb.*;
import com.novatec.book.project.ejb.to.ProductTO;
import com.novatec.book.project.ejb.entity.impl.*;
import java.rmi.RemoteException;
import java.util.Collection;
import com.novatec.book.project.ejb.entity.impl.ProductLocal;
import java.util.*;

/**
* Fornece o servio de Facade para os mtodos da entidade produto.
*/
public class ProductSessionFacadeBean implements SessionBean {

/**
* Contexto do Session Bean.
*/
SessionContext sessionContext;

/**
* Referncia local para a interface <code>Home</code> de produto.

320

Captulo 19 Aplicao J2EE Exemplo


*/
private ProductLocalHome productLocalHome;

/**
* Criao da instncia deste objeto pelo container.
* @throws CreateException exceo na criao da instncia do EJB.
*/
public void ejbCreate() throws CreateException {
}

/**
* Remoo da instncia do EJB, pelo container.
*/
public void ejbRemove() {
}

/**
* Utilizado pelo container para ativar o objeto que est passivo.
*/
public void ejbActivate() {
}

/**
* Utilizado pelo container para tornar passivo um objeto ativo.
*/
public void ejbPassivate() {
}

/**
* Configura o contexto do EJB Session Bean.
* @param sessionContext contexto do EJB Session Bean.
*/
public void setSessionContext(SessionContext sessionContext) {
try {
findProductHome();
} catch (Exception e) {
throw new EJBException(e.getMessage());
}
this.sessionContext = sessionContext;
}

321

J2EE Primeiros Passos

/**
* Cria uma entidade produto dado o seu <code>TransferObject</code>.
* @param productTO <code>TransferObject</code> de produto.
* @throws RemoteException se ocorrer erro na criao da entidade.
*/
public void createProduct(ProductTO productTO) throws RemoteException {
if (productTO == null) {
return;
}
try {
ProductLocal productLocal = productLocalHome.create(
productTO.getName(),
productTO.getDescription(),
productTO.getPrice(),
productTO.getId());
} catch (CreateException e) {
throw new RemoteException(e.getMessage());
}
}

/**
* Remove a entidade associada chave primria informada.
* @param productPK chave primria do produto.
* @throws RemoteException se ocorrer erro na remoo da entidade.
*/
public void removeProduct(ProductPK productPK) throws RemoteException {
try {
ProductLocal product =
productLocalHome.findByPrimaryKey(productPK.getId());
productLocalHome.remove(product);
} catch (Exception e) {
throw new RemoteException(e.getMessage());
}
}

/**
* Remove a entidade cujo <code>TransferObject</code> representa.
* @param productTO <code>TransferObject</code> do produto.
* @throws RemoteException se ocorrer erro na remoo da entidade.
*/

322

Captulo 19 Aplicao J2EE Exemplo


public void removeProduct(ProductTO productTO) throws RemoteException {
if (productTO != null) {
ProductPK productPK =
new ProductPK(productTO.getId());
removeProduct(productPK);
}
}

/**
* Atualiza os dados da entidade produto pelo <code>TransferObject</code>.
* @param productTO <code>TransferObject</code> do produto.
* @throws RemoteException se ocorrer erro na atualizao da entidade.
*/
public void updateProduct(ProductTO productTO) throws RemoteException {
if (productTO != null) {
ProductPK productPK =
new ProductPK(productTO.getId());
try {
ProductLocal product = productLocalHome.findByPrimaryKey(
productPK.getId());
setProductFromProductTO(product, productTO);
} catch (FinderException e) {
throw new RemoteException(e.getMessage());
}
}
}

/**
* Atualiza os dados das entidades contidas na coleo de produtos.
* @param productTOs coleo de <code>TransferObject</code> de produto.
* @throws RemoteException se ocorrer erro ao atualizar as entidades.
*/
public void updateProducts(ProductTO[] productTOs) throws RemoteException {
if (productTOs != null) {
for (int i = 0; i < productTOs.length; i++) {
updateProduct(productTOs[i]);
}
}
}

323

J2EE Primeiros Passos


/**
* Localiza um produto dado a sua chave primria.
* @param productPK chave primria do produto.
* @return <code>TransferObject</code> do produto.
* @throws RemoteException se ocorrer erro ao localizar o produto.
*/
public ProductTO productFindByPrimaryKey(ProductPK productPK) throws
RemoteException {
try {
return assembleProductTO(productLocalHome.findByPrimaryKey(
productPK.getId()));
} catch (FinderException e) {
throw new RemoteException(e.getMessage());
}
}

/**
* Localiza todos os produtos.
* @return coleo de <code>TransferObject</code> do produto.
* @throws RemoteException exceo em caso de erro ao localizar os produtos.
*/
public Collection productFindAll() throws RemoteException {
try {
Collection products = productLocalHome.findAll();
Collection returnProducts = new ArrayList(products.size());
for (Iterator iter = products.iterator(); iter.hasNext(); ) {
ProductLocal product = (ProductLocal) iter.next();
returnProducts.add(assembleProductTO(product));
}
return returnProducts;
} catch (FinderException e) {
throw new RemoteException(e.getMessage());
}
}

/**
* Configura os atributos da entidade produto.
* @param productLocal referncia local para a entidade produto.
* @param productTO <code>TransferObject</code> de produto.
*/

324

Captulo 19 Aplicao J2EE Exemplo


private void setProductFromProductTO(ProductLocal productLocal, ProductTO
productTO) {
productLocal.setName(productTO.getName());
productLocal.setDescription(productTO.getDescription());
productLocal.setPrice(productTO.getPrice());
}

/**
* Localiza a entidade produto.
* @throws RemoteException se ocorrer erro ao localizar a entidade.
*/
private void findProductHome() throws RemoteException {
final String ENTITY_NAME = java:comp/env/ejb/product;
if (productLocalHome == null) {
try {
ServiceLocator locator = ServiceLocator.getInstance();
productLocalHome = (ProductLocalHome) locator.getEjbLocalHome(
ENTITY_NAME);
} catch (ServiceLocatorException e) {
throw new RemoteException(e.getMessage());
}
}
}

/**
* Cria um <code>TransferObject</code> de produto atravs da entidade.
* @param productLocal entidade produto.
* @return <code>TransferObject</code> de produto.
*/
private ProductTO assembleProductTO(ProductLocal productLocal) {
return ProductTOAssembler.createTO(productLocal);
}

/**
* Cria uma coleo de <code>TransferObject</code> de produto atravs da
* coleo de entidades produto.
* @param productLocals entidades produto.
* @return coleo de <code>TransferObject</code> de produto.
*/
private ProductTO[] assembleProductTOs(Collection productLocals) {
List list = new ArrayList();

325

J2EE Primeiros Passos


if (productLocals != null) {
Iterator iterator = productLocals.iterator();
while (iterator.hasNext()) {
ProductLocal productLocal = (ProductLocal) iterator.next();
list.add(assembleProductTO(productLocal));
}
}
ProductTO[] returnArray = new ProductTO[list.size()];
return (ProductTO[]) list.toArray(returnArray);
}
}

Deployment Descriptor : ProductSessionFacade e ProductBean.


<?xml version=1.0" encoding=UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC -//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//
EN http://java.sun.com/dtd/ejb-jar_2_0.dtd>
<ejb-jar>
<enterprise-beans>
<session>
<display-name>ProductSessionFacade</display-name>
<ejb-name>ProductSessionFacade</ejb-name>
home>
remote>

<home>com.novatec.book.project.ejb.entity.ProductSessionFacadeHome</
<remote>com.novatec.book.project.ejb.entity.ProductSessionFacade</

<ejbclass>com.novatec.book.project.ejb.entity.ProductSessionFacadeBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
<ejb-local-ref>
<description />
<ejb-ref-name>ejb/product</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<localhome>com.novatec.book.project.ejb.entity.impl.ProductLocalHome</local-home>
<local>com.novatec.book.project.ejb.entity.impl.ProductLocal</local>
<ejb-link>Product</ejb-link>
</ejb-local-ref>
</session>
<entity>
<display-name>Product</display-name>
<ejb-name>Product</ejb-name>

326

Captulo 19 Aplicao J2EE Exemplo


local-home>

<local-home>com.novatec.book.project.ejb.entity.impl.ProductLocalHome</
<local>com.novatec.book.project.ejb.entity.impl.ProductLocal</local>

class>

<ejb-class>com.novatec.book.project.ejb.entity.impl.ProductBean</ejb<persistence-type>Container</persistence-type>

<prim-key-class>com.novatec.book.project.ejb.entity.impl.ProductPK</
prim-key-class>
<reentrant>False</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>Product</abstract-schema-name>
<cmp-field>
<field-name>name</field-name>
</cmp-field>
<cmp-field>
<field-name>description</field-name>
</cmp-field>
<cmp-field>
<field-name>price</field-name>
</cmp-field>
<cmp-field>
<field-name>id</field-name>
</cmp-field>
<primkey-field>id</primkey-field>
<query>
<query-method>
<method-name>findAll</method-name>
<method-params />
</query-method>
<ejb-ql>SELECT OBJECT(p) FROM Product p</ejb-ql>
</query>
</entity>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>ProductSessionFacade</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>

327

J2EE Primeiros Passos


<container-transaction>
<method>
<ejb-name>Product</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>

EJB Message-Driven Bean UserNotifierBean e Message - UserMessage


Apresentamos a seguir, o cdigo do EJB Message-Driven Bean UserNotifierBean. A
implementao do EJB segue logo abaixo. Observe que h uma constante chamada
HOST que deve ser configurada com o nome do host utilizado para enviar a mensagem para o usurio. Aps, segue a implementao da mensagem, UserMessage, utilizada para notificar o EJB e por fim o deployment descriptor deste EJB.

Message-Driven Bean : UserNotifierBean.


package com.novatec.book.project.ejb.mdb;

import java.util.*;
import javax.ejb.*;
import javax.jms.*;
import javax.mail.*;
import javax.naming.*;
import javax.mail.internet.*;

import com.novatec.book.project.ejb.to.*;

/**
* Responsvel por notificar o usurio das novas atualizaes do
* estado da venda de seu produto, tais como produto localizado,
* produto enviado, venda finalizada etc.
* O mtodo onMessage() responsvel por receber um mensagem do
* tipo TextMessage e enviar um email para o usurio com esta mensagem.
*/
public class UserNotifierBean implements MessageDrivenBean, MessageListener {

/**

328

Captulo 19 Aplicao J2EE Exemplo


* Contexto do Message-Drive Bean.
*/
private MessageDrivenContext messageDrivenContext;

/**
* Define o host utilizado para enviar o email.
*/
private static final String HOST =
<aqui_deve_vir_o_host_utilizado_para_enviar_o_email>;

/**
* Instncia o objeto no servidor pelo container.
*/
public void ejbCreate() {
}

/**
* Remove a instncia do objeto no servidor.
*/
public void ejbRemove() {
}

/**
* Valida a mensagem recebida e envia uma notificao ao usurio com
* a mensagem texto recebida como parmentro.
* @param msg mensagem a ser notificada.
*/
public void onMessage(javax.jms.Message msg) {
try {
if (msg instanceof ObjectMessage) {
UserMessage message = (UserMessage) ((ObjectMessage)
msg).getObject();
UserTO user = message.getUser();
this.sendEmail(HOST, user.getEmail(),
Sales Notification, message.getMessage());
}
} catch (Exception ex) {
System.err.println(Error sending email for user. + ex);
}
}

329

J2EE Primeiros Passos


/**
* Envia um email de notificao para o usurio.
* @param host host do usurio.
* @param to email do destinatrio.
* @param subject ttulo da notificao.
* @param text mensagem da notificao.
* @throws Exception exceo caso no consiga enviar o email.
*/
private void sendEmail(String host, String to, String subject, String text)
throws Exception {
try {
// Obtm as propriedades do sistema
Properties props = System.getProperties();

// Configura o servidor de email


props.put(mail.smtp.host, host);

// Obtm a sesso
javax.mail.Session session = javax.mail.Session.getDefaultInstance(
props, null);

// Define a mensagem
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(Shop));
message.addRecipient(javax.mail.Message.RecipientType.TO,
new InternetAddress(to));
message.setSubject(subject);
message.setText(text);

// Envia a mensagem
Transport.send(message);
} catch (Exception e) {
throw new Exception(Error sending mail! + e);
}
}

/**
* Configura o contexto do EJB MDB.
* @param messageDrivenContext contexto do MDB.
*/
public void setMessageDrivenContext(MessageDrivenContext messageDrivenContext) {

330

Captulo 19 Aplicao J2EE Exemplo


this.messageDrivenContext = messageDrivenContext;
}

Mensagem : UserMessage.
package com.novatec.book.project.ejb.mdb;

import java.io.*;

import com.novatec.book.project.ejb.to.*;

/**
* Objeto que contm a mensagem a ser entregue para o usurio.
* O usurio tambm definido neste objeto.
*/
public class UserMessage implements Serializable {

/**
* Usurio o qual ser enviado a mensagem.
*/
private UserTO user;

/**
* Mensagem a ser enviada para o usurio.
*/
private String message;

/**
* Construtor padro.
*/
public UserMessage() {
}

/**
* Construtor customizado.
* @param user usurio o qual ser enviado a mensagem.
* @param message mensagem a ser enviada para o usurio.
*/
public UserMessage(UserTO user, String message) {

331

J2EE Primeiros Passos


this.user = user;
this.message = message;
}

/**
* Obtm a mensagem a ser enviada para o usurio.
* @return mensagem a ser enviada para o usurio.
*/
public String getMessage() {
return message;
}

/**
* Configura a mensagem a ser enviada para o usurio.
* @param message mensagem a ser enviada para o usurio.
*/
public void setMessage(String message) {
this.message = message;
}

/**
* Obtm o usurio o qual ser enviado a mensagem.
* @return usurio o qual ser enviado a mensagem.
*/
public UserTO getUser() {
return user;
}

/**
* Configura o usurio o qual ser enviado a mensagem.
* @param user usurio o qual ser enviado a mensagem.
*/
public void setUser(UserTO user) {
this.user = user;
}
}

Deployment Descriptor : UserNotifierBean.


<?xml version=1.0" encoding=UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC -//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//
EN http://java.sun.com/dtd/ejb-jar_2_0.dtd>

332

Captulo 19 Aplicao J2EE Exemplo


<ejb-jar>
<enterprise-beans>
<message-driven>
<display-name>UserNotifier</display-name>
<ejb-name>UserNotifier</ejb-name>
<ejb-class>com.novatec.book.project.ejb.mdb.UserNotifierBean</ejb-class>
<transaction-type>Container</transaction-type>
<message-driven-destination>
<destination-type>javax.jms.Queue</destination-type>
</message-driven-destination>
</message-driven>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>UserNotifier</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>

EJB Session Bean Stateless - ProjectSupportBean


Foi criado um EJB Session Bean Stateless ProjecSupportBean, com o intuito de preparar o ambiente da aplicao exemplo. O cdigo do EJB, tais como suas interfaces,
implementao e deployment descriptors no foram comentadas pois utilizado
somente como um servio auxiliar para a aplicao. Seguem os cdigos do EJB.

Interface Home : ProjectSupportHome


package com.novatec.book.project.ejb.session;

import javax.ejb.*;
import java.util.*;
import java.rmi.*;

/**
* Inteface Home, obtm uma referncia para a interface Remote, esta
* ultima que fornece os servios de suporte a aplicao exemplo.

333

J2EE Primeiros Passos


*/
public interface ProjectSupportHome extends javax.ejb.EJBHome {

/**
* Cria uma referncia remota para o componente <code>ProjectSupport</code>.
* @return referncia remota para o componente <code>ProjectSupport</code>.
* @throws CreateException se ocorrer erro ao criar a instncia.
* @throws RemoteException outros erros na criao da instncia.
*/
ProjectSupport create() throws CreateException, RemoteException;
}

Interface Remote : ProjectSupport


package com.novatec.book.project.ejb.session;

import javax.ejb.*;
import java.util.*;
import java.rmi.*;

/**
* Interface Remote do EJB <code>ProjectSupportBean</code>.
* Apresenta servios de suporte para a aplicao exemplo.
*/
public interface ProjectSupport extends javax.ejb.EJBObject {

/**
* Prepara o amibente para a execuo da aplicao exemplo.
* @throws RemoteException se ocorrer erro ao executar o mtodo.
*/
void prepareEnvironment() throws RemoteException;

/**
* Limpa o ambiente de execuo da aplicao exemplo.
* @throws RemoteException se ocorrer erro ao executar o mtodo.
*/
void clearEnvironment() throws RemoteException;
}

334

Captulo 19 Aplicao J2EE Exemplo

Session Bean Stateless : ProjectSupportBean


package com.novatec.book.project.ejb.session;

import java.sql.*;
import java.rmi.*;
import javax.ejb.*;
import javax.naming.*;

/**
* EJB Session Bean Stateless utilizado como servio de suporte para
* a aplicao exemplo.
* <p>
* Prov servios para preparao do ambiente.
*/
public class ProjectSupportBean implements SessionBean {

/**
* Contexto do Session Bean.
*/
private SessionContext sessionContext;

/**
* Criao da instncia deste objeto pelo container.
* @throws CreateException exceo na criao da instncia do EJB.
*/
public void ejbCreate() throws CreateException {
}

/**
* Remoo da instncia do EJB, pelo container.
*/
public void ejbRemove() {
}

/**
* Utilizado pelo container para ativar o objeto que est passivo.
*/
public void ejbActivate() {
}

335

J2EE Primeiros Passos

/**
* Utilizado pelo container para tornar passivo um objeto ativo.
*/
public void ejbPassivate() {
}

/**
* Configura o contexto do EJB Session Bean.
* @param sessionContext contexto do EJB Session Bean.
*/
public void setSessionContext(SessionContext sessionContext) {
this.sessionContext = sessionContext;
}

/**
* Prepara o amibente para a execuo da aplicao exemplo.
*/
public void prepareEnvironment() {
System.out.println(Preparing environment.);
try {
InitialContext ctx = new InitialContext();
javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup(
java:/DefaultDS);
Connection conn = ds.getConnection();
try {
PreparedStatement stmt = conn.prepareStatement(
CREATE TABLE USER (NAME VARCHAR(40), CPF VARCHAR(30),
+ ADDRESS VARCHAR(50), EMAIL VARCHAR(30),
+ CONSTRAINT PK_USER PRIMARY KEY (CPF) ));
try {
stmt.execute();
} finally {
stmt.close();
}
} finally {
conn.close();
}
} catch (Exception ex) {
throw new EJBException(Error preparing environment. +

336

Captulo 19 Aplicao J2EE Exemplo


ex.getMessage());
}
System.out.println(Do it.);
}

/**
* Limpa o ambiente de execuo da aplicao exemplo.
*/
public void clearEnvironment() {
System.out.println(Clearing environment.);
try {
InitialContext ctx = new InitialContext();
javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup(
java:/DefaultDS);
Connection conn = ds.getConnection();
try {
PreparedStatement stmt = conn.prepareStatement(
DROP TABLE USER);
try {
stmt.execute();
} finally {
stmt.close();
}
} finally {
conn.close();
}
} catch (Exception ex) {
throw new EJBException(Error clearing environment. +
ex.getMessage());
}
System.out.println(Do it.);
}
}

Deployment Descriptor : ProjectSupportBean


<?xml version=1.0" encoding=UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC -//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//
EN http://java.sun.com/dtd/ejb-jar_2_0.dtd>
<ejb-jar>
<enterprise-beans>

337

J2EE Primeiros Passos


<session>
<display-name>ProjectSupport</display-name>
<ejb-name>ProjectSupport</ejb-name>
<home>com.novatec.book.project.ejb.session.ProjectSupportHome</home>
<remote>com.novatec.book.project.ejb.session.ProjectSupport</remote>
<ejb-class>com.novatec.book.project.ejb.session.ProjectSupportBean</ejb-

class>

<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>ProjectSupport</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>

TransferObjects ProductTO e UserTO e Assemblers ProductTOAssembler


e UserTOAssembler
A seguir seguem os cdigos dos TransferObjects ProcuctTO e UserTO e seus respectivos Assemblers, ProductTOAssembler e UserTOAssembler.

TransferObject : ProductTO
package com.novatec.book.project.ejb.to;

/**
* Apresenta um <code>TransferObject</code> de Produtos.
* Este VO ser utilizado pelo cliente, para informar os produtos
* selecionados na compra.
*/
public class ProductTO implements java.io.Serializable {

/**
* Identificador do produto.

338

Captulo 19 Aplicao J2EE Exemplo


*/
private Integer id;

/**
* Nome do produto.
*/
private String name;

/**
* Descrio do produto.
*/
private String description;

/**
* Preo do produto.
*/
private Double price;

/**
* Construtor padro.
*/
public ProductTO() {
}

/**
* Construtor customizado.
* @param id identificador do produto.
* @param name nome do produto.
* @param description descrio do produto.
* @param price preo do produto.
*/
public ProductTO(Integer id, String name, String description,
Double price) {
this.id = id;
this.name = name;
this.description = description;
this.price = price;
}

/**

339

J2EE Primeiros Passos


* Obtm o identificador do produto.
* @return identificador do produto.
*/
public Integer getId() {
return id;
}

/**
* Configura o identificador do produto.
* @param id identificador do produto.
*/
public void setId(Integer id) {
this.id = id;
}

/**
* Obtm o nome do produto.
* @return nome do produto.
*/
public String getName() {
return name;
}

/**
* Configura o nome do produto.
* @param name nome do produto.
*/
public void setName(String name) {
this.name = name;
}

/**
* Obtm a descrio do produto.
* @return descrio do produto.
*/
public String getDescription() {
return description;
}

/**

340

Captulo 19 Aplicao J2EE Exemplo


* Configura a descrio do produto.
* @param description descrio do produto.
*/
public void setDescription(String description) {
this.description = description;
}

/**
* Obtm o preo do produto.
* @return preo do produto.
*/
public Double getPrice() {
return price;
}

/**
* Configura o preo do produto.
* @param price preo do produto.
*/
public void setPrice(Double price) {
this.price = price;
}

/**
* Avalia se o objeto informado, igual a este objeto.
* @param obj objeto a ser comparado.
* @return verdadeiro caso o objeto seja igual, falso caso contrrio.
*/
public boolean equals(Object obj) {
if ( this == obj ) {
return true;
}

if (!(obj instanceof ProductTO)) {


return false;
}

ProductTO that = (ProductTO) obj;

return this.id == that.id &&

341

J2EE Primeiros Passos


this.name == that.name &&
this.description == that.description &&
this.price == that.price;
}

/**
* Chave de Hash, utilizada pelas Maps, para manter este objeto.
* @return chave de hash para este objeto.
*/
public int hashCode() {
int result = 17;
result = 37 * result + id.hashCode();
result = 37 * result + name.hashCode();
result = 37 * result + description.hashCode();
result = 37 * result + price.hashCode();
return result;
}

/**
* Obtm uma descrio textual do objeto.
* @return descrio textual do objeto.
*/
public String toString() {
StringBuffer sb = new StringBuffer(1024);
sb.append([ + id + , + name + , + description
+ , + price + ]);
return sb.toString();
}
}

TransferObject : UserTO
package com.novatec.book.project.ejb.to;

/**
* Apresenta um <code>TransferObject</code> de usurio.
* Contm um identificador para o usurio, nome, endereo e email.
*/
public class UserTO implements java.io.Serializable {

/**

342

Captulo 19 Aplicao J2EE Exemplo


* Identificador do usurio.
*/
private Integer id;

/**
* Nome do usurio.
*/
private String name;

/**
* CPF do usurio.
*/
private String cpf;

/**
* Endereo do usurio.
*/
private String address;

/**
* Email do usurio.
*/
private String email;

/**
* Construtor padro.
*/
public UserTO() {
}

/**
* Construtor customizado.
* @param id identificador do produto.
* @param name nome do produto.
* @param cpf cpf do usurio.
* @param address endereo do usurio.
* @param email email do usurio.
*/
public UserTO(Integer id, String name, String cpf, String address,
String email) {

343

J2EE Primeiros Passos


this.id = id;
this.name = name;
this.cpf = cpf;
this.address = address;
this.email = email;
}

/**
* Obtm o endereo do usurio.
* @return endereo do usurio.
*/
public String getAddress() {
return address;
}

/**
* Configura o endereo do usurio.
* @param address endereo do usurio.
*/
public void setAddress(String address) {
this.address = address;
}

/**
* Obtm o email do usurio.
* @return email do usurio.
*/
public String getEmail() {
return email;
}

/**
* Configura o email do usurio.
* @param email email do usurio.
*/
public void setEmail(String email) {
this.email = email;
}

/**

344

Captulo 19 Aplicao J2EE Exemplo


* Obtm o identificador do usurio.
* @return identificador do usurio.
*/
public Integer getId() {
return id;
}

/**
* Configura o identificador do usurio.
* @param id identificador do usurio.
*/
public void setId(Integer id) {
this.id = id;
}

/**
* Obtm o nome do usurio.
* @return nome do usurio.
*/
public String getName() {
return name;
}

/**
* Configura o nome do usurio.
* @param name nome do usurio.
*/
public void setName(String name) {
this.name = name;
}

/**
* Obtm o cpf do usurio.
* @return cpf do usurio.
*/
public String getCpf() {
return cpf;
}

/**

345

J2EE Primeiros Passos


* Configura o cpf do usurio.
* @param cpf cpf do usurio.
*/
public void setCpf(String cpf) {
this.cpf = cpf;
}

/**
* Avalia se o objeto informado, igual a este objeto.
* @param obj objeto a ser comparado.
* @return verdadeiro caso o objeto seja igual, falso caso contrrio.
*/
public boolean equals(Object obj) {
if ( this == obj ) {
return true;
}

if (!(obj instanceof UserTO)) {


return false;
}

UserTO that = (UserTO) obj;

return this.id == that.id &&


this.name == that.name &&
this.cpf == that.cpf &&
this.address == that.address &&
this.email == that.email;
}

/**
* Chave de Hash, utilizada pelas Maps, para manter este objeto.
* @return chave de hash para este objeto.
*/
public int hashCode() {
int result = 17;
result = 37 * result + id.hashCode();
result = 37 * result + name.hashCode();
result = 37 * result + cpf.hashCode();
result = 37 * result + address.hashCode();

346

Captulo 19 Aplicao J2EE Exemplo


result = 37 * result + email.hashCode();
return result;
}

/**
* Obtm uma descrio textual do objeto.
* @return descrio textual do objeto.
*/
public String toString() {
StringBuffer sb = new StringBuffer(1024);
sb.append([ + id + , + name + , + cpf + , + address
+ , + email + ]);
return sb.toString();
}
}

Assembler : ProductTOAssembler
package com.novatec.book.project.ejb.to;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Collection;
import java.util.List;
import com.novatec.book.project.ejb.entity.impl.ProductLocal;

/**
* Fornece <code>TransferObject</code> de Produto.
*/
public class ProductTOAssembler {

/**
* Cria uma <code>TransferObject</code> a partir da referncia
* remota da entidade produto.
* @param productLocal referncia remota da entidade produto.
* @return objeto <code>TransferObject</code> de produto.
*/
public static ProductTO createTO(ProductLocal productLocal) {
ProductTO productTO = new ProductTO();

if (productLocal != null) {

347

J2EE Primeiros Passos


productTO.setName(productLocal.getName());
productTO.setDescription(productLocal.getDescription());
productTO.setPrice(productLocal.getPrice());
productTO.setId(productLocal.getId());
}
return productTO;
}

/**
* Cria uma coleo de <code>TransferObject</code> do tipo ProductTO.
* @param productLocals coleo de referncias remotas da entidade produto.
* @return coleo de objetos <code>TransferObject</code> ProductTO.
*/
public static ProductTO[] createTOs(Collection productLocals) {
List list = new ArrayList();

if (productLocals != null) {
Iterator iterator = productLocals.iterator();
while (iterator.hasNext()) {
list.add(createTO((ProductLocal) iterator.next()));
}
}
ProductTO[] returnArray = new ProductTO[list.size()];
return (ProductTO[]) list.toArray(returnArray);
}
}

Assembler : UserTOAssembler
package com.novatec.book.project.ejb.to;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Collection;
import java.util.List;
import com.novatec.book.project.ejb.entity.impl.UserLocal;

/**
* Fornece <code>TransferObject</code> de Produto.
*/
public class UserTOAssembler {

348

/**
* Cria uma <code>TransferObject</code> a partir da referncia
* remota da entidade usurio.
* @param userLocal referncia remota da entidade usurio.
* @return objeto <code>TransferObject</code> de usurio.
*/
public static UserTO createTO(UserLocal userLocal) {
UserTO userTO = new UserTO();

if (userLocal != null) {
userTO.setName(userLocal.getName());
userTO.setCpf(userLocal.getCpf());
userTO.setAddress(userLocal.getAddress());
userTO.setEmail(userLocal.getEmail());
}
return userTO;
}

/**
* Cria uma coleo de <code>TransferObject</code> do tipo UserTO.
* @param userLocals coleo de referncias remotas da entidade usurio.
* @return coleo de objetos <code>TransferObject</code> UserTO.
*/
public static UserTO[] createTOs(Collection userLocals) {
List list = new ArrayList();

if (userLocals != null) {
Iterator iterator = userLocals.iterator();
while (iterator.hasNext()) {
list.add(createTO((UserLocal) iterator.next()));
}
}
UserTO[] returnArray = new UserTO[list.size()];
return (UserTO[]) list.toArray(returnArray);
}
}

349

J2EE Primeiros Passos

Business Delegates ProductDelegate e UserDelegate


A seguir seguem os BusinessDelegates que podem ser utilizados pelas camadas superiores (apresentao), para obter os servios dos EJBs.

BusinessDelegate : ProductDelegate
package com.novatec.book.project.delegate;

import java.util.Collection;
import com.novatec.book.project.ejb.ServiceLocator;
import com.novatec.book.project.ejb.ServiceLocatorException;
import

com.novatec.book.project.ejb.entity.ProductSessionFacadeHome;

import

com.novatec.book.project.ejb.entity.ProductSessionFacade;

import com.novatec.book.project.ejb.to.ProductTO;
import com.novatec.book.project.ejb.entity.impl.ProductPK;

/**
* Apresenta o <code>Business Delegate</code> para os servios oferecidos
* pelo <code>Facade</code> de usurio.
*/
public class ProductDelegate {

/**
* Referncia para a interface Home do Facade de produto.
*/
private ProductSessionFacadeHome productSessionFacadeHome;

/**
* Referncia para a interface Remote do Facade de produto.
*/
private ProductSessionFacade productSessionFacade;

/**
* Construtor customizado.
* @throws java.lang.Exception se ocorrer erro ao obter as referncias.
*/
public ProductDelegate() throws Exception {
initializeProductSessionFacadeHome();
productSessionFacade = productSessionFacadeHome.create();
}

350

Captulo 19 Aplicao J2EE Exemplo

/**
* Cria um produto dado o seu <code>TransferObject</code>.
* @param productTO <code>TransferObject</code> de produto.
* @throws Exception se ocorrer erro na criao do produto.
*/
public void createProduct(ProductTO productTO) throws Exception {
productSessionFacade.createProduct(productTO);
}

/**
* Remove o produto associado chave primria informada.
* @param productPK chave primria do produto.
* @throws Exception se ocorrer erro na remoo do produto.
*/
public void removeProduct(ProductPK productPK) throws Exception {
productSessionFacade.removeProduct(productPK);
}

/**
* Remove o produto cujo <code>TransferObject</code> representa.
* @param productTO <code>TransferObject</code> do produto.
* @throws Exception se ocorrer erro na remoo do produto.
*/
public void removeProduct(ProductTO productTO) throws Exception {
productSessionFacade.removeProduct(productTO);
}

/**
* Atualiza os dados do produto pelo <code>TransferObject</code>.
* @param productTO <code>TransferObject</code> do produto.
* @throws Exception se ocorrer erro na atualizao do produto.
*/
public void updateProduct(ProductTO productTO) throws Exception {
productSessionFacade.updateProduct(productTO);
}

/**
* Atualiza os dados dos produtos contidos na coleo de produtos.
* @param productDtos coleo de <code>TransferObject</code> de produto.

351

J2EE Primeiros Passos


* @throws Exception se ocorrer erro ao atualizar dos produtos.
*/
public void updateProducts(ProductTO[] productDtos) throws Exception {
productSessionFacade.updateProducts(productDtos);
}

/**
* Localiza um produto dado a sua chave primria.
* @param productPK chave primria do produto.
* @return <code>TransferObject</code> do produto.
* @throws Exception se ocorrer erro ao localizar o produto.
*/
public ProductTO productFindByPrimaryKey(ProductPK productPK) throws
Exception {
return productSessionFacade.productFindByPrimaryKey(productPK);
}

/**
* Localiza a coleo de produtos.
* @return coleo de <code>TransferObject</code> do produto.
* @throws Exception se ocorrer erro ao localizar o produto.
*/
public Collection productFindAll() throws Exception {
return productSessionFacade.productFindAll();
}

/**
* Cria referncia para o Facade de produto.
* @throws java.lang.Exception se ocorrer erro ao localizar o componente.
*/
private void initializeProductSessionFacadeHome() throws Exception {
String FACADE_NAME =
ejb/SESSION/com/novatec/book/project/ejb/entity/
ProductSessionFacade;
Class FACADE_CLASS = com.novatec.book.project.ejb.entity.
ProductSessionFacadeHome.class;
if (productSessionFacadeHome == null) {
try {
ServiceLocator locator = ServiceLocator.getInstance();
productSessionFacadeHome = (ProductSessionFacadeHome) locator.
getEjbHome(FACADE_NAME, FACADE_CLASS);

352

Captulo 19 Aplicao J2EE Exemplo


if (productSessionFacadeHome == null) {
throw new Exception(Did not get home for + FACADE_NAME);
}
} catch (ServiceLocatorException e) {
throw new Exception(e.getMessage());
}
}
}
}

BusinessDelegate : UserDelegate
package com.novatec.book.project.delegate;

import com.novatec.book.project.ejb.ServiceLocator;
import com.novatec.book.project.ejb.ServiceLocatorException;
import

com.novatec.book.project.ejb.entity.UserSessionFacadeHome;

import com.novatec.book.project.ejb.entity.UserSessionFacade;
import com.novatec.book.project.ejb.to.UserTO;

/**
* Apresenta o <code>Business Delegate</code> para os servios oferecidos
* pelo <code>Facade</code> de usurio.
*/
public class UserDelegate {

/**
* Referncia para a interface Home do Facade de usurio.
*/
private UserSessionFacadeHome userSessionFacadeHome;

/**
* Referncia para a interface Remote do Facade de usurio.
*/
private UserSessionFacade userSessionFacade;

/**
* Construtor customizado.
* @throws java.lang.Exception se ocorrer erro ao obter as referncias.
*/
public UserDelegate() throws Exception {

353

J2EE Primeiros Passos


initializeUserSessionFacadeHome();
userSessionFacade = userSessionFacadeHome.create();
}

/**
* Cria um usurio dado o seu <code>TransferObject</code>.
* @param userTO <code>TransferObject</code> de usurio.
* @throws Exception se ocorrer erro na criao do usurio.
*/
public void createUser(UserTO userTO) throws Exception {
userSessionFacade.createUser(userTO);
}

/**
* Remove o usurio associado chave primria informada.
* @param cpf cpf do usurio.
* @throws Exception se ocorrer erro na remoo do usurio.
*/
public void removeUser(String cpf) throws Exception {
userSessionFacade.removeUser(cpf);
}

/**
* Remove o usurio cujo <code>TransferObject</code> representa.
* @param userTO <code>TransferObject</code> do usurio.
* @throws Exception se ocorrer erro na remoo do usurio.
*/
public void removeUser(UserTO userTO) throws Exception {
userSessionFacade.removeUser(userTO);
}

/**
* Atualiza os dados do usurio pelo <code>TransferObject</code>.
* @param userTO <code>TransferObject</code> do usurio.
* @throws Exception se ocorrer erro na atualizao do usurio.
*/
public void updateUser(UserTO userTO) throws Exception {
userSessionFacade.updateUser(userTO);
}

354

Captulo 19 Aplicao J2EE Exemplo


/**
* Atualiza os dados dos usurios contidos na coleo de usurios.
* @param userTOs coleo de <code>TransferObject</code> de usurio.
* @throws Exception se ocorrer erro ao atualizar os usurios.
*/
public void updateUsers(UserTO[] userDtos) throws Exception {
userSessionFacade.updateUsers(userDtos);
}
/**
* Localiza um usurio dado a sua chave primria.
* @param cpf cpf do usurio.
* @return <code>TransferObject</code> do usurio.
* @throws Exception se ocorrer erro ao localizar o produto.
*/
public UserTO userFindByPrimaryKey(String cpf) throws Exception {
return userSessionFacade.userFindByPrimaryKey(cpf);
}
/**
* Cria referncia para o Facade de usurio.
* @throws java.lang.Exception se ocorrer erro ao localizar o componente.
*/
private void initializeUserSessionFacadeHome() throws Exception {
String FACADE_NAME =
ejb/SESSION/com/novatec/book/project/ejb/entity/UserSessionFacade;
Class FACADE_CLASS = com.novatec.book.project.ejb.entity.
UserSessionFacadeHome.class;
if (userSessionFacadeHome == null) {
try {
ServiceLocator locator = ServiceLocator.getInstance();
userSessionFacadeHome = (UserSessionFacadeHome) locator.
getEjbHome(FACADE_NAME, FACADE_CLASS);
if (userSessionFacadeHome == null) {
throw new Exception(Did not get home for + FACADE_NAME);
}
} catch (ServiceLocatorException e) {
throw new Exception(e.getMessage());
}
}
}
}

355

J2EE Primeiros Passos

ServiceLocator
A seguir seguem o ServiceLocator da aplicao e sua exceo especfica.

ServiceLocator
package com.novatec.book.project.ejb;

import javax.rmi.PortableRemoteObject;
import javax.naming.NamingException;
import javax.naming.InitialContext;
import javax.naming.Context;
import javax.ejb.EJBHome;
import javax.ejb.EJBLocalHome;

/**
* Apresenta o <code>ServiceLocator</code> utilizado pelas classes para
* localizar EJBs.
*/
public class ServiceLocator {

/**
* Instncia nica do locator.
*/
private static ServiceLocator serviceLocator;

/**
* Instncia nica do contexto.
*/
private static Context context;

/**
* Construtor customizado.
* Impede que seja acessado externamente.
* @throws ServiceLocatorException se ocorrer erro ao obter o contexto
* inicial.
*/
protected ServiceLocator() throws ServiceLocatorException {
context = getInitialContext();
}

356

Captulo 19 Aplicao J2EE Exemplo


/**
* Obtm a referncia remota para a interface <code>Home</code> do EJB
* informado.
* @param ejbName nome do EJB.
* @param ejbClass classe do EJB.
* @return referncia para a interface <code>Home</code> do EJB informado.
* @throws ServiceLocatorException se ocorrer erro ao obtr a referncia.
*/
public static EJBHome getEjbHome(String ejbName, Class ejbClass) throws
ServiceLocatorException {
try {
Object object = context.lookup(ejbName);
EJBHome ejbHome = null;
ejbHome = (EJBHome) PortableRemoteObject.narrow(object, ejbClass);
if (ejbHome == null) {
throw new ServiceLocatorException(Could not get home for +
ejbName);
}
return ejbHome;
} catch (NamingException ne) {
throw new ServiceLocatorException(ne.getMessage());
}
}
/**
* Obtm uma referncia local para a interface <code>Home</code> do EJB
* informado.
* @param ejbName nome do EJB.
* @return referncia local para a interface <code>Home</code> do EJB.
* @throws ServiceLocatorException se ocorrer erro ao localizar o EJB.
*/
public static EJBLocalHome getEjbLocalHome(String ejbName) throws
ServiceLocatorException {
try {
Object object = context.lookup(ejbName);
EJBLocalHome ejbLocalHome = null;
ejbLocalHome = (EJBLocalHome) object;
if (ejbLocalHome == null) {
throw new ServiceLocatorException(
Could not get local home for + ejbName);
}

357

J2EE Primeiros Passos


return ejbLocalHome;
} catch (NamingException ne) {
throw new ServiceLocatorException(ne.getMessage());
}
}
/**
* Obtm uma instncia do <code>ServiceLocator</code>.
* @return instncia do <code>ServiceLocator</code>.
* @throws ServiceLocatorException
*/
public static synchronized ServiceLocator getInstance() throws
ServiceLocatorException {
if (serviceLocator == null) {
serviceLocator = new ServiceLocator();
}
return serviceLocator;
}
/**
* Obtm o contexto inicial para localizar os componentes.
* @return contexto inicial para localizar os componentes.
* @throws ServiceLocatorException se ocorrer erro ao criar o contexto.
*/
protected static Context getInitialContext()
throws ServiceLocatorException {
try {
return new InitialContext();
} catch (NamingException e) {
throw new ServiceLocatorException(e.getMessage());
}
}
}

ServiceLocatorException
package com.novatec.book.project.ejb;

/**
* Exceo utilizada pelo <code>ServiceLocator</code>.
*/
public class ServiceLocatorException extends Exception {

358

Captulo 19 Aplicao J2EE Exemplo

/**
* Construtor customizado.
* @param message mensagem de erro.
*/
public ServiceLocatorException(String message) {
super(message);
}
}

Descritores Completos
Deployment Descriptor completo da Aplicao Exemplo : ejb-jar.xml
<?xml version=1.0" encoding=UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC -//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//
EN http://java.sun.com/dtd/ejb-jar_2_0.dtd>
<ejb-jar>
<enterprise-beans>
<session>
<display-name>ProjectSupport</display-name>
<ejb-name>ProjectSupport</ejb-name>
<home>com.novatec.book.project.ejb.session.ProjectSupportHome</home>
<remote>com.novatec.book.project.ejb.session.ProjectSupport</remote>
<ejb-class>
com.novatec.book.project.ejb.session.ProjectSupportBean
</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
<session>
<display-name>SalesBasket</display-name>
<ejb-name>SalesBasket</ejb-name>
<home>com.novatec.book.project.ejb.session.SalesBasketHome</home>
<remote>com.novatec.book.project.ejb.session.SalesBasket</remote>
class>

<ejb-class>com.novatec.book.project.ejb.session.SalesBasketBean</ejb<session-type>Stateful</session-type>
<transaction-type>Container</transaction-type>
<ejb-ref>
<description />

359

J2EE Primeiros Passos


<ejb-ref-name>ejb/productfacade</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
home>
remote>

<home>com.novatec.book.project.ejb.entity.ProductSessionFacadeHome</
<remote>com.novatec.book.project.ejb.entity.ProductSessionFacade</
<ejb-link>ProductSessionFacade</ejb-link>
</ejb-ref>
</session>
<session>
<display-name>SalesSupport</display-name>
<ejb-name>SalesSupport</ejb-name>
<home>com.novatec.book.project.ejb.session.SalesSupportHome</home>
<remote>com.novatec.book.project.ejb.session.SalesSupport</remote>

class>

<ejb-class>com.novatec.book.project.ejb.session.SalesSupportBean</ejb<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
<session>
<display-name>ProductSessionFacade</display-name>
<ejb-name>ProductSessionFacade</ejb-name>
<home>com.novatec.book.project.ejb.entity.ProductSessionFacadeHome</home>
<remote>com.novatec.book.project.ejb.entity.ProductSessionFacade</remote>
<ejb-class>
com.novatec.book.project.ejb.entity.ProductSessionFacadeBean
</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
<ejb-local-ref>
<description />
<ejb-ref-name>ejb/product</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<local-home>
com.novatec.book.project.ejb.entity.impl.ProductLocalHome
</local-home>
<local>com.novatec.book.project.ejb.entity.impl.ProductLocal</local>
<ejb-link>Product</ejb-link>
</ejb-local-ref>
</session>
<session>

360

Captulo 19 Aplicao J2EE Exemplo


<display-name>UserSessionFacade</display-name>
<ejb-name>UserSessionFacade</ejb-name>
<home>com.novatec.book.project.ejb.entity.UserSessionFacadeHome</home>
<remote>com.novatec.book.project.ejb.entity.UserSessionFacade</remote>
<ejb-class>
com.novatec.book.project.ejb.entity.UserSessionFacadeBean
</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
<ejb-local-ref>
<description />
<ejb-ref-name>ejb/user</ejb-ref-name>
<ejb-ref-type>Entity</ejb-ref-type>
<local-home>com.novatec.book.project.ejb.entity.impl.UserLocalHome</

local-home>

<local>com.novatec.book.project.ejb.entity.impl.UserLocal</local>
<ejb-link>User</ejb-link>
</ejb-local-ref>
</session>
<entity>
<display-name>Product</display-name>
<ejb-name>Product</ejb-name>
local-home>

<local-home>com.novatec.book.project.ejb.entity.impl.ProductLocalHome</
<local>com.novatec.book.project.ejb.entity.impl.ProductLocal</local>

class>

<ejb-class>com.novatec.book.project.ejb.entity.impl.ProductBean</ejb<persistence-type>Container</persistence-type>

<prim-key-class>com.novatec.book.project.ejb.entity.impl.ProductPK</
prim-key-class>
<reentrant>False</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>Product</abstract-schema-name>
<cmp-field>
<field-name>name</field-name>
</cmp-field>
<cmp-field>
<field-name>description</field-name>
</cmp-field>
<cmp-field>
<field-name>price</field-name>
</cmp-field>

361

J2EE Primeiros Passos


<cmp-field>
<field-name>id</field-name>
</cmp-field>
<query>
<query-method>
<method-name>findAll</method-name>
<method-params />
</query-method>
<ejb-ql>SELECT OBJECT(p) FROM Product p</ejb-ql>
</query>
</entity>
<entity>
<display-name>User</display-name>
<ejb-name>User</ejb-name>
local-home>

<local-home>com.novatec.book.project.ejb.entity.impl.UserLocalHome</
<local>com.novatec.book.project.ejb.entity.impl.UserLocal</local>
<ejb-class>com.novatec.book.project.ejb.entity.impl.UserBean</ejb-class>
<persistence-type>Bean</persistence-type>
<prim-key-class>java.lang.String</prim-key-class>
<reentrant>False</reentrant>

</entity>
<message-driven>
<display-name>UserNotifier</display-name>
<ejb-name>UserNotifier</ejb-name>
<ejb-class>com.novatec.book.project.ejb.mdb.UserNotifierBean</ejb-class>
<transaction-type>Container</transaction-type>
<message-driven-destination>
<destination-type>javax.jms.Queue</destination-type>
</message-driven-destination>
</message-driven>
</enterprise-beans>
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>ProjectSupport</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>

362

Captulo 19 Aplicao J2EE Exemplo


<method>
<ejb-name>SalesBasket</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>SalesSupport</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>UserNotifier</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>Product</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>User</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
<container-transaction>
<method>
<ejb-name>ProductSessionFacade</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>

363

J2EE Primeiros Passos


</container-transaction>
<container-transaction>
<method>
<ejb-name>UserSessionFacade</ejb-name>
<method-name>*</method-name>
</method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar>

Deployment Descriptor especfico para o JBoss : jboss.xml


<?xml version=1.0" encoding=UTF-8"?>
<!DOCTYPE jboss PUBLIC -//JBoss//DTD JBOSS 3.0//EN http://www.jboss.org/j2ee/dtd/
jboss_3_0.dtd>

<jboss>
<enterprise-beans>
<session>
<ejb-name>ProjectSupport</ejb-name>
<jndi-name>ejb/SESSION/com/novatec/book/project/ejb/session/
ProjectSupport</jndi-name>
</session>
<session>
<ejb-name>SalesBasket</ejb-name>
<jndi-name>ejb/SESSION/com/novatec/book/project/ejb/session/
SalesBasket</jndi-name>
<ejb-ref>
<ejb-ref-name>ejb/productfacade</ejb-ref-name>
<jndi-name>
ejb/SESSION/com/novatec/book/project/ejb/entity/
ProductSessionFacade
</jndi-name>
</ejb-ref>
</session>
<session>
<ejb-name>SalesSupport</ejb-name>
<jndi-name>ejb/SESSION/com/novatec/book/project/ejb/session/
SalesSupport</jndi-name>
</session>
<session>
<ejb-name>ProductSessionFacade</ejb-name>

364

Captulo 19 Aplicao J2EE Exemplo


<jndi-name>ejb/SESSION/com/novatec/book/project/ejb/entity/
ProductSessionFacade
</jndi-name>
<ejb-local-ref>
<ejb-ref-name>ejb/product</ejb-ref-name>
<local-jndi-name>ejb/CMP/com/novatec/book/project/ejb/entity/Product
</local-jndi-name>
</ejb-local-ref>
</session>
<session>
<ejb-name>UserSessionFacade</ejb-name>
<jndi-name>ejb/SESSION/com/novatec/book/project/ejb/entity/
UserSessionFacade
</jndi-name>
<ejb-local-ref>
<ejb-ref-name>ejb/user</ejb-ref-name>
<local-jndi-name>ejb/CMP/com/novatec/book/project/ejb/entity/User
</local-jndi-name>
</ejb-local-ref>
</session>
<entity>
<ejb-name>Product</ejb-name>
<local-jndi-name>ejb/CMP/com/novatec/book/project/ejb/entity/Product
</local-jndi-name>
</entity>
<entity>
<ejb-name>User</ejb-name>
<local-jndi-name>ejb/CMP/com/novatec/book/project/ejb/entity/User</
local-jndi-name>
</entity>
<message-driven>
<ejb-name>UserNotifier</ejb-name>
<destination-jndi-name>queue/testQueue</destination-jndi-name>
</message-driven>
</enterprise-beans>
</jboss>

Deployment Descriptor especfico para o JBoss : jbosscmp-jdbc.xml


<?xml version=1.0" encoding=UTF-8"?>
<!DOCTYPE jbosscmp-jdbc PUBLIC -//JBoss//DTD JBOSSCMP-JDBC 3.0//EN http://
www.jboss.org/j2ee/dtd/jbosscmp-jdbc_3_0.dtd>

365

J2EE Primeiros Passos


<jbosscmp-jdbc>
<defaults>
<create-table>true</create-table>
<remove-table>true</remove-table>
</defaults>
<enterprise-beans>
<entity>
<ejb-name>Product</ejb-name>
<table-name>PRODUCT</table-name>
<cmp-field>
<field-name>name</field-name>
<column-name>NAME</column-name>
</cmp-field>
<cmp-field>
<field-name>description</field-name>
<column-name>DESCRIPTION</column-name>
</cmp-field>
<cmp-field>
<field-name>price</field-name>
<column-name>PRICE</column-name>
</cmp-field>
<cmp-field>
<field-name>id</field-name>
<column-name>ID</column-name>
</cmp-field>
</entity>
</enterprise-beans>
</jbosscmp-jdbc>

Observe que este exemplo apresentou somente a camada de negcio, implementada


com o uso dos componentes EJBs. Deixamos a cargo do leitor implementar a camada
de apresentao do exemplo, utilizando os conceitos abordados na Parte I deste livro. Disponibilizamos neste exemplo um BusicessDelegate, que poder ser utilizado
pela camada de apresentao para prover os servios necessrios e implementados
nos componentes EJB.

366

Apndice A
Glossrio
ACID propriedades de segurana. Atomicity Consistency Isolation Durability.
ANT makefile opensource utilizado para compilar e empacotar aplicaes Java.
API Application Program Interface.
BMP Bean Managed Persistence. Estratgia de persistncia utilizada em EJB Entity
Bea, na qual o prprio bean, isto , o programador deve definir a forma de persistncia dos dados do objeto.
BMT Bean Managed Transaction. Transao gerenciada pelo bean.
CMP Container Managed Persistence. Estratgia de persistncia utilizada em EJB
Entity Bean, na qual o prprio container se encarrega de persistir e manter os dados
do objeto.
CMT Container Managed Transaction. Transao gerenciada pelo container.
EAR Enterprise Archive. Utilizado para empacotar aplicaes Java Enterprise.
EJB Enterprise JavaBean. Componente utilizado na arquitetura J2EE.
EJB-QL Enterprise JavaBean Query Language. O mesmo que EQL.
EQL Enterprise Query Language. Utilizado para realizar consultas para EJB Entity
Bean. Tambm conhecida como EJB-QL.
J2SDK Java 2 Software Development Kit.
J2SE Java 2 Standart Edition. API Java para aplicaes standalone.
J2EE Java 2 Enterprise Edition. API Java para aplicao Enterprise.
J2EE SDK J2EE Software Development Kit.
JAR Java Archive. Utilizado para empacotar aplicaes e classes Java standalone.

367

J2EE Primeiros Passos


JNDI Java Naming Directory Interface. Utilizado para localizar componentes em
uma rvore de componentes.
JSP Java ServerPages. Componente Web para renderizar contedos visuais.
MOM Middleware Oriented Message.
RAR Resource Archive. Utilizado para empacotar recursos externos.
SQL Structure Query Language. Linguagem de consulta estruturada, utilizada em
bancos de dados relacionais.
WAR Web Application Archive. Utilizado para empacotar aplicaes Web.

368

Apndice B
Bibliografia
BOOCH G., RUMBAUGH J. JACOBSON I., UML Guia do Referncia. Rio de Janeiro: Editora Campus, 2000.
BLOCH J. Effective Java Programming Language Guide. 1.ed.: Addisson-Wesley,
2002.
CRUPI J.; MALKS D.; ALUR D. Core J2EE Patterns: As melhores prticas e estratgias de design. 1.ed.:Rio de Janeiro: Editora Campus, 2002.
FOWLER M., SCOTT K. UML Essencial. 2.ed.: Porto Alegre: Bookman, 2000.
GAMMA, E.; HELM, R.; JOHNSON R.; VLISSIDES J. Padres de Projeto: Solues
Reutilizveis de Software Orientado a Objetos. Porto Alegre: Bookman, 2002.
HALL M. Core Servlets and Javaserver Pages 1.ed: Prentice Hall, 2001.
TANEMBAUM, A. S. Distributed Operating Systems, Prentice Hall, 1994.

369