universidade tecnológica federal do paraná departamento

Propaganda
UNIVERSIDADE TECNOLÓGICA FEDERAL DO PARANÁ
DEPARTAMENTO ACADÊMICO DE INFORMÁTICA
ESPECIALIZAÇÃO EM TECNOLOGIA JAVA
ALESSANDER FECCHIO
JAVA EE 5: DESENVOLVENDO APLICAÇÕES CORPORATIVAS
CURITIBA
2006
UNIVERSIDADE TECNOLÓGICA FEDERAL DO PARANÁ
DEPARTAMENTO ACADÊMICO DE INFORMÁTICA
ESPECIALIZAÇÃO EM TECNOLOGIA JAVA
ALESSANDER FECCHIO
JAVA EE 5: DESENVOLVENDO APLICAÇÕES CORPORATIVAS
Trabalho apresentado como requisito para a
obtenção de título de especialista em tecnologia
Java, da Universidade Tecnológica Federal do
Paraná.
Orientadora: Prof. Ana Cristina B. Kochem
Vendramin.
CURITIBA
2006
SUMÁRIO
1 Introdução.................................................................................................................................. 8
2 O Java........................................................................................................................................ 9
2.1 Uma breve história do Java..................................................................................................9
2.2 Nomenclatura e versionamento do Java ..............................................................................12
2.3 Conceitos fundamentais da estrutura da plataforma Java .....................................................13
2.3.1 Java é uma linguagem interpretada.............................................................................14
2.3.2 Edições do Java .........................................................................................................15
3 Visão geral do Java EE.............................................................................................................. 17
3.1 Modelo de desenvolvimento do Java EE.............................................................................17
3.2 Componentes Java EE.......................................................................................................18
3.2.1 Clientes Java EE........................................................................................................19
3.2.2 Componentes web.....................................................................................................19
3.2.3 Componentes de negócios.......................................................................................... 19
3.2.4 Outros componentes..................................................................................................19
3.3 Containers Java EE...........................................................................................................20
4 Tecnologias empregadas...........................................................................................................22
4.1 Ambiente de desenvolvimento integrado.............................................................................22
4.1.1 Utilização de recursos do sistema...............................................................................23
4.1.2 Aproveitamento do código já desenvolvido................................................................... 23
4.1.3 Adequação do IDE ao tipo de aplicação a ser desenvolvida..........................................24
4.1.4 Controle de versões...................................................................................................24
4.2 Servidor de aplicações.......................................................................................................24
4.3 MVC.................................................................................................................................25
4.4 Banco de dados.................................................................................................................27
4.4.1 MySql........................................................................................................................27
4.4.2 PostgreSQL...............................................................................................................28
4.4.3 Derby........................................................................................................................29
5 Uma Aplicação prática da tecnologia Java EE.............................................................................30
5.1 Ambiente de desenvolvimento............................................................................................31
5.1.1 Pré-requisitos.............................................................................................................31
5.1.2 Instalação dos software..............................................................................................31
5.2 Integração do NetBeans com o SJSAS...............................................................................32
5.3 Criação do banco de dados................................................................................................34
5.3.1 Conceitos sobre acesso a bancos de dados no Java....................................................37
5.4 Configuração do SJSAS.....................................................................................................43
6 Enterprise Java Beans...............................................................................................................46
6.1 Beans...............................................................................................................................47
6.2 Session beans...................................................................................................................47
6.2.1 Statefull beans...........................................................................................................47
6.2.2 Stateless beans.......................................................................................................... 48
6.3 Interfaces..........................................................................................................................48
6.4 Anotações.........................................................................................................................49
6.5 Container para aplicações cliente.......................................................................................49
6.6 Java Web Start..................................................................................................................50
6.7 Contexto...........................................................................................................................50
6.8 Tipos de arquivo ................................................................................................................51
6.9 Persistência de dados........................................................................................................51
6.10 Facades..........................................................................................................................52
7 Uma aplicação simples..............................................................................................................53
7.1 Session bean..................................................................................................................... 53
7.2 Interfaces..........................................................................................................................53
7.3 Aplicação cliente................................................................................................................54
7.4 Construção da aplicação com o NetBeans..........................................................................55
7.4.1 Criação de um projeto................................................................................................56
7.4.2 Criação do bean.........................................................................................................57
7.4.3 Programação do bean e das interfaces........................................................................58
7.4.4 Programação da aplicação cliente...............................................................................58
7.4.5 Deploy da aplicação...................................................................................................60
7.4.6 Execução do cliente...................................................................................................61
8 Prova de Conceito - uma aplicação completa..............................................................................62
8.1 Projeto..............................................................................................................................62
8.1.1 Diagrama de casos de uso.......................................................................................... 63
8.1.2 Diagrama de seqüência..............................................................................................63
8.2 Arquivos de configuração...................................................................................................64
8.3 Módulo EJB.......................................................................................................................65
8.3.1 Criação dos entity beans............................................................................................. 65
8.3.2 Entidade....................................................................................................................69
8.3.3 Entidades para chaves primárias.................................................................................71
8.3.4 Criação dos session beans.........................................................................................72
8.3.5 Persistência...............................................................................................................74
8.3.6 Interfaces................................................................................................................... 75
8.4 Completando a aplicação EJB............................................................................................76
8.5 Acesso aos EJB num cliente desktop..................................................................................77
8.5.1 Listagem....................................................................................................................77
8.5.2 Inclusão.....................................................................................................................77
8.5.3 Pesquisa.................................................................................................................... 78
8.5.4 Atualização................................................................................................................78
8.5.5 Exclusão....................................................................................................................79
8.5.6 Criação de usuários.................................................................................................... 79
8.6 Acesso ao EJB numa aplicação web...................................................................................80
8.7 Documentação..................................................................................................................83
9 Conclusão................................................................................................................................87
Referências.................................................................................................................................89
Apêndice A - Script para criação das tabelas no banco de dados....................................................91
Apêndice B - Módulo EJB.............................................................................................................93
Apêndice C - Módulo cliente desktop........................................................................................... 113
Apêndice D - Módulo aplicativo web............................................................................................119
LISTA DE FIGURAS
Figura 1: O aparelho Star 7 [JAVA NET]......................................................................................... 9
Figura 2: Versões de Duke - o mascote Java [JAVA NET]..............................................................10
Figura 3: Esquema básico de programação, compilação e execução de um programa.....................15
Figura 4: Edições do Java e suas máquinas virtuais.......................................................................16
Figura 5: Diagrama das camadas do Java EE................................................................................18
Figura 6: Tipos de container do Java EE 5 [BALL 2006].................................................................21
Figura 7: Inicialização do SJSAS a partir do NetBeans...................................................................32
Figura 8: Mensagem de inicialização do Java DB...........................................................................33
Figura 9: Mensagem de inicialização do SJSAS.............................................................................33
Figura 10: Mensagem indicando que o SJSAS foi iniciado..............................................................33
Figura 11: Tela principal do ASADMIN..........................................................................................34
Figura 12: Menu para iniciar e parar o Java DB..............................................................................35
Figura 13: Mensagem de início do Java DB...................................................................................35
Figura 14: Configurações do banco de dados Maxigroupware......................................................... 35
Figura 15: Nova conexão criada....................................................................................................36
Figura 16: Componentes disponíveis na conexão com o banco de dados........................................36
Figura 17: Mensagens de criação das tabelas................................................................................ 37
Figura 18: Step 1 of 2 - Criação do pool de conexões.....................................................................41
Figura 19: Step 2 of 2 - Propriedades do pool de conexões............................................................41
Figura 20: Novo pool criado..........................................................................................................42
Figura 21: Criação de um recurso JDBC........................................................................................42
Figura 22: Recurso JDBC criado...................................................................................................43
Figura 23: Alteração da porta padrão do container web..................................................................45
Figura 24: Acesso de um bean por um cliente remoto....................................................................48
Figura 25: Criação de uma aplicação Enterprise no NetBeans........................................................56
Figura 26: Módulos criados pelo assistente Enterprise Application..................................................57
Figura 27: Criação de um session bean no NetBeans.....................................................................57
Figura 28: Programas criados pelo assistente de session beans.....................................................58
Figura 29: Atualização das interfaces............................................................................................58
Figura 30: Criação de uma classe Java simples.............................................................................59
Figura 31: Criação de uma nova classe Java .................................................................................59
Figura 32: Nova classe criada.......................................................................................................60
Figura 33: Diagrama de casos de uso..........................................................................................63
Figura 34: Diagrama de seqüência................................................................................................63
Figura 35: Arquivos de configuração da aplicação enterprise..........................................................64
Figura 36: Criação de entidades a partir do banco de dados...........................................................65
Figura 37: Escolha do datasource e das tabelas para criação das entidades...................................66
Figura 38: Nomenclatura e empacotamento das entidades.............................................................67
Figura 39: Criação da persistence unit...........................................................................................67
Figura 40: Entidade criadas no projeto..........................................................................................68
Figura 41: Entidades criadas no projeto.........................................................................................69
Figura 42: Criação de session beans.............................................................................................72
Figura 43: Assistente para criação de session beans...................................................................... 73
Figura 44: Empacotamento e escolha das interfaces a serem criadas.............................................73
Figura 45: Session bean e interface criados...................................................................................74
Figura 46: Regras de navegação da aplicação web........................................................................81
Figura 47: Acesso à ferramenta AutoComment..............................................................................84
Figura 48: Ferramenta AutoComment............................................................................................84
Figura 49: Geração da documentação...........................................................................................85
Figura 50: Mensagem de sucesso ao gerar a documentação..........................................................85
Figura 51: Página inicial da documentação....................................................................................86
LISTA DE SIGLAS
API
CRUD
CVS
DBCP
EAR
EJB
GCS
GPL
GUI
HTML
IDE
J2EE
J2ME
J2SE
JAR
Java EE 5
JCE
JDBC
JDK
JFC
JMS
JNDI
JPA
JSF
JSP
JVM
JWS
LCD
MVC
PCMCIA
PDA
SJSAS
UML
WAR
WSDP
Application Programming Interface
Create, Recover, Update, Delete
Concurrent Version System
Database Connection Pool
Enterprise Archive
Enterprise Java Beans
Gerência de Configuração de Software
General Public License
Graphic User Interface
Hyper Text Meta Language
Integrated Development Environment
Java 2 Enterprise Edition
Java 2 Micro Edition
Java 2 Standard Edition
Java Archive
Java Enterprise Edition 5
Java Cryptography Extension
Java Database Connectivity
Java Development Kit
Java Foundation Classes
Java Message Service
Java Naming and Directory
Java Persistence API
Java Server Faces
Anúncio da tecnologia Java Server Pages
Java Virtual Machine
Java Web Start
Liquid Crystal Display
Model-View-Controller
Personal Computer Memory Card International Association
Personal Digital Assistant
Sun Java System Application Server
Unified Modeling Language
Web Archive
Java Web Services Developer Pack
RESUMO
O desenvolvimento de aplicações corporativas utilizando a versão enterprise do Java sempre foi
considerada de grande complexidade, entre outros motivos pela grande quantidade e pela extensão
de seus arquivos de configuração. Uma vez que a especificação Java deixa em aberto a possibilidade
de cada fornecedor implementar suas próprias características aos servidores de aplicação, os
arquivos de configuração acabam por não seguir um padrão. A versão enterprise do Java, chamada
de Java EE 5, tem por objetivo simplificar o desenvolvimento de aplicações e abstrair os
desenvolvedores da complexa configuração dos servidores. O objetivo deste trabalho é demonstrar a
utilização da tecnologia Java EE 5 para o desenvolvimento de aplicações corporativas. O documento
inclui demonstrações de uso dos principais tópicos relacionados à tecnologia, como persistência de
dados, EJB, aplicações cliente desktop e web, bem como a utilização de servidores de aplicação
Java. Com isto, espera-se desmitificar a idéia de que o desenvolvimento em Java EE 5 é uma tarefa
árdua mesmo para desenvolvedores experientes.
Palavras-chave: Java, EJB, enterprise, persistência de dados, servidor de aplicações.
8
1 INTRODUÇÃO
O Java é considerado como um dos maiores fenômenos da informática em todos os
tempos, pela velocidade com que novos recursos são criados e disponibilizados para a comunidade
de desenvolvedores e usuários.
Nascida inicialmente como uma linguagem de programação para atender a um nicho de
mercado, o Java hoje é utilizado em aplicativos de todos os tipos, e também embarcado em milhares
de aparelhos ao redor do mundo.
É possível encontrá-lo em pequenos aplicativos ou utilitários, complexos sistemas
corporativos , ou em processadores de computadores de bordo de automóveis, por causa de sua
fantástica flexibilidade. Esta flexibilidade peculiar à linguagem fez com que ela se desenvolvesse
muito rapidamente, gerando outras tecnologias dela dependentes, como por exemplo os servidores
de aplicação.
Se por um lado esta gama de tecnologias ajudou a resolver problemas dos mais
diversos, por outro lado criou duas dificuldades aos profissionais de informática: a escolha da melhor
tecnologia a ser adotada, e no caso de escolher mais de uma, como integrá-las da maneira mais
eficaz.
As questões inerentes à integração destes componentes não são fáceis de responder.
Muitas empresas, pelos mais diversos motivos, optam por utilizar apenas uma tecnologia para
desenvolver toda sua aplicação. Mas nem sempre isto é possível num cenário onde se desenvolvem
aplicações que precisam ser executas em ambientes distintos, como web , estações de trabalho e
dispositivos móveis.
Tem-se então o problema da interoperabilidade. Apesar da padronização Java ser muito
rígida, e de tecnologias específicas para um ambiente (como o desktop, também chamado de estação
de trabalho) serem capazes de se comunicar com outras (como a internet), nem sempre a
comunicação é simples.
O objetivo deste trabalho é demonstrar como estas tecnologias podem ser integradas,
fornecendo maneiras de criar um ambiente robusto, ágil e seguro para a disponibilização de
aplicações corporativas.
9
2 O JAVA
2.1 UMA BREVE HISTÓRIA DO JAVA
O ano era 1991. O local, um pequeno escritório localizado na rua Sand Hill Road, em
Menlo Park. Lá, um grupo de treze pessoas liderado por James Gosling, Patrick Naughton e Mike
Sheridan isolou-se da Sun Microsystems e trabalhou arduamente num projeto secreto conhecido
apenas pelo codinome Green Project [JAVA]. O grupo, conhecido por Green Team, tinha a função de
antecipar e planejar o que estava por vir na área da computação. Eles acreditavam que um ponto
importante nesta evolução seria a convergência entre computadores e dispositivos pessoais comuns
(como geladeiras, por exemplo).
O resultado apareceu dezoito meses depois, na forma de um controlador de dispositivos
(uma espécie de controle remoto), através do qual um usuário poderia controlar sua geladeira, sua
torradeira, sua TV a cabo, e quaisquer dispositivos prontos para a tecnologia.
Conforme ilustra a Figura 1, o aparelho desenvolvido, conhecido como *7 (Star 7), era
uma handheld wireless, utilizando um processador SPARC, com tela Liquid Crystal Display (LCD)
colorida de 5 polegadas touchscreen, rede de 900 MHz, Personal Computer Memory Card
International Association (PCMCIA), codecs de áudio e vídeo. O aparelho tinha um novo
gerenciamento de energia e, para controlar tudo isso, uma versão do UNIX era executada em menos
de 1 MB de RAM – inclusive os drivers [JAVA NET].
Figura 1: O aparelho Star 7 [JAVA NET]
10
Segundo os responsáveis pelo projeto, o Star 7 também possuía
“...a new small, safe, secure, distributed, robust, interpreted, garbage collected, multi-threaded,
architecture neutral, high performance, dynamic programming language...” [JAVA NET]
Ou, numa tradução livre:
“...uma linguagem de programação pequena, segura, distribuída, robusta, interpretada, com
memória auto-gerenciada, multi-threaded, de arquitetura neutra, de alto desempenho e
dinâmica...”
Esta linguagem foi batizada de Oak (carvalho, em inglês) - uma árvore que James
Gosling podia ver de sua janela, enquanto trabalhava.
Um segundo produto nasceu daquela equipe: um cartoon, criado e desenhado por Joe
Palrang, chamado Duke (ver Figura 2). Duke era o assistente utilizado para o Star 7, e sua função era
ensinar o usuário a utilizar os recursos do equipamento. Com o fim do produto e o tempo passando,
acabou se transformando no mundialmente mascote Java [JAVA NET].
Figura 2: Versões de Duke - o mascote Java [JAVA NET]
O Star 7 carecia de um nicho de mercado onde poderia ser inserido. Inicialmente, a
equipe pensou que uma boa idéia seria controlar vídeo sob demanda através da TV a cabo e para
isso, chegou a construir um protótipo.
O grande problema era que a indústria de TV a cabo não tinha como oferecer o que o
Star 7 podia controlar. Nem mesmo infraestrutura existia e seria caríssimo para que apenas um grupo
de empresas a construísse. Ironicamente, o vídeo sob demanda e o controle da televisão digital é
hoje uma realidade no mundo, e tanto a Oak como o Star 7 estavam fadados ao desaparecimento.
Entretanto, um fato viria a mudar este aparente fracasso para uma das mais
estrondosas vitórias do mundo da informática: a internet.
A rápida
evolução
da internet
fez
com
que
uma imensa infraestrutura
de
telecomunicações e transmissão de dados fosse disponibilizada, calcada inicialmente na malha de
cabos e fios das empresas de telecomunicações. A infraestrutura que declarou o fim do Star 7,
repentinamente fora criada.
11
James Gosling, foi novamente incumbido de um projeto, dessa vez de preparar a Oak
para a internet. Em 1995, ele conclui seu trabalho, lançando uma nova versão do Oak , rebatizada de
Java [WIRED].
Java foi inteiramente desenvolvida para atuar em ambientes heterogêneos, como o da
internet. Assim, Java poderia ser executado diretamente nos browsers (navegadores de internet), na
forma de applets1 . Os browsers, que antes eram limitados a um conteúdo estático, podiam agora
exibir também conteúdo dinâmico. Isso fez com que o Java crescesse como nenhuma outra
linguagem de programação cresceu na história da informática, rapidamente sendo alçado à categoria
de plataforma [WIKIPEDIA 01].
Dez anos depois, não só a linguagem, mas toda a plataforma evoluiu muito, e alguns
números bem interessantes podem mostrar este crescimento [JAVA 01]:
•
4 milhões de desenvolvedores ao redor do mundo;
•
mais de 700 milhões de computadores;
•
mais de 700 milhões de celulares e outros dispositivos;
•
mais de 1 bilhão de smart cards;
•
impressoras, web cams, jogos, sistemas de navegação de automóveis e muitos
outros.
Hoje, o Java pode ser encontrado na internet, em computadores, laptops e telefones
celulares, e em equipamentos onde as pessoas nem imaginam, como geladeiras, fornos de
microondas e cartões de crédito.
A linha do tempo da Tabela 1 demonstra sua evolução.
Ano
Fato
1991
•
Lançamento do Green Project
1992
•
Lançamento da linguagem Oak, do Star7 e do Duke
1994
•
Lançamento do WebRunner, o primeiro navegador a suportar conteúdo
dinâmico
1995
1996
1
•
Nascimento do Java. Pai: James Gosling. Mãe: Sun Microsystems;
•
Anúncio oficial na SunWorld.
•
Lançamento do Java Development Kit (JDK) 1.0;
•
Primeira JavaOne (conferência de desenvolvedores);
•
JavaBeans , Servlets e outras tecnologias anunciadas;
•
Application Programming Interface (API) Java Card anunciada.
Um applet é um programa escrito em Java, embutido numa página web (dinâmica ou estática), que é executado na JVM da
estação cliente.
12
Ano
Fato
1997
•
Lançamento do JDK 1.1;
•
Lançamento do Java Servlet Developers Kit;
•
Anúncio da tecnologia Enterprise Java Beans (EJB);
•
Inclusão da tecnologia Java Foundation Classes (JFC) na plataforma Java.
•
Anúncio das JFC/"Project Swing";
•
Visa lança o primeiro smart card com tecnologia Java Card;
•
Lançamento do Java 2 para Linux;
•
Lançamento da plataforma Java 2.
•
Liberação do código fonte da plataforma Java 2;
•
Anúncio da tecnologia Java Server Pages (JSP);
•
Divisão oficial da plataforma Java 3 edições: Java 2 Standard Edition (J2SE),
1998
1999
Java 2 Enterprise Edition (J2EE), Java 2 Micro Edition (J2ME);
•
Liberação da plataforma J2EE;
•
Liberação da plataforma J2SE para Linux.
•
Liberação da plataforma J2SE 1.3;
•
Liberação da plataforma J2SE 1.3 para Apple Mac OS X.
2001
•
Liberação da Java Web Start 1.0.
2002
•
Lançamento do JDK 1.4;
•
Lançamento do Java Web Services Developer Pack (WSDP);
•
Lançamento da J2EE 1.4 Beta.
2004
•
Lançamento do Java 5.0.
2005
•
Java – 10º aniversário;
•
Aproximadamente 4,5 milhões de desenvolvedores utilizam Java.
•
Lançamento do Java Enterprise Edition 5 (Java EE 5), nova versão do J2EE
2000
2006
Tabela 1: Evolução da plataforma Java. [JAVA 02]
2.2 NOMENCLATURA E VERSIONAMENTO DO JAVA
Como é possível notar na Tabela 1, com o lançamento da versão 5 do Java, houve uma
grande mudança em sua nomenclatura, e a compreensão destes nomes e acrônimos torna-se
necessária para o completo entendimento da estrutura do Java.
13
As edições do Java (discutidas na seção 2.3.2) foram lançadas em 1999, pouco tempo
depois do lançamento do Java 2. O próprio nome Java 2 na realidade não se refere à versão 2 do
Java, e sim à versão 1.2. Esta estranha alteração de nome foi feita como uma jogada de marketing,
para mostrar que a linguagem havia sido radicalmente alterada, da sintaxe de alguns comandos até a
estrutura interna da Java Virtual Machine (JVM). Assim, havia o JDK 1.2 e o JRE 1.2 que eram a base
do Java 2. Esta diferença entre a versão do software e a versão da linguagem gerava muita confusão.
Em 2004, o Java 5 foi lançado, e com ele o novo padrão de nomenclatura, desta vez
bem simplificado. A comunidade pôde participar da definição da nomenclatura, e junto com o
departamento de marketing da Sun, chegaram à conclusão que o melhor caminho para a
simplificação seria simples: tirar o 2 e expandir o acrônimo.
Não existe Java 3 e nem o Java 4. A versão passou diretamente da versão 2 para a 5. O
motivo é simples: existe um número de versão utilizado internamente pela Sun e existe o nome
comercial. A versão utilizada internamente pela Sun atualmente é a 1.5. Para sincronizar a versão
interna com a versão comercial, optou-se por retirar a expressão "1." da versão comercial, gerando
assim o Java 5.
Oficialmente, a partir de junho de 2005, a nova nomenclatura foi adotada, sendo que de
imediato, as seguintes alterações foram realizadas:
•
J2SE 6.0 foi chamado de Java SE 6 e J2SE 7.0 será chamado de Java SE 7,
quando lançado;
•
J2EE 5.0 foi chamado de Java EE 5;
•
J2ME foi chamado de Java ME, pois não tem um número de versão.
Outro ponto importante do versionamento é que versões intermediárias do software não
mais serão lançadas, somente serão disponibilizadas versões para correção de erros. Novos recursos
e implementações serão sempre lançadas com as versões principais (Java 6, etc).
2.3 CONCEITOS FUNDAMENTAIS DA ESTRUTURA DA PLATAFORMA JAVA
Para se entender a plataforma Java, é necessário primeiro conhecer sua estrutura.
Por definição, plataforma é “um ambiente de hardware ou software no qual um
programa é executado” [JAVA 03]. Java é uma plataforma apenas de software, sendo executada
numa outra plataforma, composta de hardware e software (o sistema operacional, dependente do
hardware onde é executado).
14
A plataforma Java é composta de duas partes:
•
A JVM, responsável pela execução dos programas;
•
A Java API, conjunto de classes responsáveis por prover os mais diversos recursos,
como acessar bancos de dados.
2.3.1 Java é uma linguagem interpretada
O Java segue a filosofia Write Once, Run Everywhere (Escreva uma vez, execute em
todos os lugares). Um programa escrito em Java puro pode ser executado em todas as plataformas
disponíveis, do desktop ao mainframe.
Para que seja executado em todas as plataformas, o programa Java depende da JVM,
ou seja, Java é uma linguagem interpretada. O diferencial para as linguagens interpretadas mais
conhecidas (como o antigo BASIC), é que a VM não interpreta o programa original.
Ao ser compilado, um programa Java gera um código intermediário, que não é um
programa fonte, nem um executável. Este código intermediário – chamado de byte code – é que pode
ser interpretado pela VM [JAVA 03]. Como a execução do byte code depende apenas da VM,
qualquer sistema operacional que tenha uma VM pode executá-lo sem precisar ser reescrito. Por isto,
Java é considerado multi plataforma.
O processo pode ser melhor compreendido através da Figura 3.
15
Figura 3: Esquema básico de programação, compilação e execução de um programa
O fato de ser interpretado, fez com que o Java fosse conhecido como uma linguagem
lenta, de baixo desempenho. Atualmente, os avanços da informática e o empenho dos especialistas
da Sun em otimizar este componente conseguiram tornar o Java quase tão rápido quanto o C++,
embora essa afirmação seja fonte de muitas discussões em listas e fóruns na internet.
Existem três tipos de VM:
•
Java Card VM, utilizada em smart cards [JAVA CARD];
•
KVM, utilizada em dispositivos móveis como celulares e Personal Digital Assistant
(PDA) [KVM];
•
JVM, utilizada em computadores e alguns tipos de dispositivos móveis [JVM].
Cada uma das VMs tem como base uma tecnologia diferenciada, formada por uma ou
mais API. Por exemplo: a KVM utiliza a API para dispositivos móveis.
2.3.2 Edições do Java
Uma edição do Java é uma versão da plataforma que contém os recursos necessários
para atender um determinado segmento do mercado. Cada edição é formada por dois conjuntos de
API. Um deles é chamada de core, sendo o conjunto de bibliotecas que deve ser suportada por todas
as implementação compatíveis com a edição. O outro é opcional, sendo fornecido com a edição, e
16
pode ou não ser implementado por uma edição compatível. Opcionalmente, os pacotes adicionais
podem se tornar parte do core, se houver demanda do mercado.
O objetivo é que as classes que pertencem ao core estejam disponíveis em todos os
sistemas operacionais que possam executar o Java. Portanto, se um programa utiliza apenas as
classes do core, ele é 100% portável, podendo ser executado em qualquer plataforma.
Existem três edições do Java:
•
Java ME: utilizada em dispositivos móveis, normalmente com pequeno poder de
processamento, como celulares, PDAs e impressoras, entre outros. Oferece
funcionalidades que vão desde criar interfaces simples até protocolos complexos de
rede, passando por um robusto modelo de segurança [JAVA ME];
•
Java SE: utilizada para desenvolver e distribuir aplicativos em desktops e
servidores. Com ela também é possível desenvolver software embarcado e para
ambientes de real-time. Além disso, contém a base para o Java EE [JAVA SE];
•
Java EE: utilizada para o desenvolvimento de aplicações corporativas, de grande
porte, executadas num servidor. É formada pelo Java SE e um conjunto de
bibliotecas complementares, e provê serviços como web services, modelos de
componentes, API para gerenciamento e mensagens, entre outros recursos. É a
edição utilizada para o desenvolvimento deste trabalho [JAVA EE].
A Figura 4 demonstra as edições do Java, e a JVM utilizada por cada uma delas.
Figura 4: Edições do Java e suas máquinas virtuais
17
3 VISÃO GERAL DO JAVA EE
O Java EE é a edição mais abrangente do Java, pois engloba todas as tecnologias para
desenvolvimento em ambientes de servidor e desktop.
No desenvolvimento deste trabalho, é utilizado o Java EE 5, nova versão da plataforma
corporativa do Java. O grande objetivo dessa versão é simplificar o desenvolvimento de aplicações
corporativas, sem entretanto alterar os recursos disponíveis na versão 1.4.
As principais alterações do Java EE 5 em relação a sua versão anterior são [JAVA EE]:
•
Uso de annotations (anotações), que insere grande parte das configurações da
aplicação dentro do próprio código;
•
A versão 3.0 do EJB foi bastante simplificada;
•
Java Server Faces (JSF), um poderoso framework que possibilita o uso de
componentes similares aos de Graphic User Interface (GUI) em aplicações web;
•
Tecnologia de web services simplificada;
•
Java Persistence API, uma camada de persistência objeto-relacional que pode ser
utilizada também fora do contexto Java EE 5.
3.1 MODELO DE DESENVOLVIMENTO DO JAVA EE
O Java EE utiliza um modelo de múltiplas camadas para aplicações corporativas. Uma
aplicação é dividida em componentes de acordo com sua função, e os componentes podem ser
instalados em vários servidores, de acordo com a camada:
•
Componentes da camada cliente são executados na estação cliente;
•
Componentes da camada web são executados no servidor Java EE;
•
Componentes da camada de negócios são executados no servidor Java EE;
•
Componentes da camada de sistemas de informação (normalmente um banco de
dados) são executados num servidor próprio.
A Figura 5 mostra um diagrama das camadas do Java [BALL 2006].
18
Figura 5: Diagrama das camadas do Java EE
3.2 COMPONENTES JAVA EE
Aplicações Java EE são formadas por componentes. Componentes são unidades de
software funcionais e independentes, cujas classes e arquivos se comunicam com outros
componentes. A especificação Java define três componentes [BALL 2006]:
•
Clientes Java EE;
•
Java Servlets e JSP, que são componentes web da aplicação;
•
Enterprise Java Beans, que são componentes de negócios.
Cada um destes componentes pode acessar qualquer tecnologia Java disponível no
servidor Java EE (ou em um container, se for o caso). Uma descrição dos três componentes é
apresentada a seguir.
3.2.1 Clientes Java EE
Os clientes Java EE são executados na estação de trabalho, e são divididos em dois
tipos:
19
•
Aplicações desktop, que podem ter uma GUI ou uma interface por linha de
comando. Podem interagir com os componentes de negócio, acessando-os direta
ou indiretamente (por meio de conexões HTTP);
•
Um conjunto de navegador web e applet.
3.2.2 Componentes web
Os componentes web são executados no servidor (que pode ser um servidor Java EE
ou simplesmente um container JSP).
Há dois tipos de componentes web:
•
Java Servlets: classes que recebem uma requisição e a processam dinamicamente,
gerando conteúdo HTML como saída;
•
JSP: documentos texto plano, que são executados no servidor.
3.2.3 Componentes de negócios
Os componentes de negócio são executados no servidor Java EE, e contêm as regras
de negócio da aplicação. Entre outras funções, acessam bancos de dados, processam dados e os
reenviam, para os clientes ou para o próprio banco de dados. São os Enterprise Java Beans.
3.2.4 Outros componentes
Existe ainda um outro tipo de componente, chamado Java Bean, que não é considerado
um componente Java EE. Normalmente eles são utilizados para controlar o fluxo de dados entre uma
aplicação cliente e os componentes no servidor. Java Beans possuem propriedades e métodos get e
set para acessá-los. Utilizados desta maneira, são fáceis de implementar, mas devem seguir a
especificação Java quanto à nomenclatura utilizada.
3.3 CONTAINERS JAVA EE
Cada tecnologia disponível no servidor Java EE deve ser executada em um container.
Um container é um pequeno servidor dentro do servidor Java EE, especializado em um determinado
serviço. Por extensão, um servidor Java EE pode ser considerado um conjunto de containeres.
O mais famoso exemplo de container é o Tomcat, muitas vezes chamado de servidor
JSP [TOMCAT]. Na realidade, ele é um container responsável pela execução de Servlets e JSP.
Ficou tão conhecido como servidor por ser um bom substituto aos tradicionais servidores Java EE,
20
complexos de administrar e grandes consumidores de recursos de hardware. Ele tornou-se o padrão
de fato em containeres JSP, sendo utilizado atualmente por grande parte dos servidores Java EE do
mercado.
Quando uma aplicação é desenvolvida, seus módulos devem ser empacotados e
distribuídos para seus respectivos containeres. Empacotamento é o processo pelo qual todos os
programas, bibliotecas e arquivos de configuração são colocados num único arquivo compactado
chamado package [BALL 2006]. Uma das funções do servidor Java EE é receber o pacote e distribuir
cada módulo para seu respectivo container.
Uma vez que o container é dependente do servidor Java EE e não da aplicação, um
componente pode se comportar de maneiras diferentes, de acordo com a configuração do container.
Um exemplo: um EJB distribuído para um servidor Java EE de testes e também para um de
produção. Com os servidores configurados para acessar bancos de dados diferentes, o EJB
acessaria diferentes informações, sem que precisasse ser alterado.
Os tipos de container do Java EE são (ver Figura 6):
•
Container EJB: executa os EJB. O container, por sua vez, é executado dentro do
servidor Java EE;
•
Container web: executa JSP e servlets. É executado dentro do servidor Java EE;
•
Container da aplicação cliente: é executado na estação cliente, e é responsável
pela execução de aplicações desktop;
•
Container applet: executa os applets carregados em navegadores web, na estação
cliente. Normalmente, é formado pelo navegador e um plugin Java.
21
Figura 6: Tipos de container do Java EE 5 [BALL 2006]
22
4 TECNOLOGIAS EMPREGADAS
O que é mostrado a partir deste ponto é uma prova de tecnologia utilizando os principais
recursos da plataforma Java EE de maneira integrada. O foco não é a linguagem de programação em
si, embora em alguns momentos a discussão de alguns pontos seja necessária. O objetivo principal é
demonstrar como realizar a integração entre componentes distribuídos por plataformas tão diferentes
, como o desktop e um container EJB.
A seguir, são discutidos todas as tecnologias e software necessários à aplicação, e os
motivos pelos quais são utilizados neste trabalho.
4.1 AMBIENTE DE DESENVOLVIMENTO INTEGRADO
Todo desenvolvedor tem preferência por algum Integrated Development Environment
(IDE),
seja porque
consome menos
memória,
possui
mais
recursos, ou porque
geram
automaticamente quase a totalidade do código. Também existem desenvolvedores que não utilizam
IDEs, preferindo editores mais simples, que normalmente não geram código automaticamente.
IDE é um aplicativo que agrega várias ferramentas com o único objetivo de desenvolver
software . A maioria dos IDE possui ferramentas que permitem:
•
Editar o código fonte e formatá-lo dentro de padrões próprios ou definidos pelo
usuário;
•
Automatizar tarefas repetitivas, como gerar os pacotes de distribuição da aplicação;
•
Compilar, executar, testar e depurar o código;
•
Navegar pela estrutura do projeto;
•
Verificar erros de digitação e possíveis erros de compilação, propondo soluções
alternativas;
•
Integrar-se com ferramentas externas, como versionadores, servidores de aplicação
e utilitários de construção e distribuição;
•
Refactoring (propagação das alterações efetuadas em um componente para todas
as suas ocorrências no projeto – por exemplo, renomear uma classe);
•
Auditoria e otimização do código, para garantir a aderência a padrões e convenções
de mercado;
23
•
Suporte a plugins (extensões), componentes normalmente desenvolvidos por
terceiros, que podem adicionar funcionalidades ainda não existentes no IDE.
O processo de escolha de um IDE não deve considerar apenas os aspectos técnicos.
Um ferramenta, apesar de ser tecnicamente a melhor, pode não ser a mais adequada ao trabalho
desenvolvido. São comuns os casos de desenvolvedores que utilizam mais de um IDE, cada qual
com características únicas. Além das especificações técnicas, algumas características operacionais
também devem ser analisadas. Algumas delas são listadas a seguir.
4.1.1 Utilização de recursos do sistema
O IDE não deve consumir exageradamente os recursos do sistema, como memória. Isso
diminui a produtividade, pois desde o acesso aos menus do aplicativo até o processo de compilação o
IDE é prejudicado com a perda de desempenho.
4.1.2 Aproveitamento do código já desenvolvido
Um problema muito comum ao adotar uma nova ferramenta de desenvolvimento é que o
código desenvolvido com a ferramenta antiga não funciona como esperado no novo IDE. O problema
neste caso não é o código (que continua sendo executado sem erros), mas a maneira como os IDE
geram o código, que nem sempre é compreendido por outros IDE. Isto acontece porque cada
ferramenta possui um padrão de geração de código.
A grande dificuldade em migrar programas de uma ferramenta para outra não está no
que se vê, e sim no que não se vê. Quando um IDE abre uma classe para edição, realiza-se também
uma série de verificações, que vão desde o classpath da aplicação até a busca por erros de
compilação e dependências.
Adicionalmente, nos arquivos que possuem um editor gráfico (caso das GUI), é feito
também uma análise da estrutura do programa, que busca identificar como o código fonte pode ser
transformado em elementos visuais. Se esta estrutura estiver incorreta, o IDE não a reconhecerá, não
podendo executar o editor visual, embora o programa seja executado sem problemas.
Existe outro fator complicador: muitas vezes, as ferramentas disponibilizam recursos
que não são padrão no Java. Um bom exemplo são os gerenciados de layout . O SpringLayout , por
exemplo, não é implementado por nenhum IDE de mercado atualmente. O IDE que mais se aproxima
de uma implementação é o NetBeans, com o Matisse – gerenciador baseado no SpringLayout .
Alguém que desenvolva uma aplicação utilizando o Matisse não pode editá-la em nenhum IDE que
não seja o NetBeans.
24
4.1.3 Adequação do IDE ao tipo de aplicação a ser desenvolvida
Ao desenvolver aplicativos para um determinado ambiente, é natural que a ferramenta
escolhida para seu trabalho deva possuir recursos adequados à plataforma.
Como exemplo, o IDE Java Studio Creator, da Sun, foi criado especificamente para o
desenvolvimento de aplicações para a internet. Se o foco for desenvolver aplicativos para telefones
celulares, o NetBeans oferece grande quantidade de recursos (desde que a extensão apropriada seja
instalada). Já o principal nicho de utilização do JDeveloper - a t é s u a v e r s ã o 9 – e r a o
desenvolvimento de aplicações corporativas que utilizassem o banco de dados Oracle.
Para o desenvolvimento deste trabalho optou-se pela utilização do IDE NetBeans, na
versão 5.5 - projeto de código aberto mantido pela Sun. A escolha se deve ao fato do NetBeans ser
compatível com o tipo de aplicação desenvolvida, sendo um dos únicos com suporte completo ao
desenvolvimento de EJB na versão 3.0. Além de possuir um equilibrado conjunto de ferramentas,
como desenvolvimento de diagramas UML e monitoramento de memória.
Existe também a questão mercadológica. A Sun é a principal patrocinadora do
NetBeans, e todas as suas outras ferramentas de desenvolvimento são nele baseados. Precisando
popularizar o NetBeans (e conseqüentemente seus outros IDE), a Sun une esforços no sentido de
dotá-lo de recursos visando a facilidade de uso e o baixo consumo de recursos.
4.1.4 Controle de versões
Praticamente todos os IDEs de hoje possuem um pequeno gerenciador de versões, o
suficiente para desenvolvimento de pequenas aplicações. Entretanto, quando o desenvolvimento de
software é feito em grandes equipes, é necessário que o controle de versões seja centralizado. Para
isso, utiliza-se aplicativos de Gerência de Configuração de Software (GCS).
É desejável que a ferramenta utilizada possa ser integrada com algum software de GCS.
Normalmente isso não é considerado um problema, uma vez que praticamente todos os IDEs são
compatíveis pelo menos com o Concurrent Version System (CVS), um software livre de GCS que está
entre os mais utilizados no mundo [SAVANNAH].
4.2 SERVIDOR DE APLICAÇÕES
Muitas vezes os desenvolvedores se deparam com um dos grandes problemas do
desenvolvimento Java: a compatibilidade entre as ferramentas disponíveis no mercado. Este
problema é ainda maior quando se trata de uma tecnologia nova, como o Java EE 5. Não pela
tecnologia em si, mas pelo suporte que as ferramentas de desenvolvimento dão a ela.
25
Como exemplo, é possível citar o servidor de aplicações. No início do desenvolvimento
deste trabalho, apenas o GlassFish e o Sun Java System Application Server (SJSAS) tinham suporte
completo à especificação Java EE 5 - e isto porque o SJSAS é baseado no GlassFish. Outros
servidores são compatíveis apenas com alguns dos novos recursos da especificação.
A seguir, são apresentados os principais motivos pela escolha do SJSAS para o
desenvolvimento deste trabalho [GLASSFISH]:
•
É homologado pela Sun, dando suporte completo à especificação Java EE 5;
•
Consome poucos recursos do equipamento onde é executado, por não implementar
recursos avançados de gerenciamento, como clustering e computação em grade;
•
Foi desenvolvido especialmente para a versão 5 do Java, tirando proveito de todos
os novos recursos da linguagem;
•
Fácil administração;
•
É gratuito para ambientes de desenvolvimento e produção.
Um dos problemas causados pelo pioneirismo da implementação da especificação é
que não existe ainda uma grande comunidade de desenvolvedores, de modo que o suporte em caso
de problemas nem sempre é rápido.
4.3 MVC
MVC é o acrônimo de Model-View-Controller, uma arquitetura de software que separa
as camadas de modelo de dados (Model ), interface com o usuário (View) e lógica de negócio
(Controller), de modo que as alterações em uma camada causem o menor impacto possível nas
outras [SUNONE].
A camada do modelo é onde os processamentos são realizados, desde cálculos de
impostos sobre as vendas até a verificação se uma data é válida. Embora pelo padrão MVC não
exista uma camada específica para o acesso ao banco de dados, estas operações são implicitamente
realizadas pela camada do modelo.
A camada de visualização é responsável por transformar as informações do modelo em
componentes visuais, de modo que o usuário possa compreendê-las, como uma lista dos filmes
melhor avaliados de uma vídeo locadora.
Na camada de controle, as ações ordenadas pelo usuário na camada de visualização
são interpretadas pela aplicação, indicando qual ação da camada do modelo deve ser executada.
26
Esta separação garante certa independência entre as camadas, pois um elemento
nunca está presente em duas camadas distintas. Por exemplo, pode-se garantir que uma atualização
no banco de dados seja realizada unicamente na camada de modelo. Desta maneira, no caso de
alguma alteração no banco de dados, apenas um ponto da aplicação deve ser alterado. Do mesmo
modo, caso uma tela seja alterada na camada de visualização, ela em nada influencia nas demais
camadas.
Este padrão de arquitetura provocou o surgimento dos frameworks, software
construídos para fornecer infraestrutura a outros software. Eles são criados para que os
desenvolvedores possam se preocupar com os requisitos da aplicação a ser desenvolvida, e não com
a infraestrutura necessária para ele. Por exemplo, numa aplicação de comércio eletrônico, o
desenvolvedor deve estar focado em como um pedido deverá ser finalizado, e não em como navegar
sem erro entre as páginas – decisão tomada pela camada de controle.
Ultimamente, o padrão MVC tem sido fortemente empregado em aplicativos para a web ,
onde a complexidade pde desenvolvimento é maior que em ambientes cliente-servidor. Por este
motivo, várias implementações distintas apareceram, inclusive no ambiente Java. Duas delas
despontam como as mais utilizadas: Struts (mais antiga e mais utilizada, atuando no nível de páginas)
e JSF (atua no nível de componentes) [PLUGMASTERS].
O Struts é um projeto da Fundação Apache. É uma camada de controle MVC baseada
unicamente em tecnologias padrão Java além de várias bibliotecas da família Commons.
Seu ponto forte é o componente de controle, sendo facilmente integrado a outras
tecnologias, de modo a prover as camadas de modelo e visualização. Na camada de modelo, pode
interagir com tecnologias como JDBC, EJB e camadas de persistência como o Hibernate. Sua
camada de visualização pode ser construída utilizando JSP, JSF ou outros frameworks de
apresentação [STRUTS].
JSF é uma especificação aberta, que pode ser implementada por qualquer pessoa ou
empresa. De fato, além da implementação de referência da própria Sun (mantenedora da
especificação), a Fundação Apache também possui uma implementação chamada MyFaces.
Este framework está ganhando muitos adeptos, entre outros motivos por possuir uma
configuração mais simplificada que os demais frameworks disponíveis hoje. Mas existe outro ponto
que o diferencia dos demais. Desde o início de seu projeto, o objetivo do JSF sempre foi tratar cada
parte da aplicação como um componente, que por sua vez atende a todo o modelo de
desenvolvimento Java, como por exemplo o tratamento de eventos, que podem ocorrer até mesmo
dentro de uma página JSP, com a diferença de que este evento é disparado no servidor, e não no
cliente.
27
Para que os componentes de visualização (como listas, botões e caixas de texto)
pudessem tirar proveito desta característica, eles passaram a ser desenhados no servidor, e não mais
pelo navegador web . Todos os componentes do Hyper Text Meta Language (HTML, a linguagem
utilizada para se construir páginas da internet) foram substituídos por componentes JSF.
Por estas características, o JSF foi utilizado para o desenvolvimento deste trabalho,
utilizando a implementação de referência da Sun.
4.4 BANCO DE DADOS
Atualmente, existem diversos bancos de dados gratuitos e livres disponíveis no
mercado. Dentre eles, os mais conhecidos são o MySql, o PostgreSQL e mais recentemente o Derby
(desenvolvido e mantido pela Fundação Apache). Identificar qual o melhor deles é uma tarefa
bastante subjetiva, pois possuem características próprias que os levam a ser mais interessantes para
uso em algumas áreas, em detrimento de outras.
4.4.1 MySql
O MySql é um produto desenvolvido pela MySql AB (http://www.mysql.com). Foi criado
para satisfazer a necessidade de maior flexibilidade e desempenho para acesso aos dados da
empresa, que utilizava o mSQL. Segundo a empresa, o nome MySql não tem origem muito clara.
Enquanto alguns dizem que o nome se deve ao fato de que um grande número de bibliotecas tinham
o prefixo my, outros dizem que é uma homenagem à filha de um dos fundadores da empresa, Monty
Widenius, que se chama My. Assim, a origem real do nome MySql é um mistério para a própria
empresa [MYSQL].
Sem concorrentes de peso no chamado "mundo livre", sua utilização foi disseminada
pelo mundo todo, especialmente durante a expansão da internet (o chamado boom da internet). Entre
os motivos para o sucesso do MySql pode-se citar:
•
o seu alto desempenho;
•
o fato de ser gratuito para utilização em websites;
•
ser leve, consumindo poucos recursos de processamento e memória dos
servidores.
A necessidade de alcançar alto desempenho fez com que muitos recursos típicos de
bancos de dados como transações e stored procedures fossem deixado de lado em suas primeiras
versões, e alguns deles ainda não foram implementados nas versões mais recentes.
28
O MySql é licenciado de duas maneiras:
•
pela General Public License (GPL), se o software desenvolvido também utilizar uma
licença livre;
•
pela licença comercial da MySql AB, se o software for liberado por uma licença nãolivre ou for obtido lucro com ele.
4.4.2 PostgreSQL
O PostgreSQL, inicialmente chamado de Postgres, foi criado na Universidade de
Berkley (Califórnia) em 1986, pelo professor Michael Stonebraker, em substituição ao Ingres, banco
de dados que na época foi comprado pela Computer Associates. Postgres tem o significado de "após
o Ingres"). Ele foi desenvolvido pelo professor e seus alunos por oito anos, período no qual os
principais recursos de bancos de dados relacionais foram incorporados. O Postgres foi então
comercializado e se tornou o Illustra, que foi comprado pela Informix, que por sua vez foi comprado
pela IBM [POSTGRESQL].
Em 1995, após a substituição da linguagem interna do Postgres, ele foi rebatizado de
Postgres95, e no ano seguinte seu código foi aberto, sendo que um grupo de alunos de Berkeley
continuou a desenvolvê-lo. Após alguns anos e muitas modificações, foi novamente rebatizado, desta
vez como PostgreSQL. Sua primeira versão foi a 6.0, em memória aos longos anos de
desenvolvimento anteriores, que lhe deram a reputação de um banco de dados robusto e confiável.
Atualmente, o PostgreSQL está na versão 8.1.
Sendo um banco de dados livre, seguro, rápido e disponível em várias plataforma, o
PostgreSQL despertou o interesse de grandes corporações, que viram nele uma alternativa não só
econômica, mas principalmente tecnicamente viável aos caríssimos bancos de dados proprietários.
Por causa disto, várias delas (como a Fujitsu Australia, Red Hat e Sun Microsystems) estão
contribuindo com o projeto, seja financeira ou tecnicamente.
29
4.4.3 Derby
Em 1996 a Cloudscape Inc., empresa baseada em Oakland (Califórnia), foi fundada com
o objetivo de desenvolver tecnologias para bancos de dados em Java. A primeira versão de seu
produto foi lançada em 1997, com o nome de JBMS, sendo mais tarde rebatizado de Cloudscape. Em
1999, a Cloudscape foi adquirida pela Informix, que dois anos depois foi comprada pela IBM. O banco
de dados foi novamente renomeado, desta vez para IBM Cloudscape, que continuou a desenvolvê-lo,
mas desta vez com foco em bancos de dados embarcados. Em 2004, a IBM cedeu o código do IBM
Cloudscape para a Fundação Apache, que o transformou no Derby. Em julho de 2005, o Derby foi
lançado oficialmente.
Dentre as principais características do Derby pode-se citar [DERBY]:
•
é livre para qualquer tipo de uso;
•
totalmente desenvolvido em Java, o que garante sua execução em múltiplas
plataformas;
•
facilidade de uso para desenvolvedores e usuários finais, que não precisam
administrá-lo;
•
é pequeno – o banco de dados completo, com o motor e driver JDBC embarcado,
tem apenas 2 MB, o que garante alto desempenho e baixa utilização dos recursos
da máquina, permitindo seu uso até mesmo em telefones celulares;
•
baseado nos padrões Java e ANSI SQL, incluindo a sintaxe SQL, transações,
concorrência, triggers e backup on-line.
Tendo sido desenvolvido como um banco de dados embarcado, o Derby é facilmente
integrado em diversas ferramentas, entre elas o SJSAS, que o utiliza inclusive para armazenar os
dados internos do servidor – não impedindo sua utilização para qualquer tipo de aplicação. Da
mesma maneira, o NetBeans 5.5, acessa diretamente o Derby do SJSAS, permitindo operações
como criação de bancos de dados e tabelas e realização de consultas, entre outras.
Por todas estas características, o Derby foi utilizado no desenvolvimento deste trabalho.
30
5 UMA APLICAÇÃO PRÁTICA DA TECNOLOGIA JAVA EE
A aplicação base para este trabalho é um software gerenciador de projetos. Foram
desenvolvidos apenas os módulos necessários para a demonstração das tecnologias envolvidas. A
mesma linha foi adotada quanto aos recursos do servidor de aplicações Java EE, onde apenas foram
configurados os recursos necessários para o desenvolvimento do aplicativo.
É importante frisar que o objetivo deste trabalho não é ser uma referência para o ensino
da linguagem de programação Java . O objetivo é dar subsídios para o início do desenvolvimento de
aplicações que englobam várias das tecnologias disponíveis na plataforma Java EE 5.
Parte-se do pressuposto, então, que o leitor já possua conhecimentos da linguagem de
programação Java em ambientes desktop e web , bem como familiaridade com algum IDE e o
framework JSF.
Por conta disto, o enfoque maior é o que, e não como fazer. De fato, pouco código foi
escrito – o trabalho foi em grande parte feito pelo próprio IDE. Baseado neste código, os principais
conceitos e configurações serão discutidos.
O aplicativo a ser desenvolvido é bastante simples, e ao final do desenvolvimento, os
principais recursos tratados terão sido (não necessariamente nesta ordem):
1. Banco de dados
1.1. Utilização do Derby a partir do NetBeans;
1.2. Pool de conexões controlado pelo servidor de aplicações;
1.3. Recursos de acesso ao banco de dados controlado pelo servidor de aplicações;
1.4. Utilização de camada de persistência;
1.5. Utilização da Java Persistence API (JPA).
2. Camada de negócios
2.1. Beans
2.1.1. Interfaces locais e remotas;
2.1.2. Anotações.
2.2. Entidades
2.2.1. Para tabelas simples;
2.2.2. Para tabelas com chaves estrangeiras;
2.2.3. Para tabelas com chaves compostas;
31
2.2.4. Interfaces locais e remotas;
2.2.5. Facades.
2.3. Arquivos de configuração;
2.4. Utilização da Java Cryptography Extension (JCE).
3. Camada de visualização (desktop)
3.1. Acesso aos componentes de negócio a partir da aplicação desktop;
3.2. Utilização do container de aplicações cliente do SJSAS.
4. Camada de visualização (web )
4.1. Utilização de EJB a partir da aplicação web ;
4.2. Acesso aos recursos do contexto Faces;
5.1 AMBIENTE DE DESENVOLVIMENTO
Para a construção do aplicativo, é fundamental que o ambiente de desenvolvimento
esteja configurado. Ao final do procedimento a seguir, o ambiente deve estar instalado, integrado e
em funcionamento.
A correta configuração do NetBeans é fundamental para o desenvolvimento do projeto,
pois praticamente todas as operações serão realizadas através dele.
Todo o desenvolvimento foi realizado na plataforma Windows XP Professional, com o
Service Pack 2 instalado.
5.1.1 Pré-requisitos
•
JDK 1.5.0_03 ou acima. Neste trabalho, foi utilizada a versão 1.5.0_08, disponível
em http://java.sun.com/javase/downloads/index.jsp;
•
NetBeans 5.5, disponível em http://www.netbeans.org/downloads..
•
SJSAS, disponível no endereço http://java.sun.com/javaee/downloads/index.jsp. Ao
final da página, escolha o componente Sun Java System Application Server
Platform Edition 9, Multi-language.
5.1.2 Instalação dos software
O s software podem ser instalados em qualquer pasta do computador. Entretanto, é
importante que seja criada uma variável de ambiente chamada JAVA_HOME, cujo conteúdo é o
caminho para a pasta de instalação do JDK. Todos eles podem ser instalados com as configurações
default.
32
5.2 INTEGRAÇÃO DO NETBEANS COM O SJSAS
O NetBeans e o SJSAS são patrocinados pela Sun, e por isso são facilmente
integrados:
•
No NetBeans, acesse o menu Tools / Server manager;
•
Clique no botão Add Server;
•
Na tela que abrir, deixe os valores default e clique em Next;
•
No campo Platform location, informe a pasta de instalação do SJSAS;
•
Se já não estiver marcada, marque a opção Register Local Default Domain. A URL
localhost:4848...\domain1 é localizada automaticamente;
•
Clique em Next e, na próxima tela digite o usuário e senha de administração,
informados durante a instalação do SJSAS.
A partir deste momento, é possível iniciar e parar o SJSAS através do NetBeans. Para
testar a integração, o seguinte procedimento pode ser realizado:
•
Selecione a aba Runtime (está localizada no topo esquerdo da área de trabalho do
NetBeans), abra o nó Servers, acesse o menu de contexto e selecione Start,
conforme ilustra a figura a seguir.
Figura 7: Inicialização do SJSAS a partir do NetBeans
•
Na área de mensagens do NetBeans serão abertas duas janelas, uma chamada
Java DB Database Process e a outra Sun Java System Application Server.
•
O procedimento de inicialização termina quando as mensagens das Figuras 8 e 9
forem mostradas na área de output.
Figura 8: Mensagem de inicialização do Java DB
33
Figura 9: Mensagem de inicialização do SJSAS
•
Num navegador web, acesse o endereço http://localhost:8080 . Se o SJSAS foi
carregado corretamente, uma tela com a mensagem abaixo deve ser mostrada.
Figura 10: Mensagem indicando que o SJSAS foi iniciado
O container web do servidor de aplicações por padrão utiliza a porta 8080 para que as
aplicações seja mostradas aos usuários. Entretanto, o SJSAS possui uma aplicação que responde na
porta 4848, utilizada para administração e configuração do servidor, chamada de Admin Console
(Painel de Administração). Para acessá-la, basta utilizar o endereço http://localhost:4848. Informe o
usuário admin e a senha informada durante a instalação, e uma página como ilustra a Figura 11 é
mostrada.
Sempre que for necessário configurar algum parâmetro no SJSAS, o procedimento deve
se feito através do Painel de Administração.
Figura 11: Tela principal do ASADMIN
34
5.3 CRIAÇÃO DO BANCO DE DADOS
A criação do banco de dados e das tabelas necessárias ao aplicativo é feita através do
próprio NetBeans. Este procedimento é adotado pois o banco utilizado, o Derby, é embarcado no
servidor de aplicações, e não possui nenhum tipo de ferramenta visual.
Entretanto, o NetBeans possui um módulo básico de acesso a banco de dados que
permite executar instruções SQL, criar e excluir tabelas, além de outras opções. Este módulo utiliza
conexões JDBC, e é compatível com praticamente todos os principais produtos do mercado, entre
eles o Derby.
Uma observação se faz necessária. A Sun utiliza o Derby embarcado em vários de seus
produtos, como o SJSAS. Seu principal objetivo é ser um banco de dados para desenvolvimento,
para que programadores testem suas aplicações sem a necessidade de possuir uma infraestrutura
complexa. No procedimento a seguir, várias figuras fazem alusão ao Java DB, nome pelo qual a Sun
chama sua versão customizada do Derby.
O primeiro passo é criar um banco de dados para utilizar na aplicação.
•
Inicie o banco de dados. Para isto, acesse o menu Tools / Java DB Database / Start
Java DB Server (ver Figura 12). Se o SJSAS já tiver sido iniciado esta opção estará
desabilitada, pois o Java DB é inciado juntamente ao servidor de aplicações.
Figura 12: Menu para iniciar e parar o Java DB
•
Verifique na área de saída do NetBeans (parte inferior da tela) se o banco foi
iniciado (ver Figura 13).
Figura 13: Mensagem de início do Java DB
•
Acesse o menu Tools / Java DB Database / Create Java DB Database. Na tela a
seguir, informe os dados constantes na Figura 14 e clique em OK.
35
Figura 14: Configurações do banco de dados Maxigroupware
O local de gravação do banco de dados é indicado no campo Database Location. Para
alterar o local onde o Java DB cria os bancos de dados, basta seguir as instruções constantes na
própria tela.
•
Com o banco de dados criado, é criada também uma conexão para acessá-lo (ver
Figura 15). Acesse seu menu de contexto, e escolha a opção Connect... Informe a
senha, se necessário.
Figura 15: Nova conexão criada
•
Expanda a conexão, e vários componentes do banco de dados serão mostrados,
conforme ilustra a Figura 16.
Figura 16: Componentes disponíveis na conexão com o banco de dados
36
O segundo passo é criar as tabelas do banco de dados. A criação pode ser feita de duas
maneiras:
1.
Através da opção Create table, do menu de contexto da opção Tables;
2.
Através de scripts SQL.
Neste trabalho foi utilizado um script simples, que cria as três tabelas necessárias à aplicação. O
conteúdo do script está disponível no Apêndice A.
Para executar o script:
•
Acesse o menu de contexto de qualquer componente da conexão (incluindo ela
mesma) e escolha a opção Execute command;
•
Na janela que se abrir no NetBeans, digite o conteúdo do script e execute-o. Para
isto, clique no botão
da barra de ferramentas. As mensagens da Figura 17
serão mostradas.
Figura 17: Mensagens de criação das tabelas
•
Acesse o menu de contexto do nó Tabelas e escolha a opção Refresh. As tabelas
criadas serão mostradas.
As tabelas de projetos e usuários foram criadas com uma chave primária do tipo autoincremento, ou seja, o próprio banco de dados controla a geração dos códigos de projetos e usuários.
O problema desta abordagem é que campos de auto-incremento não são comuns a todos os bancos
de dados (por exemplo, Oracle e PostgreSQL utilizam as chamadas sequences ).
Esta abordagem foi utilizada apenas para fins didáticos, e não é a maneira ideal de se
controlar esta informação. O correto é criar seu próprio gerenciador de identidades, garantindo que
ele seja compatível com todos os bancos de dados. Entretanto, esta implementação não faz parte do
escopo deste trabalho.
37
5.3.1 Conceitos sobre acesso a bancos de dados no Java
Quando se fala em acessar bancos de dados utilizando Java, é necessário conhecer
três conceitos, nos quais se baseiam a conexão, a pesquisa e a utilização destes dados, otimizando
os recursos disponíveis de máquina. Estes conceitos são:
•
Conexão direta via Java Database Connectivity (JDBC);
•
Pool de conexões;
•
Camadas de persistência.
5.3.1.1 Conexão direta via JDBC
JDBC é o mecanismo básico de acesso ao banco de dados. Todos os acessos são
realizados através de conexões JDBC. É uma API completa que permite realizar desde simples
consultas até o gerenciamento completo do banco de dados.
Cada banco de dados tem um driver específico para acessá-lo. Este driver
(normalmente desenvolvido pelo próprio fabricante do banco de dados) é específico para o banco,
não havendo nenhum driver genérico.
No desenvolvimento tradicional, a cada acesso ao banco de dados é associada uma
conexão. Desta maneira, se num determinado método forem executados cinco acessos ao banco,
serão criadas cinco conexões. Estas conexões somente serão liberadas através de comandos no
próprio programa, ou então quando o banco o banco de dados enviar um sinal de timeout . Se muitas
conexões forem executadas simultaneamente (como num ambiente corporativo), o banco pode não
suportar a carga, perdendo desempenho.
Criar uma conexão pode consumir vários segundos, enquanto a instrução SQL
executada por ela pode consumir apenas milissegundos. Num ambiente internet, por exemplo, com
milhares de usuários, o consumo de recursos seria enorme. Por esta ineficiência, a conexão via
JDBC é pouco utilizada. Seu principal uso é a execução de pesquisa complexas, nas quais as
camadas de persistência normalmente têm baixo desempenho.
Para resolver este problema, são utilizados os pools de conexão.
5.3.1.2 Pool de conexões
O conceito de pool de conexões é bastante simples. Ao invés de criar as conexões sob
demanda, gerando sobrecarga ao banco de dados, cria-se um conjunto de conexões durante a carga
da aplicação. Estas conexões vão sendo utilizadas pela aplicação. Após o uso, as conexões são
38
liberadas. Quando todas as conexões do pool são utilizadas, novas conexões são recusadas, ou
então são adicionadas novas conexões ao conjunto já existente, aumentando sua capacidade (o
comportamento depende da configuração do pool) [IMASTERS].
Não são necessárias grandes quantidade de conexões dentro do pool, pois parte-se do
princípio que embora uma aplicação possa ter milhares de usuários, poucos deles farão acesso ao
banco de dados num determinado momento, e o tempo utilizado para o acesso é muito pequeno
(alguns milissegundos). Isto garante que sempre haja uma conexão disponível para uso.
Como as conexões não precisam mais ser criadas com grande freqüência, o
desempenho do acesso ao banco de dados é muito superior, e apenas o crescimento do número de
conexões é feito sob demanda. As conexões extras criadas serão canceladas pelo banco quando
expirar seu timeout , não sobrecarregando nem o servidor de aplicações, nem o de banco de dados.
Um pool de conexões pode ser facilmente implementado, sendo que existem boas
bibliotecas gratuitas disponíveis hoje, como o DBCP (acrônimo para Database Connection Pool), da
Fundação Apache [DBCP].
5.3.1.3 Camadas de persistência
Conceitualmente, uma camada de persistência permite o armazenamento em meio
físico das informações contidas num objeto.
Para uma melhor compreensão, tome-se por exemplo a tabela Projeto , criada no
banco de dados Maxigroupware. Sempre que um objeto do tipo Projeto precisar ser gravado no
banco de dados, deve-se obter os dados do objeto e executar um comando no banco de dados, já
com os dados do projeto, para gravação.
O tratamento manual desta operação pode provocar uma grande quantidade de
problemas. Por exemplo, se a estrutura da tabela for alterada no banco de dados, deve-se alterar,
recompilar e redistribuir o programa para os usuários.
O objetivo da camada de persistência é abstrair o desenvolvedor deste problema.
Utilizando vários recursos do Java, ao receber um objeto do tipo Projeto, ela sabe perfeitamente
quais dados obter do objeto, e a quais campos da tabela eles devem ser associados. Também
gerencia um pool de conexões próprio e centraliza o acesso ao banco de dados, facilitando a
manutenção do sistema.
O grande problema das camadas de persistência é que, às vezes, ela pode ser
ineficiente. Sendo bibliotecas genéricas, devem trabalhar da maneira mais padronizada possível, e
39
portanto não pode utilizar os recursos avançados típicos de cada banco. Prendendo-se a padrões
SQL, muitas vezes não seguidos pelos fornecedores de banco de dados, as camadas de persistência
têm aí o seu ponto fraco.
5.3.1.4 Pool de conexões no servidor de aplicações
Como citado anteriormente, o pool de conexões otimiza bastante o acesso ao banco de
dados, mas apresenta um problema. Cada aplicação deve controlar seu próprio pool. Aparentemente,
esta é uma tarefa simples, mas se for levado em consideração um ambiente corporativo, pode-se
chegar a alguns números interessantes. Por exemplo: um ambiente com 80 aplicações, todas
acessando o mesmo banco de dados. Para cada uma delas deveria ser criado um pool com 10
conexões. Seriam utilizadas 800 conexões ao banco.
Para minimizar o problema, é possível criar um pool não na aplicação, mas no próprio
servidor de aplicações, e compartilhar este pool entre várias aplicações diferentes, otimizando o
acesso ao banco. No exemplo acima, poderia ser criado um único pool, com 10 conexões servindo a
todas as aplicações. Deixariam de ser utilizadas 790 conexões.
Obviamente, existem limitações. A principal delas é que cada pool pode acessar apenas
um banco de dados de cada vez – o que não impede que seja criado um pool para cada banco. Neste
caso (e ainda utilizando o exemplo acima), num ambiente com 20 bancos diferentes, seriam criados
20 pools, totalizando 200 conexões. Ainda assim, deixariam de ser criadas 600 conexões.
5.3.1.5 Criação do pool de conexões ao banco de dados
Novamente é utilizado o painel de administração do SJSAS.
•
No menu principal, acesse a opção Resources / JDBC / Connection Pools;
•
Na tela mostrada, clique no botão New;
•
Na nova tela mostrada (ver Figura 18) informe os dados abaixo:
Name..................: MaxigroupwarePool
ResourceType.....: javax.sql.DataSource
DatabaseVendor. . : Derby
•
Clique em Next;
•
Na tela seguinte (ver Figura 19), preencha apenas as seguintes propriedades:
•
No menu aparece o nome do novo pool conforme pode ser visto na Figura 20.
Clique sobre ele para editá-lo e exclua todas as propriedades não listadas no item
anterior. Clique em Save.
40
Figura 18: Step 1 of 2 - Criação do pool de conexões
Figura 19: Step 2 of 2 - Propriedades do pool de conexões
41
Figura 20: Novo pool criado
5.3.1.6 Criação do recurso JDBC
O recurso JDBC é o elo de ligação entre a aplicação e o pool de conexões. Quando for
necessário se conectar ao banco de dados, é este recurso que deve ser referenciado, o que
automaticamente seleciona o pool de conexões correto.
Para criar o recurso JDBC:
•
Acesse o menu Resources / JDBC / JDBC Resources (ver Figura 21 ). Depois,
clique em New...;
Figura 21: Criação de um recurso JDBC
42
•
Na tela mostrada, informe:
JNDI Name. . : jdbc/maxigroupware
Pool Name...: MaxigroupwarePool
•
Clique em OK;
•
O recurso foi criado (ver Figura 22).
Figura 22: Recurso JDBC criado
Uma consideração sobre o JNDI Name. JNDI significa Java Naming and Directory
Interface. O nome JNDI é utilizado para organizar e localizar componentes num ambiente de
computação distribuído, de maneira análoga a um índice de páginas amarelas encontrado em listas
telefônicas. Como conseqüência, o nome JNDI é o método mais importante de acesso aos recursos
do servidor de aplicações.
Dentro do servidor de aplicações, os componentes são agrupados em categorias. Podese compará-las a um diretório localizado no servidor de aplicações, dentro do qual estão diversos
recursos do mesmo tipo. A primeira parte do nome JNDI indica a pasta a ser pesquisada.
Por convenção, o nome do diretório com os recursos de banco de dados começa com
jdbc/. Assim, para localizar o recurso JDBC chamado maxigroupware , utilizamos o endereço
jdbc/maxigroupware.
5.4 CONFIGURAÇÃO DO SJSAS
O SJSAS em sua versão gratuita não pode ser considerado um servidor de aplicações
corporativo, devido à inexistência de recursos como computação em grade, balanceamento de carga
e alta escalabilidade, entre outros. Por isto, é considerado um servidor departamental.
Isto não impede que ele seja utilizado em ambientes com grande quantidade de
processamento, mas não existem garantias quanto ao desempenho em caso de sobrecarga.
Outra característica é que após sua instalação, ele está pronto para ser utilizado. Suas
configurações iniciais sugerem sua utilização num ambiente não muito pesado, e para isto ele é uma
43
ótima opção. Vale ressaltar que o SJSAS é baseado no GlassFish, projeto de código aberto
patrocinado pela Sun, e que o GlassFish nas próximas versões será distribuído com recursos
avançados de escalabilidade e tolerância a falhas [GLASSFISH WIKI].
Com isto, nenhuma configuração é realmente necessária para este trabalho. Entretanto,
foi alterada a porta padrão do servidor HTTP.
Por padrão, todas as requisições HTTP são feitas na porta 80 do servidor, e por este
motivo, não é necessário informá-la nos endereços web. Por exemplo, quando o endereço
http://localhost é digitado, a ausência do número da porta identifica que deve ser utilizada a porta 80.
Por outro lado, containeres web como o Tomcat utilizam por padrão a porta 8080,
mesmo respondendo a requisições HTTP. Por isso, é necessário indicar a porta na URL (por
exemplo: http://localhost:8080).
Para facilitar a digitação das URL utilizadas nos exemplos, a porta padrão do container
web do SJSAS foi alterada para 80, dispensando a informação da porta nos endereços.
Todas as configurações do SJSAS serão feitas a partir de sua página de administração.
•
Num navegador, acesse o endereço http://localhost:4848/asadmin.
•
Informe o usuário admin e a senha informada durante a instalação do servidor de
aplicações (ou outra, se ela foi alterada). É mostrado o painel de administração.
•
No menu à esquerda, acesse: Configuration / HTTP Service / HTTP Listeners / httplistener-1;
•
Altere a opção Listener Port para 80;
•
Clique no botão Save;
•
Para testar a configuração, acesse o endereço http://localhost em um navegador.
Uma tela com o conteúdo mostrado na Figura 10 deve ser mostrada.
Veja as opções na Figura 23.
44
Figura 23: Alteração da porta padrão do container web
45
6 ENTERPRISE JAVA BEANS
O Java EE não é uma tecnologia simples. Ao contrário, ela é muito complexa, o
suficiente para não ser tratada como uma tecnologia monolítica, mas formada por partes menores,
chamadas de componentes . O conceito de componente deve ser bem compreendido antes de
qualquer desenvolvimento em Java EE.
A universidade de Princeton (localizada em Princeton, nos Estados Unidos) possui um
interessante serviço chamado de WordNet, que é essencialmente um dicionário léxico [PRINCETON].
Lá, o conceito de componente é:
“...um artefato que é uma parte individual de uma entidade composta, especialmente uma parte
que possa ser separada de ou anexada a um sistema...”.
Entretanto, componentes de software vão além disto. Eles são uma parte concreta do
sistema, um código escrito para representar o comportamento de um conceito abstrato. Por exemplo
um componente chamado AmortizaFinanciamento deve conter todo o código necessário para realizar
a amortização de um financiamento (com todas as particularidades que o processo de amortização
possui), e interagir com elementos como pessoas, empresas, e até mesmo outros componentes
[SRIGANESH 2006].
Um componente é independente, e se for bem construído pode ser reutilizado por outros
componentes e sistemas. Quando distribuído, deve ser empacotado juntamente com todos os
recursos necessários para seu funcionamento, como arquivos e configurações, de modo que ele
possa existir por si só, sem depender da aplicação original. Desta maneira, um sistema pode ser
formado por vários componentes reutilizados, cada um com sua funcionalidade específica.
Com um bom conjunto de componentes reutilizáveis, é possível montar um sistema
inteiro simplesmente definindo as ligações entre eles.
6.1 BEANS
Beans são componentes reutilizáveis, que realizam algum tipo de trabalho quando
acionados pelas aplicações clientes, encapsulando a lógica do negócio [JAVABEANS]. Podem, por
46
exemplo, consultar um preço, processar o cancelamento de nota fiscal, ou apenas armazenar os itens
de um carrinho de compras de uma aplicação de comércio eletrônico.
Desta maneira, não é necessário (nem recomendável) desenvolver a lógica de negócio
nas aplicações cliente. Isto permite acessar os beans de várias maneiras: numa aplicação web , numa
aplicação desktop ou através de web services.
Existem dois tipos de beans [BALL 2006]:
•
Session beans: realizam operações para os clientes, e podem conter web services;
•
Message driven beans: atuam como listeners para algum tipo de mensagem,
definidas pela API Java Message Service (JMS).
Neste trabalho, são utilizados apenas os Session Beans que, deste em ponto em diante
são tratados simplesmente como beans.
6.2 SESSION BEANS
Um session bean representa uma única instância do cliente, dentro do servidor de
aplicações. A única maneira de um cliente acessar as informações da aplicação são os métodos dos
beans , o que abstrai o cliente completamente da complexidade da aplicação.
Um bean é único e atende somente a um cliente que o acessa através de uma sessão
(daí o nome de session bean). Um bean não pode ser compartilhado entre sessões, nem persistido
(gravado em banco de dados, por exemplo). Uma vez que o cliente finaliza a sessão, o bean não é
mais associado a ela, e simplesmente é destruído.
Existem dois tipos de beans, classificados quanto à maneira que tratam seus estados
[BALL 2006]: stateless (os mais comuns) e statefull.
6.2.1 Statefull beans
O estado de um bean consiste nos valores de suas variáveis no decorrer da sessão. Um
statefull bean mantém esses valores enquanto durar a sessão do cliente. Se a aplicação cliente
remove o bean ou então é encerrado (por exemplo, o navegador é fechado), a sessão termina e o
bean é destruído. Caso contrário, mesmo que o bean termine de ser utilizado, ele permanece
disponível no servidor, e pode ser acessado a qualquer momento, juntamente com os dados
previamente informados.
47
6.2.2 Stateless beans
Num stateless bean, as variáveis podem ter um estado, mas ele somente é válido
durante a execução do método que chamou o bean. Quanto a execução termina, o estado das
variáveis não é retido.
À exceção de quando um método é executado, todas as instâncias de um stateless
bean são iguais, permitindo ao container EJB alocar qualquer instância para qualquer cliente. Esta
característica permite que eles sejam utilizados por vários clientes, e por isto são utilizados em
aplicações que tenham grande número de usuários simultâneos, otimizando a carga do servidor e
conseqüentemente seu desempenho.
Outra característica deste tipo de bean é que ele é o único que pode implementar web
services.
6.3 INTERFACES
Um cliente não pode acessar um bean diretamente. Por mais métodos que um bean
possua, o cliente só pode acessar os que forem declarados em suas interfaces. Isto é importante,
pois um bean pode ter métodos para seu uso próprio, que não são visíveis ao cliente. A Figura 24
mostra os passos para um cliente remoto acessar um bean.
Figura 24: Acesso de um bean por um cliente remoto
Interfaces são fundamentais para a construção de aplicativos de fácil manutenção. Além
de abstrair os clientes da complexidade da aplicação, permitem que o bean seja alterado sem afetar
os clientes. Se uma interface for escrita e algum dia for alterada, todos os clientes que a utilizam
deverão ser alterados também.
Existem três tipos de interfaces para acesso aos beans: remotas, locais e web services.
Os web services não são tratados neste trabalho.
As interfaces locais são utilizadas quando um bean é acessado por outro bean, e ambos
estejam na mesma JVM. Por exemplo: após realizar uma operação, um bean deve enviar um e-mail
para o responsável pelo processo. O bean que envia a mensagem é acessado somente para este tipo
48
de uso. Sendo acessado somente pelos beans já criados no container EJB, ele somente necessita da
interface local.
A s interfaces remotas são utilizadas quando aplicações externas ao container EJB
acessam os beans lá mantidos. Por exemplo, se uma aplicação web precisa acessar um bean,
somente pode fazê-lo a partir de uma interface remota, pois a aplicação web é executada em outro
container.
Como última observação, é necessário ressaltar que um bean pode implementar as
duas interfaces, sendo então referenciados por clientes remotos ou locais.
6.4 ANOTAÇÕES
Nas versões anteriores da especificação J2EE (nome do Java EE, até a versão 1.4),
todas as configurações necessárias à aplicação era feita em arquivos XML. Nestes arquivos,
chamados de deployment descriptors (descritores de publicação) eram especificados os beans
constantes da aplicação, se estes eram stateless o u statefull, se eram acessados remota ou
localmente, entre outras informações. Esta quantidade de informações gerava arquivos muito grandes
e de alta complexidade, o que por extensão tornava o desenvolvimento J2EE extremamente difícil e
demorado.
Na especificação Java EE 5, um dos principais objetivos é simplificar o desenvolvimento
e aumentar a produtividade. Para isso, parte das configurações antes descritas em arquivos XML são
agora inseridas na própria codificação do programa, através das annotations (anotações), e o
trabalho pesado ficou a cargo do servidor de aplicações. Como resultado direto, os arquivos de
configuração tiveram seus tamanhos (e complexidade) reduzidos drasticamente.
As anotações no Java são sempre precedidas do símbolo da arroba (@).
6.5 CONTAINER PARA APLICAÇÕES CLIENTE
O servidor de aplicações possui um container desenvolvido especificamente para
executar aplicações cliente. O principal objetivo é facilitar a distribuição e execução da aplicação em
ambiente distribuído. Neste container, o próprio servidor de aplicações se encarrega de fornecer as
bibliotecas necessárias à sua execução.
Quando se desenvolve um cliente, este normalmente faz referências a várias bibliotecas
(por exemplo, um componente para desenho de telas). O IDE envia as bibliotecas necessárias
juntamente com a aplicação e todas as configurações necessárias, como o classpath. O servidor de
49
aplicações então se encarrega de prover toda a infraestrutura necessária para a execução da
aplicação.
6.6 JAVA WEB START
Outro motivo para utilizar o container de aplicações cliente, é que normalmente os
clientes são desenvolvidos utilizando uma interface gráfica, como o Swing. O container se encarrega
de automaticamente disponibilizar a aplicação através do Java Web Start (JWS), sem que seja
necessário escrever uma única linha de código.
O JWS é uma tecnologia que permite distribuir e atualizar as aplicações cliente para
todos os usuários. Seu funcionamento é bastante simples: quando o usuário acessa a aplicação pela
primeira vez, o JWS copia a aplicação e todas as bibliotecas necessárias à execução para estação, e
depois a executa. Quando o usuário carrega a aplicação pela segunda vez, ao invés de copiar toda a
aplicação, o JWS copia apenas os arquivos alterados desde a última execução da aplicação pelo
usuário.
A tecnologia JWS permite que:
•
o usuário sempre tenha a última versão do aplicativo;
•
seja definida apenas uma origem para a aplicação, acabando com o problema de
enviar ao usuário algum tipo de mídia (CD ou disco flexível) ou de deixar a cargo do
usuário a instalação da nova versão.
6.7 CONTEXTO
Um contexto é uma área do servidor de aplicações onde ficam armazenadas as
informações dos EJB disponíveis. Basicamente, é um mapa relacionando objetos a seus respectivos
nomes, para que seja possível localizá-los no container EJB [JNDI].
Para acessar um EJB, é necessário primeiro criar um contexto, identificando o servidor e
a porta disponível para acessá-lo. Só então pode-se pesquisar o EJB, cujo nome sempre é relativo a
este contexto.
6.8 TIPOS DE ARQUIVO
Cada módulo de uma aplicação enterprise possui um tipo de arquivo diferente, que o
servidor de aplicações utiliza de maneiras diferentes. Embora estes arquivos possuam extensões
50
diferentes, todos eles são arquivos compactados no formato ZIP, que possuem internamente uma
estrutura de pastas e arquivos definida pela especificação Java.
Graças a este padrão, o servidor ou container onde o arquivo está sendo publicado sabe
interpretá-lo corretamente, e tomar as ações necessárias para disponibilizá-lo.
Estes arquivos são [BALL 2006]:
•
JAR: tipo mais comum de arquivo do Java, o Java ARchive tem por finalidade
agrupar classes para criar bibliotecas. Normalmente uma aplicação Java pode
conter várias centenas de classes e o “empacotamento” em uma biblioteca facilita a
disponibilização do aplicativo.
•
WAR: os Web ARchives são arquivos que contêm aplicações web completas, já
prontas para disponibilização num container JSP/Servlet como o Tomcat ou num
servidor de aplicações como o SJSAS.
•
EAR: são os Enterprise ARchives, que contêm aplicações empresariais completas.
Um EAR normalmente é formado por vários módulos, que podem ser arquivos JAR
e/ou WAR. Estes arquivos somente são manipulados corretamente por servidores
de aplicação.
6.9 PERSISTÊNCIA DE DADOS
A persistência de dados é um dos pontos mais importantes de qualquer sistema. Por
melhor que seja seu desempenho, se o acesso ao banco de dados for lento, o sistema também o
será. Por isto, a especificação Java EE 5 tem diversos recursos para facilitar este acesso [BALL
2006]:
•
Entity beans - ou simplesmente entidades, são os objetos responsáveis pelo acesso
direto aos bancos de dados utilizados numa aplicação. Uma entidade representa
uma tabela, e cada uma de suas instâncias corresponde a um registro desta tabela;
•
A JPA fornece meios para gerenciar o mapeamento objeto-relacional de objetos
Java para um banco de dados. O mapeamento objeto-relacional relaciona cada
propriedade da entidade com uma coluna da tabela.
•
Um PersistenceContext é um conjunto de instâncias de entidades no qual para cada
entidade existe apenas uma instância com um determinado valor de chave primária.
•
A API EntityManager é usada para executar operações no banco de dados, como
inclusão, exclusão, alteração e consulta. Uma vez realizada a operação no
EntityManager, o PersistenceContext e o banco de dados são automaticamente
atualizados.
51
•
O conjunto de entidades que podem ser acessadas por uma Entity Manager é
definido numa Persistence Unit. Ela supervisiona todas as operações de
persistência da aplicação. Sua configuração é feita no arquivo persistence.xml, que
também define o datasource e que tipo de operações podem ser realizadas, entre
outras informações.
•
Um datasource é um recurso criado no servidor de aplicações que possui
informações de conexão ao banco de dados, como usuário, senha, protocolo de
rede utilizado e outras informações. Utilizando um datasource, a aplicação não
precisa fazer nenhuma conexão através de JDBC, pois elas serão fornecidas pelo
próprio datasource.
6.10 FACADES
Facades s ã o session beans que encapsulam as chamadas a todos os serviços do
sistema. Quando se deseja executar uma ação do sistema, o cliente acessa um dos métodos da
classe facade, que por sua vez executa a tarefa necessária. [FACADE]
Não existe nenhum tipo de padrão quanto à quantidade de facades num sistema. É
possível construir sistemas de qualquer porte com apenas um facade e uma interface. Como beans
normais, não existe a obrigatoriedade de publicar todos os métodos da classe na interface.
Cada método da facade pode executar uma operação simples (como retornar o texto
“Olá, Mundo”) tanto como serviços complexos (como criar uma nota fiscal envolvendo processos
como expurgo de impostos e substituições tributárias, por exemplo).
52
7 UMA APLICAÇÃO SIMPLES
Este capítulo descreve um exemplo de aplicação contendo um EJB simples, suas
interfaces (remota e local), e um pequeno cliente em linha de comando para acessá-lo.
7.1 SESSION BEAN
O código abaixo é um stateless session bean simples. Sua função é unicamente
retornar a popular expressão Ola, Mundo.
package teste;
import javax.ejb.Stateless;
@Stateless
public class OlaMundoBean implements OlaMundoRemote, OlaMundoLocal {
public String digaOla() {
return "Ola, Mundo";
}
}
O primeiro ponto a observar é a anotação @Stateless. Esta anotação identifica o bean
como sendo do tipo stateless.
O segundo ponto é a implementação de duas interfaces, uma delas remota
( OlaMundoRemote ) e outra local (OlaMundoLocal). Isto possibilita ao bean ser acessado tanto por
clientes quanto por outros beans do mesmo container.
O único método do bean, digaOla, não possui nenhum argumento e retorna uma string
com o conteúdo Ola, Mundo .
7.2 INTERFACES
Como visto anteriormente, para executar um método do bean é necessário que sua
interface seja acessada. Neste exemplo, o bean implementa duas interfaces.
53
A interface remota tem o seguinte código:
package teste;
import javax.ejb.Remote;
@Remote
public interface OlaMundoRemote {
java.lang.String digaOla();
}
A anotação @Remote é o único código que identifica a interface como remota. Da
mesma maneira, na interface local o identificador de que a interface é local é a anotação @Local:
package teste;
import javax.ejb.Remote;
@Local
public interface OlaMundoLocal {
java.lang.String digaOla();
}
7.3 APLICAÇÃO CLIENTE
Um cliente simplificado para acessar o EJB, utilizando apenas uma janela do prompt de
comando do Windows tem o seguinte conteúdo:
package olamundo;
import
import
import
import
import
java.util.Properties;
javax.naming.Context;
javax.naming.InitialContext;
javax.naming.NamingException;
teste.OlaMundoRemote;
public class Main {
public static void main(String[] args) {
Main teste = new Main();
teste.executa();
}
public void executa() {
try {
Properties p = System.getProperties();
p.put(Context.PROVIDER_URL, "localhost:1099");
Context ctx = new InitialContext(p);
OlaMundoRemote olaMundoRemote =
(OlaMundoRemote)
ctx.lookup("teste.OlaMundoRemote");
System.out.println(olaMundoRemote.digaOla());
} catch (NamingException ex) {
System.out.println("EJB OlaMundo não encontrado");
}
}
}
Um contexto sempre é criado a partir das variáveis de ambiente do servidor. No
processo de criação, espera-se que esteja disponível uma variável de ambiente com um endereço
54
válido do servidor de nomes. Este servidor de nomes deve estar ativo e respondendo num porta
conhecida.
O servidor de nomes utiliza a tecnologia JNDI (ver seção 5.3.1.6).
Para criar a variável de ambiente, são executadas as linhas abaixo, o que indica uma
chave
chamada
java.naming.provider.url
(que
é
o
conteúdo
da
constante
definida
por
Context.PROVIDER_URL), cujo valor é o endereço localhost:1099.
Properties p = System.getProperties();
p.put(Context.PROVIDER_URL, "localhost:1099");
A criação do contexto é realizada pela instrução abaixo:
Context ctx = new InitialContext(p);
O contexto ctx é criado, e acessa o servidor JNDI especificado na variável de ambiente
previamente definida. A partir deste momento, é possível pesquisar o EJB disponíveis no contexto,
através do método lookup():
OlaMundoRemote olaMundoRemote =
(OlaMundoRemote) ctx.lookup("teste.OlaMundoRemote");
Nenhuma referência direta é feita ao EJB, mas sim à sua interface. Por este motivo, ao
pesquisar um EJB passamos como argumento o nome da interface correspondente. No exemplo, a
aplicação cliente é executada num container diferente do qual EJB está sendo executado, por isto é
referenciada sua interface remota.
A partir deste ponto, sempre que o objeto olaMundoRemote for referenciado, ele está
automaticamente acessando o EJB OlaMundoBean, pois este implementa a interface remota
OlaMundoRemote . Isto é facilmente verificado pela instrução abaixo:
System.out.println(olaMundoRemote.digaOla());
Esta instrução é a responsável por acessar o método digaOla do EJB.
7.4 CONSTRUÇÃO DA APLICAÇÃO COM O NETBEANS
Os passos a seguir criam a aplicação OlaMundo com a utilização do IDE NetBeans. Os
mesmos passos são utilizados para criar a aplicação de controle de projetos. Para isto, o NetBeans
deve estar sendo executado, e o servidor de aplicações deve ter sido iniciado, conforme descrito na
seção 5.2.
55
7.4.1 Criação de um projeto
•
Acesse o menu File / New Project;
•
Na tela mostrada, selecione Enterprise na janela da esquerda, e Enterprise
Application na janela da direita;
•
Clique em Next;
•
É mostrada uma tela com os dados da nova aplicação conforme ilustra a Figura 25.
Informe OlaMundo como nome do projeto. Os outros dados serão preenchidos
automaticamente, refletindo a alteração;
•
Se desejar, altere a pasta definida em Project Location;
•
Certifique-se que a opção Create Application Client Module esteja marcada;
•
Clique em Finish.
Figura 25: Criação de uma aplicação Enterprise no NetBeans
O projeto é criado, com quatro módulos: uma aplicação corporativa (enterprise), uma
aplicação cliente, um módulo EJB e uma aplicação web, conforme ilustra a Figura 26.
56
Figura 26: Módulos criados pelo assistente Enterprise Application
7.4.2 Criação do bean
O bean e suas interfaces devem ser criados dentro do módulo EJB da aplicação. Esta
operação pode ser feita rapidamente através do assistente disponível no IDE.
•
Acesse o menu de contexto do módulo OlaMundo-ejb e acesse a opção New /
Session Bean, para que o assistente seja iniciado;
•
Na tela mostrada (ver Figura 27, informe o EJB Name (OlaMundo) e o package
(teste);
•
Marque o tipo Stateless;
•
Certifique-se de que os dois tipos de interface (Remote e Local) estejam marcados;
•
Clique em Finish;
Figura 27: Criação de um session bean no NetBeans
57
O bean e as interfaces serão criados, conforme ilustra a Figura 28.
Figura 28: Programas criados pelo assistente de session beans
7.4.3 Programação do bean e das interfaces
•
Abra o arquivo OlaMundoBean.java para edição;
•
Altere o programa, criando o método olaMundo, conforme a listagem da seção 7.1;
•
Posicione o cursor na linha com a assinatura do método olaMundo. Um pequeno
símbolo (uma lâmpada amarela) aparece ao lado do número da linha (ver Figura
29). Clique sobre ele e acesse a opção Add to Local interface. Repita a operação,
desta vez acessando a opção Add to Remote interface.
Figura 29: Atualização das interfaces
•
Para verificar a criação do métodos nas interfaces , basta abrir os arquivos para
edição e comparar com o conteúdo da seção 7.2.
7.4.4 Programação da aplicação cliente
•
Selecione o projeto OlaMundo-app-client ;
•
Acesse o menu File / New File;
•
Certifique-se de que o projeto OlaMundo-app-client esteja selecionado;
•
Selecione as opções Java classes na janela da esquerda e Java Class na janela da
direita (ver Figura 30);
•
Clique em Next ;
58
Figura 30: Criação de uma classe Java simples
•
Na tela New Java Class (ver Figura 31), informe o Class Name Main, e o package
olamundo ;
•
Clique em Finish;
•
Uma nova classe foi criada e está disponível no projeto (ver Figura 32);
•
Substitua o conteúdo da classe pelo código disponível na seção 7.3.
Figura 31: Criação de uma nova classe Java
59
Figura 32: Nova classe criada
7.4.5 Deploy da aplicação
Há três maneiras de realizar o deploy (publicação) da aplicação no SJSAS:
•
Pelo painel de administração do servidor:
•
Pelo NetBeans: acessando o menu de contexto da aplicação enterprise e escolher a
opção Deploy Project, o NetBeans faz o deploy da aplicação;
•
Manualmente: copiando o EAR gerado pelo IDE para a pasta autodeploy do
servidor de aplicações (o nome desta pasta varia de um servidor de aplicações para
outro).
Na pasta onde o projeto enterprise do NetBeans é gravado, são criadas várias pastas:
•
build: pasta para onde o NetBeans copia os arquivos finais já empacotados dos
projetos, para posteriormente criar o EAR. Estes arquivos são os JAR dos módulos
EJB e cliente, e o WAR das aplicações web;
•
dist: pasta utilizada pelo NetBeans para gerar o arquivo EAR final, a ser publicado
no servidor de aplicações;
•
projeto-app-client: contém o projeto da aplicação cliente. Projeto deve ser
substituído pelo nome do projeto enterprise criado – no caso, OlaMundo ;
•
projeto-ejb: contém o projeto do módulo EJB;
•
projeto-war : contém a aplicação web .
No SJSAS, a pasta autodeploy está localizada na pasta domains\nome_do_domínio
(tomando por base a pasta de instalação do SJSAS). Nome_do_dominio deve ser substituído pelo
domínio onde a aplicação será publicada – no caso deste trabalho é utilizado sempre o padrão
domain1 .
Alguns instantes após a cópia, é gerado um outro arquivo, com o mesmo nome do EAR,
mas com a extensão ear_deployed, indicando que o arquivo foi publicado com sucesso. Se o arquivo
não foi criado ou foi criado com outra extensão, então a publicação teve problemas.
60
7.4.6 Execução do cliente
Para executar o cliente dentro do container do servidor de aplicações basta executar o
seguinte comando, numa tela de linha de comando:
SERVER\bin\appclient -client APP\ARQUIVO.JAR -mainclass CLASSE
Os dados escritos em letras maiúsculas devem ser substituídos pelo seguinte conteúdo:
•
SERVER: pasta de instalação do SJSAS;
•
APP: pasta onde são instalados os arquivos já publicados da aplicação.
Normalmente
a
pasta
é
SERVER\domains\domain1\generated\xml\j2ee-
apps\NomeAplicacao;
•
ARQUIVO.JAR; nome do JAR que contém a aplicação cliente;
•
CLASSE: classe do JAR a ser executada.
Uma vez que as linhas de comando tendem a ficar extensas, é aconselhável a criação
de um arquivo de processamento em lote (batch) para executar a aplicação. Um conteúdo possível é:
@echo off
set SERVER=D:\Apl\Sun\AppServer
set APP=D:\Apl\Sun\AppServer\domains\domain1\generated\xml\j2ee-apps\OlaMundo
set JAR=OlaMundoClient.jar
set CLASSE=olamundo.Main
cls
@echo on
%SERVER%\bin\appclient -client %APP%\%JAR% -mainclass %CLASSE%
Ao ser executado, este script executa a aplicação OlaMundo dentro do container de
aplicações cliente do SJSAS.
61
8 PROVA DE CONCEITO - UMA APLICAÇÃO COMPLETA
O objetivo deste capítulo é demonstrar a utilização da persistência em banco de dados
através
de uma aplicação
enterprise que
envolve
os
módulos
EJB,
web
e
desktop.
Convencionalmente, esta aplicação é chamada de CRUD (Create, Recover, Update, Delete), por
considerar as quatro operações básicas de um banco de dados (inserir, pesquisar, atualizar e excluir)
[WIKIPEDIA 02].
A aplicação é apenas uma prova de conceito, uma demonstração de como a tecnologia
funciona e pode ser aplicada no dia a dia e por isto é essencialmente didática.
Para o desenvolvimento da aplicação, os seguintes pontos devem ser observados:
•
os software descritos na seção 5 devem ter sido instalados e configurados;
•
uma aplicação enterprise deve ter sido criada, como descrito na seção 7.4.1. O
projeto contém os três módulos (EJB, web e application client). Neste trabalho, o
nome do projeto foi definido como Maxigroupware.
No desenvolvimento, foram utilizados o máximo possível de recursos do NetBeans. Esta
abordagem foi feita para evitar a complexidade de criar e manipular os arquivos de configuração
manualmente. Esta seria uma tarefa árdua e desnecessária, uma vez que uma das funções dos IDE é
aumentar a produtividade do desenvolvedor, automatizando grande parte dos processos.
Os fontes completos do aplicativo estão disponíveis no Apêndice B.
8.1 PROJETO
Mesmo sendo um aplicativo simples contendo apenas a operação de autenticar um
usuário, o projeto é necessário para facilitar a compreensão do que deve ser feito em sua
implementação. Neste trabalho, foi utilizada a Unified Modeling Language (UML).
A UML é uma linguagem-padrão para a elaboração de projetos de software, usada para
visualizar, especificar, construir e documentar sistemas de qualquer espécie. É uma linguagem
gráfica, formada por componentes que por sua vez são agrupados em diagramas. Existem treze tipos
de diagramas na última versão da UML [OMG].
62
8.1.1 Diagrama de casos de uso
Este tipo de diagrama demonstra de maneira generalizada os principais serviços
realizados pelo sistema. No aplicativo de testes, existe apenas um caso de uso (ver Figura 33):
Efetuar login
Usuário
Figura 33: Diagrama de casos de uso
8.1.2 Diagrama de seqüência
O diagrama de seqüência identifica as interações entre os objetos num espaço de
tempo, indicando quais operações e dados trafegam na troca de informações entre os objetos.
A Figura 34 ilustra o diagrama de seqüência para autenticação do usuário, do momento
em que os dados são informados na página de login até a exibição da mensagem confirmando ou
negando a autenticação.
Usuário
:Página login
:Login
:UsuarioFacadeRemote
UsuarioFacade
SGBD
1: usuário, senha
2: autenticar( )
3: autentica( usuario, senha)
4: status = autentica(usuario, senha)
5: findByLogin(usuario)
6 : login
10: mensagem
9: status
8: status
Figura 34: Diagrama de seqüência
7: dados pesquisados
63
8.2 ARQUIVOS DE CONFIGURAÇÃO
Ao criar uma aplicação enterprise, o NetBeans automaticamente cria os arquivos de
configuração necessário. No decorrer do desenvolvimento, estes arquivos são automaticamente
mantidos pelo IDE, e por isto normalmente não são alterados manualmente.
O principal arquivo de configuração da aplicação enterprise é o application.xml . Ele
pode ser encontrado no nó Configuration files da aplicação enterprise (ver Figura 35).
Figura 35: Arquivos de configuração da aplicação enterprise
O conteúdo do arquivo é descrito a seguir:
<?xml version="1.0" encoding="UTF-8"?>
<application version="5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/application_5.xsd">
<display-name>Maxigroupware</display-name>
<module>
<web>
<web-uri>Maxigroupware-war.war</web-uri>
<context-root>/Maxigroupware-war</context-root>
</web>
</module>
<module>
<java>Maxigroupware-app-client.jar</java>
</module>
<module>
<ejb>Maxigroupware-ejb.jar</ejb>
</module>
</application>
Os elementos do arquivo são:
•
display-name: é o texto descritivo a ser mostrado ao usuário (por exemplo, no painel
de administração) no servidor de aplicações;
•
module: são os módulos que compõem a aplicação. Podem ser do tipo web
(aplicações web), java (aplicações cliente) ou ejb (componentes enterprise). Pode
haver vários módulos de um mesmo tipo;
•
web-uri: nome do pacote (arquivo WAR) que contém uma aplicação web;
64
•
context-root: contexto a ser criado no servidor de aplicações para execução da
aplicação web . É utilizado para formar a URL a ser utilizada no navegador. No
arquivo acima, a aplicação tem a URL http://nome_do_servidor/Maxigroupware-war ;
•
java: nome do pacote (arquivo JAR) que contém uma aplicação cliente;
•
ejb: nome do pacote arquivo JAR) que contém um módulo EJB.
Embora os valores definidos originalmente funcionem corretamente, neste trabalho o
elemento context-root foi alterado para o seguinte conteúdo:
<context-root>/maxi</context-root>
Desta maneira, a URL para acessar o aplicativo é http://nome_do_servidor/maxi,
simplificando sua utilização.
8.3 MÓDULO EJB
8.3.1 Criação dos entity beans
•
No menu de contexto do módulo Maxigroupware-ejb acesse a opção New / Entity
beans from database (ver Figura 36);
Figura 36: Criação de entidades a partir do banco de dados
•
Na tela mostrada (ver Figura 37), informe o nome do datasource criado no servidor
de aplicações. A partir dele, serão lidas todas as tabelas disponíveis no banco de
dados, que serão mostradas na janela da esquerda.
•
Selecione a tabele Projeto, clique em Add e em seguida em Next;
65
•
Na
tela mostrada
(ver
Figura
38),
informe
o
nome
do package como
entidades.projeto;
•
Desmarque a opção Generate Named Query...;
•
Clique em Create Persistence Unit;
Figura 37: Escolha do datasource e das tabelas para criação das entidades
Figura 38: Nomenclatura e empacotamento das entidades
66
•
Na tela mostrada (ver Figura 39), aceite todas as opções fornecidas,
•
Certifique-se que a opção Table Generation Strategy esteja definida como None.
Esta opção define como a criação das tabelas relativas às entidades é tratada. Para
mais informações sobre a persistence unit, veja a seção 6.9;
•
Clique em Create;
Figura 39: Criação da persistence unit
•
Na tela mostrada (ver Figura 38), cliquem em Finish;
•
As entidades criadas serão mostradas no painel Projects, conforme ilustra figura a
seguir.
Figura 40: Entidade criadas no projeto
•
Abra o arquivo Projeto.java para edição, e insira a anotação a seguir logo após a
anotação @Id:
@GeneratedValue(strategy=GenerationType.IDENTITY)
•
Tecle a combinação ALT – SHIFT – F ; isto faz com que os imports correspondentes
sejam adicionados à classe, refletindo a alteração.
67
Agora basta repetir o processo para criar as entidades para as outras tabelas. Para o
desenvolvimento do aplicativo, foram utilizadas as configurações descritas na Tabela 2.
Tabela
USUARIO
Classe
Usuario
PROJ_USUARIO
ProjetoUsuario
Tabela 2: Entidades adicionais do projeto
Pacote
entidades.usuario
entidades.projetousuario
•
Ao final, a estrutura do projeto estará conforme a Figura 41.
•
Abra o arquivo Usuario.java para edição, e insira a anotação a seguir logo após a
anotação @Id. Como anteriormente, tecle a combinação ALT – SHIFT – F para
importar as classes correspondentes.
@GeneratedValue(strategy=GenerationType.IDENTITY)
Figura 41: Entidades criadas no projeto
8.3.2 Entidade
Uma entidade possui diversas características que a diferenciam de uma classe
tradicional. A listagem a seguir é um extrato do código da entidade Projeto gerado pelo NetBeans,
que pode ser encontrado no Apêndice B.
...
@Entity
@Table(name = "PROJETO")
public class Projeto implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "CODPROJETO", nullable = false)
private Integer codprojeto;
@Column(name = "NOME", nullable = false)
private String nome;
@Lob
@Column(name = "DESCRICAO", nullable = false)
private String descricao;
68
public Projeto() {
}
// métodos get e set
...
@Override
public String toString() {
return "entidades.projeto.Projeto[codprojeto=" +
codprojeto + "]";
}
}
Como é possível observar, uma entidade possui várias anotações, que a diferenciam de
uma classe normal. Muitas têm argumentos que alteram seu comportamento padrão.
@Entity
Define esta classe como uma entidade. É obrigatória para todas as entidades.
@Table(name="PROJETO")
Identifica qual tabela no banco de dados esta entidade vai representar. Pela
especificação Java EE 5, se esta anotação for omitida ela referenciará uma tabela com o mesmo
nome da classe. Portanto, sua inclusão somente é obrigatória se a tabela e a entidade não tiverem o
mesmo nome.
@Id
Define que a próxima propriedade contém a chave primária da entidade. É utilizada
somente se a chave primária contiver apenas uma coluna, caso contrário é obrigatória a utilização de
outra entidade representando a chave primária (como na entidade ProjetoUsuario.java , discutida
adiante).
@GeneratedValue(strategy=GenerationType.IDENTITY)
Define qual a estratégia de geração de chaves primárias. Os bancos de dados
trabalham com diferentes tipos de estruturas para geração automática de chaves primárias. Por
exemplo, o Oracle utiliza o recurso de sequences , enquanto o Derby utiliza um campo do tipo inteiro
com atributo de identidade, o que provoca seu incremento automático.
Neste caso, a estratégia utilizada é a identidade, implementada nos bancos de dados
como campos de valor auto incrementados. Seus outros valores podem ser AUTO (a decisão fica a
cargo da camada de persistência), SEQUENCE (utiliza uma seqüência previamente criada no banco de
dados) e TABLE (a camada de persistência utiliza uma tabela do banco de dados para criação das
chaves primárias).
69
@Column(name="CODPROJETO", nullable = false)
A anotação @Column identifica um coluna da tabela. Seu comportamento é o mesmo
da anotação @Table: se omitida, o padrão é referenciar uma coluna com o mesmo nome da
propriedade. A opção nullable definida como false (o default é true) reflete a característica not null
definida no momento da criação da tabela no banco de dados, ou seja, torna seu preenchimento
obrigatório.
@Lob
Especifica que a propriedade deve ser persistida do banco de dados como um large
object. Pode ser dos tipos binário (campo do tipo BLOB no banco de dados) ou então caracter
(normalmente um campo do tipo TEXT.
@Override
Esta anotação indica que o método a seguir sobrescreve um método da superclasse.
Foi criada na versão 5 do Java, atendendo a pedidos de desenvolvedores. Antes era impossível
saber se um método era sobrescrito ou não.
8.3.3 Entidades para chaves primárias
No código da classe ProjetoUsuario.java , observa-se a utilização de outras
anotações além das discutidas anteriormente, juntamente com o uso de uma outra entidade como
chave primária.
...
@Table(name = "PROJ_USUARIO")
public class ProjetoUsuario implements Serializable {
@EmbeddedId
protected ProjetoUsuarioPK projetoUsuarioPK;
@JoinColumn(name="CODPROJETO", referencedColumnName="CODPROJETO",
insertable=false, updatable=false)
@ManyToOne
private Projeto projeto;
@JoinColumn(name="CODUSUARIO", referencedColumnName="CODUSUARIO",
insertable=false, updatable=false)
@ManyToOne
private Usuario usuario;
public ProjetoUsuario(ProjetoUsuarioPK projetoUsuarioPK) {
this.projetoUsuarioPK = projetoUsuarioPK;
}
public ProjetoUsuario(int codusuario, int codprojeto, String lider){
this.projetoUsuarioPK = new ProjetoUsuarioPK(codusuario,
codprojeto);
this.lider = lider;
}
public ProjetoUsuarioPK getProjetoUsuarioPK() {
return this.projetoUsuarioPK;
}
70
public void setProjetoUsuarioPK(ProjetoUsuarioPK projetoUsuarioPK) {
this.projetoUsuarioPK = projetoUsuarioPK;
}
// métodos get e set
....
}
@Table
A entidade ProjetoUsuario referencia a tabela Proj_Usuario. Uma vez que o nome da
entidade difere da tabela, a anotação @Table torna-se obrigatória.
@EmbeddedId
A
anotação
@EmbeddedId
identifica
uma
chave
primária
composta,
tratada
obrigatoriamente por outra entidade. A entidade ProjetoUsuarioPK foi gerada automaticamente
pelo NetBeans, no momento em que foi identificada uma tabela com uma chave primária composta.
Na utilização da entidade ProjetoUsuario , sempre que a chave primária precisar ser referenciada,
deve-se utilizar a entidade ProjetoUsuarioPK .
@JoinColumn
Identifica uma chave estrangeira. Quando uma pesquisa na entidade ProjetoUsuario é
realizada, sua chave primária também é atualizada automaticamente. Por isto, na entidade
ProjetoUsuarioPK serão realizadas pesquisas nas entidades Projeto e Usuario . A anotação
@JoinColumn é responsável por identificar a coluna da tabela a ser utilizada para realizar a pesquisa,
sendo que a tabela é definida pelo próprio tipo de objeto da variável.
Os outros parâmetros da anotação (insertable=false e updatable=false ) são
obrigatórios neste caso. Eles fazem com que as entidades Projeto e Usuario não possam atualizar
as colunas da chave primária em suas respectivas tabelas no banco de dados. Desta maneira, as
entidades atuando como chaves estrangeiras podem apenas pesquisar no banco de dados, nunca
alterá-lo – procedimento previsto na especificação Java EE 5.
@ManyToOne
Identifica a cardinalidade muitos-para-um no banco de dados. Ou seja, para cada
entidade que for chave estrangeira, pode haver várias entidades descendentes. Exemplo: um usuário
pode ser alocado em vários projetos.
@Embeddable
A anotação @Embeddable é utilizada em todas as entidades que puderem ser utilizadas
como chaves primárias embarcadas. Nas classes utilizadas neste trabalho, a única que utiliza esta
anotação é a ProjetoUsuarioPK.
71
8.3.4 Criação dos session beans
•
No menu de contexto do nó Source Packages do painel Projects, acesse a opção
New / Session Beans For Entity Classes (ver Figura 42);
Figura 42: Criação de session beans
•
Na tela mostrada (ver Figura 43), selecione a entidade Projeto e clique sobre Add;
•
Clique em Next ;
Figura 43: Assistente para criação de session beans
•
Na tela seguinte (ver Figura 44), altere o package para entidades.projeto;
•
Certifique que apenas a opção Remote esteja marcada e clique em Finish;
•
Os session beans (que neste caso serão facades) e suas interfaces serão criados;
•
Repita o processo, criando os beans e interfaces restantes nos pacotes de suas
respectivas
entidades.
É
possível
criar
as
classes
para
cada
entidade
separadamente, ou então criar todas ao mesmo tempo, e depois selecionar as
classes de um pacote e arrastá-la para o pacote correto (neste caso, deve-se
arrastar e soltar uma classe de cada vez).
72
Figura 44: Empacotamento e escolha das interfaces a serem criadas
Figura 45: Session bean e interface criados
8.3.5 Persistência
Como explanado na seção 6.10, facades são o ponto de acesso para as aplicações
cliente executarem as ações do sistema, sendo session beans normais.
A listagem a seguir é a facade utilizada para as operações realizadas com entidade
Projeto . E l a é u m stateless session bean , definido pela anotação @Stateless . Para realizar
operações de persistência com a entidade, é utilizado um EntityManager .
...
@Stateless
public class ProjetoFacade implements ProjetoFacadeRemote {
@PersistenceContext
private EntityManager em;
73
public ProjetoFacade() {
}
public void create(Projeto projeto) {
em.persist(projeto);
}
public void edit(Projeto projeto) {
em.merge(projeto);
}
public void destroy(Projeto projeto) {
em.remove(em.merge(projeto));
}
public void destroy(int id) {
em.remove(this.find(id));
}
public Projeto find(Object pk) {
return (Projeto) em.find(Projeto.class, pk);
}
public List findAll() {
return em.createQuery("select object(o) from Projeto as o")
.getResultList();
}
}
Os métodos mais utilizados da API EntityManager são os seguintes:
persist
Persiste (grava) uma nova instância da entidade no PersistenceContext .
merge
Altera os dados de uma instância da entidade no PersistenceContext .
remove
Exclui uma instância da entidade do PersistenceContext.
find
Localiza uma entidade através de sua chave primária. O retorno é uma entidade com os
dados pesquisados.
createQuery
Cria uma instância de Query . Query é um objeto que pode realizar qualquer tipo de
operação no PersistenceContext. É utilizado quando os métodos tradicionais não são suficientes
para realizar a operação desejada (por exemplo, é necessário localizar uma entidade por um índice
diferente da chave primária). Seus métodos principais são:
74
•
executeUpdate:
atualiza
(inclui
ou
altera)
ou
exclui
uma
entidade
do
PersistenceContext;
•
getSingleResult: executa uma pesquisa retornando uma única entidade.
•
getResultList: executa uma pesquisa, retornando uma ou mais entidades na forma
de um List.
8.3.6 Interfaces
As interfaces são a referência dos facades dentro do servidor JNDI, ou seja, é através
delas que podemos localizar os EJB. A seguir, o código da interface do bean ProjetoFacade . O
único ponto em que se diferencia de uma interface tradicional do Java é a anotação @Remote,
indicando que é um interface remota. Se fosse uma interface local, a anotação seria @Local .
...
@Remote
public interface ProjetoFacadeRemote {
void create(Projeto projeto);
void edit(Projeto projeto);
void destroy(Projeto projeto);
Projeto find(Object pk);
List findAll();
void destroy(int id);
}
8.4 COMPLETANDO A APLICAÇÃO EJB
Embora o NetBeans gere grande parte do código da aplicação, sempre é necessário
fazer pequenos ajustes, a fim de fornecer maiores funcionalidades ao aplicativo.
A Tabela 3 lista as alterações necessárias para completar o módulo EJB. Os fontes
completos estão disponíveis no Apêndice B.
Classe
Alterações
ProjetoUsuarioFacade
•
Criar o método findProjetosPorUsuario ;
ProjetoUsuarioFacadeRemote
•
Adicionar o método findProjetosPorUsuario à
interface.
ProjetoFacade
•
Criar o método destroy(int id) ;
ProjetoFacadeRemote
•
Adicionar o método destroy(int id) à interface;
UsuarioFacade
•
Alterar o construtor UsuarioFacade() ;
UsuarioFacade
•
Alterar o método create(Usuario usuario) ;
UsuarioFacade
•
Criar o método destroy(int id) ;
75
Classe
Alterações
UsuarioFacade
•
Criar o método findByLogin(String login) ;
UsuarioFacade
•
Criar
o
método
autentica(String
login,
String senha);
UsuarioFacadeRemote
•
Inserir os métodos destroy , findByLogin e
autentica ;
Tabela 3: Alterações necessárias ao módulo EJB
Além disto, é necessário criar as seguintes classes:
•
utils.Criptografia;
•
utils.Mensagem.
8.5 ACESSO AOS EJB NUM CLIENTE DESKTOP
O acesso aos EJB numa aplicação desktop é bastante simples, como visto
anteriormente na seção 7.3.
A listagem disponível no Apêndice C é um pequeno cliente em linha de comando que,
dependendo dos parâmetros passados, realiza as operações de inserir, excluir, alterar, consultar e
listar projetos. Este programa deve ser criado criado no projeto Maxigroupware-app-client , e é
chamado de maxigroupware.Main . Para executá-lo, é possível executar um batch como o abaixo:
@echo off
set SERVER=D:\Apl\Sun\AppServer
set APP=%SERVER%\domains\domain1\generated\xml\j2ee-apps\MaxiGroupware
set JARNAME=MaxiGroupwareClient.jar
set CLASS=maxigroupware.Main
cls
@echo on
%SERVER%\bin\appclient -client %APP%\%JARNAME% -mainclass %CLASS% %1 %2
O programa é um aplicativo CRUD que trabalha unicamente com o EJB relacionado à
tabela Projeto. O acesso aos EJB a partir de uma aplicação cliente foi discutido na seção 7.3. Os
métodos que trabalham com a entidade são discutidos a seguir.
8.5.1 Listagem
Antes e depois de cada operação os registros gravados no banco de dados (se houver
algum) serão listados, para que uma comparação dos dados seja possível.
76
O método implementado para imprimir os registros é o lista(). Ele executa uma
pesquisa na entidade Projeto, através do método findAll(), que retorna todos os registros
cadastrados, imprimindo-os a seguir.
List lista = projetoFR.findAll();
for (Object o : lista) {
System.out.println("
" + o.toString());
}
8.5.2 Inclusão
A inclusão de registros é realizada pelo método create(). Um objeto do tipo Projeto é
criado e seus dados são inicializados. Nesta implementação, o nome e a descrição do projeto contém
a data e hora de criação do objeto. Desta maneira, mesmo que sejam incluídos vários projetos, nunca
haverão dois registros iguais.
private void create() {
System.out.println("\n--- Criando ---");
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
Projeto p = new Projeto();
p.setNome("Prj: " + timestamp);
p.setDescricao("Criado em " + timestamp);
projetoFR.create(p);
System.out.println("
" + p.toString());
System.out.println();
}
A linha a seguir é responsável pela gravação do registro no banco de dados. Observe
que é acessado o método create() da interface ProjetoFacadeRemote , sendo passado como
parâmetro o objeto a ser gravado.
projetoFR.create(p);
8.5.3 Pesquisa
A pesquisa é realizada pelo método recover() . Para que seja realizada, o código do
projeto deve ser informado como argumento na linha de comando. O código é então passado ao
método find() da interface. Este método retorna um objeto que pode ser nulo (caso o código não
tenha sido cadastrado previamente), ou então um projeto já inicializado com o conteúdo gravado no
banco de dados.
Projeto p = projetoFR.find(codigo);
if (p==null) {
System.out.println("
Projeto nao encontrado: " + s);
} else {
System.out.println("
" + p.toString());
77
}
8.5.4 Atualização
O processo de atualização é realizado pelo método update() e envolve dois
procedimentos. O primeiro é a pesquisa do projeto a ser alterado, realizado pela instrução a seguir:
Projeto p = projetoFR.find(codigo);
O código deve ter sido passado como argumento na linha de comando. A pesquisa é
necessária para que não seja feita uma tentativa de atualizar um registro que ainda não foi criado, o
que provocaria um erro na execução do comando.
O segundo procedimento é a alteração dos dados do objeto pesquisado e sua gravação:
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
p.setNome("Prj: " + timestamp);
p.setDescricao("Alterado em " + timestamp);
projetoFR.edit(p);
O método edit() definido na interface do EJB é acionado e, então, realiza-se a
gravação dos dados.
8.5.5 Exclusão
A exclusão de registros é feita pelo método delete() e a instrução responsável é a
seguinte:
projetoFR.destroy(codigo);
O código deve ter sido passado como argumento na linha de comando.
É importante notar que o método destroy(int id) foi criado manualmente, não sendo
gerado automaticamente pelo NetBeans. Desta maneira, a pesquisa ao projeto com o código
correspondente é realiza da diretamente no container EJB, e não na aplicação cliente, aumentando o
desempenho do processo.
8.5.6 Criação de usuários
Para o desenvolvimento da aplicação web , é necessário também a criação de um
cliente cuja única função é incluir usuários no banco de dados.
78
O código fonte do cliente está disponível no Apêndice D, e sua operação foi discutida na
seção anterior.
A seguir está um exemplo de arquivo batch para acessá-lo:
@echo off
set SERVER=D:\Apl\Sun\AppServer
set APP=%SERVER%\domains\domain1\generated\xml\j2ee-apps\MaxiGroupware
set JARNAME=MaxiGroupwareClient.jar
set CLASS=maxigroupware.CreateUser
cls
@echo on
%SERVER%\bin\appclient -client %APP%\%JARNAME% -mainclass %CLASS% %1 %2 %3 %4
Para utilizá-lo, basta executar o programa passando como parâmetros, nesta ordem, o
login, a senha, o nome e o e-mail do usuário.
No processo de criação, a senha é automaticamente codificada.
8.6 ACESSO AO EJB NUMA APLICAÇÃO WEB
Há muito tempo, o desenvolvimento de aplicações web em Java tem sido feito na
maioria das vezes utilizando unicamente JSP. Muitos desenvolvedores acabam mesclando código
HTML com scriptlets (código programado em Java dentro de páginas JSP). Embora esta abordagem
não seja contra a especificação Java, ela não é bem vista por muitos desenvolvedores por várias
razões [INFORMIT]:
•
prejudica a legibilidade do código da página;
•
coloca a lógica do negócio dentro da camada de visualização;
•
aumenta a complexidade da manutenção das páginas.
Para evitar estes problemas, todo o acesso à camada de negócio é feito através de
servlets (ver seção 3.2.2) ou beans. Estes componentes por sua vez acessam os EJB e realizam as
ações necessárias.
Neste trabalho, a abordagem utilizada é carregar os EJB a partir de beans. Foi criada
uma aplicação simples utilizando JSF (ver seção 4.3), cuja única função é verificar a autenticidade de
um usuário. Para isto, é utilizado o método autentica , do EJB UsuarioFacade.
Uma visão geral da aplicação é fornecida a seguir:
•
A página inicial é definida no arquivo web.xml (), seção welcome-file-list, como
sendo index.jsp. É possível alterar esta configuração identificando o nome da nova
79
página inicial para qualquer nome que se deseje (por exemplo, login.jsp), embora
não seja usual.
•
As páginas informativas sobre o sucesso ou não da autenticação do usuário estão
na pasta mensagens ;
•
Os arquivos auxiliares cabecalho.jsp, rodape.jsp e o arquivo estilos.css estão na
pasta recursos ;
•
O único bean gerenciado sendo utilizado é o login.java, localizado no pacote
manage e configurado no arquivo faces-config.xml, juntamente com as regras de
navegação (seção 9).
Na aplicação, deve-se informar um usuário e senha válidos. Caso os dados estejam
corretos o usuário é autenticado e a página indicando o sucesso da operação é mostrada. Em caso
de problemas com a autenticação, seja por dados incorretos ou não informados, é mostrada uma
página com o erro correspondente. O esquema de navegação é mostrado na Figura 46.
Figura 46: Regras de navegação da aplicação web
Na página login.jsp (Apêndice D) são informados os dados para autenticação. O
elemento commandButton define o método a ser chamado quando o usuário clicar sobre ele:
<h:commandButton value="Login" id="enviar" action="#{Login.autenticar}"/>
A cláusula action indica que o método autenticar do bean gerenciado Login será
acionado (Login.autenticar ).
O método possui o seguinte conteúdo:
public String autenticar() {
String result = "nao_autenticado";
80
String usuarioForm = getLogin().getValue().toString();
String senhaForm = getSenha().getValue().toString();
boolean autenticado = false;
try {
if (usuarioForm.equals("") || senhaForm.equals("")) {
addErrorMessage("Informe o login e a senha!");
} else {
autenticado = usuarioFR.autentica(usuarioForm, senhaForm);
if (autenticado) {
setUsuario(usuarioFR.findByLogin(usuarioForm));
FacesContext facesContext=FacesContext.getCurrentInstance();
facesContext.getExternalContext()
.getSessionMap().put("_usuario", getUsuario());
addSuccessMessage("Autenticação OK!");
} else {
throw new Exception("Erro");
}
}
} catch (Exception e) {
setUsuario(null);
addErrorMessage("Erro na autenticação do usuário. " +
"Certifique-se que informou os dados corretos!");
}
return (autenticado ? "autenticado" : "nao_autenticado");
}
O método autenticar utiliza os recursos básicos de uma aplicação JSF, buscando os
conteúdos dos campos de texto do formulário exibido ao usuário, e inicializando variáveis com esses
valores. Após o processamento o método retorna uma string contendo o resultado da operação (as
expressões autenticado ou nao_autenticado). Esta string é capturada pelo servlet controlador do
JSF, que se encarrega de chamar a página correspondente ao resultado, conforme definido nas
regras de navegação.
A primeira consistência é verificar se todos os dados foram informados, lembrando que
um campo vazio não possui valor null, e sim uma string vazia de tamanho zero. Por este motivo é
utilizada a instrução
if (usuarioForm.equals("") || senhaForm.equals("")) { ...
e não
if (usuarioForm==null || senhaForm==null) { ...
Se algum dado não for informado, a execução do método é interrompida. Caso
contrário, executa-se a autenticação, através da instrução a seguir:
autenticado = usuarioFR.autentica(usuarioForm, senhaForm);
O objeto usuarioFR é instanciado na classe, com a seguinte chamada:
@EJB(beanName="UsuarioFacade", beanInterface=UsuarioFacadeRemote.class)
81
private UsuarioFacadeRemote usuarioFR;
A anotação @EJB é responsável por referenciar um bean existente no servidor. Como
parâmetros, exige-se o nome do bean ( beanName) e a classe de sua interface (beanInterface ).
Desta maneira controla-se o bean e o acesso a ele. Deste ponto em diante, utiliza-se o objeto
usuarioFR de maneira transparente, executando-se os métodos nele definidos, como na instrução a
seguir, que pesquisa um usuário através de seu login (lembrando que neste ponto o usuário já foi
autenticado):
setUsuario(usuarioFR.findByLogin(usuarioForm));
O usuário retornado pela pesquisa é atribuído ao atributo da classe usuario , do tipo
entidades.usuario.Usuario. Esta operação é realizada para que o bean gerenciado possa criar um
atributo de sessão chamado _usuario, que contém o usuário autenticado e inicializado:
FacesContext facesContext=FacesContext.getCurrentInstance();
facesContext.getExternalContext()
.getSessionMap().put("_usuario", getUsuario());
Desta maneira, é possível a qualquer bean gerenciado acessar o contexto de uma
aplicação web que o utiliza, e conseqüentemente qualquer informação que possa ser acessada por
uma página JSP tradicional, ou então um servlet, bem como manipulá-las.
8.7 DOCUMENTAÇÃO
Uma das partes mais importantes de um aplicativo, não importa seu tamanho ou
complexidade, é a documentação. No caso de um desenvolvedor não dar mais manutenção em um
sistema, é a documentação que servirá de subsídio para que outra pessoa assuma seu lugar. A
documentação deve ser simples e objetiva, embora completa.
O Java possui um interessante mecanismo de documentação dos programa fonte,
chamado de JavaDoc. É um conjunto de tags (instruções) mesclado ao programa, que contém
informações sobre a classe, os métodos e seus parâmetros, e sobre o tipo de retorno que terá este
método. Também pode fornecer informações sobre versões e autoria da classe, entre outras coisas –
basta que se forneça a tag correta e o texto desejado.
Após criar a documentação no programa, é realizada uma análise do código e gerado
um conjunto de páginas no formato HTML, que contém a documentação. A análise e geração dos
documentos são realizados por um programa chamado javadoc.exe, que faz parte do JDK. Por
convenção, os documentos gerados e também as tags de documentação também são chamados de
JavaDoc.
82
O NetBeans possui ferramentas para o auxílio na geração tanto das tags quanto dos
documentos. Isto facilita bastante o trabalho do desenvolvedor, que pode criar a documentação do
programa simultaneamente ao desenvolvimento.
Para criar a documentação é utilizada uma ferramenta chamada AutoComment . Para
acessá-la basta acessar o menu de contexto do programa e selecionar a opção Tools /
AutoComment , como mostra a Figura 47.
Figura 47: Acesso à ferramenta AutoComment.
A tela do AutoComment é dividida em várias seções, conforme ilustra a Figura 48.
83
Figura 48: Ferramenta AutoComment.
À esquerda são mostrados os objetos passíveis de documentação, como classes e
métodos. Logo abaixo há uma área indicando a classe sendo documentada, bem como os erros
existentes na documentação e que devem ser corrigidos.
O botão AutoCorrect gera uma documentação básica, indicando o que deve ser
preenchido pelo desenvolvedor no campo Javadoc Comment Text. Este texto deve explicar qual o
objetivo do componente sendo documentado.
O campo Tags provê uma maneira simples de incluir as tags de documentação no texto.
O botão New mostra uma lista com todas as opções disponíveis. Após incluí-la, basta pressionar o
botão Delete para excluí-la.Os botões Move up e Move down movem a tag para cima ou para baixo
da lista, indicando a ordem em que aparecerão na documentação. Finalmente, a lista Name seleciona
uma das tags para que sua descrição seja informada no campo Description.
A qualquer momento, é possível ver como ficará as tags de documentação. Para isto,
basta selecionar a aba do editor que contém o programa sendo documentado, ou então pressionar o
botão View Source. Exemplos de código documentado estão disponíveis no Apêndice B.
Após documentar todos os programas desejados, é necessário gerar a documentação
em formato HTML. Para gerar a documentação, basta seguir os passos:
84
•
Selecione um projeto;
•
Acesse o menu de contexto, selecionando a opções Generate Javadoc for Project
(conforme Figura 49);
Figura 49: Geração da documentação.
•
Quando o processo for finalizado, será emitida uma mensagem na área de saída do
NetBeans. No exemplo da Figura 50, a mensagem indica que a documentação foi
gerada com sucesso;
Figura 50: Mensagem de sucesso ao gerar a documentação.
•
Em caso de sucesso da geração, será aberto um navegador, mostrando a
documentação gerada, como mostra a Figura 51;
85
Figura 51: Página inicial da documentação.
A página da documentação é dividida em três partes:
•
Na parte superior esquerda são mostrados todos os pacotes disponíveis na
documentação. Para mostrar as classes do pacotes, basta acessar seu link. Para
mostrar novamente todas as classes do projeto, basta acessar o link All classes;
•
Na parte inferior esquerda, são listadas as classes pertencentes ao pacote
selecionado. Se nenhum pacote for selecionado (por exemplo, logo ao iniciar o
navegador), serão mostradas todas as classes;
•
Na janela à direita é mostrado o conteúdo da documentação, já formatada.
86
9 CONCLUSÃO
Como exposto neste trabalho, a plataforma Java é uma boa alternativa ao
desenvolvimento de aplicações corporativas, especialmente em sua nova versão Java EE 5.
A separação bem definida entre as diversas camadas da aplicação, que à primeira vista
remete ao pensamento de complexidade de integração, mostra-se fundamental para fins de
organização e manutenção da aplicação. Esta possibilidade de integração, aliada ao grande poder
dos atuais IDE propiciam ao desenvolvedor uma excelente produtividade, uma das características
que as empresas mais buscam atualmente.
A facilidade para se criar aplicações, principal característica da nova versão Java EE 5,
mostrou ser seu ponto forte, conseguindo integrar o poder da plataforma à simplicidade no
desenvolvimento e à simplicidade de integração entre os diversos componentes. Isto permite gerar
aplicativos complexos, ao mesmo tempo em que é mantida a simplicidade do código.
Este conjunto de facilidades prova que o desenvolvimento de aplicações corporativas
utilizando Java EE 5 não só é viável, como também foge do estigma de ser uma tecnologia complexa,
o que o torna uma boa opção para a construção de sistemas de qualquer porte.
Por ser uma tecnologia lançada recentemente, a falta de materiais como livros e tutoriais
(estes disponíveis na internet) que descrevam o desenvolvimento de aplicações corporativas em
todas as camadas é considerado um problema. São poucos títulos disponíveis e os tutoriais cobrem
apenas parte da necessidade.
Dentro desta expectativa, o presente trabalho serve como uma guia que conduzirá os
desenvolvedores à compreensão de conceitos relacionados às camadas de
uma aplicação
corporativa. Tais conceitos englobam desde os componentes de configuração de uma aplicação,
como os EJB, containers , session beans e facades , até a infra-estrutura necessária para sua
execução, no caso o servidor de aplicações.
No que pese a escolha de determinadas ferramentas para o desenvolvimento e
execução do aplicativo, a especificação Java é suficientemente rígida para garantir que estes
conceitos possam ser aplicados em qualquer IDE e servidor de aplicações, desde que seja
obedecidas as características destas ferramentas.
87
Diante disto pode-se concluir que o estudo de uma tecnologia complexa, se amparado
em uma fonte de referência simples e objetiva, pode fornecer resultados rápidos, que servem de base
para estudos mais complexos, estes sim utilizando fontes de referência mais especializadas.
88
REFERÊNCIAS 2
[BALL 2006] BALL, Jennifer, et al. The Java EE 5 Tutorial. Santa Clara, EUA. Sun Microsystems.
2006. 1262 p.
[DBCP] THE APACHE SOFTWARE FOUNDATION. Commons DBCP.
<http://jakarta.apache.org/commons/dbcp>. Acesso em: 03 novembro 2006.
Disponível
em:
[DERBY]
THE APACHE SOFTWARE FOUNDATION.
<http://db.apache.org/derby>. Acesso em: 27 outubro 2006.
Disponível
em:
Apache
Derby.
[FACADE] SUN MICROSYSTEMS. Core J2EE Patterns - Session Facade.
<http://docs.sun.com/source/819-0079/dgjndi.html>. Acesso em: 31 outubro 2006.
Disponível em:
[GLASSFISH WIKI] GLASSFISH WIKI. List of Features proposed for v2. Disponível em:
<http://www.glassfishwiki.org/gfwiki/Wiki.jsp?page=ProposedHighLevelFeaturesForV2>. Acesso em:
27outubro 2006.
[GLASSFISH]
GLASSFISH
COMMUNITY.
About
GlassFish.
Disponível
<https://glassfish.dev.java.net/public/faq/GF_FAQ_2.html>. Acesso em: 27outubro 2006.
em:
[IMASTERS]
IMASTERS.
Usando
Connection
Pooling.
Disponível
em:
<http://www.imasters.com.br/artigo/3033/dotnet/usando_connection_pooling>. Acesso em: 27 outubro
2006.
[INFORMIT] INFORMIT.COM. Comparing JSTL and JSP Scriptlet Programming. Disponível em:
<http://www.informit.com/articles/article.asp?p=30334&seqNum=2&rl=1>. Acesso em: 30 outubro
2006.
[JAVA 01] SUN MICROSYSTEMS. Saiba mais sobre a tecnologia Java. Disponível
<http://www.java.com/pt_BR/about>. Acesso em: 27 outubro 2006.
em:
[JAVA
02]
SUN
MICROSYSTEMS.
The
Java
History
Timeline.
<http://www.java.com/en/javahistory/timeline.jsp>. Acesso em: 10 fevereiro 2006.
em:
Disponível
[JAVA 03] SUN MICROSYSTEMS. About the Java Technology.
Disponível em:
<http://java.sun.com/docs/books/tutorial/getStarted/intro/definition.html>. Acesso em: 23 maio 2006.
[JAVA CARD] SUN MICROSYSTEMS. Java Card Platform Specification 2.2.2. Disponível em:
<http://java.sun.com/products/javacard/specs.html>. Acesso em: 19 maio 2006.
[JAVA EE]
SUN MICROSYSTEMS. Java EE
<http://java.sun.com/javaee>. Acesso em: 19 maio 2006.
at
a
Glance.
Disponível
em:
[JAVA ME] SUN MICROSYSTEMS. Java ME - Micro App Development Made Easy. Disponível em:
<http://java.sun.com/javame>. Acesso em: 19 maio 2006.
[JAVA SE]
SUN MICROSYSTEMS. Java SE
<http://java.sun.com/javase>. Acesso em: 19 maio 2006.
2
at
a
Glance.
Disponível
em:
Sítios utilizados como referência em mais de um ponto possuem o número da referência logo após o nome do site. As
tecnologias do Java são referenciadas separadamente. Livros e assemelhados são identificados com o ano de publicação.
89
[JAVA NET] THE SOURCE FOR JAVA TECHNOLOGY COLLABORATION. A Brief History of the
Green Project. Disponível em: <http://today.java.net/jag/old/green>. Acesso em: 27 outubro 2006.
[JAVABEANS]
SUN
MICROSYSTEMS.
JavaBeans.
<http://java.sun.com/products/javabeans>. Acesso em: 27 outubro 2006.
Disponível
em:
[JNDI] SUN MICROSYSTEMS. Using the Java Naming and Directory Interface. Disponível em:
<http://docs.sun.com/source/819-0079/dgjndi.html>. Acesso em: 28 outubro 2006.
[JVM]
SUN MICROSYSTEMS. The Java Virtual Machine Specification.
Disponível em:
<http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html>. Acesso em: 19
maio 2006.
[KVM]
SUN
MICROSYSTEMS.
The
K
Virtual
Machine.
<http://java.sun.com/products/cldc/ds>. Acesso em: 19 maio 2006.
Disponível
[MYSQL]
MYSQL
AB.
History
of
MySQL.
Disponível
<http://dev.mysql.com/doc/refman/5.0/en/history.html>. Acesso em: 23 junho 2006.
em:
em:
[OMG] OBJECT MANAGEMENT GROUP. Introduction to OMG's Unified Modeling Language (UML).
Disponível em <http://www.omg.org/gettingstarted/what_is_uml.htm>. Acesso em 03 novembro 2006.
[PLUGMASTERS] PLUGMASTERS. Framework MVC: Apache Struts ou JavaServer Faces? parte 1.
Disponível em: <http://www.plugmasters.com.br/sys/materias/211/1/Framework-MVC:-Apache-Strutsou-JavaServer-Faces%3F-parte-1>. Acesso em: 27outubro 2006.
[PLUGMASTERS] PLUGMASTERS. Framework MVC: Apache Struts ou JavaServer Faces? parte 1.
Disponível em: <http://www.plugmasters.com.br/sys/materias/211/1/Framework-MVC:-Apache-Strutsou-JavaServer-Faces%3F-parte-1>. Acesso em: 27outubro 2006.
[POSTGRESQL] POSTGRESQL. History. Disponível em: <http://www.postgresql.org/about/history>.
Acesso em: 23 junho 2006.
[PRINCETON]
WORDNET.
Wordnet
search.
<http://wordnet.princeton.edu/perl/webwn>. Acesso em: 05 novembro 2006.
Disponível
[SAVANNAH]
SAVANNAH.
Concurrent
Versions
System.
<http://savannah.nongnu.org/projects/cvs>. Acesso em: 10 fevereiro 2006.
Disponível
em:
em:
[SRIGANESH 2006] SRIGANESH, Rima Patel; BROSE, Gerald; SILVERMAN, Micah. Mastering
Enterprise JavaBeans 3.0. Indianapolis, EUA: Wiley Publishing, Inc. 2006. 688 p.
[STRUTS]
THE
APACHE
SOFTWARE
FOUNDATION.
Struts.
<http://struts.apache.org/1.2.9/index.html>. Acesso em: 27 outubro 2006.
Disponível
[SUNONE]
SUN MICROSYSTEMS. Sun ONE Architecture Guide.
<http://www.sun.com/software/sunone/docs/arch>. Acesso em: 27outubro 2006.
Disponível
[TOMCAT]
THE APACHE SOFTWARE FOUNDATION. Apache Tomcat.
<http://tomcat.apache.org>. Acesso em: 27 outubro 2006.
Disponível
em:
em:
em:
[WIKIPEDIA
01]
WIKIPEDIA.
Java
(linguagem
de
programação).
Disponível
<http://pt.wikipedia.org/wiki/Linguagem_de_programação_Java>. Acesso em: 27 outubro 2006.
em:
[WIKIPEDIA
02]
WIKIPEDIA.
CRUD
(acronym).
<http://en.wikipedia.org/wiki/CRUD_(acronym)>. Acesso em: 28 outubro 2006.
em:
Disponível
[WIRED]
WIRED
NEWS.
The
Java
Saga.
Disponível
<http://www.wired.com/wired/archive/3.12/java.saga.html?pg=6>. Acesso em 27 outubro 2006.
em:
90
APÊNDICE A
SCRIPT PARA CRIAÇÃO DAS TABELAS NO BANCO DE DADOS
91
--- Estrutura da tabela PROJETO
-create table projeto (
codProjeto integer not null generated always as identity
(start with 1, increment by 1),
nome varchar(30) not null,
descricao long varchar not null,
constraint prj_PK primary key (codProjeto),
constraint prj_nome_IDX unique (nome)
);
--- Estrutura da tabela USUARIO
-CREATE TABLE usuario (
codUsuario integer not null generated always as identity
(start with 1, increment by 1),
login varchar(10) not null,
senha varchar(256) not null,
nome varchar(30) not null,
email varchar(60) not null,
constraint usu_PK primary key (codUsuario),
constraint usu_email_IDX unique (email)
);
--- Estrutura da tabela PROJ_USUARIO
-CREATE TABLE proj_usuario (
codProjeto int not null,
codUsuario int not null,
lider varchar(1) not null,
constraint prjusu_PK primary key
constraint prjusu_codUsuario_IDX
constraint prjusu_prj_FK foreign
projeto (codProjeto),
constraint prjusu_usu_FK foreign
usuario (codUsuario)
);
(codProjeto, codUsuario),
unique (codUsuario, codProjeto, lider),
key (codProjeto) references
key (codUsuario) references
92
APÊNDICE B
MÓDULO EJB
93
Projeto.java
package entidades.projeto;
import
import
import
import
import
import
import
import
java.io.Serializable;
javax.persistence.Column;
javax.persistence.Entity;
javax.persistence.GeneratedValue;
javax.persistence.GenerationType;
javax.persistence.Id;
javax.persistence.Lob;
javax.persistence.Table;
/**
* Classe entidade: Projeto
*
* @author Alessander Fecchio
*/
@Entity
@Table(name = "PROJETO")
public class Projeto implements Serializable {
/** Código do projeto. */
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "CODPROJETO", nullable = false)
private int codprojeto;
/** Nome do projeto. */
@Column(name = "NOME", nullable = false)
private String nome;
/** Descrição do projeto. */
@Lob
@Column(name = "DESCRICAO", nullable = false)
private String descricao;
/** Cria uma nova instância de Projeto. */
public Projeto() {
}
/**
* Cria uma nova instância de Projeto com dados já fornecidos.
* @param codprojeto O código do projeto.
*/
public Projeto(int codprojeto) {
this.codprojeto = codprojeto;
}
94
/**
* Cria uma nova instância de Projeto com dados já fornecidos.
* @param codprojeto O código do projeto.
* @param nome O nome do projeto.
* @param descricao A descrição do projeto.
*/
public Projeto(int codprojeto, String nome, String descricao) {
this.codprojeto = codprojeto;
this.nome = nome;
this.descricao = descricao;
}
/**
* Lê o código o projeto.
* @return O código do projeto.
*/
public int getCodprojeto() {
return this.codprojeto;
}
/**
* Altera o código do projeto para o valor especificado.
* @param codprojeto O novo código.
*/
public void setCodprojeto(int codprojeto) {
this.codprojeto = codprojeto;
}
/**
* Lê o nome do projeto.
* @return O nome do projeto.
*/
public String getNome() {
return this.nome;
}
/**
* Altera o nome do projeto para o valor especificado.
* @param nome O novo nome.
*/
public void setNome(String nome) {
this.nome = nome;
}
/**
* Lê a descrição do projeto.
* @return A descrição do projeto.
*/
public String getDescricao() {
return this.descricao;
}
/**
* Altera a descrição do projeto para o valor especificado.
* @param descricao A nova descrição.
*/
public void setDescricao(String descricao) {
this.descricao = descricao;
}
95
/**
* Retorna uma representação do objeto na forma de uma String.
* @return String com a descrição do objeto.
*/
@Override
public String toString() {
return "entidades.projeto.Projeto[codprojeto=" + codprojeto +
"] = " + nome;
}
}
PROJETOFACADE.JAVA
package entidades.projeto;
import
import
import
import
java.util.List;
javax.ejb.Stateless;
javax.persistence.EntityManager;
javax.persistence.PersistenceContext;
/**
* Classe facade para manipulação de Projeto.
*
* @author Alessander Fecchio
*/
@Stateless
public class ProjetoFacade implements ProjetoFacadeRemote {
@PersistenceContext
private EntityManager em;
/** Cria uma instância de ProjetoFacade */
public ProjetoFacade() {
}
/**
* Insere um projeto no banco de dados.
* @param projeto Projeto a ser inserido.
*/
public void create(Projeto projeto) {
em.persist(projeto);
}
/**
* Altera um projeto existente no banco de dados.
* @param projeto Projeto a ser alterado.
*/
public void edit(Projeto projeto) {
em.merge(projeto);
}
/**
* Exclui um projeto do banco de dados.
* @param projeto Projeto a ser excluído.
*/
public void destroy(Projeto projeto) {
em.remove(em.merge(projeto));
}
96
/**
* Exclui um projeto do banco de dados.
* @param id Código do projeto a ser excluído.
*/
public void destroy(int id) {
em.remove(this.find(id));
}
/**
* Pesquisa um projeto no banco de dados.
* @param pk Dados da chave primária para pesquisa (no caso,
* o código do projeto).
* @return O projeto localizado, ou então null.
*/
public Projeto find(Object pk) {
return (Projeto) em.find(Projeto.class, pk);
}
/**
* Pesquisa todos os projetos do banco de dados. Pode provocar queda no
* desempenho, de acordo com a quantidade de projetos cadastrados.
* @return List contendo os projetos localizados.
*/
public List findAll() {
return em.createQuery("select object(o) from Projeto as o")
.getResultList();
}
}
PROJETOFACADEREMOTE.JAVA
package entidades.projeto;
import java.util.List;
import javax.ejb.Remote;
/**
* Interface remota para acesso à classe ProjetoFacade.
* Maiores detalhes podem ser verificados na própria classe.
*
* @author Alessander Fecchio
*/
@Remote
public interface ProjetoFacadeRemote {
void create(Projeto projeto);
void edit(Projeto projeto);
void destroy(Projeto projeto);
Projeto find(Object pk);
List findAll();
void destroy(int id);
}
97
USUARIO.JAVA
package entidades.usuario;
import
import
import
import
import
import
import
java.io.Serializable;
javax.persistence.Column;
javax.persistence.Entity;
javax.persistence.GeneratedValue;
javax.persistence.GenerationType;
javax.persistence.Id;
javax.persistence.Table;
/**
* Classe entidade: Usuario
*
* @author Alessander Fecchio
*/
@Entity
@Table(name = "USUARIO")
public class Usuario implements Serializable {
/**
* Código do usuário.
*/
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "CODUSUARIO", nullable = false)
private int codusuario;
/**
* Login do usuário.
*/
@Column(name = "LOGIN", nullable = false)
private String login;
/**
* Senha do usuário.
*/
@Column(name = "SENHA", nullable = false)
private String senha;
/**
* Nome do usuário.
*/
@Column(name = "NOME", nullable = false)
private String nome;
/**
* E-mail do usuário.
*/
@Column(name = "EMAIL", nullable = false)
private String email;
/** Cria uma nova instância de Usuario. */
public Usuario() {
}
/**
* Cria uma nova instância de Projeto com dados já fornecidos.
* @param codusuario O código do Usuario.
*/
public Usuario(int codusuario) {
this.codusuario = codusuario;
}
98
/**
* Cria uma nova instância de Projeto com dados já fornecidos.
* @param codusuario Código do usuário.
* @param login Login do usuário.
* @param senha Senha do usuário.
* @param nome Nome do usuário.
* @param email E-mail do usuário.
*/
public Usuario(int codusuario, String login, String senha, String nome,
String email) {
this.codusuario = codusuario;
this.login = login;
this.senha = senha;
this.nome = nome;
this.email = email;
}
/**
* Lê o código do Usuario.
* @return O código do usuário.
*/
public int getCodusuario() {
return this.codusuario;
}
/**
* Altera o código do usuário para o novo valor.
* @param codusuario O novo código.
*/
public void setCodusuario(int codusuario) {
this.codusuario = codusuario;
}
/**
* Lê o login do usuário.
* @return O login do usuário.
*/
public String getLogin() {
return this.login;
}
/**
* Altera o login do usuário para o novo valor.
* @param login O novo login.
*/
public void setLogin(String login) {
this.login = login;
}
/**
* Lê a senha do usuário.
* @return A senha do usuário.
*/
public String getSenha() {
return this.senha;
}
/**
* Altera a senha do usuário para o novo valor.
* @param senha A nova senha.
*/
public void setSenha(String senha) {
this.senha = senha;
}
99
/**
* Lê o nome do usuário.
* @return O nome do usuário.
*/
public String getNome() {
return this.nome;
}
/**
* Altera o nome do usuário para o novo valor.
* @param nome O novo nome.
*/
public void setNome(String nome) {
this.nome = nome;
}
/**
* Lê o e-mail do usuário.
* @return O e-mail do usuário.
*/
public String getEmail() {
return this.email;
}
/**
* Altera o e-mail do usuário para o novo valor.
* @param e-mail O novo e-mail.
*/
public void setEmail(String email) {
this.email = email;
}
/**
* Retorna uma representação do objeto na forma de uma String.
* @return String com a descrição do objeto.
*/
@Override
public String toString() {
return "entidades.usuario.Usuario[codusuario=" + codusuario +
"] - " + nome;
}
}
USUARIOFACADE.JAVA
package entidades.usuario;
import
import
import
import
import
import
java.util.List;
javax.ejb.Stateless;
javax.persistence.EntityManager;
javax.persistence.PersistenceContext;
javax.persistence.Query;
utils.Criptografia;
/**
* Classe facade para a entidade Usuario.
* @author Alessander Fecchio
*/
@Stateless
public class UsuarioFacade implements UsuarioFacadeRemote {
100
/**
* O contexto de persistência.
*/
@PersistenceContext
private EntityManager em;
/**
* Objeto utilizado para docificar e decodificar strings.
*/
private Criptografia cripto;
/** Contrutor padrão */
public UsuarioFacade() {
try {
cripto = new Criptografia();
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* Insere um usuário no banco de dados.
* @param usuario Usuário a ser inserido.
*/
public void create(Usuario usuario) {
try {
cripto = new Criptografia();
usuario.setSenha(cripto.codificar(usuario.getSenha()));
em.persist(usuario);
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* Altera um usuário do banco de dados.
* @param usuario O usuário a ser alterado.
*/
public void edit(Usuario usuario) {
em.merge(usuario);
}
/**
* Exclui um usuário do banco de dados.
* @param usuario Usuário a ser excluído.
*/
public void destroy(Usuario usuario) {
em.remove(em.merge(usuario));
}
/**
* Exclui um usuário do banco de dados, localizando-o pelo seu código.
* @param id Código do usuário a ser excluído.
*/
public void destroy(int id) {
em.remove(this.find(id));
}
/**
* Pesquisa um usuário no banco de dados.
* @param pk O código do usuário a ser localizado.
* @return O usuário, se ele for localizado.
*/
public Usuario find(Object pk) {
return (Usuario) em.find(Usuario.class, pk);
}
101
/**
* Pesquisa todos os usuários do banco de dados.
* @return Um List com todo os usuários cadastrados.
*/
public List findAll() {
return em.createQuery("select object(o) from Usuario as o")
.getResultList();
}
/**
* Pesquisa um usuário pelo seu login.
* @param login Login do usuário a ser encontrado.
* @return O usuário com o login especificado, se ele for localizado.
*/
public Usuario findByLogin(String login) {
String s = "select object(o) from Usuario as o " +
"where o.login=:prmLogin";
Query q = em.createQuery(s);
q.setParameter("prmLogin", login);
Usuario result = (Usuario) q.getSingleResult();
return result;
}
/**
* Autentica um usuário e senha.
* @param login Login do usuário.
* @param senha Senha do usuário.
* @return Um valor booleano true (se o usuário e senha estiverem
* corretos) ou false (caso não estejam).
*/
public boolean autentica(String login, String senha) {
boolean result = false;
Usuario usuario = findByLogin(login);
if (usuario==null) {
result = false;
} else {
try {
senha = cripto.codificar(senha);
result = usuario.getSenha().equals( senha );
} catch (Exception ex) {
result = false;
}
}
return result;
}
}
USUARIOFACADEREMOTE.JAVA
package entidades.usuario;
import java.util.List;
import javax.ejb.Remote;
/**
* Interface remota para acesso à classe UsuarioFacade.
* Maiores detalhes podem ser verificados na própria classe.
*
* @author Alessander Fecchio
*/
102
@Remote
public interface UsuarioFacadeRemote {
void create(Usuario usuario);
void edit(Usuario usuario);
void destroy(Usuario usuario);
Usuario find(Object pk);
List findAll();
void destroy(int id);
Usuario findByLogin(String login);
boolean autentica(String login, String senha);
}
PROJETOUSUARIO.JAVA
package entidades.projetousuario;
import
import
import
import
import
import
import
import
import
entidades.projeto.Projeto;
entidades.usuario.Usuario;
java.io.Serializable;
javax.persistence.Column;
javax.persistence.EmbeddedId;
javax.persistence.Entity;
javax.persistence.JoinColumn;
javax.persistence.ManyToOne;
javax.persistence.Table;
/**
* Entidade: ProjetoUsuario (associação indicando em
* quais projetos cada usuário está alocado)
*
* @author Alessander Fecchio
*/
@Entity
@Table(name = "PROJ_USUARIO")
public class ProjetoUsuario implements Serializable {
/** Chave primária */
@EmbeddedId
protected ProjetoUsuarioPK projetoUsuarioPK;
/** Indica se o usuário é lider do projeto indicado. */
@Column(name = "LIDER", nullable = false)
private String lider;
/** O projeto ao qual o usuário está alocado */
@JoinColumn(name = "CODPROJETO", referencedColumnName = "CODPROJETO",
insertable = false, updatable = false)
@ManyToOne
private Projeto projeto;
103
/** Usuário alocado ao projeto */
@JoinColumn(name = "CODUSUARIO", referencedColumnName = "CODUSUARIO",
insertable = false, updatable = false)
@ManyToOne
private Usuario usuario;
/** Cria uma instância de ProjetoUsuario */
public ProjetoUsuario() {
}
/**
* Cria uma instância de ProjetoUsuario, com valores já
* iniciados.
* @param projetoUsuarioPK A chave primária do ProjetoUsuario.
*/
public ProjetoUsuario(ProjetoUsuarioPK projetoUsuarioPK) {
this.projetoUsuarioPK = projetoUsuarioPK;
}
/**
* Cria uma instância de ProjetoUsuario, com valores já
* iniciados.
* @param projetoUsuarioPK A chave primária do ProjetoUsuario.
* @param lider Indica se o usuário é lider ("S") ou não ("N") do projeto
* em questão.
*/
public ProjetoUsuario(ProjetoUsuarioPK projetoUsuarioPK, String lider) {
this.projetoUsuarioPK = projetoUsuarioPK;
this.lider = lider;
}
/**
* Cria uma instância de ProjetoUsuario, com valores já
* iniciados.
* @param codusuario Código do usuário.
* @param codprojeto Código do projeto.
* @param lider Indica se o usuário é lider ("S") ou não ("N") do projeto
* em questão.
*/
public ProjetoUsuario(int codusuario, int codprojeto, String lider) {
this.projetoUsuarioPK = new ProjetoUsuarioPK(codusuario, codprojeto);
this.lider = lider;
}
/**
* Método para cria um ProjetoUsuario a partir dos códigos de
* projeto e usuário.
* @param codusuario O código do usuário.
* @param codprojeto O código do projeto.
*/
public ProjetoUsuario(int codusuario, int codprojeto) {
this.projetoUsuarioPK = new ProjetoUsuarioPK(codusuario, codprojeto);
}
/**
* Retorna a chave primária de ProjetoUsuario.
* @return A chave primária.
*/
public ProjetoUsuarioPK getProjetoUsuarioPK() {
return this.projetoUsuarioPK;
}
104
/**
* Define a chave primária do ProjetoUsuario.
* @param projetoUsuarioPK A chave primária.
*/
public void setProjetoUsuarioPK(ProjetoUsuarioPK projetoUsuarioPK) {
this.projetoUsuarioPK = projetoUsuarioPK;
}
/**
* Lê o conteúdo do campo lider.
* @return String indicando se o usuário é lider ("S") ou não ("N") do
* projeto.
*/
public String getLider() {
return this.lider;
}
/**
* Altera o indicador de liderança para o novo valor.
* @param lider O novo valor de lider.
*/
public void setLider(String lider) {
this.lider = lider;
}
/**
* Indicando se o usuário é lider ou não do projeto
* @return Boolean indicando se o usuário é lider (true) ou não (false) do
* projeto
*/
public boolean isLider() {
return (this.getLider().equalsIgnoreCase("s"));
}
/**
* Lê o projeto de ProjetoUsuario.
* @return O Projeto.
*/
public Projeto getProjeto() {
return this.projeto;
}
/**
* Altera o Projeto para do ProjetoUsuario.
* @param projeto O novo projeto.
*/
public void setProjeto(Projeto projeto) {
this.projeto = projeto;
}
/**
* Lê o usuário do ProjetoUsuario.
* @return O usuário.
*/
public Usuario getUsuario() {
return this.usuario;
}
/**
* Altera o Usuario do ProjetoUsuario.
* @param usuario O novo Usuario.
*/
public void setUsuario(Usuario usuario) {
this.usuario = usuario;
}
105
/**
* Retorna uma representação do objeto na forma de uma String.
* @return String com a descrição do objeto.
*/
@Override
public String toString() {
return "entidades.projetousuario.ProjetoUsuario[projetoUsuarioPK="
+ projetoUsuarioPK + "]";
}
}
PROJETOUSUARIOFACADE.JAVA
package entidades.projetousuario;
import java.util.List;
import javax.ejb.Stateless;
import javax.jws.WebService;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
/**
* Classe para manipulação de ProjetoUsuario no banco de dados.
*
* @author Alessander Fecchio
*/
@Stateless
public class ProjetoUsuarioFacade implements ProjetoUsuarioFacadeRemote {
/** Contexto de persistência, utilizado para realizar operações no
* banco de dados.
*/
@PersistenceContext
private EntityManager em;
/** Cria uma instância de ProjetoUsuarioFacade. */
public ProjetoUsuarioFacade() {
}
/**
* Insere um ProjetoUsuario no banco de dados.
* @param projetoUsuario O ProjetoUsuario a ser gravado.
*/
public void create(ProjetoUsuario projetoUsuario) {
em.persist(projetoUsuario);
}
/**
* Altera um ProjetoUsuario gravado no banco de dados.
* @param projetoUsuario O ProjetoUsuario a ser gravado.
*/
public void edit(ProjetoUsuario projetoUsuario) {
em.merge(projetoUsuario);
}
106
/**
* Exclui um ProjetoUsuario gravado no banco de dados.
* @param projetoUsuario O ProjetoUsuario a ser excluído.
*/
public void destroy(ProjetoUsuario projetoUsuario) {
em.remove(em.merge(projetoUsuario));
}
/**
* Pesquisa um ProjetoUsuario gravado no banco de dados.
* A chave primária é um objeto do tipo ProjetoUsuarioPK.
* @param pk ProjetoUsuarioPK contendo o projeto e usuário a
* ser pesquisado.
* @return Um ProjetoUsuario correspondente à chave primária.
* Se não for encontrado, retornará um ProjetoUsuario vazio.
*/
public ProjetoUsuario find(Object pk) {
return (ProjetoUsuario) em.find(ProjetoUsuario.class, pk);
}
/**
* Retorna todos os ProjetoUsuario gravados no banco de dados.
* @return Todos os ProjetoUsuario gravados no banco de dados.
*/
public List findAll() {
return em.createQuery("select object(o) from ProjetoUsuario as o")
.getResultList();
}
/**
* Pesquisa todos os projetos ligados a um determinado usuário.
* @param codUsuario Código do usuário de quem os projetos serão
* pesquisados.
* @return List com todos os projetos dos quais o usuário participa.
*/
public List findProjetosPorUsuario(int codUsuario) {
String q = "select object(o) from ProjetoUsuario as o " +
"where o.usuario.codusuario=:codUsuario";
Query query = em.createQuery(q);
query.setParameter("codUsuario", codUsuario);
List result = query.getResultList();
return result;
}
}
PROJETOUSUARIOFACADEREMOTE.JAVA
package entidades.projetousuario;
import java.util.List;
import javax.ejb.Remote;
/**
* Interface remota para acesso à classe ProjetoUsuarioFacade.
* Maiores detalhes podem ser verificados na própria classe.
*
* @author Alessander Fecchio
*/
107
@Remote
public interface ProjetoUsuarioFacadeRemote {
void create(ProjetoUsuario projetoUsuario);
void edit(ProjetoUsuario projetoUsuario);
void destroy(ProjetoUsuario projetoUsuario);
ProjetoUsuario find(Object pk);
List findAll();
List findProjetosPorUsuario(int codUsuario);
}
PROJETOUSUARIOPK.JAVA
package entidades.projetousuario;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
/**
* Chave primária da entidade ProjetoUsuario
*
* @author Alessander Fecchio
*/
@Embeddable
public class ProjetoUsuarioPK implements Serializable {
/** Código do projeto. */
@Column(name = "CODPROJETO", nullable = false)
private int codprojeto;
/** Código do usuário */
@Column(name = "CODUSUARIO", nullable = false)
private int codusuario;
/** Cria uma nova instância de ProjetoUsuarioPK */
public ProjetoUsuarioPK() {
}
/**
* Cria uma nova instância de ProjetoUsuarioPK com valores
* já definidos.
* @param codusuario O código do usuário.
* @param codprojeto O código do projeto.
*/
public ProjetoUsuarioPK(int codusuario, int codprojeto) {
this.codusuario = codusuario;
this.codprojeto = codprojeto;
}
/**
* Lê o código do projeto.
* @return O código do projeto.
*/
public int getCodprojeto() {
return this.codprojeto;
}
108
/**
* Altera o código do projeto.
* @param codprojeto O novo código do projeto.
*/
public void setCodprojeto(int codprojeto) {
this.codprojeto = codprojeto;
}
/**
* Lê o código do usuário.
* @return O código do usuário.
*/
public int getCodusuario() {
return this.codusuario;
}
/**
* Altera o código do usuário.
* @param codusuario O novo código do usuário.
*/
public void setCodusuario(int codusuario) {
this.codusuario = codusuario;
}
/**
* Retorna uma representação do objeto na forma de uma String.
* @return String com a descrição do objeto.
*/
@Override
public String toString() {
return "entidades.projetousuario.ProjetoUsuarioPK[codusuario=" +
codusuario + ", codprojeto=" + codprojeto + "]";
}
}
MENSAGEM.JAVA
package utils;
/**
* Classe auxiliar utilizada para criar mensagens para envio ao log do
* servidor de aplicações.
* @author Alessander Fecchio
*/
public class Mensagem {
/** Construtor padrão. */
public Mensagem() {
}
109
/**
* Cria uma String, contendo qtd repetições da string msg.
* @param msg String a ser repetida.
* @param qtd Quantidade de vezes que msg será repetida.
* @return Uma String contendo qtd repetições de msg.
*/
public static String replicate(String msg, int qtd) {
String result = "";
for (int i=0; i<qtd; i++) {
result += msg;
}
return result;
}
/**
* Formata a mensagem a ser enviada ao log.
* @param msg Mensagem a ser enviada ao log.
* @return A mensagem formatada.
*/
public static String erroConsole(String msg) {
String linha = replicate("-", msg.length());
String result = "\n";
result += "+-" + linha + "-+\n";
result += "| " + msg
+ " |\n";
result += "+-" + linha + "-+\n";
return result;
}
}
CRIPTOGRAFIA.JAVA
package utils;
import
import
import
import
import
import
import
import
com.sun.crypto.provider.SunJCE;
java.security.Security;
java.security.spec.AlgorithmParameterSpec;
java.security.spec.KeySpec;
javax.crypto.Cipher;
javax.crypto.SecretKey;
javax.crypto.SecretKeyFactory;
javax.crypto.spec.DESedeKeySpec;
/**
* Classe para codificação e decodificação de Strings.
* Utilizada para criptografia das senhas.
*
* @author Alessander Fecchio
*/
public class Criptografia {
/** Chave a ser utilizada nos processos de codificação e decodificação. */
private SecretKey chaveSecreta;
/**
* Interface para criação de parâmetros criptográficos.
*/
private AlgorithmParameterSpec paramSpec = null;
110
/**
* Cria uma nova instância de Criptografia.
* @throws Exception Exceção genérica.
*/
public Criptografia() throws Exception {
/* cada elemento é um código ASCII convertido para hexadecimal e
* typecasted para byte.
* DICA: pode-se mudar a chave padrão para mesclar dados próprios do
* usuário, como nome, sobrenome, etc,
*/
byte[] chavePadrao = {
(byte)0x73, (byte)0x33, (byte)0x57, (byte)0x43,
(byte)0x55, (byte)0x40, (byte)0x38, (byte)0x6C,
(byte)0xDE, (byte)0x90, (byte)0x21, (byte)0x2C,
(byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C,
(byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40,
(byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB
};
SunJCE provider = new SunJCE();
Security.addProvider(provider);
geraChaveSecreta(chavePadrao);
}
/**
* Converte um array de bytes em uma string hexadecimal.
* Durante o processo, é efetuado um deslocamento bit a bit, de modo a
* aumentar a complexidade da chave e, conseqüentemente, sua segurança.
* @param block Array de bytes a ser convertido.
* @return Uma string codificada, contendo hexadecimais.
*/
private String toHexString(byte[] block) {
String hexits = "0123456789ABCDEF";
StringBuffer buf = new StringBuffer();
for (int i = 0; i < block.length; i++) {
buf.append(hexits.charAt((block[i] >>> 4) & 0xf));
buf.append(hexits.charAt(block[i] & 0xf));
}
return buf.toString();
}
/**
* Converte uma string hexadecimal em um array de bytes.
* @param valueHexa Strinf de hexadecimais.
* @return Um array de bytes.
*/
private byte[] toByteArray(String valueHexa) {
byte[] array = new byte[valueHexa.length() / 2];
for (int i = valueHexa.length(); i > 0; i -= 2) {
array[(i / 2) - 1] =
(byte) Integer.parseInt(valueHexa.substring(i - 2, i), 16);
}
return array;
}
111
/**
* Método utilizado para gerar um SecretKey utilizado no
* processo de criptografia.
* @param chave Um array de bytes contendo a chave.
* @throws Exception Exceção genérica.
*/
private void geraChaveSecreta(byte[] chave) throws Exception {
KeySpec keySpec;
keySpec = new DESedeKeySpec(chave);
// Gera a chave secreta
SecretKeyFactory factory = SecretKeyFactory.getInstance("TripleDES");
chaveSecreta = factory.generateSecret(keySpec);
}
/**
* Codifica uma string.
* @param mensagem String a ser codificada.
* @throws Exception Exceção genérica.
* @return Uma string codificada, contendo hexadecimais.
*/
public String codificar(String mensagem) throws Exception {
Cipher cipher = Cipher.getInstance("TripleDES");
cipher.init(Cipher.ENCRYPT_MODE, chaveSecreta, paramSpec);
return toHexString(cipher.doFinal(mensagem.getBytes()));
}
/**
* Decofica uma string já codificada.
* @param mensagem String a ser decodificado.
* @throws Exception wexceção genérica.
* @return A String original, antes de ser codificada.
*/
public String decodificar(String mensagem) throws Exception {
Cipher cipher = Cipher.getInstance("TripleDES");
cipher.init(Cipher.DECRYPT_MODE, chaveSecreta, paramSpec);
return new String(cipher.doFinal(toByteArray(mensagem)));
}
}
112
APÊNDICE C
MÓDULO CLIENTE DESKTOP
113
MAIN.JAVA
package maxigroupware;
import entidades.projeto.Projeto;
import entidades.projeto.ProjetoFacadeRemote;
import java.sql.Timestamp;
import java.util.List;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
/**
* Aplicação cliente, executada pela linha de comando,
* para teste de manipulação de EJB.
* @author Alessander Fecchio
*/
public class Main {
/** Interface para acesso à entidade Projeto. */
private static ProjetoFacadeRemote projetoFR;
/**
* Método executável da classe.
* @param args Lista de argumentos passados via linha de comando.
* O método escreveSintaxe contém todas as sintaxes válidas.
*/
public static void main(String[] args) {
Main teste = new Main();
teste.executa(args);
}
/**
* Método chamado pelo método main(), executa todas
* as operações possíveis.
* @param args Lista de argumentos passada via linha de comando.
*/
private void executa(String[] args) {
try {
Properties p = System.getProperties();
p.put(Context.PROVIDER_URL, "localhost:1099");
Context ctx = new InitialContext(p);
try {
projetoFR = (ProjetoFacadeRemote)
ctx.lookup("entidades.projeto.ProjetoFacadeRemote");
} catch (NameNotFoundException ex) {
System.out.println(utils.Mensagem.erroConsole(
"EJB não encontrado: ProjetoFacadeRemote"));
System.exit(1);
}
114
if (! verificaParametros(args)) {
System.exit(1);
}
if (args[0].equals("-l")) {
lista("");
} else {
lista("ANTES");
if (args[0].equals("-c")) {
create();
} else if (args[0].equals("-r")) {
recover(args[1]);
} else if (args[0].equals("-u")) {
update(args[1]);
} else if (args[0].equals("-d")) {
delete(args[1]);
}
lista("DEPOIS");
}
} catch (NamingException ex) {
ex.printStackTrace();
}
}
/**
* Lista todos os projetos cadastrados.
* @param s Mensagem a ser impressa no cabeçalho da lista.
*/
private void lista(String s) {
System.out.println("\n--- Lista " + s + " ---");
List lista = projetoFR.findAll();
for (Object o : lista) {
System.out.println("
" + o.toString());
}
System.out.println();
}
/**
* Cria um projeto. Inclui um Timestamp no nome e da descrição.
* Deste modo, é possível incluir vários projetos sem informar
* estes dados, que serão gerados dinamicamente.
*/
private void create() {
System.out.println("\n--- Criando ---");
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
Projeto p = new Projeto();
p.setNome("Prj: " + timestamp);
p.setDescricao("Criado em " + timestamp);
projetoFR.create(p);
System.out.println("
" + p.toString());
System.out.println();
}
/**
* Pesquisa um projeto gravado no banco de dados.
* Se encontrar, mostra seus dados. Caso contrário,
* emite uma mensagem de erro.
* O código do projeto deve ser informado na linha
* de comando e ser um projeto válido.
* @param s Código do projeto a ser pesquisado.
*/
private void recover(String s) {
int codigo = Integer.parseInt(s);
System.out.println("\n--- Recuperando projeto " + s + " ---");
115
Projeto p = projetoFR.find(codigo);
if (p==null) {
System.out.println("
Projeto nao encontrado: " + s);
} else {
System.out.println("
" + p.toString());
}
System.out.println();
}
/**
* Exclui um projeto do banco de dados.
* O código do projeto deve ser informado na linha
* de comando e ser um projeto válido.
* @param s Código do projeto a ser excluído.
*/
private void delete(String s) {
int codigo = Integer.parseInt(s);
System.out.println("\n--- Excluindo projeto " + s + " ---");
projetoFR.destroy(codigo);
System.out.println();
}
/**
* Atualiza um projeto no banco de dados.
* O código do projeto deve ser informado na linha
* de comando e ser um projeto válido.
* A alteração é a substituição do Timestamp da criação
* pelo da alteração.
* @param s Código do projeto a ser atualizado.
*/
private void update(String s) {
int codigo = Integer.parseInt(s);
System.out.println("\n--- Atualizando projeto " + s + " ---");
Projeto p = projetoFR.find(codigo);
if (p==null) {
System.out.println("
Projeto nao encontrado: " + s);
} else {
System.out.println("
Antes da alteracao: " + p.toString());
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
p.setNome("Prj: " + timestamp);
p.setDescricao("Alterado em " + timestamp);
projetoFR.edit(p);
System.out.println("
Depois: " + p.toString());
}
System.out.println();
}
/**
* Verifica se os parâmetros passados via linha
* de comando são válidos. Se não forem, o aplicativo
* é finalizado.
* @param args Argumentos passados via linha de comando.
* @return Booleando indicando se os parâmetros são
* válidos (true) ou não (false).
*/
private boolean verificaParametros(String[] args) {
boolean result = true;
// parâmetros não informados
if (args.length == 0) {
escreveSintaxe("Nenhum parametro informado");
return false;
};
116
args[0] = args[0].toLowerCase();
String aux = "-c-r-u-d-l";
if (args[0].startsWith("-") && aux.contains(args[0])) {
// parâmetro válido
aux = "-r-u-d";
if (aux.contains(args[0]) && args.length<2) {
// código não informado
escreveSintaxe("Codigo do projeto nao informado.");
return false;
} else if (aux.contains(args[0])) {
try {
int tmp = Integer.parseInt(args[1]);
} catch (NumberFormatException ex) {
escreveSintaxe("Codigo deve ser um numero inteiro.");
return false;
}
}
} else {
// parâmetro inválido
escreveSintaxe("Parametro invalido.");
return false;
}
return true;
}
/**
* Escreve a sintaxe do aplicativo na tela, com uma
* mensagem de cabeçalho.
* @param s Mensagem a ser exibida no cabeçalho.
*/
public void escreveSintaxe(String s) {
System.out.println("\n\n" + s);
System.out.println("+----------------------+");
System.out.println("| PARA
UTILIZE
|");
System.out.println("| ------------- |");
System.out.println("| Listar
-l
|");
System.out.println("| Criar
-c
|");
System.out.println("| Pesquisar -r codigo |");
System.out.println("| Atualizar -u codigo |");
System.out.println("| Excluir
-d codigo |");
System.out.println("+----------------------+");
}
}
CREATEUSER.JAVA
package maxigroupware;
import entidades.usuario.Usuario;
import entidades.usuario.UsuarioFacadeRemote;
import java.util.List;
import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
/** @author Alessander Fecchio */
public class CreateUser {
/** Interface para acesso à entidade Usuario. */
private static UsuarioFacadeRemote usuarioFR;
117
/**
* Método executável da classe.
* @param args Lista de argumentos passados via linha de comando.
* O método escreveSintaxe contém todas as sintaxes válidas.
*/
public static void main(String[] args) {
CreateUser teste = new CreateUser();
teste.executa(args);
}
/**
* Lista todos os usuarios cadastrados.
* @param s Mensagem a ser impressa no cabeçalho da lista.
*/
private void lista(String s) {
System.out.println("\n--- Lista " + s + " ---");
List lista = usuarioFR.findAll();
for (Object o : lista) {
System.out.println("
" + o.toString());
}
System.out.println();
}
/**
* Método chamado pelo método main(), cria o usuário solicitado.
* @param args Lista de argumentos passada via linha de comando.
*/
private void executa(String[] args) {
try {
Properties p = System.getProperties();
p.put(Context.PROVIDER_URL, "localhost:1099");
Context ctx = new InitialContext(p);
try {
usuarioFR = (UsuarioFacadeRemote)
ctx.lookup("entidades.usuario.UsuarioFacadeRemote");
} catch (NameNotFoundException ex) {
System.out.println(utils.Mensagem.erroConsole(
"EJB não encontrado: UsuarioFacadeRemote"));
System.exit(1);
}
if (args.length <4) {
System.out.println("\nNumero de parametros incorreto.");
System.out.println("\nUTILIZE");
System.out.println(" CreateUser <login> <senha> <nome> <email> |");
System.out.println("\nDados que contenham espacos em branco " +
"devem ser informados entre aspas.");
System.exit(1);
};
lista("ANTES");
/* Criação do usuario */
System.out.println("\n--- Criando ---");
Usuario usuario = new Usuario();
usuario.setLogin(args[0]);
usuario.setSenha(args[1]);
usuario.setNome(args[2]);
usuario.setEmail(args[3]);
usuarioFR.create(usuario);
System.out.println("
" + usuario.toString() + " criado.");
System.out.println();
lista("DEPOIS");
} catch (NamingException ex) {
ex.printStackTrace();
}
}
}
118
APÊNDICE D
MÓDULO APLICATIVO WEB
119
INDEX.JSP
<script>
document.location="./faces/login.jsp"
</script>
LOGIN.JSP
<%@ include file="/recursos/cabecalho.jsp" %>
<f:view>
<h1>Não Autenticado</h1>
<h:messages errorClass="errorMessage" infoClass="successMessage"
layout="table" /></p>
<h:form id="form1">
<h:panelGrid columns="2" id="panelGrid1">
<h:outputText value="Login" id="outLogin"/>
<h:inputText binding="#{Login.login}" id="login"/>
<h:outputText value="Senha" id="outputText2"/>
<h:inputSecret binding="#{Login.senha}" id="senha"/>
</h:panelGrid>
<p>
<h:commandButton value="Login" id="enviar"
action="#{Login.autenticar}"/>
</p>
</h:form>
</f:view>
<%@ include file="/recursos/rodape.jsp" %>
MENSAGENS/LOGIN_ERRO.JSP
<%@ include file="/recursos/cabecalho.jsp" %>
<f:view>
<h1>Não Autenticado</h1>
<h:messages errorStyle="color: red" infoStyle="color: green" layout="table" />
</f:view>
<p>
<a href="./faces/login.jsp">Login</a><p/>
<%@ include file="/recursos/rodape.jsp" %>
mensagens/login_ok.jsp
<%@ include file="/recursos/cabecalho.jsp" %>
<%@ page import="entidades.usuario.Usuario" %>
<f:view>
<h1>Autenticado</h1>
<h:messages errorStyle="color: red" infoStyle="color: green" layout="table" />
</p>
<h:outputText value="Usuario: #{Login.usuario}" />
</f:view>
<p>
<a href="./faces/login.jsp">Login</a><p/>
<%@ include file="/recursos/rodape.jsp" %>
120
RECURSOS/ESTILOS.CSS
body, p {
font-family: Verdana, Helvetica, sans-serif;
font-size:9pt;
color:#000000;
}
h1 {
font-family: Verdana, Helvetica, sans-serif;
color:#336699;
width : 100%;
font-size:170%;
border : solid #CCCC99;
border-width : 0px 0px 2px 0px;
}
RECURSOS/CABECALHO.JSP
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="/maxi/recursos/estilos.css" rel="stylesheet"/>
<title>MaxiGroupware</title>
</head>
<body>
recursos/rodape.jsp
</body>
</html>
FACES_CONFIG.XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE faces-config PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces
Config 1.1//EN" "http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config xmlns="http://java.sun.com/JSF/Configuration">
<managed-bean>
<managed-bean-name>Login</managed-bean-name>
<managed-bean-class>manage.Login</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<navigation-rule>
<from-view-id>/login.jsp</from-view-id>
<navigation-case>
<from-action>#{Login.autenticar}</from-action>
<from-outcome>autenticado</from-outcome>
<to-view-id>/mensagens/login_ok.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{Login.autenticar}</from-action>
<from-outcome>nao_autenticado</from-outcome>
<to-view-id>/mensagens/login_erro.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
121
WEB.XML
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>com.sun.faces.verifyObjects</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.validateXml</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
SUN-WEB.XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Application Server 9.0 Servlet 2.5//EN"
"http://www.sun.com/software/appserver/dtds/sun-web-app_2_5-0.dtd">
<sun-web-app error-url="">
<context-root>/maxi</context-root>
<class-loader delegate="true"/>
<jsp-config>
<property name="classdebuginfo" value="true">
<description>Enable debug info compilation in the generated servlet
class</description>
</property>
<property name="mappedfile" value="true">
<description>Maintain a one-to-one correspondence between static content and
the generated servlet class' java code</description>
</property>
</jsp-config>
</sun-web-app>
122
MANAGE/LOGIN.JAVA
package manage;
import entidades.usuario.Usuario;
import entidades.usuario.UsuarioFacadeRemote;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.component.html.HtmlCommandButton;
import javax.faces.component.html.HtmlInputSecret;
import javax.faces.component.html.HtmlInputText;
import javax.faces.context.FacesContext;
import utils.Criptografia;
/**
* Bean gerenciado para manipular informações do login do usuário.
* @author Alessander Fecchio
*/
public class Login {
/** Referência ao EJB UsuarioFacade através de sua interface remota. */
@EJB(beanName="UsuarioFacade", beanInterface=UsuarioFacadeRemote.class)
private UsuarioFacadeRemote usuarioFR;
/** Objeto Usuario, para manipulação das informações. */
private Usuario usuario=null;
/**
* Instância da classe Criptografia, utilizada para
* codificar e decodificar informações.
*/
private Criptografia cripto;
/** Componente visual da página JSF para informar o login do usuário. */
private HtmlInputText login;
/** Componente visual da página JSF para informar a senha do usuário. */
private HtmlInputSecret senha;
/** Botão Enviar. */
private HtmlCommandButton enviar;
/**
* Busca o objeto representando o componente visual Login.
* @return O componente visual Login.
*/
public HtmlInputText getLogin() {
return login;
}
/**
* Altera o conteúdo do componente visual Login.
* @param login O novo login.
*/
public void setLogin(HtmlInputText login) {
this.login = login;
}
/**
* Busca o objeto representando o componente visual Senha.
* @return O componente visual Login.
*/
public HtmlInputSecret getSenha() {
return senha;
}
123
/**
* Altera o conteúdo do componente visual Senha.
* @param senha A nova senha.
*/
public void setSenha(HtmlInputSecret senha) {
this.senha = senha;
}
/**
* Autentica o usuário utilizando o login e senha informados.
* @return String contendo a próxima página a ser mostrada,
* de acordo com o resultado da autenticação.
*/
public String autenticar() {
String result = "nao_autenticado";
String usuarioForm = getLogin().getValue().toString();
String senhaForm = getSenha().getValue().toString();
boolean autenticado = false;
try {
if (usuarioForm.equals("") || senhaForm.equals("")) {
addErrorMessage("Informe o login e a senha!");
} else {
autenticado = usuarioFR.autentica(usuarioForm, senhaForm);
if (autenticado) {
setUsuario(usuarioFR.findByLogin(usuarioForm));
FacesContext facesContext=FacesContext.getCurrentInstance();
facesContext.getExternalContext()
.getSessionMap().put("_usuario", getUsuario());
addSuccessMessage("Autenticação OK!");
} else {
throw new Exception("Erro");
}
}
} catch (Exception e) {
setUsuario(null);
addErrorMessage("Erro na autenticação do usuário. " +
"Certifique-se que informou os dados corretos!");
}
return (autenticado ? "autenticado" : "nao_autenticado");
}
/**
* Adiciona uma mensagem de erro à lista de mensagens da sessão.
* @param msg A mensagem a ser adicionada.
*/
public static void addErrorMessage(String msg) {
FacesMessage facesMsg =
new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, msg);
FacesContext fc = FacesContext.getCurrentInstance();
fc.addMessage(null, facesMsg);
}
/**
* Adiciona uma mensagem de erro à lista de mensagens da sessão.
* @param msg A mensagem a ser adicionada.
*/
public static void addSuccessMessage(String msg) {
FacesMessage facesMsg =
new FacesMessage(FacesMessage.SEVERITY_INFO, msg, msg);
FacesContext fc = FacesContext.getCurrentInstance();
fc.addMessage(null, facesMsg);
}
124
/**
* Retorna o usuário autenticado.
* @return O usuário autenticado.
*/
public Usuario getUsuario() {
return usuario;
}
/**
* Define o novo usuário autenticado.
* @param usuario O novo usuário.
*/
public void setUsuario(Usuario usuario) {
this.usuario = usuario;
}
}
Download