Professional Documents
Culture Documents
ALESSANDER FECCHIO
CURITIBA
2006
UNIVERSIDADE TECNOLÓGICA FEDERAL DO PARANÁ
DEPARTAMENTO ACADÊMICO DE INFORMÁTICA
ESPECIALIZAÇÃO EM TECNOLOGIA JAVA
ALESSANDER FECCHIO
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
1 INTRODUÇÃ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.
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
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).
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].
“...a new small, safe, secure, distributed, robust, interpreted, garbage collected, multi-threaded,
architecture neutral, high performance, dynamic programming language...” [JAVA NET]
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].
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.
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].
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]:
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 • Nascimento do Java. Pai: James Gosling. Mãe: Sun Microsystems;
• Anúncio oficial na SunWorld.
1996 • 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.
1 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.
1998 • 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.
1999 • 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),
Java 2 Enterprise Edition (J2EE), Java 2 Micro Edition (J2ME);
• Liberação da plataforma J2EE;
• Liberação da plataforma J2SE para Linux.
2000 • 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.
2006 • Lançamento do Java Enterprise Edition 5 (Java EE 5), nova versão do J2EE
Tabela 1: Evolução da plataforma Java. [JAVA 02]
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.
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.
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.
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.
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.
A Figura 4 demonstra as edições do Java, e a JVM utilizada por cada uma delas.
O Java EE é a edição mais abrangente do Java, pois engloba todas as tecnologias para
desenvolvimento em ambientes de servidor e desktop.
As principais alterações do Java EE 5 em relação a sua versão anterior são [JAVA EE]:
• 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.
Os componentes web são executados no servidor (que pode ser um servidor Java EE
ou simplesmente um container JSP).
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.
• 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
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.
IDE é um aplicativo que agrega várias ferramentas com o único objetivo de desenvolver
software . A maioria dos IDE possui ferramentas que permitem:
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.
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.
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.
É 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.3 MVC
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].
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
Por estas características, o JSF foi utilizado para o desenvolvimento deste trabalho,
utilizando a implementação de referência da Sun.
4.4.1 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:
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
• 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ão-
livre ou for obtido lucro com ele.
4.4.2 PostgreSQL
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.
Por todas estas características, o Derby foi utilizado no desenvolvimento deste trabalho.
30
É 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.
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.
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
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.
O NetBeans e o SJSAS são patrocinados pela Sun, e por isso são facilmente
integrados:
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:
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.
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.
• 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.
• 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.
O segundo passo é criar as tabelas do banco de dados. A criação pode ser feita de duas
maneiras:
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.
As tabelas de projetos e usuários foram criadas com uma chave primária do tipo auto-
incremento, 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
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.
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.
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].
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 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.
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.
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.
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.
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.
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.
“...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.
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.
• 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.
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.
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.
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.
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.
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.
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.
6.7 CONTEXTO
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.
• 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.
• 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
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
package teste;
import javax.ejb.Stateless;
@Stateless
public class OlaMundoBean implements OlaMundoRemote, OlaMundoLocal {
public String digaOla() {
return "Ola, Mundo";
}
}
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
package teste;
import javax.ejb.Remote;
@Remote
public interface OlaMundoRemote {
java.lang.String digaOla();
}
package teste;
import javax.ejb.Remote;
@Local
public interface OlaMundoLocal {
java.lang.String digaOla();
}
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 java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import teste.OlaMundoRemote;
OlaMundoRemote olaMundoRemote =
(OlaMundoRemote)
ctx.lookup("teste.OlaMundoRemote");
System.out.println(olaMundoRemote.digaOla());
} catch (NamingException ex) {
System.out.println("EJB OlaMundo não encontrado");
}
}
}
válido do servidor de nomes. Este servidor de nomes deve estar ativo e respondendo num porta
conhecida.
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");
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());
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
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.
• 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.
• 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.
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 .
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
Os dados escritos em letras maiúsculas devem ser substituídos pelo seguinte conteúdo:
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%
8.1 PROJETO
Efetuar login
Usuário
1: usuário, senha
2: autenticar( )
6 : login
<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>
<context-root>/maxi</context-root>
• 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
Figura 37: Escolha do datasource e das tabelas para criação das entidades
• 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.
@GeneratedValue(strategy=GenerationType.IDENTITY)
8.3.2 Entidade
...
@Entity
@Table(name = "PROJETO")
public class Projeto implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "CODPROJETO", nullable = false)
private Integer codprojeto;
@Lob
@Column(name = "DESCRICAO", nullable = false)
private String descricao;
68
public Projeto() {
}
@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
@GeneratedValue(strategy=GenerationType.IDENTITY)
@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
...
@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;
@Table
@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
@JoinColumn é responsável por identificar a coluna da tabela a ser utilizada para realizar a pesquisa,
@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
• Na tela mostrada (ver Figura 43), selecione a entidade Projeto e clique sobre Add;
• Clique em Next ;
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.
...
@Stateless
public class ProjetoFacade implements ProjetoFacadeRemote {
@PersistenceContext
private EntityManager em;
73
public ProjetoFacade() {
}
persist
Persiste (grava) uma nova instância da entidade no PersistenceContext .
merge
remove
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
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);
}
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 ;
• utils.Criptografia;
• utils.Mensagem.
O acesso aos EJB numa aplicação desktop é bastante simples, como visto
anteriormente na seção 7.3.
@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
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
8.5.2 Inclusão
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
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.
8.5.5 Exclusão
projetoFR.destroy(codigo);
É 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.
O código fonte do cliente está disponível no Apêndice D, e sua operação foi discutida na
seção anterior.
@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.
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.
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).
A cláusula action indica que o método autenticar do bean gerenciado Login será
acionado (Login.autenticar ).
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");
}
e não
@EJB(beanName="UsuarioFacade", beanInterface=UsuarioFacadeRemote.class)
81
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));
FacesContext facesContext=FacesContext.getCurrentInstance();
facesContext.getExternalContext()
.getSessionMap().put("_usuario", getUsuario());
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 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.
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.
• Selecione um projeto;
• Acesse o menu de contexto, selecionando a opções Generate Javadoc for Project
(conforme Figura 49);
• 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;
9 CONCLUSÃO
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.
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.
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.
[FACADE] SUN MICROSYSTEMS. Core J2EE Patterns - Session Facade. Disponível em:
<http://docs.sun.com/source/819-0079/dgjndi.html>. Acesso em: 31 outubro 2006.
[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.
[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 em:
<http://www.java.com/pt_BR/about>. Acesso em: 27 outubro 2006.
[JAVA 02] SUN MICROSYSTEMS. The Java History Timeline. Disponível em:
<http://www.java.com/en/javahistory/timeline.jsp>. Acesso em: 10 fevereiro 2006.
[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 ME] SUN MICROSYSTEMS. Java ME - Micro App Development Made Easy. Disponível em:
<http://java.sun.com/javame>. Acesso em: 19 maio 2006.
2 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.
[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.
[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.
[SRIGANESH 2006] SRIGANESH, Rima Patel; BROSE, Gerald; SILVERMAN, Micah. Mastering
Enterprise JavaBeans 3.0. Indianapolis, EUA: Wiley Publishing, Inc. 2006. 688 p.
APÊNDICE A
--
-- 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 (codProjeto, codUsuario),
constraint prjusu_codUsuario_IDX unique (codUsuario, codProjeto, lider),
constraint prjusu_prj_FK foreign key (codProjeto) references
projeto (codProjeto),
constraint prjusu_usu_FK foreign key (codUsuario) references
usuario (codUsuario)
);
92
APÊNDICE B
MÓDULO EJB
93
Projeto.java
package entidades.projeto;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
/**
* Classe entidade: Projeto
*
* @author Alessander Fecchio
*/
@Entity
@Table(name = "PROJETO")
public class Projeto implements Serializable {
/**
* 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 java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
/**
* Classe facade para manipulação de Projeto.
*
* @author Alessander Fecchio
*/
@Stateless
public class ProjetoFacade implements ProjetoFacadeRemote {
@PersistenceContext
private EntityManager em;
/**
* 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 {
List findAll();
}
97
USUARIO.JAVA
package entidades.usuario;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import 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 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 java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import 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;
/**
* 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);
List findAll();
PROJETOUSUARIO.JAVA
package entidades.projetousuario;
import entidades.projeto.Projeto;
import entidades.usuario.Usuario;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import 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 {
/**
* 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 {
/**
* 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);
List findAll();
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 {
/**
* 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 {
/**
* 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 com.sun.crypto.provider.SunJCE;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
/**
* Classe para codificação e decodificação de Strings.
* Utilizada para criptografia das senhas.
*
* @author Alessander Fecchio
*/
public class Criptografia {
/**
* 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
};
/**
* 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);
/**
* 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
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;
/**
* 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
MENSAGENS/LOGIN_ERRO.JSP
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
WEB.XML
<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
<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 {
/**
* Instância da classe Criptografia, utilizada para
* codificar e decodificar informações.
*/
private Criptografia cripto;
/**
* 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();
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!");
}
/**
* 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;
}