Sie sind auf Seite 1von 225

JAVA NA PRTICA

Tpicos Avanados
JDBC Threads Redes RMI CORBA Servlets JSP

Alcione de Paiva Oliveira


Vincius Valente Maciel

8 de Novembro de 2003

Direitos Autorais

Todos os direitos sobre esta obra esto reservados para os autores do livro. Texto registrado na Biblioteca Nacional: registro
297.373, livro 540, folha 33.

O48J
OLIVEIRA, Alcione de Paiva
Java na prtica, tpicos avanados: RMI CORBA
JDBC threads redes servlets JSP / Alcione de Paiva Oliveira,
Vincius Valente Maciel. - Viosa : Fbrica de Livros Ed.,
2003.
225 p. il.
1. Linguagem de programao. 2. Java. I. MACIEL,
Vincius Valente. II. Ttulo.
CDD: 005.133
CDU: 519.682

Sobre os Autores
Alcione de Paiva Oliveira Doutor em Informtica pela
PUC-Rio, Mestre em Cincias pelo Instituto Militar de Engenharia e Bacharel em Oceanograa pela UERJ. Ex-diretor tcnico
da INFAX Tecnologia e Sistemas e ex-coordenador do curso de
Engenharia de Computao do Instituto Militar de Engenharia.
Atualmente exerce o cargo de professor Adjunto do Departamento
de Informtica da Universidade Federal de Viosa. Suas reas de
interesse so Inteligncia Articial, Linguagens de Programao e
Engenharia de Software.
Vincius Valente Maciel Mestrando em Cincia da Computao pela Universidade Federal Fluminense e Bacharel em Cincia da Computao pela Universidade Federal de Viosa. Atualmente exerce o cargo de Analista de Sistemas da INFAX Tecnologia e Sistemas Ltda. Suas reas de interesse so Especicao Formal de Sistemas, Linguagens de Programao, Sistemas de
Tempo-Real e Engenharia de Software.

AGRADECIMENTOS

A elaborao do presente trabalho contou com a colaborao direta e indireta de diversas pessoas. Primeiramente gostaramos de
agradecer nossas mulheres e companheiras Alexandra e Andria
que nos apoiaram (e nos toleraram) em todos os momentos. Da
mesma forma gostaramos de agradecer a nossos pais que sempre esto ao nosso lado. No podemos esquecer tambm todos os
nossos alunos que ajudaram com sugestes quando este material
ainda era uma apostila. Finalmente, gostaramos de agradecer a
todos que direta e indiretamente ajudaram na concretizao deste
sonho.

PREFCIO

O propsito deste livro tentar preencher um espao no coberto


pelos livros relacionados com a linguagem Java. No existe, at
o momento, um livro que aborde um conjunto de tpicos avanados da linguagem e que seja, ao mesmo tempo, didtico e prtico.
De modo a promover a didtica procuramos nos ater aos principais aspectos dos assuntos tratados, sem tentar esgotar todos os
aspectos do tema. J o lado prtico advm do uso intensivo de
exemplos. Alm disso, existe um exemplo, o da agenda eletrnica,
que apresentado com um grau crescente de complexidade, o que
permite que o leitor dirija sua ateno para as novas tcnicas que
esto sendo introduzidas. O exemplo da agenda eletrnica possui
um grau de complexidade suciente para ser usado como embrio
de sistemas mais sosticados.
O livro aborda os recursos da linguagem para o tratamento de
concorrncia, acesso a banco de dados, programao em redes e
programao para a Web. Estes so assuntos que no so abordados em muitos livros com um nmero bem maior de pginas.
Mesmo os livros existentes em tpicos avanados cobrem apenas
um ou dois dos tpicos mencionados.
Esperamos que o livro cumpra o objetivo proposto e permita
que os leitores possam tirar o mximo de proveito da linguagem
Java.

LISTA DE SIGLAS

ASP
AWT
CGI
GUI
CORBA
CPU
DMZ
FAPESP
HTML
HTTP
IP
JDBC
JDK
JSP
MIME
MVC
ODBC
ORB
PHP
RMI
TCP
UDP
URI
URL

ActiveServer Pages
Abstract Window Toolkit
Common Gateway Interface
graphical user interface
Common Object Request Broker Architecture
Central Processing Unit
Demilitarized Zone
Fundao de Amparo Pesquisa do Estado de
So Paulo
Hypertext Markup Language
Hypertext Transfer Protocol
Internet Protocol
Java Database Connectivity
Java Development Toolkit
Java Server Pages
Multipurpose Internet Mail Extensions
modelo-viso-controle
Open Database Connectivity
Object Request Broker
Personal Home Pages
Remote Method Invocation
Transmission Control Protocol
User Datagram Protocol
Uniform Resource Identier
Uniform Resource Locator

Contedo
1 Introduo
1.1

Convenes . . . . . . . . . . . . . . . . . . . . . .

2 Concorrncia
2.1
2.2
2.3
2.4
2.5

2.6

Criando threads em Java . . . . . . . . . . . . . . .


2.1.1 Usando a interface Runnable . . . . . . . .
A classe Thread . . . . . . . . . . . . . . . . . . . .
2.2.1 Variveis pblicas . . . . . . . . . . . . . .
Ciclo de Vida dos Threads . . . . . . . . . . . . . .
2.3.1 sleep(), yield(), join(), stop(), suspend() e
resume() . . . . . . . . . . . . . . . . . . . .
Daemon Threads . . . . . . . . . . . . . . . . . . .
A Inuncia do Sistema Operacional sobre os Threads
2.5.1 Forma de escalonamento de threads . . . .
2.5.2 Relacionamento entre os nveis de prioridades denidas na linguagem Java e os nveis
de prioridades denidas nos Sistemas Operacionais . . . . . . . . . . . . . . . . . . . .
Compartilhamento de Memria e Sincronizao . .
2.6.1 Atomicidade de Instrues e Sincronizao
do Acesso Sesses Crticas . . . . . . . . .
2.6.2 Comunicao entre Threads: wait() e notify()

3 Programao em rede
3.1

Conceitos Sobre Protocolos Usados na Internet . .


3.1.1 TCP . . . . . . . . . . . . . . . . . . . . . .
v

1
6

10
13
14
17
18

19
23
25
26

27
28
32
39

55

55
57

3.2

3.1.2 UDP . . . . . . . . . . . . . . . . . . . . . .
3.1.3 Identicao de Hosts (Nmero IP) . . . . .
3.1.4 Identicao de Processos (Portas) . . . . .
Programao em Rede com Java . . . . . . . . . .
3.2.1 Comunicao Bsica Entre Aplicaes . . .
3.2.2 Comunicao orientada a conexo (cliente)
3.2.3 Comunicao orientada conexo (servidor)
3.2.4 Comunicao Sem Conexo (UDP) . . . . .
3.2.5 Comunicao por meio de URL . . . . . . .
3.2.6 Manipulando URLs em Java . . . . . . . .
3.2.7 Comunicando por meio de URLConnection

4 Acesso a Banco de Dados


4.1
4.2

Modelos de Acesso a Servidores . . . . . . . . . .


Tipos de Drivers JDBC . . . . . . . . . . . . . .
4.2.1 Obtendo os Drivers JDBC . . . . . . . . .
4.3 Preparando o Banco de Dados . . . . . . . . . .
4.4 Exemplo Inicial . . . . . . . . . . . . . . . . . . .
4.4.1 Carregando o Driver . . . . . . . . . . . .
4.4.2 Estabelecendo a conexo . . . . . . . . . .
4.4.3 Criando e Executando Comandos . . . . .
4.5 Recuperando Valores . . . . . . . . . . . . . . . .
4.6 Trabalhando com Metadados . . . . . . . . . . .
4.7 Trabalhando com datas . . . . . . . . . . . . . .
4.8 Transaes e Nvel de Isolamento . . . . . . . .
4.8.1 Transao . . . . . . . . . . . . . . . . . .
4.8.2 Nveis de isolamento . . . . . . . . . . . .
4.9 Prepared Statements . . . . . . . . . . . . . . . .
4.10 Procedimentos Armazenados (Stored Procedures)
4.11 Agenda Eletrnica verso JDBC . . . . . . . . .
4.12 Como congurar a ponte JDBC-ODBC . . . . .

5 RMI
5.1
5.2

Arquitetura RMI . . . . . . . . . .
Criando nossa agenda distribuda .
5.2.1 Passo a Passo . . . . . . . .
5.2.2 Implementando interface do
5.2.3 Escrevendo objeto remoto .

. . . .
. . . .
. . . .
objeto
. . . .

58
58
59
60
61
61
63
66
69
70
72

75

. 76
. 77
. 79
. 79
. 84
. 85
. 85
. 86
. 87
. 89
. 91
. 92
. 92
. 94
. 97
. 98
. 100
. 107

. . . . .
. . . . .
. . . . .
remoto
. . . . .

111

112
112
112
113
114

5.2.4
5.2.5

5.3

Gerando Stub . . . . . . . .
Desenvolvendo o cdigo que
objeto . . . . . . . . . . . .
5.2.6 Escrevendo o cliente . . . .
Testando tudo . . . . . . . . . . . .
5.3.1 No Windows . . . . . . . .
5.3.2 No Linux . . . . . . . . . .

6 CORBA
6.1
6.2

6.3

O que CORBA? . . . . . . . . . . . . .
Exemplo CORBA em Java . . . . . . . . .
6.2.1 Escrevendo a IDL . . . . . . . . .
6.2.2 Compilando a IDL . . . . . . . . .
6.2.3 Implementando nosso Objeto . . .
6.2.4 Escrevendo o servidor . . . . . . .
6.2.5 Escrevendo o cliente . . . . . . . .
6.2.6 Rodando o exemplo . . . . . . . .
Exemplo CORBA (Java + C) . . . . . . .
6.3.1 Compilando a IDL . . . . . . . . .
6.3.2 Implementando nosso Objeto . . .
6.3.3 Escrevendo o Servidor . . . . . . .
6.3.4 Escrevendo o Cliente . . . . . . . .
6.3.5 Compilando e Rodando o Exemplo

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

Servlets . . . . . . . . . . . . . . . . . . . . . .
7.1.1 Applets X Servlets . . . . . . . . . . . .
7.1.2 CGI X Servlets . . . . . . . . . . . . . .
A API Servlet . . . . . . . . . . . . . . . . . . .
7.2.1 Exemplo de Servlet . . . . . . . . . . . .
Compilando o Servlet . . . . . . . . . . . . . .
7.3.1 Instalando o Tomcat . . . . . . . . . . .
Preparando para executar o Servlet . . . . . . .
7.4.1 Compilando o Servlet . . . . . . . . . .
7.4.2 Criando uma aplicao no Tomcat . . .
Executando o Servlet . . . . . . . . . . . . . . .
7.5.1 Invocando diretamente pelo Navegador .
7.5.2 Invocando em uma pgina HTML . . .

.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.

7 Servlets e JSP
7.1
7.2
7.3
7.4
7.5

. . . . . . . . .
disponibiliza o
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

115
115
116
117
117
118

119

119
126
126
127
127
128
129
130
130
131
132
132
134
135

137

137
139
139
139
142
143
143
148
148
148
149
149
150

7.5.3 Diferenas entre as requisies GET e POST 150


Concorrncia . . . . . . . . . . . . . . . . . . . . . 151
Obtendo Informaes sobre a Requisio . . . . . 154
Lidando com Formulrios . . . . . . . . . . . . . . 156
Lidando com Cookies . . . . . . . . . . . . . . . . . 157
Lidando com Sesses . . . . . . . . . . . . . . . . . 161
JSP . . . . . . . . . . . . . . . . . . . . . . . . . . 164
7.11.1 PHP X JSP . . . . . . . . . . . . . . . . . . 166
7.11.2 ASP X JSP . . . . . . . . . . . . . . . . . . 166
7.11.3 Primeiro exemplo em JSP . . . . . . . . . . 167
7.11.4 Executando o arquivo JSP . . . . . . . . . . 168
7.11.5 Objetos implcitos . . . . . . . . . . . . . . 169
7.11.6 Tags JSP . . . . . . . . . . . . . . . . . . . 169
7.11.7 Extraindo Valores de Formulrios . . . . . . 175
7.11.8 Criando e Modicando Cookies . . . . . . . 177
7.11.9 Lidando com sesses . . . . . . . . . . . . . 178
7.11.10 O Uso de JavaBeans . . . . . . . . . . . . . 180
7.11.11 Escopo do bean . . . . . . . . . . . . . . . . 183
7.12 Reencaminhando ou Redirecionando requisies . . 187
7.13 Uma Arquitetura para comrcio eletrnico . . . . . 189
7.13.1 Tipos de aplicaes na WEB . . . . . . . . 189
7.13.2 Arquitetura MVC para a Web . . . . . . . 190
7.13.3 Agenda Web: Um Exemplo de uma aplicao Web usando a arquitetura MVC . . . . 192
7.6
7.7
7.8
7.9
7.10
7.11

Captulo 1

Introduo
Java uma linguagem de programao desenvolvida pela Sun Microsystems e lanada em verso beta em 1995. O seu desenvolvimento foi iniciado em 1991 pela equipe liderada por James Gosling visando o mercado de bens eletrnicos de consumo. Por isso
foi projetada desde o incio para ser independente de hardware,
uma vez que as caractersticas dos equipamentos variam amplamente neste nicho de desenvolvimento. Outro objetivo estabelecido desde sua concepo foi o de ser uma linguagem segura. Segura tanto no sentido de evitar algumas falhas comuns que os programadores costumam cometer durante o desenvolvimento, como
no sentido de evitar ataques externos. Isto importante no mercado de bens eletrnicos de consumo porque ningum gostaria de
adquirir um produto que necessitasse desligar e religar para que
voltasse a funcionar corretamente. Estas caractersticas despertaram o interesse para utilizao de Java em outro ambiente que
tambm necessitava de uma linguagem com este perl: a Internet.
A Internet tambm um ambiente constitudo por equipamentos de diferentes arquiteturas e necessita muito de uma linguagem
que permita a construo de aplicativos seguros. Muitas pessoas
argumentaro que estas caractersticas podem ser encontradas em
outras linguagens e portanto isto no explica o sbito sucesso da
linguagem. Podemos arriscar alguns palpites apesar de este ser
um terreno um pouco pantanoso para se aventurar, at porque
1

Java na prtica

as linguagens de programao tendem assumir um carter quase


religioso. Uma das razes que na nossa opinio favoreceram a
rpida adoo da linguagem foi a sintaxe. Java sintaticamente
muito semelhante linguagem C/C++, apesar de existirem diferenas fundamentais na losoa de implementao entre as duas
linguagens. Isto facilitou a migrao de uma legio imensa de
programadores C/C++ para a nova linguagem. Outra razo que
no pode ser desprezada o momento atual onde os desenvolvedores esto ansiosos para se libertarem de sistemas proprietrios.
Portanto, apesar de no serem novas as idias embutidas na linguagem Java, a reunio delas em uma s linguagem, juntamente
com a facilidade de migrao dos programadores e o momento
atual, contriburam para o rpido sucesso da linguagem.
Hoje, segundo a International Data Corp. (IDC), existem mais
de 2 milhes de programadores Java no mundo e a estimativa
que o nmero de desenvolvedores ultrapasse os 5 milhes em
2004. Segunda a Gartner, 62% das grandes companhias do Brasil
possuem algum tipo de aplicao em Java e em 2005 previsto
que este nmero chegar a 80%. Os prossionais que dominam a
linguagem esto entre os mais bem pagos da rea de Tecnologia
da Informao (TI), segundo a revista Info Exame (dezembro de
2001). A lista abaixo apresenta as principais caractersticas de
Java, de modo que o leitor tenha uma viso geral da linguagem:

Orientao a objetos. Java no uma linguagem totalmente orientada a objetos como Smalltalk, onde tudo
objeto ou mtodos de objetos. Por questes de ecincia foram mantidos alguns tipos primitivos e suas operaes. No
entanto Java possui um grau de orientao a objetos bem
maior que C/C++, o que a torna bem mais harmoniosa e
fcil de assimilar, uma vez que o programador tenha compreendido esta forma de desenvolvimento.
Compilao do cdigo fonte para cdigo de uma mquina virtual (Bytecodes). Esta caracterstica visa tornar a linguagem independente de plataforma de Hardware
e Sistema Operacional. Obviamente necessrio que exista
um programa capaz de interpretar o cdigo em Bytecodes
para cada Sistema Operacional, denominado de Mquina

Tpicos Avanados

Virtual. Porm, nada impede que o cdigo fonte seja traduzido diretamente para o cdigo executvel na mquina
de destino. J existem ambientes de desenvolvimento que
apresentam este tipo de opo. Alternativamente possvel
projetar equipamentos que processem em hardware os Bytecodes. O diagrama da gura 1.1 ilustra as etapas envolvidas
na execuo de um cdigo Java.

Figura 1.1 Fases para execuo de um programa fonte em


Java.

Ausncia de manipulao explcita de ponteiros. Em


linguagens como C/C++ e Pascal existe o tipo ponteiro
como tipo primitivo da linguagem. A especicao original de Pascal restritiva no uso de ponteiros, permitindo
que sejam usados apenas para referenciar memria obtida
na rea de alocao dinmica (heap) e no permite que o
programador examine o valor da varivel do tipo ponteiro,
nem que realize operaes aritmticas com ponteiros. J
a linguagem C/C++ permite que o valor armazenado na
varivel do tipo ponteiro faa referncia a qualquer rea de
memria, inclusive rea esttica e automtica (pilha), alm
de permitir aritmtica de ponteiros e o exame direto do valor armazenado. A manipulao do tipo ponteiro exige uma
grande dose de ateno por parte do programador e mesmo
programadores experientes frequentemente cometem erros
no seu uso. Alm disso, o uso de ponteiros uma fonte
de insegurana na linguagem, uma vez que permite que o
usurio faa acesso a memria que pode pertencer a outros
processos, abrindo a possibilidade para desenvolvimento de
programas hostis ao sistema. A linguagem Java no possui
o tipo ponteiro. Isto no quer dizer que no seja possvel

Java na prtica
realizar alocao dinmica de memria. Todo objeto criado
alocado na rea de heap (memria de alocao dinmica),
mas o usurio no pode manipular a referncia ao objeto
explicitamente.

Recuperao automtica de memria no utilizada


(Coleta de Lixo - Garbage Collection). Nas linguagens
onde existe alocao dinmica de memria, o programador
responsvel pela liberao de memria previamente obtida
na rea de alocao dinmica e que no est sendo mais utilizada. Se houver falhas na execuo desta responsabilidade
ocorrer o problema que conhecido sob a denominao de
"vazamento de memria". Este problema faz com que, a
partir de certo ponto, o programa no consiga obter memria para criao de novos objetos, apesar de existir rea
que no est sendo mais usada mas que no foi devolvida
ao gerente de memria. Outro erro comum a tentativa de
acesso a reas de memria j liberadas. Todos os programadores que trabalham com linguagens que permitem alocao
dinmica conhecem bem estes problemas e sabem o quanto
difcil implementar programas que no possuam estes tipos de erros. A maior parte dos erros que ocorrem no uso
destas linguagens devido a problemas na alocao/liberao de memria. Visando o desenvolvimento de aplicaes
robustas, livres deste tipo de falha, os projetistas de Java incorporaram um procedimento de coleta automtica de lixo
mquina virtual. Deste modo, os objetos que no esto
sendo mais usados so identicados pelo procedimento, que
libera a memria para ser utilizada na criao de novos objetos.
Segurana. As pessoas costumam dizer que Java uma linguagem segura. Mas o que uma linguagem de programao
segura? Segurana possui signicados distintos para pessoas
diferentes. No caso da linguagem Java na verso 1.0, segurana signica impedir que programas hostis possam causar
danos ao ambiente computacional ou busquem informaes
sigilosas em computadores remotos para uso no autorizado.
Na verso 1.1, foi adicionada a capacidade de permitir a ve-

Tpicos Avanados

ricao da identidade dos programas (autenticao) e, na


verso 1.2, os dados que os programas enviam e recebem podem ser criptografados por meio do uso de um pacote adicional. Na verso 1.4, o pacote de criptograa JCE (JavaTM
Cryptography Extension) foi incorporado ao J2SDK.

Suporte Concorrncia. A construo de servidores,


a criao de programas com interfaces grcas, e programas semelhantes que tem em comum a necessidade de que o
atendimento de uma solicitao no incapacite o sistema de
responder a outras solicitaes concorrentemente, demandam o uso de uma linguagem que facilite o desenvolvimento
deste tipo de programa. As linguagens projetadas antes do
surgimento destas necessidades, como C/C++, no previam
facilidades para este tipo de programao, o que obrigou a
incorporao destes recursos posteriormente, por meio de
funes adicionais. Como a programao concorrente uma
forma de programao que difere bastante da programao
sequencial convencional, a simples adio de novas funes,
para tentar adaptar a linguagem a esta forma de codicao, no cria um ajuste perfeito com a linguagem subjacente. Por outro lado, Java foi projetada visando facilitar
a programao concorrente. Isto faz com que a criao de
linhas de execuo (threads) seja bem mais natural dos que
nas linguagens tradicionais.Programao em rede. Java possui em seu ncleo bsico classes para comunicao em rede
por meio dos protocolos pertencentes pilha de protocolos
TCP/IP. A pilha de protocolos TCP/IP a utilizada pela
Internet e tornou-se o padro de fato para comunicao entre computadores em uma rede heterognea. Isto torna Java
particularmente atrativa para o desenvolvimento de aplicaes na Internet. Alm disso Java est incorporando um amplo conjunto de solues para computao distribuda, como
CORBA (Common Object Request Broker Architecture),
RMI (Remote Method Invocation) e Servlets/JSP (aplicaes Java que so executadas por servidores Web).
Aps o lanamento da verso beta da linguagem em 1995, a
Sun tem liberado diversas evolues da linguagem na forma de

Java na prtica

verses e releases de um conjunto de ferramentas denominado de


Java Development Kit (JDK) at a verso 1.2, quando se passou
a denominar Java 2 SDK (Standard Development Kit). Isto ocorreu porque outros kits de desenvolvimento com propsitos especcos foram lanados, como o J2EE (Java 2 Enterprise Edition),
voltado para aplicaes distribudas escalveis e o J2ME (Java 2
Micro Edition), voltado para aplicaes embutidas em dispositivos eletrnicos (Celulares, handheld, etc.). Durante a elaborao
deste livro, a ltima verso estvel do SDK era a de nmero 1.4
que pode ser obtida gratuitamente no site http://java.sun.com/.

1.1 Convenes
As seguintes convenes so usadas neste livro.
1. Fontes com larguras constantes so usadas em:

exemplos de cdigo
public c l a s s Ponto

{
}

private int x , y ;

nomes de mtodos, classes e variveis mencionadas no


texto.
2. Fontes com larguras constantes em negrito so usadas dentro
de exemplos de cdigos para destacar palavras chave.
3. Fontes em itlico so usadas:

em termos estrangeiros;
na primeira vez que for usado um termo cujo signicado
no for conhecimento generalizado.

Captulo 2

Concorrncia
Um sistema operacional dito concorrente se permite que mais de
uma tarefa seja executada ao mesmo tempo. Na prtica a concorrncia real ou paralelismo s possvel se o hardware subjacente
possui mais de um processador. No entanto, mesmo em computadores com apenas um processador possvel obter um certo tipo
de concorrncia fazendo com que o processador central execute
um pouco de cada tarefa por vez, dando a impresso de que as
tarefas esto sendo executadas simultaneamente.
Dentro da nomenclatura empregada, uma instncia de um programa em execuo chamada de processo. Um processo ocupa
um espao em memria principal para o cdigo e para as variveis
transientes (variveis que so eliminadas ao trmino do processo).
Cada processo possui pelo menos uma linha de execuo (Thread ).
Para ilustrarmos o que uma linha de execuo suponha um determinado programa prog1. Ao ser posto em execuo criado
um processo, digamos A, com uma rea de cdigo e uma rea de
dados e iniciada a execuo do processo a partir do ponto de
entrada. A instruo inicial assim como as instrues subsequentes formam uma linha de execuo do processo A. Portanto, um
thread nada mais que uma sequncia de instrues que est em
execuo de acordo com que foi determinado pelo programa. O
estado corrente da linha de execuo representada pela instruo que est sendo executada. A gura 2.1 mostra a relao entre
7

Java na prtica

estes elementos.

Figura 2.1 Relao entre Programa, Processo e Thread.


possvel existir mais de uma linha de execuo em um nico
processo. Cada linha de execuo pode tambm ser vista como um
processo, com a diferena que enquanto cada processo possui sua
rea de cdigo e dados separada de outros processos, os threads
em um mesmo processo compartilham o cdigo e a rea de dados.
O que distingue um thread de outro em um mesmo processo a
instruo corrente e uma rea de pilha usada para armazenar o
contexto da sequncia de chamadas de cada thread. Por isso os
threads tambm so chamados de processos leves (light process ).
A gura 2.2 mostra esquematicamente a diferena entre processos
e threads.

Figura 2.2 (a) Processos; (b) Threads.

Tpicos Avanados

Sistemas monotarefas e monothreads como o MS-DOS possuem apenas um processo em execuo em um determinado instante e apenas um thread no processo. Sistemas multitarefas e
monothreads como o Windows 3.1 permitem vrios processos em
execuo e apenas um thread por processo. Sistemas multitarefas e multithread como o Solaris, OS/2, Linux, QNX e Windows
98/NT/XP/2000 permitem vrios processos em execuo e vrios
threads por processo.
Como os threads em um mesmo processo possuem uma rea de
dados em comum, surge a necessidade de controlar o acesso a essa
rea de dados, de modo que cada thread no leia ou altere dados no
momento que esto sendo alterados por outro thread. A incluso
de instrues para controlar o acesso a reas compartilhadas torna
o cdigo mais complexo do que o cdigo de processos monothreads.
Uma pergunta pode surgir na mente do leitor: se a incluso
de mais de um thread torna o cdigo mais complexo, ento porque razo algum projetaria cdigo multithread ? A resposta :
processos com vrios threads podem realizar mais de uma tarefa
simultaneamente e, por isso, so teis na criao de processos
servidores, criao de animaes e no projeto de interfaces com
o usurio que no cam travadas durante a execuo de alguma
funo. Por exemplo, imagine um processo servidor a espera de
requisies de servios. Podemos projet-lo de modo que, ao surgir uma solicitao de um servio por um processo cliente, ele crie
um thread para atender a solicitao enquanto volta a esperar a
requisio de novos servios. Com isto os processos clientes no
precisam esperar o trmino do atendimento de alguma solicitao
para ter sua requisio atendida.
O mesmo pode ser dito em relao ao projeto de interfaces com
o usurio. O processo pode criar threads para executar as funes
solicitadas pelo usurio, enquanto aguarda novas interaes. Caso
contrrio, a interface caria impedida de receber novas solicitaes
enquanto processa a solicitao corrente, o que poderia causar
uma sensao de travamento ao usurio.
Outra aplicao para processos multithread a animao de
interfaces. Nesse caso cria-se um ou mais threads para gerenciar
as animaes enquanto outros threads cuidam das outras tarefas,
como por exemplo, a entrada de dados.

10

Java na prtica

A rigor todas as aplicaes acima como outras aplicaes de


processos multithread podem ser executados por meio de processos
monothreads. No entanto, o tempo gasto na mudana de contexto1
entre processos na maioria dos sistemas operacionais muito mais
lenta que a simples alternncia entre threads, uma vez que a maior
parte das informaes contextuais so compartilhadas pelos threads de um mesmo processo.
Mesmo que voc no crie mais de um thread, todo processo
Java possui vrios threads : thread para garbage collection, thread
para monitoramento de eventos, thread para carga de imagens,
etc.

2.1 Criando threads em Java


Processo Multithread no uma inveno da linguagem Java.
possvel criar processos multithread em quase todas as linguagens
do mercado, como C++ e Object Pascal. No entanto, Java foi
projetada para trabalhar com threads e incorporou threads ao ncleo bsico da linguagem tornando, desta forma, mais natural o
seu uso. Na verdade o uso de threads est to intimamente ligado
a Java que quase impossvel escrever um programa til que no
seja multithread.
A classe Thread agrupa os recursos necessrios para a criao
de um thread. A forma mais simples de se criar um thread criar
uma classe derivada da classe Thread. Por exemplo:
c l a s s MeuThread extends Thread

{
}

...

preciso tambm sobrescrever o mtodo run() da classe


Thread. O mtodo run() o ponto de entrada do thread, da
1 Mudana de Contexto (task switch ): o conjunto de operaes necessrias para gravar o estado atual do processo corrente e recuperar o estado de
outro processo de modo a torn-lo o processo corrente.

Tpicos Avanados

11

mesma forma que o mtodo main() ponto de entrada de uma


aplicao. O exemplo 2.1 mostra uma classe completa.
public c l a s s MeuThread extends Thread

String s ;

public MeuThread ( S t r i n g a s )

{
}

super ( ) ;
s = new S t r i n g ( a s ) ;

public void run ( )

for ( int i = 0 ; i < 5 ; i ++)


System . out . p r i n t l n ( i+" "+s ) ;
System . out . p r i n t l n ( "FIM ! "+s ) ;

Exemplo 2.1 Subclasse da classe Thread.


No exemplo 2.1, o mtodo run() contm o cdigo que ser
executado pelo thread. Ele possui um comando for que imprime
cinco vezes o atributo s. Para iniciar a execuo de um thread criase um objeto da classe e invoca-se o mtodo start() do objeto.
O mtodo start() cria o thread e inicia sua execuo pelo mtodo run(). Se o mtodo run() for chamado diretamente, ento
nenhum thread novo ser criado e o mtodo run() ser executado
no thread corrente. O exemplo 2.2 mostra uma forma de se criar
um thread usando a classe denida no exemplo 2.1.
public c l a s s TesteThread1

public s t a t i c void main ( S t r i n g [ ] a r g s )

{
}

new MeuThread ( " Linha1 " ) . s t a r t ( ) ;

Exemplo 2.2 Criao de um Thread.

12

Java na prtica

No exemplo anterior apenas um thread, alm do principal criado. Nada impede que sejam criados mais objetos da mesma classe
para disparar um nmero maior de threads. O exemplo 2.3 mostra a execuo de dois threads sobre dois objetos de uma mesma
classe.
public c l a s s TesteThread2

public s t a t i c void main ( S t r i n g [ ] a r g s )

new MeuThread ( " Linha1 " ) . s t a r t ( ) ;


new MeuThread ( " Linha2 " ) . s t a r t ( ) ;

Exemplo 2.3 Criao de dois threads.


Cada thread executado sobre uma instncia da classe e, por
consequncia, sobre uma instncia do mtodo run(). A sada gerada pela execuo do exemplo 2.3 depende do sistema operacional
subjacente. Uma sada possvel a seguinte:
0 Linha2
0 Linha1
1 Linha2
1 Linha1
2 Linha2
2 Linha1
3 Linha2
3 Linha1
4 Linha2
4 Linha1
FIM! Linha2
FIM! Linha1

Esta sada mostra que os threads executam intercaladamente.


No entanto, em alguns sistemas operacionais os threads do exemplo 2.3 executariam um aps o outro. A relao entre a sequncia
de execuo e o sistema operacional e dicas de como escrever programas multithread com sequncia de execuo independente de
plataforma operacional sero nas sees 2.5 e 2.6.

Tpicos Avanados

13

2.1.1 Usando a interface Runnable


Algumas vezes no possvel criar uma subclasse da classe Thread
porque a classe j deriva outra classe, por exemplo a classe Applet.
Outras vezes, por questes de pureza de projeto, o projetista no
deseja derivar a classe Thread simplesmente para poder criar um
thread, uma vez que isto viola o signicado da relao de classesubclasse. Para esses casos existe a interface Runnable. A interface Runnable possui apenas um mtodo para ser implementado: o mtodo run(). Para criar um thread usando a interface
Runnable preciso criar um objeto da classe Thread, passando
para o construtor uma instncia da classe que implementa a interface. Ao invocar o mtodo start() do objeto da classe Thread,
o thread criado inicia sua execuo no mtodo run() da instncia
da classe que implementou a interface. O exemplo 2.4 mostra a
criao de um thread usando a interface Runnable.
public c l a s s TesteThread2 implements Runnable

private S t r i n g men ;
public s t a t i c void main ( S t r i n g a r g s [ ] )

TesteThread2 ob1 = new TesteThread2 ( " o l a " ) ;


Thread t 1 = new Thread ( ob1 ) ;
t1 . s t a r t ( ) ;

public TesteThread2 ( S t r i n g men ) { this . men=men ; }


public void run ( )

{
}

for ( ; ; ) System . out . p r i n t l n (men ) ;

Exemplo 2.4 Criao de um thread por meio da interface


Runnable.

Note que agora ao invocarmos o mtodo start() o thread


criado iniciar a execuo sobre o mtodo run() do objeto passado
como parmetro, e no sobre o mtodo run() do objeto Thread.
Nada impede que seja criado mais de um thread executando sobre

14

Java na prtica

o mesmo objeto:
Thread t 1 = new Thread ( ob1 ) ;
Thread t 2 = new Thread ( ob1 ) ;

Neste caso alguns cuidados devem ser tomados, uma vez que
existe o compartilhamento das variveis do objeto por dois threads.
Os problemas que podem advir de uma situao como esta sero
tratados mais adiante.

2.2 A classe Thread


A classe Thread extensa, possuindo vrios construtores, mtodos
e variveis pblicas. Aqui mostraremos apenas os mais usados.

Hierarquia
A classe Thread deriva diretamente da classe Object.

java.lang.Object
|
+--java.lang.Thread

Construtores
A tabela 2.1 mostra os principais construtores da classe Thread.
Podemos notar que possvel nomear os threads e agrup-los. Isto
til para obter a referncia de threads por meio do seu nome.

Tpicos Avanados

Construtor
Thread(ThreadGroup g, String nome)
Thread(Runnable ob, String nome)
Thread(ThreadGroup g,
Runnable ob, String nome)
Thread(String nome)
Thread()
Thread(Runnable ob)
Thread(ThreadGroup g, Runnable ob)

15

Descrio

Cria um novo thread com o


nome especicado dentro do
grupo g.
Cria um novo thread para executar sobre o objeto ob, com o
nome especicado.
Cria um novo thread para executar sobre o objeto ob, dentro
do grupo g, com o nome especicado.
Cria um novo thread com o
nome especicado.
Cria um novo thread com o
nome default.
Cria um novo thread para executar sobre o objeto ob.
Cria um novo thread para executar sobre o objeto ob, dentro
do grupo g.

Tabela 2.1 Principais construtores da classe Thread.

Mtodos
A tabela 2.2 apresenta os principais mtodos da classe Thread.
Alguns mtodos muito usados nas verses anteriores do SDK1.2
esto sendo descontinuados (deprecated ) por serem considerados
inseguros ou com tendncia a causarem deadlock 2 . Os mtodos
descontinuados so: stop(), suspend() e resume().

2 Travamento causado pela espera circular de recursos em um conjunto de

threads. O travamento por deadlock mais simples o abrao mortal onde um


thread A espera que um thread B libere um recurso, enquanto que o thread
B s libera o recurso esperado por A se obter um recurso mantido por A.
Desta forma os dois threads so impedidos indenidamente de prosseguir.

16

Java na prtica

Mtodo
static Thread currentThread()
static int enumerate(Thread[] v)
String getName()
int getPriority()
ThreadGroup getThreadGroup()
void interrupt()
void run()
void setName(String name)
void setPriority(int p)
static void sleep(long milis)
static void sleep(long milis,
int nanos)
void start()
static void yield()

Descrio

Retorna uma referncia para o


thread corrente em execuo.
Copia para o array todos os thread ativos no grupo do thread.
Obtm o nome do thread.
Obtm a prioridade do thread.
Retorna o grupo do thread.
Interrompe este thread.
Se o thread foi construdo
usando um objeto Runnable
separado ento o mtodo do
objeto Runnable chamado.
Caso contrrio nada ocorre.
Muda o nome do thread.
Muda a prioridade do thread.
Suspende o thread em execuo
o nmero de milissegundos especicados.
Suspende o thread em execuo o nmero de milissegundos
mais o nmero de nanossegundos especicados.
Inicia a execuo do thread. A
mquina virtual chama o mtodo run() do thread.
Faz com que o thread corrente
interrompa permitindo que outro thread seja executado.

Tabela 2.2 Principais mtodos da classe Thread.

Existem alguns mtodos da classe Object que so importantes


para o controle dos threads, como mostra a tabela 2.3. O leitor
pode estar se perguntando porque mtodos relacionados a threads
esto na superclasse Object que me de todas as classe em
Java. A razo disso que esses mtodos lidam com um elemento
associado a todo objeto e que usado para promover o acesso
exclusivo aos objetos. Esse elemento chamado de monitor. Na
seo 2.6 os monitores sero discutidos mais detalhadamente.

Tpicos Avanados

17

Mtodo

Descrio

Notica um thread que est esperando sobre um objeto.


Notica todos os threads que esto
esperando sobre um objeto.
Espera para ser noticado por outro thread.
Espera para ser noticado por outro thread ou at que se passe o
tempo em milissegundos expresso
por milis, adicionado ao tempo
em nanossegundos expresso por
nanos.
Espera para ser noticado por outro thread ou at que se passe o
tempo em milissegundos expresso
por milis.

void notify()
void notifyAll()
void wait()
void wait(long milis,
int nanos)

void wait(long milis)

Tabela 2.3 Mtodos da classe Object relacionados com


threads.

2.2.1 Variveis pblicas


As variveis pblicas da classe Thread denem valores mximo,
mnimo e default para a prioridade de execuo dos threads. Java
estabelece dez valores de prioridade. Como essas prioridades so
associadas s prioridades do ambiente operacional ento, cada
implementao de mquina virtual pode ter uma associao diferente, o que pode inuenciar no resultado nal da execuo do
programa. Na seo 2.5 abordaremos a inuncia do ambiente
operacional na execuo de programas multithread.

Mtodo

Descrio

static final int MAX_PRIORITY


static final int MIN_PRIORITY
static final int NORM_PRIORITY

A prioridade mxima que um thread pode ter.


A prioridade mnima que um thread pode ter.
A prioridade default associado a
um thread.

Tabela 2.4 Variveis pblicas.

18

Java na prtica

2.3 Ciclo de Vida dos Threads


Um thread pode possuir quatro estados conforme mostra a gura 2.3. Podemos observar que uma vez ativo o thread alterna
os estados em execuo, suspenso e pronto at que passe para
o estado morto. A transio de um estado para outro pode ser
determinada por uma chamada explcita a um mtodo ou devida
a ocorrncia de algum evento no nvel de ambiente operacional ou
de programa.

Figura 2.3 Estados de um thread.


A transio de um thread do estado novo para algum estado
ativo sempre realizada pela invocao do mtodo start() do
objeto Thread. J as transies do estado em execuo para o
estado suspenso, do suspenso para o estado pronto e desses
para o estado morto podem ser disparadas tanto pela invocao
de variados mtodos como pela ocorrncia de eventos. O exemplo 2.5 mostra as ocorrncias de transio em um cdigo.
public c l a s s TesteThread3 extends Thread

public TesteThread3 ( S t r i n g s t r ) { super ( s t r ) ; }


public void run ( )

for ( int i = 0 ; i < 1 0 ; i ++)

System . out . p r i n t l n ( i + " " + getName ( ) ) ;


try {
// Comando para s u s p e n d e r o t h r e a d por

Tpicos Avanados

19

// 1 0 0 0 m i l i s e g u n d o s ( 1 segundo )
// Transio do e s t a d o em execuo
// para o e s t a d o s u s p e n s o
sleep (1000);
} catch ( I n t e r r u p t e d E x c e p t i o n e ) { }
// Evento : fim do tempo de s u s p e n s o
// Transio do e s t a d o em s u s p e n s o
// para o e s t a d o pr on to e d e s t e p/ execuo

}
System . out . p r i n t l n ( "FIM ! " + getName ( ) ) ;
// Evento : fim da execuo do t h r e a d
// Transio do e s t a d o a t i v o s u s p e n s o para o
// e s t a d o morto

public s t a t i c void main ( S t r i n g a r g s [ ] )

TesteThread3 t 1 = new TesteThread3 ( a r g s [ 0 ] ) ;


t 1 . s t a r t ( ) ; // Transio para um e s t a d o a t i v o

Exemplo 2.5 Alguns comandos e eventos que acarretam


transio de estados.

2.3.1 sleep(), yield(), join(), stop(), suspend()


e resume()
Agora que vimos os estados que podem ser assumidos por um
thread em seu ciclo de vida vamos examinar mais detalhadamente
alguns dos mtodos responsveis pela mudana de estado de um
thread.

sleep
O mtodo sleep() um mtodo esttico e possui as seguintes
interfaces:
static void sleep(long ms)
throws InterruptedException

ou

20

Java na prtica
static void sleep(long ms, int ns)
throws InterruptedException

onde ms um valor em milissegundos e ns um valor em nanossegundos.


O mtodo sleep() faz com que o thread seja suspenso
por um determinado tempo, permitindo que outros threads
sejam executados. Como o mtodo pode lanar a exceo
InterruptedException, preciso envolver a chamada em um
bloco try/catch ou propagar a exceo. O exemplo 2.6 dene
uma espera mnima de 100 milisegundos entre cada volta da iterao. Note que o tempo de suspenso do thread pode ser maior
que o especicado, uma vez que outros threads de maior ou mesmo
de igual prioridade podem estar sendo executados no momento em
que expira o tempo de suspenso solicitado.
public c l a s s ThreadComSleep extends Thread

String s ;

public ThreadComSleep ( S t r i n g a s )

{
}

super ( ) ;
s = new S t r i n g ( a s ) ;

public void run ( )

for ( int i = 0 ; i < 5 ; i ++)

System . out . p r i n t l n ( i+" "+s ) ;


try {
Thread . s l e e p ( 1 0 0 ) ;
catch ( I n t e r r u p t e d E x c e p t i o n e ) { }

}
System . out . p r i n t l n ( "FIM ! "+s ) ;

Exemplo 2.6 Uso do mtodo sleep().


Outro problema com o sleep() que a maioria dos sistemas
operacionais no suportam resoluo de nanossegundos. Mesmo a

Tpicos Avanados

21

resoluo na unidade de milissegundo no suportada em alguns


sistemas operacionais. No caso do sistema operacional no suportar a resoluo de tempo solicitada, o tempo ser arredondado
para a nvel de resoluo suportado pela plataforma operacional.

yield
O mtodo yield() um mtodo esttico com a seguinte interface:

static void yield()


Uma chamada ao mtodo yield() faz com que o thread corrente libere automaticamente a CPU (Central Processing Unit )
para outro thread de mesma prioridade. Se no houver nenhum
outro thread de mesma prioridade aguardando, ento o thread corrente mantm a posse da CPU. O exemplo 2.7 altera o exemplo 2.1
de modo a permitir que outros threads de mesma prioridade sejam
executados a cada volta da iterao.
public c l a s s ThreadComYield extends Thread

String s ;

public ThreadComYield ( S t r i n g a s )

{
}

super ( ) ;
s = new S t r i n g ( a s ) ;

public void run ( )

for ( int i = 0 ; i < 5 ; i ++)

System . out . p r i n t l n ( i+" "+s ) ;


Thread . y i e l d ( ) ;

}
System . out . p r i n t l n ( "FIM ! "+s ) ;

Exemplo 2.7 Uso do mtodo yield().

22

Java na prtica

join
O mtodo join() um mtodo de instncia da classe Thread e
utilizado quando existe a necessidade do thread corrente esperar
pelo trmino da execuo de outro thread. As verses do mtodo
join() so as seguintes:

public final void join();


public final void join(long millisecond);
public final void join(long millisecond, int
nanosecond);
Na primeira verso o thread corrente espera indenidamente
pelo encerramento da execuo do segundo thread. Na segunda e
terceira verso o thread corrente espera pelo trmino da execuo
do segundo thread at no mximo um perodo de tempo prexado.
O exemplo 2.8 mostra como usar o mtodo join().
c l a s s ThreadComJoin extends Thread

String s ;

public ThreadComJoin ( S t r i n g a s )

{
}

super ( ) ;
s = new S t r i n g ( a s ) ;

public void run ( )

for ( int i = 0 ; i < 1 0 ; i ++)

System . out . p r i n t l n ( i+" "+s ) ;


System . out . p r i n t l n ( "Fim do t h r e a d ! " ) ;

public c l a s s T e s t a J o i n

public s t a t i c void main ( S t r i n g a r g s [ ] )

ThreadComJoin t 1 = new ThreadComJoin ( a r g s [ 0 ] ) ;


t 1 . s t a r t ( ) ; // Transio para um e s t a d o a t i v o
t 1 . j o i n ( ) ; // Espera p e l o trmino do t h r e a d
System . out . p r i n t l n ( "Fim do programa ! " ) ;

Exemplo 2.8 Uso do mtodo join().

Tpicos Avanados

23

stop, suspend e resume


A partir da verso 1.2 do SDK os mtodos stop(), suspend() e
resume() tornaram-se deprecated (sero descontinuados) uma vez
que a utilizao desses mtodos tendia a gerar erros. No entanto,
devido a grande quantidade de cdigo que ainda utiliza estes mtodos, acreditamos que seja importante mencion-los.
O mtodo stop() um mtodo de instncia que encerra a
execuo do thread ao qual pertence. Os recursos alocados ao
thread so liberados. recomendvel substituir o mtodo stop()
pelo simples retorno do mtodo run().
O mtodo suspend() um mtodo de instncia que suspende
a execuo do thread ao qual pertence. Nenhum recurso liberado, inclusive os monitores que possua no momento da suspenso
(os monitores sero vistos na seo 2.6 e servem para controlar o
acesso variveis compartilhadas). Isto faz com que o mtodo
suspend() tenda a ocasionar deadlocks.
O mtodo resume() um mtodo de instncia que reassume
a execuo do thread ao qual pertence. Os mtodos suspend() e
resume() devem ser substitudos respectivamente pelos mtodos
wait() e notify(), como veremos na seo 2.6.

2.4 Daemon Threads


Daemon threads so threads que rodam em background com a
funo de prover algum servio mas no fazem parte do propsito
principal do programa. Quando s existem threads do tipo daemon o programa encerrado. Um exemplo de daemon o thread
para coleta de lixo.
Um thread denido como daemon por meio do mtodo de
instncia setDaemon(). Para vericar se um thread um daemon
usado o mtodo de instncia isDaemon(). O exemplo 2.9 mostra
como usar esses mtodos.
import j a v a . i o . ;
c l a s s ThreadDaemon extends Thread
{

public ThreadDaemon ( )

24

Java na prtica
{

setDaemon ( true ) ;
start ();

public void run ( )

{
}

for ( ; ; ) y i e l d ( ) ;

public c l a s s TestaDaemon

public s t a t i c void main ( S t r i n g [ ] a r g s )

Thread d = new ThreadDaemon ( ) ;


System . out . p r i n t l n ( "d . isDaemon ( ) = "+
d . isDaemon ( ) ) ;
B u f f e r e d R e a d e r s t d i n = new B u f f e r e d R e a d e r (
new InputStreamReader ( System . i n ) ) ;
System . out . p r i n t l n ( " D i g i t e q u a l q u e r c o i s a " ) ;

try

stdin . readLine ( ) ;
} catch ( IOException e ) { }

Exemplo 2.9 Uso dos mtodos relacionados com daemons.


No exemplo 2.9 o mtodo main() da classe TestaDaemon
cria um objeto da classe ThreadDaemon. O construtor da classe
ThreadDaemon dene o thread como daemon por meio do mtodo
setDaemon() e inicia a execuo do thread. Como apenas um
thread de demonstrao o mtodo run() da classe ThreadDaemon
no faz nada, apenas liberando a posse da CPU toda vez que
a adquire. Aps a criao da instncia da classe ThreadDaemon
no mtodo main() o objeto testado para vericar se um daemon, utilizando para esse m o mtodo isDaemon(). Depois
disso o programa simplesmente espera o usurio pressionar a tecla <enter>. O programa termina logo aps o acionamento da
tecla, mostrando dessa forma que o programa permanece ativo
apenas enquanto existem threads no daemons ativos.

Tpicos Avanados

25

2.5 A Inuncia do Sistema Operacional


sobre os Threads
Apesar da linguagem Java prometer a construo de programas
independentes de plataforma operacional, o comportamento dos
threads pode ser fortemente inuenciado pelo sistema operacional
subjacente. Portanto, o programador deve tomar alguns cuidados
se deseja construir programas que funcionem da mesma forma,
independente do ambiente onde sero executados.
Alguns sistemas operacionais no oferecem suporte a execuo
de threads. Neste caso, cada processo possui apenas um thread.
Mesmo em sistemas operacionais que oferecem suporte a execuo
de mltiplos threads por processo, o projetista da mquina virtual
pode optar por no usar o suporte nativo a threads. Deste modo,
responsabilidade da mquina virtual criar um ambiente multithread. Threads implementados desta forma, no nvel de usurio,
so chamados de green-threads . As inuncias da plataforma operacional podem ser agrupadas em dois tipos:
1. Forma de escalonamento de threads . O ambiente pode
adotar um escalonamento no preemptivo ou preemptivo .
No escalonamento no preemptivo (tambm chamado de cooperativo) um thread em execuo s perde o controle da
CPU se a liberar voluntariamente ou se necessitar de algum
recurso que ainda no est disponvel. J no escalonamento
preemptivo, alm das formas acima, um thread pode perder o controle da CPU por eventos externos, como o m
do tempo mximo denido pelo ambiente para a execuo
contnua de um thread (fatia de tempo) ou porque um thread de mais alta prioridade est pronto para ser executado.
Exemplos de sistemas operacionais no preemptivos so MSWindows 3.1 e IBM OS/2. Exemplos de sistemas operacionais preemptivos so MS-Windows 95/98/2000/XP, Linux,
QNX e muitos outros. Alguns sistemas operacionais adotam uma abordagem hbrida, suportando tanto o modelo
cooperativo como o preemptivo, como o Solaris da Sun.
2. Relacionamento entre os nveis de prioridades de-

26

Java na prtica

nidas na linguagem Java e os nveis de prioridades


denidas nos Sistemas Operacionais. Em um SO pre-

emptivo um thread de uma determinada prioridade perde a


posse da CPU para um thread de prioridade mais alta que
esteja pronto para ser executado. A linguagem Java prev
dez nveis de prioridades que podem ser atribudas aos threads. No entanto, cada SO possui um nmero de prioridades diferente e o mapeamento das prioridades da linguagem
Java para as prioridades do SO subjacente pode inuenciar
o comportamento do programa.

2.5.1 Forma de escalonamento de threads


A especicao da mquina virtual Java determina que a forma
de escalonamento de threads seja preemptiva. Portanto, mesmo
em ambientes operacionais cooperativos a mquina virtual deve
garantir um escalonamento preemptivo. No entanto, um escalonamento preemptivo no obriga a preempo por m de fatia
de tempo. Podemos ter um escalonamento preemptivo onde um
thread de mais alta prioridade interrompe o thread que detem
a posse da CPU mas no existe preempo por m de fatia de
tempo. Um escalonamento onde threads de mesma prioridade intercalam a posse da CPU por fora do m da fatia de tempo
chamado de escalonamento Round-Robin . A especicao da mquina virtual Java no prev o escalonamento Round-Robin, mas
tambm no o descarta, abrindo a possibilidade de implementaes distintas de mquinas virtuais e introduzindo o no determinismo na execuo de programas multithread. O exemplo 2.3
poderia ter uma sada distinta da apresentada anteriormente caso
seja executado por uma mquina virtual que no implementa o
escalonamento Round-Robin. Nesse caso a sada seria a seguinte:
0 Linha2
1 Linha2
2 Linha2
3 Linha2
4 Linha2
FIM! Linha2
0 Linha1

Tpicos Avanados

27

1 Linha1
2 Linha1
3 Linha1
4 Linha1
FIM! Linha1

Neste caso, se o programador deseja que a execuo de threads


se processe de forma alternada, independentemente da implementao da mquina virtual, ento necessrio que ele insira cdigo
para a liberao voluntria da CPU. Isso pode ser feito com o
mtodo yield() ou com o mtodo sleep().

2.5.2 Relacionamento entre os nveis de prioridades denidas na linguagem Java e os


nveis de prioridades denidas nos Sistemas Operacionais
Como j dissemos a linguagem Java prev dez nveis de prioridades que podem ser atribudas aos threads. Na verdade so onze
prioridades, mas a prioridade de nvel 0 reservada para threads
internos. As prioridades atribudas aos threads so estticas, ou
seja no se alteram ao longo da vida do thread, a no ser que por
meio de chamadas a mtodos denidos para esse propsito. A
classe thread possui variveis pblicas nais com valores de prioridade predenidos, como mostrado na tabela 2.4. No entanto, os
sistemas operacionais podem possuir um nmero maior ou menor
de nveis de prioridades. Vamos citar um exemplo: o MSWindows 9x/NT. Este sistema possui apenas sete nveis de prioridades e estes sete nveis devem ser mapeados para os onze nveis
de prioridades especicados em Java. Cada mquina virtual far
este mapeamento de modo diferente, porm a implementao mais
comum mostrada na tabela 2.5.
Note que, nesta implementao, nveis de prioridades diferentes em Java sero mapeados para um mesmo nvel de prioridade
em MSWindows. Isto pode levar a resultados inesperados caso o
programador projete uma aplicao esperando, por exemplo, que
um thread de prioridade 4 ir interromper um thread de prioridade 3. Para evitar este tipo de problema o programador pode

28

Java na prtica

adotar dois tipos de abordagem:


1. utilizar,
se for possvel,
apenas as prioridades
Thread.MIN_PRIORITY,
Thread.NORM_PRIORITY
e
Thread.MAX_PRIORITY para atribuir prioridades aos
threads ; ou
2. no se basear em nveis de prioridades para denir o escalonamento de threads, utilizando, alternativamente, primitivas
de sincronizao que sero abordadas na prxima seo.

Prioridades Java

Prioridades MSWindows

0
1(Thread.MIN_PRIORITY)
2
3
4
5(Thread.NORM_PRIORITY)
6
7
8
9
10(Thread.MAX_PRIORITY)

THREAD_PRIORITY_IDLE
THREAD_PRIORITY_LOWEST
THREAD_PRIORITY_LOWEST
THREAD_PRIORITY_BELOW_NORMAL
THREAD_PRIORITY_BELOW_NORMAL
THREAD_PRIORITY_NORMAL
THREAD_PRIORITY_ABOVE_NORMAL
THREAD_PRIORITY_ABOVE_NORMAL
THREAD_PRIORITY_BELOW_HIGHEST
THREAD_PRIORITY_BELOW_HIGHEST
THREAD_TIME_CRITICAL

Tabela 2.5 Mapeamento das prioridades de Java para


MSWindows.

2.6 Compartilhamento de Memria e


Sincronizao
Como j foi dito, mais de um thread pode ser criado sobre um
mesmo objeto. Neste caso, cuidados especiais devem ser tomados,
uma vez que os threads compartilham as mesmas variveis e problemas podem surgir se um thread est atualizando uma varivel
enquanto outro thread est lendo ou atualizando a mesma varivel. Este problema pode ocorrer mesmo em threads que executam
sobre objetos distintos, j que os objetos podem possuir referncias para um mesmo objeto. O exemplo 2.10 mostra a execuo de

Tpicos Avanados

29

dois threads sobre um mesmo objeto. O nome do thread usado


para que o thread decida que ao tomar. O thread de nome um
cria um nmero de 0 a 1000 gerado aleatoriamente e o coloca na
posio inicial de um array de dez posies. As outras posies
do array so preenchidas com os nove nmeros inteiros seguintes
ao nmero inicial. O thread de nome dois imprime o contedo
do vetor. A inteno inicial do projetista obter na tela sequncias de dez nmeros inteiros consecutivos iniciados aleatoriamente.
No entanto, como os dois threads compartilham o mesmo objeto
e no existe qualquer sincronismo entre eles, pouco provvel que
o projetista obtenha o resultado esperado.
public c l a s s CalcDez implements Runnable

private int v e t I n t [ ] ;
public CalcDez ( ) { v e t I n t=new int [ 1 0 ] ; }
public void run ( )

if

( Thread . c u r r e n t T h r e a d ( ) . getName ( ) . e q u a l s ( "um" ) )


for ( ; ; )
{
v e t I n t [ 0 ] = ( int ) ( Math . random ( ) 1 0 0 0 ) ;
for ( int i =1; i <10; i ++)
ve t I nt [ i ]= v e t I nt [0]+ i ;
}

else
for ( ; ; )
{

System . out . p r i n t l n ( " S e r i e i n i c i a d a por "+


vetInt [ 0 ] ) ;
for ( int i =1; i <10; i ++)
System . out . p r i n t l n ( v e t I n t [ i ] + " " ) ;

public s t a t i c void main ( S t r i n g a r g s [ ] )

CalcDez ob = new CalcDez ( ) ;


Thread t 1 = new Thread ( ob , "um" ) ;
Thread t 2 = new Thread ( ob , " d o i s " ) ;
t1 . s t a r t ( ) ;
t2 . s t a r t ( ) ;

30

Java na prtica
}

Exemplo 2.10 Dois threads executando sobre o mesmo objeto.


Se a mquina virtual no implementar um escalonamento
Round-Robin apenas um thread ser executado, visto que os dois
threads possuem a mesma prioridade. J no caso da mquina virtual implementar um escalonamento Round-Robin a alternncia
da execuo dos threads produzir resultados imprevisveis. Um
trecho de uma das sadas possveis pode ser visto na gura 2.4.
Ele foi obtido em Pentium 100MHz executando a mquina virtual
da Sun, verso 1.2, sob o sistema operacional MSWindows 95.
258
259
Serie iniciada por573
574
575
576
577
578
579
580
581
582
Serie iniciada por80
81
82

Figura 2.4 Sada do exemplo 2.10.


Podemos notar as sequncias esto misturadas, mostrando que
cada thread interrompe o outro no meio da execuo da tarefa
especicada. O mesmo problema pode ocorrer mesmo em threads
que executam sobre objetos diferentes, bastando que cada thread
possua uma referncia para um mesmo objeto. O exemplo 2.11
mostra a execuo de dois threads sobre objetos distintos.

Tpicos Avanados

31

c l a s s Compartilhada

private int v e t I n t [ ] ;
public Compartilhada ( ) { v e t I n t=new int [ 1 0 ] ; }
public void s e t V a l ( )

for ( ; ; )

}
}

v e t I n t [ 0 ] = ( int ) ( Math . random ( )


for ( int i =1; i <10; i ++)

1000);

v et I n t [ i ]= v e tI n t [0]+ i ;

public int g e t V a l ( int i ) { return v e t I n t [ i ] ; }

public c l a s s CalcDez2 extends Thread

private Compartilhada o b j ;
private int t i p o ;
public CalcDez2 ( Compartilhada aObj , int aTipo )
{ o b j = aObj ; t i p o = aTipo ; }

public void run ( )

for ( ; ; )
i f ( t i p o ==1) o b j . s e t V a l ( ) ;
else
{

System . out . p r i n t l n ( " S e r i e i n i c i a d a por "+


obj . getVal ( 0 ) ) ;
for ( int i =1; i <10; i ++)
System . out . p r i n t l n ( o b j . g e t V a l ( i )+ " " ) ;

public s t a t i c void main ( S t r i n g a r g s [ ] )

Compartilhada o b j = new Compartilhada ( ) ;


CalcDez2 t 1 = new CalcDez2 ( obj , 1 ) ;
CalcDez2 t 2 = new CalcDez2 ( obj , 2 ) ;
t1 . s t a r t ( ) ;
t2 . s t a r t ( ) ;

Exemplo 2.11 Dois threads executando sobre objetos distintos.


importante que o leitor no confunda o exemplo 2.11 com
o exemplo 2.10 achando que nos dois exemplos os dois threads
executam sobre o mesmo objeto, uma vez que a etapa da criao dos threads bem parecida. No entanto, no exemplo 2.11

32

Java na prtica

foi declarada uma subclasse da classe Thread e no uma classe


que implementa a interface Runnable. Apesar de parecer que no
exemplo 2.11 ambos os threads executam sobre um mesmo objeto
da classe Compartilhada que passado como argumento, na verdade cada thread executar sobre sua prpria instncia da classe
CalcDez2, sendo que o objeto da classe Compartilhada referenciado pelos dois threads. O comportamento do cdigo do exemplo 2.11 semelhante ao do exemplo 2.10, com a diferena que
no primeiro a sequncia de inteiros encapsulada pelo objeto da
classe Compartilhada.
Este tipo de situao, onde o resultado de uma computao
depende da forma como os threads so escalonados, chamado
de condies de corrida (Race Conditions ). um problema a ser
evitado uma vez que o programa passa a ter um comportamento
no determinstico.

2.6.1 Atomicidade de Instrues e Sincronizao do Acesso Sesses Crticas


A condio de corrida ocorre porque o acesso a reas de memria compartilhadas feito de forma no atmica, e de forma no
exclusiva. Por forma no atmica queremos dizer que o acesso
feito por meio de vrias instrues e pode ser interrompido por
outro thread antes que todas as instrues, que fazem parte do
acesso, sejam executadas. Por forma no exclusiva queremos dizer que um thread pode consultar/atualizar um objeto durante a
consulta/atualizao do mesmo objeto por outros threads. Poucas operaes so atmicas em Java. Em geral, as atribuies
simples, com exceo dos tipos long e double, so atmicas, de
forma que o programador no precisa se preocupar em ser interrompido no meio de uma operao de atribuio. No entanto, no
caso de operaes mais complexas sobre variveis compartilhadas
preciso que o programador garanta o acesso exclusivo a essas
variveis. Os trechos de cdigo onde so feitos os acessos s variveis compartilhadas so chamados de Sees Crticas ou Regies
Crticas .
Uma vez determinada uma regio crtica como garantir o
acesso exclusivo? A linguagem Java permite que o programador

Tpicos Avanados

33

garanta o acesso exclusivo utilizando o conceito de monitor . O


conceito de monitor foi proposto por C. A. R. Hoare em 1974 e
pode ser encarado como um objeto que garante a excluso mtua
na execuo dos procedimentos a ele associados. Ou seja, apenas
um procedimento associado ao monitor pode ser executado em um
determinado momento. Por exemplo, suponha que dois procedimentos A e B esto associados a um monitor. Se no momento
da invocao do procedimento A o procedimento B estiver sendo
executado, ento o processo ou thread que invocou o procedimento
A ca suspenso at o trmino da execuo do procedimento B.
Ao trmino do procedimento B o processo que invocou o procedimento A acordado e sua execuo retomada.

Figura 2.5 Uma possvel sequncia na disputa de dois threads


pela autorizao de um monitor.

O uso de monitores em Java uma variao do proposto por

34

Java na prtica

Hoare. Na linguagem Java todo objeto possui um monitor associado. Para facilitar o entendimento podemos encarar o monitor
como detentor de um passe. Todo thread pode pedir emprestado o passe ao monitor de um objeto antes de realizar alguma
computao. Como o monitor possui apenas um passe, apenas
um thread pode adquirir o passe em um determinado instante.
O passe tem que ser devolvido para o monitor para possibilitar
o emprstimo do passe a outro thread. A gura 2.5 ilustra essa
analogia.
Nos resta saber como solicitar o passe ao monitor. Isto feito
por meio da palavra chave synchronized. Existem duas formas
de se usar a palavra chave synchronized: na declarao de mtodos e no incio de blocos. O exemplo 2.12 mostra duas verses
da classe FilaCirc que implementa uma la circular de valores
inteiros: uma com mtodos synchronized e outra com blocos
synchronized. Um objeto desta classe pode ser compartilhado
por dois ou mais threads para implementar o exemplo clssico de
concorrncia do tipo produtor/consumidor.
A palavra chave synchronized na frente dos mtodos de instncia signica que o mtodo ser executado se puder adquirir o
monitor do objeto a quem pertence o mtodo3 . Caso contrrio, o
thread que invocou o mtodo ser suspenso at que possa adquirir
o monitor. Esta forma de sincronizao abordada no exemplo 2.12 a. Portanto, se algum thread chamar algum mtodo de
um objeto da classe FilaCirc nenhum outro thread que compartilha o mesmo objeto poder executar um mtodo do objeto at
que o mtodo chamado pelo primeiro thread termine. Caso outro
thread invoque um mtodo do mesmo objeto car bloqueado at

3 No usaremos mais a analogia com a aquisio do passe do monitor. Ela


foi usada apenas para facilitar o entendimento do leitor. Quando se trata
de monitores os termos mais usados so: adquirir o monitor e liberar o
monitor.

Tpicos Avanados

35

que possa adquirir o monitor.


a) Verso com mtodos synchronized

b) Verso com blocos synchronized

class FilaCirc
{
private final int TAM = 10;
private int vetInt[];
private int inicio, total;

class FilaCirc
{
private final int TAM = 10;
private int vetInt[];
private int inicio, total;

public FilaCirc()
{
vetInt=new int[TAM];
inicio=0;
total =0;
}
public synchronized
void addElement(int v)
throws Exception
{
if (total == TAM) throw new
Exception("Fila cheia!");
vetInt[(inicio+total)%TAM] = v;
total++;
}
public synchronized
int getElement()
throws Exception
{
if (total == 0 ) throw new
Exception("Fila vazia!");
int temp = vetInt[inicio];
inicio = (++inicio)%TAM;
total--;
return temp;
}
}

public FilaCirc()
{
vetInt=new int[TAM];
inicio=0;
total =0;
}
public void addElement(int v)
throws Exception
{
synchronized(this) {
if (total == TAM) throw new
Exception("Fila cheia!");
vetInt[(inicio+total)%TAM] = v;
total++;
}
}
public int getElement()
throws Exception
{
synchronized(this) {
if (total == 0 ) throw new
Exception("Fila vazia!");
int temp = vetInt[inicio];
inicio = (++inicio)%TAM;
total--;
}
return temp;
}

Exemplo 2.12 Duas verses de uma classe que implementa


uma la circular de inteiros.

O leitor pode estar se perguntando sobre a necessidade de sincronizar os mtodos da classe FilaCirc uma vez que ocorrem
apenas atribuies simples a elementos individuais de um vetor e
as atribuies de inteiros so atmicas. De fato o problema ocorre
no na atribuio dos elementos e sim na indexao do array. Por
exemplo, a instruo

inicio = (++inicio)%TAM;

36

Java na prtica

do mtodo getElement() no atmica. Suponha que os mtodos da classe FilaCirc no sejam sincronizados e que as variveis
inicio e total possuam os valores 9 e 1 respectivamente. Suponha tambm que thread invocou o mtodo getElement() e foi
interrompido na linha de cdigo mostrada acima aps o incremento da varivel inicio mas antes da concluso da linha de
cdigo. Nesse caso o valor de inicio 10. Se neste instante
outro thread executar o mtodo getElement() do mesmo objeto
ocorrer uma exceo IndexOutOfBoundsException ao atingir a
linha de cdigo

int temp = vetInt[inicio];


se alterarmos a linha de cdigo para

inicio = (inicio+1)%TAM;
evitaremos a exceo, mas no evitaremos o problema de retornar
mais de uma vez o mesmo elemento. Por exemplo, se um thread
for interrompido no mesmo local do caso anterior, outro thread
pode obter o mesmo elemento, uma vez que os valores de inicio
e total no foram alterados. Na verdade, o nmero de situaes problemticas, mesmo para esse exemplo pequeno, enorme
e perderamos muito tempo se tentssemos descrev-las em sua
totalidade.
Em alguns casos pode ser indesejvel sincronizar todo um mtodo, ou pode-se desejar adquirir o monitor de outro objeto, diferente daquele a quem pertence o mtodo. Isto pode ser feito
usando a palavra chave synchronized na frente de blocos. Esta
forma de sincronizao mostrada no exemplo 2.12 b. Neste
modo de usar a palavra-chave synchronized necessrio indicar
o objeto do qual se tentar adquirir o monitor. Caso o monitor
seja adquirido, o bloco executado, caso contrrio o thread suspenso at que possa adquirir o monitor. O monitor liberado no
nal do bloco.
No exemplo 2.12 b, o monitor usado na sincronizao o
do prprio objeto do mtodo, indicado pela palavra chave this.
Qualquer outro objeto referencivel no contexto poderia ser usado.

Tpicos Avanados

37

O que importa que os grupos de threads, que possuam reas de


cdigo que necessitam de excluso mtua, usem o mesmo objeto.
No exemplo 2.12 no existe vantagem da forma de implementao a) sobre a forma de implementao b) ou vice-versa. Isso
ocorre, principalmente, quando os mtodos so muito pequenos
ou quando no realizam computaes muito complexas. No entanto, se o mtodo for muito longo ou levar muito tempo para ser
executado, sincronizar todo o mtodo pode travar em demasia a
execuo da aplicao. Nesses casos, a sincronizao somente das
sees crticas mais indicada. Outra vantagem da segunda forma
de sincronizao a liberdade no uso de monitores de qualquer
objeto referencivel. Isto permite a implementao sincronizaes
mais complexas como veremos mais adiante. O exemplo 2.13 mostra como pode ser usado um objeto da classe FilaCirc.
public c l a s s T e s t a F i l a C i r c extends Thread

private F i l a C i r c o b j ;
private int t i p o ;
public T e s t a F i l a C i r c ( F i l a C i r c aObj , int aTipo )
{ o b j = aObj ; t i p o = aTipo ; }

public void run ( )

for ( ; ; )
try
{

i f ( t i p o ==1)

int i = ( int ) ( Math . random ( ) 1 0 0 0 ) ;


System . out . p r i n t l n ( " Elemento g e r a d o : "+i ) ;
o b j . addElement ( i ) ;

else System . out . p r i n t l n ( " Elemento o b t i d o : "+

o b j . getElement ( ) ) ;
} catch ( E x c e p t i o n e )
{ System . out . p r i n t l n ( e . getMessage ( ) ) ; }

public s t a t i c void main ( S t r i n g a r g s [ ] )

F i l a C i r c o b j = new F i l a C i r c ( ) ;
T e s t a F i l a C i r c t 1 = new T e s t a F i l a C i r c ( obj , 1 ) ;
T e s t a F i l a C i r c t 2 = new T e s t a F i l a C i r c ( obj , 2 ) ;

38

Java na prtica

t1 . s t a r t ( ) ;
t2 . s t a r t ( ) ;

Exemplo 2.13 Uso da la circular de inteiros.


Um trecho possvel da sada obtida na execuo do programa
do exemplo 2.13 seria o seguinte:
...
Elemento obtido:154
Elemento gerado:725
Fila vazia!
Elemento gerado:801
Elemento obtido:725
Elemento gerado:204
Elemento obtido:801
...

importante observar que o monitor em Java por si s no


implementa a excluso mtua. Ele apenas um recurso que pode
ser usado pelo programador para implementar o acesso exclusivo
variveis compartilhadas. Cabe ao programador a responsabilidade pelo uso adequado deste recurso. Por exemplo, se o programador esquecer de sincronizar um bloco ou mtodo que necessite
de excluso mtua, de nada adiantar ter sincronizado os outros
mtodos ou blocos. O thread que executar o trecho no sincronizado no tentar adquirir o monitor e, portanto, de nada adianta
outro thread te-lo o adquirido.
Outro ponto importante usar a palavra chave synchronized
com muito cuidado. A sincronizao custa muito caro em se tratando de ciclos de CPU. A chamada de um mtodo sincronizado
por volta de 10 vezes mais lenta do que a chamada de um mtodo
no sincronizado. Por essa razo use sempre a seguinte regra: no
sincronize o que no for preciso.

Tpicos Avanados

39

2.6.2 Comunicao entre Threads: wait() e notify()


O exemplo 2.12 no um modelo de uma boa implementao de
programa. O thread que adiciona elementos la tenta adicionar
um elemento a cada volta do lao de iterao, mesmo que a la
esteja cheia. Por outro lado, o thread que retira os elementos da
la tenta obter um elemento a cada volta do lao de iterao,
mesmo que a la esteja vazia. Isto um desperdcio de tempo de
processador e pode tornar o programa bastante ineciente.
Algum poderia pensar em uma soluo onde o thread testaria
se a condio desejada para o processamento ocorre. Caso a condio no ocorra o thread poderia executar o mtodo sleep() para
car suspenso por algum tempo para depois testar novamente a
condio. O thread procederia desta forma at que a condio
fosse satisfeita. Este tipo de procedimento economizaria alguns
ciclos de CPU, evitando a tentativa incessante de se executar o
procedimento mesmo quando no h condies. O nome desta
forma de ao, onde o procedimento, a cada intervalo de tempo
pr-determinado testa se uma condio satisfeita, chamado de
espera ocupada (pooling ou busy wait ).
No entanto, existem alguns problemas com este tipo de abordagem. Primeiramente, apesar da economia de ciclos de CPU ainda
existe a possibilidade de inecincia, principalmente se o tempo
no for bem ajustado. Se o tempo for muito curto ocorrer vrios
testes inteis. Se for muito longo, o thread car suspenso alm
do tempo necessrio. Porm, mais grave que isto que o mtodo
sleep() no faz o thread liberar o monitor. Portanto, se o trecho
de cdigo for uma regio sincronizada, como o caso do exemplo 2.12, de nada adiantar o thread ser suspenso. O thread que
capaz de realizar a computao que satisfaz a condio esperada
pelo primeiro thread car impedido de entrar na regio crtica,
ocorrendo assim um deadlock : o thread que detm o monitor espera que a condio seja satisfeita e o thread que pode satisfazer a
condio no pode prosseguir porque no pode adquirir o monitor.
O que precisamos um tipo de comunicao entre threads que
sinalize que certas condies foram satisfeitas. Alm disso, preciso que, ao esperar por determinada condio, o thread libere

40

Java na prtica

o monitor. Esta forma de interao entre threads obtida em


Java com o uso dos mtodos de instncia wait(), notify() e
notifyAll(). Como vimos anteriormente, esses mtodos pertencem classe Object e no classe Thread. Isto ocorre porque
esses mtodos atuam sobre os monitores, que so objetos relacionados a cada instncia de uma classe Java e no sobre os threads.
Ao invocar o mtodo wait() de um objeto, o thread suspenso
e inserido na la do monitor do objeto, permanecendo na la at
receber uma noticao. Cada monitor possui sua prpria la.
Ao invocar o mtodo notify() de um objeto, um thread que est
na la do monitor do objeto noticado. Ao invocar o mtodo
notifyAll() de um objeto, todos os threads que esto na la do
monitor do objeto so noticados.
a)

b)

c)

class X
{
...
public synchronized
int mx()
{
...
// Espera uma condio
while(!cond) wait();
// Prossegue com a
// condio satisfeita
...
}
...
}

class Y
{
X ob;
...
public int my()
{
...
synchronized (ob)
{
// Notifica algum
// thread
ob.notify();
...
}
...
}

class Z
{
X ob;
...
public int mz()
{
...
synchronized (ob)
{
// Notifica todos
// os threads que
// esperam na fila
// do monitor de ob
ob.notifyAll();
...
}
...
}

Exemplo 2.14 Exemplos de chamadas dos mtodos wait(),


notify() e notifyAll().

A nica exigncia que esses mtodos sejam invocados em um


thread que detenha a posse do monitor do objeto associado ao
mtodo. Essa exigncia faz sentido uma vez que eles sinalizam
a threads que esperam na la desses monitores. Devido a essa
exigncia, a invocao desses mtodos ocorre em mtodos ou blocos sincronizados. O exemplo 2.14 mostra as formas mais comuns
de chamadas desses mtodos. Note que o thread deve possuir o

Tpicos Avanados

41

monitor do objeto ao qual pertence o mtodo. Por isso, nos exemplos 2.14 b e 2.14 c, o objeto sincronizado no bloco o mesmo que
invoca os mtodos notify() e notifyAll().
Outra observao importante que o thread que invoca o mtodo wait() o faz dentro de um lao sobre a condio de espera.
Isto ocorre porque apesar de ter sido noticado isto no assegura
que a condio est satisfeita. O thread pode ter sido noticado
por outra razo ou, entre a noticao e a retomada da execuo
do thread, a condio pode ter sido novamente alterada.
Uma vez noticado o thread no retoma imediatamente a execuo. preciso primeiro retomar a posse do monitor que no
momento da noticao pertence ao thread que noticou. Mesmo
aps a liberao do monitor nada garante que o thread noticado
ganhe a posse do monitor. Outros threads podem ter solicitado a
posse do monitor e terem preferncia na sua obteno.
O exemplo 2.14 mostra apenas um esquema para uso dos mtodos para noticao. O exemplo 2.15 uma verso do exemplo 2.12 a que usa os mtodos de noticao para evitar problemas
como a espera ocupada. O exemplo 2.13 pode ser usado sem modicaes para testar essa verso.
class FilaCirc

private f i n a l int TAM = 1 0 ;


private int v e t I n t [ ] ;
private int i n i c i o , t o t a l ;
public F i l a C i r c ( )

v e t I n t=new int [TAM] ;


i n i c i o =0;
t o t a l =0;

public synchronized void addElement ( int v )


throws E x c e p t i o n

while ( t o t a l == TAM) w a i t ( ) ;

v e t I n t [ ( i n i c i o+t o t a l )%TAM] = v ;
t o t a l ++;
notify ();

public synchronized int getElement ( )

42

Java na prtica

throws E x c e p t i o n
while ( t o t a l = = 0 ) w a i t ( ) ;
int temp = v e t I n t [ i n i c i o ] ;

i n i c i o = (++ i n i c i o )%TAM;
t o t a l ;
notify ();
return temp ;

Exemplo 2.15 Classe que implementa uma la circular de


inteiros com noticao.

Figura 2.6 Uma possvel sequncia na execuo de trs threads.


A necessidade de se testar a condio em um comando de
repetio pode ser observada na gura 2.6 que mostra a evoluo da execuo de trs threads sobre objetos que compartilham
uma instncia da classe FilaCirc. O thread 3 executa o mtodo
addElement(), no entanto, em virtude da condio total==TAM,
obrigado a invocar o mtodo wait() e esperar uma noticao. O prximo thread a assumir a CPU o thread 1 que executa
o mtodo getElement(), que estabelece a condio total<TAM
e executa um notify(). No entanto, o prximo thread a assumir a CPU o thread 2 e no o thread 3. O thread 2 executa o

Tpicos Avanados

43

mtodo addElement(), o qual estabelece novamente a condio


total==TAM. Quando o thread 3 assume novamente a CPU, uma
vez que foi noticado, testa a condio e invoca novamente o mtodo wait() para esperar a condio favorvel execuo. Caso
no testasse a condio em um comando de repetio o thread 3
tentaria inserir um elemento em uma la cheia.
O mtodo notify() no indica que evento ocorreu. No caso do
exemplo 2.15 existem dois tipos de eventos (a la no est cheia
e a la no est vazia), no entanto, podemos observar que no
existe a possibilidade de um thread ser noticado em decorrncia
de um evento diferente do que est aguardando.
Porm, existem alguns casos mais complexos onde podem
existir vrios threads aguardando em um mesmo monitor mas
esperando por evento diferentes. Neste caso podemos usar o
notifyAll() para noticar todos os threads que esperam em um
nico monitor que um evento ocorreu. Cada thread, a medida
que fosse escalado, testaria se ocorreu condio para a execuo,
em caso positivo prosseguiria na execuo e em caso contrrio,
voltaria a aguardar no monitor.
O exemplo 2.16 mostra o cdigo de um gerenciador de mensagens. Ele responsvel por receber mensagens destinadas vrios
threads. As mensagens de cada thread so colocadas em uma la
implementada por um objeto da classe Vector. Cada la por
sua vez colocada em uma tabela hash onde a chave um nome associado ao thread ao qual as mensagens se destinam. As las so
criadas na primeira tentativa de acesso, tanto na leitura quanto
no armazenamento. No existe bloqueio devido la cheia, uma
vez que as las so implementadas por objetos da classe Vector
que crescem conforme a necessidade. Portanto, o nico evento
que necessita ser noticado a chegada de alguma mensagem.
Como todos os threads aguardam sobre o mesmo monitor usado
o mtodo notifyAll() para noticar todos os threads.
import j a v a . u t i l . ;
c l a s s GerenteMen {
private H a s h t a b l e tamMen ;
public GerenteMen ( ) { tamMen=new H a s h t a b l e ( ) ; }

44

Java na prtica

// Mtodo para a d i c i o n a r uma mensagem


// f i l a de um d e s t i n a t r i o

public synchronized void addMen ( S t r i n g d e s t ,

S t r i n g men)

i f ( d e s t==null | | men==null ) return ;


Vector l i s t a M e n = ( Vector ) tamMen . g e t ( d e s t ) ;
i f ( l i s t a M e n==null ) l i s t a M e n = new Vector ( ) ;
l i s t a M e n . addElement (men ) ;
tamMen . put ( d e s t , l i s t a M e n ) ;
notifyAll ();

// Mtodo para obteno da mensagem

public synchronized S t r i n g getMen ( S t r i n g d e s t )


throws E x c e p t i o n

i f ( d e s t==null ) return null ;


Vector l i s t a M e n = ( Vector ) tamMen . g e t ( d e s t ) ;
// Se no e x i s t e a f i l a para e s s e t h r e a d
// c r i a uma v a z i a

i f ( l i s t a M e n==null )

{
}

l i s t a M e n = new Vector ( ) ;
tamMen . put ( d e s t , l i s t a M e n ) ;

// A f i l a e s t vazia , p o r t a n t o t h r e a d deve
// e s p e r a r a chegada de mensagens

while ( l i s t a M e n . s i z e ()==0) w a i t ( ) ;

S t r i n g temp = ( S t r i n g ) l i s t a M e n . f i r s t E l e m e n t ( ) ;

// A mensagem removida da f i l a
l i s t a M e n . removeElementAt ( 0 ) ;

return temp ;

Exemplo 2.16 Gerenciador de mensagens.


O exemplo 2.17 mostra como pode ser usado o gerente de las
do exemplo 2.16. Devido o uso da classe ThreadGroup assim como
vrios de seus mtodos, resolvemos numerar as linhas de cdigo do
exemplo 2.17 para melhor podermos explicar o seu funcionamento.
1 c l a s s Rec ept or extends Thread
2 {
3
private GerenteMen g e r ;
4
public Rec ept or ( ThreadGroup tg , S t r i n g nome ,
5
GerenteMen aGer )

Tpicos Avanados
6
{
7
super ( tg , nome ) ;
8
g e r = aGer ;
9
}
10
public void run ( )
11
{
12
S t r i n g nome = Thread . c u r r e n t T h r e a d ( ) . getName ( ) ;
13
for ( ; ; )
14
try
15
{
16
S t r i n g men = g e r . getMen ( nome ) ;
17
i f ( men . e q u a l s ( " fim " ) ) return ;
18
System . out . p r i n t l n ( nome+">Mensagem r e c e b i d a : "+
19
men ) ;
20
} catch ( E x c e p t i o n e )
21
{
22
System . out . p r i n t l n ( e . getMessage ( ) ) ;
23
}
24
}
25 }
26
27 c l a s s Gerador extends Thread
28 {
29
private GerenteMen g e r ;
30
public Gerador ( ThreadGroup tg , S t r i n g nome ,
31
GerenteMen aGer )
32
{
33
super ( tg , nome ) ;
34
g e r = aGer ;
35
}
36
public void run ( )
37
{
38
S t r i n g nome = Thread . c u r r e n t T h r e a d ( ) . getName ( ) ;
39
ThreadGroup t g =
40
Thread . c u r r e n t T h r e a d ( ) . getThreadGroup ( ) ;
41
Thread [ ] t l=null ;
42
for ( int i =0; i <100; i ++)
43
{
44
i f ( t l==null | | t l . l e n g t h != t g . a c t i v e C o u n t ( ) )
45
t l = new Thread [ t g . a c t i v e C o u n t ( ) ] ;
46
t g . enumerate ( t l ) ;
47
int n = ( int ) ( Math . random ( ) 1 0 0 0 ) % t l . l e n g t h ;
48
i f ( t l [ n ] ! = Thread . c u r r e n t T h r e a d ( ) )
49
{
50
System . out . p r i n t l n ( nome+
51
">Mensagem e n v i a d a para "+
52
t l [ n ] . getName ()+ " : mensagem "+i ) ;
53
g e r . addMen ( t l [ n ] . getName ( ) , "mensagem "+i ) ;
54
}
55
}
56
t l = new Thread [ t g . a c t i v e C o u n t ( ) ] ;
57
t g . enumerate ( t l ) ;
58
for ( int i =0; i <t l . l e n g t h ; i ++)
59
i f ( t l [ i ] ! = Thread . c u r r e n t T h r e a d ( ) )
60
g e r . addMen ( t l [ i ] . getName ( ) , " fim " ) ;
61
}

45

46

Java na prtica

62 }
63
64 public c l a s s TestaGerenteMen
65 {
66
public s t a t i c void main ( S t r i n g a r g s [ ] )
67
throws E x c e p t i o n
68
{
69
GerenteMen g e r = new GerenteMen ( ) ;
70
ThreadGroup t g = new ThreadGroup ( " t g " ) ;
71
Re cep tor r 1 = new Rec ept or ( tg , "r_um" , g e r ) ;
72
Re cep tor r 2 = new Rec ept or ( tg , " r _ d o i s " , g e r ) ;
73
Gerador g = new Gerador ( tg , " g " , g e r ) ;
74
r1 . s t a r t ( ) ;
75
r2 . s t a r t ( ) ;
76
g . start ();
77
}
78 }

Exemplo 2.17 Uso do gerenciador de las.


Um objeto da classe ThreadGroup agrupa um conjunto de threads. Um ThreadGroup pode possuir, como membros, outros objetos da classe ThreadGroup formando assim uma rvore onde todos
os grupos, exceto o primeiro possuem um grupo pai. O objetivo
de se agrupar os threads em conjuntos facilitar a sua manipulao. No caso do exemplo 2.17 usaremos esse agrupamento para
acessar cada thread.
As linhas 1 a 25 denem a classe que ser usada para criao
de objetos receptores de mensagens. Na linha 3 declarada a
varivel que ir referenciar um objeto do tipo GerenteMen. As
linhas 4 a 9 contm o cdigo do nico construtor da classe. Ele
recebe uma referncia para o grupo de threads ao qual deve se
associar, o nome que deve ser atribudo ao thread e a referncia
ao gerente de las. Na linha 7 os primeiros dois parmetros so
passados ao construtor da superclasse. Na linha 8 a referncia ao
gerente de las atribuda varivel da instncia. As linhas 10 a
24 contm o cdigo do mtodo run() que o mtodo de entrada
do thread. Na linha 12 invocado o mtodo

Thread.currentThread().getName();
para se obter o nome do thread corrente. O nome do thread
usado para referenciar a la de mensagens do thread. Entre as

Tpicos Avanados

47

linhas 13 e 23 executado um lao innito onde o thread recebe


e imprime as mensagens recebidas. Na linha 17 o thread testa se
a mensagem recebida igual a m. Neste caso o thread encerra
sua execuo.
As linhas 27 a 62 denem a classe que ser usada para criao
do objeto gerador de mensagens. Este exemplo foi projetado para
lidar com apenas um thread gerador de mensagem. Modicaes
devem ser realizadas para tratar de aplicaes com mais de um
thread gerador de mensagens. Na linha 29 declarada a varivel
que ir referenciar um objeto do tipo GerenteMen. As linhas 30
a 35 contm o cdigo do nico construtor da classe. Ele recebe
uma referncia para o grupo de threads ao qual deve se associar,
o nome que deve ser atribudo ao thread e a referncia ao gerente
de las. Na linha 33 os primeiros dois parmetros so passados ao
construtor da superclasse. Na linha 34 a referncia ao gerente de
las atribuda varivel da instncia. As linhas 36 a 61 contm
o cdigo do mtodo run() que o mtodo de entrada do thread.
Na linha 38 obtido o nome do thread corrente que ser usado na
impresso de mensagens. Na linha 40 o mtodo

Thread.currentThread().getThreadGroup();
obtm uma referncia para o grupo de threads ao qual pertence
o thread corrente. Na linha 41 declarada uma varivel que ir
referenciar um vetor contendo referncias a todos os threads ativos
do grupo. Entre as linhas 42 e 55 executado um lao com 100
iteraes que produz e armazena as mensagens. Na linha 44
realizado um teste para a vericar da necessidade de criar o vetor
que ir conter as referncias para os threads ativos. Ele deve ser
criado a primeira vez e em todas as vezes que a capacidade do vetor
for diferente do nmero de threads ativos do grupo. O tamanho
do vetor determinado pelo mtodo de instncia activeCount()
da classe ThreadGroup. A linha 46 contm o cdigo

tg.enumerate(tl);
que insere as referncias de todos os threads no vetor tl. O comando

48

Java na prtica

int n = (int)(Math.random()*1000)%tl.length;
da linha 47 calcula um nmero que ser usado para acessar o thread
dentro do vetor de referncias. O teste da linha 48 impede que
seja enviada uma mensagem para o prprio gerador, descartando
as mensagens. As linhas 50 a 53 tratam da impresso e envio da
mensagem construda. J fora da iterao, as linhas 56 a 60 tratam
do envio da mensagem m para todos os threads receptores, o
que far com que encerrem sua execuo.
As linhas 64 a 78 denem a classe que ser usada como ponto
de entrada da aplicao. Ela responsvel pela criao dos objetos
e disparos dos threads. No exemplo, alm do thread gerador, apenas dois threads receptores so criados. interessante notar que
no preciso indicar para o thread gerador as referncias para os
threads receptores. Elas so obtidas dinamicamente por meio do
grupo de threads. Um possvel trecho da sada obtida na execuo
do programa do exemplo 2.17 seria o seguinte:
...
g>Mensagem enviada para r_dois:mensagem 88
r_um>Mensagem recebida:mensagem 87
g>Mensagem enviada para r_dois:mensagem 90
r_dois>Mensagem recebida:mensagem 88
g>Mensagem enviada para r_um:mensagem 91
r_dois>Mensagem recebida:mensagem 90
g>Mensagem enviada para r_um:mensagem 93
r_um>Mensagem recebida:mensagem 91
g>Mensagem enviada para r_um:mensagem 95
r_um>Mensagem recebida:mensagem 93
g>Mensagem enviada para r_um:mensagem 96
r_um>Mensagem recebida:mensagem 95
g>Mensagem enviada para r_um:mensagem 97
r_um>Mensagem recebida:mensagem 96
g>Mensagem enviada para r_dois:mensagem 99
r_um>Mensagem recebida:mensagem 97
r_dois>Mensagem recebida:mensagem 99

Otimizando a Programao Multithread


Existe um problema bvio com a abordagem do exemplo 2.16 : a
mensagem dirigida a apenas um thread mas todos sero noti-

Tpicos Avanados

49

cados, sobrecarregando o sistema, uma vez que todos os threads


precisaram testar se a mensagem destinada a eles. Para contornar esse problema necessrio vislumbrar uma forma de noticar
apenas o thread destinatrio. Isto pode ser obtido se cada thread
esperar em um monitor de um objeto diferente. No importa o
tipo do objeto desde que seja referencivel pelo thread receptor e
pelo thread que ir armazenar a mensagem. Um candidato natural a la de mensagem de cada thread. Existe uma la para cada
thread e o thread que armazena a mensagem tem acesso a todas as
las por meio da tabela hash. O exemplo 2.18 mostra uma verso
do exemplo 2.16 que utiliza esta tcnica para criar uma aplicao
multithread mais otimizada.
import j a v a . u t i l . ;
c l a s s GerenteMen {
private H a s h t a b l e tamMen ;
public GerenteMen ( ) { tamMen=new H a s h t a b l e ( ) ; }
// Mtodo para a d i c i o n a r uma mensagem f i l a de
// um d e s t i n a t r i o

public void addMen ( S t r i n g d e s t , S t r i n g men)

i f ( d e s t==null | | men==null ) return ;


Vector l i s t a M e n = ( Vector ) tamMen . g e t ( d e s t ) ;
i f ( l i s t a M e n==null ) l i s t a M e n = new Vector ( ) ;
synchronized ( l i s t a M e n )
{
l i s t a M e n . addElement (men ) ;
tamMen . put ( d e s t , l i s t a M e n ) ;
listaMen . notify ( ) ;
}

// Mtodo para obteno da mensagem

public S t r i n g getMen ( S t r i n g d e s t )
throws E x c e p t i o n

i f ( d e s t==null ) return null ;


Vector l i s t a M e n = ( Vector ) tamMen . g e t ( d e s t ) ;
// Se no e x i s t e a f i l a para e s s e t h r e a d
// c r i a uma v a z i a

i f ( l i s t a M e n==null )

{
}

l i s t a M e n = new Vector ( ) ;
tamMen . put ( d e s t , l i s t a M e n ) ;

// A f i l a e s t vazia , p o r t a n t o t h r e a d

50

Java na prtica
// deve e s p e r a r

while ( l i s t a M e n . s i z e ()==0)
synchronized ( l i s t a M e n ) { l i s t a M e n . w a i t ( ) ; }

S t r i n g temp = ( S t r i n g ) l i s t a M e n . f i r s t E l e m e n t ( ) ;

// A mensagem removida da f i l a

l i s t a M e n . removeElementAt ( 0 ) ;
return temp ;

Exemplo 2.18 Gerenciador de mensagens otimizado.


Note que os mtodos wait() e notify() invocados pertencem
la relacionada com cada thread. O exemplo 2.17 pode ser usado
sem modicaes para testar essa verso.

Criando outros mecanismos de sincronizao


Existem vrias propostas de primitivas de sincronizao. Dentre as mais comuns podemos citar os semforos, mutex, variveis
condicionais, monitores e encontros (rendevouz ). Cada uma dessas primitivas mais adequada a um determinado propsito. A
implementao de monitores na linguagem Java, juntamente com
os mtodos wait() e notify(), que formam um tipo de variveis condicionais, podem ser combinados para implementar muitas dessas outras primitivas, de modo a atender objetivos especcos. Para exemplicar essa possibilidade mostraremos como
implementar um semforo usando as primitivas de sincronizao
da linguagem Java.
Um semforo uma varivel inteira sobre a qual pode-se realizar as seguintes operaes:

Operao
inicializar
P
V

Descrio

Um valor inteiro maior ou igual a zero atribudo ao semforo.


Se o semforo maior que zero, o semforo
decrementado. Caso contrrio, o thread
suspenso at que o semforo contenha um valor
maior que zero.
Incrementa o semforo e acorda os threads que
estiverem bloqueados na la de espera do semforo.

Tpicos Avanados

51

Tabela 2.6 Operaes sobre um semforo.


Semforo um mecanismo de sincronizao muito utilizado
quando existe a necessidade de comunicao entre dois ou mais
processos, como no caso de sistemas do tipo produtor/consumidor. Por exemplo, suponha dois processos onde um coloca mensagens em um buer e outro retira as mensagens. Os processos
podem usar dois semforos para sincronizar o acesso ao buer de
mensagens: um para controlar a entrada na regio crtica e outro
para contar o nmero de mensagens. A gura 2.7 mostra os esquemas dos processos. A implementao dos semforos em Java pode
ser visto no exemplo 2.19 e o uso dos semforos em uma situao
como a ilustrada pela gura 2.7 pode ser visto no exemplo 2.20.

Produtor

Consumidor

s=1; n=0;
incio loop

incio loop

Produz mensagem

P(n) //Checa se existem mens.

P(s) //Checa se pode entrar na

P(s) //Checa se pode entrar na

//regio crtica

//regio crtica

Coloca mensagem no buer

Retira mensagem

V(n) //incrementa no.

V(s) //sai da regio crtica

de mens.

V(s) //sai da regio crtica


fim loop

Consome Mensagem
fim loop

Figura 2.7 Comunicao entre processos usando semforos.


public c l a s s Semaforo

private int c o n t ;
public Semaforo ( ) { c o n t = 0 ; }
public Semaforo ( int i ) { c o n t = i ; }
public synchronized void P ( )
throws I n t e r r u p t e d E x c e p t i o n

{
}

while ( c o n t <=0) this . w a i t ( ) ;


cont ;

52

Java na prtica
public synchronized void V( )

{
}

c o n t++;
notifyAll ();

Exemplo 2.19 Implementao de um Semforo.


import j a v a . u t i l . Vector ;
c l a s s Consumidor extends Thread

private Vector b u f f ;
private Semaforo s , n ;
public Consumidor ( Vector aBuff , Semaforo as ,
{
}

Semaforo an )

super ( ) ;

b u f f = a B u f f ; s = a s ; n = an ;

public void run ( )

for ( ; ; )
try
{

n . p ( ) ; // V e r i f i c a se e x i s t e mensagens
s . p ( ) ; // V e r i f i c a se pode e n t r a r na

// r e g i o c r t i c a

S t r i n g men = ( S t r i n g ) b u f f . f i r s t E l e m e n t ( ) ;
b u f f . removeElementAt ( 0 ) ;
s .v();
i f ( men . e q u a l s ( " fim " ) ) return ;
System . out . p r i n t l n ( "Mensagem r e c e b i d a : "+
men ) ;
} catch ( E x c e p t i o n e )
{ System . out . p r i n t l n ( e . getMessage ( ) ) ; }

c l a s s Produtor extends Thread

private Vector b u f f ;
private Semaforo s , n ;
public Produtor ( Vector aBuff , Semaforo as ,
{

Semaforo an )

super ( ) ;

Tpicos Avanados

b u f f = a B u f f ; s = a s ; n = an ;

public void run ( )

for ( int i =0; i <11; i ++)

try

s . p ( ) ; // V e r i f i c a se pode e n t r a r na

// r e g i o c r t i c a

i f ( i <10)

b u f f . addElement ( " "+i ) ;


System . out . p r i n t l n (
"Mensagem e n v i a d a : "+ i ) ;

e l s e b u f f . addElement ( " fim " ) ;


n . v ( ) ; // incrementa o nmero de mensagens
s . v ( ) ; // abandona a r e g i o c r t i c a
Thread . y i e l d ( ) ;
} catch ( E x c e p t i o n e )
{ System . out . p r i n t l n ( e . getMessage ( ) ) ; }

public c l a s s TestaSemaforo

public s t a t i c void main ( S t r i n g a r g s [ ] )


throws E x c e p t i o n

Vector b u f f = new Vector ( ) ;


Semaforo s = new Semaforo ( 1 ) ;
Semaforo n = new Semaforo ( 0 ) ;
Produtor t 1 = new Produtor ( b u f f , s , n ) ;
Consumidor t 2 = new Consumidor ( b u f f , s , n ) ;
t1 . s t a r t ( ) ;
t2 . s t a r t ( ) ;

Exemplo 2.20 Uso de semforos por dois threads

53

54

Java na prtica

Captulo 3

Programao em rede
Diferentemente da maioria das linguagens de programao atuais,
Java foi projetada na era da Internet, e por isso mesmo ferramentas para comunicao dentro da Grande Rede foram incorporadas
linguagem desde a sua concepo. Classes para manipulao de
URLs (Uniform Resource Locator ) e dos protocolos que constituem a Internet fazem parte do ncleo bsico da linguagem. Isto
facilita muito a tarefa de desenvolver aplicaes para a Internet
ou outras redes que fazem uso do mesmo conjunto de protocolos.
Esta uma das principais foras da linguagem Java. Para entendermos como desenvolver aplicaes em rede com Java importante a compreenso de alguns conceitos bsicos sobre protocolos
de comunicao.

3.1 Conceitos Sobre Protocolos Usados


na Internet
Um protocolo de comunicao um conjunto de formatos e regras usadas para transmitir informao. Computadores distintos
devem obedecer estas regras e formatos de modo que se possam
comunicar. Podemos encarar o protocolo como a denio de uma
linguagem comum, de modo a possibilitar a comunicao entre diferentes entidades.
55

56

Java na prtica

Visando diminuir a complexidade de implementao e uso do


protocolo, ele divido e organizado em forma de camadas de protocolos, onde a camada relativamente inferior a outra na pilha
estabelece as regras para a camada superior sobre a utilizao de
seus servios. As camadas inferiores fornecem servios mais bsicos de transmisso de dados, enquanto que as camadas superiores
oferecem servios de mais alto nvel. Esta forma de organizao
hierrquica de protocolos tambm chamada de pilha de protocolos.
A pilha de protocolos sobre a qual a Internet se organiza
a pilha de protocolos TCP/IP. Por simplicidade chamaremos a
pilha de protocolos TCP/IP apenas como protocolo TCP/IP ou
TCP/IP. A gura 3.1 mostra como se organizam alguns dos protocolos que fazem parte do TCP/IP.

Figura 3.1 Alguns protocolos da pilha TCP/IP.


A camada fsica a responsvel pelo transporte efetivo dos
dados sobre o meio fsico. A camada de rede responsvel pela
interface lgica entre os computadores. A camada de transporte
prov transferncia de dados no nvel de servio, e a camada de
aplicao prov comunicao no nvel de processos ou aplicaes.
Exemplos de protocolos no nvel de aplicao so: FTP, usado

Tpicos Avanados

57

para transferncia de arquivos; HTTP, usado para transmisso


de pginas Web; TELNET prov capacidade de log-on remoto;
SMTP prov servios bsicos de correio eletrnico; SNMP usado
para gerncia da rede; e MIME que uma extenso do SMTP
para lidar com mensagens com contedos diversos.
No processo de transmisso de dados sobre uma rede TCP/IP
os dados so divididos em grupos chamados de pacotes. Cada
camada adiciona alguns dados a mais no incio de cada pacote para
permitir que o mesmo chegue ao destino. Os dados adicionados
so chamados de headers.

Figura 3.2 Headers adicionados a cada camada de protocolo.


Na camada de transporte existem dois protocolos que fazem
uso do protocolo IP: o protocolo TCP/IP e o UDP.

3.1.1 TCP
O protocolo TCP um protocolo orientado a conexo que prov
um uxo convel de dados entre dois computadores. Por protocolo orientado a conexo queremos dizer que estabelecido um
canal de comunicao ponto-a-ponto onde os dados podem trafegar em ambas as direes. O TCP garante que os dados enviados
em uma ponta cheguem ao destino, na mesma ordem que foram
enviados. Caso contrrio, um erro reportado. Protocolos como

58

Java na prtica

HTTP, FTP e TELNET exigem um canal de comunicao convel e a ordem de recebimento dos dados fundamental para o
sucesso dessas aplicaes.

3.1.2 UDP
No entanto, nem todas as aplicaes necessitam destas caractersticas do protocolo TCP e o processamento adicional exigido
para garantir a conabilidade e a ordenao dos dados podem
inviabiliz-las. Para esses casos existe o protocolo de transporte
UDP. UDP um protocolo para envio de pacotes independentes
de dados, chamados de datagramas, de um computador a outro,
sem garantias sobre a chegada dos pacotes. O protocolo UDP no
orientado a conexo.

3.1.3 Identicao de Hosts (Nmero IP)


Cada computador conectado a uma rede TCP/IP chamado de
Host e identicado por um nico nmero de 32 bits, denominado
de nmero IP. O nmero IP representado por quatro grupos de
8 bits, limitando desta forma o valor numrico de cada grupo ao
valor mximo de 255. Um exemplo de nmero IP 200.65.18.70.
Uma vez que muito difcil lembrar e atribuir signicado a nmeros existe uma forma alternativa de identicar os computadores
da rede por meio de nomes. Um ou mais computadores da rede
fazem o papel de resolvedores de nomes (servidores DNS- Domain
Name Server ), mantendo bases de dados que associam o nomes do
Hosts seus nmeros IP. Desta forma possvel um computador
comunicar com outro computador por meio do nome lgico e no
por meio do nmero IP. A gura 3.3 ilustra a comunicao entre
dois computadores. A Internet representada como uma nuvem
devido a complexidade da rede.

Tpicos Avanados

59

Figura 3.3 Representao da comunicao entre dois


computadores.

O representao dos nomes dos computadores na Internet


feita por substrings separadas por `.' e obedecem uma regra de
nomeao que dene que o primeiro substring representa o nome
da mquina, e os restantes representam o domnio onde est inserida a mquina. Um domnio um agrupamento de computadores
que pertencem a uma instituio, rgo, empresa, ou uma organizao qualquer. Assim, no exemplo da gura 3.3 o computador meucomp pertence ao domnio com.br. No Brasil a FAPESP
(Fundao de Amparo Pesquisa do Estado de So Paulo) responsvel pela gerncia dos nomes dos domnios na Internet.

3.1.4 Identicao de Processos (Portas)


A comunicao entre dois processos em uma rede TCP/IP assimtrica, no sentido que um processo faz o papel de servidor,
oferecendo um servio e outro faz o papel de cliente do servio.
Em um nico Host vrios processos podem estar fazendo o papel
de servidor, oferecendo servios atravs de um nico meio fsico.
Portanto, preciso uma forma de identicar os servidores em um
mesmo Host. Isto feito por meio da associao de um nmero
inteiro, chamado de porta, ao processo servidor. Essa associao
feita pelo processo assim que carregado, por meio de uma chamada ao sistema. O nmero da porta pode variar de 1 a 65535,
no entanto os nmeros de 1 a 1023 so reservados para servios
conhecidos, como por exemplo o FTP e o HTTP. O programador
no deve usar estas portas a no ser que esteja implementando
algum desses servios. Nos ambientes Unix as portas que vo de
6000 a 6999 so usadas pelo gerenciador de Interfaces X Windows

60

Java na prtica

e 2000 a 2999 por outros servios, como o NFS. Nestes ambientes,


estas faixas de nmeros de portas tambm devem ser evitadas. A
tabela 3.1 mostra o nmero da porta de alguns dos servios mais
conhecidos.

Protocolo
HTTP
echo
FTP
SMTP
Finger
Daytime
pop3

Porta
80
7
20, 21
25
79
13
110

Tabela 3.1 Nmero das portas dos principais servios.


Uma vez associado a uma porta o servio pode ser acessado por
uma aplicao cliente, bastando para isso que, ao se comunicar,
ela indique o nome do Host e o nmero da porta.

3.2 Programao em Rede com Java


O pacote java.net contm as classes e interfaces usadas para
programao de sistemas em rede com Java. As classes podem
ser enquadradas em trs categorias:
1. Classes para comunicao bsica em rede. Tratam
da comunicao em baixo nvel entre aplicaes. Outros
protocolos podem ser implementados usando como base esta
comunicao bsica.
2. Classes para comunicao dentro da Web. Estas classes provem facilidades para acessar contedos por meio de
URLs.
3. Classes para tratamento dos formatos estendidos
da Web. Utilizadas para tratar novos protocolos e tipos
MIME.

Tpicos Avanados

61

3.2.1 Comunicao Bsica Entre Aplicaes


Classe

Descrio

Socket

Prov um socket cliente para comunicao orientada


conexo via protocolo TCP.
Prov um socket servidor para comunicao orientada
conexo via protocolo TCP.
Prov um socket UDP para comunicao no orientada
conexo.
Representa um datagrama que pode ser enviado
usando DatagramSocket.
Representa os dados de um Host (Nome e endereo
IP).

ServerSocket
DatagramSocket
DatagramPacket
InetAddress

Tabela 3.2 Classes para comunicao bsica.


As classes Socket, ServerSocket, DatagramSocket,
DatagramPacket e InetAddress, fornecem os mtodos necessrios para a comunicao bsica entre dois processos. A
tabela 3.2 descreve sucintamente cada uma das classes.
As classes Socket e ServerSocket so utilizadas para
comunicao orientada a conexo, enquanto que as classes
DatagramSocket e DatagramPacket so utilizadas para comunicao no orientada a conexo.

3.2.2 Comunicao orientada a conexo (cliente)


Para comunicar via protocolo TCP preciso que a aplicao cliente crie um objeto Socket. preciso passar o nome ou nmero
IP do Host e o nmero da porta onde o servidor est esperando
as solicitaes de servio. A classe Socket possui os mtodos
getInputStream() e getOutputStream(), que so usados para
obter Streams associados ao Socket. Deste modo, a transmisso
de dados via Socket idntica leitura e escrita em arquivos via
streams. O exemplo 3.1 mostra o cdigo de um cliente que acessa
um servidor de Daytime. O servio de Daytime disponibilizado
nas plataformas UNIX e acessado via porta 13. Sua funo
enviar, aos processos clientes, uma linha de texto contendo a data
e a hora corrente .

62

Java na prtica

import j a v a . i o . ;
import j a v a . n e t . ;
public c l a s s C l i e n t e D a t a

public s t a t i c void main ( S t r i n g [ ] a r g s )


throws IOException

S o c k e t s o c k e t = null ;
B u f f e r e d R e a d e r i n = null ;

try

s o c k e t = new S o c k e t ( a r g s [ 0 ] , 1 3 ) ;
i n = new B u f f e r e d R e a d e r (
new InputStreamReader (
socket . getInputStream ( ) ) ) ;
} catch ( UnknownHostException e )
{
System . e r r . p r i n t l n ( " h o s t i n e x i s t e n t e : "+a r g s [ 0 ] ) ;
System . e x i t ( 1 ) ;
} catch ( IOException e )
{
System . e r r . p r i n t l n ( " Erro I /O: "+e . getMessage ( ) ) ;
System . e x i t ( 1 ) ;

System . out . p r i n t l n ( "Data : " + i n . r e a d L i n e ( ) ) ;

in . close ( ) ;
socket . close ( ) ;

Exemplo 3.1 Cliente para o servio de Daytime.


No programa do exemplo 3.1 o usurio precisa passar o nome
do Host servidor pela linha de comando. Voc pode testar este
programa mesmo que seu computador no esteja conectado em
uma rede, desde que o protocolo TCP/IP esteja instalado. Neste
caso voc deve passar como parmetro o nome do seu computador ou, alternativamente, o nome localhost, ou, ainda, o nmero
IP 127.0.0.1. O nome localhost e o nmero IP 127.0.0.1 sem-

Tpicos Avanados

63

pre identicam o computador local. Note que, aps a criao do


objeto Socket, o mtodo getInputStream() chamado e o objeto
retornado envolvido por um objeto BufferedReader de modo a
comunicar dados via rede da mesma forma que realizada uma
operao de E/S. Ao se terminar a operao preciso fechar tanto
a instncia BufferedReader quanto o objeto Socket. A instncia
da classe de E/S sempre deve ser fechada primeiro.
Os Hosts que utilizam as variaes do sistema operacional
UNIX possuem o servio de Daytime, no entanto, outros sistemas
operacionais podem no implementar este servio. O programador pode resolver este problema implementando ele mesmo um
servidor de Daytime. A prxima seo mostrar como isto pode
ser feito.

3.2.3 Comunicao orientada conexo (servidor)


Para criar um processo servidor preciso associ-lo uma porta.
Isto feito ao se criar uma instncia da classe ServerSocket. Se
estamos criando um novo servio preciso associar a uma porta
com valor maior que 1023. Se estamos implementando um servio
j estabelecido preciso obedecer as especicaes denidas para
o servio. O exemplo 3.2 mostra o cdigo de um servidor do
servio Daytime. Como no queremos substituir o servio padro
de Daytime utilizaremos o nmero de porta 5013 no lugar do
nmero 13. Para testar este servidor com o programa cliente do
exemplo 3.1 preciso alterar o nmero da porta no cdigo do
cliente.
import j a v a . u t i l . ;
import j a v a . i o . ;
import j a v a . n e t . ;
public c l a s s ServerData {
public s t a t i c void main ( S t r i n g [ ] a r g s )
throws IOException
{

S e r v e r S o c k e t s s o c k e t = null ;
S o c k e t s o c k e t = null ;
B u f f e r e d W r i t e r out = null ;

64

Java na prtica
try

s s o c k e t = new S e r v e r S o c k e t ( 5 0 1 3 , 5 ) ;

for ( ; ; )

socket = ssocket . accept ( ) ;


out = new B u f f e r e d W r i t e r (
new OutputStreamWriter (
s o c k e t . getOutputStream ( ) ) ) ;
out . w r i t e ( ( new Date ( ) ) . t o S t r i n g ()+ " \n" ) ;

}
} catch ( IOException e )
{
System . out . p r i n t l n ( e . getMessage ( ) ) ;
}
finally {
out . c l o s e ( ) ;
socket . close ( ) ;
}

Exemplo 3.2 Servidor de Daytime.


Ao criar uma instncia da classe ServerSocket o programador
pode indicar o tamanho da la de solicitaes de conexo. As conexes so colocadas na la at que o servidor possa atend-las. Se
chegar alguma conexo e no houver espao na la a conexo ser
recusada. No nosso exemplo passamos como parmetro o valor
5. Aps criar o objeto ServerSocket o servidor deve indicar que
est disposto a receber conexes. Isto feito por meio da execuo
do mtodo accept() do objeto ServerSocket. Ao executar este
mtodo o processo passa para o estado bloqueado at que alguma
conexo seja solicitada. Quando a conexo solicitada o mtodo
accept() retorna um objeto Socket que ser usado para obter os
streams onde ser efetuada a comunicao. O stream obtido do
objeto Socket encapsulado em um objeto BufferedWriter que
ser encarregado de enviar a cadeia de caracteres contendo a data
e a hora para o cliente. O Servidor implementa um lao innito,
recebendo e tratando solicitaes de servios.

Tpicos Avanados

65

O servidor implementado trata uma solicitao de servio por


vez. Isto pode ser problemtico quando existem vrios clientes
solicitando servios ao mesmo tempo e o servidor leva um longo
tempo tratando cada solicitao. Nesta situao o cliente pode
car muito tempo a espera de atendimento. Isto pode ser remediado por meio da implementao de servidores Multithreaded.
Apesar do servio implementado pelo exemplo 3.2 no exigir um
servidor Multithreaded, uma vez que o cliente atendido rapidamente, o servidor Daytime foi alterado para exemplicar a implementao de um servidor Multithreaded. O exemplo 3.3 mostra o
cdigo da verso Multithreaded do servidor.
import j a v a . u t i l . ;
import j a v a . n e t . ;
import j a v a . i o . ;
public c l a s s ServerDataM

public s t a t i c void main ( S t r i n g a r g s [ ] )


throws IOException

S e r v e r S o c k e t s s o c k e t=null ;

try

s s o c k e t = new S e r v e r S o c k e t ( 5 0 1 3 , 5 ) ;

while ( true )

Socket socket = s s o c k e t . accept ( ) ;


( new SubServer ( s o c k e t ) ) . s t a r t ( ) ;

}
} catch ( E x c e p t i o n e )
{ System . e r r . p r i n t l n ( e . getMessage ( ) ) ; }
finally { ssocket . close ();}

c l a s s SubServer extends Thread

Socket socket ;

public SubServer ( S o c k e t a S o c k e t )

66

Java na prtica

socket = aSocket ;

public void run ( )

try

}
}

B u f f e r e d W r i t e r out = new B u f f e r e d W r i t e r (
new OutputStreamWriter (
s o c k e t . getOutputStream ( ) ) ) ;
out . w r i t e ( ( new Date ( ) ) . t o S t r i n g ()+ "\n" ) ;
out . f l u s h ( ) ;
out . c l o s e ( ) ;
socket . close ( ) ;

catch ( E x c e p t i o n e ) { System . e r r . p r i n t l n ( e ) ; }

Exemplo 3.3 Servidor de Daytime Multithreaded.


No exemplo 3.3, ao receber uma conexo o servidor cria um
Thread para atender o cliente e ca disponvel para receber novas
solicitaes. Esse exemplo pode ser usado como esqueleto para
desenvolvimento de servidores mais complexos, porm, neste caso
necessrio limitar o nmero de Threads que podem ser criados.

3.2.4 Comunicao Sem Conexo (UDP)


Como j dissemos na seo anterior, nem sempre necessrio um
canal de comunicao convel entre duas aplicaes. Para estes
casos existe o protocolo UDP, que prov uma forma de comunicao onde a aplicao envia pacotes de dados, chamados de
datagramas, para outra aplicao, sem garantias se e quando a
mensagem vai chegar, nem se o contedo ser preservado.
As portas do protocolo UDP obedecem a mesma distribuio
das TCP porm so distintas uma da outra, de modo que o programador pode associar uma porta TCP de um determinado nmero
uma aplicao em um host e o mesmo nmero de porta UDP a
outra aplicao no mesmo host.

Tpicos Avanados

67

As classes DatagramPacket e DatagramSocket contm os mtodos necessrios para realizar este tipo de comunicao. Para
ilustrar o uso destas classes modicaremos os exemplos 3.1 e 3.2
para implementarmos uma aplicao Cliente/Servidor Daytime
que usa o protocolo UDP. O exemplo 3.4 mostra o cdigo fonte
do cliente e o exemplo 3.5 mostra o cdigo do servidor.
import j a v a . i o . ;
import j a v a . n e t . ;
public c l a s s DataClienteUDP

public s t a t i c void main ( S t r i n g a r g s [ ] )


throws E x c e p t i o n

i f ( args . length != 1)

System . e r r . p r i n t l n (
"Uso : j a v a DataClienteUDP h o s t " ) ;
System . e x i t ( 1 ) ;

byte [ ] b u f f = new byte [ 6 4 ] ;


DatagramSocket ds = new DatagramSocket ( ) ;

DatagramPacket dp =
new DatagramPacket ( b u f f , b u f f . l e n g t h ,
I n e t A d d r e s s . getByName ( a r g s [ 0 ] ) , 5 0 1 3 ) ;
ds . r e c e i v e ( dp ) ;
S t r i n g s = new S t r i n g ( dp . getData ( ) ) ;
System . out . p r i n t l n ( "Data e hora r e c e b i d a de "+
dp . g e t A d d r e s s ()+ " : "+s ) ;

Exemplo 3.4 Cliente Daytime UDP.


Analisando o cdigo da aplicao cliente podemos notar que
necessrio criar um objeto da classe DatagramPacket para representar os Datagrama onde os dados so armazenados. No nosso
exemplo colocamos tambm os dados do host e a porta, porm
estes dados poderiam ser omitidos na construo do datagrama e
serem passados somente no envio/recepo do pacote ou na construo do DatagramSocket. O Datagrama dever armazenar os

68

Java na prtica

dados enviados pelo servidor e foi dimensionado para conter 64 bytes. O mtodo receive() do objeto DatagramSocket aguarda o
recebimento do pacote, tendo como argumento o objeto da classe
DatagramPacket. Aps o recebimento do pacote os dados so
convertidos para String e exibidos na sada padro.
import j a v a . i o . ;
import j a v a . n e t . ;
import j a v a . u t i l . ;
public c l a s s DataServerUDP

public s t a t i c void main ( S t r i n g a r g s [ ] )


throws E x c e p t i o n

DatagramSocket ds ;
DatagramPacket dp ;
I n e t A d d r e s s addr =
I n e t A d d r e s s . getByName ( " 2 5 5 . 2 5 5 . 2 5 5 . 0 " ) ;
ds = new DatagramSocket ( ) ;

byte [ ] b u f f ;
for ( ; ; )
{

Thread . s l e e p ( 1 0 0 0 ) ;
S t r i n g s = ( new Date ( ) ) . t o S t r i n g ( ) ;
buff = s . getBytes ( ) ;
dp = new DatagramPacket (
b u f f , b u f f . l e n g t h , addr , 5 0 1 3 ) ;
ds . send ( dp ) ;

Exemplo 3.5 Servidor Daytime UDP.


O servidor, diferentemente do servidor TCP, precisa saber a
quem deve enviar os pacotes, uma vez que no estabelecida
uma conexo. Podamos simplesmente passar o nome do host
pela linha de comando, mas resolvemos adotar uma estratgia
de Broadcasting. Nesta abordagem os datagramas so enviados
a vrios computadores e no apenas um. Isto feito passandose como argumento para o mtodo InetAddress.getByName() o
endereo de Broadcast da rede.
O tipo de endereo de Broadcast depende da classe de endereamento IP da rede. O endereo usado no exemplo 3.5 funciona

Tpicos Avanados

69

para a classe de endereamento C. Para descobrir que tipo de


classe pertence a rede onde est seu computador olhe o primeiro
byte do endereo IP de sua mquina e verique junto a tabela 3.3.
Primeiro byte do endereo IP

Classe

Endereo de Broadcast

0 a 126
128 a 191
192 a 223

A
B
C

255.0.0.0
255.255.0.0
255.255.255.0

Tabela 3.3 Endereos de Broadcast.


O envio dos dados feito pelo mtodo send() do objeto
DatagramSocket, tendo como argumento um objeto da classe
DatagramPacket. Note que no necessrio um Socket servidor uma vez que o servidor envia os pacotes independentemente
de existir clientes solicitando-os.

3.2.5 Comunicao por meio de URL


Uma URL (Uniform Resource Locator ) uma referncia (um endereo) a um recurso na Internet. A URL dividida em partes,
sendo que apenas a primeira parte obrigatria. A maioria das
URLs dividida em trs partes:

Figura 3.4 Divises da URL.


A parte do protocolo dene o protocolo que deve ser usado
para acessar o recurso. Os protocolos mais comuns so FTP,
HTTP e le, este ltimo indicando que o recurso se encontra no
sistema de arquivos local. O protocolo seguido do caractere :.

70

Java na prtica

A parte com informao sobre o host fornece a informao


necessria para acessar o host, ou seja, onde est localizado o
recurso. A informao sobre o host precedida por duas barras
(//), no caso de aplicao na Internet e apenas por uma barra
(/), caso contrrio. A informao sobre o host tambm pode
ser dividida em trs partes: a) o nome do domnio do host; b)
o nome e senha do usurio para login; e c) o nmero da porta
caso necessrio, aps o nome do host, precedida pelo caractere :.
Exemplos:

http://java.sun.com:80/doc/tutorial.html
http://infax.com.br."claudio"."1234"/base/vendas
A ltima parte de uma URL representa o caminho at o recurso
no sistema de arquivos do host e chamada de URI (Uniform
Resource Identier ). Esta seo separada da seo anterior por
uma barra simples (/).

3.2.6 Manipulando URLs em Java


A linguagem Java fornece as seguintes classes para manipulao
de URLs:

Classe

Descrio

URL
URLConnection

Representa um URL.
Classe abstrata que representa uma conexo entre uma
aplicao e um URL. Instncias desta classe podem ser
usadas para ler e escrever no recurso referenciado pela
URL.
Usada para lidar com o formato MIME.
Classe abstrata usada para dar suporte a conexes
HTTP.

URLEncoder
HttpURLConnection

Tabela 3.4 Classes para manipulao de URLs.


Um objeto URL criado passando como parmetro para o
construtor o URL na forma de uma cadeia de caracteres:

URL dpi = new URL("http://www.dpi.ufv.br");

Tpicos Avanados

71

Um objeto URL pode ser construdo passando como parmetro


outro URL para servir de endereo base. Por exemplo

URL profs = new URL (dpi,"professores.html");


Isto tem o mesmo efeito que gerar uma instncia da classe URL
com primeiro construtor, passando como parmetro o endereo:

http://www.dpi.ufv.br/professores.html
Os construtores geram a exceo MalformedURLException, se
o URL invlido. Portanto, o programador deve providenciar o
cdigo para a captura e tratamento desta exceo.
import j a v a . n e t . ;
import j a v a . i o . ;
public c l a s s LeURL

public s t a t i c void main ( S t r i n g [ ] a r g s )


throws E x c e p t i o n

i f ( a r g s . l e n g t h < 1)

System . e r r . p r i n t l n ( " uso : j a v a LeURL <URL>" ) ;


System . e x i t ( 1 ) ;

}
URL u r l = new URL( a r g s [ 0 ] ) ;
B u f f e r e d R e a d e r i n = new B u f f e r e d R e a d e r (
new InputStreamReader ( u r l . openStream ( ) ) ) ;
String linha ;

while ( ( l i n h a = i n . r e a d L i n e ( ) ) ! = null )
System . out . p r i n t l n ( l i n h a ) ;

in . close ( ) ;

Exemplo 3.6 Leitor de URL.

72

Java na prtica

De posse de um objeto URL possvel obter um objeto


InputStream para ler os dados endereados pela URL, utilizando
o mtodo openStream() do objeto URL. O exemplo 3.6 mostra o
cdigo de um programa que pode ser usado para listar na sada
padro o contedo de um URL passado pela linha de comando.

3.2.7 Comunicando por meio de URLConnection


O programador pode utilizar o mtodo openConnection() do
objeto URL para obter uma conexo entre a aplicao e o recurso
referenciado pela URL. O mtodo openConnection()retorna um
objeto URLConnection, que permite que a aplicao escreva e leia
atravs da conexo. Alguns URLs, como os associados scripts
CGI1 (Common-Gateway Interface ), JSP, PHP ou ASP permitem
que aplicao cliente escreva informao na URL.
<%

S t r i n g v a l o r = r e q u e s t . getParameter ( " c e l c i u s " ) ;


i f ( v a l o r ! = null )
{
double f = Double . p a r s e D o u b l e ( v a l o r ) 9 / 5 + 3 2 ;
out . p r i n t l n ( f ) ;
}
%>

Exemplo 3.7 Pgina JSP que realiza a converso.


A resposta requisio pode ser interceptada pelo programa
Java de modo que possa ser exibida para o usurio. Para ilustrar esta forma de comunicao mostraremos um programa que
submete um nmero, indicando uma temperatura em graus celsius, a uma URL para que seja transformado para graus fahrenheit e enviado de volta. A URL aponta para uma pgina JSP
1 Common-Gateway Interface (CGI) um mecanismo para gerar pginas

Web dinamicamente. Os dados so obtidos de formulrios HTML e submetidos a um programa binrio no servidor que gera a resposta na forma de uma
pgina Web. O programa pode ser escrito em uma variedade de linguagens,
como Perl e C.

Tpicos Avanados

73

(exemplo 3.7) que realiza a converso. Para o teste foi usado um


servidor HTTP local e a pgina foi colocada na seguinte URL
http://127.0.0.1:8080/teste/conversao.jsp
O exemplo 3.8 contm o programa que envia a temperatura
em graus celsius para o URL recebe de volta a temperatura em
graus fahrenheit.
import j a v a . i o . ;
import j a v a . n e t . ;
public c l a s s Converte

public s t a t i c void main ( S t r i n g [ ] a r g s )


throws E x c e p t i o n

i f ( args . length != 2)

System . e r r . p r i n t l n (
"Uso : j a v a Converte temp u r l " ) ;
System . e x i t ( 1 ) ;

String string =
URLEncoder . encode ( a r g s [ 0 ] , "UTF8" ) ;
URL u r l = new URL( a r g s [ 1 ] ) ;
URLConnection c = u r l . openConnection ( ) ;
c . setDoOutput ( true ) ;
P r i n t W r i t e r out =
new P r i n t W r i t e r ( c . getOutputStream ( ) ) ;
out . p r i n t l n ( " c e l c i u s=" + s t r i n g ) ;
out . c l o s e ( ) ;
B u f f e r e d R e a d e r i n = new B u f f e r e d R e a d e r (
new InputStreamReader (
c . getInputStream ( ) ) ) ;
String retorno ;

while ( ( r e t o r n o = i n . r e a d L i n e ( ) ) ! = null )
System . out . p r i n t l n ( r e t o r n o ) ;

in . close ( ) ;

Exemplo 3.8 Programa que escreve em um URL.

74

Java na prtica

necessrio codicar a cadeia de caracteres enviada por meio


do mtodo esttico encode() da classe URLEncoder, uma vez que
algumas transformaes so necessrias, como por exemplo, os
espaos em branco so substitudos pelo caractere +, os campos
so separados pelo caractere & e valor do campo separado do
nome do campo pelo caracter =.
Em seguida o programa cria um objeto URL relacionado com
o endereo onde se encontra o script, abre uma conexo e dene
que esta ser usada para entrada e sada.

URL url = new URL(args[1]);


URLConnection c = url.openConnection();
c.setDoOutput(true);
Neste momento o programa est preparado para trabalhar com
o URL como se fosse um stream. O stream para escrever no
URL obtido do objeto URLConnection por meio do mtodo
getOutputStream() e o stream para ler do URL obtido do
objeto URLConnection por meio do mtodo getInputStream().
Primeiro o programa submete a cadeia de caracteres a ser invertida precedida pelo nome do campo e pelo caractere =:

out.println("string="+ string);
Aps isso o stream de sada fechado e o stream de entrada
aberto. A cadeia de caracteres com a temperatura convertida
lida e exibida no dispositivo de sada padro.

Captulo 4

Acesso a Banco de
Dados
Nos dias de hoje, uma linguagem sem recursos para acesso a sistemas de Banco de Dados est fadada ao fracasso. Pensando nisso
a Sun incluiu, como parte do ncleo de bibliotecas de classes da
linguagem Java, uma API (Application Program Interface ) com
o objetivo de preencher esta funo, chamada de JDBC (segundo
a Sun JDBC apenas um acronismo, no entanto, muitas pessoas acreditam que uma sigla para Java Database Connectivity ).
JDBC uma API baseada no X/Open SQL Call Level Interface,
tendo sido desenvolvida originalmente como um pacote separado,
porm a partir do JDK1.1 passou a fazer parte do ncleo bsico de
pacotes. Utilizando a API JDBC possvel conectar um programa
Java com servidores de Banco de Dados e executar comandos SQL
(Structure Query Language ). Sendo uma API independente do
Sistema Gerenciador de Banco de Dados, no necessrio escrever uma aplicao para acessar um Banco de Dados Oracle, outra
para uma Base de Dados Sybase, outra para o DB2, e assim por
diante.
A idia de se usar uma camada intermediria entre o Banco
de Dados e a aplicao, com o objetivo de isol-la das particularidades do SGBD (Sistema gerenciador de Banco de dados), no
75

76

Java na prtica

nova. O exemplo mais popular deste enfoque a API ODBC


(Open DataBase Connectivity ), proposta pela Microsoft. O leitor pode estar se perguntando porque a Sun resolveu propor mais
uma API em vez de adotar o ODBC. Existem vrios motivos, porm o principal que a API ODBC simplesmente no adequada
para a linguagem Java. Isto ocorre porque ODBC foi desenvolvida para ser usada na linguagem C e baseada fortemente no
uso de ponteiros, estrutura que no existe em Java. Alm disso,
a API ODBC no foi desenvolvida tendo em vista as facilidades
do interfaciamento com uma linguagem orientada a objetos.

4.1 Modelos de Acesso a Servidores


O modelo mais simples de aplicao Cliente/Servidor o chamado
modelo de duas camadas, onde a aplicao acessa diretamente
o Banco de Dados. A gura 4.1 mostra o esquema para uma
aplicao que acessa um Banco de Dados usando o modelo de
duas camadas.

Figura 4.1 Modelo de acesso a Banco de Dados em duas


camadas.

No entanto, hoje em dia, mais comum o desenvolvimento de


sistemas com trs ou mais camadas. A vantagem de se usar um nmero maior de camadas a possibilidade de um maior isolamento
das funes, permitindo assim uma melhor manutenabilidade e
exibilidade do sistema. A gura 4.2 mostra o esquema para uma

Tpicos Avanados

77

aplicao que acessa um Banco de Dados usando o modelo de trs


camadas.

Figura 4.2 Modelo de acesso a Banco de Dados em trs


camadas.

4.2 Tipos de Drivers JDBC


Os drivers JDBC devem suportar o nvel de entrada do padro
ANSI SQL-2. Na API JDBC 2.0 foi includo suporte para tipos
de dados do padro SQL3, tais como BLOB, CLOBCLOB e
tipos estruturados. No momento, os drivers JDBC existentes se
encaixam em um dos quatro tipos abaixo:

Tipo 1 (Ponte JDBC-ODBC com driver ODBC) : o dri-

ver JDBC acessa o banco de dados via drivers ODBC. Como


o ODBC um cdigo binrio e, em alguns casos, compe o
cdigo do cliente, necessrio instal-lo em cada mquina
cliente que usa o driver. Essa uma soluo adequada somente para testes ou para pequenas aplicaes, uma vez que
a traduo para o protocolo ODBC inuencia o desempenho.

78

Java na prtica

Tipo 2 (Driver Java parcial e Api Nativa) : neste caso as

chamadas JDBC so convertidas para as chamadas na API


nativa do SGBD. Como o driver possui uma parte em cdigo binrio necessrio instalar algum cdigo na mquina
cliente, como feito nos drivers do tipo 1.

Tipo 3 (Driver puro Java e protocolo de rede) :

neste
caso as chamadas JDBC so convertidas para um protocolo
de rede independente do SGBD que depois traduzido para
as chamadas na API nativa do SGBD por um servidor.
Esta uma arquitetura em trs camadas, onde o servidor
middleware capaz de conectar seus clientes Java puros
com vrios SGBDs. Esta soluo permite o desenvolvimento
de clientes 100% Java, tendo como consequncia a no
necessidade de instalao de qualquer cdigo na mquina
cliente.

Tipo 4 (Driver Java Puro e protocolo nativo) : neste caso

as chamadas JDBC so convertidas para as chamadas na


API nativa do SGBD pelo driver, que foi escrito totalmente
em Java. Este driver independente de plataforma, uma
vez que totalmente escrito em Java.

Tpicos Avanados

79

4.2.1 Obtendo os Drivers JDBC


Informaes sobre como obter drivers JDBC podem ser obtidas no
site http://www.javasoft.com/products/jdbc. Outra alternativa acessar as pginas dos fabricantes de SGBD, para vericar
se existe driver disponvel.

4.3 Preparando o Banco de Dados


Os exemplos deste livro usam um driver JDBC do tipo 4 para para
conectar com o SGBD HSQLDB. O HSQLDB (www.hsqldb.org)
um SGBD de cdigo aberto desenvolvido em Java. Ele obedece
os padres SQL e JDBC, e possui as seguintes caractersticas:

Tamanho pequeno (100KB).


Funciona como servidor, standalone e in-memory.
Suporta transao.
Suporta integridade referencial.
Suporta procedimentos Armazenados em Java.
Possibilita a atribuio de direitos de acessos.
Para instal-lo execute as seguintes etapas:
1. Descompacte o arquivo hsqldb_1_7_1.zip em um diretrio qualquer. Por exemplo : c:\ (MS-Windows) ou /usr
(Linux).
2. Adicione as classes do HSQLDB ao CLASSPATH:
SET CLASSPATH=%CLASSPATH%;c:\hsqldb\lib\hsqldb.jar (MS-Windows)

ou
export CLASSPATH=$CLASSPATH:/usr/hsqldb/lib/hsqldb.jar (Linux)

Para iniciar a execuo do HSQLDB em modo servidor, abra


uma shell, mude para o diretrio onde voc deseja que o banco de
dados seja gravado e digite:

80

Java na prtica
java org.hsqldb.Server -database meudb

onde meudb o nome do banco de dados. Para executar o gerenciador grco para execuo de comandos digite:

java org.hsqldb.util.DatabaseManager

A gura 4.3 mostra a tela inicial do gerenciador do HSQLDB.


Nessa tela o usurio deve selecionar a opo HSQL Database
Engine Server e pressionar o boto OK (o usurio sa e a senha ). A gura 4.4 mostra a tela principal do gerenciador do
HSQLDB.

Figura 4.3 Tela inicial do gerenciador do HSQLDB.

Tpicos Avanados

81

Figura 4.4 Tela principal do gerenciador do HSQLDB.


Aps isso necessrio criar uma base de dados no SGBD. Nos
exemplos deste livro ser usada uma base contendo dados sobre
livros, alunos e emprstimos de livros aos alunos. No trataremos
neste livro dos conceitos relacionados com banco de dados relacionais nem sobre a linguagem de consulta SQL. Existem vrios
textos sobre o assunto onde o leitor pode buscar essas informaes,
tais como Elmasri e Navathe ou Silberschatz, Forth e Sudarshan
(1997).
As tabelas 4.1 a 4.3 mostram as tabelas que formam a base de
dados usada nos exemplos. O banco de dados formado por trs
tabelas. Uma para armazenar os dados dos alunos, outra para
receber os dados dos livros e uma terceira para conter os dados
dos emprstimos.

matricula
1
2
3
4
5
6

nome
Railer Costa Freire
Alexandre Alto Pigatti
Andr M. A. Landro
Ana Maria Freitas
Claudia Maria Oliveira
Alexandra Moreira

Tabela 4.1 Tabela alunos.

82

Java na prtica

codlivro
1
2
3
4
5
6
7
8
9
10

titulo
Curso Pratico de Java
Curso Pratico de Java
Introduo a Compiladores
Fundamentos de Banco de Dados
Redes de Computadores Fcil
Redes de Computadores Fcil
Lgica matemtica
Engenharia de Software para Leigos
Aprenda Computao Grfica em duas horas
Aprenda Inteligncia Artificial em 5 anos

volume
1
2
1
1
1
2
1
1
1
1

Tabela 4.2 Tabela livros.


codlivro
1
7
9
1
4
10

matricula
1
3
6
3
2
2

dataemp
01/01/99
03/01/99
12/01/99
20/01/99
03/02/99
12/02/99

datadev
10/01/99
13/01/99
22/01/99
30/01/99
13/02/99
22/02/99

Tabela 4.3 Tabela emprestimos.


Em um Banco de Dados Relacional cada tabela representa
um conjunto de entidades ou relacionamentos entre entidades, e
cada linha da tabela representa uma entidade particular ou um
relacionamento entre entidades. Assim, cada linha das tabelas
alunos e livros representa um aluno e um livro respectivamente.
J na tabela emprestimos cada linha representa o relacionamento
por emprstimo de um livro a um aluno. Para estabelecer este tipo
de relacionamento em um Banco de Dados Relacional preciso
colocar na tabela que representa o relacionamento os atributos
chaves de cada entidade que participa da relao. Atributos chaves
so os atributos que identicam cada entidade. No caso dos alunos
seu nmero de matrcula, uma vez que pode existir dois alunos
com o mesmo nome. J no caso de um livro o seu atributo chave
o cdigo do livro. Um Banco de Dados Relacional pode ser

Tpicos Avanados

83

representado pelo diagrama de classes da UML, como mostrado


pela gura 4.5, onde cada tabela vista como uma classe.

Figura 4.5 Diagrama de Classes do Banco de Dados.


CREATE TABLE ALUNOS (MATRICULA INT PRIMARY KEY,
NOME VARCHAR( 5 0 ) NOT NULL ) ;
CREATE TABLE LIVROS (CODLIVRO INT PRIMARY KEY,
TITULO VARCHAR( 5 0 ) NOT NULL,
VOLUME INT NOT NULL ) ;
CREATE TABLE EMPRESTIMOS (

CODLIVRO INT NOT NULL,


MATRICULA INT NOT NULL,
DATAEMP DATE NOT NULL,
DATADEV DATE,
CONSTRAINT PK_EMP PRIMARY KEY
(CODLIVRO, MATRICULA, DATAEMP) ,
CONSTRAINT FK_EMP1
FOREIGN KEY (CODLIVRO)
REFERENCES LIVROS (CODLIVRO ) ,
CONSTRAINT FK_EMP2
FOREIGN KEY (MATRICULA)
REFERENCES ALUNOS (MATRICULA ) ) ;

Exemplo 4.1 Comandos em DDL para criao das tabelas em


um SGBD relacional.

Para criao das tabelas em banco de dados relacional deve-se


usar comandos DDL (Data Denition Language ). O exemplo 4.1
mostra os comandos em DDL para a criao das tabelas do exemplo.

84

Java na prtica

4.4 Exemplo Inicial


O pacote java.sql fornece as classes e interfaces necessrias para
a conexo com uma base de dados e a posterior manipulao dos
dados. As etapas para se criar uma aplicao cliente de um SGBD
em Java so as seguintes:
1. Carregar o driver JDBC.
2. Estabelecer a conexo.
3. Criar um objeto Statement.
4. Executar o comando SQL por meio de um mtodo do objeto
Statement.
5. Receber o resultado, se for o caso.
Para comentar cada uma destas etapas utilizaremos o exemplo 4.2 que mostra o cdigo de uma aplicao que lista no dispositivo de sada padro o nome de todos os alunos.
import j a v a . s q l . ;
import j a v a . n e t .URL;
class jdbc

public s t a t i c void main ( S t r i n g a [ ] )

try

C l a s s . forName ( " o r g . h s q l d b . j d b c D r i v e r " ) ;


Connection con =
DriverManager . g e t C o n n e c t i o n (
" j d b c : h s q l d b : h s q l : / / l o c a l h o s t " , " s a " , "" ) ;
Statement stmt = con . c r e a t e S t a t e m e n t ( ) ;
R e s u l t S e t r s = stmt . executeQuery
( "SELECT NOME FROM a l u n o s " ) ;
System . out . p r i n t l n ( "Nome" ) ;
while ( r s . next ( ) )
System . out . p r i n t l n ( r s . g e t S t r i n g ( "nome" ) ) ;
stmt . c l o s e ( ) ;
con . c l o s e ( ) ;
} catch ( E x c e p t i o n e )

Tpicos Avanados

85

{ System . out . p r i n t l n ( e . getMessage ( ) ) ;


e . printStackTrace ( ) ; }

Exemplo 4.2 Cdigo para listar o nome dos alunos.

4.4.1 Carregando o Driver


A primeira etapa carregar o driver JDBC. Para isso usado o
mtodo esttico forName() da classe Class. Em caso de erro este
mtodo lana a exceo ClassNotFoundException. O mtodo
cria uma instncia do driver e o registra junto ao DriverManager.
No exemplo 4.2 carregado o driver JDBC que vem junto com o
HSQLDB.

4.4.2 Estabelecendo a conexo


A segunda etapa realizada por meio do mtodo esttico
getConnection() da classe DriverManager. Este mtodo, na sua
forma mais simples, recebe como parmetro um URL que faz referncia a base de dados e retorna um objeto da classe Connection,
que representa a conexo com a base de dados. URLs (Uniform
Resource Locator ) so endereos de recursos na Web. No entanto,
existem algumas particularidades no que refere a URLs que fazem
referncia Banco de Dados. O formato padro deste tipo de
URL o seguinte:

jdbc:<subprotocolo >:<identificador >


onde:
1. jdbc representa o protocolo;
2. <subprotocolo> se refere ao driver ou ao mecanismo de conexo com o Banco de Dados, que pode ser suportado por
um ou mais drivers. No exemplo 4.2 o subprotocolo representado pela palavra hsqldb.

86

Java na prtica
3. <identicador> a parte onde se identica o Banco de Dados. A forma de identicao varia de acordo com o subprotocolo. Como o HSQLDB gerencia apenas uma base dados
em uma determinada mquina, ento preciso apenas indicar a mquina onde est localizado o gerenciador. Isto feito
por meio da palavra chave hsql: seguida da identicao da
mquina. Como o gerenciador est executando na mquina
local, ento a identicao da mquina localhost.

Tanto o uso local como remoto pode requerer a identicao do


usurio, assim como uma senha. Estes dados podem ser passados
como parmetro no mtodo getConnection(). No exemplo 4.2 o
nome do usurio  sa e a senha . Alguns exemplos de URLs
esto descritos na tabela 4.4.

Arquivo

Descrio

jdbc:odbc:biblioteca

Referencia fonte de dados biblioteca via ponte


JDBC-ODBC.
Referencia fonte de dados bd1
via ponte JDBC-ODBC. denido o tamanho do cache.
Referencia fonte de dados
contas via ponte JDBC-ODBC.
passado tambm o nome do
usurio e a senha.
Referencia fonte de dados
agenda no host
remoto
sap.dpi.ufv.br via subprotocolo oracle.
passado
tambm o nmero da porta
usada no acesso.
Referencia fonte de dados dpi
no host local via subprotocolo
postgresql.

jdbc:odbc:bd1;CacheSize=20
jdbc:odbc:contas;UID=ana;PWD=sght

jdbc:oracle:thin:@sap.ufv.br:1521:agenda

jdbc:postgresql://localhost/dpi

Tabela 4.4 Exemplos de URLs JDBC.

4.4.3 Criando e Executando Comandos


necessrio criar um ou mais objetos da classe Statement, que
possui os mtodos necessrios para manipular a base de dados.

Tpicos Avanados

87

Este objeto criado por meio do mtodo createStatement() do


objeto da classe Connection.

Statement stmt = con.createStatement();


Podemos ento usar o objeto Statement para executar comandos de manipulao do Banco de Dados. No exemplo 4.2 o
objetivo recuperar os nomes dos alunos. Este objetivo atingido
por meio da execuo do comando SQL

SELECT nome FROM alunos


passado como parmetro para o mtodo executeQuery() do
objeto Statement. Este mtodo retorna um objeto que implementa a interface ResultSet, e que fornece os meios de acesso ao
resultado da consulta. Muitas vezes, como no exemplo, o resultado de uma consulta uma tabela com vrias linhas. O programador pode utilizar o objeto ResultSet para acessar cada linha
da tabela resultante em sequncia. Para isso o objeto mantm um
apontador para a linha corrente, chamado de cursor. Inicialmente
o cursor posicionado antes da primeira linha e movimentado
para prxima linha por meio de chamadas ao mtodo next() do
objeto ResultSet.
O mtodo executeQuery() usado apenas para consultas. Alm desse mtodo, a classe Statement possui o mtodoexecute() que retorna mltiplos ResultSets e o mtodo
executeUpdate(), para atualizao (comandos INSERT, DELETE e UPDATE da linguagem SQL), criao de tabelas (comandos CREATE TABLE) e remoo (DROP TABLE). O valor
de retorno do mtodo executeUpdate() um valor inteiro indicando o nmero de linhas afetadas ou zero no caso do DROP
TABLE. Um exemplo de um comando para inserir um novo aluno
na tabela seria:
stmt.executeUpdate("INSERT INTO alunos VALUES(7,'Ana mia')");

4.5 Recuperando Valores


O objeto ResultSet possui os mtodos necessrios para recuperar os valores de cada coluna da tabela, bastando passar o nome

88

Java na prtica

da coluna como parmetro. No exemplo 4.2 utilizado mtodo


getString() para recuperar o valor da coluna nome. Os mtodos para recuperao possuem o formato geral getXXX(), onde
XXX o nome de um tipo. A tabela 4.5 mostra qual o mtodo
mais indicado para cada tipo SQL.

Tabela 4.5 Tabelas com os mtodos indicados para recuperao


de valores.

possvel recuperar o valor da coluna passando como parmetro o nmero da coluna no lugar de seu nome. Neste caso a
recuperao do nome do aluno no exemplo 4.2 caria na seguinte
forma:

rs.getString(1);

Tpicos Avanados

89

4.6 Trabalhando com Metadados


Metadados so informaes sobre dados. No caso de bases de
dados relacionais estas informaes so os nomes das tabelas, os
nomes e os tipos da colunas, os nomes dos ndices, os nomes das
restries de integridade e outras informaes que descrevem os
dados. Em muitas situaes necessrio ter acesso a essas informaes para poder implementar certas aplicaes. Por exemplo,
uma aplicaes pode no saber de antemo o nmero e nem os
nomes das colunas que sero recuperadas em uma consulta. Sem
essas informaes impossvel percorrer as colunas para recuperar
os valores. No entanto, acessando os metadados do resultado da
consulta possvel contornar esse problema.
Para recuperar essas informaes o pacote java.sql fornece
os objetos ResultSetMetaData e DatabaseMetaData. O primeiro
objeto obtido a partir do mtodo de instncia getMetaData()
do objeto ResultSet e utilizado para obter os metados de um
resultado de uma consulta, tais como nome e nmero de colunas
retornadas. J o segundo objeto obtido a partir do mtodo de
instncia getMetaData() do objeto Connection e utilizado para
obter os metados da base de dados, tais como nvel de isolamento,
suporte a comandos SQL, suporte a transaes, etc.
O exemplo 4.3 mostra o cdigo de um programa que recebe
na linha de comando uma consulta SQL e imprime o resultado
da consulta. Como o programa no sabe o nome e o nmero
de colunas que resultaro da consulta necessrio fazer uso dos
metadados para produzir uma sada adequada.
import j a v a . s q l . ;
public c l a s s TestaMeta

void accessDB ( S t r i n g c o n s u l t a )

try

C l a s s . forName ( " o r g . h s q l d b . j d b c D r i v e r " ) ;


Connection c o n n e c t i o n ;
c o n n e c t i o n=DriverManager . g e t C o n n e c t i o n (
" jdbc : hsqldb : hsql :// l o c a l h o s t " , " sa " , "" ) ;
Statement s t a t e m e n t = c o n n e c t i o n . c r e a t e S t a t e m e n t ( ) ;

90

Java na prtica
boolean h a s R e s u l t s = s t a t e m e n t . e x e c u t e ( c o n s u l t a ) ;
i f ( hasResults )

ResultSet r e s u l t = statement . getResultSet ( ) ;


i f ( r e s u l t != null ) d i s p l a y R e s u l t s ( r e s u l t ) ;

}
connection . close ( ) ;
} catch ( E x c e p t i o n ex )
{
ex . p r i n t S t a c k T r a c e ( ) ;
}

void d i s p l a y R e s u l t s ( R e s u l t S e t r ) throws SQLException

ResultSetMetaData rmeta = r . getMetaData ( ) ;

int nCol=rmeta . getColumnCount ( ) ;


S t r i n g nomeCol [ ] = new S t r i n g [ nCol ] ;
for ( int i =1; i<=nCol;++ i )

nomeCol [ i 1] = rmeta . getColumnName ( i ) ;

while ( r . next ( ) )

for ( int i =1; i<=nCol;++ i )

System . out . p r i n t l n (
nomeCol [ i 1]+"="+r . g e t S t r i n g ( i ) ) ;
i f ( i==nCol )
System . out . p r i n t ( " \n" ) ;

public s t a t i c void main ( S t r i n g a r g s [ ] )

{
}

new TestaMeta ( ) . accessDB ( a r g s [ 0 ] ) ;

Exemplo 4.3 Uso de metados em consulta.


Ao invocar o programa deve-se passar o comando SQL entre
aspas, como mostrado abaixo:
java -cp ".;/hsqldb/lib/hsqldb.jar"TestaMeta "SELECT * FROM
LIVROS"

Tpicos Avanados

91

4.7 Trabalhando com datas


SQL2 dene vrios tipos relacionados com datas. A tabela 4.6
mostra os tipos de dados para datas segundo Elmasri e Navathe.

tipo

Descrio e Exemplo

DATE

Possui dez posies e o formato padro


'AAAA-MM-DD' , onde AAAA representa o ano, MM
representa o ms e DD representa o dia. Exemplo: '2003-09-07' .
Possui oito posies e o formato padro
'HH:MM:SS' , onde HH representa a hora, MM
representa os minutos e SS representa os segundos. Exemplo: '10:30:12' .
Neste tipo de dados a preciso de segundos
incrementada de i posies para representar
fraoes de segundos.
Neste tipo de dados includa seis posies
para representar o deslocamento em relao
o meridiano de Greenwich, que pode ir de
+13:00 a -12:59.
Inclui os campos DATE e TIME e mais seis
posies para fraes de segundos.

TIME

TIME(i )

TIME WITH TIME ZONE

TIMESTAMP

Tabela 4.6 Tipos de dados relacionados com datas em SQL2.


O exemplo 4.4 mostra um mtodo que recebe como parmetros
uma conexo com o banco de dados, a matrcula de um aluno, o
cdigo de um livro e uma data e atualiza a tabela de emprestimos,
colocando a data atual no campo DATADEV no registro que tem
como chave primria a matrcula de um aluno, o cdigo do livro
e data de emprestimo iguais aos recebidos como parmetros.
...

void d e v o l v e ( Connection con , int mat , int c o d l i v r o ,

S t r i n g dataemp )

j a v a . u t i l . Date data = new j a v a . u t i l . Date ( ) ;


SimpleDateFormat f = new SimpleDateFormat ( "yyyyMMdd" ) ;
S t r i n g datadev = f . format ( data ) ;

try

Statement s t a t e m e n t = con . c r e a t e S t a t e m e n t ( ) ;
s t a t e m e n t . executeUpdate (

92

Java na prtica
"UPDATE EMPRESTIMOS SET DATADEV = ' "+
datadev+" ' WHERE MATRICULA="+mat+
" AND CODLIVRO="+c o d l i v r o+
" AND DATAEMP='"+dataemp+" ' " ) ;

}
...

} catch ( E x c e p t i o n ex )
{
ex . p r i n t S t a c k T r a c e ( ) ;
}

Exemplo 4.4 Mtodo para devoluo de um livro.

4.8 Transaes e Nvel de Isolamento


4.8.1 Transao
Uma Transao um conjunto de operaes realizadas, sobre um
banco de dados, tratadas atomicamente, em outras palavras, ou
todas operaes so realizadas e o seu resultado registrado permanentemente na base de dados ou nenhuma operao realizada.
Por default, o banco de dados trata cada operao como uma
transao, realizando implicitamente uma operao de commit ao
m de cada uma delas. A operao de commit registra permanentemente o resultado da transao na tabela.
No entanto, existem situaes onde necessrio tratar como
uma transao um conjunto de operaes, e no apenas uma operao. Por exemplo, suponha que em um Banco de Dados de uma
agncia bancria exista uma tabela com informaes sobre contas
corrente e outra com informaes sobre contas de poupana. Suponha tambm que um cliente deseje transferir o dinheiro da conta
corrente para a conta de poupana. Essa transao constituda
pelas seguintes operaes:
1. Caso exista saldo suciente, subtrao do montante da
transferncia do saldo da conta corrente.
2. Adio do montante da transferncia ao saldo da conta de
poupana.

Tpicos Avanados

93

As operaes acima precisam ocorrer totalmente ou o efeito


de nenhuma delas deve ser registrado na base de dados. Caso
contrrio podemos ter uma situao onde o dinheiro sai da conta
corrente mas no entra na conta da poupana. Este estado, onde
as informaes do banco de dados no reete a realidade, chamado de estado inconsistente.
De modo a obter esse controle sobre as transaes necessrio
desabilitar o modo de auto-commit. Isto feito por meio mtodo
setAutoCommit() do objeto Connection.

con.setAutoCommit(false);
A partir do momento em que executado o comando acima, o
programador responsvel pela indicao do nal da transao,
por meio da execuo do mtodo commit() do objeto Connection.

con.commit();
Se alguma exceo for levantada durante a execuo de qualquer operao da transao, o programador pode usar o mtodo
rollback() para desfazer as operaes j realizadas aps o ltimo commit(). O exemplo 4.5 mostra um trecho de cdigo que
procura explorar o uso do commit() e rollback().
...
con . setAutoCommit ( f a l s e ) ;

try

Statement stmt = con . c r e a t e S t a t e m e n t ( ) ;


stmt . executeUpdate (
"UPDATE EMPRESTIMOS SET DATADEV='"
+data+" ' WHERE CODLIVRO="
+c o d l i v r o+" AND MATRICULA="+mat ) ;
stmt . executeUpdate (
"UPDATE RESERVA SET LIBERADO=' s ' WHERE CODLIVRO="
+c o d l i v r o ) ;
con . commit ( ) ;
stmt . c l o s e ( ) ;

catch ( E x c e p t i o n e )

{
}

con . r o l l b a c k ( ) ;

finally

try

94

Java na prtica
{
}

con . setAutoCommit ( true ) ;

catch ( SQLException s q l e )

{
}
...

System . out . p r i n l n ( s q l . getMessage ( ) ) ;

Exemplo 4.5 Uso dos mtodos commit() e rollback().

4.8.2 Nveis de isolamento


Alm da atomicidade outra propriedade desejvel em uma transao o isolamento. A propriedade de isolamento implica que
uma transao no afetada pelas operaes realizadas por outras
transaes que esto sendo realizadas concorrentemente.
O isolamento completo entre transaes prejudica muito a execuo concorrente de transaes e pode ser desnecessrio em determinados tipos de aplicaes. Por isso os SGBDs permitem que o
programador dena o nvel de isolamento entre as transaes. De
acordo com o relaxamento do isolamento certos problemas devido
a interferncia entre as transaes podem ocorrer e o programador
deve estar ciente disso.
O nmero de nveis de isolamento, sua nomenclatura e caractersticas dependem do SGBD utilizado. Descreveremos os nveis
de isolamento denidos no pacote java.sql. Para exemplicar os
problemas que podem ocorrer devido a interferncia entre transaes utilizaremos um banco de dados exemplo com a seguinte
tabela:

NumCC
10189-9
20645-7

Saldo
200,00
300,00

Tabela 4.7 Tabela contas.


Read uncommitted : o nvel menos restritivo. Podem ocorrer leituras de registros no committed (Dirty reads). Usado

Tpicos Avanados

95

onde no existe concorrncia ou no existem alteraes


em registros ou quando essas alteraes no so relevantes. Exemplo de problema: Uma transao deve transferir
R$50,00 da conta 10189-9 para a conta 20645-7 e uma segunda transao deve somar R$70,00 conta 10189-9. A
gura a seguir mostra o estado inicial e o estado nal desejado da tabela:

Estado antes das


transaes
NumCC Saldo
10189-9
200,00
20645-7
300,00

Estado desejado aps


as transaes
NumCC Saldo
10189-9
220,00
20645-7
350,00

Cada transao divida em operaes de leitura e escrita.


Suponha que o intercalamento das operaes seja feito como
mostrado abaixo:

Tempo
1
2
3
4
5

Transao 1

Transao 2

leitura do saldo 10189


Escrita do Saldo-50,00
leitura do saldo 10189
leitura do saldo 20645
(falha na transao,
realizado rollback)

Escrita do Saldo+70,00

Como a transao 1 falhou o valor lido pela transao 2


um valor que no foi tornado permanente na tabela. Isto faz
com que a transao 2 opere sobre um resultado desfeito. A
tabela resultante, mostrada a seguir, estar em um estado
inconsistente.

96

Java na prtica

NumCC
10189-9
20645-7

Saldo
220,00
300,00

Read committed : Somente registros committed podem ser li-

dos. Evita o problema de Dirty reads, no entanto duas leituras de um mesmo item em uma mesma transao podem
possuir valores diferentes, uma vez que o valor pode ser mudado por outra transao entre duas leituras.

Repeatable Read : Somente registros committed podem ser li-

dos, alm disso impede a alterao de um item lido pela


transao. Evita o problema de Dirty reads e o problema do
non-repeatable read .

Serializable : o nvel mais restritivo. Impede Dirty reads e

non-repeatable reads. Alm disso impede o problema de


phantom reads onde um conjunto de registros satisfazendo a
condio WHERE lido enquanto outra transao insere novos
registros que satisfazem a condio.

Para se denir o nvel de isolamento na linguagem Java usa-se


um objeto DatabaseMetaData que obtido por meio do mtodo
getMetaData() do objeto Connection. Primeiro preciso saber
se o SGBD suporta o nvel de isolamento desejado para depois
denir o nvel. O exemplo 4.6 mostra uma sequncia tpica comandos.
DatabaseMetaData meta=con . getMetaData ( ) ;

i f ( meta . s u p p o r t s T r a n s a c t i o n I s o l a t i o n L e v e l (

con .TRANSACTION_READ_COMMITTED) ) {
con . s e t T r a n s a c t i o n I s o l a t i o n (
con .TRANSACTION_READ_COMMITTED) ;

else return ;

Exemplo 4.6 Estabelecimento do nvel de isolamento.

Tpicos Avanados

97

A tabela 4.8 mostra as constantes relacionadas com os nveis


de isolamento da linguagem Java. A constante TRANSACTION_NONE
indica que no existe suporte para transaes:

Constante
TRANSACTION_NONE
TRANSACTION_READ_UNCOMMITTED
TRANSACTION_READ_COMMITTED
TRANSACTION_REPEATABLE_READ
TRANSACTION_SERIALIZABLE

Tabela 4.8 Tabela com as constantes dos nveis de isolamento.

4.9 Prepared Statements


Cada vez que se executa um comando SQL, passado por meio de
um String, ele analisado pelo processador de SQL do SGBD
que ir, no caso do String estar sintaticamente correta, gerar
um cdigo binrio que ser executado para atender solicitao.
Todo esse processo caro e sua execuo repetidas vezes ter um
impacto signicativo sobre o desempenho da aplicao e do SGBD
como um todo.
Existem duas abordagens para se tentar solucionar esse problema: Comandos preparados (prepared statements) e procedimentos armazenados (stored procedures). Discutiremos primeiramente os prepared statements.
Prepared Statement indicado nos casos onde um comando
ser executado vrias vezes em uma aplicao. Neste caso melhor compilar o comando uma nica vez e toda vez que for necessrio execut-lo basta enviar o comando compilado. Alm disso, o
comando pr-compilado pode ser parametrizado, tornando-o mais
genrico e, portanto, apto a expressar um maior nmero de consultas.
Para criar um Prepared Statement necessrio obter um objeto
PreparedStatement por meio do mtodo prepareStatement()
do objeto Connection, passando como argumento um comando
SQL.

98

Java na prtica

PreparedStatement pstmt = con . p r e p a r e S t a t e m e n t (


"INSERT INTO a l u n o s ( m a t r i c u l a , nome ) VALUES ( ? , ? ) " ) ;

O comando anterior insere uma nova linha na tabela alunos


com os valores das colunas matricula e nome passados por parmetro. O caractere ` ?' representa o parmetro. Este tipo de
comando s possui valor tendo parmetros, caso contrrio teria
pouca chance de ser reutilizado. Para executar o comando devemos especicar o valor dos parmetros e executar o comando,
como mostrado no exemplo seguinte:
...
pstmt . c l e a r P a r a m e t e r s ( ) ;
pstmt . s e t I n t ( 1 , 8 ) ;
pstmt . s e t S t r i n g ( 2 , " C l a r a Maria " ) ;
pstmt . executeUpdate ( ) ;
...

Antes de especicar os parmetros necessrio limpar qualquer outro parmetro previamente especicado. Para especicar
os parmetros utilizado um conjunto de mtodos com o nome no
formato setXXX(), onde XXX o tipo sendo passado. O primeiro
parmetro do mtodo setXXX() o ndice da ocorrncia do caractere ` ?' que ser substitudo pelo valor. O segundo parmetro
o valor que ser transmitido.

4.10 Procedimentos Armazenados (Stored Procedures)


A maioria dos SGBDs possuem algum tipo de linguagem de programao interna, como por exemplo a PL/SQL do Oracle ou
mesmo Java e C/C++. Estas linguagens permitem que os desenvolvedores insiram parte do cdigo da aplicao diretamente no
banco de dados e invoquem este cdigo a partir da aplicao. Esta
abordagem possui as seguintes vantagens:

Reuso de cdigo - o cdigo precisa ser escrito apenas uma

Tpicos Avanados

99

vez e usado em vrias aplicaes, comunicando com vrias


linguagens.

Independncia entre a aplicao e o esquema do BD - se o esquema mudar, provavelmente ser necessrio mudar apenas
os procedimentos armazenados.
Desempenho - os procedimentos so previamente compilados, eliminando esta etapa.
Segurana - as aplicaes possuem privilgio apenas para
execuo de procedimentos armazenados, evitando assim
acessos no autorizados.
A sintaxe dos procedimentos armazenados depende do SGBD
em questo. Utilizaremos um exemplo em PL/SQL. No exemplo 4.7 o procedimento retorna o nome do aluno a partir de sua
matrcula.
CREATE OR REPLACE PROCEDURE sp_obtem_nome
( i d IN INTEGER, Nome_aluno out VARCHAR2) IS
BEGIN

SELECT nome INTO Nome_aluno


FROM a l u n o s
WHERE m a t r i c u l a = i d ;
END;
/

Exemplo 4.7 Procedimento PL/SQL.


Para invocar o procedimento anterior de dentro de uma aplicao Java necessrio obter um objeto CallableStatement por
meio do mtodo prepareCall() do objeto Connection, passando
como argumento a chamada ao procedimento armazenado. O
exemplo 4.8 mostra a chamada ao procedimento denido no exemplo 4.7.
C a l l a b l e S t a t e m e n t cstmt =
con . p r e p a r e C a l l ( " { CALL sp_obtem_nome ( ? , ? ) } " ) ;
cstmt . r e g i s t e r O u t P a r a m e t e r ( 2 , Types .VARCHAR) ;

100

Java na prtica

cstmt . s e t I n t ( 1 , 3 ) ;
cstmt . e x e c u t e ( ) ;
System . out . p r i n l n ( "O nome do a l u n o numero 3 : "
+cstmt . g e t S t r i n g ( 2 ) ;

Exemplo 4.8 Chamada do procedimento PL/SQL.

4.11 Agenda Eletrnica verso JDBC


A seguir mostrado o cdigo dos mdulos que compem a verso
da agenda eletrnica que usa um gerenciador de banco de dados
para armazenar os dados. O gerenciador de banco de dados utilizado o HSQLDB, mas o programa pode ser facilmente adaptado
para outros gerenciadores, bastando para isso alterar as linhas relacionadas com a carga do driver e com a obteno da conexo no
arquivo Agenda.java. A gura 4.6 mostra a tela principal desta
verso da agenda eletrnica.

Figura 4.6 Tela principal da agenda eletrnica.


O exemplo 4.9 mostra a classe Agenda que a principal do
programa. Ao iniciar, a classe cria uma instncia da classe
AgendaIntUsuario que implementa a interface com o usurio.

Tpicos Avanados

101

Alm disso, no incio de seu processamento, a classe Agenda estabelece uma conexo com o gerenciador de banco de dados que
permanece ativa at que o programa termine. Esta no a melhor forma de se manter conexes com o banco de dados, a no ser
que o sistema funcione com poucos usurios. O mais adequado
que as conexes sejam estabelecidas apenas durante os acessos ao
banco de dados e que sejam, preferencialmente, gerenciadas em
um pool de conexes1 .
Note que o mtodo exibeTodos() usa no comando SQL a expresso LIKE `...%'. Esta expresso usada quando se deseja
obter cadeias de caracteres com um trecho idntico ao da expresso. O caractere `%' funciona como um curinga que casa com
qualquer sequncia de palavras. Portanto, a expresso utilizada
no exemplo determina que todos os nomes que iniciam com a
sequncia digitada devem ser recuperados.
import j a v a . s q l . ;
public c l a s s Agenda

Connection con=null ;
AgendaIntUsuario a i = null ;

// Construtor

public Agenda ( )

{
}

public void i n i c i a ( )

a i = new AgendaIntUsuario ( this ) ;


a i . show ( ) ;

try

C l a s s . forName ( " o r g . h s q l d b . j d b c D r i v e r " ) ;


con=DriverManager . g e t C o n n e c t i o n (
" jdbc : hsqldb : hsql :// l o c a l h o s t " , " sa " , "" ) ;
} catch ( E x c e p t i o n e )
{
a i . s e t S t a t u s ( e . getMessage ( ) ) ;
}

public void c l o s e A g e n d a ( )
1 pool de conexes uma camada de software que ca entre o programa
e o SGBD e que responsvel pelo manuteno e reuso compartilhado das
conexes com o SGBD, de forma a promover um uso otimizado deste recurso.

102
{
}

Java na prtica
i f ( con ! = null )
try { con . c l o s e ( ) ; } catch ( E x c e p t i o n e ) { } ;

public void i n s e r i r ( S t r i n g n , S t r i n g t )

i f ( con == null ) return ;


try

Statement stmt = con . c r e a t e S t a t e m e n t ( ) ;


S t r i n g s = "INSERT INTO p e s s o a s ( nome , t e l e f o n e ) "+
" v a l u e s ( ' "+n+" ' , ' "+t+" ' ) " ;
stmt . executeUpdate ( s ) ;

stmt . c l o s e ( ) ;
} catch ( E x c e p t i o n e ) { a i . s e t S t a t u s ( e . getMessage ( ) ) ; }

public void c o n s u l t a r ( S t r i n g n )

i f ( con == null ) return ;


try

Statement stmt = con . c r e a t e S t a t e m e n t ( ) ;


R e s u l t S e t r s = stmt . executeQuery (
"SELECT T e l e f o n e FROM p e s s o a s WHERE Nome='"
+n+" ' " ) ;
i f ( r s . next ( ) )
{
a i . setNome ( r s . g e t S t r i n g ( "Nome" ) ) ;
a i . setNome ( r s . g e t S t r i n g ( " T e l e f o n e " ) ) ;
}
stmt . c l o s e ( ) ;
} catch ( E x c e p t i o n e ) { a i . s e t S t a t u s ( e . getMessage ( ) ) ; }

public void remover ( S t r i n g n )

i f ( con == null ) return ;


try

Statement stmt = con . c r e a t e S t a t e m e n t ( ) ;


i f ( stmt . e x e c u t e (
"DELETE FROM p e s s o a s WHERE Nome='"+n+" ' " ) )
a i . s e t S t a t u s ( " removido " ) ;

else

a i . s e t S t a t u s ( " no e n c o n t r a d o " ) ;
stmt . c l o s e ( ) ;
} catch ( E x c e p t i o n e ) { a i . s e t S t a t u s ( e . getMessage ( ) ) ; }

public void exibeTodos ( S t r i n g n )

Tpicos Avanados
{

i f ( con == null ) return ;


try

Statement stmt = con . c r e a t e S t a t e m e n t ( ) ;


R e s u l t S e t r s = stmt . executeQuery (
"SELECT Nome , T e l e f o n e FROM p e s s o a s " +
" WHERE Nome LIKE ' " + n + "%'" ) ;
a i . se tSa ida ( "" ) ;
while ( r s . next ( ) )
{
a i . p r i n t l n ( "Nome : "+r s . g e t S t r i n g ( "Nome" ) ) ;
a i . p r i n t l n ( " Tel . : "+r s . g e t S t r i n g ( " T e l e f o n e " ) ) ;
}
stmt . c l o s e ( ) ;
} catch ( E x c e p t i o n e ) { a i . s e t S t a t u s ( e . getMessage ( ) ) ; }

public s t a t i c void main ( S t r i n g a r g s [ ] )

{
}

new Agenda ( ) . i n i c i a ( ) ;

Exemplo 4.9 Arquivo Agenda.java.


import j a v a x . swing . ;
public c l a s s AgendaIntUsuario extends JFrame {
Agenda ag = null ;

public AgendaIntUsuario ( Agenda a )

{
}

ag =a ;
initComponents ( ) ;

private void initComponents ( )

j P a n e l 1 = new j a v a x . swing . JPanel ( ) ;


j L a b e l 1 = new j a v a x . swing . JLabel ( ) ;
jTextFieldNome = new j a v a x . swing . J T e x t F i e l d ( ) ;
j L a b e l 2 = new j a v a x . swing . JLabel ( ) ;
j T e x t F i e l d T e l = new j a v a x . swing . J T e x t F i e l d ( ) ;
j P a n e l 2 = new j a v a x . swing . JPanel ( ) ;
j S c r o l l P a n e 1 = new j a v a x . swing . J S c r o l l P a n e ( ) ;
j T e x t A r e a S a i d a = new j a v a x . swing . JTextArea ( ) ;
j P a n e l 3 = new j a v a x . swing . JPanel ( ) ;

103

104

Java na prtica
j L a b e l S t a t u s = new j a v a x . swing . JLabel ( ) ;
j P a n e l 4 = new j a v a x . swing . JPanel ( ) ;
jButtonCons = new j a v a x . swing . JButton ( ) ;
j B u t t o n I n s = new j a v a x . swing . JButton ( ) ;
jButtonRem = new j a v a x . swing . JButton ( ) ;
j B u t t o n L i s t = new j a v a x . swing . JButton ( ) ;
addWindowListener ( new j a v a . awt . e v e n t . WindowAdapter ( )
{
public void windowClosing (
j a v a . awt . e v e n t . WindowEvent e v t )
{
exitForm ( e v t ) ;
}
});
j P a n e l 1 . s e t L a y o u t ( new j a v a . awt . GridLayout ( 2 , 2 ) ) ;
j L a b e l 1 . s e t T e x t ( "Nome : " ) ;
j P a n e l 1 . add ( j L a b e l 1 ) ;
j P a n e l 1 . add ( jTextFieldNome ) ;
jLabel2 . setText ( " Telefone : " ) ;
j P a n e l 1 . add ( j L a b e l 2 ) ;
j P a n e l 1 . add ( j T e x t F i e l d T e l ) ;
getContentPane ( ) . add (
j P a n e l 1 , j a v a . awt . BorderLayout .NORTH) ;
j T e x t A r e a S a i d a . setColumns ( 6 0 ) ;
jTextAreaSaida . s e t E d i t a b l e ( f a l s e ) ;
jTextAreaSaida . setFont (
new j a v a . awt . Font ( " C o u r i e r " , 0 , 1 0 ) ) ;
j T e x t A r e a S a i d a . setRows ( 1 2 ) ;
j S c r o l l P a n e 1 . setViewportView ( j T e x t A r e a S a i d a ) ;
j P a n e l 2 . add ( j S c r o l l P a n e 1 ) ;
getContentPane ( ) . add ( j P a n e l 2 ,
j a v a . awt . BorderLayout .CENTER) ;
j P a n e l 3 . s e t L a y o u t ( new j a v a . awt . BorderLayout ( ) ) ;
j L a b e l S t a t u s . setBackground (
new j a v a . awt . C o l o r ( 0 , 2 5 5 , 2 5 5 ) ) ;
jLabelStatus . setForeground (
new j a v a . awt . C o l o r ( 2 5 5 , 0 , 1 0 2 ) ) ;
jLabelStatus . setHorizontalAlignment (
SwingConstants . LEFT ) ;
jLabelStatus . setVerticalAlignment (
SwingConstants .TOP) ;
jLabelStatus . setBorder (
new j a v a x . swing . b o r d e r . T i t l e d B o r d e r ( " S t a t u s " ) ) ;
j P a n e l 3 . add ( j L a b e l S t a t u s ,

Tpicos Avanados
j a v a . awt . BorderLayout .CENTER) ;
getContentPane ( ) . add ( j P a n e l 3 ,
j a v a . awt . BorderLayout .SOUTH) ;
j P a n e l 4 . s e t L a y o u t ( new j a v a . awt . GridLayout ( 4 , 0 ) ) ;
jButtonCons . s e t T e x t ( " C o n s u l t a r " ) ;
jButtonCons . a d d A c t i o n L i s t e n e r (
new j a v a . awt . e v e n t . A c t i o n L i s t e n e r ( ) {
public void a c t i o n P e r f o r m e d (
j a v a . awt . e v e n t . ActionEvent e v t ) {
jButtonConsActionPerformed ( e v t ) ;
}
});
j P a n e l 4 . add ( jButtonCons ) ;
jButtonIns . setText ( " I n s e r i r " ) ;
jButtonIns . addActionListener (
new j a v a . awt . e v e n t . A c t i o n L i s t e n e r ( ) {
public void a c t i o n P e r f o r m e d (
j a v a . awt . e v e n t . ActionEvent e v t ) {
jButtonInsActionPerformed ( evt ) ;
}
});
j P a n e l 4 . add ( j B u t t o n I n s ) ;
jButtonRem . s e t T e x t ( "Remover" ) ;
jButtonRem . a d d A c t i o n L i s t e n e r (
new j a v a . awt . e v e n t . A c t i o n L i s t e n e r ( ) {
public void a c t i o n P e r f o r m e d (
j a v a . awt . e v e n t . ActionEvent e v t ) {
jButtonRemActionPerformed ( e v t ) ;
}
});
j P a n e l 4 . add ( jButtonRem ) ;
jButtonList . setText ( " L i s t a r " ) ;
jButtonList . addActionListener (
new j a v a . awt . e v e n t . A c t i o n L i s t e n e r ( ) {
public void a c t i o n P e r f o r m e d (
j a v a . awt . e v e n t . ActionEvent e v t ) {
jButtonListActionPerformed ( evt ) ;
}
});
j P a n e l 4 . add ( j B u t t o n L i s t ) ;
getContentPane ( ) . add ( j P a n e l 4 ,
j a v a . awt . BorderLayout . EAST ) ;
}

pack ( ) ;

105

106

Java na prtica

private void j B u t t o n I n s A c t i o n P e r f o r m e d (
}

j a v a . awt . e v e n t . ActionEvent e v t ) {
ag . i n s e r i r ( getNome ( ) , g e t T e l ( ) ) ;

private void jButtonConsActionPerformed (


}

j a v a . awt . e v e n t . ActionEvent e v t ) {
ag . c o n s u l t a r ( getNome ( ) ) ;

private void jButtonRemActionPerformed (


}

j a v a . awt . e v e n t . ActionEvent e v t ) {
ag . remover ( getNome ( ) ) ;

private void j B u t t o n L i s t A c t i o n P e r f o r m e d (
}

j a v a . awt . e v e n t . ActionEvent e v t ) {
ag . exibeTodos ( getNome ( ) ) ;

private void exitForm ( j a v a . awt . e v e n t . WindowEvent e v t )

{
}

ag . c l o s e A g e n d a ( ) ;
System . e x i t ( 0 ) ;

public s t a t i c void main ( S t r i n g a r g s [ ] ) {


new AgendaIntUsuario ( null ) . show ( ) ;

public void s e t S t a t u s ( j a v a . l a n g . S t r i n g s ) {
}

jLabelStatus . setText ( s ) ;

public void s e t S a i d a ( j a v a . l a n g . S t r i n g s ) {
}

jTextAreaSaida . setText ( s ) ;

public void p r i n t ( j a v a . l a n g . S t r i n g s ) {
}

j T e x t A r e a S a i d a . append ( s ) ;

public void p r i n t l n ( j a v a . l a n g . S t r i n g s ) {
}

j T e x t A r e a S a i d a . append ( ' \n '+s ) ;

public S t r i n g getNome ( ) {
return jTextFieldNome . getText ( ) ;

public S t r i n g g e t T e l ( ) {
return j T e x t F i e l d T e l . getText ( ) ;

public void setNome ( S t r i n g s ) {

Tpicos Avanados

107

jTextFieldNome . s e t T e x t ( s ) ;

public void s e t T e l ( S t r i n g s ) {
}

jTextFieldTel . setText ( s ) ;

private
private
private
private
private
private
private
private
private
private
private
private
private
private
private

j a v a x . swing . JButton jButtonRem ;


j a v a x . swing . JLabel j L a b e l S t a t u s ;
j a v a x . swing . J T e x t F i e l d jTextFieldNome ;
j a v a x . swing . JButton j B u t t o n L i s t ;
j a v a x . swing . JPanel j P a n e l 4 ;
j a v a x . swing . JPanel j P a n e l 3 ;
j a v a x . swing . JPanel j P a n e l 2 ;
j a v a x . swing . JPanel j P a n e l 1 ;
j a v a x . swing . J S c r o l l P a n e j S c r o l l P a n e 1 ;
j a v a x . swing . J T e x t F i e l d j T e x t F i e l d T e l ;
j a v a x . swing . JTextArea j T e x t A r e a S a i d a ;
j a v a x . swing . JButton j B u t t o n I n s ;
j a v a x . swing . JButton jButtonCons ;
j a v a x . swing . JLabel j L a b e l 2 ;
j a v a x . swing . JLabel j L a b e l 1 ;

Exemplo 4.10 Arquivo AgendaIntUsuario.java.

4.12 Como congurar a ponte JDBCODBC


Apesar de estarmos utilizando um banco de dados que possui um
driver JDBC do tipo 4, til saber como congurar um driver
do tipo 1 (ponte JDBC-ODBC), para aqueles casos onde o SGBD
no possui um driver JDBC ou para testes rpidos. Por isso resolvemos mostrar como utilizar a ponte JDBC-ODBC na plataforma
MS-Windows. No entanto, importante mencionar que a ponte
JDBC-ODBC no adequada para sistemas em produo, devido
ao seu menor desempenho. Para utilizar a ponte JDBC-ODBC
necessrio, primeiro, congurar o ODBC para acessar a base
de dados. Por exemplo, suponha que a base de dados foi criada
por meio do MS-Access e foi gravada em um arquivo de nome
agenda.mdb. Na plataforma MS-Windows 98, a congurao do
ODBC seria feita da seguinte forma:

108

Java na prtica

Figura 4.7 Seleo da fonte de dados.

1. Execute o programa de congurao do ODBC por meio do


cone ODBC de 32bits do painel de controle.

2. Clique na pasta NFD do sistema e em seguida no boto


de adicionar... (gura 4.7). O NFD do sistema escolhido no lugar da opo NFD do usurio porque permite
o compartilhamento da base de dados.

3. Selecione o driver do banco de dados e pressione o boto de


concluir. Por exemplo, se voc estiver usando o MS-Access
selecione a opo Driver para o Microsoft Access (*.mdb).

Tpicos Avanados

109

Figura 4.8 Seleo do driver ODBC no Windows.


4. Ao surgir a tela para a seleo do Banco de Dados, utilize
o boto Selecionar... para localizar o arquivo onde est a
base de dados. Preencha a janela de texto Nome da fonte
de dados com o nome que ser usado para referenciar a
base.

Figura 4.9 Seleo da base de dados.


5. Feche o programa de congurao.

110

Java na prtica

Aps isso a base de dados pode ser acessada via ponte JDBCODBC por meio do driver sun.jdbc.odbc.JdbcOdbcDriver e da
URL jdbc:odbc:agenda, onde agenda o nome dado fonte de
dados na congurao do ODBC.

Captulo 5

RMI
A RMI (Remote Method Invocation ) uma tecnologia que coloca a programao com rede em um nvel mais alto. RMI torna
possvel que objetos distribudos em uma rede se comuniquem de
forma transparente para o programador utilizando chamadas de
procedimentos remotos.
O principal objetivo da tecnologia RMI permitir que programadores desenvolvam programas distribudos utilizando a mesma
sintaxe e semntica de programas Java convencionais. Antes da
introduo da RMI no mundo Java, no JDK 1.1, para fazer com
que dois objetos em mquinas diferentes se comunicassem, o programador deveria denir um protocolo de comunicao e escrever
cdigo utilizando soquete para implementar este protocolo. Com
RMI a maior parte do trabalho quem realiza a mquina virtual
Java.
Existem outras tecnologias, como CORBA, que tambm tem
como objetivo fazer com que objetos distribudos em uma rede se
comuniquem. Java tem suporte a CORBA, mas para projetos em
um ambiente Java puro, a RMI consideravelmente mais simples
que a CORBA.
111

112

Java na prtica

5.1 Arquitetura RMI


A arquitetura do Sistema RMI se baseia na distino entre os
conceitos de interface e implementao fornecidos pela plataforma
Java. Por isso podemos ter aplicaes clientes que conhecem apenas a interface de um objeto, e consegue utiliz-lo, mesmo estando
sua implementao rodando em outra mquina virtual, possivelmente at em outra mquina de uma rede.
Na gura 5.1 vemos a separao possvel entre um objeto cliente e um objeto servidor. A denio de um servio feita utilizando uma interface Java e a implementao codicada como
uma classe. 1

Figura 5.1 Arquitetura RMI.

5.2 Criando nossa agenda distribuda


Seguindo a mesma abordagem, esta seo mostra e explica os
conceitos e o cdigo de nossa agenda distribuda.

5.2.1 Passo a Passo


1. Escrever e compilar a interface que descreve como sero as
chamadas do cliente ao servidor;
1 Uma interface Java no carrega consigo nenhum cdigo. Temos ento um
grande desacoplamento entre o objeto cliente e o servidor.

Tpicos Avanados

113

2. Escrever e compilar a classe que implementa a interface do


passo 1 (objeto servidor);
3. Gerar o stub do objeto distribudo;
4. Desenvolver o cdigo que disponibiliza o objeto;
5. Escrever e compilar o cdigo para o cliente RMI;

5.2.2 Implementando interface do objeto remoto


O primeiro passo quando se deseja criar um objeto Remoto com
RMI implementar uma interface para este objeto. Essa interface deve herdar a interface Remote. atravs dessa interface
Remote, que no tem mtodos, que a mquina virtual Java sabe
qual objeto pode ser disponibilizado para acesso remoto. Abaixo
temos o exemplo da interface do nosso objeto:
public interface Agenda extends
j a v a . rmi . Remote{

public void i n s e r i r ( Pessoa p )


throws j a v a . rmi . RemoteException ;
public Pessoa g e t P e s s o a ( S t r i n g nome )
throws j a v a . rmi . RemoteException ;
public j a v a . u t i l . Enumeration g e t P e s s o a s ( )
throws j a v a . rmi . RemoteException ;

Exemplo 5.1 Interface remota de Agenda.


A interface Remote deve ser herdada pela nossa interface
Agenda.
Com objetos distribudos sempre estaremos sujeitos a falha de
rede e problemas com algumas mquinas. Por isso todos os mtodos devem poder levantar a exceo java.rmi.RemoteException.
Para compilar a interface Agenda utilizamos o comando:
javac Agenda.java

114

Java na prtica

5.2.3 Escrevendo objeto remoto


Em seguida, deve ser criada a classe AgendaImp que implementa
a interface Agenda. O exemplo 5.2 mostra a listagem da classe
AgendaImpl que utiliza uma Hashtable.

2
4

import j a v a . rmi . ;
import j a v a . u t i l . ;
public c l a s s AgendaImpl
extends j a v a . rmi . s e r v e r . UnicastRemoteObject
implements Agenda{
Hashtable pessoas ;

public AgendaImpl ( ) throws RemoteException {


super ( ) ;
p e s s o a s = new H a s h t a b l e ( ) ;

10
12

public void i n s e r i r ( Pessoa p )


throws RemoteException {

14

public Pessoa g e t P e s s o a ( S t r i n g nome )


throws RemoteException {
return ( Pessoa ) p e s s o a s . g e t ( nome ) ;

16

18

public Enumeration g e t P e s s o a s ( )
throws RemoteException {
return p e s s o a s . e l e m e n t s ( ) ;

20
22

p e s s o a s . put ( p . getNome ( ) , p ) ;

Exemplo 5.2 Implementa classe de Agenda Remota.


Uma
classe
de
implementao
deve
usar
UnicastRemoteObject para se ligar ao sistema RMI, como
na linha 4 do exemplo 5.2.
A classe AgendaImpl usa a
UnicastRemoteObject atravs de herana, mas se uma classe
no puder herdar UnicastRemoteObject , lembrando que Java
no possui herana mltipla, ela pode usar o seu mtodo
exportObject() para se ligar ao RMI.

Tpicos Avanados

115

Quando uma classe herda UnicastRemoteObject, seu construtor deve poder levantar a exceo java.rmi.RemoteException e
este construtor deve chamar o mtodo super() que inicializa a
classe para usar RMI, como na linha 8.
Para compilar a AgendaImpl, usamos:
javac AgendaImpl.java

5.2.4 Gerando Stub


O prximo passo a gerao do stub de AgendaImpl. Nesta tarefa
o compilador rmic utilizado. Este compilador cria uma classe
stub que responsvel por passar as chamadas de mtodos remotos
para o sistema RMI. Esse por sua vez se conecta ao objeto servidor
pela rede e chama seus mtodos.
Para gerar o stub, digitamos o comando:
rmic -v1.2 AgendaImpl

A opcao -v1.2 diz ao rmic para criar somente o stub para o


RMI do Java 2. Na verso Java 1.1 o comando rmic criava um
stub e um esqueleto, este esqueleto no mais criado no Java 2.
Este comando gera um arquivo de stub para o RMI do Java 2
com o nome AgendaImpl_Stub.class.

5.2.5 Desenvolvendo o cdigo que disponibiliza


o objeto
Um dos problemas que se enfrenta quando temos vrios objetos
distribudos em uma rede trocando requisies e dados, saber
onde est determinado objeto. Este uma das questes que resolvemos com servidores de nomes ou diretrios.
O sistema RMI pode utilizar vrios servidores diferentes, entre
eles o JNDI (Java Naming and Directory Interface ). O sistema
RMI nos disponibiliza um servidor de nomes simples chamado
RMI registry .
Chamamos de vinculao o processo de associar um objeto a
uma URL no sistema RMI. Todos os clientes que precisarem usar
este objeto iro localiz-lo atravs desta URL.

116

2
4
6

Java na prtica

import j a v a . rmi . Naming ;


public c l a s s AgendaServer {
public AgendaServer ( ) {
try {
Agenda a = new AgendaImpl ( ) ;

8
10

12

Naming . r e b i n d ( " rmi : / / l o c a l h o s t : 1 0 9 9 / Agenda" , a ) ;


} catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
}

public s t a t i c void main ( S t r i n g a r g s [ ] ) {


new AgendaServer ( ) ;

14
16 }

Exemplo 5.3 Servidor do objeto Agenda.


A linha 6 do exemplo 5.3 cria um objeto AgendaImpl, que ser
o objeto disponibilizado para uso remoto.
A classe Naming fornece o mtodo para armazenar a referncia
de um objeto remoto Agenda no sistema de registro do RMI (linha
7).
O mtodo rebind() cria uma associao entre a URL
"rmi://localhost:1099/Agenda" e o objeto AgendaImpl criado
na linha anterior.

5.2.6 Escrevendo o cliente


Abaixo temos o cdigo de um cliente para o objeto Agenda que
disponibilizamos.
2
4
6
8
10
12

import j a v a . rmi . ;
public c l a s s AgendaCliente {
public s t a t i c void main ( S t r i n g [ ] a r g s ) {
try {

Agenda a = ( Agenda )
Naming . lookup ( " rmi : / / l o c a l h o s t : 1 0 9 9 / Agenda" ) ;
Pessoa p1 = new Pessoa ( " Joo S i l v a " ,
" 999 99999 " , "Rua Avenida " ) ;
Pessoa p2 = new Pessoa ( " Manuel " ,
" 888 8888 " , " Avenida Rua" ) ;
a . i n s e r i r ( p1 ) ;
a . i n s e r i r ( p2 ) ;

Tpicos Avanados

14
16
18
20 }

117

Pessoa b = a . g e t P e s s o a ( " Manuel " ) ;


System . out . p r i n t l n ( b . getNome ( ) + " " +
b . getTelefone ( ) ) ;
} catch ( E x c e p t i o n e ) {
e . printStackTrace ( ) ;
}

Exemplo 5.4 Exemplo de cliente para o objeto Agenda.


A linha 6 do exemplo 5.4 utiliza o mtodo lookup() para obter
uma referncia para o objeto remoto Agenda. Obtida esta referncia todo o resto do programa a utiliza como em uma programa
convencional.
O processo de transformar uma chamada de um mtodo remoto para um formato que possa ser transmitido pela rede chamado de arranjo. O inverso, transformar o formato transmitido
pela rede em classes Java e chamado desarranjo.
Um objeto para participar de um arranjo ou desarranjo deve
ser Serializable. Um objeto do tipo Pessoa o parmetro do
mtodo inserir da interface Agenda, por isso classe Pessoa deve
ser do tipo Serializable.

5.3 Testando tudo


Nesta seo as formas de testar o programa construdo no Windows e no Linux sero mostradas.

5.3.1 No Windows
Abra trs janelas do DOS e digite na primeira:
rmiregistry

Isso inicializa o servidor de nomes do RMI. Na segunda janela


do DOS digite:
java AgendaServer
rmiregistry

118

Java na prtica

Agora temos o objeto servidor inicializado e vinculado ao servidor de nomes. Na terceira janela do DOS digite o teste:
java AgendaCliente
rmiregistry

que produzir a seguinte saida:


Manuel 888-8888

5.3.2 No Linux
Abra uma shell e digite:
rmiregistry &

Isso inicializa o servidor de nomes do RMI. Em seguida digite:


java AgendaServer &

Digite agora o teste:


java AgendaCliente

que produzir a seguinte saida:


Manuel 888-8888

Captulo 6

CORBA
A tecnologia RMI prov, para a plataforma Java, uma forma eciente e intuitiva de trabalhar com objetos distribudos. Contudo,
alguns problemas surgem quando os sistemas vo se tornando mais
complexos. Caractersticas como interoperabilidade com diferentes componentes, possivelmente escritos em vrias linguagens e
plataformas diferentes, passam a ser exigidas. Interfaciamento
com sistemas legados so tambm caractersticas que grandes sistemas reais geralmente pedem. Neste cenrio temos aplicaes
escritas em COBOL, C, ADA e outras linguagens, rodando em
Sistemas Operacionais distintos como Windows, UNIX e VMS.
Uma abordagem para tratar de forma homegnia esse problema
o uso de CORBA.
Neste Captulo sero mostrados os conceitos bsicos de
CORBA e como criar e utilizar objetos em um ORB, escrevendoos em Java. Na seo 6.2 um exemplo de objetos escritos em Java
interoperando com objetos escritos em C ser mostrado.

6.1 O que CORBA?


CORBA (Common Object Request Broker Architecture ) um conjunto de padres que denem o que chamado de um sistema de
objetos distribudos. Esses padres so escritos pelo OMG (Object
119

120

Java na prtica

Management Group ). O OMG composto por mais de 700 empresas com o propsito comum de utilizar esse conjunto de protocolos
padres. CORBA dene o protocolo de interao entre objetos.
Uma das diretrizes desses padres que objetos podem ser escritos em diferentes linguagens de programao, rodar em diferentes
sistemas operacionais, hospedados em diferentes mquinas.
O meio de comunicao entre os objetos o ORB (Object Request Broker ). O ORB pode transmitir mensagens entre objetos,
sendo que estes objetos podem estar na mesma mquina ou em
mquinas diferentes na rede. No primeiro caso, o ORB deve otimizar a troca de mensagens.
O ORB especico da implementao CORBA, mas ORBs
de diferentes fornecedores devem poder se comunicar, transparentemente, utilizando um protocolo comum. Isso signica que ns
podemos usar um ORB para desenvolver os objetos, e mais tarde,
por qualquer motivo, podemos usar outro ORB para interagir com
nossos objetos.
Para possibilitar que os objetos CORBA sejam escritos em diferentes linguagens, mquinas e sistemas operacionais, utilizada
uma notao para denir quais caractersticas do objeto (mtodos, atributos) so expostas. CORBA oferece tambm um padro
para esta notao: a IDL (Interface Denition Language ).

Implementacao
Cliente

do Objeto
IDL

IDL

ORB

Figura 6.1 Modelo de computao.


O ORB permite aos clientes invocarem operaes em objetos
distribudos sem se preocuparem com:

Tpicos Avanados

121

as localizaes dos objetos - Objetos CORBA podem ser


colocados junto com os clientes ou distribudos em servidores
remotos sem afetar suas implementaes ou usos;
os Sistemas Operacionais - CORBA roda em vrias plataformas, tais como: Windows, UNIX, Linux e sistemas para
tempo real e embutidos como QNX e VxWorks;
as linguagens de programao - Linguagens com mapeamentos padronizados pela OMG incluem: C, C++, Java,
Lisp, Ada95, COBOL e Smalltalk. Outras linguagens, apesar de no padronizadas pela OMG, tambm suportam
CORBA, entre elas: Perl, Object Pascal(Delphi), Python;
os protocolos de comunicao - Os protocolos de comunicao e interconectores que podem ser suportadas pelo
CORBA incluem: TCP/IP, IPX/SPX, FDDI, ATM, Ethernet, Fast Ethernet, backplanes de sistemas embutidos e memria compartilhada; e
os hardware envolvidos - CORBA esconde das aplicaes
os detalhes de diferentes hardwares como layout de armazenamento e tamanhos e faixas de tipos de dados.

Implementacao
Cliente

Implementacao
Cliente

do Objeto
IDL

IDL

do Objeto
IDL

IDL

ORB

ORB

Rede

Figura 6.2 Modelo de distribuio mostrando dois objetos em


mquinas diferentes se comunicando atravs dos ORBs.

Alguns componentes bsicos da arquitetura do CORBA so


necessrios para se entender sua forma de funcionamento e alguns
detalhes da sua programao. So eles:

122

Java na prtica

Cliente - Realiza suas tarefas obtendo referncias para objetos e invocando suas operaes. Os objetos podem estar
na mesma mquina que o cliente ou estarem localizados em
outras mquinas. A chamada de um mtodo remoto, para
o programador, no difere da chamada de um mtodo local.
Objeto - No CORBA um objeto uma instncia de uma
interface da linguagem IDL. O objeto identicado unicamente por uma referncia de objeto. Um ObjectId associa
um objeto com o servant que o implementa.
Servant - Este componente implementa as operaes denidas pela IDL. Em linguagens como Java, que suportam
orientao a objetos (OO), os servants so implementados
usando um ou mais objetos. Em linguagens no OO, os
servants so implementados usando funes e structs. Um
cliente nunca interage diretamente com um servant, e sim
atravs de um objeto.
ORB core - Quando um cliente invoca uma operao em
um objeto, o ORB Core responsvel por entregar a requisio para o objeto correto e retornar a resposta, se existir alguma, para o cliente. Para objetos executando remotamente, um ORB CORBA deve se comunicar com outro
via alguma verso do General Inter-ORB Protocol (GIOP).
Normalmente um ORB Core implementado como uma biblioteca que linkada no cliente e no servidor.
GIOP - O General InterORB Protocol especica todos os
aspectos de interoperabilidade sobre o transporte das mensagens na rede. O GIOP dene um pequeno conjunto de
mensagens que um ORB transmite para outro quando um
cliente invoca um mtodo de um objeto servidor. O GIOP
no dene como essas mensagens devem ser transportadas.
IIOP - A especicao da GIOP sendo transportada pela
pilha TCP/IP recebe o nome de IIOP(Internet Inter-ORB
Protocol )

Tpicos Avanados

123

Interface do ORB - Um ORB uma abstrao que pode


ser implementada de vrias formas (um ou vrios processos,
um conjunto de bibliotecas etc). Para desacoplar as aplicaes dos detalhes de implementao, a especicao CORBA
dene a interface para um ORB. Essa interface fornece operaes padres para:

 inicializar e parar o ORB;


 converter referncias para objetos em strings e viceversa;

 criar listas de argumentos para requisies dinmicas.


Stubs e Skeletons da IDL - IDL stubs e skeletons servem
como uma "cola"entre o cliente e o servant, respectivamente,
com o ORB.
Quando queremos fazer uma chamada a um objeto, devemos criar a mensagem correta, isso feito pelo stub. O
skeleton responsvel por traduzir essa mensagem para a
chamada correta dos objetos. O programador responsvel por escrever o stub e o skeleton, mas vrias ferramentas
so disponibilizadas para auxili-lo nesta tarefa. O stub age
como um objeto de representao local ou proxy que habilita o trabalho com o objeto remoto como se ele fosse local.
O skeleton faz o contrrio.

compilador IDL - Um compilador IDL automaticamente


transforma uma denio em OMG IDL no cdigo dos stubs
e skeletons para a linguagem de implementao. O SDK
Java fornece um compilador IDL.
Adaptador de objetos - Um adaptador de objetos responsvel por:






gerar referncias para objetos;


ativar e desativar servants ;
demultiplexar requisies para servants ;
colaborar com os skeletons IDL para invocar operaes
dos servants.

124

Java na prtica
A gura 6.3 mostra um adaptador direcionando requisies
para os servants.

Requisicao

ORB

Servants

POA

Figura 6.3 Funcionamento do Adaptador.


IOR - Uma Interoperable Object Reference tm sua estrutura mostrada na gura 6.4.

Nome do Tipo
(ID no repositorio)

Protocolo e
detalhes de endereco
e porta

Chave do objeto
(Adaptador e
nome do objeto

Figura 6.4 Referncia a objetos.


Em CORBA as referncias a objetos so opacas, i.e., no
permitido ao cdigo da aplicao olhar para dentro da referncia ou assumir qualquer coisa baseado em seu interior.
Essa caracterstica deixa transparente para a aplicao detalhes como protocolo, linguagem e forma de transporte.
O binding de uma requisio ilustrada na gura 6.5. A
requisio segue os seguintes passos:

Tpicos Avanados

125

1. Uma requisio enviada para a mquina onde est


o objeto baseado no campo contendo os detalhes de
endereo e porta;
2. O adaptador referenciado na chave do objeto direciona
a mensagem para o servant correto;
3. O retorno da requisio, se existir, enviado para o
cliente.

Cliente

Referencia do Objeto
IDL:MeuObj:1.0

serv:4443

CT5, Math

Servidor em serv:4443
Adaptadores

Obj5
Obj1

CT5
Obj1
Math
Obj10

(2)

(1)

Math

CK1
(3)

Obj5
Obj10
Servants

Figura 6.5 Caminho da requisio.


Esta a base da arquitetura CORBA. O ORB um framework
para objetos, mas CORBA tambm dene um conjunto rico de
objetos e pseudo-objetos (faades ) para vrios problemas comuns
do trabalho com objetos distribudos:

CORBA Services que permite que o programador tenha, por


exemplo, naming services, security services (autenticao de
objetos, encriptao da comunicao, etc) e license services
(que controla o uso dos objetos pelos usurios)

126

Java na prtica

CORBA facilities so construdos sobre os CORBA services


e um conjunto de objetos especcos para determinadas
reas da indstria: mdica, legal, etc.

Objetos da
Aplicacao

Cliente

Cliente

Object Request Broker

CORBA Services

Figura 6.6 Servio CORBA.

6.2 Exemplo CORBA em Java


CORBA tem, como discutido na seo anterior, uma srie de qualidades, mas um dos seus defeitos a grande quantidade de cdigo
gerado para utiliz-la. Parte desse cdigo gerado automaticamente pelos compiladores de IDL. Para evitar a incluso de grandes listagens nesse livro, trabalharemos um exemplo mais simples,
mas nem por isso menos interessante.
Faremos, agora, um objeto CORBA que realiza operaes matemtica. No exemplo teremos somente uma operao, o fatorial.

6.2.1 Escrevendo a IDL


A interface de nosso objeto deve ser denida atravs da
OMG/IDL. Nosso objeto far parte de uma biblioteca de objetos de nome MinhaLib.
module MinhaLib {
interface Matematica {
long f a t o r i a l ( i n long n ) ;

Tpicos Avanados

};

127

};

Exemplo 6.1 Arquivo Fatorial.idl


O arquivo Fatorial.idl dene nosso objeto, contendo somente um mtodo fatorial que retorna long e recebe como parmetro de entrada um outro valor long.

6.2.2 Compilando a IDL


Para compilar a IDL e gerar os stubs e skeletons utilizamos o
programa idlj que acompanha o JDK. Ao executar o comando:

idlj -fall Fatorial.idl


um diretrio de nome MinhaLib gerado e dentro desse diretrio
estaro o stub, o skeleton e a classe base para a implementao de
nosso objeto.

6.2.3 Implementando nosso Objeto


Dentro do diretrio do mdulo estar a classe base para nossa
implementao, essa classe abstrata, no nosso caso seu nome
_MatematicaImplBase.
Na listagem 6.2 temos a implementao do mtodo fatorial
declarado na IDL.
package MinhaLib ;
public c l a s s MatematicaImpl extends _MatematicaImplBase {
public int f a t o r i a l ( int n ) {
i f ( n > 0 ) return n f a t o r i a l ( n 1 ) ;
else return 1 ;
}

Exemplo 6.2 Arquivo MatematicaImpl.java

128

Java na prtica

6.2.4 Escrevendo o servidor


Agora, com nosso objeto implementado, devemos escrever o cdigo que o disponibilize para o uso de seus clientes. A listagem 6.3
mostra esse cdigo. A seguinte sequncia de passos seguida:
1. o ORB inicializado;
2. uma instncia do objeto MatematicaImpl criada;
3. o mtodo connect disponibiliza o objeto no ORB;
4. a referncia para o objeto convertida em uma string e
gravada no arquivo Matematica.ior; e
5. a execuo do thread que executa o mtodo main suspendida.
Nos nossos exemplos, para simplicar o cdigo e facilitar os
teste, no utilizamos nenhum servidor de nomes. Colocamos nossa
referncia ao objeto CORBA gravada em um arquivo que o cliente
deve ler.
import o r g . omg .CORBA.ORB;
import j a v a . u t i l . P r o p e r t i e s ;
import j a v a . i o . ;
public c l a s s F a t o r i a l S e r v e r {
public s t a t i c void main ( S t r i n g a r g s [ ] ) {
try {

P r o p e r t i e s p r o p s = System . g e t P r o p e r t i e s ( ) ;

ORB orb = ORB. i n i t ( a r g s , p r o p s ) ;


MinhaLib . MatematicaImpl s e r v a n t =
new MinhaLib . MatematicaImpl ( ) ;
orb . c o n n e c t ( s e r v a n t ) ;
S t r i n g i o r = orb . o b j e c t _ t o _ s t r i n g ( s e r v a n t ) ;
FileWriter f i l e =
new j a v a . i o . F i l e W r i t e r ( " Matematica . i o r " ) ;
P r i n t W r i t e r p f i l e = new j a v a . i o . P r i n t W r i t e r ( f i l e ) ;

Tpicos Avanados

129

pfile . println ( ior );


pfile . flush ();
pfile . close ();
j a v a . l a n g . Object sync = new j a v a . l a n g . Object ( ) ;

synchronized ( sync ) {
}

sync . w a i t ( ) ;

} catch ( E x c e p t i o n ex ) {
ex . p r i n t S t a c k T r a c e ( ) ;
}

Exemplo 6.3 Arquivo FatorialServer.java

6.2.5 Escrevendo o cliente


O cliente deve inicializar o ORB, obter a refrencia ao objeto,
convert-la em um objeto Java e usar seu mtodo fatorial.

import o r g . omg .CORBA.ORB;


import j a v a . u t i l . P r o p e r t i e s ;
import j a v a . i o . F i l e R e a d e r ;
import j a v a . i o . B u f f e r e d R e a d e r ;
public c l a s s F a t o r i a l C l i e n t {
public s t a t i c void main ( S t r i n g a r g s [ ] ) {
try {

P r o p e r t i e s p r o p s = System . g e t P r o p e r t i e s ( ) ;

ORB orb = ORB. i n i t ( a r g s , p r o p s ) ;


FileReader f i l e =
new j a v a . i o . F i l e R e a d e r ( " Matematica . i o r " ) ;
BufferedReader input =
new j a v a . i o . B u f f e r e d R e a d e r ( f i l e ) ;
String i o r = input . readLine ( ) ;
input . c l o s e ( ) ;
o r g . omg .CORBA. Object o b j =

130

Java na prtica
orb . s t r i n g _ t o _ o b j e c t ( i o r ) ;

i f ( o b j == null )
throw new RuntimeException ( ) ;

MinhaLib . Matematica s r v =
MinhaLib . MatematicaHelper . narrow ( o b j ) ;
i f ( s r v == null )
throw new RuntimeException ( ) ;

long r e s = s r v . f a t o r i a l ( 1 0 ) ;

System . out . p r i n t l n ( "O f a t o r i a l de 1 0 e "


+ res );
} catch ( E x c e p t i o n ex ) {
ex . p r i n t S t a c k T r a c e ( ) ;
}

Exemplo 6.4 Arquivo FatorialClient.java

6.2.6 Rodando o exemplo


Para rodar o exemplo devemos abrir dois consoles e no primeiro
digitar:

java FatorialServer
no outro console digite:

java FatorialClient
a saida ser:

O fatorial de 10 e 3628800

6.3 Exemplo CORBA (Java + C)


Nesta seo codicaremos o mesmo exemplo da seo 6.2 utilizando um mapeamento de IDL para a linguagem C e o ORB
free-source ORBit. Detalhes sobre o mapeamento da IDL para
C no faz parte do escopo deste livro, podendo ser encontrados
diretamente no site da OMG(www.omg.org).

Tpicos Avanados

131

O ORBit um ORB compatvel com a verso 2.4 da especicao. Os principais mapeamentos do ORBit so para as linguagens C e Perl, mas mapeamentos para outras tambm esto
disponveis C++, Lisp, Pascal, Python, Ruby e TCL). O ORBit
tem como diretriz de desenvolvimento a grande preocupao com
a performance. Por isso o core ORB escrito em C e foi escolhido como base para a comunicao entre objetos no ambiente
grco GNOME. O ORBit roda sobre Linux, UNIX (BSD, Solaris, HP-UX) e Windows. Outra importante caracterstica o
desenvolvimento realizado sobre a licensa GPL/LGPL.
O ORBit no utiliza por default a comunicao entre objetos
atravs da rede, colocando todas as trocas de mensagens entre objetos sendo realizada por mecanismos de IPC do sistema operacional. Essa abordagem justicada pela busca de alta performance.
Como nosso ORB Java no conhece esse interconector IPC, que
prprio do ORBit, devemos habilitar o uso do IIOP sobre sockets
de rede. Com esse propsito a listagem 6.5 deve ser colocada no
diretrio home do usurio que colocar os objetos para rodar.
ORBIIOPUSock=1
ORBIIOPIPv4=1
ORBIIOPIPv6=0

Exemplo 6.5 Arquivo .orbitrc


No exemplo utilizaremos a mesma IDL utilizada no exemplo
Java.

6.3.1 Compilando a IDL


O compilador de IDL do ORBit tem o nome orbit-idl e deve ser
usado da primeira vez com o parmetro --skeleton-impl para
gerar uma implementao vazia do objeto CORBA.

orbit-idl skeleton-impl Fatorial.idl


Esse comando tambm criar os arquivos stubs e skeletons.
Num segundo passo devemos alterar o arquivo de implementao
gerado para dar a funcionalidade desejada para nosso objeto.

132

Java na prtica

6.3.2 Implementando nosso Objeto


No nosso exemplo o arquivo de implementao vazio gerado ter o nome Fatorial-skelimpl.c.
Esse arquivo
extenso, e a parte que interessa o corpo da funo
impl_MinhaLib_Matematica_fatorial. Para implementarmos a
funcionalidade da fatorial declaramos a seguinte funo acima de
impl_MinhaLib_Matematica_fatorial:
s t a t i c long f a t o r i a l ( long n ) {
i f ( n > 0 ) return n f a t o r i a l ( n 1 ) ;
else return 1 ;

Exemplo 6.6 Funo que realiza a operao de fatorial.


O Corpo de impl_MinhaLib_Matematica_fatorial modicado para:
s t a t i c CORBA_long
impl_MinhaLib_Matematica_fatorial (
impl_POA_MinhaLib_Matematica s e r v a n t ,
CORBA_long n , CORBA_Environment ev )
{
CORBA_long r e t v a l ;
retval = f a t o r i a l (n ) ;
return r e t v a l ;
}

Exemplo 6.7 Funo impl_MinhaLib_Matematica_fatorial


modicada.

Essas duas alteraes implementam o mtodo do nosso objeto.

6.3.3 Escrevendo o Servidor


Semelhante a implementao do servidor em Java, escolhemos
mostrar a referncia do objeto CORBA (ior) criado na sada padro.

Tpicos Avanados

133

Os passos para criao e disponibilizao do objeto em C so


os mesmos realizados em Java.
#include " F a t o r i a l s k e l i m p l . c "
#include < s t d i o . h>
int

main ( int argc , char argv [ ] )


{
CORBA_ORB
orb ;
CORBA_Environment
ev ;
PortableServer_ObjectId oid ;
MinhaLib_Matematica
Mat ;
PortableServer_POA
root_poa ;
PortableServer_POAManager pm;
CORBA_char
objref ;
ev = g_new0 ( CORBA_Environment , 1 ) ;
CORBA_exception_init ( ev ) ;
orb = CORBA_ORB_init(& argc , argv ,
" o r b i t l o c a l orb " , ev ) ;
/ Manipula uma p o s s i v e l e x c e c a o /
root_poa = ( PortableServer_POA )
CORBA_ORB_resolve_initial_references ( orb ,
"RootPOA" , ev ) ;
/ Manipula uma p o s s i v e l e x c e c a o /
Mat = impl_MinhaLib_Matematica__create ( root_poa , ev ) ;
/ Manipula uma p o s s i v e l e x c e c a o /
o b j r e f = CORBA_ORB_object_to_string ( orb , Mat , ev ) ;
/ Manipula uma p o s s i v e l e x c e c a o /
g_print ( "%s \n" , o b j r e f ) ;
pm = PortableServer_POA__get_the_POAManager (
root_poa , ev ) ;
/ Manipula uma p o s s i v e l e x c e c a o /
PortableServer_POAManager_activate (pm , ev ) ;
/ Manipula uma p o s s i v e l e x c e c a o /

134

Java na prtica

CORBA_ORB_run( orb , ev ) ;
return 0 ;

Exemplo 6.8 Cdigo do servidor Fatorial-server.c.

6.3.4 Escrevendo o Cliente


Nosso cliente de teste obtm o ior do servidor atravs da linha de
comando e chama o mtodo fatorial para calcular o fatorial de
10 e mostr-lo na sada padro.
#include < orb / o r b i t . h>
#include " F a t o r i a l . h"
#include < s t d i o . h>
int

main ( int argc , char argv [ ] ) {


CORBA_Environment ev ;
CORBA_ORB
orb ;
CORBA_Object
server ;
gchar
dummy_argv [ 2 ] ;
gint
dummy_argc ;
int i ;
dummy_argc = 1 ;
dummy_argv [ 0 ] = argv [ 0 ] ;
dummy_argv [ 1 ] = 0 ;

CORBA_exception_init(&ev ) ;
orb = CORBA_ORB_init(&dummy_argc ,
dummy_argv , " o r b i t l o c a l orb " , & ev ) ;
s e r v e r = CORBA_ORB_string_to_object (
orb , argv [ 1 ] , & ev ) ;
p r i n t f ( "O f a t o r i a l de 1 0 e i g u a l a %d\n" ,
MinhaLib_Matematica_fatorial ( s e r v e r , 1 0 , & ev ) ) ;
CORBA_Object_release ( s e r v e r ,& ev ) ;
exit (0);

Exemplo 6.9 Cdigo do cliente Fatorial-client.c.

Tpicos Avanados

135

6.3.5 Compilando e Rodando o Exemplo


Para compilar todos os exemplo o arquivo Makefile abaixo pode
ser utilizado:
LIBS = ` o r b i t c o n f i g l i b s s e r v e r c l i e n t ` ggdb
CFLAGS= ` o r b i t c o n f i g c f l a g s s e r v e r c l i e n t ` \
` g l i b c o n f i g c f l a g s g l i b ` ggdb
LISTA_SERVER= F a t o r i a l common . o \
F a t o r i a l s k e l s . o \
F a t o r i a l s e r v e r . o
LISTA_CLIENTE= F a t o r i a l common . o \
F a t o r i a l s t u b s . o \
F a t o r i a l c l i e n t . o
a l l : ORBJava ORBC
ORBJava :

i d l j f a l l Fatorial . idl
j a v a c MinhaLib / . j a v a
javac . java

ORBC: c l i e n t s e r v e r
c l i e n t : codigo
g c c o c l i e n t $ ( LIBS ) $ (LISTA_CLIENTE)
server : codigo
g c c o s e r v e r $ ( LIBS ) $ (LISTA_SERVER)
codigo : i d l
g c c c $ (CFLAGS ) . c
idl : Fatorial . idl
o r b i t i d l F a t o r i a l . i d l
clean :

cd MinhaLib ; rm f . c l a s s ~
rm f . o ~ s e r v e r c l i e n t . c l a s s . i o r

Exemplo 6.10 arquivo Makele


Devemos lembrar, novamente, que a primeira execuo
do orbit-idl deve ser feita manualmente com o parmetro

136

Java na prtica

--skeleton-impl, como descrito na seo 6.3.1.


Para executar o servidor escrito em C devemos utilizar o comando:
./server > Matematica.ior
e para rodar o cliente, use o comando:

./client `cat Matematica.ior`


A interoperao entre objetos C e objetos Java pode ser obtida
substituindo o cliente e/ou o servidor pelo programas Java.

Captulo 7

Servlets e JSP
Servlets e JSP so duas tecnologias criadas pela Sun para desenvolvimento de aplicaes na Web a partir de componentes Java
que executem no lado servidor. Essas duas tecnologias fazem parte
da plataforma J2EE (Java 2 Enterprise Edition ) que fornece um
conjunto de tecnologias para o desenvolvimento de solues escalveis e robustas para a Web. Neste livro abordaremos apenas as
tecnologias Servlets e JSP, sendo o suciente para o desenvolvimento de sites dinmicos de razovel complexidade. Se a aplicao
exigir uma grande robustez e escalabilidade o leitor deve considerar o uso em conjunto de outras tecnologias da plataforma J2EE.

7.1 Servlets
Servlets so classes Java que so instanciadas e executadas em
associao com servidores Web, atendendo requisies realizadas
por meio do protocolo HTTP. Ao serem acionados, os objetos Servlets podem enviar a resposta na forma de uma pgina HTML ou
qualquer outro contedo MIME. Na verdade os Servlets podem
trabalhar com vrios tipos de servidores e no s servidores Web,
uma vez que a API dos Servlets no assume nada a respeito do
ambiente do servidor, sendo independente de protocolos e plataformas. Em outras palavras Servlets uma API para construo
137

138

Java na prtica

de componentes do lado servidor com o objetivo de fornecer um


padro para comunicao entre clientes e servidores. Os Servlets
so tipicamente usados no desenvolvimento de sites dinmicos.
Sites dinmicos so sites onde algumas de suas pginas so construdas no momento do atendimento de uma requisio HTTP.
Assim possvel criar pginas com contedo varivel, de acordo
com o usurio, tempo, ou informaes armazenadas em um banco
de dados.

Figura 7.1 Relacionamento entre Servlets, container e servidor


Web.

Servlets no possuem interface grca e suas instncias so


executadas dentro de um ambiente Java denominado de Container. O container gerencia as instncias dos Servlets e prov os
servios de rede necessrios para as requisies e respostas. O
container atua em associao com servidores Web recebendo as
requisies reencaminhada por eles. Tipicamente existe apenas
uma instncia de cada Servlet, no entanto, o container pode criar
vrios threads de modo a permitir que uma nica instncia Servlet atenda mais de uma requisio simultaneamente. A gura 7.1
fornece uma viso do relacionamento destes componentes.
Servlets provem uma soluo interessante para o relacionamento cliente/servidor na Internet, tornando-se uma alternativa
para a implantao de sistemas para a Web. Antes de entrarmos
em detalhes na construo de Servlets, compararemos esta soluo
com outras duas solues possveis para implantao de aplicaes
na Internet.

Tpicos Avanados

139

7.1.1 Applets X Servlets


Apesar de ser uma soluo robusta, existem problemas no uso
de Applets para validao de dados e envio para o servidor. O
programador precisa contar com o fato do usurio possuir um
navegador com suporte a Java e na verso apropriada. Voc no
pode contar com isso na Internet, principalmente se voc deseja
estender a um grande nmero de usurio o acesso s suas pginas.
Em se tratando de Servlets, no lado do cliente pode existir apenas
pginas HTML, evitando restries de acesso s pginas. Em
resumo, o uso de Applets no recomendado para ambientes com
diferentes navegadores ou quando a semntica da aplicao possa
ser expressa por componentes HTML.

7.1.2 CGI X Servlets


Como j comentado, scripts CGI (Common Gateway Interface),
acionam programas no servidor. O uso de CGI sobrecarrega o
servidor uma vez que cada requisio de servio acarreta a execuo de um programa executvel (que pode ser escrito em qualquer
linguagem que suporte o padro CGI) no servidor, alm disso,
todo o processamento realizado pelo CGI no servidor. Se houver algum erro na entrada de dados o CGI tem que produzir uma
pgina HTML explicando o problema. J os Servlets so carregados apenas uma vez e como so executados de forma multithread
podem atender mais de uma mesma solicitao simultaneamente.
Verses posteriores de CGI contornam este tipo de problema, mas
permanecem outros como a falta de portabilidade e a insegurana
na execuo de cdigo escrito em uma linguagem como C/C++.

7.2 A API Servlet


A API Servlet composta por um conjunto de interfaces e Classes.
O componente mais bsico da API a interface Servlet. Ela
dene o comportamento bsico de um Servlet. A gura 7.2 mostra
a interface Servlet.

140

Java na prtica

public interface S e r v l e t {
public void i n i t ( S e r v l e t C o n f i g c o n f i g )
throws S e r v l e t E x c e p t i o n ;
public S e r v l e t C o n f i g g e t S e r v l e t C o n f i g ( ) ;
public void s e r v i c e ( S e r v l e t R e q u e s t req ,
ServletResponse res )

throws S e r v l e t E x c e p t i o n , IOException ;
public S t r i n g g e t S e r v l e t I n f o ( ) ;
public void d e s t r o y ( ) ;

Figura 7.2 Interface Servlet.


O mtodo service() responsvel pelo tratamento de todas
as requisies dos clientes. J os mtodos init() e destroy()
so chamados quando o Servlet carregado e descarregado do
container, respectivamente. O mtodo getServletConfig() retorna um objeto ServletConfig que contm os parmetros de
inicializao do Servlet. O mtodo getServletInfo() retorna
um String contendo informaes sobre o Servlet, tais como verso e autor.
Tendo como base a interface Servlet o restante da API Servlet
se organiza hierarquicamente como mostra a gura 7.3.

Figura 7.3 Hierarquia de classes da API Servlet.


A classe GenericServlet implementa um servidor genrico e
geralmente no usada. A classe HttpServlet a mais utilizada

Tpicos Avanados

141

e foi especialmente projetada para lidar com o protocolo HTTP.


A gura 7.4 mostra a denio da classe abstrata HttpServlet.
HttpServlet

public abstract c l a s s H t t p S e r v l e t
extends G e n e r i c S e r v l e t
implements j a v a . i o . S e r i a l i z a b l e

Figura 7.4 Denio da classe HttpServlet.


Note que por ser a HttpServlet uma classe abstrata, para
se criar um Servlet que atenda requisies HTTP o programador
deve criar uma classe derivada da HttpServlet e sobrescrever pelo
menos um dos mtodos abaixo:

mtodo
doGet
doPost
doPut
doDelete

Descrio
Trata as requisies
Trata as requisies
Trata as requisies
Trata as requisies

HTTP
HTTP
HTTP
HTTP

GET.
POST.
PUT.
DELETE.

Tabela 7.1 Mtodos da classe HttpServlet que devem ser


sobrescritos para tratar requisies HTTP.

Todos esses mtodos so invocados pelo servidor por meio do


mtodo service(). O mtodo doGet() trata as requisies GET.
Este tipo de requisio pode ser colocada em um bookmark, possibilitando assim, o seu envio repetidas vezes. O mtodo doPost()
trata as requisies POST que permitem que o cliente envie dados
de tamanho ilimitado para o servidor Web uma nica vez, sendo
til para enviar informaes tais como o nmero do carto de crdito. O mtodo doPut() trata as requisies PUT. Este tipo de
requisio permite que o cliente envie um arquivo para o servidor
semelhana de como feito via FTP. O mtodo doDelete()
trata as requisies DELETE, permitindo que o cliente remova um
documento ou uma pgina do servidor. O mtodo service(), que
recebe todas as requisies, em geral no sobrescrito, sendo sua
tarefa direcionar a requisio para o mtodo adequado.

142

Java na prtica

7.2.1 Exemplo de Servlet


Para entendermos o que um Servlet nada melhor que um exemplo simples. O exemplo 7.1 gera uma pgina HTML em resposta
a uma requisio GET. A pgina HTML gerada contm simplesmente a frase Ola mundo!!!. Este um Servlet bem simples que
ilustra as funcionalidades bsicas da classe.
import j a v a x . s e r v l e t . ;
import j a v a x . s e r v l e t . h t t p . ;
public c l a s s Ola extends H t t p S e r v l e t

public S t r i n g g e t S e r v l e t I n f o ( )
{ return " Ola v e r s o 0 . 1 " ; }
public void doGet ( H t t p S e r v l e t R e q u e s t req ,

HttpServletResponse res )

throws IOException , S e r v l e t E x c e p t i o n
r e s . setContentType ( " t e x t / html " ) ;
j a v a . i o . P r i n t W r i t e r out = r e s . g e t W r i t e r ( ) ;
out . p r i n t l n ( "<html>" ) ;
out . p r i n t l n ( "<head>" ) ;
out . p r i n t l n ( "< t i t l e >S e r v l e t </ t i t l e >" ) ;
out . p r i n t l n ( "</head>" ) ;
out . p r i n t l n ( "<body>Ola mundo ! ! ! " ) ;
out . p r i n t l n ( "</body>" ) ;
out . p r i n t l n ( "</html>" ) ;
out . c l o s e ( ) ;

Exemplo 7.1 Servlet Ola.


O mtodo doGet() recebe dois objetos: um da classe
HttpServletRequest e outro da classe HttpServletResponse. O
HttpServletRequest responsvel pela comunicao do cliente
para o servidor e o HttpServletResponse responsvel pela comunicao do servidor para o cliente. Sendo o exemplo 7.1 apenas
um exemplo simples ele ignora o que foi enviado pelo cliente, tratando apenas de enviar uma pgina HTML como resposta. Para

Tpicos Avanados

143

isso utilizado o objeto da classe HttpServletResponse. Primeiramente usado o mtodo setContentType() para denir o
tipo do contedo a ser enviado ao cliente. Como argumento deve
ser passado um dos tipos denidos no protocolo MIME (Multipurpose Internet Mail Extensions ). Tipos MIME denem o tipo de
contedo que est sendo transmitido e so especicados na forma
tipo-principal/subtipo. Exemplos de tipos MIME so text/html,
application/pdf e image/gif. O mtodo setContentType()
deve ser usado apenas uma vez e antes de se obter um objeto
do tipo PrintWriter ou ServletOutputStream para a resposta.
Aps isso usado o mtodo getWriter() para se obter um objeto
do tipo PrintWriter que usado para escrever a resposta. Neste
caso os dados da resposta so baseados em caracteres. Se o programador desejar enviar a resposta em bytes deve usar o mtodo
getOutputStream() para obter um objeto OutputStream. A partir de ento o programa passa a usar o objeto PrintWriter para
enviar a pgina HTML.

7.3 Compilando o Servlet


A API Servlet no est incorporada ao SDK, portanto, para compilar um Servlet preciso adicionar um pacote ao classpath. Existem vrias formas de se fazer isso. A Sun fornece a especicao da API e diversos produtores de software executam a implementao. Atualmente, a especicao da API Servlet est
na verso 2.3. Uma das implementaes da API que pode ser
baixada gratuitamente pela Internet a fornecida pelo projeto
Jakarta (http://jakarta.apache.org) denominada de Tomcat.
A implementao da API Servlet feita pelo projeto Jakarta a
implementao de referncia indicada pela Sun. Ou seja, a implementao que os outros fabricantes devem seguir para garantir
a conformidade com a especicao da API.

7.3.1 Instalando o Tomcat


Assim como para se executar um Applet era preciso de um navegador Web com Java habilitado, no caso de Servlets preciso de

144

Java na prtica

servidor Web que execute Java ou que passe as requisies feitas


a Servlets para programas que executem os Servlets. O Tomcat
tanto a implementao da API Servlet como a implementao
de um container, que pode trabalhar em associao com um servidor Web como o Apache ou o IIS, ou pode tambm trabalhar
isoladamente, desempenhando tambm o papel de um servidor
Web. Nos exemplos aqui mostrados usaremos o Tomcat isoladamente. Em um ambiente de produo esta congurao no a
mais adequada, uma vez que os servidores Web possuem um melhor desempenho no despacho de pginas estticas. As instrues
para congurar o Tomcat para trabalhar em conjunto com um
servidor Web podem ser encontradas junto s instrues gerais do
programa. As guras 7.5 e 7.6 ilustram essas duas situaes.

Figura 7.5 Servidor Web habilitado para Servlet.

Figura 7.6 Servidor Web reencaminhando as requisies para o


Servlet container.

A verso estvel do Tomcat a 4.1 e, aps baix-la do site do


projeto Jakarta, o usurio deve executar as instrues de instalao. Por exemplo, no ambiente Windows o programa de instalao
gera a seguinte rvore de diretrios:

Tpicos Avanados

145

C:\...\Tomcat 4.1
|
|______bin
|______common
|______conf
|______logs
|______server
|______shared
|______temp
|______src
|______webapps
|______work

No diretrio bin encontram-se os programas para execuo e interrupo do container Tomcat. No diretrio common
encontram-se as bibliotecas e classes de uso comum. No diretrio conf encontram-se os arquivos de congurao. No diretrio logs so registradas as mensagens geradas durante a execuo do sistema. No diretrio server encontram-se as classes do
Tomcat e aplicaes para administrao do Tomcat. No diretrio
shared encontram-se as classes compartilhadas entre as aplicaes do Tomcat. O diretrio temp usado pela mquina virtual
para armazenamento temporrio. No diretrio src encontram-se
os arquivos fontes do container e da implementao da API de
congurao. Finalmente, no diretrio webapps encontram-se as
pginas e cdigos das aplicaes dos usurios. O diretrio work
usado pelo Tomcat para armazenar as classes resultantes da compilao dos Servlets.
Antes de executar o Tomcat necessrio denir a varivel de
ambiente CATALINA_HOME com o valor do diretrio onde foi instalado o Tomcat. Por exemplo, supondo que no Linux o Tomcat foi
instalado no diretrio /usr/jakarta-tomcat-4.1.24-LE-jdk14
ento os seguintes comandos devem ser colocados no arquivo de
inicializao apropriado:
CATALINA_HOME=/usr/jakarta-tomcat-4.1.24-LE-jdk14
export CATALINA_HOME

146

Java na prtica

Aps denir a varivel de ambiente CATALINA_HOME pode-se


executar o Tomcat por meio do seguinte comando1 :
%CATALINA_HOME%\bin\startup

(Windows)

$CATALINA_HOME/bin/startup.sh

(Unix)

Para interromper a execuo servidor basta executar o comando:


%CATALINA_HOME%\bin\shutdown

(Windows)

$CATALINA_HOME/bin/shutdown.sh

(Unix)

No ambiente MS-Windows o instalador do Tomcat adiciona


atalhos para iniciar e nalizar o Tomcat a partir do menu de
programas.
Ao entrar em execuo o servidor l as conguraes constantes no arquivo server.xml e, por default, se conecta porta
8080. Para vericar se o programa est funcionando corretamente
execute um navegador como o Netscape ou o Internet Explorer e
digite a seguinte URL:

http://127.0.0.1:8080/
ou

http://localhost:8080/
A gura 7.7 mostra a tela principal do Tomcat.
1 Caso ao iniciar o servidor no MS-Windos aparea a mensagem sem
espao de ambiente clique com o boto direito do mouse no arquivo .bat e
edite as propriedades denindo o ambiente inicial com 4096 bytes de memria.
Feche o arquivo e execute novamente.

Tpicos Avanados

147

Figura 7.7 Tela inicial do Tomcat.


O nmero da porta default para recebimento das requisies HTTP pode ser alterado por meio da edio do arquivo
server.xml do diretrio conf como mostrado abaixo:
<!-- Define a non-SSL Coyote HTTP/1.1 Connector on port 8081 -->
<Connector className="org.apache.coyote.tomcat4.CoyoteConnector"
port="8080" minProcessors="5" maxProcessors="75"
enableLookups="true" redirectPort="8443"
acceptCount="10" debug="0" connectionTimeout="20000"
useURIValidationHack="false" />

Figura 7.8 Trecho do arquivo server.xml relacionado com a


porta de conexo.

No entanto, caso o Tomcat esteja operando em conjunto com


um servidor HTML, o ideal que ele no responda requisies
diretamente.

148

Java na prtica

7.4 Preparando para executar o Servlet


7.4.1 Compilando o Servlet
Antes de executar o Servlet e preciso compil-lo. Para compil-lo
preciso que as classes que implementam a API Servlet estejam
no classpath. Isto feito da seguinte forma no ambiente MSWindows:
set CLASSPATH=%CLASSPATH%;%TOMCAT_HOME%\common\lib\servlet.jar

e no ambiente Unix seria


export CLASSPATH=$CLASSPATH:${TOMCAT_HOME}/common/lib/servlet.jar

Alternativamente, possvel indicar o classpath na prpria linha de execuo do compilador Java. Por exemplo, no ambiente
MS-Windows caria na seguinte forma:
javac -cp %CLASSPATH%;%TOMCAT_HOME%\common\lib\servlet.jar Ola.java

7.4.2 Criando uma aplicao no Tomcat


Agora preciso denir onde deve ser colocado o arquivo compilado. Para isso preciso criar uma aplicao no Tomcat ou usar
uma das aplicaes j existentes. Vamos aprender como criar uma
aplicao no Tomcat. Primeiramente preciso criar a seguinte estrutura de diretrios abaixo do diretrio webapps do Tomcat:
webapps
|_____ Nome da aplicao
|_____ WEB-INF
|_____classes

O diretrio de uma aplicao2 denominado de contexto da


aplicao.
Copie o arquivo compilado Ola.class para o subdiretrio
/webapps/nome aplicao/Web-inf/classes do Tomcat. preciso tambm editar um arquivo web.xml que deve ser colocado no
diretrio WEB-INF da aplicao com o seguinte contedo:
2 Na verdade possvel denir outro diretrio para colocar as aplicaes do
Tomcat. Para indicar outro diretrio preciso editar o arquivo server.xml e
indicar o diretrio por meio do tag Context path.

Tpicos Avanados

149

<?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>Teste</display-name>
<description> Primeiro teste </description>
<servlet>
<servlet-name>ola</servlet-name>
<servlet-class>Ola</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ola</servlet-name>
<url-pattern>/ola</url-pattern>
</servlet-mapping>
</web-app>

Figura 7.9 Exemplo do arquivo web.xml.


O tag servlet usado para descrever cada Servlet da aplicao. O subtag servlet-name usado para associar um nome ao
Servlet e o subtag servlet-class associa o nome classe que implementa o Servlet. O tag servlet-mapping usado denir quais
URLs sero mapeadas para Servlets. O subtag servlet-name
usado para denir que Servlet ser mapeado e o subtag
url-pattern dene o padro da URL. No caso da gura 7.9 uma
URL na forma http://<servidor >/<contexto >/ola ser mapeado para o Servlet. A elaborao do arquivo web.xml pode ser
bastante complexa. Os detalhes fornecidos aqui so sucientes
apenas para executar os exemplos. Maiores detalhes devem ser
obtidos na prpria documentao que acompanha o Tomcat.

7.5 Executando o Servlet


7.5.1 Invocando diretamente pelo Navegador
Podemos executar um Servlet diretamente digitando a URL do
Servlet no navegador. A URL em geral possui o seguinte formato:
http://<servidor >/<contexto >/<mapeamento >

150

Java na prtica

Por exemplo, suponha que o nome da aplicao criada no Tomcat seja teste e que o Tomcat esteja rodando no computador local. Ento a URL para a invocao do Servlet do exemplo 7.1
teria a seguinte forma:
http://mquina :porta /contexto da aplicao /nome servlet

Por exemplo,

http://localhost:8080/teste/ola

7.5.2 Invocando em uma pgina HTML


No caso de uma pgina HTML basta colocar a URL na forma de
link. Por exemplo,
<a href="http://localhost:8080/teste/ola>Servlet Ola</a>

Neste caso o Servlet Ola ser solicitado quando o link associado


ao texto Servlet Ola for acionado. Se o arquivo HTML pertencer
ao mesmo contexto do Servlet, ento basta denir um link como
mostrado a seguir:

<a href="ola">Servlet Ola</a>


Por exemplo, o Servlet do exemplo 7.1 pode ser acessado por
meio do seguinte arquivo HTML colocado no subdiretrio teste:
<HTML>
<BODY>
<a href="ola">Servlet Ola</a>
</BODY>
</HTML>

Figura 7.10 Arquivo html para acessar o Servlet Ola.

7.5.3 Diferenas entre as requisies GET e


POST
Os dois mtodos mais comuns, denidos pelo protocolo HTTP,
de se enviar uma requisio a um servidor Web so os mtodos

Tpicos Avanados

151

POST e GET. Apesar de aparentemente cumprirem a mesma funo, existem diferenas importantes entre estes dois mtodos. O
mtodo GET tem por objetivo enviar uma requisio por um recurso. As informaes necessrias para a obteno do recurso
(como informaes digitadas em formulrios HTML) so adicionadas URL e, por consequncia, no so permitidos caracteres
invlidos na formao de URLs, como espaos em branco e caracteres especiais. J na requisio POST os dados so enviados no
corpo da mensagem.
O mtodo GET possui a vantagem de ser idempotente, ou seja,
os servidores Web podem assumir que a requisio pode ser repetida, sendo possvel adicionar a URL ao bookmark. Isto muito
til quando o usurio deseja manter a URL resultante de uma
pesquisa. Como desvantagem as informaes passadas via GET
no podem ser muito longas, um vez que o nmero de caracteres
permitidos por volta de 2K.
J as requisies POST, a princpio, podem ter tamanho ilimitado. No entanto, elas no so idempotente, o que as tornam
ideais para formulrios onde os usurios precisam digitar informaes condenciais, como nmero de carto de crdito. Desta
forma o usurio obrigado a digitar a informao toda vez que
for enviar a requisio, no sendo possvel registrar a requisio
em um bookmark.

7.6 Concorrncia
Uma vez carregado o Servlet no mais descarregado, a no ser
que o servidor Web tenha sua execuo interrompida. De modo
geral, cada requisio que deve ser direcionada a uma determinada instncia de Servlet tratada por um thread sobre a instncia de Servlet. Isto signica que se existirem duas requisies
simultneas que devem ser direcionadas para um mesmo objeto o
container criar dois threads sobre o mesmo objeto Servlet para
tratar as requisies. A gura 7.11 ilustra esta situao.

152

Java na prtica

Figura 7.11 Relacionamento entre as instncias dos Servlets e


os threads.

Em conseqncia disto temos os benefcios de uma sobrecarga


menor para servidor, uma vez que a criao de threads menos
onerosa do que a criao de processos, e uma aparente melhora
no tempo de resposta.
Por outro lado, o fato dos Servlets operarem em modo multithread aumenta a complexidade das aplicaes e cuidados especiais,
como visto no captulo sobre concorrncia, devem tomados para
evitar comportamentos errticos. Por exemplo, suponha um Servlet que receba um conjunto de nmeros inteiros e retorne uma
pgina contendo a soma dos nmeros. O exemplo 7.2 mostra o
cdigo do Servlet. O leitor pode imaginar um cdigo muito mais
eciente para computar a soma de nmeros, mas o objetivo do cdigo do exemplo ilustrar o problema da concorrncia em Servlets.
O exemplo contm tambm um trecho de cdigo para recebimento
de valores de formulrios, o que ser discutido mais adiante.
import j a v a . u t i l . ;
import j a v a x . s e r v l e t . ;
import j a v a x . s e r v l e t . h t t p . ;
public c l a s s Soma extends H t t p S e r v l e t {
Vector v = new Vector ( 5 ) ;
protected void doPost ( H t t p S e r v l e t R e q u e s t req ,

HttpServletResponse res )

throws S e r v l e t E x c e p t i o n , j a v a . i o . IOException {

Tpicos Avanados

153

v. clear ();
Enumeration e = r e q . getParameterNames ( ) ;

while ( e . hasMoreElements ( ) ) {

S t r i n g name = ( S t r i n g ) e . nextElement ( ) ;
S t r i n g v a l u e = r e q . getParameter ( name ) ;
i f ( v a l u e ! = null ) v . add ( v a l u e ) ;

r e s . setContentType ( " t e x t / html " ) ;


j a v a . i o . P r i n t W r i t e r out = r e s . g e t W r i t e r ( ) ;
out . p r i n t l n ( "<html>" ) ;
out . p r i n t l n (
"<head><t i t l e >S e r v l e t </ t i t l e ></head>" ) ;
out . p r i n t l n ( "<body>" ) ;
out . p r i n t l n ( "<h1 > A soma e ' " ) ;
int soma = 0 ;
for ( int i = 0 ; i < v . s i z e ( ) ; i ++) {
soma += I n t e g e r . p a r s e I n t ( ( S t r i n g ) v . g e t ( i ) ) ;
}
out . p r i n t l n ( soma ) ;
out . p r i n t l n ( "<h1>" ) ;
out . p r i n t l n ( "</body>" ) ;
out . p r i n t l n ( "</html>" ) ;
out . c l o s e ( ) ;

Exemplo 7.2 Servlet com problemas de concorrncia.


Note que o Servlet utiliza uma varivel de instncia para referenciar o Vector que armazena os valores. Se no forem usadas
primitivas de sincronizao (como no cdigo do exemplo) e se duas
requisies chegarem simultaneamente ao Servlet o resultado pode
ser inconsistente, uma vez que o Vector poder conter parte dos
valores de uma requisio e parte dos valores de outra requisio.
Neste caso em particular, para corrigir esse problema basta declarar a varivel como local ao mtodo doPost() ou usar primitivas
de sincronizao.

154

Java na prtica

7.7 Obtendo Informaes sobre a Requisio


O objeto HttpServletRequest passado para o Servlet contm vrias informaes importantes relacionadas com a requisio, como
por exemplo o mtodo empregado (POST ou GET), o protocolo
utilizado, o endereo remoto, informaes contidas no cabealho
e muitas outras. O Servlet do exemplo 7.3 retorna uma pgina
contendo informaes sobre a requisio e sobre o cabealho da
requisio.
import
import
import
import

java . io . ;
java . u t i l . ;
javax . s e r v l e t . ;
javax . s e r v l e t . http . ;

public c l a s s R e q u e s t I n f o extends H t t p S e r v l e t

public void doGet ( H t t p S e r v l e t R e q u e s t req ,

HttpServletResponse res )

throws IOException , S e r v l e t E x c e p t i o n
r e s . setContentType ( " t e x t / html " ) ;
P r i n t W r i t e r out = r e s . g e t W r i t e r ( ) ;
out . p r i n t l n ( "<html><head>" ) ;
out . p r i n t l n (
"< t i t l e >Exemplo de R e q u i s i c a o de I n f o </ t i t l e >" ) ;
out . p r i n t l n ( "</head><body>" ) ;
out . p r i n t l n (
"<h3 > Exemplo s o b r e R e q u i s i c a o de I n f o </h3>" ) ;
out . p r i n t l n ( "Metodo : " + r e q . getMethod ()+ "<br>" ) ;
out . p r i n t l n (
" Request URI : " + r e q . getRequestURI ()+ "<br>" ) ;
out . p r i n t l n (
" P r o t o c o l o : " + r e q . g e t P r o t o c o l ()+ "<br>" ) ;
out . p r i n t l n (
" P a t h I n f o : " + r e q . g e t P a t h I n f o ()+ "<br>" ) ;
out . p r i n t l n ( " Endereco remoto : "+r e q . getRemoteAddr ()+
"<br><br>" ) ;
Enumeration e = r e q . getHeaderNames ( ) ;
while ( e . hasMoreElements ( ) )
{
S t r i n g name = ( S t r i n g ) e . nextElement ( ) ;
S t r i n g v a l u e = r e q . getHeader ( name ) ;

Tpicos Avanados

155

out . p r i n t l n ( name + " = " + v a l u e+"<br>" ) ;


}
out . p r i n t l n ( "</body></html>" ) ;

public void doPost ( H t t p S e r v l e t R e q u e s t req ,

HttpServletResponse res )

{
}

throws IOException , S e r v l e t E x c e p t i o n
doGet ( req , r e s ) ;

Exemplo 7.3 Servlet que retorna as informaes sobre a


requisio.

Note que o mtodo doPost() chama o mtodo doGet(), de


modo que o Servlet pode receber os dois tipos de requisio. A
gura 7.12 mostra o resultado de uma execuo do Servlet do
exemplo 7.3.

Exemplo sobre Requisicao de Info


Metodo: GET
Request URI: /teste/req
Protocolo: HTTP/1.1
PathInfo: null
Endereco remoto: 127.0.0.1

accept =image/gif,image/x-xbitmap, image/jpeg, image/pjpeg,


application/vnd.ms-excel, application/msword,
application/vnd.ms-powerpoint, */*
accept-language = pt-br
accept-encoding = gzip, deflate
user-agent =Mozilla/4.0(compatible;MSIE 5.0;Windows 98;DigExt)
host = localhost:8080
connection = Keep-Alive
cookie = JSESSIONID=B536655B2CD30258F11011808C3C6205

Figura 7.12 Sada da execuo do Servlet que exibe as


informaes sobre a requisio.

156

Java na prtica

7.8 Lidando com Formulrios


Ser capaz de lidar com as informaes contidas em formulrios
HTML fundamental para qualquer tecnologia de desenvolvimento de aplicaes para Web. por meio de formulrios que os
usurios fornecem dados, preenchem pedidos de compra e (ainda
mais importante) digitam o nmero do carto de crdito. As informaes digitadas no formulrio chegam at o Servlet por meio
do objeto HttpServletRequest e so recuperadas por meio do
mtodo getParameter() deste objeto. Todo item de formulrio
HTML possui um nome e esse nome passado como argumento
para o mtodo getParameter() que retorna, na forma de String,
o valor do item de formulrio.
O Servlet do exemplo 7.4 exibe o valor de dois itens de formulrios do tipo text. Um denominado nome e o outro denominado
de sobrenome. Em seguida o Servlet cria um formulrio contendo
os mesmos itens de formulrio. Note que um formulrio criado
por meio do tag <form>. Como parmetros opcionais deste tag
temos o mtodo da requisio (method), a URL para onde ser
submetida a requisio (action). No caso do exemplo, o mtodo
adotado o POST e a requisio ser submetida ao prprio Servlet
Form.
import
import
import
import

java . io . ;
java . u t i l . ;
javax . s e r v l e t . ;
javax . s e r v l e t . http . ;

public c l a s s Form extends H t t p S e r v l e t

public void doGet ( H t t p S e r v l e t R e q u e s t req ,


HttpServletResponse res )

throws IOException , S e r v l e t E x c e p t i o n
r e s . setContentType ( " t e x t / html " ) ;
P r i n t W r i t e r out = r e s . g e t W r i t e r ( ) ;
out . p r i n t l n ( "<html>" ) ;
out . p r i n t l n (
"<head><t i t l e >Trata f o r m u l a r i o </ t i t l e ></head>" ) ;
out . p r i n t l n ( "<body b g c o l o r =\" w h i t e \">" ) ;

Tpicos Avanados

157

out . p r i n t l n ( "<h3>Trata f o r m u l a r i o </h3>" ) ;


S t r i n g nome = r e q . getParameter ( "nome" ) ;
S t r i n g sobreNome = r e q . getParameter ( " sobrenome " ) ;
i f ( nome ! = null | | sobreNome ! = null )
{
out . p r i n t l n ( "Nome = " + nome + "<br>" ) ;
out . p r i n t l n ( " Sobrenome = " + sobreNome ) ;
}
out . p r i n t l n ( "<P>" ) ;
out . p r i n t ( "<form a c t i o n =\"Form \ " method=POST>" ) ;
out . p r i n t l n (
"Nome : < i n p u t type=t e x t s i z e =20 name=nome><br>" ) ;
out . p r i n t l n ( " Sobrenome : "+
"<i n p u t type=t e x t s i z e =20 name=sobrenome>" ) ;
out . p r i n t l n ( "<br><i n p u t type=submit>" ) ;
out . p r i n t l n ( "</form>" ) ;
out . p r i n t l n ( "</body></html>" ) ;

public void doPost ( H t t p S e r v l e t R e q u e s t req ,


HttpServletResponse res )

{
}

throws IOException , S e r v l e t E x c e p t i o n
doGet ( req , r e s ) ;

Exemplo 7.4 Servlet para lidar com um formulrio simples.

7.9 Lidando com Cookies


Um cookie nada mais que um bloco de informao que enviado
do servidor para o navegador no header pgina. A partir de ento,
dependendo do tempo de validade do cookie, o navegador reenvia
essa informao para o servidor a cada nova requisio. Dependo
do caso o cookie tambm armazenado no disco da mquina cliente e quando o site novamente visitado o cookie enviado novamente para o servidor, fornecendo a informao desejada.
Os cookies foram a soluo adotada pelos desenvolvedores do
Netscape para implementar a identicao de clientes no protocolo HTTP, que no orientado conexo. Esta soluo, apesar

158

Java na prtica

das controvrsias sobre a possibilidade de quebra de privacidade,


passou ser amplamente adotada e hoje os cookies so parte integrante do padro Internet, normalizados pela norma RFC 2109.
A necessidade da identicao do cliente de onde partiu a requisio e o monitoramento de sua interao com o site (denominada de sesso) importante para o desenvolvimento de sistemas
para a Web pelas seguintes razes:

necessrio associar os itens selecionados para compra com


o usurio que deseja adquir-los. Na maioria da vezes a seleo dos itens de uma compra feita por meio da navegao
de vrias pginas do site e a todo instante necessrio distinguir os usurios que esto realizando as requisies.
necessrio acompanhar as interao do usurio com o site
para observar seu comportamento e, a partir dessas informaes, realizar adaptaes no site para atrair um maior
nmero de usurios ou realizar campanhas de marketing.
necessrio saber que usurio est acessando o site para,
de acordo com o seu perl, fornecer uma visualizao e um
conjunto de funcionalidades adequadas s suas preferncias.
Todas essas necessidades no podem ser atendidas com o uso
bsico do protocolo HTTP, uma vez que ele no orientado
sesso ou conexo. Com os cookies possvel contornar essa decincia, uma vez que podem ser usados para identicar os clientes
e armazenar informaes. Existem outras formas de contornar a
decincia do protocolo de HTTP, como a codicao de URL e o
uso de campos escondidos nas pginas HTML, mas o uso de cookies a tcnica mais utilizada, por ser mais simples e padronizada.
No entanto, o usurio pode impedir que o navegador aceite cookies, o que torna o ato de navegar pela Web muito desagradvel.
Neste caso, necessrio utilizar as outras tcnicas para controle
de sesso.
A API Servlet permite a manipulao explcita de cookies.
Para controle de sesso o programador pode manipular diretamente os cookies, ou usar uma abstrao de nvel mais alto, implementada por meio da classe HttpSession. Se o cliente no

Tpicos Avanados

159

permitir o uso de cookies a API Servlet fornece mtodos para a


codicao de URL. O exemplo 7.5 mostra o uso de cookies para
armazenar as informaes digitadas em um formulrio.
import j a v a . i o . ;
import j a v a x . s e r v l e t . ;
import j a v a x . s e r v l e t . h t t p . ;
public c l a s s C o o k i e T e s t e extends H t t p S e r v l e t

public void doGet ( H t t p S e r v l e t R e q u e s t req ,


HttpServletResponse res )

throws IOException , S e r v l e t E x c e p t i o n
r e s . setContentType ( " t e x t / html " ) ;
P r i n t W r i t e r out = r e s . g e t W r i t e r ( ) ;
out . p r i n t l n ( "<html>" ) ;
out . p r i n t l n ( "<body b g c o l o r =\" w h i t e \">" ) ;
out . p r i n t l n ( "<head><t i t l e >T e s t e de C o o k i e s " ) ;
out . p r i n t l n ( "</ t i t l e ></head><body>" ) ;
out . p r i n t l n ( "<h3>T e s t e de Cookies </h3>" ) ;
Cookie [ ] c o o k i e s = r e q . g e t C o o k i e s ( ) ;
i f ( c o o k i e s . l e n g t h > 0)
{
for ( int i = 0 ; i < c o o k i e s . l e n g t h ; i ++)
{
Cookie c o o k i e = c o o k i e s [ i ] ;
out . p r i n t ( " Cookie Nome : " +
c o o k i e . getName ( ) + "<br>" ) ;
out . p r i n t l n ( " Cookie Valor : " +
c o o k i e . g e t V a l u e ( ) + "<br><br>" ) ;
}
}
S t r i n g cName = r e q . getParameter ( " cookienome " ) ;
S t r i n g c V a l o r = r e q . getParameter ( " c o o k i e v a l o r " ) ;
i f ( cName ! = null && c V a l o r ! = null )
{
Cookie c o o k i e = new Cookie ( cName , c V a l o r ) ;
r e s . addCookie ( c o o k i e ) ;
out . p r i n t l n ( "<P>" ) ;
out . p r i n t l n ( "<br>" ) ;
out . p r i n t ( "Nome : "+cName +"<br>" ) ;

160

Java na prtica

out . p r i n t ( " Valor : "+c V a l o r ) ;

out . p r i n t l n ( "<P>" ) ;
out . p r i n t (
"<form a c t i o n =\" C o o k i e T e s t e \ " method=POST>" ) ;
out . p r i n t l n ( "Nome : "+
"<i n p u t type=t e x t l e n g t h =20 name=cookienome>" ) ;
out . p r i n t l n ( "<br>Valor : "+
"<i n p u t type=t e x t l e n g t h =20 name=c o o k i e v a l o r >" ) ;
out . p r i n t l n ( "<br><i n p u t type=submit></form>" ) ;
out . p r i n t l n ( "</body>" ) ;
out . p r i n t l n ( "</html>" ) ;

public void doPost ( H t t p S e r v l e t R e q u e s t req ,


HttpServletResponse res )

{
}

throws IOException , S e r v l e t E x c e p t i o n
doGet ( req , r e s ) ;

Exemplo 7.5 Servlet para lidar com Cookies.


Para se criar um cookie necessrio criar um objeto Cookie,
passando para o construtor um nome e um valor, sendo ambos
instncias de String. O cookie enviado para o navegador por
meio do mtodo addCookie() do objeto HttpServletResponse.
Um vez que os cookies so enviados no header da pgina, o mtodo addCookie() deve ser chamado antes do envio de qualquer contedo para o navegador. Para recuperar os cookies enviados pelo navegador usa-se o mtodo getCookies() do objeto
HttpServletRequest que retorna um array de Cookie. Os mtodos getName() e getvalue() do objeto Cookie so utilizados
para recuperar o nome o valor da informao associada ao cookie.
Os objetos da classe Cookie possuem vrios mtodos para controle do uso de cookies. possvel denir o tempo de vida mximo
do cookie, os domnios que devem receber o cookie (por default o
domnio que deve receber o cookie o que o criou), o diretrio
da pgina que deve receber o cookie, se o cookie deve ser enviado somente sob um protocolo seguro, etc. Por exemplo, para

Tpicos Avanados

161

denir a idade mxima de um cookie devemos utilizar o mtodo


setMaxAge(), passando um inteiro como parmetro. Se o inteiro
for positivo indicar em segundos o tempo mximo de vida do cookie. Um valor negativo indica que o cookie deve apagado quando
o navegador terminar. O valor zero indica que o cookie deve ser
apagado imediatamente. O trecho de cdigo do exemplo 7.6 mostra algumas alteraes no comportamento default de um cookie.
...
Cookie c o o k i e = new Cookie ( cName , c V a l o r ) ;
// t o d o s os domnios como d p i . u f v . b r mas no
// como . d p i . u f v . br
c o o k i e . setDomain ( " . u v f . br " ) ;

// uma hora de tempo de v i d a


c o o k i e . setMaxAge ( 3 6 0 0 ) ;
...

Exemplo 7.6 Mudanas no comportamento default do cookie.

7.10 Lidando com Sesses


A manipulao direta de cookies para controle de sesso um
tanto trabalhosa, uma vez que o usurio deve se preocupar com
a identicao, tempo de vida e outros detalhes. Por isso a API
Servlet fornece um objeto com controles de nvel mais alto para
monitorar a sesso, o HttpSession. O objeto HttpSession monitora a sesso utilizando cookies de forma transparente. No entanto, se o cliente no aceitar o uso de cookies possvel utilizar
como alternativa a codicao de URL para adicionar o identicador da sesso. Essa opo, apesar de ser mais genrica, no
primeira opo devido a possibilidade de criao de gargalos pela
necessidade da anlise prvia de todas requisies que chegam ao
servidor. O exemplo 7.7 mostra o uso de um objeto HttpSession
para armazenar as informaes digitadas em um formulrio.
import j a v a . i o . ;
import j a v a . u t i l . ;

162

Java na prtica

import j a v a x . s e r v l e t . ;
import j a v a x . s e r v l e t . h t t p . ;
public c l a s s S e s s i o n T e s t e extends H t t p S e r v l e t

public void doGet ( H t t p S e r v l e t R e q u e s t req ,


HttpServletResponse resp )

throws IOException , S e r v l e t E x c e p t i o n
r e s p . setContentType ( " t e x t / html " ) ;
P r i n t W r i t e r out = r e s p . g e t W r i t e r ( ) ;
out . p r i n t l n ( "<html><head>" ) ;
out . p r i n t l n ( "< t i t l e >T e s t e de S e s s a o </ t i t l e >" ) ;
out . p r i n t l n ( "</head>" ) ;
out . p r i n t l n ( "<body>" ) ;
out . p r i n t l n ( "<h3>T e s t e de S e s s a o </h3>" ) ;
H t t p S e s s i o n s e s s i o n = r e q . g e t S e s s i o n ( true ) ;
out . p r i n t l n ( " I d e n t i f i c a d o r : " + s e s s i o n . g e t I d ( ) ) ;
out . p r i n t l n ( "<br>" ) ;
out . p r i n t l n ( "Data : " ) ;
out . p r i n t l n ( new Date ( s e s s i o n . g e t C r e a t i o nT i m e ())+
"<br>" ) ;
out . p r i n t l n ( " Ultimo a c e s s o : " ) ;
out . p r i n t l n (
new Date ( s e s s i o n . g e tL a s tA c c es s e dT i m e ( ) ) ) ;
S t r i n g nomedado = r e q . getParameter ( "nomedado" ) ;
S t r i n g v a l o r d a d o = r e q . getParameter ( " v a l o r d a d o " ) ;
i f ( nomedado ! = null && v a l o r d a d o ! = null )
{
s e s s i o n . s e t A t t r i b u t e ( nomedado , v a l o r d a d o ) ;
}
out . p r i n t l n ( "<P>" ) ;
out . p r i n t l n ( "Dados da S e s s a o : " + "<br>" ) ;
Enumeration valueNames =
s e s s i o n . ge t At tr i bu t eN am e s ( ) ;

while ( valueNames . hasMoreElements ( ) )

S t r i n g name = ( S t r i n g ) valueNames . nextElement ( ) ;


String value = ( String )
s e s s i o n . g e t A t t r i b u t e ( name ) ;
out . p r i n t l n ( name + " = " + v a l u e+"<br>" ) ;

Tpicos Avanados

163

out . p r i n t l n ( "<P>" ) ;
out . p r i n t (
"<form a c t i o n =\" S e s s i o n T e s t e \ " method=POST>" ) ;
out . p r i n t l n (
"Nome:< i n p u t type=t e x t s i z e =20 name=nomedado>" ) ;
out . p r i n t l n ( "<br>Valor : "+
"<i n p u t type=t e x t s i z e =20 name=valordado >" ) ;
out . p r i n t l n ( "<br><i n p u t type=submit>" ) ;
out . p r i n t l n ( "</form>" ) ;
out . p r i n t l n ( "</body></html>" ) ;

public void doPost ( H t t p S e r v l e t R e q u e s t req ,


HttpServletResponse resp )

{
}

throws IOException , S e r v l e t E x c e p t i o n
doGet ( req , r e s p ) ;

Exemplo 7.7 Servlet para lidar com Sesses.


Para controlar a sesso necessrio obter um objeto
HttpSession por meio do mtodo getSession() do objeto
HttpServletRequest. Opcionalmente, o mtodo getSession()
recebe como argumento um valor booleano que indica se para
criar o objeto HttpSession,caso ele no exista (argumento true)
ou se para retorna null (argumento false). Para se associar um
objeto ou informao sesso usa-se o mtodo setAttribute()
do objeto HttpSession, passando para o mtodo um String e
um objeto que ser identicado pelo String. Note que o mtodo
aceita qualquer objeto e, portanto, qualquer objeto pode ser associado sesso. Os objetos associados a uma sesso so recuperados com o uso mtodo getAttribute() do objeto HttpSession,
que recebe como argumento o nome associado ao objeto. Para
se obter uma enumerao do nomes associados sesso usa-se
o mtodo getAttributeNames() do objeto HttpSession. A gura 7.13 mostra o resultado da execuo do exemplo 7.7.

164

Java na prtica

Figura 7.13 Sada resultante da execuo do Servlet que lida


com Sesses.

7.11 JSP
Servlets uma boa idia, mas voc se imaginou montando uma
pgina complexa usando println()? Muitas vezes o desenvolvimento de um site uma tarefa complexa que envolve vrios
prossionais. A tarefa de projeto do layout da pgina ca a cargo
do Web Designer, incluindo a diagramao dos textos e imagens,
aplicao de cores, tratamento das imagens, denio da estrutura
da informao apresentada no site e dos links para navegao pela
mesma. J o Desenvolvedor Web responsvel pela criao das
aplicaes que vo executar em um site. O trabalho destes dois
prossionais somado na criao de um nico produto, mas durante o desenvolvimento a interferncia mtua deve ser a mnima
possvel. Ou seja, um prossional no deve precisar alterar o que
foi feito pelo outro prossional para cumprir sua tarefa. A tecnologia Servlet no nos permite atingir esse objetivo. Por exemplo,
suponha que um Web Designer terminou o desenvolvimento de
uma pgina e a entregou para o Desenvolvedor Web codicar em
um Servlet. Se aps a codicao o Web Designer desejar realizar
uma alterao na pgina ser necessrio que ele altere o cdigo do
Servlet (do qual ele nada entende) ou entregar uma nova pgina
para o Desenvolvedor Web para que ele a codique totalmente,

Tpicos Avanados

165

mais uma vez. Qualquer uma dessas alternativas indesejvel e


foi devido a esse problema a que Sun desenvolveu uma tecnologia
baseada em Servlets chamada de JSP.

Java Server Pages (JSP) so pginas HTML que incluem cdigo Java e outros tags especiais. Desta forma as partes estticas
da pgina no precisam ser geradas por println(). Elas se encontram na prpria pgina. A parte dinmica gerada pelo cdigo
JSP. Assim a parte esttica da pgina pode ser projetada por um
Web Designer que nada sabe de Java.
A primeira vez que uma pgina JSP carregada pelo container JSP o cdigo Java compilado gerando um Servlet que
executado, gerando uma pgina HTML que enviada para o
navegador. As chamadas subsequentes so enviadas diretamente
ao Servlet gerado na primeira requisio, no ocorrendo mais as
etapas de gerao e compilao do Servlet.
A gura 7.14 mostra um esquema das etapas de execuo de
uma pgina JSP na primeira vez que requisitada. Na etapa (1)
a requisio enviada para um servidor Web que reencaminha a
requisio (etapa 2) para o container Servlet/JSP. Na etapa (3)
o container verica que no existe nenhuma instncia de Servlet
correspondente pgina JSP. Neste caso, a pgina JSP traduzida
para cdigo fonte de uma classe Servlet que ser usada na resposta
requisio. Na etapa (4) o cdigo fonte do Servlet compilado,
e na etapa (5) criada uma instncia da classe. Finalmente, na
etapa (6) invocado o mtodo service() da instncia Servlet
para gerar a resposta requisio.
A idia de se usar scripts de linguagens de programao em pginas HTML que so processados no lado servidor para gerar contedo dinmico no restrita linguagem Java. Existem vrias
solues desse tipo fornecida por outros fabricantes. Apresentase, a seguir, comparaes com outras duas tecnologias similares a
JSP.

166

Java na prtica

Figura 7.14 Etapas da primeira execuo de uma pgina JSP.

7.11.1 PHP X JSP


PHP (Personal Home Pages ) uma linguagem script para ser executada no lado servidor criada em 1994 como um projeto pessoal
de Rasmus Lerdorf. A sintaxe fortemente baseada em C mas
possui elementos de C++, Java e Perl. Possui suporte a programao OO por meio de classes e objetos. Possui tambm suporte
extensivo Banco de dados ODBC, MySql, Sybase, Oracle e outros. PHP uma linguagem mais fcil no desenvolvimento de pequenas aplicaes para Web em relao JSP, uma vez que uma
linguagem mais simples e menos rgida do que JSP. No entanto,
a medida que passamos para aplicaes de maior porte, o uso de
PHP no indicado, uma vez que necessrio o uso de linguagens
com checagem mais rgidas e com maior suporte escalabilidade,
como o caso de Java.

7.11.2 ASP X JSP


ASP (ActiveServer Pages ) a soluo desenvolvida pela
c para atender as requisies feitas a servidores Web.
Microsoft
Incorporada inicialmente apenas ao Internet Information Server

Tpicos Avanados

167

(IIS), atualmente j suportada por outros servidores populares,


como o Apache. O desenvolvimento de pginas que usam ASP
envolve a produo de um script contendo HTML misturado com
blocos de cdigo de controle ASP. Este cdigo de controle pode
conter scripts em JavaScript ou VBScript. A primeira vantagem
de JSP sobre ASP que a parte dinmica escrita em Java e
no Visual Basic ou outra linguagem proprietria da Microsoft,
portanto JSP mais poderoso e fcil de usar. Em segundo lugar
JSP mais portvel para outros sistemas operacionais e servidores
WEB que no sejam Microsoft.

7.11.3 Primeiro exemplo em JSP


Para que o leitor possa ter uma idia geral da tecnologia JSP
apresentaremos agora a verso JSP do Ol mundo. O exemplo 7.8
mostra o cdigo da pgina.
<html>
<head>
< t i t l e >Exemplo JSP</ t i t l e >
</ head>
<body>
<%
String x = " Ol Mundo ! " ;
%>
<%=x%>
</ body>
</ html>

Exemplo 7.8 Verso JSP do Ol mundo.


Quem est habituado aos tags HTML notar que se trata basicamente de uma pgina HTML contendo cdigo Java delimitado pelos
smbolos  <% e %>. No primeiro trecho de script declarada uma
varivel x com o valor Ol mundo. No segundo trecho de script o
contedo da varivel x extrado e colocado na pgina resultante da
execuo do Servlet correspondente. Em seguida mostraremos como
executar o exemplo 7.8.

168

Java na prtica

7.11.4 Executando o arquivo JSP


Para executar o exemplo 7.8 salve-o com a extenso .jsp. Por exemplo, ola.jsp. Se voc estiver usando o servidor Tomcat, coloque o
arquivo no subdiretrio /webapps/contexto do Tomcat. Por exemplo
webapps/teste/. Para invocar o arquivo JSP basta embutir a URL em
uma pgina ou digitar diretamente a seguinte URL no navegador.

http://localhost:8080/teste/ola.jsp
O Servlet criado a partir da pgina JSP colocado em um diretrio
de trabalho. No caso do Tomcat o Servlet colocado em subdiretrio
associado aplicao e subordinado ao diretrio /work do Tomcat. O
exemplo 7.9 mostra os principais trechos do Servlet criado a partir da
traduo do arquivo ola.jsp pelo tradutor do Tomcat. Note que o
Servlet subclasse de uma classe HttpJspBase e no da HttpServlet.
Alm disso, o mtodo que executado em resposta requisio o
mtodo _jspService() e no o mtodo service(). Note tambm que
todas as partes estticas da pgina JSP so colocadas como argumentos
do mtodo write() do objeto referenciado por out.
...

public c l a s s o l a _ j s p extends HttpJspBase {


...

public void _ j s p S e r v i c e ( H t t p S e r v l e t R e q u e s t r e q u e s t ,

HttpServletResponse response )

throws j a v a . i o . IOException , S e r v l e t E x c e p t i o n {
J s p F a c t o r y _jspxFactory = null ;
j a v a x . s e r v l e t . j s p . PageContext pageContext = null ;
H t t p S e s s i o n s e s s i o n = null ;
S e r v l e t C o n t e x t a p p l i c a t i o n = null ;
S e r v l e t C o n f i g c o n f i g = null ;
J s p W r i t e r out = null ;
Object page = this ;
J s p W r i t e r _jspx_out = null ;

try {

...
out . w r i t e ( "<html>\r \n
");
out . w r i t e ( "<head>\r \n
");
out . w r i t e ( "< t i t l e >Exemplo JSP" ) ;
out . w r i t e ( "</ t i t l e >\r \n
");
out . w r i t e ( "</head>\r \n
");
out . w r i t e ( "<body>\r \n
");

Tpicos Avanados

169

S t r i n g x = " Ol Mundo ! " ;

out . w r i t e ( "\ r \n
");
out . p r i n t ( x ) ;
out . w r i t e ( "\ r \n
");
out . w r i t e ( "</body>\r \n" ) ;
out . w r i t e ( "</html>" ) ;
} catch ( Throwable t ) {
...
}

Exemplo 7.9 Servlet correspondente pgina JSP do "Ol mundo".

7.11.5 Objetos implcitos


No exemplo 7.9 pode-se ver a declarao de variveis que referenciam
alguns objetos importantes. Estas variveis esto disponveis para o
projetista da pgina JSP. As variveis mais importantes so:

Classe
HttpServletRequest
HttpServletResponse
PageContext
ServletContext
HttpSession
JspWriter

Varivel
request
response
pageContext
application
session
out

Tabela 7.2 Principais variveis disponveis na pgina JSP.


Os objetos referenciados pelas variveis request e response j tiveram seu uso esclarecido na seo sobre Servlets. O objeto do tipo
JspWriter tem a mesma funo do PrinterWriter do Servlet. Os outros objetos tero sua funo esclarecida mais adiante.

7.11.6

Tags JSP

Os tags JSP possuem a seguinte forma geral:


<% Cdigo JSP %>

170

Java na prtica

O primeiro caractere % pode ser seguido de outros caracteres que


determinam o signicado do cdigo dentro do tag. Os tags JSP possuem
correspondncia com os tags XML. Existem cinco categorias de tags
JSP:
1. Expresses
2. Scriptlets
3. Declaraes
4. Diretivas
5. Comentrios
Em seguida comentaremos cada uma dessas categorias.

Expresses
<%= expresses %>

Expresses so avaliadas, convertidas para String e inseridas na


pgina enviada. A avaliao realizada em tempo de execuo, quando
a pgina requisitada.
Exemplos:
<%= new java.util.Date() %>
<%= request.getMethod() %>

No primeiro exemplo inserido na pgina a data corrente em milsimo de segundos e no segundo inserido o nome do mtodo (GET,
POST, etc.) usado na requisio. Note que cada expresso contm
apenas um comando Java. Note tambm que o comando Java no
terminado pelo caractere `;'.

Scriptlets
<%= cdigo Java %>

Quando necessrio mais de um comando Java ou, o resultado da


computao no para ser colocado na pgina de resposta, preciso
usar outra categoria de tags JSP: os Scriptlets . Os Scriptlets permitem
inserir trechos de cdigo em Java na pgina JSP. O exemplo 7.10 mostra
uma pgina JSP contendo um Scriptlet que transforma a temperatura
digitada em Celsius para o equivalente em Fahrenheit.

Tpicos Avanados

171

<html>
<head>< t i t l e >Conversao C e l s i u s F a h r e n h e i t</ t i t l e ></ head>
<body>
<%

String v a l o r = r e q u e s t . getParameter ( " c e l s i u s " ) ;

i f ( valor != null )
{
d o u b l e f = Double . p a r s e D o u b l e ( v a l o r ) 9 / 5 + 3 2 ;
out . p r i n t l n ( "<P>" ) ;
out . p r i n t l n (
"<h2>Valor em F a h r e n h e i t : " + f +"<h2><br>" ) ;
}

%>
<form action=c o n v e r s a o . j s p method=POST>
C e l c i u s : <input type=text s i z e =20 name=c e l s i u s><br>
<input type=submit>
</ form>
</ body>
</ html>

Exemplo 7.10 Pgina JSP que converte graus Celsius para


Fahrenheit.

Note o uso das variveis request e out sem a necessidade de declarao. Todo o cdigo digitado inserido no mtodo _jspService(). A
gura 7.15 mostra o resultado da requisio aps a digitao do valor
30 na caixa de texto do formulrio.

Figura 7.15 Resultado da converso de 30 graus Celsius.

172

Java na prtica

O cdigo dentro do scriptlet inserido da mesma forma que escrito


e todo o texto HTML esttico antes e aps um scriptlet convertido
para argumentos do mtodo write(). Desta forma o scriptlet no precisa conter comandos para cdigo esttico. Os blocos de controle abertos afetam o cdigo HTML envolvido por scriptlets. O exemplo 7.11
mostra duas formas de se produzir o mesmo efeito. No cdigo da esquerda os Scriplets se intercalam com cdigo HTML. O cdigo HTML,
quando da traduo da pgina JSP para Servlet, inserido como argumentos de mtodos println() ou write() gerando o cdigo da direita.
Ambas as formas podem ser usadas em pginas JSP e produzem o
mesmo efeito.
Previs&atilde;o do Tempo
out.println("Previs&atilde;o do Tempo");
<% if (Math.random() < 0.5) { %> if (Math.random() < 0.5) {
Hoje vai <B>fazer sol</B>!
out.println("Hoje vai <B>fazer sol</B>!");
<% } else { %>
} else {
Hoje vai <B>chover</B>!
out.println("Hoje vai <B>chover</B>!");
<% } %>
}

Exemplo 7.11 Dois cdigos equivalentes.

Declaraes
Uma declarao JSP permite denir variveis ou mtodos que so inseridos no corpo do Servlet. Como as declaraes no geram sada, elas
so normalmente usadas em combinao com expresses e scriptlets.
O exemplo 7.12 mostra a declarao de uma varivel que usada para
contar o nmero de vezes que a pgina corrente foi requisitada desde
que foi carregada.
<%! P r i v a t e int numAcesso = 0; % >
Acessos desde carregada :
<%= ++ numAcesso %>

Exemplo 7.12 Declarao de uma varivel usando o tag de


declarao.

As variveis declaradas desta forma sero variveis de instncia.


J as variveis declaradas em Scriptlets so variveis locais ao mtodo
_jspService(). Por isso possvel contar o nmero de requisies
com o exemplo 7.12. Se varivel fosse declarada em um Scriptlet a

Tpicos Avanados

173

varivel seria local ao mtodo _jspService() e, portanto, teria seu


valor reinicializado a cada chamada.
Como j foi dito, os tags de declaraes permitem a declarao
de mtodos. O exemplo 7.13 mostra a declarao de um mtodo que
converte Celsius para Fahrenheit.
<%!

private double c o n v e r t e ( double c )

{
}
%>

return c 9 / 5 + 3 2 ;

Exemplo 7.13 Declarao de um mtodo para a converso de


Celsius para Fahrenheit.

Comentrios
Existem dois tipos de comentrios utilizados em pginas JSP. O primeiro exclui todo o bloco comentado da sada gerada pelo processamento da pgina. A forma geral deste tipo de comentrio a seguinte:
<% comentrio %>

O segundo tipo de comentrio o utilizado em pginas HTML.


Neste caso o comentrio enviado dentro da pgina de resposta. A
forma geral deste tipo de comentrio a seguinte:
<!- comentrio >

Diretivas
Diretivas so mensagens para JSP container. Elas no enviam nada
para a pgina mas so importantes para denir atributos JSP e dependncias com o JSP container. A forma geral das diretivas a seguinte:

<%@ Diretiva atributo ="valor "%>


ou

174

Java na prtica

<%@ Diretiva atributo1 ="valor 1 "


atributo 2 ="valor 2 "
...
atributo n ="valor n " %>

Em seguida comentaremos as principais diretivas.

Diretiva page
<%@ page atributo 1 ="valor 1 ". . . atributo n ="valor n "%>
Atributo e Forma Geral

import="package.class "
ou
import="package.class 1 ,. . .,
package.class n "
contentType="MIME-Type"

isThreadSafe="true|false"

session="true|false"

buffer="tamkb |none"
autoflush="true|false"
info="mensagem "

Descrio
Permite especicar os pacotes que devem
ser importados para serem usados na pgina JSP. Exemplo:
<%@ page import="java.util.*" %>
Especica o tipo MIME da sada. O default text/html. Exemplo:
<%@ page contentType="text/plain" %>
possui o mesmo efeito do scriptlet
<%
response.setContentType("text/plain");
%>

Um valor true (default) indica um processamento normal do Servlet, onde mltiplas requisies so processadas simultaneamente. Um valor false indica que o
processamento deve ser feito por instncias
separadas do Servlet ou de forma serial.
Um valor true (default) indica que a varivel predenida session (HttpSession)
deve ser associada sesso, se existir, caso
contrrio uma nova sesso deve ser criada
e associada a ela. Um valor false indica
que nenhuma sesso ser usada.
Especica o tamanho do buer para escrita
usado pelo objeto JspWriter. O tamanho
default no menor que 8k.
Um valor true (default ) indica que o buer
deve ser esvaziado quando estiver cheio.
Dene uma cadeia de caracteres que pode
ser recuperada via getServletInfo().

Tpicos Avanados
errorPage="url "
isErrorPage="true|false"
language="java"

175
Especica a pgina JSP que deve ser processada em caso de excees no capturadas.
Indica se a pgina corrente pode atuar
como pgina de erro para outra pgina
JSP. O default false.
Possibilita denir a linguagem que est
sendo usada. No momento a nica possibilidade Java.

Tabela 7.3 Atributos da diretiva page.


A diretiva page permite a denio dos seguintes atributos, que
esto descritos na tabela 7.3:

import
contentType
isThreadSafe
session
buffer
autoflush
info
errorPage
isErrorPage
language
Tabela 7.4 Tabela de diretivas Page.

Diretiva include
<%@ include file="uri relativa " %>
Permite incluir arquivos no momento em que a pgina JSP traduzida em um Servlet. Por exemplo:

<%@ include file="/meuarq.html" %>

7.11.7 Extraindo Valores de Formulrios


Uma pgina JSP, da mesma forma que nos Servlet, pode usar o objeto
referenciado pela varivel request para obter os valores dos parmetros
de um formulrio. O exemplo 7.10 usado para converter graus Celcius
em Fahrenheit fez uso deste recurso. O exemplo 7.14 mostra outra
pgina JSP com formulrio. Note que o scriptlet usado para obter
o nome e os valores de todos os parmetros contidos no formulrio.

176

Java na prtica

Como o mtodo getParameterNames() retorna uma referncia a um


objeto Enumeration preciso importar o pacote java.util, por meio
da diretiva page.
<%@ page import=" j a v a . u t i l . " %>
<html><body>
<H1>Formulrio </H1>
<%
Enumeration campos = r e q u e s t . getParameterNames ( ) ;
while ( campos . hasMoreElements ( ) ) {
S t r i n g campo = ( S t r i n g ) campos . nextElement ( ) ;
S t r i n g v a l o r = r e q u e s t . g et Pa ra me te r ( campo); % >
< l i ><%= campo %> = <%= v a l o r %></ l i >
<% } %>
<form method="POST" a c t i o n=" form . j s p ">
Nome:< i n p u t type=" t e x t " s i z e=" 20 " name="nome" ><br>
T e l e f o n e :< i n p u t type=" t e x t " s i z e=" 20 " name=" t e l e f o n e ">
<br><INPUT TYPE=submit name=submit v a l u e=" e n v i e ">
</form>
</body></html>

Exemplo 7.14 Pgina JSP com formulrio.


A gura 7.16 mostra o resultado da requisio aps a digitao dos
valores Alcione e 333-3333 nas caixas de texto do formulrio.

Figura 7.16 Sada do exemplo 7.14.

Tpicos Avanados

177

7.11.8 Criando e Modicando Cookies


Da mesma forma que nos Servlets, os cookies em JSP so tratados por
meio da classe Cookie. Para recuperar os cookies enviados pelo navegador usa-se o mtodo getCookies() do objeto HttpServletRequest que
retorna um arranjo de Cookie. Os mtodos getName() e getvalue()
do objeto Cookie so utilizados para recuperar o nome e o valor da
informao associada ao cookie. O cookie enviado para o navegador
por meio do mtodo addCookie() do objeto HttpServletResponse. O
exemplo 7.15 mostra uma pgina JSP que exibe todos os cookies recebidos em uma requisio e adiciona mais um na resposta.
<html><body>
<H3>S e s s i o n i d : <%= s e s s i o n . g e t I d () %></H3>
<%
Cookie [ ] c o o k i e s = r e q u e s t . g e t C o o k i e s ( ) ;
f o r ( i n t i = 0 ; i < c o o k i e s . l e n g t h ; i ++) { %>
Cookie name : <%= c o o k i e s [ i ] . getName () %> <br>
Value : <%= c o o k i e s [ i ] . g e t V a l u e () %><br>
a n t i g a i d a d e mxima em seg undo s :
<%= c o o k i e s [ i ] . getMaxAge () %><br>
<% c o o k i e s [ i ] . setMaxAge ( 5 ) ; %>
nova i d a d e mxima em se gund os :
<%= c o o k i e s [ i ] . getMaxAge () %><br>
<% } %>
<%! i n t count = 0 ; i n t dcount = 0 ; %>
<% r e s p o n s e . addCookie ( new Cookie (
" Cookie " + count ++, " Valor " + dcount ++)); %>
</ body></ html>

Exemplo 7.15 Pgina JSP que exibe os cookies recebidos.

A gura 7.17 mostra o resultado aps dois acessos seguidos pgina


JSP. Note que existe um cookie a mais com o nome JSESSIONID e valor
igual sesso. Este cookie o usado pelo container para controlar a
sesso.

178

Java na prtica

Figura 7.17 Sada do exemplo 7.15 aps dois acessos.

7.11.9 Lidando com sesses


O atributos de uma sesso so mantidos em um objeto HttpSession
referenciado pela varivel session. Pode-se armazenar valores em
uma sesso por meio do mtodo setAttribute() e recuper-los por
meio do mtodo getAttribute(). O tempo de durao default de
uma sesso inativa (sem o recebimento de requisies do usurio)
30 minutos mas esse valor pode ser alterado por meio do mtodo
setMaxInactiveInterval(). O exemplo 7.16 mostra duas pginas JSP.
A primeira apresenta um formulrio onde podem ser digitados dois valores. Alm disso, exibe os atributos armazenados na sesso e dene
o intervalo mximo de inatividade da sesso em 10 segundos. A segunda pgina recebe a submisso do formulrio, insere os valores na
sesso e apresenta os valores relacionados com a sesso, assim como a
identicao da sesso.
<%@ page import=" j a v a . u t i l . " %>
<html><body>
<H1>F o r m u l r i o</H1>
<H1>Id da s e s s&a t i l d e ; o : <%= s e s s i o n . g e t I d () %></H1>
<H3>< l i >Essa s e s s&a t i l d e ; o f o i c r i a d a em
<%= s e s s i o n . g e t C r ea t i o n T i m e () %></ l i ></H3>
<H3>< l i >Antigo i n t e r v a l o de i n a t i v i d a d e =

Tpicos Avanados

179

<%= s e s s i o n . g e t M a x I n a c t i v e I n t e r v a l () %></ l i >


<% s e s s i o n . s e t M a x I n a c t i v e I n t e r v a l ( 1 0 ) ; %>
< l i >Novo i n t e r v a l o de i n a t i v i d a d e=
<%= s e s s i o n . g e t M a x I n a c t i v e I n t e r v a l () %></ l i >
</H3>
<%
Enumeration a t r i b s = s e s s i o n . ge t At tr i bu t eN am e s ( ) ;
w h i l e ( a t r i b s . hasMoreElements ( ) ) {
String a t r i b =( String ) a t r i b s . nextElement ( ) ;
String v a l o r =( String ) s e s s i o n . g e t A t t r i b u t e ( a t r i b ) ; %>
< l i ><%= a t r i b %> = <%= v a l o r %></ l i >
<% } %>
<form method="POST" action=" s e s s a o 2 . j s p ">
Nome :<input type=" t e x t " s i z e=" 20 " name="nome" ><br>
T e l e f o n e :<input type=" t e x t " s i z e=" 20 " name=" t e l e f o n e ">
<br>
<INPUT TYPE=submit name=submit value=" e n v i e ">
</ form>
</ body></ html>

<html><body>
<H1>Id da s e s s&a t i l d e ; o : <%= s e s s i o n . g e t I d () %></H1>
<%
String nome = r e q u e s t . getParameter ( "nome" ) ;
String t e l e f o n e = r e q u e s t . getParameter ( " t e l e f o n e " ) ;

%>

i f ( nome ! = n u l l && nome . l e n g t h ( )>0 )


s e s s i o n . s e t A t t r i b u t e ( "nome" , nome ) ;
i f ( t e l e f o n e ! = n u l l && t e l e f o n e . l e n g t h () >0)
session . setAttribute (" telefone " , telefone );

<FORM TYPE=POST ACTION=s e s s a o 1 . j s p>


<INPUT TYPE=submit name=submit Value=" Retorna ">
</FORM>
</ body></ html>

Exemplo 7.16 Exemplo do uso de sesso.


O exemplo 7.16 mostra que a sesso mantida mesmo quando o
usurio muda de pgina. As gura 7.18 e 7.19 mostram o resultado

180

Java na prtica

da requisio aps a digitao dos valores Alcione e 333-3333 nas


caixas de texto do formulrio, a submisso para pgina sessao2.jsp e
o retorno pgina sessao1.jsp.

Figura 7.18 Tela da pgina sessao1.jsp.

Figura 7.19 Tela da pgina sessao2.jsp.

7.11.10 O Uso de JavaBeans


A medida que o cdigo Java, dentro da pgina JSP, torna-se cada vez
mais complexo o desenvolvedor pode-se perguntar: Java em HTML no
o problema invertido do HTML em Servlet? O resultado no ser to
complexo quanto produzir uma pgina usando println()? Em outras
palavras, estou novamente misturando contedo com a forma?
Para solucionar esse problema, a especicao de JSP permite o uso
de JavaBeans para tratar parte do contedo da aplicao. Podemos
encarar um JavaBean como sendo apenas uma classe Java que obedece
a uma certa padronizao de nomeao de mtodos, formando o que
denominado de propriedade. As propriedades de um bean so acessadas
por meio de mtodos que obedecem a conveno getXxxx e setXxxx ,
onde Xxxx o nome da propriedade. Por exemplo, getItem() o
mtodo usado para retornar o valor da propriedade item. A sintaxe
para o uso de um bean em uma pgina JSP :

Tpicos Avanados

181

<jsp:useBean id="nome "class="package.class "/>

Onde nome o identicador da varivel que conter uma referncia para uma instncia do JavaBean. Voc tambm pode modicar
o atributo scope para estabelecer o escopo do bean alm da pgina
corrente.
<jsp:useBean
id="nome "scope="session "class="package.class "/>

Para modicar as propriedades de um JavaBean voc pode usar


o tag jsp:setProperty ou chamar um mtodo explicitamente em um
scriptlet. Para recuperar o valor de uma propriedade de um JavaBean
voc pode usar o jsp:getProperty ou chamar um mtodo explicitamente em um scriptlet. Quando dito que um bean tem uma propriedade prop do tipo T signica que o bean deve prover um mtodo
getProp() e um mtodo do tipo setProp(T). O exemplo 7.17 mostra
uma pgina JSP e um JavaBean. A pgina instancia o JavaBean, altera
a propriedade mensagem e recupera o valor da propriedade, colocando-o
na pgina.

Pgina bean.jsp
<HTML> <HEAD>
<TITLE>Uso de beans</TITLE>
</HEAD> <BODY> <CENTER>
<TABLE BORDER=5> <TR><TH CLASS="TITLE"> Uso de JavaBeans
</TABLE> </CENTER> <P>
<j s p : useBean i d=" t e s t e " c l a s s=" c u r s o . BeanSimples " />
<j s p : s e t P r o p e r t y name=" t e s t e " p r o p e r t y="mensagem"
value=" Ola mundo ! " />
<H1> Mensagem : <I>
<j s p : g e t P r o p e r t y name=" t e s t e " p r o p e r t y="mensagem" />
</ I></H1>
</BODY> </HTML>

Arquivo Curso/BeanSimples.java
package c u r s o ;
public c l a s s BeanSimples {

182

Java na prtica

private S t r i n g men = "Nenhuma mensagem" ;


public S t r i n g getMensagem ( ) {
return (men ) ;

public void setMensagem ( S t r i n g men ) {


this . men = men ;

Exemplo 7.17 Exemplo do uso de JavaBean.


A gura 7.20 mostra o resultado da requisio dirigida pgina
bean.jsp.

Figura 7.20 Resultado da requisio pgina bean.jsp.


Se no tag setProperty usarmos o valor * para o atributo property
ento todos os valores de elementos de formulrios que possurem nomes
iguais propriedades sero transferidos para as respectivas propriedades no momento do processamento da requisio. Por exemplo, seja
uma pgina jsp contendo um formulrio com uma caixa de texto com
nome mensagem, como mostrado no exemplo 7.18. Note que, neste caso,
a propriedade mensagem do JavaBean tem seu valor atualizado para o
valor digitado na caixa de texto, sem a necessidade de uma chamada
explcita no tag setProperty. Os valores so automaticamente convertidos para o tipo correto no bean (somente para tipos primitivos com
exceo do tipo double).
<HTML> <HEAD><TITLE>Uso de beans</TITLE> </HEAD>

Tpicos Avanados

183

<BODY> <CENTER>
<TABLE BORDER=5> <TR><TH CLASS="TITLE"> Uso de JavaBeans
</TABLE> </CENTER> <P>
<j s p : useBean i d=" t e s t e " c l a s s=" c u r s o . BeanSimples " />
<j s p : s e t P r o p e r t y name=" t e s t e " p r o p e r t y=" " />
<H1> Mensagem : <I>
<j s p : g e t P r o p e r t y name=" t e s t e " p r o p e r t y="mensagem" />
</ I></H1>
<form method="POST" action=" bean2 . j s p ">
Texto : <input type=" t e x t " s i z e=" 20 " name="mensagem" >
<br><INPUT TYPE=submit name=submit value=" e n v i e ">
</ form>
</BODY> </HTML>

Exemplo 7.18 Atualizao automtica da propriedade.


A gura 7.21 mostra o resultado da requisio dirigida pgina
bean2.jsp aps a digitao do texto Ol.

Figura 7.21 Resultado da requisio pgina bean2.jsp.

7.11.11 Escopo do bean


Existem quatro valores possveis para o escopo de um objeto: page,
request, session e application. O default page. A tabela 7.5
descreve cada tipo de escopo.

184

Java na prtica

Escopo

Descrio

page

Objetos declarados com esse escopo so vlidos at a


resposta ser enviada ou a requisio ser encaminhada
para outro programa no mesmo ambiente, ou seja, s
podem ser referenciados nas pginas onde forem declarados. Objetos declarados com escopo page so referenciados pelo objeto pagecontext.
Objetos declarados com esse escopo so vlidos durante a requisio e so acessveis mesmo quando a
requisio encaminhada para outro programa no
mesmo ambiente. Objetos declarados com escopo
request so referenciados pelo objeto request.
Objetos declarados com esse escopo so vlidos durante a sesso desde que a pgina seja denida para
funcionar em uma sesso. Objetos declarados com escopo session so referenciados pelo objeto session.
Objetos declarados com esse escopo so acessveis por
pginas no mesmo servidor de aplicao. Objetos declarados com escopo application so referenciados
pelo objeto application.

request

session

application

Tabela 7.5 Escopo dos objetos nas pginas JSP.

Implementao de um Carrinho de Compras


O exemplo abaixo ilustra o uso de JSP para implementar um carrinho
de compras virtual. O carrinho de compras virtual simula um carrinho
de compras de supermercado, onde o cliente vai colocando os produtos selecionados para compra at se dirigir para o caixa para fazer o
pagamento. No carrinho de compras virtual os itens selecionados pelo
usurio so armazenados em uma estrutura de dados at que o usurio efetue o pagamento. Esse tipo de exemplo exige que a pgina JSP
funcione com o escopo session para manter o carrinho de compras
durante a sesso. O exemplo 7.19 mostra um exemplo simples de implementao de carrinho de compras. O exemplo composto por dois
arquivos: um para a pgina JSP e um para o JavaBean que armazena
os itens selecionados.

Pgina compras.jsp
<html>
<j s p : useBean i d=" c a r r i n h o " s c o p e=" s e s s i o n "
c l a s s=" compra . C a r r i n h o " />
<j s p : s e t P r o p e r t y name=" c a r r i n h o " p r o p e r t y=" " />

Tpicos Avanados

185

<body bgcolor="#FFFFFF">
<%

carrinho . processRequest ( request ) ;

String [ ] i t e m s = c a r r i n h o . g e t I t e m s ( ) ;
%>

i f ( i t e m s . l e n g t h>0 ) {

<font s i z e =+2 color="#3333FF">


Voc&e c i r c ; comprou o s s e g u i n t e s i t e n s :</ font>
< ol>
<%
f o r ( i n t i = 0 ; i <i t e m s . l e n g t h ; i ++) {
out . p r i n t l n ( "< l i >"+i t e m s [ i ] ) ;
}
}
%>
</ ol>
<hr>
<form type=POST action = compras . j s p>
<br><font color="#3333FF" s i z e =+2>
Entre um item para a d i c i o n a r ou remover :
</ font><br>
< sel e ct NAME=" item ">
<o p t i o n>T e l e v i s&a t i l d e ; o
<o p t i o n>R&a a c u t e ; d i o
<o p t i o n>Computador
<o p t i o n>V&i a c u t e ; deo C a s s e t e
</ sel ec t>
<p><input TYPE=submit name=" submit " value=" a d i c i o n e ">
<input TYPE=submit name=" submit " value=" remova ">
</ form>
</ body>
</ html>

JavaBean compra/Carrinho.java
package compra ;
import j a v a x . s e r v l e t . h t t p . ;
import j a v a . u t i l . Vector ;
import j a v a . u t i l . Enumeration ;
public c l a s s C a r r i n h o {
Vector v = new Vector ( ) ;

186

Java na prtica

S t r i n g submit = null ;
S t r i n g item = null ;

private void addItem ( S t r i n g name )


{v . addElement ( name ) ; }

private void removeItem ( S t r i n g name )


{v . removeElement ( name ) ; }

public void s e t I t e m ( S t r i n g name )


{ item = name ; }

public void se tS u b m it ( S t r i n g s )
{ submit = s ;

public S t r i n g [ ] g e t I t e m s ( ) {
S t r i n g [ ] s = new S t r i n g [ v . s i z e ( ) ] ;
}

v . copyInto ( s ) ;
return s ;

private void r e s e t ( ) {
submit = null ;
item = null ;

public void p r o c e s s R e q u e s t ( H t t p S e r v l e t R e q u e s t r e q u e s t )

i f ( submit == null ) return ;


i f ( submit . e q u a l s ( " a d i c i o n e " ) )
addItem ( item ) ;
else i f ( submit . e q u a l s ( " remova " ) ) removeItem ( item ) ;

reset ();

Exemplo 7.19 Implementao de um carrinho de compras Virtual.


O exemplo 7.19 implementa apenas o carrinho de compras, deixando de fora o pagamento dos itens, uma vez que esta etapa depende
de cada sistema. Geralmente o que feito direcionar o usurio para
outra pgina onde ele digitar o nmero do carto de crdito que ser
transmitido por meio de uma conexo segura para o servidor. Existem
outras formas de pagamento, como boleto bancrio e dinheiro virtual.
O prprio carrinho de compras geralmente mais complexo, uma vez

Tpicos Avanados

187

que os itens para compra devem ser obtidos dinamicamente de um


banco de dados. A gura 7.22 mostra a tela resultante de algumas
interaes com o carrinho de compras.

Figura 7.22 Carrinho de compras virtual.

7.12 Reencaminhando ou
nando requisies

Redirecio-

Existem algumas situaes onde pode ser desejvel transferir uma requisio para outra URL. Isto feito com frequncia em sistemas que
combinam o uso de Servlets juntamente com pginas JSP. No entanto,
a transferncia pode ser para qualquer recurso. Assim, podemos transferir uma requisio de um Servlet para uma pgina JSP, HTML ou
um outro Servlet. Da mesma forma uma pgina JSP pode transferir
uma requisio para uma outra pgina JSP, HTML ou um Servlet.
Existem dois tipos de transferncia de requisio: o redirecionamento e o reencaminhamento. O redirecionamento obtido usando o
mtodo sendRedirect() de uma instncia HttpServletResponse, passando como argumento a URL de destino. O exemplo 7.20 mostra o
cdigo de um Servlet redirecionando para a pgina JSP do exemplo 7.8.

import j a v a x . s e r v l e t . ;
import j a v a x . s e r v l e t . h t t p . ;
import j a v a . i o . ;

188

Java na prtica

public c l a s s R e d i r e c i o n a extends H t t p S e r v l e t

public void doGet ( H t t p S e r v l e t R e q u e s t req ,

HttpServletResponse res )

{
}

throws S e r v l e t E x c e p t i o n , IOException
res . sendRedirect (" ola . jsp " ) ;

Exemplo 7.20 Redirecionamento de requisio.


No caso de redirecionamento a requisio corrente perdida e
uma nova requisio feita para a URL de destino. Por isso no
se deve associar nenhum objeto requisio, uma vez que o objeto
HttpServletRequest corrente ser perdido. O que ocorre na prtica
que o servidor envia uma mensagem HTTP 302 de volta para o cliente
informando que o recurso foi transferido para outra URL e o cliente
envia uma nova requisio para a URL informada.
J no caso de reencaminhamento a requisio encaminhada diretamente para a nova URL mantendo todos os objetos associados
e evitando uma nova ida ao cliente. Portanto, o uso de reencaminhamento mais eciente do que o uso de redirecionamento. O
reencaminhamento obtido usando o mtodo forward() de uma
instncia RequestDispatcher, passando como argumento os objetos
HttpServletRequest e HttpServletResponse para a URL de destino. Uma instncia RequestDispatcher obtida por meio do mtodo
getRequestDispatcher() de uma instncia ServletContext, que obtido, por sua vez, por meio do mtodo getServletContext() do Servlet. O exemplo 7.21 mostra o cdigo de um Servlet reencaminhando
a requisio para a pgina JSP do exemplo 7.8.

import j a v a x . s e r v l e t . ;
import j a v a x . s e r v l e t . h t t p . ;
public c l a s s Reencaminha extends H t t p S e r v l e t

public void doGet ( H t t p S e r v l e t R e q u e s t r e q u e s t ,


{

HttpServletResponse response )

try

Tpicos Avanados

189

getServletContext ( ) .
getRequestDispatcher ( "/ ola . j s p " ) .
forward ( request , response ) ;
} catch ( E x c e p t i o n e ) {
System . out . p r i n t l n ( " S e r v l e t f a l h o u : " ) ;
e . printStackTrace ( ) ;
}

Exemplo 7.21 Reencaminhamento de requisio.

7.13 Uma Arquitetura para comrcio


eletrnico
O projeto de uma soluo para comrcio eletrnico uma tarefa complexa e deve atender diversos requisitos. Nesta seo mostraremos um
modelo de arquitetura bsico para comrcio eletrnico que pode ser
adaptado para solues mais especcas. Este modelo implementa o
padro de projeto MVC (Modelo-Viso-Controle), procurando, desta
forma, isolar os diferentes aspectos de um sistema de computao.

7.13.1 Tipos de aplicaes na WEB


Podemos enquadrar a maioria das aplicaes na Web em um dos seguintes tipos:

Business-to-consumer (B2C) - entre empresa e consumidor.


Exemplo: uma pessoa compra um livro na Internet.

Business-to-business (B2B) - Troca de informaes e servios entre


empresas. Exemplo: o sistema de estoque de uma empresa de
automveis detecta que um item de estoque precisa ser reposto e
faz o pedido diretamente ao sistema de produo do fornecedor de
autopeas. Neste tipo de aplicao a linguagem XML possui um
papel muito importante, uma vez que existe a necessidade de uma
padronizao dos metadados3 para comunicao de contedo.

3 Dados sobre dados. Por exemplo, em um banco de dados os dados so os


valores contidos em cada coluna e os metadados so os nomes das colunas e
tabelas.

190

Java na prtica

User-to-data - acesso bases de informao. Exemplo: um usurio


consulta uma base de informao.

User-to-user - chat, e troca de informaes entre usurios (KaZaA).


O exemplo que mostraremos tipicamente um caso de User-to-data,
(agenda eletrnica na Web) mas possui a mesma estrutura de um B2C.

7.13.2 Arquitetura MVC para a Web


A gura 7.23 contm um diagrama de blocos que mostra a participao
de Servlets, JSP e JavaBeans na arquitetura proposta. A idia isolar
cada aspecto do modelo MVC com a tecnologia mais adequada. A
pgina JSP tima para fazer o papel da viso, uma vez que possui
facilidades para a insero de componentes visuais e para a apresentao
de informao. No entanto, um pouco estranho usar uma pgina JSP
para receber e tratar uma requisio. Esta tarefa, que se enquadra no
aspecto de controle do modelo MVC mais adequada a um Servlet, uma
vez que, neste momento, componentes de apresentao so indesejveis.
Finalmente, desejvel que a modelagem do negcio que isolada dos
aspectos de interao. A proposta que a modelagem do negcio que
contida em classes de JavaBeans. Em aplicaes mais sosticadas a
modelagem do negcio deve ser implementada por classes de Enterprise
JavaBeans (EJB), no entanto esta forma de implementao foge ao
escopos deste livro. Cada componente participa da seguinte forma:
Servlets - Atua como controlador, recebendo as requisies dos
usurios. Aps a realizao das anlises necessrias sobre a requisio, instanciam os JavaBeans e os armazenam no escopo
adequado (ou no, caso os beans j tenham sido criados no escopo) e encaminha a requisio para a pgina JSP.
JavaBeans - Atuam como o modelo da soluo, independentes
da requisio e da forma de apresentao. Comunicam-se com a
camada intermediria que encapsula a lgica de acesso aos dados.
JSP - Atuam na camada de apresentao utilizando os JavaBeans
para obteno dos dados a serem exibidos, isolando-se assim da
tarefa de acessar os dados. O objetivo minimizar a quantidade
de cdigo colocado na pgina.
Camada Intermediria (Middleware ) - Incorpora a lgica de
acesso aos dados. Permite isolar os outros mdulos de problemas como estratgias de acesso aos dados e desempenho. O uso

Tpicos Avanados

191

de EJB (Enterprise JavaBeans ) recomendado para a implementao do Middleware, uma vez que os EJBs possuem capacidades
para gerncia de transaes e persistncia. Isto implica na adoo
de um servidor de aplicao habilitado para EJB.
A gura 7.23 ilustra a interao entre os componentes. Essa arquitetura possui as seguintes vantagens:

Facilidade de manuteno: a distribuio lgica das funes entre


os mdulos do sistema isola o impacto das modicaes.

Escalabilidade: as modicaes necessria para acompanhar o au-

mento da demanda de servios (database pooling, clustering, etc)


cam concentradas na camada intermediria.

Minimizao de Interferncias entre Desenvolvedores: uma

vez que as tarefas cam mais isoladas, menor ser a interferncia


entre os diferentes tipos de desenvolvedores durante a criao da
aplicao.

Figura 7.23 Arquitetura de uma aplicao para Comrcio Eletrnico.

192

Java na prtica

Figura 7.24 Arquitetura fsica de uma aplicao para Comrcio


Eletrnico.

A gura 7.24 mostra a arquitetura fsica de uma aplicao de comrcio eletrnico. Demilitarized Zone (DMZ) onde os servidores HTTP
so instalados. A DMZ protegida da rede pbica por um rewall,
tambm chamado de rewall de protocolo. O rewall de protocolo
deve ser congurado para permitir trfego apenas atravs da porta 80.
Um segundo rewall, tambm chamado de rewall de domnio separa a
DMZ da rede interna. O rewall de domnio deve ser congurado para
permitir comunicao apenas por meio das portas do servidor de aplicao. Desta forma os dados corporativos cam protegidos de ataques
externos.

7.13.3 Agenda Web: Um Exemplo de uma aplicao Web usando a arquitetura MVC
O exemplo a seguir mostra o desenvolvimento da agenda eletrnica para
o funcionamento na Web. A arquitetura adotada uma implementao
do modelo MVC. Apenas, para simplicar a soluo, a camada intermediria foi simplicada e implementada por um JavaBean que tem
a funo de gerenciar a conexo com o banco de dados. O sistema
composto pelos arquivos mostrados na tabela 7.6.

Tpicos Avanados

193

Arquivo

Descrio

agenda.html

Pgina inicial do site, contendo o formulrio


para a entrada do login e senha para entrar no
restante do site.
Pgina JSP contendo o formulrio para entrada de dados para insero, remoo ou consulta de itens da agenda.
JavaBean responsvel por vericar se o usurio
est autorizado a acessar a agenda.
Servlet responsvel pelo tratamento de requisies sobre alguma funo da agenda (consulta,
insero e remoo).
JavaBean responsvel pela execuo da ao
solicitada pelo usurio.
JavaBean responsvel pelo acesso ao DB e controle das conexes.

principal.jsp
LoginBean.java
AgendaServlet.java
AcaoBean.java
ConnectionBean.java

Tabela 7.6 Arquivos do sistema e-agenda.


O banco de dados composto por duas tabelas, uma para armazenar
os usurios autorizados a usar a tabela e outra para armazenar os itens
da agenda. A gura 7.25 mostra o esquema conceitual do banco de
dados e a gura 7.26 mostra o comando para a criao das tabelas. Note
que existe um relacionamento entre a tabela USUARIO e a tabela PESSOA,
mostrando que os dados pessoais sobre o usurio cam armazenados na
agenda.

Figura 7.25 Esquema conceitual do banco de dados para a agenda.


As tabelas do BD devem ser criadas de acordo com o seguinte script:

CREATE TABLE PESSOA ( ID INT PRIMARY KEY,


NOME VARCHAR( 5 0 ) NOT NULL,
TELEFONE VARCHAR( 5 0 ) ,
ENDERECO VARCHAR( 8 0 ) ,
EMAIL VARCHAR( 5 0 ) ,
HP
VARCHAR( 5 0 ) ,
CELULAR VARCHAR( 2 0 ) ,
DESCRICAO VARCHAR( 8 0 ) ) ;

194

Java na prtica

CREATE TABLE USUARIO ( ID INT PRIMARY KEY,


LOGIN VARCHAR( 2 0 ) NOT NULL,
SENHA VARCHAR( 2 0 ) NOT NULL,
CONSTRAINT FK_USU FOREIGN KEY ( ID )
REFERENCES PESSOA( ID ) ) ;

Figura 7.26 Script para criao das tabelas.


Para se usar a agenda necessrio que exista pelo menos um usurio
cadastrado. Como no exemplo no vamos apresentar uma tela para
cadastro de usurios ser preciso cadastr-los por meio de comandos
SQL. Os comandos da gura 7.27 mostram como cadastrar um usurio.

INSERT INTO PESSOA( ID ,NOME,TELEFONE,ENDERECO, EMAIL)


VALUES( 0 , ' A l c i o n e de Paiva O l i v e i r a ' , ' 3899 1769 ' ,
'PH R o l f s ' , ' a l c i o n e p a i v a @ i g . com . br ' ) ;

INSERT INTO USUARIO( ID , LOGIN,SENHA)


VALUES( 0 , ' A l c i o n e ' , ' senha ' ) ;

Figura 7.27 Script para cadastrar um usurio.


O diagrama de colaborao, apresentado na gura 7.28, mostra as
interao entre os componentes do sistema.

Figura 7.28 Interao entre os componentes do sistema.

Tpicos Avanados

195

Descreveremos agora cada componente da aplicao. O exemplo 7.22 mostra o cdigo HTML da pgina agenda.html. Esta a
pgina inicial da aplicao. Ela contm o formulrio para a entrada do
login e senha para entrar no restante do site.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

<HTML>
<HEAD>
<TITLE>Agenda</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<P a l i g n=" c e n t e r "><IMG s r c=" t i t . g i f " width=" 350 "
h e i g h t=" 100 " b o r d e r="0"></P>
<BR>
<CENTER>
<FORM method="POST" name=" TesteSub "
onsubmit=" r e t u r n TestaVal ( ) "
a c t i o n="/ agenda / agenda "><BR>
Login :<INPUT s i z e=" 20 " type=" t e x t " name=" l o g i n ">
<BR><BR>
Senha :<INPUT s i z e=" 20 " type=" password "
name=" senha ">
<BR><BR><BR>
<INPUT type=" submit " name=" e n v i a " v a l u e=" Enviar ">
<INPUT s i z e="3 " type=" Hidden " name=" c o r r e n t e "
v a l u e="0">
<BR>
</FORM>
</CENTER>
<SCRIPT l a n g u a g e=" J a v a S c r i p t ">
<!
f u n c t i o n TestaVal ( )
{
i f ( document . TesteSub . l o g i n . v a l u e == "" )
{
a l e r t ( "Campo Login nao P r e e n c h i d o ! " )
}

return f a l s e

else i f ( document . TesteSub . senha . v a l u e == "" )

{
}

a l e r t ( "Campo Senha nao P r e e n c h i d o ! " )

return f a l s e

else

196
42
43
44
45
46

Java na prtica

return true

}
//></SCRIPT>
</BODY></HTML>

Exemplo 7.22 agenda.html.


O formulrio est denido nas linha 12 a 24. Na linha 14 o parmetro action indica a URL que deve receber a requisio. A URL
virtual e sua associao com o Servlet AgendaServlet ser denida
no arquivo web.xml. Na linha 17 denido um campo oculto (Hidden)
como o nome de corrente e valor 0. Ele ser usado pelo AgendaServlet
para reconhecer a pgina de onde saiu a requisio. As linhas 26 a 45
denem uma funo em JavaScript que ser usada para vericar se o
usurio digitou o nome e a senha antes de enviar a requisio ao usurio.
O uso de JavaScript no lado cliente para criticar a entrada do usurio
muito comum pois diminui a sobrecarga do servidor.
O exemplo 7.23 mostra cdigo da pgina principal.jsp. Esta pgina contm o formulrio para entrada de dados para insero, remoo
ou consulta de itens da agenda. Na linha 4 a diretiva page dene que
o servidor deve acompanhar a sesso do usurio e importa o pacote
agenda. Na linha 7 um objeto da classe agenda.LoginBean recuperado da sesso por meio do mtodo getAttribute(). Para recuperar
o objeto preciso passar para o mtodo o nome que est associado
ao objeto na sesso. De forma semelhante, na linha 9 um objeto da
classe agenda.AcaoBean recuperado da requisio por meio do mtodo getAttribute(). Este objeto recuperado da requisio porque
cada requisio possui uma ao diferente associada. Na linha 11
vericado se objeto agenda.LoginBean foi recuperado e se o retorno do
mtodo getStatus() true. Se o objeto agenda.LoginBean no foi
recuperado signica que existe uma tentativa de acesso direto pgina
principal.jsp sem passar primeiro pela pgina agenda.html ou que
a sesso se esgotou. Se o mtodo getStatus() retornar false signica
que o usurio no est autorizado a acessar essa pgina. Nestes casos
processado o cdigo associado ao comando else da linha 43 que apaga
a sesso por meio do mtodo invalidate() do objeto HttpSession
(linha 45) e mostra a mensagem Usurio no autorizado (linha 47).
Caso o objeto indique que o usurio est autorizado os comandos internos ao if so executados. Na linha 13 mostrada uma mensagem com

Tpicos Avanados

197

o nome do usurio, obtido por meio do mtodo getNome() do objeto


agenda.LoginBean. Na linha 15 mostrado o resultado da ao anterior
por meio do mtodo toString() do objeto agenda.AcaoBean. A ao
pode ter sido de consulta, de insero de um novo item na agenda, ou
de remoo de um item na agenda. No primeiro caso mostrado uma
lista dos itens que satiszeram a consulta. No segundo e terceiro casos
exibida uma mensagem indicando se a operao foi bem sucedida.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

<HTML><HEAD>
<TITLE>Tela da Agenda </TITLE>
</HEAD><BODY b g c o l o r="#FFFFFF">
<%@ page s e s s i o n=" t r u e " import=" agenda . " %>
<%
agenda . LoginBean l b =(agenda . LoginBean )
session . getAttribute (" loginbean " ) ;
agenda . AcaoBean ab = ( agenda . AcaoBean )
r e q u e s t . g e t A t t r i b u t e ( " acaobean " ) ;
i f ( l b ! = null && l b . g e t S t a t u s ( ) )
{ %>
<H2>S e s s&a t i l d e ; o do <%= l b . getNome() %></H2>
<%
i f ( ab!= null ) out . p r i n t l n ( ab . t o S t r i n g ( ) ) ;
%>
<P><BR></P>
<FORM method="POST" name=" f o r m p r i n "
onsubmit=" r e t u r n TestaVal ( ) " a c t i o n="/ agenda / agenda ">
Nome: <INPUT s i z e=" 50 " type=" t e x t " name="nome"><BR>
T e l e f o n e : <INPUT s i z e=" 20 " type=" t e x t " name=" t e l e f o n e ">
<BR>
Endere&c c e d i l ; o : <INPUT s i z e=" 50 " type=" t e x t "
name=" e n d e r e c o "><BR>
Email : <INPUT s i z e=" 50 " type=" t e x t " name=" e m a i l "><BR>
<BR>
P&a a c u t e ; g i n a : <INPUT s i z e=" 50 " type=" t e x t "
name=" p a g i n a "><BR>
C e l u l a r : <INPUT s i z e=" 20 " type=" t e x t " name=" c e l u l a r ">
<BR>
D e s c r i&c c e d i l ;& a t i l d e ; o : <INPUT s i z e=" 20 " type=" t e x t "
name=" d e s c r i c a o ">
<BR><CENTER>
<INPUT type=" submit " name=" acao " v a l u e=" C o n s u l t a ">
<INPUT type=" submit " name=" acao " v a l u e=" I n s e r e ">
<INPUT type=" submit " name=" acao " v a l u e="Apaga"></CENTER>
<INPUT s i z e="3 " type=" Hidden " name=" c o r r e n t e " v a l u e="1 ">
</FORM>
<%
}

else

session . invalidate ();

198
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

Java na prtica

%>
<H1>Usu&a a c u t e ; r i o n&a t i l d e ; o a u t o r i z a d o </H1>
<%
}
%>
<SCRIPT l a n g u a g e=" J a v a S c r i p t "><!
f u n c t i o n TestaVal ( )
{
i f ( document . f o r m p r i n . nome . v a l u e == " " &&
document . f o r m p r i n . d e s c r i c a o . v a l u e== "" )
{
a l e r t ( "Nome ou D e s c r i c a o devem s e r P r e e n c h i d o s ! " )
}

return f a l s e

else

{
}

return true

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

Exemplo 7.23 principal.jsp.


As linhas 19 a 39 denem o cdigo do formulrio de entrada. Nas
linhas 19 e 20 so denidos os atributos do formulrio. O atributo
method indica que a requisio ser enviada por meio do mtodo POST.
O atributo name dene o nome do formulrio como sendo formprin. O
atributo onsubmit dene que a funo JavaScript TestaVal() deve
ser executada quando o formulrio for submetido. Finalmente, o atributo action dene a URL para onde a requisio deve ser enviada.
Neste caso a URL agenda/agenda que est mapeada para o Servlet
AgendaServlet. O mapeamento feito no arquivo web.xml do diretrio web-inf do contexto agenda, como mostrado na gura 7.30. As
linhas 21 a 33 denem os campos de texto para entrada dos valores. As
linhas 35 a 38 denem os botes tipo submit. Todos possuem o mesmo
nome, de forma que o Servlet precisa apenas examinar o valor do parmetro acao para determinar qual ao foi solicitada. Na linha 38
denido um campo oculto (Hidden) com o nome de corrente e valor 1.
Ele ser usado pelo AgendaServlet reconhecer a pgina de onde saiu
a requisio. As linha 52 a 66 denem uma funo em JavaScript que
ser usada para vericar se o usurio entrou com valores nos campos
de texto nome ou descricao. No mnimo um desses campos deve ser
preenchido para que uma consulta possa ser realizada.

Tpicos Avanados

199

O exemplo 7.24 mostra o cdigo do JavaBean usado para intermediar a conexo com o banco de dados. O JavaBean ConnectionBean
tem a responsabilidade de abrir uma conexo com o banco de dados,
retornar uma referncia desta conexo quando solicitado e registrar se
a conexo est livre ou ocupada. Neste exemplo o ConnectionBean se
encarrega apenas de obter a conexo e fech-la, no entanto, em uma
aplicao, com um nmero maior de acessos ao banco de dados, pode
ser necessrio um maior controle sobre o uso das conexes, mantendoas em uma estrutura de dados para fazer o papel de pool de conexes.
Na linha 13 podemos observar que o construtor da classe foi declarado
com o modicador de acesso private. Isto signica que no possvel
invocar o construtor por meio de um objeto de outra classe. Isto
feito para que se possa ter um controle sobre a criao de instncias da
classe. No nosso caso permitiremos apenas que uma instncia da classe
seja criada, de modo que todas as referncias apontem para um mesmo
objeto. Esta tcnica de programao, onde se permite uma nica instncia de uma classe, denominada de padro de projeto Singleton. O
objetivo de utilizarmos este padro porque desejamos que apenas um
objeto controle a conexo com o banco de dados. Mas se o construtor
no pode ser chamado fora da classe, ento como uma instncia da
classe criada e sua referncia passada para outros objetos? Esta
a tarefa do mtodo esttico getInstance() (linhas 15 a 23). Este
mtodo verica se j existe a instncia e retorna a referncia. Caso a
instncia no exista ela criada antes de se retornar a referncia. O
mtodo init() (linhas 25 a 35) chamado pelo construtor para estabelecer a conexo com o SGBD. Ele carrega o driver JDBC do tipo 4
para HSQLDB (veja a seo 4.3) e obtm uma conexo com o SGBD.
O mtodo devolveConnection() (linhas 37 a 45) chamado quando
se deseja devolver a conexo. Finalmente, o mtodo getConnection()
(linhas 57 a 57) chamado quando se deseja obter a conexo.
1
2
3
4
5
6
7
8
9
10

package agenda ;
import j a v a . s q l . ;
import j a v a . l a n g . ;
import j a v a . u t i l . ;
public c l a s s ConnectionBean

private Connection con=null ;


private s t a t i c int c l i e n t s =0;

200
11
12
13
14
15
16
17

Java na prtica

s t a t i c private ConnectionBean i n s t a n c e=null ;


private ConnectionBean ( ) {

s t a t i c synchronized
public ConnectionBean g e t I n s t a n c e ( )

18
20

21
23
24
25
26

29
30
31
32
33

36
37
38
39

return i n s t a n c e ;

try

28

35

C l a s s . forName ( " o r g . h s q l d b . j d b c D r i v e r " ) ;


con = DriverManager . g e t C o n n e c t i o n (
" jdbc : hsqldb : hsql : / / l o c a l h o s t " , " sa " , "" ) ;
} catch ( E x c e p t i o n e ) {
System . out . p r i n t l n ( e . getMessage ( ) ) ;
}

public synchronized
void d e v o l v e C o n n e c t i o n ( Connection con )

40

i f ( this . con==con )

41
42
43
44
45
46
47
48
49
50
51

i n s t a n c e = new ConnectionBean ( ) ;

private void i n i t ( )

27

34

i f ( i n s t a n c e == null )

19

22

init (); }

c l i e n t s ;
notify ();

public synchronized Connection g e t C o n n e c t i o n ( )

i f ( c l i e n t s >0)

try { w a i t ( 5 0 0 0 ) ; }

Tpicos Avanados

catch ( I n t e r r u p t e d E x c e p t i o n e ) { } ;
i f ( c l i e n t s >0) return null ;

52
53
54
55
56
57
58

201

}
c l i e n t s ++;
return con ;

Exemplo 7.24 ConnectionBean.java.


O exemplo 7.25 mostra cdigo do JavaBean usado para vericar
se o usurio est autorizado a usar a agenda. O JavaBean LoginBean
recebe o nome e a senha do usurio, obtm a conexo com o SGBD e
verica se o usurio est autorizado, registrando o resultado da consulta
na varivel status (linha 11). Tudo isso feito no construtor da classe
(linhas 13 a 40). Note que na construo do comando SQL (linhas 18
a 21) inserido uma juno entre as tabelas PESSOA e USUARIO, de
modo a ser possvel recuperar os dados relacionados armazenados em
ambas as tabelas. Os mtodos getLogin(), getNome() e getStatus()
(linhas 42 a 44) so responsveis pelo retorno do login, nome e status
da consulta respectivamente.
1 package agenda ;
2
3 import j a v a . s q l . ;
4 import j a v a . l a n g . ;
5 import j a v a . u t i l . ;
6
7 public c l a s s LoginBean
8 {
9 protected S t r i n g nome = null ;
10 protected S t r i n g l o g i n = null ;
11 protected boolean s t a t u s = f a l s e ;
12
13 public LoginBean ( S t r i n g l o g i n , S t r i n g senha )
14 {
15
this . l o g i n
=l o g i n ;
16
Connection con = null ;
17
Statement stmt = null ;
18
S t r i n g c o n s u l t a="SELECT NOME FROM PESSOA , USUARIO "+
19
"WHERE USUARIO . ID = PESSOA . ID AND "+
20
"USUARIO .SENHA = ' "+senha+" ' AND "+
21
"USUARIO . LOGIN = ' "+l o g i n+" ' " ;
22
try
23
{
24
con=ConnectionBean . g e t I n s t a n c e ( ) . g e t C o n n e c t i o n ( ) ;

202

Java na prtica

25
stmt = con . c r e a t e S t a t e m e n t ( ) ;
26
R e s u l t S e t r s = stmt . executeQuery ( c o n s u l t a ) ;
27
i f ( r s . next ( ) )
28
{
29
s t a t u s = true ;
30
nome = r s . g e t S t r i n g ( "NOME" ) ;
31
}
32
} catch ( E x c e p t i o n e ) {
33
System . out . p r i n t l n ( e . getMessage ( ) ) ;
34
}
35
finally
36
{
37
ConnectionBean . g e t I n s t a n c e ( ) . d e v o l v e C o n n e c t i o n ( con ) ;
38
try { stmt . c l o s e ( ) ; } catch ( E x c e p t i o n e e ) { } ;
39
}
40 }
41
42 public S t r i n g g e t L o g i n ( ) { return l o g i n ; }
43 public S t r i n g getNome ( ) { return nome ; }
44 public boolean g e t S t a t u s ( ) { return s t a t u s ; }
45 }

Exemplo 7.25 LoginBean.java.


O exemplo 7.26 mostra cdigo do Servlet que implementa a camada
de controle do modelo MVC. O Servlet AgendaServlet recebe as requisies e, de acordo com os parmetros, instancia os JavaBeans apropriados e reencaminha as requisies para as pginas corretas. Tanto o
mtodo doGet() (linhas 9 a 13) quanto o mtodo doPost()(linhas 14
a 18) invocam o mtodo performTask() (linhas 20 a 64) que realiza o
tratamento da requisio. Na linhas 25 a 28 do mtodo performTask()
obtido o valor do parmetro corrente que determina a pgina que
originou a requisio. Se o valor for nulo assumido o valor default
zero. Na linha 32 executado um comando switch sobre esse valor, de
modo a desviar para o bloco de comandos adequado. O bloco que vai
da linha 34 at a linha 45 trata a requisio originada em uma pgina
com a identicao 0 (pgina agenda.html). Nas linhas 34 e 35 so
recuperados o valor de login e senha digitados pelo usurio. Se algum
desses valores for nulo ento a requisio deve ser reencaminhada para
a pgina de login (agenda.html) novamente (linha 37). Caso contrrio
instanciado um objeto LoginBean, inserido na sesso corrente e denida a pgina principal.jsp como a pgina para o reencaminhamento
da requisio (linhas 40 a 43). J o bloco que vai da linha 46 at a
linha 56 trata a requisio originada em uma pgina com a identicao 1 (pgina principal.jsp). Na linha 47 recuperado o objeto

Tpicos Avanados

203

HttpSession corrente. O argumento false utilizado para impedir a


criao de um novo objeto HttpSession caso no exista um corrente. Se
o valor do objeto for null, ento a requisio deve ser reencaminhada
para a pgina de login (linha 49). Caso contrrio instanciado um
objeto AcaoBean, inserido na requisio corrente, e denida a pgina
principal.jsp como a pgina para o reencaminhamento da requisio
(linhas 52 a 54). Na linha 58 a requisio reencaminhada para a
pgina denida (pgina agenda.html ou principal.jsp).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

package agenda ;
import j a v a x . s e r v l e t . ;
import j a v a x . s e r v l e t . h t t p . ;
import agenda . ;
public c l a s s A g e n d a S e r v l e t extends H t t p S e r v l e t

public void doGet ( H t t p S e r v l e t R e q u e s t req ,


{
}

HttpServletResponse resp )

performTask ( req , r e s p ) ;

public void doPost ( H t t p S e r v l e t R e q u e s t req ,

{
}

HttpServletResponse resp )

performTask ( req , r e s p ) ;

public void performTask ( H t t p S e r v l e t R e q u e s t req ,


{

HttpServletResponse resp )

String url ;
HttpSession sessao ;
S t r i n g c o r r e n t e = r e q . getParameter ( " c o r r e n t e " ) ;
int i c o r r =0;
i f ( c o r r e n t e ! = null )
icorr = Integer . parseInt ( corrente ) ;

try

switch ( i c o r r )

case 0 : S t r i n g l o g i n = r e q . getParameter ( " l o g i n " ) ;


S t r i n g senha = r e q . getParameter ( " senha " ) ;
i f ( l o g i n == null | | senha == null )
u r l = "/ agenda . html " ;

204
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

Java na prtica
else

case 1 :

s e s s a o = r e q . g e t S e s s i o n ( true ) ;
sessao . setAttribute (" loginbean " ,
new agenda . LoginBean ( l o g i n , senha ) ) ;
u r l = "/ p r i n c i p a l . j s p " ;

break ;
sessao = req . getSession ( false ) ;
i f ( s e s s a o == null )
u r l = "/ agenda . html " ;

else

r e q . s e t A t t r i b u t e ( " acaobean " ,


new agenda . AcaoBean ( r e q ) ) ;
u r l = "/ p r i n c i p a l . j s p " ;

break ;

}
getServletContext ( ) . getRequestDispatcher ( url ) .
f o r w a r d ( req , r e s p ) ;
} catch ( E x c e p t i o n e ) {
System . out . p r i n t l n ( " A g e n d a S e r v l e t f a l h o u : " ) ;
e . printStackTrace ( ) ;
}

Exemplo 7.26 AgendaServlet.java.


O exemplo 7.27 mostra o cdigo do JavaBean usado para realizar
a manuteno da agenda. O JavaBean AcaoBean responsvel pela
consulta, remoo e insero de novos itens na agenda. Um objeto
StringBuffer referenciado pela varivel ret utilizado pelo JavaBean
para montar o resultado da execuo. O construtor (linhas 17 a 28)
verica o tipo de requisio e invoca o mtodo apropriado.
O mtodo consulta() (linhas 30 a 96) responsvel pela realizao de consultas. As consultas podem ser realizadas sobre o campo
nome ou descrio e os casamentos podem ser parciais, uma vez que
usado o operador LIKE. A consulta SQL montada nas linhas 42 a
53. Na linha 56 obtida uma conexo com SGBD por meio do objeto
ConnectionBean. Na linha 64 o comando SQL executado e as linhas
67 a 85 montam o resultado da consulta.

Tpicos Avanados

205

O mtodo insere() (linhas 98 a 176) responsvel por inserir um


item na agenda. Na linha 119 obtida uma conexo com SGBD por
meio do objeto ConnectionBean. Para inserir um novo item preciso
obter o nmero do ltimo identicador usado, incrementar o identicador e inserir na base o item com o identicador incrementado. Esta
operao requer que no seja acrescentado nenhum identicador entre
a operao de leitura do ltimo identicador e a insero de um novo
item. Ou seja, necessrio que essas operaes sejam tratadas como
uma nica transao e o isolamento entre as transaes seja do nvel
Serializable. A denio do incio da transao feita no comando da
linha 127. A mudana do nvel de isolamento feita pelos comandos
codicados nas linhas 130 a 134. Na linha 136 invocado o mtodo
obtemUltimo() (linhas 178 a 201) para obter o ltimo identicador utilizado. As linhas 139 a 153 montam o comando SQL para a execuo.
O comando SQL executado na linha 155. O m da transao denido pelo comando da linha 156. Ao m da transao, de forma a no
prejudicar a concorrncia, o nvel de isolamento deve retornar para um
valor mais baixo. Isto feito pelos comandos das linhas 157 a 161.
O mtodo apaga() (linhas 203 a 236) responsvel por remover um
item da agenda. As linhas 206 a 211 contm o cdigo para vericar se
o usurio digitou o nome associado ao item que deve ser removido. As
linhas 212 e 213 montam o comando SQL para a execuo. Na linha 216
obtida uma conexo com SGBD por meio do objeto ConnectionBean.
O comando SQL executado na linha 224.
1 package agenda ;
2 import j a v a x . s e r v l e t . h t t p . ;
3 import j a v a . l a n g . ;
4 import j a v a . u t i l . ;
5 import j a v a . s q l . ;
6
7 public c l a s s AcaoBean
8 {
9
private Connection con=null ;
10
private S t r i n g B u f f e r r e t = null ;
11
private Statement stmt=null ;
12
private S t r i n g [ ] l e g e n d a=
13
{"C&o a c u t e ; d i g o " , "Nome" , " T e l e f o n e " ,
14
" Endere&c c e d i l ; o " , " e m a i l " , "hp" ,
15
" c e l u l a r " , " D e s c r i&c c e d i l ;& a t i l d e ; o " } ;
16
17
public AcaoBean ( H t t p S e r v l e t R e q u e s t r e q )
18
{
19
S t r i n g acao = r e q . g et Pa ra me te r ( " acao " ) ;
20
i f ( acao . e q u a l s ( " C o n s u l t a " ) )
21
{
22
S t r i n g nome = r e q . g et Pa ra me te r ( "nome" ) ;

206
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

Java na prtica

}
}

S t r i n g d e s c r i = r e q . g et Pa ra me te r ( " d e s c r i c a o " ) ;
c o n s u l t a ( nome , d e s c r i ) ;

e l s e i f ( acao . e q u a l s ( " I n s e r e " ) )


e l s e i f ( acao . e q u a l s ( "Apaga" ) )

i n s e r e ( req ) ;
apaga ( r e q ) ;

private void c o n s u l t a ( S t r i n g nome , S t r i n g d e s c r i )

S t r i n g c o n s u l t a = null ;

i f ( ( nome == null | | nome . l e n g t h ()<1) &&


( d e s c r i == null | | d e s c r i . l e n g t h () <1))

r e t = new S t r i n g B u f f e r (
" D i g i t e o nome ou d e s c r i c a o ! " ) ;
return ;

i f ( d e s c r i == null | | d e s c r i . l e n g t h () <1)

consulta =
"SELECT FROM PESSOA WHERE NOME LIKE '% "
+nome+"%'"+" ORDER BY NOME" ;
e l s e i f ( nome == null | | nome . l e n g t h () <1)
consulta =
"SELECT FROM PESSOA WHERE DESCRICAO LIKE '% "
+d e s c r i+"%'"+" ORDER BY NOME" ;
e l s e c o n s u l t a=
"SELECT FROM PESSOA WHERE DESCRICAO LIKE '% "
+d e s c r i+
" % ' AND NOME LIKE '% "+nome+" % ' ORDER BY NOME" ;

try

con=ConnectionBean . g e t I n s t a n c e ( ) . g e t C o n n e c t i o n ( ) ;
i f ( con == null )
{
r e t = new S t r i n g B u f f e r (
" S e r v i d o r ocupado . Tente mais t a r d e . ! " ) ;
return ;
}
stmt = con . c r e a t e S t a t e m e n t ( ) ;
R e s u l t S e t r s = stmt . executeQuery ( c o n s u l t a ) ;
r e t = new S t r i n g B u f f e r ( ) ;
r e t . append ( "<br><h3>Resultado </h3><br>" ) ;
while ( r s . next ( ) )
{
r e t . append ( "ID : " ) . append ( r s . g e t S t r i n g ( " i d " ) ) ;
r e t . append ( "<br>Nome : " ) . append (
r s . g e t S t r i n g ( "Nome" ) ) ;
r e t . append ( "<br>T e l e f o n e : " ) . append (
rs . getString (" Telefone " ) ) ;
r e t . append ( "<br>Endereco : " ) . append (
r s . g e t S t r i n g ( " Endereco " ) ) ;
r e t . append ( "<br>e m a i l : " ) . append (
rs . getString ( " email " ) ) ;

Tpicos Avanados
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

r e t . append ( "<br>hp : " ) . append (


r s . g e t S t r i n g ( "hp" ) ) ;
r e t . append ( "<br>c e l u l a r : " ) . append (
rs . getString (" celular " ) ) ;
r e t . append ( "<br>d e s c r i c a o : " ) . append (
rs . getString (" descricao " ) ) ;
r e t . append ( "<br><br>" ) ;

}
} catch ( E x c e p t i o n e )
{
System . out . p r i n t l n ( e . getMessage ( ) ) ;
}
finally {
ConnectionBean . g e t I n s t a n c e ( ) .
d e v o l v e C o n n e c t i o n ( con ) ;
try { stmt . c l o s e ( ) ; } catch ( E x c e p t i o n e e ) { } ;
}

private void i n s e r e ( H t t p S e r v l e t R e q u e s t r e q )

S t r i n g [ ] par =
{ " t e l e f o n e " , " e n d e r e c o " , " e m a i l " , "hp" ,
" celular " ," descricao " };
S t r i n g B u f f e r comando =
new S t r i n g B u f f e r ( "INSERT INTO PESSOA( " ) ;
StringBuffer values =
new S t r i n g B u f f e r ( " VALUES( " ) ;
S t r i n g aux = r e q . g et Pa ra me te r ( "nome" ) ;
i f ( aux == null | | aux . l e n g t h () <1)
{
r e t = new S t r i n g B u f f e r (
"<br><h3>D i g i t e o nome!</h3><br>" ) ;
return ;
}

try

con=ConnectionBean . g e t I n s t a n c e ( ) . g e t C o n n e c t i o n ( ) ;
i f ( con == null )
{
r e t = new S t r i n g B u f f e r (
" S e r v i d o r ocupado . Tente mais t a r d e ! " ) ;
return ;
}
con . setAutoCommit ( f a l s e ) ;
DatabaseMetaData meta=con . getMetaData ( ) ;

i f ( meta . s u p p o r t s T r a n s a c t i o n I s o l a t i o n L e v e l (
}

con . TRANSACTION_SERIALIZABLE ) ) {
con . s e t T r a n s a c t i o n I s o l a t i o n (
con . TRANSACTION_SERIALIZABLE ) ;

207

208

Java na prtica

135
136
int u l t = obtemUltimo ( con ) ;
137
i f ( u l t ==1) return ;
138
u l t ++;
139
comando . append ( " id , nome" ) ;
140
v a l u e s . append ( u l t+" , ' " ) . append ( aux ) . append ( " ' " ) ;
141
142
for ( int i =0; i <par . l e n g t h ; i ++)
143
{
144
aux = r e q . g et Pa ra me te r ( par [ i ] ) ;
145
i f ( aux ! = null && aux . l e n g t h () >0)
146
{
147
comando . append ( " , " ) . append ( par [ i ] ) ;
148
v a l u e s . append ( " , ' " ) . append ( aux ) . append ( " ' " ) ;
149
}
150
}
151
comando . append ( " ) " ) ;
152
v a l u e s . append ( " ) " ) ;
153
aux = comando . t o S t r i n g ()+ v a l u e s . t o S t r i n g ( ) ;
154
stmt = con . c r e a t e S t a t e m e n t ( ) ;
155
stmt . executeUpdate ( aux ) ;
156
con . setAutoCommit ( true ) ;
157
i f ( meta . s u p p o r t s T r a n s a c t i o n I s o l a t i o n L e v e l (
158
con .TRANSACTION_READ_COMMITTED) ) {
159
con . s e t T r a n s a c t i o n I s o l a t i o n (
160
con .TRANSACTION_READ_COMMITTED) ;
161
}
162
r e t = new S t r i n g B u f f e r (
163
"<br><h3>I n s e r i d o !</h3><br>" ) ;
164
return ;
165
} catch ( E x c e p t i o n e )
166
{
167
r e t = new S t r i n g B u f f e r ( "<br><h3>Erro : "+
168
e . getMessage ()+ "!</h3><br>" ) ;
169
}
170
finally
171
{
172
ConnectionBean . g e t I n s t a n c e ( ) .
173
d e v o l v e C o n n e c t i o n ( con ) ;
174
try { stmt . c l o s e ( ) ; } catch ( E x c e p t i o n e e ) { } ;
175
}
176 }
177
178 private int obtemUltimo ( Connection con )
179 {
180
String consulta =
181
"SELECT MAX( ID ) AS maior FROM PESSOA" ;
182
try
183
{
184
i f ( con == null )
185
{
186
r e t = new S t r i n g B u f f e r (
187
" S e r v i d o r ocupado . Tente mais t a r d e . ! " ) ;
188
return 1;
189
}
190
stmt = con . c r e a t e S t a t e m e n t ( ) ;

Tpicos Avanados
191
R e s u l t S e t r s = stmt . executeQuery ( c o n s u l t a ) ;
192
i f ( r s . next ( ) )
193
return I n t e g e r . p a r s e I n t ( r s . g e t S t r i n g ( " maior " ) ) ;
194
e l s e return 0 ;
195
} catch ( E x c e p t i o n e ) {
196
r e t = new S t r i n g B u f f e r ( "<br><h3>Erro : "+
197
e . getMessage ()+ "!</h3><br>" ) ;
198
return 1;
199
}
200
f i n a l l y { try { stmt . c l o s e ( ) ; } catch ( E x c e p t i o n e e ) { } ; }
201 }
202
203 private void apaga ( H t t p S e r v l e t R e q u e s t r e q )
204 {
205
S t r i n g aux = r e q . ge tP ar am et er ( "nome" ) ;
206
i f ( aux == null | | aux . l e n g t h () <1)
207
{
208
r e t = new S t r i n g B u f f e r (
209
"<br><h3>D i g i t e o nome!</h3><br>" ) ;
210
return ;
211
}
212
S t r i n g c o n s u l t a = "DELETE FROM PESSOA WHERE NOME = ' "
213
+aux+" ' " ;
214
try
215
{
216
con=ConnectionBean . g e t I n s t a n c e ( ) . g e t C o n n e c t i o n ( ) ;
217
i f ( con == null )
218
{
219
r e t = new S t r i n g B u f f e r (
220
" S e r v i d o r ocupado . Tente mais t a r d e . ! " ) ;
221
return ;
222
}
223
stmt = con . c r e a t e S t a t e m e n t ( ) ;
224
stmt . executeUpdate ( c o n s u l t a ) ;
225
226
r e t=new S t r i n g B u f f e r ( "<br><h3>Removido!</h3><br>" ) ;
227
} catch ( E x c e p t i o n e ) {
228
r e t = new S t r i n g B u f f e r ( "<br><h3>Erro : "+
229
e . getMessage ()+ "!</h3><br>" ) ;
230
}
231
finally {
232
ConnectionBean . g e t I n s t a n c e ( ) .
233
d e v o l v e C o n n e c t i o n ( con ) ;
234
try { stmt . c l o s e ( ) ; } catch ( E x c e p t i o n e e ) { } ;
235
}
236 }
237
238 public S t r i n g [ ] getLe g ( ) { return l e g e n d a ; }
239 public S t r i n g t o S t r i n g ( ) { return r e t . t o S t r i n g ( ) ; }
240 }

Exemplo 7.27 AcaoBean.java.

209

210

Java na prtica

Instalao da Aplicao
Para instalar crie a seguinte estrutura de diretrio abaixo do diretrio
webapps do Tomcat:

Figura 7.29 Estrutura de diretrios para a aplicao agenda.


O arquivo web.xml deve ser alterado para conter mapeamento entre
a URL agenda e o Servlet AgendaServlet.
...
<webapp>
< s e r v l e t>
<s e r v l e t name>
agenda
</ s e r v l e t name>
<s e r v l e t c l a s s>
agenda . A g e n d a S e r v l e t
</ s e r v l e t c l a s s>
</ s e r v l e t>
<s e r v l e t mapping>
<s e r v l e t name>
agenda
</ s e r v l e t name>
<u r l p a t t e r n>
/ agenda
</ u r l p a t t e r n>
</ s e r v l e t mapping>

...
</webapp>

Figura 7.30 Arquivo web.xml para a agenda.

Tpicos Avanados

211

Consideraes sobre a soluo


A aplicao descrita implementa uma agenda que pode ser acessada por
meio da Internet, no entanto, devido falta de espao e necessidade
de destacarmos os pontos principais, alguns detalhes foram deixados de
lado, como por exemplo, uma melhor interface com o usurio. Abaixo
seguem alguns comentrios sobre algumas particularidades da aplicao:
1. O JavaBean da classe LoginBean armazenado na sesso para
permitir a vericao se o acesso ao site autorizado. Isto
impede que os usurios tentem acessar diretamente a pgina
principal.jsp da agenda. Caso tentem fazer isso, a sesso no
conter um objeto LoginBean associado e, portanto, o acesso ser
recusado.
2. O JavaBean da classe AcaoBean armazenado no objeto req uma
vez que suas informaes so alteradas a cada requisio. Uma
forma mais eciente seria manter o objeto AcaoBean na sesso e
cada nova requisio invocar um mtodo do AcaoBean para gerar
os resultados. No entanto, o objetivo da nossa implementao
no fazer a aplicao mais eciente possvel, e sim mostrar
para o leitor uma aplicao com variadas tcnicas.
3. Apesar de termos adotado o padro MVC de desenvolvimento a
aplicao no exibe uma separao total da camada de apresentao (Viso) em relao camada do modelo. Parte do cdigo
HTML da viso inserido pelo AcaoBean no momento da construo da String contendo o resultado da ao. Isto foi feito para
minimizar a quantidade de cdigo Java na pgina JSP. Podese argumentar que neste caso a promessa da separao entre as
camadas no cumprida totalmente. Uma soluo para o problema seria gerar o contedo em XML e utilizar um analisador
de XML para gerar a pgina de apresentao. No entanto, o uso
da tecnologia XML foge ao escopo deste livro.
4. A soluo apresenta cdigo redundante para criticar as entradas
do usurio. Existe cdigo JavaScript nas pginas, e cdigo Java
no Servlet e JavaBeans. O uso de cdigo JavaScript nas pginas
para crticas de entrada indispensvel para aliviarmos a carga
sobre o servidor. J o cdigo para crtica no servidor no causa
impacto perceptvel e til para evitar tentativas de violao.

ndice
B2B, 189
B2C, 189
BLOB, 77
bytecode, 2

JSP, 137, 164

carrinho de compras, 184


CGI, 72
coleta de lixo, 4
Container, 138
convenes, 6
CORBA, 111, 119

Metadados, 89
MIME, 143
monitor, 33
MVC, 190

localhost, 62
lookup, 117

nvel de isolamento, 94
Naming, 116
notify, 39

Daemon Threads, 23
DMZ, 192

ODBC, 77, 107


ORB, 119

FTP, 69

ponteiros, 3
pool de conexes, 101
preemptivo, 25
prepared statements, 97
procedimentos armazenados,
98

green-threads, 25
HSQLDB, 79
HTTP, 69
Internet, 138
IP: nmero, 58

Race Conditions, 32
rebind, 116
redes, 55
redirecionando requisies, 187
reencaminhando requisies,
187
Regies Crticas, 32
registry, 115

java.rmi.Remote, 113
java.rmi.RemoteException,
113
JDBC, 75
JDBC-ODBC, 107
JNDI, 115
join, 22

212

Tpicos Avanados
resume, 23
RMI, 111
rmic, 115
Round-Robin, 26
Runnable, 13
Scriptlets, 170
Sees Crticas, 32
semforo, 50
Servlets, 137
SGBD, 75
sleep, 19
socket, 61
SQL, 75
stop, 23
stored procedures, 98
suspend, 23
synchronized, 34
TCP, 57
Thread, 7
ThreadGroup, 44
Tomcat, 143
transao, 92
UDP, 58, 66
UnicastRemoteObject, 114
URI, 70
URL, 69, 85
wait, 39
yield, 21

213

214

Java na prtica

Bibliograa
[1] Eckel B. Thinking in Java. 3rd Ed. New Jersey: Prentice Hall,
2003.
[2] Elmasri R. e Navathe S. B. Fundamentals of Database Systems.
3rd Ed. Vancouver: Addison Wesley, 2000.
[3] Gosling J., Joy W., Steele G. The Java Language Specication.
Massachusetts : Addison-Wesley, 1996.
[4] Elmasri R., Navathe S. Fundamentals of Database Systems. 3rd
Ed. Massachusetts : Addison-Wesley, 2000.
[5] Oaks S., Wong H. Java Threads. 2nd Ed. California : O'Reilly and
Associates, Inc, 1999.
[6] Sadtler C. et al. Patterns for e-business: User-to-Business Patterns for Topology 1 and 2 using WebSphere Advanced Edition.
IBM RedBooks, California, April 2000.
[7] Silberschatz A., Forth H., Sudarshan S. Database Systems Concepts. McGraw-Hill, 1997.
[8] Wahli U. et al. Servlet and JSP Programming with IBM WebSphere
Studio and VisualAge for Java, IBM RedBooks, California, May
2000.
[9] Watt D. A. Programming Language Concepts and Paradigms.
Great Britain : Prentice Hall, 1990.

215

Das könnte Ihnen auch gefallen