SlideShare uma empresa Scribd logo
1 de 76
Baixar para ler offline
1
Apostila JavaEE 5 Componentes Distribuídos
EJB 3 e JBoss
Autor:
Gilberto Augusto T. de A. Holms
gibaholms85@gmail.com
http://gibaholms.wordpress.com/
Última revisão: 03/08/2009
2
Sumário
1. Ferramentas Utilizadas .........................................................................................4
1.1. Java JDK.......................................................................................................4
1.2. Eclipse IDE....................................................................................................4
1.3. JBoss Application Server...............................................................................5
1.4. MySQL ..........................................................................................................7
2. Computação Distribuída........................................................................................7
2.1. Por que utilizar sistemas distribuídos ? .........................................................7
2.2. O que são sistemas distribuídos ?.................................................................8
2.3. Rede IP e Sockets.........................................................................................8
2.4. CORBA .......................................................................................................10
2.4.1. Arquitetura CORBA .............................................................................10
2.5. RMI .............................................................................................................14
2.6. Modelo de Programação Distribuída ...........................................................15
2.7. Visão Geral .................................................................................................16
3. Serviço de Nomes JNDI......................................................................................16
3.1. O que é JNDI ?............................................................................................16
3.2. Serviços de Nomes .....................................................................................16
3.3. Serviços de Diretório ...................................................................................17
3.4. Principais conceitos de JNDI.......................................................................18
4. Introdução à Plataforma JEE ..............................................................................20
4.1. O que é J2EE ou JEE ?...............................................................................20
4.2. Modelo de Programação JEE......................................................................20
4.3. O Servidor de Aplicação..............................................................................21
4.4. O Container EJB .........................................................................................22
4.5. Definição de Enterprise JavaBeans.............................................................23
5. Introdução ao JBoss Application Server..............................................................23
5.1. Instalação....................................................................................................24
5.2. Estrutura de Diretórios JBoss 5.x ................................................................25
5.3. Server Configurations..................................................................................25
5.3.1. Estrutura de Diretórios do Server Configuration...................................26
5.4. Configurando um Servidor JBoss no Eclipse...............................................26
6. Enterprise JavaBeans 3.0 ...................................................................................28
6.1. Session Beans ............................................................................................29
6.1.1. Identificando os Beans ........................................................................29
6.1.2. Interfaces de Negócio..........................................................................29
6.1.3. Session Beans – Stateless ..................................................................30
6.1.4. Session Beans – Statefull....................................................................31
6.1.5. Ciclo de Vida dos Session beans.........................................................32
6.2. Distribuindo EJBs........................................................................................36
6.3. EJB Timer Service.......................................................................................37
7. Java Persistence API (JPA) ................................................................................39
7.1. Entity Manager ............................................................................................40
7.2. Ciclo de Vida ...............................................................................................41
7.3. Contexto de Persistência.............................................................................43
7.4. Configurando uma Aplicação JPA ...............................................................45
7.5. Mapeando Relacionamentos.......................................................................46
7.5.1. Um-Para-Um Unidirecional..................................................................46
7.5.2. Um-Para-Um Bidirecional ....................................................................46
7.5.3. Um-para-Muitos Unidirecional..............................................................46
7.5.4. Muitos-Para-Um Unidirecional .............................................................47
7.5.5. Um-Para-Muitos / Muitos-Para-Um Bidirecional...................................47
7.5.6. Muitos-Para-Muitos Unidirecional ........................................................47
7.5.7. Muitos-Para-Muitos Bidirecional ..........................................................47
3
7.6. Cascade Type .............................................................................................47
7.7. Lazy Loading...............................................................................................48
7.8. CRUD com JPA...........................................................................................49
7.9. Data Sources no JBoss...............................................................................49
8. Principais Design Patterns JEE...........................................................................51
8.1. Singleton .....................................................................................................51
8.2. Service Locator ...........................................................................................52
8.3. Business Delegate ......................................................................................53
8.4. Session Facade...........................................................................................54
8.5. Data Transfer Object (DTO) ........................................................................56
9. JMS e Message Driven Beans ............................................................................56
9.1. O que é Mensageria ?.................................................................................56
9.2. MOM – Message Oriented Middleware........................................................57
9.3. JMS.............................................................................................................58
9.4. Modelos de Mensagens ..............................................................................59
9.4.1. Topic (Tópico)......................................................................................59
9.4.2. Queue (Fila).........................................................................................59
9.5. Implementando Topics e Queues no JBoss ................................................59
9.6. Entendendo a JMS API ...............................................................................61
9.7. Publicando e Consumindo Mensagens JMS ...............................................62
9.7.1. Mensagens Tópico – Topic..................................................................62
9.7.2. Mensagens Fila – Queue.....................................................................63
9.8. JMS e EJB ..................................................................................................64
9.8.1. EJB – Publicando Mensagens .............................................................64
9.8.2. EJB – Message Driven Beans .............................................................65
10. Controle Transacional na Plataforma JEE...........................................................66
10.1. O que são Transações ? .............................................................................67
10.2. Níveis de Isolamento de Transações...........................................................68
10.3. Transações e EJB 3.0 .................................................................................70
10.3.1. Transações CMT .................................................................................70
10.3.2. Transações e Message Driven Beans .................................................73
10.3.3. Revertendo Transações.......................................................................74
10.3.4. Transações BMT .................................................................................74
11. Referências Bibliográficas...................................................................................75
4
1. Ferramentas Utilizadas
1.1. Java JDK
Para desenvolver aplicações Java Enterprise Edition, não precisamos de nenhum
ferramental especial. É necessário apenas algum JDK (Java Development Kit) e um
Servidor de Aplicação (Application Server) compatível com o JDK.
No momento em que foi criada esta apostila, a versão mais recente é a JDK 6 Update
13, disponível no link:
http://java.sun.com/javase/downloads/index.jsp
Note que a Sun também disponibiliza para download um pacote chamado JDK 6
Update 13 with Java EE. Este pacote é apenas um facilitador para iniciantes, pois já
vem com um servidor de aplicação, o GlassFish Enterprise Server, e também alguns
exemplos de mini-aplicativos JEE e tutoriais. O GlassFish é um Application Server
completo, disponibilizado pela Sun como open-source.
O GlassFish é um ótimo servidor de aplicação, porém não tem muita força no
mercado. Atualmente, dentro do nicho dos servidores de aplicação open-source, o
JBoss destaca-se como o mais robusto e utilizado pela comunidade, portanto, é ele
que utilizaremos neste curso.
1.2. Eclipse IDE
Como ferramenta de desenvolvimento, utilizaremos o Eclipse IDE. Trata-se de um
ambiente de desenvolvimento integrado open-source, o mais conhecido e utilizado
pela comunidade Java.
5
No momento em que foi criada esta apostila, a versão mais recente é o Eclipse
Ganymede SR1 – versão 3.4, disponível no link:
http://www.eclipse.org/home/categories/index.php?category=enterprise
O Eclipse IDE é disponibilizado para download em várias distribuições diferentes. Para
este curso utilizaremos a distribuição Eclipse IDE for Java EE Developers, pois ela já
incorpora diversos plugins direcionados ao desenvolvimento JEE, inclusive o WTP
(Web Tools Platform).
1.3. JBoss Application Server
Como servidor de aplicação e web container, utilizaremos o JBoss Application Server.
Ele é um servidor de código aberto, atualmente mantido pela empresa Hed Hat e
usado em produção em muitas empresas.
No momento em que foi criada esta apostila, a versão mais recente é o JBoss
Application Server 5.0.1.GA, disponível no link:
http://www.jboss.org/jbossas/downloads/
6
Note que dentro de uma mesma versão são disponibilidadas para download diversas
distribuições do JBoss, em diversos formatos, ou com JDK6 incluso. Para o curso nós
utilizaremos a versão “pura”, disponível no formato zip, sem nenhum adicional.
7
1.4. MySQL
Para os exercícios e projetos do curso, utilizaremos a base de dados MySQL (agora
pertencente à Sun Microsystems). Atualmente, ela é disponibilizada em duas versões:
Enterprise e Community.
No momento em que foi criada esta apostila, a versão mais recente é o MySQL
Community Server 5.1, disponível no link:
Optamos pela versão Community, pois ela é open-source.
2. Computação Distribuída
2.1. Por que utilizar sistemas distribuídos ?
o Dados são distribuídos
o Processamento é distribuído
o Usuários são distribuídos
Dados são distribuídos
Os dados que uma aplicação precisa acessar podem existir em muitos computadores,
por motivos administrativos, de segurança, de infra-estrutura ou até mesmo
geográficos. O responsável pelos dados ou processos pode permitir acesso apenas
remoto, mas não permitir que esses dados sejam armazenados localmente por um
cliente.
8
Processamento é distribuído
Uma aplicação pode executar de forma distribuída para ter vantagem de utilizar
múltiplos processadores, em diferentes máquinas ou servidores, ou até mesmo tirar
proveito de recursos específicos de uma determinada máquina ou sistema
operacional. Com isso, são garantidas escalabilidade e alta disponibilidade do sistema.
Usuários são distribuídos
Uma aplicação pode executar de forma distribuída, pois os usuários da aplicação
podem interagir entre si, compartilhando processos, cada usuário sendo responsável
por executar um pedaço do aplicativo, em diferentes sistemas, para a realização de
um fim comum.
2.2. O que são sistemas distribuídos ?
Segundo a definição de Tanembaum, um sistema distribuído é:
“Uma coleção de computadores independentes que se apresenta ao usuário
como um sistema único e consistente.”
Ou seja, um sistema distribuído é capaz de ter seu processamento compartilhado em
diversas máquinas distintas, interligadas entre uma rede, que se comunicam entre si
através de algum protocolo, independente do sistema operacional em que residem.
Tudo isso transparente ao usuário, que tem a impressão de estar acessando um único
sistema.
Cada pedaço da aplicação pode estar presente em uma máquina, e estes pedaços
podem ser reutilizados e orquestrados de forma a compor uma aplicação.
2.3. Rede IP e Sockets
Historicamente, a primeira abordagem existente para o desenvolvimento de aplicações
distribuídas foi através do uso de sockets, que é a forma mais “nativa” possível de
transferir dados através de uma rede de computadores.
Arquitetura geral de uma rede de computadores baseada em IP:
Vamos examinar rapidamente os componentes dessa arquitetura:
9
o Camada Física
É a camada que efetivamente transfere os bits, onde podemos pensar
em placas de rede, roteadores e elementos transmissores.
o Enlace de Dados
É a camada que tem diversas características de gerência e controle
sobre os dados trafegados, que realiza multiplexações, detecção,
notificação e recuperação de erros.
o Protocolo IP
A sigla IP significa “Internet Protocol”, por ser o protocolo no qual é
baseada a rede mundial de computadores (Internet). Nada mais é que
um protocolo, único e padronizado mundialmente, que permite que
dados sejam transferidos pela rede através de pacotes de dados com
uma estrutura bem definida, com informações de roteamento,
endereçamento, headers e outras informações.
o TCP / UDP
Aqui começamos a nos atentar. Existem duas maneiras (protocolos) de
se transferir dados em uma rede IP, e cada uma tem suas
características e utilização apropriada:
Protocolo UDP
• Não orientado à conexão
• Não confiável
• Não garante entrega ao destinatário
• Utilizado para comunicação em tempo real (VoIP, Vídeo, etc)
Protocolo TCP
• Orientado à conexão
• Confiável
• Garante entrega ao destinatário
o Camada de Aplicação
É onde residem os aplicativos. Nesta camada temos os protocolos de
software. Diversos aplicativos conhecidos utilizam serviços de rede.
Entre eles, podemos citar: browsers web (protocolo HTTP),
gerenciadores de email (protocolos SMTP e POP3).
Dando um zoom na nossa Camada de Aplicação, visualizamos um componente de
software vital para a comunicação em rede:
Os SOCKETS !
Sockets são um conjunto de funções (API) do sistema operacional que permitem que
os softwares utilizem um canal de comunicação sobre IP. E, logicamente, cada
linguagem de programação fornece o seu conjunto de APIs para manipulação dos
sockets do sistema operacional.
10
2.4. CORBA
Como pudemos observar nos exercícios apresentados em sala de aula, disponibilizar
objetos distribuídos nativamente através de sockets não é uma tarefa simples. Em
muitas linhas de código, onde não há transparência de localização, o cliente precisa
conhecer o servidor. Além de que implementar infra de segurança, alta disponibilidade
e pool de recursos demandaria muito esforço de desenvolvimento. Vimos também que
é muito difícil obter interoperabilidade, pois não há um padrão definido de protocolo de
comunicação, cada desenvolvedor de sistema poderia implementar de sua maneira.
Também não há transparência de linguagem de programação, ou seja, um objeto
distribuído Java seria acessado apenas por clientes Java, pois são utilizados os
recursos de serialização de objetos da própria linguagem para trafegá-los pela rede.
CORBA, ou “Common Object Request Broker Architecture”, é uma especificação de
arquitetura para criação de sistemas distribuídos orientados a objeto padronizados,
independente de plataforma ou linguagem de programação.
O Object Management Group (OMG) é responsável pela definição da arquitetura
CORBA. A OMG é um órgão formado por mais de 700 empresas fornecedoras de
tecnologia, responsável por definir e manter alguns dos principais padrões de
mercado, como por exemplo o UML.
A arquitetura CORBA define o paradigma de “Objetos Distribuídos”, que permite que
um objeto (C++, Delphi, Java, etc) em uma máquina possa interagir com um objeto de
outra máquina.
2.4.1. Arquitetura CORBA
IDL
É a definição da interface ou contrato das operações que o objeto distribuído expõe
aos clientes. Ela é criada em uma linguagem específica definida e mantida pela OMG.
Exemplo de IDL:
module LocadoraObjects {
struct InformacoesFilme {
string nome;
string genero;
double preco;
};
11
exception LocadoraException{};
interface Filme {
InformacoesFilme getInformacoesFilme() raises(LocadoraException);
void setInformacoesFilme(in InformacoesFilme info);
};
};
A partir da IDL, diversos fabricantes desenvolvem compiladores para gerar o código
em uma linguagem específica, como Java ou C++.
A plataforma Java fornece no JDK um compilador IDL para a geração de Skeletons e
Stubs CORBA. É o aplicativo idlj.exe, localizado na pasta “bin” do JDK.
Exemplo:
idlj –server –client teste.idl
ORB
Camada provedora de serviços (API) para implementação da arquitetura CORBA. Ela
é a intermediadora entre o objeto cliente e o objeto distribuído. Quando um objeto
cliente faz uma requisição a um objeto distribuído, ela localiza o objeto na rede, envia
a requisição ao objeto distribuído (através do protocolo IIOP), aguarda a resposta e a
repassa ao objeto chamador.
Um dos serviços importantes providos pela camada ORB é o serviço de nomes
(Naming Service), que permite transparência de localização dos objetos distribuídos.
Skeletons
São os objetos gerados automaticamente pelo compilador IDL para servirem
requisições no lado do servidor. Eles são responsáveis pelo marshalling e
unmarshalling dos objetos para que o ORB possa enviá-los pela rede. Desta forma, o
desenvolvedor preocupa-se apenas em implementar suas operações de negócio, sem
se preocupar com serviços de infra estrutura.
Stubs
São os objetos gerados automaticamente pelo compilador IDL para enviarem
requisições por parte do cliente. Eles são responsáveis pelo marshalling e
unmarshalling dos objetos para que o ORB possa enviá-los pela rede. Da mesma
forma, o desenvolvedor não precisa se preocupar com serviços de infra estrutura para
acessar os objetos distribuídos.
IIOP
12
O “Internet Inter Orb Protocol” é o protocolo de comunicação da arquitetura CORBA. É
um protocolo de rede (TCP/IP) que, através de uma estrutura de bytes pré-definida,
transporta as requisições e respostas através da rede.
Arquivo IDL
Cliente
Código Cliente
Stubs
Servidor
Skeletons
Implementação do Objeto
Compilador
idl2Java
Rede TCP/IP - Protocolo IIOP
ORB
ORB
POA
O “Portable Object Adapter” (POA) é um artefato evolutivo na arquitetura CORBA. Ele
fica entre a implementação do ORB e o objeto distribuído. Desta forma, com o POA
pode-se fazer com que os ORBs de diversos fabricantes rodem objetos distribuídos da
mesma forma, sem nenhuma mudança no código dos objetos. Além disso, o POA
fornece alguns serviços de controle de ciclo-de-vida, segurança, multithreading e
transiência/persistência.
COS Naming Service
O CORBA COS(Common Object Services) Naming Service é uma especificação. Sua
implementação deve fornecer um sistema de armazenamento de nomes em formado
de “árvore”, pronto para armazenar referências de objetos CORBA. Sua estrutura é
muito semelhante a um LDAP:
• Binding
13
É uma associação nome-objeto, onde uma referência a um objeto é gravada
associada a um nome, que funciona como uma chave em uma estrutura de Map.
Um binding é criado sempre em relação a um Naming Context; não existe um nome de
binding absoluto.
• Naming Context
Um conjunto único de bindings (nomes), onde não pode haver bindings com nomes
repetidos. O Naming Context é um objeto, portanto, também pode ser “bindado” ao
Naming Service, criando assim uma hierarquia de naming contexts (Naming Graph).
• Naming Graph
É quando criamos Naming Context dentro de outro Naming Context, criando assim
uma árvore de contextos.
No diretório “bin” do JDK são fornecidas duas implementações de COS Naming
Service: ORBD e TNAMESERV.
• ORDB (Object Request Broker Daemon)
É uma implementação de COS Naming Service disponibilizada de duas maneiras:
“Transient Naming Service” e “Persistent Naming Service”.
o Persistent Naming Service – indica que os registros são gravados de
forma persistente (em disco ou base de dados), permitindo que os
bindings sobrevivam a restarts e quedas do sistema.
Orb.resolve_initial_references("NameService")
o Transient Naming Service – indica que os registros são gravado em
memória, ou seja, são perdidos quando o servidor finaliza.
//o nome TNameService é proprietario do ORBD,
//o padrão do CORBA é sem o T
Orb.resolve_initial_references("TNameService")
Ferramenta SERVERTOOL – também disponível no diretório “bin” do JDK. É
um aplicativo utilitário para monitorar o ORBD, permitindo visualizar os servidores
ativos, localizar ORBs, entre outras funções.
• TNAMESERV (Transient Naming Service)
Como o próprio nome indica, é uma implementação de COS Naming Service, porém
disponível apenas na forma transiente.
Orb.resolve_initial_references("NameService")
O COS Naming Service é disponibilizado através de um objeto distribuído no ORB,
que também foi gerado a partir de um IDL, portanto é preciso obter sua referência e
fazer o narrow a partir da classe helper.
Object ctxRef = orb.resolve_initial_references("NameService");
NamingContextExt ctx = NamingContextExtHelper.narrow(ctxRef);
Nomeando Referências à Objetos:
• Interoperable Object References (IOR)
É uma referência a um objeto em forma de string, em um formato conhecido pelo
ORB.
14
Orb.object_to_string(objRef)
• Interoperable Naming Service (INS)
É uma referência a um objeto em forma “Human-Readable”, em forma de strings,
URLs, “corbaloc” ou “corbaname”.
corbaloc:iiop:1.2@localhost:1050/Locadora
2.5. RMI
O RMI (“Remote Method Invocation”) é uma API criada como uma iniciativa para que
desenvolvedores pudessem escrever sistemas distribuídos com a mesma semântica
de sistemas comuns, com o intuito de agilizar e facilitar o desenvolvimento.
A princípio, ela foi criada para suprir as necessidades do desenvolvimento de sistemas
distribuídos baseados em Java, ou seja, server Java e client Java, através do protoclo
JRMP. Porém, logo depois foi evoluída para suportar também o protocolo IIOP,
visando a interoperabilidade de sistemas.
Existem dois tipos de implementação RMI:
- Baseada em JRMP (“Java Remote Method Protocol”)
- Baseada em IIOP (“Internet Inter Orb Protocol”)
JRMP
É um protocolo nativo e específico para linguagem Java, ou seja, objetos distribuídos
via RMI-JRMP podem ser consumidos apenas por clientes Java (JVM to JVM).
• RMIREGISTRY (RMI Registry)
Disponível na pasta “bin” do JDK, é o Naming Service do RMI, que funciona
analogamente ao COS Naming Service do CORBA, porém específico para bindar e
localizar objetos RMI.
• RMIC (RMI Compiler)
É um aplicativo localizado na pasta “bin” do JDK utilizado para gerar os Skeletons e
Stubs de objetos remotos RMI. A geração explícita de Skeletons e Stubs é necessária
apenas nas versões 1.4 e anteriores do JDK, pois nas versões mais recentes esta
geração é feita e disponibilizada à JVM automaticamente pelo RMIRegistry.
Exemplo:
rmic br.curso.LocadoraImpl
IIOP
Como já estudamos no tópico sobre CORBA, o IIOP é o protocolo de comunicação da
arquitetura CORBA. Objetos distribuídos sobre RMI-IIOP possuem a vantagem de
executar sobre um ORB, assim sendo independentes de linguagem de programação.
Com o intuito de trazer para o Java a facilidade de programação do RMI fundida à
interoperabilidade do CORBA, a Sun, em conjunto com a IBM, criaram o RMI sobre
IIOP.
Além de prover interoperabilidade com sistemas CORBA, o protocolo RMI-IIOP foi
idealizado para garantir também interoperabilidade com o RMI-JRMP, para que os
sistemas mais antigos construídos nesse protocolo pudessem interagir com o novo
protocolo sem necessidade de mudança de código.
15
Para atender esses requisitos, compilador RMIC foi modificado, adicionando a opção
de geração de Skeletons e Stubs para protocolo IIOP.
Exemplo:
rmic –iiop br.curso.LocadoraImpl
Conceito de “codebase”
Para qualquer chamada remota, vimos que é necessário ter no classpath do cliente o
Stub, tal Stub que referencia a classe de implementação do objeto distribuído. Porém,
nem sempre é desejável ter este Stub localmente, pois a qualquer mudança na
implementação do objeto remoto, teríamos que recompilar todos os clientes com o
novo Stub que seria gerado.
Para evitar esse problema, ao rodar o nosso servidor java podemos setar um atributo
de JVM chamado “codebase”, indicando um local para a JVM do cliente localizar os
Stubs automaticamente em tempo de execução. Quando bindamos um objeto remoto
no RMI Registry, este local é gravado e enviado aos aplicativos que fizerem lookup do
objeto.
Exemplos:
java -Djava.rmi.server.codebase=http://server/public/stubs.jar
java -Djava.rmi.server.codebase=http://server/stubs/
A ordem em que o cliente procura as classes Stub é primeiro em seu classpath e, se
não achar, procura no codebase do Servidor.
Obs.: este conceito é válido apenas para RMI-JRMP. Não faz sentido um cliente IIOP
fazer download automático de Stubs, pois um cliente IIOP pode ser escrito em
qualquer linguagem de programação, e cada linguagem terá o seu Stub específico.
2.6. Modelo de Programação Distribuída
Quando trabalhamos com Java puro localmente sabemos que, ao invocarmos um
método local, tipos primitivos são passados como cópia e, para os objetos, é passada
uma cópia da referência.
Quando trabalhamos com objetos distribuídos, não há como trafegar referências de
objetos na rede, mesmo porquê o sistema do outro lado pode não necessariamente
ser Java.
16
Na chamada de métodos remotos sempre trabalhamos com cópias serializadas
(sequência de bytes) dos objetos, tanto os passados como argumento quanto os
retornados de métodos. Portanto, todos os objetos que irão trafegar na rede
(parâmetros e retornos de métodos) devem ser declarados como serializáveis.
Na linguagem Java um objeto é declarado como serializável quando ele implementa a
interface java.io.Serializable:
public class Filme implements Serializable {
}
2.7. Visão Geral
CLIENT  SERVER CORBA RMI – JRMP RMI – IIOP
CORBA X X
RMI – JRMP X X
RMI – IIOP X X X
3. Serviço de Nomes JNDI
3.1. O que é JNDI ?
A sigla JNDI significa Java Naming and Directory Interface. O JNDI é uma API da
plataforma Java SE que permite ao desenvolvedor manipular serviços de nomes e
diretórios.
3.2. Serviços de Nomes
A principal função de um serviço de nomes (ou Naming Service) é permitir a
associação de um nome a recursos computacionais, como:
o Endereços de memória
o Objetos
o Referências a objetos
o Arquivos
o Códigos em geral
Exemplos de serviços de nomes:
o File System – liga um caminho a um bloco de memória física
o Sistema DNS – liga um domínio a um endereço IP
o Sistema LDAP – liga um nome a um usuário ou grupo de usuários
o CORBA COS Naming Service – liga um nome lógico a uma referência
de objeto remoto CORBA
17
o RMI Registry – liga um nome lógico a uma referência de objeto remoto
RMI-JRMP
3.3. Serviços de Diretório
A principal função de um serviço de diretório (ou Directory Service) é permitir o
agrupamento de recursos computacionais de acordo com contextos ou hierarquias. O
serviço de diretório complementa o serviço de nomes, pois este agrupamento pode
ser feito logicamente a partir dos nomes. O serviço de diretório permite também
trabalhar com atributos, para guardar informações importantes sobre os objetos.
Exemplos de serviços de diretórios:
o File System – uma pasta é um agrupamento de arquivos, e arquivos
têm atributos
o Sistema DNS – um domínio é um agrupamento de sub-domínios ou
sites
o Sistema LDAP – um grupo é um agrupamento de usuários, e ambos
podem ter atributos (nome, endereço, senha)
o CORBA COS Naming Service e RMI Registry – um contexto de nomes
é um agrupamento de objetos remotos relacionados
De maneira macro percebemos que todos os exemplos de serviços de nomes e
diretório listados possuem muito em comum.
• Geralmente um serviço de nomes caminha acompanhado de um serviço de
diretórios (mas não é obrigatório).
• Como dito na própria definição do JNDI, todos eles associam nomes a recursos
computacionais.
• Eles podem guardar atributos para descrever estes recursos (mas não é
obrigatório).
• Todos eles também se organizam em forma de árvore, hierarquizada, ou seja,
um nome pode ser um contexto para agrupar outros nomes.
18
Devido a este comportamento comum, a Sun teve a brilhante idéia de desenvolver
uma API genérica, desacoplada, capaz de gerenciar qualquer serviço de nomes que
seguisse esta mesma lógica. Lógico que cada serviço de nomes tem seu protocolo
específico e sua particularidade de implementação, porém a JNDI fornece uma
interface comum para essas implementações.
O JNDI está para os “serviços de nomes e diretórios” assim como o JDBC está
para as “bases de dados”.
Com o JNDI, no que tange aos serviços de nomes e diretórios, temos os mesmos
benefícios que o JDBC fornece no que tange as bases de dados, onde a principal
delas é a independência de implementação.
3.4. Principais conceitos de JNDI
Service Provider
É a implementação (provedor do serviço) que o JNDI irá utilizar. Cada serviço de
nomes e diretórios específico possui a sua classe de implementação, conhecida como
“Service Provider”, e sua “factory”, responsável por criar a instância e atribuí-la à
interface do JNDI. Ela deve estar no classpath da aplicação e sua factory deve ser
definida no properties através da seguinte constante:
Context.INITIAL_CONTEXT_FACTORY
Initial Context
É o contexto inicial do serviço de nomes e diretórios. É a “raíz” do sistema, o “root”, o
“ponto de partida” para a navegação entre os nós da árvore de nomes.
A nível de código, ele é representado como uma classe em que seu construtor recebe
um java.util.Properties como parâmetro. É através dele que configuramos a
implementação que desejamos utilizar.
Exemplo:
Properties prop = new Properties();
prop.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
prop.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
InitialContext ctx = new InitialContext(prop);
Exemplos de implementações (service providers):
19
LDAP:
Properties prop = new Properties();
prop.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
prop.put(Context.PROVIDER_URL, "ldap://localhost:389");
*incluso no JDK
COS Naming Service:
Properties prop = new Properties();
prop.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory");
prop.put(Context.PROVIDER_URL, "iiop://localhost:1050");
*incluso no JDK
RMI Registry:
Properties prop = new Properties();
prop.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.rmi.registry.RegistryContextFactory");
prop.put(Context.PROVIDER_URL, "rmi://localhost:1099");
*incluso no JDK
DNS:
Properties prop = new Properties();
prop.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
prop.put(Context.PROVIDER_URL, "dns://server1.sun.com/java.sun.com");
prop.put(Context.AUTHORITATIVE, "true");
*incluso no JDK
File System:
Properties prop = new Properties();
Prop.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.fscontext.RefFSContextFactory");
*não incluso no JDK
Download de outros Service Providers (dns, novell, registro do windows, etc):
http://java.sun.com/products/jndi/serviceproviders.html
Obs.: para SPIs que requerem usuário e senha, utilizamos os seguintes parâmetros:
prop.put(Context.SECURITY_PRINCIPAL, "usuario");
prop.put(Context.SECURITY_CREDENTIALS, "xxxxxxx");
Context
É qualquer contexto do serviço de nomes e diretórios. Como ilustrado no capítulo
sobre COS Naming Service, um contexto pode conter sub-contextos. A característica
principal de um contexto é que ele não pode possuir nomes repetidos para
associações de recursos.
E isso faz todo o sentido, pois um recurso deve ser identificado de forma única.
Logicamente uma mesma pasta não pode conter dois arquivos com o mesmo nome,
ou um domínio não pode conter dois sub-domínios diretos com o mesmo nome.
Toda e qualquer operação de manuseio de registros de nomes é feita de forma relativa
a um contexto.
Bind
Operação de gravar uma associação nome-objeto em um contexto. Se o nome já
existir, é lançada uma javax.naming.NamingException.
Rebind
Operação de regravar uma associação nome-objeto em um contexto. A diferença para
o Bind é que, se o nome já existir, ele é sobrescrito.
Unbind
Operação de remover uma associação nome-objeto de um contexto.
20
Lookup
Operação de localizar uma associação nome-objeto em um contexto. Lembrando que
será feito sempre relativo a um contexto, pois em JNDI não existem “nomes
absolutos”.
ListBindins
Operação de listar todas as associações nome-objeto de um contexto.
4. Introdução à Plataforma JEE
4.1. O que é J2EE ou JEE ?
O termo JEE significa Java Enterprise Edition. Como o próprio nome já diz através do
termo “Enterprise”, o JEE é uma plataforma baseada em Java, desenvolvida para o
desenvolvimento de sistemas corporativos.
Na literatura atual podemos encontrar os termos J2EE ou JEE. Os duas
nomenclaturas referem-se à plataforma Java Enterprise Edition, onde a letra “2” fazia
menção à versão 2 do Java, referente ao JDK 1.4. Nas versões mais recentes da
plataforma, a letra “2” foi removida, falando-se apenas em JEE ou Java Enterprise
Edition.
O JEE não é um software nem nenhuma ferramenta especial. O JEE é um conjunto de
especificações desenvolvidas para atender as necessidades vitais de sistemas
corporativos, visando a componentização e a facilidade na implementação desses
sistemas.
A partir desse conjunto de especificações, cada fabricante implementa as
funcionalidades especificadas da forma desejada, como for mais viável e menos
custoso.
Isto torna a tecnologia JEE independente de fornecedor e de plataforma, pois a
especificação garante que um sistema desenvolvido seguindo a especificação terá o
mesmo comportamento em qualquer plataforma de qualquer fabricante (na prática não
é “tão maravilhoso assim”, mas através de algumas técnicas e boas práticas
conseguimos minimizar o impacto da dependência do fabricante).
Todas estas especificações são abertas, mantidas pela Sun e pelo Java Community
Process (JCP). O JCP é uma comunidade composta pelos principais fabricantes de
tecnologia em plataforma Java, que definem as especificações (JSRs) para as
principais tecnologias java.
Dentre este plantel de fabricantes encontram-se IBM, Oracle, HP, Lucent, Hed Hat e
todos os demais “barões” da tecnologia atual.
Todas as JSRs e suas revisões são disponibilizadas para download no site do Java
Community Process. As JSRs são documentos fabulosos para se ter como
documentação das principais APIs do JEE:
http://www.jcp.org/
4.2. Modelo de Programação JEE
Toda aplicação corporativa de missão crítica possui requisitos em comum, como
comunicação remota, componentes no lado do servidor com tecnologias de objetos
21
distribuídos, sistemas de mensageria assíncrona, segurança centralizada,
escalabilidade, pool de recursos, controle transacional, entre diversos outros
requisitos.
Desenvolver um sistema distribuído não é simples:
• O que acontecerá com a performance quando aumentar o volume de acessos
?
• Quais são os custos para se aplicar a capacidade de processamento ?
• Qual a integridade dos dados e das transações se alguma chamada falhar ?
• Quem garante a segurança e o controle de acesso ?
• E se o sistema remoto sair do ar ?
O modelo de programação JEE é baseado no reuso de componentes focando a
minimização do tempo de desenvolvimento de um sistema corporativo de larga escala.
Com o JEE o desenvolvedor não precisa se preocupar com particularidades de
infra-estrutura, como segurança, comunicação TCP-IP, pool de recursos ou
transações. O “Container JEE” fornece essas funcionalidades de forma segura e
confiável, permitindo assim que o desenvolvedor se concentre apenas na lógica
de negócio.
4.3. O Servidor de Aplicação
O Servidor de Aplicação (Application Server) é o componente macro da especificação
JEE, encarregado por implementar todos os serviços básicos de infra-estrutura,
seguindo a especificação JEE.
Ele é subdividido conceitualmente em duas partes, ou “containers”:
• Container Web
22
Responsável por disponibilizar e gerenciar os componentes de infra-estrutura
referentes a camada web (“Web Tier”), como as especificações Servlet e JSP.
• Container EJB
Responsável por disponibilizar e gerenciar os componentes de infra-estrutura
da camada de negócio (“Business Tier”), como as especificações EJB e JPA.
No mercado, atualmente, existem servidores de aplicações que disponibilizam
somente o Container Web (ex.: Tomcat e Jetty) e existem, também, os chamados
servidores de aplicação completos, que disponibilizam tanto o Container Web quanto
o Container EJB (ex.: JBoss, Sun GlassFish, IBM WebSphere, Oracle/BEA WebLogic).
4.4. O Container EJB
Um Container JEE precisa fornecer os seis serviços básicos:
o Concorrência
o Transação
o Persistência
o Distribuição de Objetos
o Atribuição de Nomes (JNDI)
o Segurança
Serviços secundários:
o Mensageria Assíncrona
o Temporização
Para um Container EJB ser completamente compatível com a especificação EJB 3.0,
ele precisa implementar as seguintes APIs:
o EJB 3.0
o JTA 1.1
o JPA 2.0
o JMS 1.1
o JavaMail 1.4 (apenas envio de email)
o JAF 1.1
o JAXP 1.2
o JAXR 1.0
o JAX-RPC 1.1
o JAX-WS 2.0
o JAXB 2.0
o SAAJ 1.3
o JAAS
o Connector 1.5
23
o Web Services 1.2
o Web Services Metadata 2.0
o Common Annotations 1.0
o StAX 1.0
APIs fornecidas pelo próprio runtime JSE sob o container:
o JDBC
o RMI-IIOP
o JNDI
4.5. Definição de Enterprise JavaBeans
Os Enterprise JavaBeans (EJBs) são componentes Java criados seguindo a
especificação JEE, que são gerenciados pelo servidor de aplicação. Os EJBs
representam a lógica de negócio do sistema (“aluguel de filmes”, “agente de viagens”,
“autenticador”, etc).
Com a junção dos EJBs e o Container, nos preocupamos em desenvolver apenas a
lógica do negócio, e o Container cuida do ciclo-de-vida dos beans, gerenciamento de
pool, segurança, controle de transações e todos os demais serviços básicos.
Definição da Sun para a Arquitetura EJB:
“A arquitetura Enterprise JavaBeans é uma arquitetura de componentes para o
desenvolvimento e a implantação de aplicativos de negócio distribuídos
baseados em componentes. Aplicativos escritos utilizando a arquitetura
Enterprise JavaBeans são escalonáveis, transacionais e seguros com multi-
usuários. Esses aplicativos podem ser escritos uma vez e então implantados em
qualquer plataforma de servidor que suporta a especificação Enterprise
JavaBeans.”
Atenção: “Enterprise JavaBeans” não são simples “JavaBeans”. O termo “JavaBeans”
propriamente dito refere-se a classes Java que seguem o padrão de nomenclatura
JavaBeans (classe encapsulada com “getters” e “setters” padronizados, ex. getAtributo
e setAtributo). Quando falamos “Enterprise JavaBeans”, esses sim são os EJBs, os
objetos de negócio distribuídos gerenciados pelo container.
Objetos Remotos vs. Objetos Distribuídos
Os Enterprise JavaBeans não representam objetos remotos (não implementam
java.rmi.Remote), e sim objetos distribuídos.
Eles podem ser “distribuídos” de diversas formas (localmente, remotamente, via
CORBA, via WebServices), porém quem faz o trabalho de distribuir os objetos é o
container. O container que implementa um Skeleton RMI ou uma interface de
WebService intercepta a requisição e a “delega” ao EJB.
5. Introdução ao JBoss Application Server
O JBoss Application Server é um servidor de aplicação JEE completo, atualmente
mantido pela empresa Red Hat. Ele é disponibilizado em duas versões: Community e
Enterprise.
A versão Community é totalmente open-source, destinada primeiramente a
desenvolvedores, mas pode ser utilizada para qualquer fim:
24
http://www.jboss.org/
Já a versão Enterprise é disponibilizada para fins comerciais, mantendo a metodologia
da Red Hat de não cobrar pelo produto, mas sim pelo suporte. Ela vem nomeada de
Application Platform, geralmente contendo pacotes adicionais como IDE de
Desenvolvimento com plugins proprietários para agilizar o desenvolvimento e outras
ferramentas e frameworks.
http://www.jboss.com/
5.1. Instalação
Após o download do pacote zip contendo o JBoss Application Server, como indicado
no capítulo 1.3 da apostila, podemos começar o procedimento de instalação.
Por ser baseado em java e assim portável, ele não possui instalador específico para
um sistema operacional. O JBoss é o conteúdo do arquivo zip.
Passos para instalação:
o Extrair o conteúdo do arquivo zip para um diretório qualquer. Para evitar
inconvenientes e incompatibilidades sobre formatos de nomes de diferentes
sistemas operacionais, devemos evitar um caminho muito comprido e
devemos evitar também o caractere “espaço” no caminho da pasta do
JBoss.
o Agora devemos apenas setar a variável de ambiente JBOSS_HOME
indicando o caminho onde o JBoss foi instalado, para que os aplicativos
que precisarem poderem localizar seu classpath
“Meu Computador” > “Propriedades”
“Avançado” > “Variáveis de Ambiente”
25
“Variáveis do Sistema” > “Nova”
Digitar a variável “JBOSS_HOME”,
informando o diretório onde foi
descompactado o JBoss
Pronto. Tendo feito isso, o JBoss estará pronto para rodar.
5.2. Estrutura de Diretórios JBoss 5.x
Para conhecermos um pouco melhor o nosso servidor de aplicação, vamos dar uma
analisada geral em sua estrutura de diretórios:
• bin – todos executáveis e scripts necessários para
ligar e desligar o servidor
• client – todos os JARs necessários para comunicar
com o JBoss a partir de aplicações client standalone
de várias naturezas
• docs – documentações do fornecedor
• lib e common – todos os JARs necessários para o
rodar o core do servidor
• server – todas as Server Configurations
5.3. Server Configurations
Cada pasta dentro do diretório server representa um “Server Configuration”, que é
uma instância do servidor.
A distribuição do JBoss fornece cinco templates de configuration: all, default, minimal,
standard e web. Cada template tem suas características e serviços configurados.
26
Atenção
Nunca carregue diretamente os templates, pois eles não foram criados para ser
usados. Eles servem como modelo para criarmos a nossa configuration
personalizada.
Para criar uma configuration, basta replicar o template (criar uma cópia da pasta) que
desejarmos e modificar o nome da pasta.
5.3.1. Estrutura de Diretórios do Server Configuration
Todos os templates possuem uma estrutura semelhante, vamos analisá-la:
• conf – configurações gerais de funcionamento do
servidor, são carregadas apenas uma vez quando o
server inicia (qualquer mudança requer restart do
server)
• deploy – diretório onde se faz o deploy de aplicações
(basta copiar nele o EAR ou o WAR e o deploy é feito
automaticamente)
• deployers – contém os serviços responsáveis por
efetuar o deploy dos arquivos no servidor (existe um
deployer para cada tipo de serviço – web, ejb3, etc)
• lib – qualquer JAR presente nessa pasta será
compartilhado e visível para todas as aplicações
deployadas no servidor
Além desses diretórios padrão, são gerados também em run-time mais quatro pastas:
• data – utilizada para todos os serviços do JBoss que precisam guardar dados
persistentes no disco (ex.: Naming Service) – Hypersonic SQL Database
(HSQLDB)
• log – onde são gerados os arquivos de log do servidor
• tmp – qualquer tipo de dado temporário necessário pelos serviços do JBoss
• work – utilizado pelo Web Container do JBoss (baseado em Tomcat), para
guardar JSPs compiladas e outros arquivos temporários necessários para web
5.4. Configurando um Servidor JBoss no Eclipse
“Window” > “Preferences”
“Server” > “Runtime Environments” > “Add...”
27
Selecione “JBoss v5.0” e clique em “Next” Escolha o JRE desejado e localize a pasta onde
reside o diretório raiz do JBoss
Na aba “Servers”, clique com o botão
direito do mouse e crie um novo server
Selecione o run-time environment criado
anteriormente marcando “JBoss v5.0” e clique em
“Next”
28
Em “Server Configuration”, digite o nome da sua configuração personalizada e finalize
Atenção: nunca utilize os templates (all, default, minimal, etc), crie sempre uma configuração
personalizada e a utilize.
6. Enterprise JavaBeans 3.0
A especificação EJB 3.0 veio a partir do JDK 1.5, com o intuito de facilitar o
desenvolvimento de EJBs substituindo os milhares de XMLs de configuração
necessários na versão EJB 2.1 pelas Annotations (recurso adicionado a partir do JDK
1.5). Além dessa evolução, o modelo de programação ficou mais simplificado
demandando menos código para implementar o mesmo beans, e houve a criação da
JPA (Java Persistence API) para substituir os antigos Entity Beans da velha
especificação (detalhes da especificação EJB 2.1 não são escopo deste curso).
Obs.: os EJBs 3.0 possuem total interoperabilidade com os EJBs 2.1, ficando quase
que transparente para o desenvolvedor caso precise integrá-los.
O capítulo 4.5 introduziu os conceitos da arquitetura de componentes Enterprise
JavaBeans. Vimos que é uma especificação que define um padrão de construção de
componentes modularizados e reutilizáveis que rodam em um servidor de aplicação,
mais especificamente em um container EJB, que lhes fornece serviços indispensáveis
de infra-estrutura distribuída (escalonáveis, transacionais e seguros com multi-
usuários).
Tipos existentes de EJBs:
• Session Beans
o Stateless Session Beans
o Statefull Session Beans
• Message Driven Beans
29
Obs.: até a versão EJB 2.1 também haviam os “Entity Beans”, porém na versão 3.0
eles foram substituidos pela JPA, e com bons motivos (veremos com mais detalhes no
capítulo sobre JPA).
6.1. Session Beans
6.1.1. Identificando os Beans
Quando modelamos um aplicativo empresarial, nos deparamos com dois tipos de
artefatos: entidades e processos. O termo “Entidade” se refere a artefatos com um
estado bem definido, geralmente se apresentam em forma de substantivos ou nomes
(ex.: “Filme”, “Usuário”, “Conta”). As entidades por si só são auto-suficientes, possuem
uma representação lógica. Já o termo “Processo” refere-se a uma tarefa, uma regra de
negócio, que não tem um estado bem definido. Geralmente os processos se
apresentam em forma de verbos ou agentes (ex.: “AgenteDeViagens”), artefatos que
não são auto-suficientes, muito pelo contrário, eles dependem das entidades e
efetuam operações com as mesmas.
Na arquitetura EJB, os Session Beans representam os processos, as tarefas, as
regras de negócio. Podem possuir ou não um estado, porém quando possuem estado,
este é um estado intermediário, transiente (em memória), que não faz sentido persistí-
lo em uma base de dados.
Quando pensamos em “sem estado”, podemos imaginar uma classe sem atributos,
composta apenas de métodos. Na prática é exatamente isso. Por exemplo, um
Session Bean de “Login” não possui estado, ele não precisa armazenar informações
entre diferentes requisições, ele não precisa “lembrar do usuário atual”, ele apenas
fornece a tarefa de efetuarLogin, e esta tarefa é auto-suficiente. Por outro lado, um
Session Bean “CarrinhoDeCompras” precisa ter um estado, pois ele não representa
uma tarefa atômica, ele precisa “lembrar do usuário atual” e armazenar seus itens de
compra, até que finalmente o usuário decida efetuar a transação.
6.1.2. Interfaces de Negócio
Construir EJBs é bem parecido com a construção de objetos remotos que vimos nos
capítulos anteriores, pois o bean pode se “apresentar como um objeto remoto”.
Primeiramente definimos a Interface de Negócio do bean, que representa o seu
contrato, as operações que o bean irá expôr aos clientes.
Interface Características
javax.ejb.Local
• É utilizada quando desejamos acessar o bean
da mesma JVM
• É a interface mais lightweight
• É realizada uma chamada de método local,
como uma classe normal
• A passagem de parâmetros e retorno de
objetos é feita por referência, como o padrão
do java
javax.ejb.Remote
• É utilizada quando desejamos acessar o bean
remotamente, via CORBA ou RMI
• Realiza uma chamada de método remota, por
CORBA, RMI-JRMP ou RMI-IIOP (configurável
de acordo com o container utilizado)
30
• A passagem de parâmetros e retorno de
objetos é feita por valor
• Devido ao item anterior, os parâmetros e
retornos que são objetos precisam ser
serializáveis
javax.ejb.MessageDriven
• É utilizada quando queremos que o MOM
acesse o bean via mensageria (mais detalhes
no capítulo sobre JMS)
javax.jws.WebService
• É utilizada quando desejamos acessar o bean
via WebService
• Disponível apenas para beans Stateless (pois
WebService não guarda estado)
Cada bean pode implementar quantas interfaces de negócio forem necessárias, e o
container EJB fará o trabalho de distribuí-lo das diversas formas solicitadas.
6.1.3. Session Beans – Stateless
Estes são os tipos mais comuns de beans, os que não apresentam estado. Os
Session Beans do tipo Stateless fornecem operações auto-suficientes, onde uma
única requisição do cliente é suficiente para efetuar o processo desejado.
Exemplo de EJB Stateless:
• Interface de Negócio Local
@Local
public interface CalculadoraLocal {
public double somar(double a, double b);
public double subtrair(double a, double b);
public double multiplicar(double a, double b);
public double dividir(double a, double b);
}
• Implementação
@Stateless
public class CalculadoraEJB implements CalculadoraLocal {
public double somar(double a, double b) {
return a + b;
}
public double subtrair(double a, double b) {
return a - b;
}
public double multiplicar(double a, double b) {
return a * b;
}
public double dividir(double a, double b) {
return a / b;
}
}
Como vimos no exemplo acima, para criar um EJB basta definir sua interface de
negócio, anotá-la da maneira desejada e implementar o bean.
Se desejarmos expor o bean também remotamente, criamos uma interface remota:
• Interface de Negócio Remota
@Remote
public interface CalculadoraRemote {
public double somar(double a, double b);
public double subtrair(double a, double b);
public double multiplicar(double a, double b);
public double dividir(double a, double b);
31
}
• Implementação
@Stateless
public class CalculadoraEJB implements CalculadoraLocal, CalculadoraRemote {
public double somar(double a, double b) {
return a + b;
}
public double subtrair(double a, double b) {
return a - b;
}
public double multiplicar(double a, double b) {
return a * b;
}
public double dividir(double a, double b) {
return a / b;
}
}
No exemplo acima, o nosso bean LocadoraEJB será exposto das duas formas,
localmente e remotamente. É permitido utilizar a interface remota para fazer chamadas
da mesma JVM, porém esta chamada será feita de forma remota (os objetos serão
serializados e passados por valor), desperdiçando assim a melhoria de performance
oferecida na chamada local.
Note também que as chamadas locais e remotas não precisam necessariamente
possuir as mesmas operações. Podemos definir operações diferentes para serem
expostas localmente e remotamente, basta definí-las nas respectivas interfaces de
negócio.
Obs.: se desejarmos fornecer exatamente as mesmas operações, podemos melhorar
o código evitando as duplicações das interfaces, da seguinte forma:
public interface CalculadoraOperations {
public double somar(double a, double b);
public double subtrair(double a, double b);
public double multiplicar(double a, double b);
public double dividir(double a, double b);
}
@Local
public interface CalculadoraLocal extends CalculadoraOperations { }
@Remote
public interface CalculadoraLocal extends CalculadoraOperations { }
6.1.4. Session Beans – Statefull
Estes são os tipos mais pesados de beans, os que apresentam estado. Eles são
pesados pois são únicos para cada cliente que os acessa, portanto o container precisa
criar uma instância do bean por requisição (veremos com mais detalhes quando
analisarmos o ciclo-de-vida dos EJBs).
Os Session Beans do tipo Statefull são capazes de guardar estado, portanto podem
ter variáveis de instância e utilizá-las no decorrer dos diversos métodos. Pode ser feita
uma analogia ao HttpSession da tecnologia web, pois é criada uma espécie de
“sessão” para cada cliente que executa o bean.
Exemplo de EJB Statefull:
• Interface de Negócio Local
@Local
public interface CarrinhoDeComprasLocal {
public void adicionarNoCarrinho(double preco);
public double obterTotal();
public void finalizarCompra();
}
32
• Implementação
@Stateful
public class CarrinhoDeComprasEJB implements CarrinhoDeComprasLocal {
private double totalCarrinho;
public void adicionarNoCarrinho(double preco) {
totalCarrinho += preco;
}
public double obterTotal() {
return totalCarrinho;
}
@Remove
public void finalizarCompra() {
System.out.println("Compra finalizada: " + totalCarrinho);
}
}
Uma sessão é criada para um determinado cliente quando o mesmo faz o primeiro
request ao bean, e é finalizada quando o cliente chama o método anotado com
@Remove, ou então quando a sessão expira (este tempo de expiração pode ser
configurado no container).
6.1.5. Ciclo de Vida dos Session beans
Session Beans – Stateless
Os session beans do tipo Stateless possuem um ciclo de vida muito simples, mas
primeiramente devemos falar sobre um serviço muito importante que o container EJB
oferece: o Pooling de Instâncias.
Uma das principais características de uma aplicação empresarial em produção é sofrer
um volume muito grande de acessos, e ela deve estar preparada para isso. Os EJBs
são objetos custosos, pesados. Portanto, como garantir a performance do sistema em
um caso crítico de acessos simultâneos? Com o intuito de otimizar o desempenho da
aplicação, o container fornece o serviço de Pooling de Instâncias. Este serviço faz
parte da especificação EJB e todo container é obrigado a implementá-lo.
O pooling de instâncias é implementado para os dois tipos de EJB que não guardam
estado: o Stateless e o MDB. O serviço funciona da seguinte forma: para cada
Stateless Session Bean e MDB deployados no servidor, o container cria um pool em
memória contendo um determinado número de instâncias desses beans. Então,
quando um cliente solicita um método de bean, uma instância aleatória é escolhida no
pool para servir à solicitação em particular. Quando a chamada do método finaliza, a
instância volta ao pool para posteriormente servir a outra solicitação.
O container não precisa ter a carga de instanciar uma nova instância do bean a cada
requisição, elas já estão prontas no pool. De acordo com a implementação do
container, ele pode decidir aumentar o pool e criar mais instâncias ou até mesmo
destruir instâncias de acordo com o número de requisições média ou memória
disponível.
Atenção
Ao contrário dos Servlets, os EJBs não executam em multithreading:
Servlets uma instância por aplicação e uma nova thread por requisição
EJBs uma instância por requisição (no caso de Stateless e MDB, a mesma
instância pode ser reutilizada por diversas requisições)
Note que isto é possível apenas para os beans Stateless e MDB, que não guardam
informações de estado e, desta forma, duas requisições subsequentes de um mesmo
33
cliente ao mesmo bean podem ser atendidas por instâncias diferentes do bean, sem
causar efeitos colaterais na aplicação.
Sendo assim, o ciclo de vida dos beans Stateless é muito simples, onde existem
apenas dois estados: “Não Existente” e “Pronto no Pool”
Session Beans – Stateful
34
Os session beans do tipo Stateful possuem um ciclo de vida um pouco mais complexo,
mas primeiramente devemos falar sobre um serviço muito importante que o container
EJB oferece: o Mecanismo de Ativação.
Para entender o motivo do mecanismo de ativação, devemos entender o
funcionamento do bean Stateful. O bean Stateful, por ter a característica de manter um
estado referente ao cliente que o chamou, não pode ter suas instâncias reutilizadas
entre clientes diferentes, pois cada instância só diz respeito a um cliente. Por exemplo,
o meu carrinho de compras mantém os valores das minhas compras, e não das
compras do João ou do Pedro. Devido a esta característica, o bean Stateful pode ter
apenas uma instância por cliente, e não pode haver pool pois elas não podem ser
reusadas.
Agora imagine um cenário empresarial, onde há milhares de clientes efetuando acesso
simultâneo a diversos beans Stateful. Como o container irá gerenciar todo esse uso de
memória ? Para isso existe o mecanismo de ativação.
Este mecanismo funciona da seguinte forma: quando o cliente termina de invocar um
método de negócio, o container persiste o estado do bean (variáveis de instância) em
um armazenamento secundário (disco ou banco de dados) e o remove da memória.
Esse processo se chama apassivação. Quando o mesmo cliente solicita novamente
outro método de negócio, o container instancia um novo bean, recupera o estado do
bean do armazenamento e refaz a instância como ela era anteriormente. O processo
de “volta” se chama ativação.
Obs.: o objeto Stub não perde a conexão durante esse processo
Desta forma, o ciclo de vida dos beans Stateful possui um estado a mais que o
Stateless e sem utilização de pool, resultando em três estados: “Não Existente” ,
“Pronto” e “Apassivado”
35
Curiosidade – Entendendo o Mecanismo Remoto Do Container
O papel do container é fazer com que o desenvolvedor esqueça os serviços primários
de infra-estrutura e se concentre em resolver a lógica de negócio através de EJBs.
Porém, vale a pena discutir como os modelos de computação distribuída estudados no
início do curso contribuíram para a especificação e funcionamento bem sucedido do
modelo EJB. Vamos entender como o container EJB trabalha !
O mecanismo de invocação de métodos remota do container é baseado em RMI,
portanto, baseando-se nos capítulos iniciais, vimos que ele precisa ter três coisas:
• Skeleton
• Stub
• Protocolo de comunicação remota
• Serviço de Nomes (Naming Service)
Os beans que implementamos não são objetos remotos, porém o container, através do
design pattern do GOF chamado Proxy, cria um “objeto proxy” que recebe as
requisições e as redireciona para os nossos beans.
Proxy Pattern
Fazendo um comparativo da figura que ilustra o pattern e a arquitetura do container
EJB, temos o bean real que codificamos, que implementa a interface de negócio.
Então, em tempo de deploy, através de reflection, o container gera uma classe proxy
36
que funciona como o Skeleton da arquitetura remota (note que o proxy também
implementa a interface de negócio). Esta classe que é responsável por receber a
invocação remota e “delegar” a chamada à instância do EJB através do container. O
container por sua vez gerencia as questões de pooling, transação e segurança da
chamada.
Vimos também que todo sistema distribuído trabalha em conjunto com um Serviço de
Nomes. Na arquitetura EJB, cada container implementa o serviço de nomes que
preferir. No caso do JBoss, o serviço de nomes padrão é o Java Naming Provider
(JNP), que é uma implementação substituta do RMI Registry. O protocolo de
comunicação padrão de distribuição de EJBs do JBoss é o RMI-JRMP.
Na camada cliente, vimos também que é necessário um Stub para realizar as
chamadas remotas. Porém, nós vimos que o lookup é feito somente com a interface
de negócio. Isto é possível devido ao conceito de codebase (capítulo 2.5), pois ao
fazer o lookup do EJB, o Naming Service informa à JVM cliente o endereço do Stub,
que é baixado e carregado automaticamente em tempo de execução pelo cliente e
desta forma a chamada remota é realizada.
6.2. Distribuindo EJBs
Pacote Sigla
Depl.
Descriptor
Descrição
WAR Web ARchive web.xml
Roda no Container Web, suporta as
especificações Servlets e JSP
EJB-JAR
EJB Java
ARchive
ejb-jar.xml
Roda no Container EJB, suporta as
especificações EJB e JPA (incluir
persistence.xml)
EAR
Enterprise
ARchive
application.xml Roda no Container EJB
• Estrutura do WAR
37
• Estrutura do EJB-JAR
• Estrutura do EAR
6.3. EJB Timer Service
Em sistemas empresariais é muito comum nos depararmos com funcionalidades de
agendamento de tarefas, como por exemplo a geração de relatórios de tempos em
tempos ou expiração de acesso depois de algum tempo de inatividade de um
determinado usuário.
38
Um sistema de agendamento é um sistema que executa algum tipo de atividade
automatizada, de acordo com um intervalo de tempo.
A especificação EJB 3.0 define um serviço de temporização, chamado de EJB Timer
Service. Ele permite a criação de tarefas agendadas, de forma transacional e segura.
Os temporizadores criados dessa forma sobrevivem a quedas e restarts do servidor de
aplicação.
Como a definição do EJB Timer Service é relativamente recente (foi incluída a partir da
versão EJB 2.1), ele ainda é um pouco engessado e pobre de funcionalidades. Porém,
para implementações simples, acaba tornando-se a ferramenta mais recomendada.
Para implementações de temporizadores mais robustos, existe um framework de
mercado chamado Quartz, que é muito mais completo e poderoso que o EJB Timer
Service, além do fato de poder ser utilizado em aplicações Java SE simples, sem a
necessidade de um container EJB (o estudo do framework Quartz não é escopo desse
curso).
Curiosidade: o JBoss Application Server já é distribuído com uma versão do
Quartz acoplada e implementa seus serviços de EJB Timer Service através do
Quartz.
Os temporizadores fornecidos pelo EJB Timer Service podem ser de dois tipos:
• Ação Única
Os temporizadores de ação única disparam apenas uma vez, depois de um certo
intervalo de tempo ou em uma data específica.
• Intervalo
Os temporizadores de intervalo disparam várias vezes, de acordo com um período
de tempo.
Para criar um temporizador, basta obter uma referência ao TimerService do container
e “inscrever” o EJB para ser o timer. Um timer é criado sempre através de um EJB, e
quando o mesmo for disparado, será executado o método que tiver a anotação
@Timeout.
Cuidado
Apenas os beans do tipo Stateless e MDB podem ser timers.
Obtendo a referência ao TimerService do container:
@Resource
private TimerService timerService;
Inscrevendo o bean para ser um timer:
@Stateless
public class TesteTemporizador implements TesteTemporizadorLocal {
@Resource
private TimerService timerService;
public void criarTemporizador() {
Calendar dataDeDisparoAsCalendar = Calendar.getInstance();
//soma 10 dias na data atual
dataDeDisparoAsCalendar.add(Calendar.DATE, 10);
Date dataDeDisparo = dataDeDisparoAsCalendar.getTime();
39
//cria um timer para executar na data informada
timerService.createTimer(dataDeDisparo, null);
}
@Timeout
public void temporizador(Timer timer) {
System.out.println("DISPAROU!");
}
}
Métodos da interface TimerService:
public Timer createTimer(Date expiration, Serializable info)
• Cria timer de Ação Única
• Expira na data especificada
public Timer createTimer(long duration, Serializable info)
• Cria timer de Ação Única
• Expira depois de passado o tempo especificado em milisegundos
public Timer createTimer(Date initialExpiration, long intervalDuration, Serializable info)
• Cria timer de Intervalo
• Expira na data especificada e subsequentemente a cada intervalo
especificado em milisegundos
public Timer createTimer(long initialDuration, long intervalDuration, Serializable info)
• Cria timer de Intervalo
• Expira depois de passado o tempo initialDuration e subsequentemente a cada
intervalo especificado em intervalDuration
public Collection getTimers()
• Retorna uma coleção contendo todos os timers agendados para o bean em
questão
7. Java Persistence API (JPA)
Como vimos no capítulo sobre Session beans, ao projetar um sistema empresarial
geralmente identificamos dois tipos de artefatos: entidades e processos, em que
“Entidade” se refere a artefatos com um estado bem definido e persistente (ex.:
“Filme”, “Usuário”, “Conta”).
Na versão EJB 2.1 existia o conceito de Entity Beans, que também eram componentes
EJB muito parecidos com os Session Beans, com interface de negócio e distribuídos
remotamente, gerando Proxies (ou Skeletons) e Stubs. Ou seja, os Entity Beans eram
pesados, faziam chamadas remotas e dependiam de um container EJB e muita
configuração XML.
Observando o grande sucesso dos frameworks ORM (Object Relational Mapping),
como por exemplo o Hibernate, a partir da versão EJB 3.0 a Sun também decidiu
especificar um framework ORM, e então foi criada a especificação JPA.
40
Note a diferença de implementação para especificação: o Hibernate é um produto, um
framework proprietário desenvolvido e mantido por alguma entidade (atualmente a
Red Hat), enquanto a JPA, assim como o EJB, é uma especificação, estudada e
desenvolvida pela JCP (Java Community Process). A vantagem de ser uma
especificação da JCP é que ele acaba definindo uma “padronização de mercado”, uma
“referência”, definida em consenso com as maiores empresas fornecedoras de
produtos Java, tornando o uso da tecnologia independente de fornecedor, ou seja,
estamos livres para usarmos a implementação que desejarmos ou que revele a melhor
performance (e sempre através da mesma interface de programação).
A JPA é leve, o modelo de desenvolvimento é baseado em POJOs (Plain Old Java
Objects), classes simples, que são manipuladas pelo framework através de
introspecção. Para a configuração das entidades é permitido optar entre configurações
via XML ou o uso das Annotations. Seu uso é bem simplificado, e suas
funcionalidades são todas encapsuladas dentro de um artefato chamado Entity
Manager.
Outra grande vantagem da especificação JPA é que ela foi criada para atuar também
em aplicações simples Java SE, não sendo necessário um servidor de aplicação para
gerenciar as entidades, todas as implementações da JPA devem fornecer uma
implementação do Entity Manager independente de container EJB.
7.1. Entity Manager
É através do Entity Manager que trabalhamos com nossas entidades; ele é o
gerenciador de entidades. Toda e qualquer operação de sincronização com a base de
dados que realizamos nas nossas entidades JPA é gerenciada pelo entity manager.
Ele que é responsável por resolver o mapeamento ORM, criar as conexões com o
banco, gerar os sql statements nativos específicos do banco e efetuar as operações
de persistência (desde que ele esteja associado a um Contexto de Persistência).
Obs.: toda operação realizada com o Entity Manager é transacional, de acordo com os
conceitos de Contexto de Persistência e Entidade Gerenciada que veremos adiante.
Principais operações oferecidas pelo Entity Manager:
persist(Object entity)
• Enfileira a entidade para criação no banco (não representa o momento real do
insert)
• É possível chamar persist fora de uma transação apenas se o contexto for
EXTENDED; nesse caso, a inserção é enfileirada até o contexto ser associado
com uma transação
• Se o parâmetro não for uma entidade, lança IllegalArgumentException
• Se for invocado fora do contexto de transação e for tipo TRANSACTION, lança
uma TransactionRequiredException
41
find(Class<T> entityClass, Object pk) : Entidade
getReference(Class<T> entityClass, Object pk) : Entidade
• Retornam uma entidade a partir de sua chave primária
• O find, se não encontrar retorna null, e utiliza as configurações de lazy-loading
• O getReference, se não encontrar lança EntityNotFoundException
• Se o contexto de persistência estiver ativo ela é acoplada, se não, ela é
desacoplada
createQuery
createXXXQuery
• Executam querys EJB-QL e consultas nativas (retornam um objeto Query)
• Entidades retornadas permanegem gerenciadas enquanto o contexto de
persistência estiver ativo
flush()
• Sincroniza as atualizações no banco antes de terminar a transacao
merge(Object entity) : Entidade
• Atualiza uma entidade desacoplada e retorna uma cópia dela acoplada
• ATENÇÃO: o objeto de parâmetro nunca é gerenciado pelo EntityManager, e
sim sua cópia que retorna. Se ele já estiver gerenciado a mesma instancia, ele
a atualiza e retorna sua referencia.
remove(Object entity)
• Remove a entidade da base e a torna desacoplada
refresh(Object entity)
• Atualiza a entidade acoplada com os dados da base
• Se ela não for acoplada ao próprio EntityManager que invoca o método, é
lançada IllegalArgumentException
• Se o objeto não estiver mais no banco devido a outra Thread ou Processo te-
lo removido, será lançado EntityNotFoundException
contains(Object entity) : Boolean
• Retorna true se a entidade estiver acoplada, false caso contrario.
clear()
• Desacopla todas as entidades atuais gerenciadas pelo EntityManager
• Suas modificações são perdidas, portanto é prudente chamar flush() antes.
7.2. Ciclo de Vida
As entidades JPA apresentam um ciclo-de-vida em relação ao Entity Manager,
mostrado na figura abaixo:
42
• New / Nova
Aqui a entidade ainda não tem um estado persistente, ela acabou de ser instanciada
Ex.:
Pessoa p = new Pessoa();
• Managed / Gerenciada / Acoplada
Aqui a entidade está gerenciada pelo Entity Manager. Isto significa que ela possui um
Id Persistente, ou seja, ela representa ativamente um registro da tabela e qualquer
mudança de seus atributos refletirá automaticamente na tabela após o flush do Entity
Manager ou no final da transação atual.
Ex.:
Pessoa p = entityManager.find(Pessoa.class, 2);
//neste momento, p está “Gerenciada”
p.setNome(“Gilberto Holms”);
p.setIdade(24);
entityManager.flush();
No trecho de código apresentado, após o comando find o Entity Manager irá retornar
uma entidade gerenciada, que representa um registro ativo no banco de dados.
• Detached / Desacoplada
Ocorre quando a entidade perde o sincronismo com o banco. Isso pode acontecer nas
seguintes ocasiões:
o Acabou o Contexto de Persistência
o Foi executado o método clear do Entity Manager
o A entidade foi removida do Contexto de Persistência (método remove)
o A entidade foi enviada ao cliente (retorno do método de negócio de um
EJB)
Ex.:
Pessoa p = entityManager.find(Pessoa.class, 2);
//neste momento, p está “Gerenciada”
p.setNome(“Gilberto Holms”);
p.setIdade(24);
entityManager.flush();
43
entityManager.clear();
//neste momento, p está “Desacoplada”
• Removed / Removida
Uma entidade torna-se removida quando é deletada do banco. Isto é feito através do
método remove do Entity Manager. Após ser removida, ela é automaticamente
desacoplada do Entity Manager.
Ex.:
Pessoa p = entityManager.find(Pessoa.class, 2);
//neste momento, p está “Gerenciada”
p.setNome(“Gilberto Holms”);
p.setIdade(24);
entityManager.flush();
entityManager.remove(p);
//neste momento, p está “Removida”
• Persisted / Persistida
Representa a entidade persistida no banco de dados. Com a abstração do JPA,
podemos entender uma linha de uma tabela como uma instância de um objeto Java.
Ela será retornada ao aplicativo após a execução de qualquer método de consulta do
Entity Manager em que ela atenda os requisitos da busca.
7.3. Contexto de Persistência
O Contexto de Persistência é um conceito da JPA, que significa “o tempo em que as
entidades estão gerenciadas pelo Entity Manager”.
Quando o Contexto de Persistência acaba, as entidades tornam-se desacopladas.
Na arquitetura EJB é possível utilizar dois tipos de contextos de persistência:
Transaction e Extended.
• Transaction
O tipo “Transaction” pode ser utilizado em qualquer tipo de EJB. Significa que o
contexto de persistência irá durar o tempo que durar a transação atual, ou seja, ao
terminar a transação atual, as entidades tornam-se desacopladas.
44
• Extended
O tipo “Extended” foi criado para ser utilizado apenas para os EJBs do tipo Stateful.
Significa que o contexto de persistência irá durar o tempo que durar a sessão do bean
Stateful, ou seja, uma entidade pode-se manter gerenciada entre diferentes
transações e métodos de negócio. Utilizando esse tipo de contexto de persistência,
podemos interagir com uma entidade mesmo fora de uma transação, pois as
alterações realizadas serão enfileiradas e efetivadas quando for iniciada a próxima
transação para aquele entity manager.
45
7.4. Configurando uma Aplicação JPA
Um conjunto de entidades JPA pode ser empacotado em um pacote EJB-JAR, como
ilustrado no capítulo 6.2. Ela será caracterizada por conter um arquivo obrigatório na
pasta META-INF, chamado “persistence.xml”.
Exemplo de persistence.xml:
<persistence>
<persistence-unit name="curso">
<jta-data-source>java:/meuDataSource</jta-data-source>
<properties>
<property name="org.hibernate.hbm2ddl"
value="update" />
</properties>
</persistence-unit>
</persistence>
Um arquivo persistence.xml pode conter várias “Persistence Unit” (Unidade de
Persistência). Uma Unidade de Persistência representa um conjunto de entidades
gerenciadas que residem no mesmo Data Source.
@Stateless
public class MyBean implements MyBusinessInterface {
@PersistenceContext(unitName="curso", type=PersistenceContextType.TRANSACTION)
private EntityManager manager;
...
}
Na prática, uma Unidade de Persistência representa um Entity Manager. Cada Entity
Manager trabalha com uma Unidade de Persistência. Em sistemas mais complexos,
onde haja mais de uma base de dados, é possível trabalhar com múltiplas unidades de
persistência.
Tags importantes:
<persistence-unit name="curso"> Declara a unidade de persistência, informando um
nome (obrigatório)
<jta-data-source> Declara um Data Source transacional (API JTA,
padrão para sistemas JEE), indicando o
“endereço JNDI” do Data Source dentro do
container
<properties> Declara propriedades específicas do fabricante da
implementação JPA utilizada
Tendo configurado o persistence.xml, basta criar as entidades e mapeá-las. O
mapeamento ORM pode ser feito de três maneiras:
• Via Annotations – mais simples, com anotações nas próprias classes de
entidade
• Via XML – é criado um arquivo chamado orm.xml, também dentro de META-
INF, contendo os mapeamentos das entidades
• Annotations com XML – caso utilizados juntos, o XML sobrescreve
parcialmente as Annotations
Obs.: os mapeamentos via XML não serão abordados nesse curso, utilizaremos
sempre as Annotations pelo fato de simplificarem o desenvolvimento e a manutenção
do sistema, porém isso não descarta a citação de trechos do XML quando for
interessante.
46
7.5. Mapeando Relacionamentos
Todos os tipos de mapeamento de entidades podem ser realizados com duas
variações: Unidirecional e Bidirecional. Quanto a sua estrutura de schema físico
(base de dados) eles não diferem em nada. Isto é relevante apenas para o
desenvolvimento na camada Java:
• Unidirecional – é quando queremos pesquisar partindo apenas de um lado do
relacionamento. Por exemplo, Pessoa vs. Enredeço: queremos saber qual é o
endereço de uma pessoa, mas não precisamos saber qual pessoa pertence a
um endereço.
pessoa.getEndereco(); //OK
endereco.getPessoa(); //NÃO EXISTE
• Bidirecional – é quando queremos pesquisar partindo de ambos os lados do
relacionamento. Por exemplo, Pessoa vs. Enredeço: queremos saber qual é o
endereço de uma pessoa e também precisamos saber qual pessoa pertence a
um endereço.
pessoa.getEndereco(); //OK
endereco.getPessoa(); //OK
7.5.1. Um-Para-Um Unidirecional
@Entity
public class Customer {
...
@OneToOne(cascade={CascadeType.ALL})
private Address address;
...
}
7.5.2. Um-Para-Um Bidirecional
@Entity
public class Customer {
...
@OneToOne(cascade={CascadeType.ALL})
private CreditCard creditCard;
...
}
@Entity
public class CreditCard {
...
@OneToOne(mappedBy="creditCard")
private Customer customer;
...
}
7.5.3. Um-para-Muitos Unidirecional
@Entity
public class Customer {
...
@OneToMany(cascade={CascadeType.ALL})
private Collection<Phone> phoneNumbers = new ArrayList<Phone>( );
...
}
47
7.5.4. Muitos-Para-Um Unidirecional
@Entity
public class Cruise {
...
@ManyToOne
private Ship ship;
...
}
7.5.5. Um-Para-Muitos / Muitos-Para-Um Bidirecional
@Entity
public class Reservation {
...
@ManyToOne
private Cruise cruise;
...
}
@Entity
public class Cruise {
...
@OneToMany(mappedBy="cruise")
private Collection<Reservation> reservations = new ArrayList<Reservation>( );
...
}
7.5.6. Muitos-Para-Muitos Unidirecional
@Entity
public class Reservation {
...
@ManyToMany
private Set<Customer> customers = new HashSet<Customer>( );
...
}
7.5.7. Muitos-Para-Muitos Bidirecional
@Entity
public class Reservation {
...
@ManyToMany
private Set<Customer> customers = new HashSet<Customer>( );
...
}
@Entity
public class Customer {
...
@ManyToMany(mappedBy="customers")
private Collection<Reservation> reservations = new ArrayList<Reservation>( );
...
}
7.6. Cascade Type
Um conceito importante é o de atividades em cascata. Existem os seguintes tipos de
cascata:
• ALL
• PERSIST
48
• MERGE
• REMOVE
• REFRESH
Por padrão, quando temos um relacionamento entre entidades, as operações do Entity
Manager são realizadas apenas para a entidade “superior” do relacionamento.
Por exemplo:
Endereco e = new Endereco();
...
pessoa.setEndereco(e);
entityManager.persist(pessoa)
No caso mostrado acima, se não tiver sido configurado nenhum tipo de cascata para o
relacionamento, ao persistir a entidade pessoa, o endereço não será persistido, a JPA
irá subentender que ele já existe na base de dados (e caso não exista, lançará
exception).
Se colocássemos um CascadeType.PERSIST, a JPA iria persistir automaticamente o
endereço (caso ele não exista na base) antes de persistir a pessoa.
Note que os nomes dos Cascade Types são idênticos a alguns métodos do Entity
Manager (exceto ALL, que indica “faça todos”). Em resumo, cada tipo de cascata
indica ao Entity Manager para “também realizar a respectiva operação para a
entidade relacionada”.
7.7. Lazy Loading
Outro conceito importante é o de Lazy Loading, que significa “trazer dados sob
demanda”. Quando setamos um relacionamento como LAZY, significa que a JPA irá
trazer as entidades relacionadas apenas quando o código java precisar acessá-las.
Este recurso é útil quando possuimos uma entidade com muitos relacionamentos.
Por exemplo:
Entidade:
@Entity
public class Customer {
...
@OneToMany(cascade={CascadeType.ALL})
private Collection<Phone> phoneNumbers = new ArrayList<Phone>( );
...
}
FetchType.LAZY
Customer c = entityManager.find(Customer.class, 2);
//neste momento o objeto c não contém a lista de telefones
c.getPhoneNumbers().size();
//apenas nesse momento a JPA carrega a lista de telefones
FetchType.EAGER
Customer c = entityManager.find(Customer.class, 2);
//neste momento o objeto c já contém a lista de telefones
Atenção
49
O carregamento sob demanda funciona apenas se a entidade ainda estiver
gerenciada pelo container. Quando a entidade torna-se desacoplada, qualquer
tentativa de carregamento LAZY resulta em exception.
7.8. CRUD com JPA
Inserir:
Pessoa p = new Pessoa();
p.setNome("Gilberto");
p.setIdade(24);
...
entityManager.persist(p);
Atualizar:
p.setNome("Holms");
...
p = entityManager.merge(p);
Excluir:
entityManager.remove(p);
Buscar (por Primery Key):
Pessoa p = entityManager.find(Pessoa.class, 2);
//procura um registro através da Primery Key da tabela
//se não encontrar, retorna null
Listar (por EJB-QL):
Query query = entityManager.createQuery(
"SELECT p FROM Pessoa AS p WHERE p.nome = :nome"
);
query.setParameter("nome", "Gilberto");
List pessoas = query.getResultList();
7.9. Data Sources no JBoss
Para a plataforma Java Enterprise, o termo “Data Sources” (Fonte de Dados)
representa um ponto de acesso a um sistema de armazenamento secundário,
geralmente um banco de dados.
Nos aplicativos JEE, devido à capacidade do container de injetar dependências e
gerenciar recursos, esse Data Source é configurado em algum arquivo de
configurações ou console administrativo do servidor, e disponibilizado para a aplicação
via JNDI Global.
Tendo esse Data Source configurado, qualquer aplicativo pode fazer seu “lookup” e
utilizá-lo para abrir uma sessão com a base de dados. Quando isso ocorre em um
servidor JEE, ele ainda pode gerenciar todo o controle transacional (através de JTA –
Java Transaction API) peculiar da especificação.
Reduzindo ao nosso mundo, no escopo da utilização da JPA, vimos anteriormente que
devemos configurar um Data Source no persistence.xml, e é através desse Data
Source que a JPA irá persistir os objetos.
Veja novamente um trecho de um arquivo persistence.xml:
<persistence>
50
<persistence-unit name="curso">
<jta-data-source>java:/meuDataSource</jta-data-source>
</persistence-unit>
</persistence>
Quando utilizamos a tag <jta-data-source> estamos definindo o endereço JNDI
do Data Source que a nossa unidade de persistência irá utilizar.
Obs.: note que podemos ter outra unidade de persistência com um Data Source
diferente, e utilizar um Entity Manager para cada unidade.
Nos diversos servidores de aplicação disponíveis no mercado, cada um tem sua forma
específica de configurar Data Sources. Em servidores mais poderosos, como por
exemplo o Oracle WebLogic, essa configuração é feita via console administrativo.
Infelizmente o console administrativo do JBoss ainda não chegou nesse nível de
maturidade, o que torna necessária a configuração de Data Sources via arquivo XML.
No JBoss Application Server podemos criar Data Sources no escopo do servidor ou no
escopo da aplicação.
• Criar Data Sources no JBoss, escopo de servidor:
o Criar um arquivo de final “-ds.xml” com as configurações do DS (ex.:
curso-ds.xml)
o Copiar o JAR do Driver JDBC da base de dados configurada para a
pasta “lib” do seu Server Configuration
o Copiar o arquivo “-ds.xml” para a pasta “deploy” do seu Server
Configuration
o Pronto, o DS estará disponível para qualquer aplicação
• Criar Data Souces no JBoss, escopo de aplicação:
o Criar um arquivo de final “-ds.xml” com as configurações do DS (ex.:
curso-ds.xml)
o Copiar o JAR do Driver JDBC da base de dados configurada para a
pasta “APP-INF/lib” do seu EAR
o Copiá-lo para a pasta “META-INF” do seu EAR
o O DS estará disponível para esta aplicação específica
Exemplo de –ds.xml:
<datasources>
<local-tx-datasource>
<jndi-name>cursoDS</jndi-name>
<connection-url>jdbc:mysql://localhost:3306/curso</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>root</user-name>
<password>root</password>
<exception-sorter-class-name>
org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
</exception-sorter-class-name>
<metadata>
<type-mapping>mySQL</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>
Atenção
As configurações de data source são específicas para cada fornecedor de base
de dados, porém o JBoss já vem com um exemplo de configuração para as
principais bases de dados, basta modificá-los e utilizá-los. Estes exemplos
residem na pasta “docs/examples/jca”, a partir do diretório raiz JBoss.
51
8. Principais Design Patterns JEE
Em 1994, um grupo de quatro experientes desenvolvedores e arquitetos de software
(Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides), após reunirem suas
experiências sobre sistemas orientados a objeto, acabaram criando o livro “Design
Patterns: Elements of Reusable Object-Oriented Software”, que é o mais
renomado livro sobre design patterns conhecido até os dias de hoje. Este grupo foi
nomeado como “Gang of Four” (GoF).
Após a publicação deste livro é que se teve o conceito de Design Patterns bem
definido e adotado mundialmente. Design patterns são padrões de desenvolvimento
bem sucedidos e reutilizáveis, criados para resolver os problemas arquiteturais mais
comuns do desenvolvimento orientado a objetos através de uma solução testada e
bem sucedida nos diversos aspectos. O livro da GoF define 23 patterns que resolvem
grande parte dos problemas estruturais de sistemas orientado a objeto.
Porém, quando lançada a arquitetura Java EE, os próprios arquitetos da Sun
identificaram na sua estrutura algumas limitações e pontos de atenção que, se não
estudados devidamente, poderiam causar muitos problemas para as aplicações
baseadas no modelo JEE. Após esse estudo, foi lançado o conceito de “J2EE
Patterns”, que são os padrões de projeto específicos para um desenvolvimento
correto sobre a estrutura JEE. Este conceito foi introduzido no livro “Core J2EE
Patterns: Best Practices and Design Strategies”, escrito pelos mais renomados
arquitetos de software da Sun Microsystems, desenvolvedores do JEE (Deepak Alur,
John Crupi e Dan Malks).
8.1. Singleton
O Design pattern “Singleton” não é um pattern JEE, mas sim um pattern do GoF. O
estudo dos design patterns da GoF não é escopo deste livro, porém este pattern em
especial é utilizado como parte de diversos J2EE Patterns, portanto é importante o seu
entendimento.
Como o próprio nome do pattern indica, o seu objetivo é manter apenas uma instância
de um objeto na memória, e todas as classes que utilizarem este objeto estarão
utilizando a mesma instância dele.
Ele traz diversos benefícios, como menor consumo de memória garantindo que existe
apenas uma instância do objeto, fornecimento de um único ponto de acesso ao objeto
e maior flexibilidade que métodos estáticos, pois permite polimorfismo.
Procedimentos para implementação:
• Criar um atributo privado e estático do tipo da própria classe
• Criar um construtor privado, para não permitir que outras classes instanciem
seu objeto
• Cria um método estático getInstance, que irá retornar a única instância que
existirá
Exemplo de Implementação:
public class Configuracoes {
//atributo com a unica instância existente
private static Configuracoes configuracoes;
52
//Construtor privado
private Configuracoes(){
// qualquer código de inicialização da instância
}
//método que retorna a instância singleton
public static Configuracoes getInstance() {
if (configuracoes == null) {
configuracoes = new Configuracoes();
}
return configuracoes;
}
}
8.2. Service Locator
Aqui iniciamos os J2EE patterns. Com o uso de sistemas distribuídos e serviços de
nomes, tornou-se muito comum em sistemas J2EE a necessidade de localização de
recursos na rede ou no disco, tais recursos que poderiam constantemente ser
trocados de endereço ou domínio.
Nos capítulos sobre RMI e EJB vimos constantemente a necessidade de lookup de
recursos no JNDI, porém não é uma boa solução deixar esse serviço dentro da lógica
do negócio, mesmo porque ele não representa uma questão de negócio, e sim uma
questão de infra-estrutura.
Para resolver esta questão arquitetural foi desenvolvido o pattern “Service Locator”,
que torna-se uma camada responsável por localizar recursos e serviços, abstraindo a
localização física dos mesmos.
Procedimentos para implementação:
• Criar uma classe para representar o Service Locator, utilizando o padrão
Singleton
• Fornecer um método para retornar cada tipo de recurso desejado, através de
alguma identificação do mesmo
Exemplo de Implementação:
public class ServiceLocator {
//atributo de instância singleton
private static ServiceLocator serviceLocator;
private Context initialContext;
//construtor singleton
private ServiceLocator() throws ServiceLocatorException{
Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
properties.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
try {
this.initialContext = new InitialContext(properties);
} catch (NamingException e) {
throw new ServiceLocatorException(e);
}
}
//método que retorna a instância singleton
public static ServiceLocator getInstance() throws ServiceLocatorException {
if (serviceLocator == null) {
serviceLocator = new ServiceLocator();
}
53
return serviceLocator;
}
//método que retorna um servico do jndi configurado (um EJB, DataSource, etc...)
public Object getService(String jndiName, Class clazz) throws
ServiceLocatorException {
try {
Object ref = initialContext.lookup(jndiName);
return PortableRemoteObject.narrow(ref, clazz);
} catch (NamingException e) {
throw new ServiceLocatorException(e);
}
}
}
Com isso, garantimos que os recursos que dependem de localização serão criados
através de um único ponto do sistema, deixando o negócio transparente da localização
física dos recursos, abstraindo as chamadas de lookup e particularidades de JNDI.
Poderíamos ainda incrementar nosso Service Locator com arquivos “properties”
associando beans a endereços, ou ainda implementar um mecanismo de cache.
8.3. Business Delegate
O papel do Business Delegate é encapsular as chamadas aos objetos de negócio. O
Business Delegate pode localizar o recurso na rede, obter o Stub e invocar suas
operações, podendo também tratar error de i/o remoto.
O Business Delegate remove o acoplamento entre a camada cliente e os objetos de
negócio. Desta forma, a camada cliente não precisa se preocupar com localização de
objetos, pode reduzir o tráfico na rede agrupando chamadas a objetos e permite ainda
a implementação de algum mecanismo de cache.
54
Procedimentos para implementação:
• Criar uma classe para representar o Business Delegate, contendo como
variável de instância o objeto de negócio que ele encapsulará.
• Fornecer um construtor público, que irá localizar o recurso através do Service
Locator e guardá-lo na variável de instância.
• Fornecer um método para encapsular cada método de negócio que será
chamado (não precisa ser necessariamente um-para-um, sempre que possível
pode-se, por exemplo, encapsular duas chamadas ao objeto de negócio em
apenas uma chamada ao Business Delegate).
Exemplo de Implementação:
public class LocadoraDelegate {
private Locadora locadora;
private static final Class clazz = Locadora.class;
public LocadoraDelegate() throws DelegateException {
try {
this.locadora =
(Locadora)ServiceLocator.getInstance().getService("java:/Locadora", clazz);
} catch(ServiceLocatorException e) {
throw new DelegateException(e);
} catch(RemoteException e) {
throw new DelegateException(e);
}
}
public int alugarFilme(int id) throws DelegateException {
try {
int protocolo = locadora.alugarFilme(id);
return protocolo;
} catch(RemoteException e) {
throw new DelegateException(e);
}
}
}
8.4. Session Facade
Quando distribuímos objetos pela rede, expomos suas interfaces de negócio ao
cliente, consequentemente criando uma granularidade muito alta de serviços. Isso
força o cliente a realizar muitas chamadas remotas a um objeto distribuído para
realizar uma determinada operação, aumentando o tráfego na rede.
Além do problema da rede, temos também uma falta de padronização nas chamadas
de negócio provenientes de diferentes clientes e alto acoplamento entre o cliente e os
objetos distribuídos.
Com a criação de um Session Facade, transformamos muitas chamadas remotas
complexas em uma única chamada remota, de grossa granularidade, a qual encapsula
as chamadas finas que se tornarão locais, diminuindo assim o tráfego na rede.
• Sem Session Facade:
55
• Com Session Facade:
Como observamos nos diagramas acima, antes da criação do Session Facade, um
determinado cliente realiza três chamadas remotas para realizar uma determinada
funcionalidade. Após a criação do Session facade, que também é um objeto remoto (o
nome “Session” vem de “Session Bean”), é realizada uma única chamada remota, de
grossa granularidade e baixa complexidade, onde o Session Facade realiza três
chamadas que tornam-se locais, pois ele vive “no mesmo local” que os objetos
remotos.
Obs.: existem dois tipos de Session Facade: Stateless e Stateful, que analogamente
são criados a partir dos respectivos Session Beans, para funcionalidades de negócio
sem estado e com estado respectivamente.
56
8.5. Data Transfer Object (DTO)
Na especificação EJB 2.1 e anteriores, havia o conceito de Entity Beans, onde
entidades persistentes eram implementadas como componentes de negócio EJB,
possuindo interfaces de negócio, consequentemente Stub, Skeleton e operação
remota. Devido a essa arquitetura, quando um cliente solicitava uma entidade ao
container EJB, esta entidade era retornada como um objeto remoto, e cada interação
com a mesma resultava em uma chamada custosa ao servidor, deteriorando a
performance do sistema.
Para resolver este problema foi criado o pattern Data Transfer Object (conhecido
também por outros nomes como Transfer Object ou Value Object). O pattern consiste
na criação de um POJO contendo os atributos da entidade ou qualquer outro conjunto
de informações, o qual será trafegado para o cliente ao invés do Entity Bean. Desta
forma o cliente recebe um objeto java simples, preenchido com os dados relevantes da
chamada realizada, sem precisar realizar mais chamadas remotas.
A partir da criação da versão EJB 3.0, com a introdução da Java Persistence (JPA),
muitos autores discutem sobre a necessidade do uso desse pattern, pois como agora
as entidades já são POJOs, o servidor pode retorná-las diretamente ao cliente como
entidades desacopladas, ou seja, elas já seriam o DTO.
Porém, ainda assim há cenários em que seria relevante o uso do pattern DTO.
Imagine que você tem uma entidade JPA com oitenta campos, porém sua tela
necessita apenas de três deles, ou ainda que sua tela precise de informações
provenientes de três entidades distintas, ou então você não deseja nenhum
acoplamento entre sua tela e as entidades de negócio. Reflita sobre o uso do DTO
nesses casos.
9. JMS e Message Driven Beans
Ao decorrer deste livro estudamos alguns componentes da especificação JEE, como
Stateless Session Beans, Stateful Session Beans e Entidades JPA. Porém, todos eles
têm uma característica em comum: são síncronos. Quando executamos uma operação
da interface de negócio de um Session Bean, nós ficamos aguardando a resposta.
Outra característica é o forte acoplamento, pois um cliente precisa conhecer bem o
componente remoto que está invocando, pois ele é dependente de sua interface de
negócio.
Porém, em alguns casos seria muito interessante possuir um sistema assíncrono e
desacoplado para troca de informações e este é o papel dos Message Driven Beans.
9.1. O que é Mensageria ?
Dentro de uma aplicação, existem diversas de se trocar informações entre
componentes. Por exemplo, no RMI a troca de mensagens é feita via chamadas de
métodos sobre algum protocolo de rede. O componente cliente precisa conhecer cada
componente remoto que invoca e aguardar sua resposta para prosseguir o
processamento.
O componente cliente é completamente dependente do recipiente, pois ele só
funcionará se o recipiente estiver online e pronto para responder a chamada. Podemos
fazer uma analogia a uma ligação telefônica: quando ligamos para uma pessoa e esta
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss
JavaEE EJB JPA JMS no JBoss

Mais conteúdo relacionado

Mais procurados

Mais procurados (15)

Apostila de hardware
Apostila de hardwareApostila de hardware
Apostila de hardware
 
Apostila de-formação-operações-unitárias
Apostila de-formação-operações-unitáriasApostila de-formação-operações-unitárias
Apostila de-formação-operações-unitárias
 
Apostila Java
Apostila JavaApostila Java
Apostila Java
 
Guia Quantum GIS
Guia Quantum GISGuia Quantum GIS
Guia Quantum GIS
 
Moodle
MoodleMoodle
Moodle
 
Hardware idepac
Hardware idepacHardware idepac
Hardware idepac
 
Cientista da computacao usando python
Cientista da computacao usando pythonCientista da computacao usando python
Cientista da computacao usando python
 
Desenvolvimento-web-com-html-css-e-javascript
Desenvolvimento-web-com-html-css-e-javascriptDesenvolvimento-web-com-html-css-e-javascript
Desenvolvimento-web-com-html-css-e-javascript
 
Manutencão pcs
Manutencão pcsManutencão pcs
Manutencão pcs
 
Mpoda(1)
Mpoda(1)Mpoda(1)
Mpoda(1)
 
Resumo de aulas lp1
Resumo de aulas lp1Resumo de aulas lp1
Resumo de aulas lp1
 
Installdebian
InstalldebianInstalldebian
Installdebian
 
Python
PythonPython
Python
 
Guia lego
Guia legoGuia lego
Guia lego
 
Ubuntu guia_do_iniciante
Ubuntu guia_do_inicianteUbuntu guia_do_iniciante
Ubuntu guia_do_iniciante
 

Semelhante a JavaEE EJB JPA JMS no JBoss

caelum-java-objetos-fj11.pdf
caelum-java-objetos-fj11.pdfcaelum-java-objetos-fj11.pdf
caelum-java-objetos-fj11.pdfssuserbc6cf7
 
Manual Do Professor192 B
Manual Do Professor192 BManual Do Professor192 B
Manual Do Professor192 BGILMARMASCHIO
 
Manual Do Professor192 B
Manual Do Professor192 BManual Do Professor192 B
Manual Do Professor192 Bvaldemirfasul
 
Manual Do Professor192 B
Manual Do Professor192 BManual Do Professor192 B
Manual Do Professor192 BAlineDaiana
 
Caelum java-web-vraptor-hibernate-ajax-fj28
Caelum java-web-vraptor-hibernate-ajax-fj28Caelum java-web-vraptor-hibernate-ajax-fj28
Caelum java-web-vraptor-hibernate-ajax-fj28Valdinho Pereira
 
Qgis 1.4.0 manual-do_usuário_0.1_ForDãO.
Qgis 1.4.0 manual-do_usuário_0.1_ForDãO.Qgis 1.4.0 manual-do_usuário_0.1_ForDãO.
Qgis 1.4.0 manual-do_usuário_0.1_ForDãO.Tiago ForDão
 
Aprenda computação com python 3.0 (1)
Aprenda computação com python 3.0 (1)Aprenda computação com python 3.0 (1)
Aprenda computação com python 3.0 (1)intaum
 
Programando ooo b
Programando ooo bProgramando ooo b
Programando ooo bvangney
 
Aprenda a Programar com C#
Aprenda a Programar com C#Aprenda a Programar com C#
Aprenda a Programar com C#Antonio Trigo
 
K19 k11-orientacao-a-objetos-em-java
K19 k11-orientacao-a-objetos-em-javaK19 k11-orientacao-a-objetos-em-java
K19 k11-orientacao-a-objetos-em-javaOnilson Oliveira
 
K19 k11-orientacao-a-objetos-em-java
K19 k11-orientacao-a-objetos-em-javaK19 k11-orientacao-a-objetos-em-java
K19 k11-orientacao-a-objetos-em-javavicnetepc
 

Semelhante a JavaEE EJB JPA JMS no JBoss (20)

Vim
VimVim
Vim
 
Zope
ZopeZope
Zope
 
caelum-java-objetos-fj11.pdf
caelum-java-objetos-fj11.pdfcaelum-java-objetos-fj11.pdf
caelum-java-objetos-fj11.pdf
 
Apostila JSF 2.0 - K19
Apostila JSF 2.0 - K19Apostila JSF 2.0 - K19
Apostila JSF 2.0 - K19
 
Manual Do Professor192 B
Manual Do Professor192 BManual Do Professor192 B
Manual Do Professor192 B
 
Manual Do Professor192 B
Manual Do Professor192 BManual Do Professor192 B
Manual Do Professor192 B
 
Manual Do Professor192 B
Manual Do Professor192 BManual Do Professor192 B
Manual Do Professor192 B
 
Caelum java-web-vraptor-hibernate-ajax-fj28
Caelum java-web-vraptor-hibernate-ajax-fj28Caelum java-web-vraptor-hibernate-ajax-fj28
Caelum java-web-vraptor-hibernate-ajax-fj28
 
Php
PhpPhp
Php
 
Qgis 1.4.0 manual-do_usuário_0.1_ForDãO.
Qgis 1.4.0 manual-do_usuário_0.1_ForDãO.Qgis 1.4.0 manual-do_usuário_0.1_ForDãO.
Qgis 1.4.0 manual-do_usuário_0.1_ForDãO.
 
Caelum java-web-fj21
Caelum java-web-fj21Caelum java-web-fj21
Caelum java-web-fj21
 
Aprenda computação com python 3.0 (1)
Aprenda computação com python 3.0 (1)Aprenda computação com python 3.0 (1)
Aprenda computação com python 3.0 (1)
 
Programando ooo b
Programando ooo bProgramando ooo b
Programando ooo b
 
Introdução ao SciLab
Introdução ao SciLabIntrodução ao SciLab
Introdução ao SciLab
 
20220093 scilab-manual
20220093 scilab-manual20220093 scilab-manual
20220093 scilab-manual
 
Aprenda a Programar com C#
Aprenda a Programar com C#Aprenda a Programar com C#
Aprenda a Programar com C#
 
Apostila geo gebra
Apostila geo gebraApostila geo gebra
Apostila geo gebra
 
K19 k11-orientacao-a-objetos-em-java
K19 k11-orientacao-a-objetos-em-javaK19 k11-orientacao-a-objetos-em-java
K19 k11-orientacao-a-objetos-em-java
 
K19 k11-orientacao-a-objetos-em-java
K19 k11-orientacao-a-objetos-em-javaK19 k11-orientacao-a-objetos-em-java
K19 k11-orientacao-a-objetos-em-java
 
Tutorial java
Tutorial javaTutorial java
Tutorial java
 

Mais de Gilberto Holms

BalanceLine4j Framework Overview
BalanceLine4j Framework OverviewBalanceLine4j Framework Overview
BalanceLine4j Framework OverviewGilberto Holms
 
Resumo Anotacoes Certificacao OCE WebLogic Portal 10g Developer
Resumo Anotacoes Certificacao OCE WebLogic Portal 10g DeveloperResumo Anotacoes Certificacao OCE WebLogic Portal 10g Developer
Resumo Anotacoes Certificacao OCE WebLogic Portal 10g DeveloperGilberto Holms
 
Resumo Anotacoes JAX-WS Certificacao SCDJWS 5
Resumo Anotacoes JAX-WS Certificacao SCDJWS 5Resumo Anotacoes JAX-WS Certificacao SCDJWS 5
Resumo Anotacoes JAX-WS Certificacao SCDJWS 5Gilberto Holms
 
Resumo Anotacoes Certificacao SCBCD 5
Resumo Anotacoes Certificacao SCBCD 5Resumo Anotacoes Certificacao SCBCD 5
Resumo Anotacoes Certificacao SCBCD 5Gilberto Holms
 
Resumo Anotacoes Certificacao SCWCD 5
Resumo Anotacoes Certificacao SCWCD 5Resumo Anotacoes Certificacao SCWCD 5
Resumo Anotacoes Certificacao SCWCD 5Gilberto Holms
 
Resumo Anotacoes Certificacao SCJP 5
Resumo Anotacoes Certificacao SCJP 5Resumo Anotacoes Certificacao SCJP 5
Resumo Anotacoes Certificacao SCJP 5Gilberto Holms
 
FFPOJO Framework Overview
FFPOJO Framework OverviewFFPOJO Framework Overview
FFPOJO Framework OverviewGilberto Holms
 

Mais de Gilberto Holms (7)

BalanceLine4j Framework Overview
BalanceLine4j Framework OverviewBalanceLine4j Framework Overview
BalanceLine4j Framework Overview
 
Resumo Anotacoes Certificacao OCE WebLogic Portal 10g Developer
Resumo Anotacoes Certificacao OCE WebLogic Portal 10g DeveloperResumo Anotacoes Certificacao OCE WebLogic Portal 10g Developer
Resumo Anotacoes Certificacao OCE WebLogic Portal 10g Developer
 
Resumo Anotacoes JAX-WS Certificacao SCDJWS 5
Resumo Anotacoes JAX-WS Certificacao SCDJWS 5Resumo Anotacoes JAX-WS Certificacao SCDJWS 5
Resumo Anotacoes JAX-WS Certificacao SCDJWS 5
 
Resumo Anotacoes Certificacao SCBCD 5
Resumo Anotacoes Certificacao SCBCD 5Resumo Anotacoes Certificacao SCBCD 5
Resumo Anotacoes Certificacao SCBCD 5
 
Resumo Anotacoes Certificacao SCWCD 5
Resumo Anotacoes Certificacao SCWCD 5Resumo Anotacoes Certificacao SCWCD 5
Resumo Anotacoes Certificacao SCWCD 5
 
Resumo Anotacoes Certificacao SCJP 5
Resumo Anotacoes Certificacao SCJP 5Resumo Anotacoes Certificacao SCJP 5
Resumo Anotacoes Certificacao SCJP 5
 
FFPOJO Framework Overview
FFPOJO Framework OverviewFFPOJO Framework Overview
FFPOJO Framework Overview
 

JavaEE EJB JPA JMS no JBoss

  • 1. 1 Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss Autor: Gilberto Augusto T. de A. Holms gibaholms85@gmail.com http://gibaholms.wordpress.com/ Última revisão: 03/08/2009
  • 2. 2 Sumário 1. Ferramentas Utilizadas .........................................................................................4 1.1. Java JDK.......................................................................................................4 1.2. Eclipse IDE....................................................................................................4 1.3. JBoss Application Server...............................................................................5 1.4. MySQL ..........................................................................................................7 2. Computação Distribuída........................................................................................7 2.1. Por que utilizar sistemas distribuídos ? .........................................................7 2.2. O que são sistemas distribuídos ?.................................................................8 2.3. Rede IP e Sockets.........................................................................................8 2.4. CORBA .......................................................................................................10 2.4.1. Arquitetura CORBA .............................................................................10 2.5. RMI .............................................................................................................14 2.6. Modelo de Programação Distribuída ...........................................................15 2.7. Visão Geral .................................................................................................16 3. Serviço de Nomes JNDI......................................................................................16 3.1. O que é JNDI ?............................................................................................16 3.2. Serviços de Nomes .....................................................................................16 3.3. Serviços de Diretório ...................................................................................17 3.4. Principais conceitos de JNDI.......................................................................18 4. Introdução à Plataforma JEE ..............................................................................20 4.1. O que é J2EE ou JEE ?...............................................................................20 4.2. Modelo de Programação JEE......................................................................20 4.3. O Servidor de Aplicação..............................................................................21 4.4. O Container EJB .........................................................................................22 4.5. Definição de Enterprise JavaBeans.............................................................23 5. Introdução ao JBoss Application Server..............................................................23 5.1. Instalação....................................................................................................24 5.2. Estrutura de Diretórios JBoss 5.x ................................................................25 5.3. Server Configurations..................................................................................25 5.3.1. Estrutura de Diretórios do Server Configuration...................................26 5.4. Configurando um Servidor JBoss no Eclipse...............................................26 6. Enterprise JavaBeans 3.0 ...................................................................................28 6.1. Session Beans ............................................................................................29 6.1.1. Identificando os Beans ........................................................................29 6.1.2. Interfaces de Negócio..........................................................................29 6.1.3. Session Beans – Stateless ..................................................................30 6.1.4. Session Beans – Statefull....................................................................31 6.1.5. Ciclo de Vida dos Session beans.........................................................32 6.2. Distribuindo EJBs........................................................................................36 6.3. EJB Timer Service.......................................................................................37 7. Java Persistence API (JPA) ................................................................................39 7.1. Entity Manager ............................................................................................40 7.2. Ciclo de Vida ...............................................................................................41 7.3. Contexto de Persistência.............................................................................43 7.4. Configurando uma Aplicação JPA ...............................................................45 7.5. Mapeando Relacionamentos.......................................................................46 7.5.1. Um-Para-Um Unidirecional..................................................................46 7.5.2. Um-Para-Um Bidirecional ....................................................................46 7.5.3. Um-para-Muitos Unidirecional..............................................................46 7.5.4. Muitos-Para-Um Unidirecional .............................................................47 7.5.5. Um-Para-Muitos / Muitos-Para-Um Bidirecional...................................47 7.5.6. Muitos-Para-Muitos Unidirecional ........................................................47 7.5.7. Muitos-Para-Muitos Bidirecional ..........................................................47
  • 3. 3 7.6. Cascade Type .............................................................................................47 7.7. Lazy Loading...............................................................................................48 7.8. CRUD com JPA...........................................................................................49 7.9. Data Sources no JBoss...............................................................................49 8. Principais Design Patterns JEE...........................................................................51 8.1. Singleton .....................................................................................................51 8.2. Service Locator ...........................................................................................52 8.3. Business Delegate ......................................................................................53 8.4. Session Facade...........................................................................................54 8.5. Data Transfer Object (DTO) ........................................................................56 9. JMS e Message Driven Beans ............................................................................56 9.1. O que é Mensageria ?.................................................................................56 9.2. MOM – Message Oriented Middleware........................................................57 9.3. JMS.............................................................................................................58 9.4. Modelos de Mensagens ..............................................................................59 9.4.1. Topic (Tópico)......................................................................................59 9.4.2. Queue (Fila).........................................................................................59 9.5. Implementando Topics e Queues no JBoss ................................................59 9.6. Entendendo a JMS API ...............................................................................61 9.7. Publicando e Consumindo Mensagens JMS ...............................................62 9.7.1. Mensagens Tópico – Topic..................................................................62 9.7.2. Mensagens Fila – Queue.....................................................................63 9.8. JMS e EJB ..................................................................................................64 9.8.1. EJB – Publicando Mensagens .............................................................64 9.8.2. EJB – Message Driven Beans .............................................................65 10. Controle Transacional na Plataforma JEE...........................................................66 10.1. O que são Transações ? .............................................................................67 10.2. Níveis de Isolamento de Transações...........................................................68 10.3. Transações e EJB 3.0 .................................................................................70 10.3.1. Transações CMT .................................................................................70 10.3.2. Transações e Message Driven Beans .................................................73 10.3.3. Revertendo Transações.......................................................................74 10.3.4. Transações BMT .................................................................................74 11. Referências Bibliográficas...................................................................................75
  • 4. 4 1. Ferramentas Utilizadas 1.1. Java JDK Para desenvolver aplicações Java Enterprise Edition, não precisamos de nenhum ferramental especial. É necessário apenas algum JDK (Java Development Kit) e um Servidor de Aplicação (Application Server) compatível com o JDK. No momento em que foi criada esta apostila, a versão mais recente é a JDK 6 Update 13, disponível no link: http://java.sun.com/javase/downloads/index.jsp Note que a Sun também disponibiliza para download um pacote chamado JDK 6 Update 13 with Java EE. Este pacote é apenas um facilitador para iniciantes, pois já vem com um servidor de aplicação, o GlassFish Enterprise Server, e também alguns exemplos de mini-aplicativos JEE e tutoriais. O GlassFish é um Application Server completo, disponibilizado pela Sun como open-source. O GlassFish é um ótimo servidor de aplicação, porém não tem muita força no mercado. Atualmente, dentro do nicho dos servidores de aplicação open-source, o JBoss destaca-se como o mais robusto e utilizado pela comunidade, portanto, é ele que utilizaremos neste curso. 1.2. Eclipse IDE Como ferramenta de desenvolvimento, utilizaremos o Eclipse IDE. Trata-se de um ambiente de desenvolvimento integrado open-source, o mais conhecido e utilizado pela comunidade Java.
  • 5. 5 No momento em que foi criada esta apostila, a versão mais recente é o Eclipse Ganymede SR1 – versão 3.4, disponível no link: http://www.eclipse.org/home/categories/index.php?category=enterprise O Eclipse IDE é disponibilizado para download em várias distribuições diferentes. Para este curso utilizaremos a distribuição Eclipse IDE for Java EE Developers, pois ela já incorpora diversos plugins direcionados ao desenvolvimento JEE, inclusive o WTP (Web Tools Platform). 1.3. JBoss Application Server Como servidor de aplicação e web container, utilizaremos o JBoss Application Server. Ele é um servidor de código aberto, atualmente mantido pela empresa Hed Hat e usado em produção em muitas empresas. No momento em que foi criada esta apostila, a versão mais recente é o JBoss Application Server 5.0.1.GA, disponível no link: http://www.jboss.org/jbossas/downloads/
  • 6. 6 Note que dentro de uma mesma versão são disponibilidadas para download diversas distribuições do JBoss, em diversos formatos, ou com JDK6 incluso. Para o curso nós utilizaremos a versão “pura”, disponível no formato zip, sem nenhum adicional.
  • 7. 7 1.4. MySQL Para os exercícios e projetos do curso, utilizaremos a base de dados MySQL (agora pertencente à Sun Microsystems). Atualmente, ela é disponibilizada em duas versões: Enterprise e Community. No momento em que foi criada esta apostila, a versão mais recente é o MySQL Community Server 5.1, disponível no link: Optamos pela versão Community, pois ela é open-source. 2. Computação Distribuída 2.1. Por que utilizar sistemas distribuídos ? o Dados são distribuídos o Processamento é distribuído o Usuários são distribuídos Dados são distribuídos Os dados que uma aplicação precisa acessar podem existir em muitos computadores, por motivos administrativos, de segurança, de infra-estrutura ou até mesmo geográficos. O responsável pelos dados ou processos pode permitir acesso apenas remoto, mas não permitir que esses dados sejam armazenados localmente por um cliente.
  • 8. 8 Processamento é distribuído Uma aplicação pode executar de forma distribuída para ter vantagem de utilizar múltiplos processadores, em diferentes máquinas ou servidores, ou até mesmo tirar proveito de recursos específicos de uma determinada máquina ou sistema operacional. Com isso, são garantidas escalabilidade e alta disponibilidade do sistema. Usuários são distribuídos Uma aplicação pode executar de forma distribuída, pois os usuários da aplicação podem interagir entre si, compartilhando processos, cada usuário sendo responsável por executar um pedaço do aplicativo, em diferentes sistemas, para a realização de um fim comum. 2.2. O que são sistemas distribuídos ? Segundo a definição de Tanembaum, um sistema distribuído é: “Uma coleção de computadores independentes que se apresenta ao usuário como um sistema único e consistente.” Ou seja, um sistema distribuído é capaz de ter seu processamento compartilhado em diversas máquinas distintas, interligadas entre uma rede, que se comunicam entre si através de algum protocolo, independente do sistema operacional em que residem. Tudo isso transparente ao usuário, que tem a impressão de estar acessando um único sistema. Cada pedaço da aplicação pode estar presente em uma máquina, e estes pedaços podem ser reutilizados e orquestrados de forma a compor uma aplicação. 2.3. Rede IP e Sockets Historicamente, a primeira abordagem existente para o desenvolvimento de aplicações distribuídas foi através do uso de sockets, que é a forma mais “nativa” possível de transferir dados através de uma rede de computadores. Arquitetura geral de uma rede de computadores baseada em IP: Vamos examinar rapidamente os componentes dessa arquitetura:
  • 9. 9 o Camada Física É a camada que efetivamente transfere os bits, onde podemos pensar em placas de rede, roteadores e elementos transmissores. o Enlace de Dados É a camada que tem diversas características de gerência e controle sobre os dados trafegados, que realiza multiplexações, detecção, notificação e recuperação de erros. o Protocolo IP A sigla IP significa “Internet Protocol”, por ser o protocolo no qual é baseada a rede mundial de computadores (Internet). Nada mais é que um protocolo, único e padronizado mundialmente, que permite que dados sejam transferidos pela rede através de pacotes de dados com uma estrutura bem definida, com informações de roteamento, endereçamento, headers e outras informações. o TCP / UDP Aqui começamos a nos atentar. Existem duas maneiras (protocolos) de se transferir dados em uma rede IP, e cada uma tem suas características e utilização apropriada: Protocolo UDP • Não orientado à conexão • Não confiável • Não garante entrega ao destinatário • Utilizado para comunicação em tempo real (VoIP, Vídeo, etc) Protocolo TCP • Orientado à conexão • Confiável • Garante entrega ao destinatário o Camada de Aplicação É onde residem os aplicativos. Nesta camada temos os protocolos de software. Diversos aplicativos conhecidos utilizam serviços de rede. Entre eles, podemos citar: browsers web (protocolo HTTP), gerenciadores de email (protocolos SMTP e POP3). Dando um zoom na nossa Camada de Aplicação, visualizamos um componente de software vital para a comunicação em rede: Os SOCKETS ! Sockets são um conjunto de funções (API) do sistema operacional que permitem que os softwares utilizem um canal de comunicação sobre IP. E, logicamente, cada linguagem de programação fornece o seu conjunto de APIs para manipulação dos sockets do sistema operacional.
  • 10. 10 2.4. CORBA Como pudemos observar nos exercícios apresentados em sala de aula, disponibilizar objetos distribuídos nativamente através de sockets não é uma tarefa simples. Em muitas linhas de código, onde não há transparência de localização, o cliente precisa conhecer o servidor. Além de que implementar infra de segurança, alta disponibilidade e pool de recursos demandaria muito esforço de desenvolvimento. Vimos também que é muito difícil obter interoperabilidade, pois não há um padrão definido de protocolo de comunicação, cada desenvolvedor de sistema poderia implementar de sua maneira. Também não há transparência de linguagem de programação, ou seja, um objeto distribuído Java seria acessado apenas por clientes Java, pois são utilizados os recursos de serialização de objetos da própria linguagem para trafegá-los pela rede. CORBA, ou “Common Object Request Broker Architecture”, é uma especificação de arquitetura para criação de sistemas distribuídos orientados a objeto padronizados, independente de plataforma ou linguagem de programação. O Object Management Group (OMG) é responsável pela definição da arquitetura CORBA. A OMG é um órgão formado por mais de 700 empresas fornecedoras de tecnologia, responsável por definir e manter alguns dos principais padrões de mercado, como por exemplo o UML. A arquitetura CORBA define o paradigma de “Objetos Distribuídos”, que permite que um objeto (C++, Delphi, Java, etc) em uma máquina possa interagir com um objeto de outra máquina. 2.4.1. Arquitetura CORBA IDL É a definição da interface ou contrato das operações que o objeto distribuído expõe aos clientes. Ela é criada em uma linguagem específica definida e mantida pela OMG. Exemplo de IDL: module LocadoraObjects { struct InformacoesFilme { string nome; string genero; double preco; };
  • 11. 11 exception LocadoraException{}; interface Filme { InformacoesFilme getInformacoesFilme() raises(LocadoraException); void setInformacoesFilme(in InformacoesFilme info); }; }; A partir da IDL, diversos fabricantes desenvolvem compiladores para gerar o código em uma linguagem específica, como Java ou C++. A plataforma Java fornece no JDK um compilador IDL para a geração de Skeletons e Stubs CORBA. É o aplicativo idlj.exe, localizado na pasta “bin” do JDK. Exemplo: idlj –server –client teste.idl ORB Camada provedora de serviços (API) para implementação da arquitetura CORBA. Ela é a intermediadora entre o objeto cliente e o objeto distribuído. Quando um objeto cliente faz uma requisição a um objeto distribuído, ela localiza o objeto na rede, envia a requisição ao objeto distribuído (através do protocolo IIOP), aguarda a resposta e a repassa ao objeto chamador. Um dos serviços importantes providos pela camada ORB é o serviço de nomes (Naming Service), que permite transparência de localização dos objetos distribuídos. Skeletons São os objetos gerados automaticamente pelo compilador IDL para servirem requisições no lado do servidor. Eles são responsáveis pelo marshalling e unmarshalling dos objetos para que o ORB possa enviá-los pela rede. Desta forma, o desenvolvedor preocupa-se apenas em implementar suas operações de negócio, sem se preocupar com serviços de infra estrutura. Stubs São os objetos gerados automaticamente pelo compilador IDL para enviarem requisições por parte do cliente. Eles são responsáveis pelo marshalling e unmarshalling dos objetos para que o ORB possa enviá-los pela rede. Da mesma forma, o desenvolvedor não precisa se preocupar com serviços de infra estrutura para acessar os objetos distribuídos. IIOP
  • 12. 12 O “Internet Inter Orb Protocol” é o protocolo de comunicação da arquitetura CORBA. É um protocolo de rede (TCP/IP) que, através de uma estrutura de bytes pré-definida, transporta as requisições e respostas através da rede. Arquivo IDL Cliente Código Cliente Stubs Servidor Skeletons Implementação do Objeto Compilador idl2Java Rede TCP/IP - Protocolo IIOP ORB ORB POA O “Portable Object Adapter” (POA) é um artefato evolutivo na arquitetura CORBA. Ele fica entre a implementação do ORB e o objeto distribuído. Desta forma, com o POA pode-se fazer com que os ORBs de diversos fabricantes rodem objetos distribuídos da mesma forma, sem nenhuma mudança no código dos objetos. Além disso, o POA fornece alguns serviços de controle de ciclo-de-vida, segurança, multithreading e transiência/persistência. COS Naming Service O CORBA COS(Common Object Services) Naming Service é uma especificação. Sua implementação deve fornecer um sistema de armazenamento de nomes em formado de “árvore”, pronto para armazenar referências de objetos CORBA. Sua estrutura é muito semelhante a um LDAP: • Binding
  • 13. 13 É uma associação nome-objeto, onde uma referência a um objeto é gravada associada a um nome, que funciona como uma chave em uma estrutura de Map. Um binding é criado sempre em relação a um Naming Context; não existe um nome de binding absoluto. • Naming Context Um conjunto único de bindings (nomes), onde não pode haver bindings com nomes repetidos. O Naming Context é um objeto, portanto, também pode ser “bindado” ao Naming Service, criando assim uma hierarquia de naming contexts (Naming Graph). • Naming Graph É quando criamos Naming Context dentro de outro Naming Context, criando assim uma árvore de contextos. No diretório “bin” do JDK são fornecidas duas implementações de COS Naming Service: ORBD e TNAMESERV. • ORDB (Object Request Broker Daemon) É uma implementação de COS Naming Service disponibilizada de duas maneiras: “Transient Naming Service” e “Persistent Naming Service”. o Persistent Naming Service – indica que os registros são gravados de forma persistente (em disco ou base de dados), permitindo que os bindings sobrevivam a restarts e quedas do sistema. Orb.resolve_initial_references("NameService") o Transient Naming Service – indica que os registros são gravado em memória, ou seja, são perdidos quando o servidor finaliza. //o nome TNameService é proprietario do ORBD, //o padrão do CORBA é sem o T Orb.resolve_initial_references("TNameService") Ferramenta SERVERTOOL – também disponível no diretório “bin” do JDK. É um aplicativo utilitário para monitorar o ORBD, permitindo visualizar os servidores ativos, localizar ORBs, entre outras funções. • TNAMESERV (Transient Naming Service) Como o próprio nome indica, é uma implementação de COS Naming Service, porém disponível apenas na forma transiente. Orb.resolve_initial_references("NameService") O COS Naming Service é disponibilizado através de um objeto distribuído no ORB, que também foi gerado a partir de um IDL, portanto é preciso obter sua referência e fazer o narrow a partir da classe helper. Object ctxRef = orb.resolve_initial_references("NameService"); NamingContextExt ctx = NamingContextExtHelper.narrow(ctxRef); Nomeando Referências à Objetos: • Interoperable Object References (IOR) É uma referência a um objeto em forma de string, em um formato conhecido pelo ORB.
  • 14. 14 Orb.object_to_string(objRef) • Interoperable Naming Service (INS) É uma referência a um objeto em forma “Human-Readable”, em forma de strings, URLs, “corbaloc” ou “corbaname”. corbaloc:iiop:1.2@localhost:1050/Locadora 2.5. RMI O RMI (“Remote Method Invocation”) é uma API criada como uma iniciativa para que desenvolvedores pudessem escrever sistemas distribuídos com a mesma semântica de sistemas comuns, com o intuito de agilizar e facilitar o desenvolvimento. A princípio, ela foi criada para suprir as necessidades do desenvolvimento de sistemas distribuídos baseados em Java, ou seja, server Java e client Java, através do protoclo JRMP. Porém, logo depois foi evoluída para suportar também o protocolo IIOP, visando a interoperabilidade de sistemas. Existem dois tipos de implementação RMI: - Baseada em JRMP (“Java Remote Method Protocol”) - Baseada em IIOP (“Internet Inter Orb Protocol”) JRMP É um protocolo nativo e específico para linguagem Java, ou seja, objetos distribuídos via RMI-JRMP podem ser consumidos apenas por clientes Java (JVM to JVM). • RMIREGISTRY (RMI Registry) Disponível na pasta “bin” do JDK, é o Naming Service do RMI, que funciona analogamente ao COS Naming Service do CORBA, porém específico para bindar e localizar objetos RMI. • RMIC (RMI Compiler) É um aplicativo localizado na pasta “bin” do JDK utilizado para gerar os Skeletons e Stubs de objetos remotos RMI. A geração explícita de Skeletons e Stubs é necessária apenas nas versões 1.4 e anteriores do JDK, pois nas versões mais recentes esta geração é feita e disponibilizada à JVM automaticamente pelo RMIRegistry. Exemplo: rmic br.curso.LocadoraImpl IIOP Como já estudamos no tópico sobre CORBA, o IIOP é o protocolo de comunicação da arquitetura CORBA. Objetos distribuídos sobre RMI-IIOP possuem a vantagem de executar sobre um ORB, assim sendo independentes de linguagem de programação. Com o intuito de trazer para o Java a facilidade de programação do RMI fundida à interoperabilidade do CORBA, a Sun, em conjunto com a IBM, criaram o RMI sobre IIOP. Além de prover interoperabilidade com sistemas CORBA, o protocolo RMI-IIOP foi idealizado para garantir também interoperabilidade com o RMI-JRMP, para que os sistemas mais antigos construídos nesse protocolo pudessem interagir com o novo protocolo sem necessidade de mudança de código.
  • 15. 15 Para atender esses requisitos, compilador RMIC foi modificado, adicionando a opção de geração de Skeletons e Stubs para protocolo IIOP. Exemplo: rmic –iiop br.curso.LocadoraImpl Conceito de “codebase” Para qualquer chamada remota, vimos que é necessário ter no classpath do cliente o Stub, tal Stub que referencia a classe de implementação do objeto distribuído. Porém, nem sempre é desejável ter este Stub localmente, pois a qualquer mudança na implementação do objeto remoto, teríamos que recompilar todos os clientes com o novo Stub que seria gerado. Para evitar esse problema, ao rodar o nosso servidor java podemos setar um atributo de JVM chamado “codebase”, indicando um local para a JVM do cliente localizar os Stubs automaticamente em tempo de execução. Quando bindamos um objeto remoto no RMI Registry, este local é gravado e enviado aos aplicativos que fizerem lookup do objeto. Exemplos: java -Djava.rmi.server.codebase=http://server/public/stubs.jar java -Djava.rmi.server.codebase=http://server/stubs/ A ordem em que o cliente procura as classes Stub é primeiro em seu classpath e, se não achar, procura no codebase do Servidor. Obs.: este conceito é válido apenas para RMI-JRMP. Não faz sentido um cliente IIOP fazer download automático de Stubs, pois um cliente IIOP pode ser escrito em qualquer linguagem de programação, e cada linguagem terá o seu Stub específico. 2.6. Modelo de Programação Distribuída Quando trabalhamos com Java puro localmente sabemos que, ao invocarmos um método local, tipos primitivos são passados como cópia e, para os objetos, é passada uma cópia da referência. Quando trabalhamos com objetos distribuídos, não há como trafegar referências de objetos na rede, mesmo porquê o sistema do outro lado pode não necessariamente ser Java.
  • 16. 16 Na chamada de métodos remotos sempre trabalhamos com cópias serializadas (sequência de bytes) dos objetos, tanto os passados como argumento quanto os retornados de métodos. Portanto, todos os objetos que irão trafegar na rede (parâmetros e retornos de métodos) devem ser declarados como serializáveis. Na linguagem Java um objeto é declarado como serializável quando ele implementa a interface java.io.Serializable: public class Filme implements Serializable { } 2.7. Visão Geral CLIENT SERVER CORBA RMI – JRMP RMI – IIOP CORBA X X RMI – JRMP X X RMI – IIOP X X X 3. Serviço de Nomes JNDI 3.1. O que é JNDI ? A sigla JNDI significa Java Naming and Directory Interface. O JNDI é uma API da plataforma Java SE que permite ao desenvolvedor manipular serviços de nomes e diretórios. 3.2. Serviços de Nomes A principal função de um serviço de nomes (ou Naming Service) é permitir a associação de um nome a recursos computacionais, como: o Endereços de memória o Objetos o Referências a objetos o Arquivos o Códigos em geral Exemplos de serviços de nomes: o File System – liga um caminho a um bloco de memória física o Sistema DNS – liga um domínio a um endereço IP o Sistema LDAP – liga um nome a um usuário ou grupo de usuários o CORBA COS Naming Service – liga um nome lógico a uma referência de objeto remoto CORBA
  • 17. 17 o RMI Registry – liga um nome lógico a uma referência de objeto remoto RMI-JRMP 3.3. Serviços de Diretório A principal função de um serviço de diretório (ou Directory Service) é permitir o agrupamento de recursos computacionais de acordo com contextos ou hierarquias. O serviço de diretório complementa o serviço de nomes, pois este agrupamento pode ser feito logicamente a partir dos nomes. O serviço de diretório permite também trabalhar com atributos, para guardar informações importantes sobre os objetos. Exemplos de serviços de diretórios: o File System – uma pasta é um agrupamento de arquivos, e arquivos têm atributos o Sistema DNS – um domínio é um agrupamento de sub-domínios ou sites o Sistema LDAP – um grupo é um agrupamento de usuários, e ambos podem ter atributos (nome, endereço, senha) o CORBA COS Naming Service e RMI Registry – um contexto de nomes é um agrupamento de objetos remotos relacionados De maneira macro percebemos que todos os exemplos de serviços de nomes e diretório listados possuem muito em comum. • Geralmente um serviço de nomes caminha acompanhado de um serviço de diretórios (mas não é obrigatório). • Como dito na própria definição do JNDI, todos eles associam nomes a recursos computacionais. • Eles podem guardar atributos para descrever estes recursos (mas não é obrigatório). • Todos eles também se organizam em forma de árvore, hierarquizada, ou seja, um nome pode ser um contexto para agrupar outros nomes.
  • 18. 18 Devido a este comportamento comum, a Sun teve a brilhante idéia de desenvolver uma API genérica, desacoplada, capaz de gerenciar qualquer serviço de nomes que seguisse esta mesma lógica. Lógico que cada serviço de nomes tem seu protocolo específico e sua particularidade de implementação, porém a JNDI fornece uma interface comum para essas implementações. O JNDI está para os “serviços de nomes e diretórios” assim como o JDBC está para as “bases de dados”. Com o JNDI, no que tange aos serviços de nomes e diretórios, temos os mesmos benefícios que o JDBC fornece no que tange as bases de dados, onde a principal delas é a independência de implementação. 3.4. Principais conceitos de JNDI Service Provider É a implementação (provedor do serviço) que o JNDI irá utilizar. Cada serviço de nomes e diretórios específico possui a sua classe de implementação, conhecida como “Service Provider”, e sua “factory”, responsável por criar a instância e atribuí-la à interface do JNDI. Ela deve estar no classpath da aplicação e sua factory deve ser definida no properties através da seguinte constante: Context.INITIAL_CONTEXT_FACTORY Initial Context É o contexto inicial do serviço de nomes e diretórios. É a “raíz” do sistema, o “root”, o “ponto de partida” para a navegação entre os nós da árvore de nomes. A nível de código, ele é representado como uma classe em que seu construtor recebe um java.util.Properties como parâmetro. É através dele que configuramos a implementação que desejamos utilizar. Exemplo: Properties prop = new Properties(); prop.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); prop.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099"); InitialContext ctx = new InitialContext(prop); Exemplos de implementações (service providers):
  • 19. 19 LDAP: Properties prop = new Properties(); prop.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); prop.put(Context.PROVIDER_URL, "ldap://localhost:389"); *incluso no JDK COS Naming Service: Properties prop = new Properties(); prop.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory"); prop.put(Context.PROVIDER_URL, "iiop://localhost:1050"); *incluso no JDK RMI Registry: Properties prop = new Properties(); prop.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.rmi.registry.RegistryContextFactory"); prop.put(Context.PROVIDER_URL, "rmi://localhost:1099"); *incluso no JDK DNS: Properties prop = new Properties(); prop.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); prop.put(Context.PROVIDER_URL, "dns://server1.sun.com/java.sun.com"); prop.put(Context.AUTHORITATIVE, "true"); *incluso no JDK File System: Properties prop = new Properties(); Prop.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.fscontext.RefFSContextFactory"); *não incluso no JDK Download de outros Service Providers (dns, novell, registro do windows, etc): http://java.sun.com/products/jndi/serviceproviders.html Obs.: para SPIs que requerem usuário e senha, utilizamos os seguintes parâmetros: prop.put(Context.SECURITY_PRINCIPAL, "usuario"); prop.put(Context.SECURITY_CREDENTIALS, "xxxxxxx"); Context É qualquer contexto do serviço de nomes e diretórios. Como ilustrado no capítulo sobre COS Naming Service, um contexto pode conter sub-contextos. A característica principal de um contexto é que ele não pode possuir nomes repetidos para associações de recursos. E isso faz todo o sentido, pois um recurso deve ser identificado de forma única. Logicamente uma mesma pasta não pode conter dois arquivos com o mesmo nome, ou um domínio não pode conter dois sub-domínios diretos com o mesmo nome. Toda e qualquer operação de manuseio de registros de nomes é feita de forma relativa a um contexto. Bind Operação de gravar uma associação nome-objeto em um contexto. Se o nome já existir, é lançada uma javax.naming.NamingException. Rebind Operação de regravar uma associação nome-objeto em um contexto. A diferença para o Bind é que, se o nome já existir, ele é sobrescrito. Unbind Operação de remover uma associação nome-objeto de um contexto.
  • 20. 20 Lookup Operação de localizar uma associação nome-objeto em um contexto. Lembrando que será feito sempre relativo a um contexto, pois em JNDI não existem “nomes absolutos”. ListBindins Operação de listar todas as associações nome-objeto de um contexto. 4. Introdução à Plataforma JEE 4.1. O que é J2EE ou JEE ? O termo JEE significa Java Enterprise Edition. Como o próprio nome já diz através do termo “Enterprise”, o JEE é uma plataforma baseada em Java, desenvolvida para o desenvolvimento de sistemas corporativos. Na literatura atual podemos encontrar os termos J2EE ou JEE. Os duas nomenclaturas referem-se à plataforma Java Enterprise Edition, onde a letra “2” fazia menção à versão 2 do Java, referente ao JDK 1.4. Nas versões mais recentes da plataforma, a letra “2” foi removida, falando-se apenas em JEE ou Java Enterprise Edition. O JEE não é um software nem nenhuma ferramenta especial. O JEE é um conjunto de especificações desenvolvidas para atender as necessidades vitais de sistemas corporativos, visando a componentização e a facilidade na implementação desses sistemas. A partir desse conjunto de especificações, cada fabricante implementa as funcionalidades especificadas da forma desejada, como for mais viável e menos custoso. Isto torna a tecnologia JEE independente de fornecedor e de plataforma, pois a especificação garante que um sistema desenvolvido seguindo a especificação terá o mesmo comportamento em qualquer plataforma de qualquer fabricante (na prática não é “tão maravilhoso assim”, mas através de algumas técnicas e boas práticas conseguimos minimizar o impacto da dependência do fabricante). Todas estas especificações são abertas, mantidas pela Sun e pelo Java Community Process (JCP). O JCP é uma comunidade composta pelos principais fabricantes de tecnologia em plataforma Java, que definem as especificações (JSRs) para as principais tecnologias java. Dentre este plantel de fabricantes encontram-se IBM, Oracle, HP, Lucent, Hed Hat e todos os demais “barões” da tecnologia atual. Todas as JSRs e suas revisões são disponibilizadas para download no site do Java Community Process. As JSRs são documentos fabulosos para se ter como documentação das principais APIs do JEE: http://www.jcp.org/ 4.2. Modelo de Programação JEE Toda aplicação corporativa de missão crítica possui requisitos em comum, como comunicação remota, componentes no lado do servidor com tecnologias de objetos
  • 21. 21 distribuídos, sistemas de mensageria assíncrona, segurança centralizada, escalabilidade, pool de recursos, controle transacional, entre diversos outros requisitos. Desenvolver um sistema distribuído não é simples: • O que acontecerá com a performance quando aumentar o volume de acessos ? • Quais são os custos para se aplicar a capacidade de processamento ? • Qual a integridade dos dados e das transações se alguma chamada falhar ? • Quem garante a segurança e o controle de acesso ? • E se o sistema remoto sair do ar ? O modelo de programação JEE é baseado no reuso de componentes focando a minimização do tempo de desenvolvimento de um sistema corporativo de larga escala. Com o JEE o desenvolvedor não precisa se preocupar com particularidades de infra-estrutura, como segurança, comunicação TCP-IP, pool de recursos ou transações. O “Container JEE” fornece essas funcionalidades de forma segura e confiável, permitindo assim que o desenvolvedor se concentre apenas na lógica de negócio. 4.3. O Servidor de Aplicação O Servidor de Aplicação (Application Server) é o componente macro da especificação JEE, encarregado por implementar todos os serviços básicos de infra-estrutura, seguindo a especificação JEE. Ele é subdividido conceitualmente em duas partes, ou “containers”: • Container Web
  • 22. 22 Responsável por disponibilizar e gerenciar os componentes de infra-estrutura referentes a camada web (“Web Tier”), como as especificações Servlet e JSP. • Container EJB Responsável por disponibilizar e gerenciar os componentes de infra-estrutura da camada de negócio (“Business Tier”), como as especificações EJB e JPA. No mercado, atualmente, existem servidores de aplicações que disponibilizam somente o Container Web (ex.: Tomcat e Jetty) e existem, também, os chamados servidores de aplicação completos, que disponibilizam tanto o Container Web quanto o Container EJB (ex.: JBoss, Sun GlassFish, IBM WebSphere, Oracle/BEA WebLogic). 4.4. O Container EJB Um Container JEE precisa fornecer os seis serviços básicos: o Concorrência o Transação o Persistência o Distribuição de Objetos o Atribuição de Nomes (JNDI) o Segurança Serviços secundários: o Mensageria Assíncrona o Temporização Para um Container EJB ser completamente compatível com a especificação EJB 3.0, ele precisa implementar as seguintes APIs: o EJB 3.0 o JTA 1.1 o JPA 2.0 o JMS 1.1 o JavaMail 1.4 (apenas envio de email) o JAF 1.1 o JAXP 1.2 o JAXR 1.0 o JAX-RPC 1.1 o JAX-WS 2.0 o JAXB 2.0 o SAAJ 1.3 o JAAS o Connector 1.5
  • 23. 23 o Web Services 1.2 o Web Services Metadata 2.0 o Common Annotations 1.0 o StAX 1.0 APIs fornecidas pelo próprio runtime JSE sob o container: o JDBC o RMI-IIOP o JNDI 4.5. Definição de Enterprise JavaBeans Os Enterprise JavaBeans (EJBs) são componentes Java criados seguindo a especificação JEE, que são gerenciados pelo servidor de aplicação. Os EJBs representam a lógica de negócio do sistema (“aluguel de filmes”, “agente de viagens”, “autenticador”, etc). Com a junção dos EJBs e o Container, nos preocupamos em desenvolver apenas a lógica do negócio, e o Container cuida do ciclo-de-vida dos beans, gerenciamento de pool, segurança, controle de transações e todos os demais serviços básicos. Definição da Sun para a Arquitetura EJB: “A arquitetura Enterprise JavaBeans é uma arquitetura de componentes para o desenvolvimento e a implantação de aplicativos de negócio distribuídos baseados em componentes. Aplicativos escritos utilizando a arquitetura Enterprise JavaBeans são escalonáveis, transacionais e seguros com multi- usuários. Esses aplicativos podem ser escritos uma vez e então implantados em qualquer plataforma de servidor que suporta a especificação Enterprise JavaBeans.” Atenção: “Enterprise JavaBeans” não são simples “JavaBeans”. O termo “JavaBeans” propriamente dito refere-se a classes Java que seguem o padrão de nomenclatura JavaBeans (classe encapsulada com “getters” e “setters” padronizados, ex. getAtributo e setAtributo). Quando falamos “Enterprise JavaBeans”, esses sim são os EJBs, os objetos de negócio distribuídos gerenciados pelo container. Objetos Remotos vs. Objetos Distribuídos Os Enterprise JavaBeans não representam objetos remotos (não implementam java.rmi.Remote), e sim objetos distribuídos. Eles podem ser “distribuídos” de diversas formas (localmente, remotamente, via CORBA, via WebServices), porém quem faz o trabalho de distribuir os objetos é o container. O container que implementa um Skeleton RMI ou uma interface de WebService intercepta a requisição e a “delega” ao EJB. 5. Introdução ao JBoss Application Server O JBoss Application Server é um servidor de aplicação JEE completo, atualmente mantido pela empresa Red Hat. Ele é disponibilizado em duas versões: Community e Enterprise. A versão Community é totalmente open-source, destinada primeiramente a desenvolvedores, mas pode ser utilizada para qualquer fim:
  • 24. 24 http://www.jboss.org/ Já a versão Enterprise é disponibilizada para fins comerciais, mantendo a metodologia da Red Hat de não cobrar pelo produto, mas sim pelo suporte. Ela vem nomeada de Application Platform, geralmente contendo pacotes adicionais como IDE de Desenvolvimento com plugins proprietários para agilizar o desenvolvimento e outras ferramentas e frameworks. http://www.jboss.com/ 5.1. Instalação Após o download do pacote zip contendo o JBoss Application Server, como indicado no capítulo 1.3 da apostila, podemos começar o procedimento de instalação. Por ser baseado em java e assim portável, ele não possui instalador específico para um sistema operacional. O JBoss é o conteúdo do arquivo zip. Passos para instalação: o Extrair o conteúdo do arquivo zip para um diretório qualquer. Para evitar inconvenientes e incompatibilidades sobre formatos de nomes de diferentes sistemas operacionais, devemos evitar um caminho muito comprido e devemos evitar também o caractere “espaço” no caminho da pasta do JBoss. o Agora devemos apenas setar a variável de ambiente JBOSS_HOME indicando o caminho onde o JBoss foi instalado, para que os aplicativos que precisarem poderem localizar seu classpath “Meu Computador” > “Propriedades” “Avançado” > “Variáveis de Ambiente”
  • 25. 25 “Variáveis do Sistema” > “Nova” Digitar a variável “JBOSS_HOME”, informando o diretório onde foi descompactado o JBoss Pronto. Tendo feito isso, o JBoss estará pronto para rodar. 5.2. Estrutura de Diretórios JBoss 5.x Para conhecermos um pouco melhor o nosso servidor de aplicação, vamos dar uma analisada geral em sua estrutura de diretórios: • bin – todos executáveis e scripts necessários para ligar e desligar o servidor • client – todos os JARs necessários para comunicar com o JBoss a partir de aplicações client standalone de várias naturezas • docs – documentações do fornecedor • lib e common – todos os JARs necessários para o rodar o core do servidor • server – todas as Server Configurations 5.3. Server Configurations Cada pasta dentro do diretório server representa um “Server Configuration”, que é uma instância do servidor. A distribuição do JBoss fornece cinco templates de configuration: all, default, minimal, standard e web. Cada template tem suas características e serviços configurados.
  • 26. 26 Atenção Nunca carregue diretamente os templates, pois eles não foram criados para ser usados. Eles servem como modelo para criarmos a nossa configuration personalizada. Para criar uma configuration, basta replicar o template (criar uma cópia da pasta) que desejarmos e modificar o nome da pasta. 5.3.1. Estrutura de Diretórios do Server Configuration Todos os templates possuem uma estrutura semelhante, vamos analisá-la: • conf – configurações gerais de funcionamento do servidor, são carregadas apenas uma vez quando o server inicia (qualquer mudança requer restart do server) • deploy – diretório onde se faz o deploy de aplicações (basta copiar nele o EAR ou o WAR e o deploy é feito automaticamente) • deployers – contém os serviços responsáveis por efetuar o deploy dos arquivos no servidor (existe um deployer para cada tipo de serviço – web, ejb3, etc) • lib – qualquer JAR presente nessa pasta será compartilhado e visível para todas as aplicações deployadas no servidor Além desses diretórios padrão, são gerados também em run-time mais quatro pastas: • data – utilizada para todos os serviços do JBoss que precisam guardar dados persistentes no disco (ex.: Naming Service) – Hypersonic SQL Database (HSQLDB) • log – onde são gerados os arquivos de log do servidor • tmp – qualquer tipo de dado temporário necessário pelos serviços do JBoss • work – utilizado pelo Web Container do JBoss (baseado em Tomcat), para guardar JSPs compiladas e outros arquivos temporários necessários para web 5.4. Configurando um Servidor JBoss no Eclipse “Window” > “Preferences” “Server” > “Runtime Environments” > “Add...”
  • 27. 27 Selecione “JBoss v5.0” e clique em “Next” Escolha o JRE desejado e localize a pasta onde reside o diretório raiz do JBoss Na aba “Servers”, clique com o botão direito do mouse e crie um novo server Selecione o run-time environment criado anteriormente marcando “JBoss v5.0” e clique em “Next”
  • 28. 28 Em “Server Configuration”, digite o nome da sua configuração personalizada e finalize Atenção: nunca utilize os templates (all, default, minimal, etc), crie sempre uma configuração personalizada e a utilize. 6. Enterprise JavaBeans 3.0 A especificação EJB 3.0 veio a partir do JDK 1.5, com o intuito de facilitar o desenvolvimento de EJBs substituindo os milhares de XMLs de configuração necessários na versão EJB 2.1 pelas Annotations (recurso adicionado a partir do JDK 1.5). Além dessa evolução, o modelo de programação ficou mais simplificado demandando menos código para implementar o mesmo beans, e houve a criação da JPA (Java Persistence API) para substituir os antigos Entity Beans da velha especificação (detalhes da especificação EJB 2.1 não são escopo deste curso). Obs.: os EJBs 3.0 possuem total interoperabilidade com os EJBs 2.1, ficando quase que transparente para o desenvolvedor caso precise integrá-los. O capítulo 4.5 introduziu os conceitos da arquitetura de componentes Enterprise JavaBeans. Vimos que é uma especificação que define um padrão de construção de componentes modularizados e reutilizáveis que rodam em um servidor de aplicação, mais especificamente em um container EJB, que lhes fornece serviços indispensáveis de infra-estrutura distribuída (escalonáveis, transacionais e seguros com multi- usuários). Tipos existentes de EJBs: • Session Beans o Stateless Session Beans o Statefull Session Beans • Message Driven Beans
  • 29. 29 Obs.: até a versão EJB 2.1 também haviam os “Entity Beans”, porém na versão 3.0 eles foram substituidos pela JPA, e com bons motivos (veremos com mais detalhes no capítulo sobre JPA). 6.1. Session Beans 6.1.1. Identificando os Beans Quando modelamos um aplicativo empresarial, nos deparamos com dois tipos de artefatos: entidades e processos. O termo “Entidade” se refere a artefatos com um estado bem definido, geralmente se apresentam em forma de substantivos ou nomes (ex.: “Filme”, “Usuário”, “Conta”). As entidades por si só são auto-suficientes, possuem uma representação lógica. Já o termo “Processo” refere-se a uma tarefa, uma regra de negócio, que não tem um estado bem definido. Geralmente os processos se apresentam em forma de verbos ou agentes (ex.: “AgenteDeViagens”), artefatos que não são auto-suficientes, muito pelo contrário, eles dependem das entidades e efetuam operações com as mesmas. Na arquitetura EJB, os Session Beans representam os processos, as tarefas, as regras de negócio. Podem possuir ou não um estado, porém quando possuem estado, este é um estado intermediário, transiente (em memória), que não faz sentido persistí- lo em uma base de dados. Quando pensamos em “sem estado”, podemos imaginar uma classe sem atributos, composta apenas de métodos. Na prática é exatamente isso. Por exemplo, um Session Bean de “Login” não possui estado, ele não precisa armazenar informações entre diferentes requisições, ele não precisa “lembrar do usuário atual”, ele apenas fornece a tarefa de efetuarLogin, e esta tarefa é auto-suficiente. Por outro lado, um Session Bean “CarrinhoDeCompras” precisa ter um estado, pois ele não representa uma tarefa atômica, ele precisa “lembrar do usuário atual” e armazenar seus itens de compra, até que finalmente o usuário decida efetuar a transação. 6.1.2. Interfaces de Negócio Construir EJBs é bem parecido com a construção de objetos remotos que vimos nos capítulos anteriores, pois o bean pode se “apresentar como um objeto remoto”. Primeiramente definimos a Interface de Negócio do bean, que representa o seu contrato, as operações que o bean irá expôr aos clientes. Interface Características javax.ejb.Local • É utilizada quando desejamos acessar o bean da mesma JVM • É a interface mais lightweight • É realizada uma chamada de método local, como uma classe normal • A passagem de parâmetros e retorno de objetos é feita por referência, como o padrão do java javax.ejb.Remote • É utilizada quando desejamos acessar o bean remotamente, via CORBA ou RMI • Realiza uma chamada de método remota, por CORBA, RMI-JRMP ou RMI-IIOP (configurável de acordo com o container utilizado)
  • 30. 30 • A passagem de parâmetros e retorno de objetos é feita por valor • Devido ao item anterior, os parâmetros e retornos que são objetos precisam ser serializáveis javax.ejb.MessageDriven • É utilizada quando queremos que o MOM acesse o bean via mensageria (mais detalhes no capítulo sobre JMS) javax.jws.WebService • É utilizada quando desejamos acessar o bean via WebService • Disponível apenas para beans Stateless (pois WebService não guarda estado) Cada bean pode implementar quantas interfaces de negócio forem necessárias, e o container EJB fará o trabalho de distribuí-lo das diversas formas solicitadas. 6.1.3. Session Beans – Stateless Estes são os tipos mais comuns de beans, os que não apresentam estado. Os Session Beans do tipo Stateless fornecem operações auto-suficientes, onde uma única requisição do cliente é suficiente para efetuar o processo desejado. Exemplo de EJB Stateless: • Interface de Negócio Local @Local public interface CalculadoraLocal { public double somar(double a, double b); public double subtrair(double a, double b); public double multiplicar(double a, double b); public double dividir(double a, double b); } • Implementação @Stateless public class CalculadoraEJB implements CalculadoraLocal { public double somar(double a, double b) { return a + b; } public double subtrair(double a, double b) { return a - b; } public double multiplicar(double a, double b) { return a * b; } public double dividir(double a, double b) { return a / b; } } Como vimos no exemplo acima, para criar um EJB basta definir sua interface de negócio, anotá-la da maneira desejada e implementar o bean. Se desejarmos expor o bean também remotamente, criamos uma interface remota: • Interface de Negócio Remota @Remote public interface CalculadoraRemote { public double somar(double a, double b); public double subtrair(double a, double b); public double multiplicar(double a, double b); public double dividir(double a, double b);
  • 31. 31 } • Implementação @Stateless public class CalculadoraEJB implements CalculadoraLocal, CalculadoraRemote { public double somar(double a, double b) { return a + b; } public double subtrair(double a, double b) { return a - b; } public double multiplicar(double a, double b) { return a * b; } public double dividir(double a, double b) { return a / b; } } No exemplo acima, o nosso bean LocadoraEJB será exposto das duas formas, localmente e remotamente. É permitido utilizar a interface remota para fazer chamadas da mesma JVM, porém esta chamada será feita de forma remota (os objetos serão serializados e passados por valor), desperdiçando assim a melhoria de performance oferecida na chamada local. Note também que as chamadas locais e remotas não precisam necessariamente possuir as mesmas operações. Podemos definir operações diferentes para serem expostas localmente e remotamente, basta definí-las nas respectivas interfaces de negócio. Obs.: se desejarmos fornecer exatamente as mesmas operações, podemos melhorar o código evitando as duplicações das interfaces, da seguinte forma: public interface CalculadoraOperations { public double somar(double a, double b); public double subtrair(double a, double b); public double multiplicar(double a, double b); public double dividir(double a, double b); } @Local public interface CalculadoraLocal extends CalculadoraOperations { } @Remote public interface CalculadoraLocal extends CalculadoraOperations { } 6.1.4. Session Beans – Statefull Estes são os tipos mais pesados de beans, os que apresentam estado. Eles são pesados pois são únicos para cada cliente que os acessa, portanto o container precisa criar uma instância do bean por requisição (veremos com mais detalhes quando analisarmos o ciclo-de-vida dos EJBs). Os Session Beans do tipo Statefull são capazes de guardar estado, portanto podem ter variáveis de instância e utilizá-las no decorrer dos diversos métodos. Pode ser feita uma analogia ao HttpSession da tecnologia web, pois é criada uma espécie de “sessão” para cada cliente que executa o bean. Exemplo de EJB Statefull: • Interface de Negócio Local @Local public interface CarrinhoDeComprasLocal { public void adicionarNoCarrinho(double preco); public double obterTotal(); public void finalizarCompra(); }
  • 32. 32 • Implementação @Stateful public class CarrinhoDeComprasEJB implements CarrinhoDeComprasLocal { private double totalCarrinho; public void adicionarNoCarrinho(double preco) { totalCarrinho += preco; } public double obterTotal() { return totalCarrinho; } @Remove public void finalizarCompra() { System.out.println("Compra finalizada: " + totalCarrinho); } } Uma sessão é criada para um determinado cliente quando o mesmo faz o primeiro request ao bean, e é finalizada quando o cliente chama o método anotado com @Remove, ou então quando a sessão expira (este tempo de expiração pode ser configurado no container). 6.1.5. Ciclo de Vida dos Session beans Session Beans – Stateless Os session beans do tipo Stateless possuem um ciclo de vida muito simples, mas primeiramente devemos falar sobre um serviço muito importante que o container EJB oferece: o Pooling de Instâncias. Uma das principais características de uma aplicação empresarial em produção é sofrer um volume muito grande de acessos, e ela deve estar preparada para isso. Os EJBs são objetos custosos, pesados. Portanto, como garantir a performance do sistema em um caso crítico de acessos simultâneos? Com o intuito de otimizar o desempenho da aplicação, o container fornece o serviço de Pooling de Instâncias. Este serviço faz parte da especificação EJB e todo container é obrigado a implementá-lo. O pooling de instâncias é implementado para os dois tipos de EJB que não guardam estado: o Stateless e o MDB. O serviço funciona da seguinte forma: para cada Stateless Session Bean e MDB deployados no servidor, o container cria um pool em memória contendo um determinado número de instâncias desses beans. Então, quando um cliente solicita um método de bean, uma instância aleatória é escolhida no pool para servir à solicitação em particular. Quando a chamada do método finaliza, a instância volta ao pool para posteriormente servir a outra solicitação. O container não precisa ter a carga de instanciar uma nova instância do bean a cada requisição, elas já estão prontas no pool. De acordo com a implementação do container, ele pode decidir aumentar o pool e criar mais instâncias ou até mesmo destruir instâncias de acordo com o número de requisições média ou memória disponível. Atenção Ao contrário dos Servlets, os EJBs não executam em multithreading: Servlets uma instância por aplicação e uma nova thread por requisição EJBs uma instância por requisição (no caso de Stateless e MDB, a mesma instância pode ser reutilizada por diversas requisições) Note que isto é possível apenas para os beans Stateless e MDB, que não guardam informações de estado e, desta forma, duas requisições subsequentes de um mesmo
  • 33. 33 cliente ao mesmo bean podem ser atendidas por instâncias diferentes do bean, sem causar efeitos colaterais na aplicação. Sendo assim, o ciclo de vida dos beans Stateless é muito simples, onde existem apenas dois estados: “Não Existente” e “Pronto no Pool” Session Beans – Stateful
  • 34. 34 Os session beans do tipo Stateful possuem um ciclo de vida um pouco mais complexo, mas primeiramente devemos falar sobre um serviço muito importante que o container EJB oferece: o Mecanismo de Ativação. Para entender o motivo do mecanismo de ativação, devemos entender o funcionamento do bean Stateful. O bean Stateful, por ter a característica de manter um estado referente ao cliente que o chamou, não pode ter suas instâncias reutilizadas entre clientes diferentes, pois cada instância só diz respeito a um cliente. Por exemplo, o meu carrinho de compras mantém os valores das minhas compras, e não das compras do João ou do Pedro. Devido a esta característica, o bean Stateful pode ter apenas uma instância por cliente, e não pode haver pool pois elas não podem ser reusadas. Agora imagine um cenário empresarial, onde há milhares de clientes efetuando acesso simultâneo a diversos beans Stateful. Como o container irá gerenciar todo esse uso de memória ? Para isso existe o mecanismo de ativação. Este mecanismo funciona da seguinte forma: quando o cliente termina de invocar um método de negócio, o container persiste o estado do bean (variáveis de instância) em um armazenamento secundário (disco ou banco de dados) e o remove da memória. Esse processo se chama apassivação. Quando o mesmo cliente solicita novamente outro método de negócio, o container instancia um novo bean, recupera o estado do bean do armazenamento e refaz a instância como ela era anteriormente. O processo de “volta” se chama ativação. Obs.: o objeto Stub não perde a conexão durante esse processo Desta forma, o ciclo de vida dos beans Stateful possui um estado a mais que o Stateless e sem utilização de pool, resultando em três estados: “Não Existente” , “Pronto” e “Apassivado”
  • 35. 35 Curiosidade – Entendendo o Mecanismo Remoto Do Container O papel do container é fazer com que o desenvolvedor esqueça os serviços primários de infra-estrutura e se concentre em resolver a lógica de negócio através de EJBs. Porém, vale a pena discutir como os modelos de computação distribuída estudados no início do curso contribuíram para a especificação e funcionamento bem sucedido do modelo EJB. Vamos entender como o container EJB trabalha ! O mecanismo de invocação de métodos remota do container é baseado em RMI, portanto, baseando-se nos capítulos iniciais, vimos que ele precisa ter três coisas: • Skeleton • Stub • Protocolo de comunicação remota • Serviço de Nomes (Naming Service) Os beans que implementamos não são objetos remotos, porém o container, através do design pattern do GOF chamado Proxy, cria um “objeto proxy” que recebe as requisições e as redireciona para os nossos beans. Proxy Pattern Fazendo um comparativo da figura que ilustra o pattern e a arquitetura do container EJB, temos o bean real que codificamos, que implementa a interface de negócio. Então, em tempo de deploy, através de reflection, o container gera uma classe proxy
  • 36. 36 que funciona como o Skeleton da arquitetura remota (note que o proxy também implementa a interface de negócio). Esta classe que é responsável por receber a invocação remota e “delegar” a chamada à instância do EJB através do container. O container por sua vez gerencia as questões de pooling, transação e segurança da chamada. Vimos também que todo sistema distribuído trabalha em conjunto com um Serviço de Nomes. Na arquitetura EJB, cada container implementa o serviço de nomes que preferir. No caso do JBoss, o serviço de nomes padrão é o Java Naming Provider (JNP), que é uma implementação substituta do RMI Registry. O protocolo de comunicação padrão de distribuição de EJBs do JBoss é o RMI-JRMP. Na camada cliente, vimos também que é necessário um Stub para realizar as chamadas remotas. Porém, nós vimos que o lookup é feito somente com a interface de negócio. Isto é possível devido ao conceito de codebase (capítulo 2.5), pois ao fazer o lookup do EJB, o Naming Service informa à JVM cliente o endereço do Stub, que é baixado e carregado automaticamente em tempo de execução pelo cliente e desta forma a chamada remota é realizada. 6.2. Distribuindo EJBs Pacote Sigla Depl. Descriptor Descrição WAR Web ARchive web.xml Roda no Container Web, suporta as especificações Servlets e JSP EJB-JAR EJB Java ARchive ejb-jar.xml Roda no Container EJB, suporta as especificações EJB e JPA (incluir persistence.xml) EAR Enterprise ARchive application.xml Roda no Container EJB • Estrutura do WAR
  • 37. 37 • Estrutura do EJB-JAR • Estrutura do EAR 6.3. EJB Timer Service Em sistemas empresariais é muito comum nos depararmos com funcionalidades de agendamento de tarefas, como por exemplo a geração de relatórios de tempos em tempos ou expiração de acesso depois de algum tempo de inatividade de um determinado usuário.
  • 38. 38 Um sistema de agendamento é um sistema que executa algum tipo de atividade automatizada, de acordo com um intervalo de tempo. A especificação EJB 3.0 define um serviço de temporização, chamado de EJB Timer Service. Ele permite a criação de tarefas agendadas, de forma transacional e segura. Os temporizadores criados dessa forma sobrevivem a quedas e restarts do servidor de aplicação. Como a definição do EJB Timer Service é relativamente recente (foi incluída a partir da versão EJB 2.1), ele ainda é um pouco engessado e pobre de funcionalidades. Porém, para implementações simples, acaba tornando-se a ferramenta mais recomendada. Para implementações de temporizadores mais robustos, existe um framework de mercado chamado Quartz, que é muito mais completo e poderoso que o EJB Timer Service, além do fato de poder ser utilizado em aplicações Java SE simples, sem a necessidade de um container EJB (o estudo do framework Quartz não é escopo desse curso). Curiosidade: o JBoss Application Server já é distribuído com uma versão do Quartz acoplada e implementa seus serviços de EJB Timer Service através do Quartz. Os temporizadores fornecidos pelo EJB Timer Service podem ser de dois tipos: • Ação Única Os temporizadores de ação única disparam apenas uma vez, depois de um certo intervalo de tempo ou em uma data específica. • Intervalo Os temporizadores de intervalo disparam várias vezes, de acordo com um período de tempo. Para criar um temporizador, basta obter uma referência ao TimerService do container e “inscrever” o EJB para ser o timer. Um timer é criado sempre através de um EJB, e quando o mesmo for disparado, será executado o método que tiver a anotação @Timeout. Cuidado Apenas os beans do tipo Stateless e MDB podem ser timers. Obtendo a referência ao TimerService do container: @Resource private TimerService timerService; Inscrevendo o bean para ser um timer: @Stateless public class TesteTemporizador implements TesteTemporizadorLocal { @Resource private TimerService timerService; public void criarTemporizador() { Calendar dataDeDisparoAsCalendar = Calendar.getInstance(); //soma 10 dias na data atual dataDeDisparoAsCalendar.add(Calendar.DATE, 10); Date dataDeDisparo = dataDeDisparoAsCalendar.getTime();
  • 39. 39 //cria um timer para executar na data informada timerService.createTimer(dataDeDisparo, null); } @Timeout public void temporizador(Timer timer) { System.out.println("DISPAROU!"); } } Métodos da interface TimerService: public Timer createTimer(Date expiration, Serializable info) • Cria timer de Ação Única • Expira na data especificada public Timer createTimer(long duration, Serializable info) • Cria timer de Ação Única • Expira depois de passado o tempo especificado em milisegundos public Timer createTimer(Date initialExpiration, long intervalDuration, Serializable info) • Cria timer de Intervalo • Expira na data especificada e subsequentemente a cada intervalo especificado em milisegundos public Timer createTimer(long initialDuration, long intervalDuration, Serializable info) • Cria timer de Intervalo • Expira depois de passado o tempo initialDuration e subsequentemente a cada intervalo especificado em intervalDuration public Collection getTimers() • Retorna uma coleção contendo todos os timers agendados para o bean em questão 7. Java Persistence API (JPA) Como vimos no capítulo sobre Session beans, ao projetar um sistema empresarial geralmente identificamos dois tipos de artefatos: entidades e processos, em que “Entidade” se refere a artefatos com um estado bem definido e persistente (ex.: “Filme”, “Usuário”, “Conta”). Na versão EJB 2.1 existia o conceito de Entity Beans, que também eram componentes EJB muito parecidos com os Session Beans, com interface de negócio e distribuídos remotamente, gerando Proxies (ou Skeletons) e Stubs. Ou seja, os Entity Beans eram pesados, faziam chamadas remotas e dependiam de um container EJB e muita configuração XML. Observando o grande sucesso dos frameworks ORM (Object Relational Mapping), como por exemplo o Hibernate, a partir da versão EJB 3.0 a Sun também decidiu especificar um framework ORM, e então foi criada a especificação JPA.
  • 40. 40 Note a diferença de implementação para especificação: o Hibernate é um produto, um framework proprietário desenvolvido e mantido por alguma entidade (atualmente a Red Hat), enquanto a JPA, assim como o EJB, é uma especificação, estudada e desenvolvida pela JCP (Java Community Process). A vantagem de ser uma especificação da JCP é que ele acaba definindo uma “padronização de mercado”, uma “referência”, definida em consenso com as maiores empresas fornecedoras de produtos Java, tornando o uso da tecnologia independente de fornecedor, ou seja, estamos livres para usarmos a implementação que desejarmos ou que revele a melhor performance (e sempre através da mesma interface de programação). A JPA é leve, o modelo de desenvolvimento é baseado em POJOs (Plain Old Java Objects), classes simples, que são manipuladas pelo framework através de introspecção. Para a configuração das entidades é permitido optar entre configurações via XML ou o uso das Annotations. Seu uso é bem simplificado, e suas funcionalidades são todas encapsuladas dentro de um artefato chamado Entity Manager. Outra grande vantagem da especificação JPA é que ela foi criada para atuar também em aplicações simples Java SE, não sendo necessário um servidor de aplicação para gerenciar as entidades, todas as implementações da JPA devem fornecer uma implementação do Entity Manager independente de container EJB. 7.1. Entity Manager É através do Entity Manager que trabalhamos com nossas entidades; ele é o gerenciador de entidades. Toda e qualquer operação de sincronização com a base de dados que realizamos nas nossas entidades JPA é gerenciada pelo entity manager. Ele que é responsável por resolver o mapeamento ORM, criar as conexões com o banco, gerar os sql statements nativos específicos do banco e efetuar as operações de persistência (desde que ele esteja associado a um Contexto de Persistência). Obs.: toda operação realizada com o Entity Manager é transacional, de acordo com os conceitos de Contexto de Persistência e Entidade Gerenciada que veremos adiante. Principais operações oferecidas pelo Entity Manager: persist(Object entity) • Enfileira a entidade para criação no banco (não representa o momento real do insert) • É possível chamar persist fora de uma transação apenas se o contexto for EXTENDED; nesse caso, a inserção é enfileirada até o contexto ser associado com uma transação • Se o parâmetro não for uma entidade, lança IllegalArgumentException • Se for invocado fora do contexto de transação e for tipo TRANSACTION, lança uma TransactionRequiredException
  • 41. 41 find(Class<T> entityClass, Object pk) : Entidade getReference(Class<T> entityClass, Object pk) : Entidade • Retornam uma entidade a partir de sua chave primária • O find, se não encontrar retorna null, e utiliza as configurações de lazy-loading • O getReference, se não encontrar lança EntityNotFoundException • Se o contexto de persistência estiver ativo ela é acoplada, se não, ela é desacoplada createQuery createXXXQuery • Executam querys EJB-QL e consultas nativas (retornam um objeto Query) • Entidades retornadas permanegem gerenciadas enquanto o contexto de persistência estiver ativo flush() • Sincroniza as atualizações no banco antes de terminar a transacao merge(Object entity) : Entidade • Atualiza uma entidade desacoplada e retorna uma cópia dela acoplada • ATENÇÃO: o objeto de parâmetro nunca é gerenciado pelo EntityManager, e sim sua cópia que retorna. Se ele já estiver gerenciado a mesma instancia, ele a atualiza e retorna sua referencia. remove(Object entity) • Remove a entidade da base e a torna desacoplada refresh(Object entity) • Atualiza a entidade acoplada com os dados da base • Se ela não for acoplada ao próprio EntityManager que invoca o método, é lançada IllegalArgumentException • Se o objeto não estiver mais no banco devido a outra Thread ou Processo te- lo removido, será lançado EntityNotFoundException contains(Object entity) : Boolean • Retorna true se a entidade estiver acoplada, false caso contrario. clear() • Desacopla todas as entidades atuais gerenciadas pelo EntityManager • Suas modificações são perdidas, portanto é prudente chamar flush() antes. 7.2. Ciclo de Vida As entidades JPA apresentam um ciclo-de-vida em relação ao Entity Manager, mostrado na figura abaixo:
  • 42. 42 • New / Nova Aqui a entidade ainda não tem um estado persistente, ela acabou de ser instanciada Ex.: Pessoa p = new Pessoa(); • Managed / Gerenciada / Acoplada Aqui a entidade está gerenciada pelo Entity Manager. Isto significa que ela possui um Id Persistente, ou seja, ela representa ativamente um registro da tabela e qualquer mudança de seus atributos refletirá automaticamente na tabela após o flush do Entity Manager ou no final da transação atual. Ex.: Pessoa p = entityManager.find(Pessoa.class, 2); //neste momento, p está “Gerenciada” p.setNome(“Gilberto Holms”); p.setIdade(24); entityManager.flush(); No trecho de código apresentado, após o comando find o Entity Manager irá retornar uma entidade gerenciada, que representa um registro ativo no banco de dados. • Detached / Desacoplada Ocorre quando a entidade perde o sincronismo com o banco. Isso pode acontecer nas seguintes ocasiões: o Acabou o Contexto de Persistência o Foi executado o método clear do Entity Manager o A entidade foi removida do Contexto de Persistência (método remove) o A entidade foi enviada ao cliente (retorno do método de negócio de um EJB) Ex.: Pessoa p = entityManager.find(Pessoa.class, 2); //neste momento, p está “Gerenciada” p.setNome(“Gilberto Holms”); p.setIdade(24); entityManager.flush();
  • 43. 43 entityManager.clear(); //neste momento, p está “Desacoplada” • Removed / Removida Uma entidade torna-se removida quando é deletada do banco. Isto é feito através do método remove do Entity Manager. Após ser removida, ela é automaticamente desacoplada do Entity Manager. Ex.: Pessoa p = entityManager.find(Pessoa.class, 2); //neste momento, p está “Gerenciada” p.setNome(“Gilberto Holms”); p.setIdade(24); entityManager.flush(); entityManager.remove(p); //neste momento, p está “Removida” • Persisted / Persistida Representa a entidade persistida no banco de dados. Com a abstração do JPA, podemos entender uma linha de uma tabela como uma instância de um objeto Java. Ela será retornada ao aplicativo após a execução de qualquer método de consulta do Entity Manager em que ela atenda os requisitos da busca. 7.3. Contexto de Persistência O Contexto de Persistência é um conceito da JPA, que significa “o tempo em que as entidades estão gerenciadas pelo Entity Manager”. Quando o Contexto de Persistência acaba, as entidades tornam-se desacopladas. Na arquitetura EJB é possível utilizar dois tipos de contextos de persistência: Transaction e Extended. • Transaction O tipo “Transaction” pode ser utilizado em qualquer tipo de EJB. Significa que o contexto de persistência irá durar o tempo que durar a transação atual, ou seja, ao terminar a transação atual, as entidades tornam-se desacopladas.
  • 44. 44 • Extended O tipo “Extended” foi criado para ser utilizado apenas para os EJBs do tipo Stateful. Significa que o contexto de persistência irá durar o tempo que durar a sessão do bean Stateful, ou seja, uma entidade pode-se manter gerenciada entre diferentes transações e métodos de negócio. Utilizando esse tipo de contexto de persistência, podemos interagir com uma entidade mesmo fora de uma transação, pois as alterações realizadas serão enfileiradas e efetivadas quando for iniciada a próxima transação para aquele entity manager.
  • 45. 45 7.4. Configurando uma Aplicação JPA Um conjunto de entidades JPA pode ser empacotado em um pacote EJB-JAR, como ilustrado no capítulo 6.2. Ela será caracterizada por conter um arquivo obrigatório na pasta META-INF, chamado “persistence.xml”. Exemplo de persistence.xml: <persistence> <persistence-unit name="curso"> <jta-data-source>java:/meuDataSource</jta-data-source> <properties> <property name="org.hibernate.hbm2ddl" value="update" /> </properties> </persistence-unit> </persistence> Um arquivo persistence.xml pode conter várias “Persistence Unit” (Unidade de Persistência). Uma Unidade de Persistência representa um conjunto de entidades gerenciadas que residem no mesmo Data Source. @Stateless public class MyBean implements MyBusinessInterface { @PersistenceContext(unitName="curso", type=PersistenceContextType.TRANSACTION) private EntityManager manager; ... } Na prática, uma Unidade de Persistência representa um Entity Manager. Cada Entity Manager trabalha com uma Unidade de Persistência. Em sistemas mais complexos, onde haja mais de uma base de dados, é possível trabalhar com múltiplas unidades de persistência. Tags importantes: <persistence-unit name="curso"> Declara a unidade de persistência, informando um nome (obrigatório) <jta-data-source> Declara um Data Source transacional (API JTA, padrão para sistemas JEE), indicando o “endereço JNDI” do Data Source dentro do container <properties> Declara propriedades específicas do fabricante da implementação JPA utilizada Tendo configurado o persistence.xml, basta criar as entidades e mapeá-las. O mapeamento ORM pode ser feito de três maneiras: • Via Annotations – mais simples, com anotações nas próprias classes de entidade • Via XML – é criado um arquivo chamado orm.xml, também dentro de META- INF, contendo os mapeamentos das entidades • Annotations com XML – caso utilizados juntos, o XML sobrescreve parcialmente as Annotations Obs.: os mapeamentos via XML não serão abordados nesse curso, utilizaremos sempre as Annotations pelo fato de simplificarem o desenvolvimento e a manutenção do sistema, porém isso não descarta a citação de trechos do XML quando for interessante.
  • 46. 46 7.5. Mapeando Relacionamentos Todos os tipos de mapeamento de entidades podem ser realizados com duas variações: Unidirecional e Bidirecional. Quanto a sua estrutura de schema físico (base de dados) eles não diferem em nada. Isto é relevante apenas para o desenvolvimento na camada Java: • Unidirecional – é quando queremos pesquisar partindo apenas de um lado do relacionamento. Por exemplo, Pessoa vs. Enredeço: queremos saber qual é o endereço de uma pessoa, mas não precisamos saber qual pessoa pertence a um endereço. pessoa.getEndereco(); //OK endereco.getPessoa(); //NÃO EXISTE • Bidirecional – é quando queremos pesquisar partindo de ambos os lados do relacionamento. Por exemplo, Pessoa vs. Enredeço: queremos saber qual é o endereço de uma pessoa e também precisamos saber qual pessoa pertence a um endereço. pessoa.getEndereco(); //OK endereco.getPessoa(); //OK 7.5.1. Um-Para-Um Unidirecional @Entity public class Customer { ... @OneToOne(cascade={CascadeType.ALL}) private Address address; ... } 7.5.2. Um-Para-Um Bidirecional @Entity public class Customer { ... @OneToOne(cascade={CascadeType.ALL}) private CreditCard creditCard; ... } @Entity public class CreditCard { ... @OneToOne(mappedBy="creditCard") private Customer customer; ... } 7.5.3. Um-para-Muitos Unidirecional @Entity public class Customer { ... @OneToMany(cascade={CascadeType.ALL}) private Collection<Phone> phoneNumbers = new ArrayList<Phone>( ); ... }
  • 47. 47 7.5.4. Muitos-Para-Um Unidirecional @Entity public class Cruise { ... @ManyToOne private Ship ship; ... } 7.5.5. Um-Para-Muitos / Muitos-Para-Um Bidirecional @Entity public class Reservation { ... @ManyToOne private Cruise cruise; ... } @Entity public class Cruise { ... @OneToMany(mappedBy="cruise") private Collection<Reservation> reservations = new ArrayList<Reservation>( ); ... } 7.5.6. Muitos-Para-Muitos Unidirecional @Entity public class Reservation { ... @ManyToMany private Set<Customer> customers = new HashSet<Customer>( ); ... } 7.5.7. Muitos-Para-Muitos Bidirecional @Entity public class Reservation { ... @ManyToMany private Set<Customer> customers = new HashSet<Customer>( ); ... } @Entity public class Customer { ... @ManyToMany(mappedBy="customers") private Collection<Reservation> reservations = new ArrayList<Reservation>( ); ... } 7.6. Cascade Type Um conceito importante é o de atividades em cascata. Existem os seguintes tipos de cascata: • ALL • PERSIST
  • 48. 48 • MERGE • REMOVE • REFRESH Por padrão, quando temos um relacionamento entre entidades, as operações do Entity Manager são realizadas apenas para a entidade “superior” do relacionamento. Por exemplo: Endereco e = new Endereco(); ... pessoa.setEndereco(e); entityManager.persist(pessoa) No caso mostrado acima, se não tiver sido configurado nenhum tipo de cascata para o relacionamento, ao persistir a entidade pessoa, o endereço não será persistido, a JPA irá subentender que ele já existe na base de dados (e caso não exista, lançará exception). Se colocássemos um CascadeType.PERSIST, a JPA iria persistir automaticamente o endereço (caso ele não exista na base) antes de persistir a pessoa. Note que os nomes dos Cascade Types são idênticos a alguns métodos do Entity Manager (exceto ALL, que indica “faça todos”). Em resumo, cada tipo de cascata indica ao Entity Manager para “também realizar a respectiva operação para a entidade relacionada”. 7.7. Lazy Loading Outro conceito importante é o de Lazy Loading, que significa “trazer dados sob demanda”. Quando setamos um relacionamento como LAZY, significa que a JPA irá trazer as entidades relacionadas apenas quando o código java precisar acessá-las. Este recurso é útil quando possuimos uma entidade com muitos relacionamentos. Por exemplo: Entidade: @Entity public class Customer { ... @OneToMany(cascade={CascadeType.ALL}) private Collection<Phone> phoneNumbers = new ArrayList<Phone>( ); ... } FetchType.LAZY Customer c = entityManager.find(Customer.class, 2); //neste momento o objeto c não contém a lista de telefones c.getPhoneNumbers().size(); //apenas nesse momento a JPA carrega a lista de telefones FetchType.EAGER Customer c = entityManager.find(Customer.class, 2); //neste momento o objeto c já contém a lista de telefones Atenção
  • 49. 49 O carregamento sob demanda funciona apenas se a entidade ainda estiver gerenciada pelo container. Quando a entidade torna-se desacoplada, qualquer tentativa de carregamento LAZY resulta em exception. 7.8. CRUD com JPA Inserir: Pessoa p = new Pessoa(); p.setNome("Gilberto"); p.setIdade(24); ... entityManager.persist(p); Atualizar: p.setNome("Holms"); ... p = entityManager.merge(p); Excluir: entityManager.remove(p); Buscar (por Primery Key): Pessoa p = entityManager.find(Pessoa.class, 2); //procura um registro através da Primery Key da tabela //se não encontrar, retorna null Listar (por EJB-QL): Query query = entityManager.createQuery( "SELECT p FROM Pessoa AS p WHERE p.nome = :nome" ); query.setParameter("nome", "Gilberto"); List pessoas = query.getResultList(); 7.9. Data Sources no JBoss Para a plataforma Java Enterprise, o termo “Data Sources” (Fonte de Dados) representa um ponto de acesso a um sistema de armazenamento secundário, geralmente um banco de dados. Nos aplicativos JEE, devido à capacidade do container de injetar dependências e gerenciar recursos, esse Data Source é configurado em algum arquivo de configurações ou console administrativo do servidor, e disponibilizado para a aplicação via JNDI Global. Tendo esse Data Source configurado, qualquer aplicativo pode fazer seu “lookup” e utilizá-lo para abrir uma sessão com a base de dados. Quando isso ocorre em um servidor JEE, ele ainda pode gerenciar todo o controle transacional (através de JTA – Java Transaction API) peculiar da especificação. Reduzindo ao nosso mundo, no escopo da utilização da JPA, vimos anteriormente que devemos configurar um Data Source no persistence.xml, e é através desse Data Source que a JPA irá persistir os objetos. Veja novamente um trecho de um arquivo persistence.xml: <persistence>
  • 50. 50 <persistence-unit name="curso"> <jta-data-source>java:/meuDataSource</jta-data-source> </persistence-unit> </persistence> Quando utilizamos a tag <jta-data-source> estamos definindo o endereço JNDI do Data Source que a nossa unidade de persistência irá utilizar. Obs.: note que podemos ter outra unidade de persistência com um Data Source diferente, e utilizar um Entity Manager para cada unidade. Nos diversos servidores de aplicação disponíveis no mercado, cada um tem sua forma específica de configurar Data Sources. Em servidores mais poderosos, como por exemplo o Oracle WebLogic, essa configuração é feita via console administrativo. Infelizmente o console administrativo do JBoss ainda não chegou nesse nível de maturidade, o que torna necessária a configuração de Data Sources via arquivo XML. No JBoss Application Server podemos criar Data Sources no escopo do servidor ou no escopo da aplicação. • Criar Data Sources no JBoss, escopo de servidor: o Criar um arquivo de final “-ds.xml” com as configurações do DS (ex.: curso-ds.xml) o Copiar o JAR do Driver JDBC da base de dados configurada para a pasta “lib” do seu Server Configuration o Copiar o arquivo “-ds.xml” para a pasta “deploy” do seu Server Configuration o Pronto, o DS estará disponível para qualquer aplicação • Criar Data Souces no JBoss, escopo de aplicação: o Criar um arquivo de final “-ds.xml” com as configurações do DS (ex.: curso-ds.xml) o Copiar o JAR do Driver JDBC da base de dados configurada para a pasta “APP-INF/lib” do seu EAR o Copiá-lo para a pasta “META-INF” do seu EAR o O DS estará disponível para esta aplicação específica Exemplo de –ds.xml: <datasources> <local-tx-datasource> <jndi-name>cursoDS</jndi-name> <connection-url>jdbc:mysql://localhost:3306/curso</connection-url> <driver-class>com.mysql.jdbc.Driver</driver-class> <user-name>root</user-name> <password>root</password> <exception-sorter-class-name> org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter </exception-sorter-class-name> <metadata> <type-mapping>mySQL</type-mapping> </metadata> </local-tx-datasource> </datasources> Atenção As configurações de data source são específicas para cada fornecedor de base de dados, porém o JBoss já vem com um exemplo de configuração para as principais bases de dados, basta modificá-los e utilizá-los. Estes exemplos residem na pasta “docs/examples/jca”, a partir do diretório raiz JBoss.
  • 51. 51 8. Principais Design Patterns JEE Em 1994, um grupo de quatro experientes desenvolvedores e arquitetos de software (Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides), após reunirem suas experiências sobre sistemas orientados a objeto, acabaram criando o livro “Design Patterns: Elements of Reusable Object-Oriented Software”, que é o mais renomado livro sobre design patterns conhecido até os dias de hoje. Este grupo foi nomeado como “Gang of Four” (GoF). Após a publicação deste livro é que se teve o conceito de Design Patterns bem definido e adotado mundialmente. Design patterns são padrões de desenvolvimento bem sucedidos e reutilizáveis, criados para resolver os problemas arquiteturais mais comuns do desenvolvimento orientado a objetos através de uma solução testada e bem sucedida nos diversos aspectos. O livro da GoF define 23 patterns que resolvem grande parte dos problemas estruturais de sistemas orientado a objeto. Porém, quando lançada a arquitetura Java EE, os próprios arquitetos da Sun identificaram na sua estrutura algumas limitações e pontos de atenção que, se não estudados devidamente, poderiam causar muitos problemas para as aplicações baseadas no modelo JEE. Após esse estudo, foi lançado o conceito de “J2EE Patterns”, que são os padrões de projeto específicos para um desenvolvimento correto sobre a estrutura JEE. Este conceito foi introduzido no livro “Core J2EE Patterns: Best Practices and Design Strategies”, escrito pelos mais renomados arquitetos de software da Sun Microsystems, desenvolvedores do JEE (Deepak Alur, John Crupi e Dan Malks). 8.1. Singleton O Design pattern “Singleton” não é um pattern JEE, mas sim um pattern do GoF. O estudo dos design patterns da GoF não é escopo deste livro, porém este pattern em especial é utilizado como parte de diversos J2EE Patterns, portanto é importante o seu entendimento. Como o próprio nome do pattern indica, o seu objetivo é manter apenas uma instância de um objeto na memória, e todas as classes que utilizarem este objeto estarão utilizando a mesma instância dele. Ele traz diversos benefícios, como menor consumo de memória garantindo que existe apenas uma instância do objeto, fornecimento de um único ponto de acesso ao objeto e maior flexibilidade que métodos estáticos, pois permite polimorfismo. Procedimentos para implementação: • Criar um atributo privado e estático do tipo da própria classe • Criar um construtor privado, para não permitir que outras classes instanciem seu objeto • Cria um método estático getInstance, que irá retornar a única instância que existirá Exemplo de Implementação: public class Configuracoes { //atributo com a unica instância existente private static Configuracoes configuracoes;
  • 52. 52 //Construtor privado private Configuracoes(){ // qualquer código de inicialização da instância } //método que retorna a instância singleton public static Configuracoes getInstance() { if (configuracoes == null) { configuracoes = new Configuracoes(); } return configuracoes; } } 8.2. Service Locator Aqui iniciamos os J2EE patterns. Com o uso de sistemas distribuídos e serviços de nomes, tornou-se muito comum em sistemas J2EE a necessidade de localização de recursos na rede ou no disco, tais recursos que poderiam constantemente ser trocados de endereço ou domínio. Nos capítulos sobre RMI e EJB vimos constantemente a necessidade de lookup de recursos no JNDI, porém não é uma boa solução deixar esse serviço dentro da lógica do negócio, mesmo porque ele não representa uma questão de negócio, e sim uma questão de infra-estrutura. Para resolver esta questão arquitetural foi desenvolvido o pattern “Service Locator”, que torna-se uma camada responsável por localizar recursos e serviços, abstraindo a localização física dos mesmos. Procedimentos para implementação: • Criar uma classe para representar o Service Locator, utilizando o padrão Singleton • Fornecer um método para retornar cada tipo de recurso desejado, através de alguma identificação do mesmo Exemplo de Implementação: public class ServiceLocator { //atributo de instância singleton private static ServiceLocator serviceLocator; private Context initialContext; //construtor singleton private ServiceLocator() throws ServiceLocatorException{ Properties properties = new Properties(); properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); properties.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099"); try { this.initialContext = new InitialContext(properties); } catch (NamingException e) { throw new ServiceLocatorException(e); } } //método que retorna a instância singleton public static ServiceLocator getInstance() throws ServiceLocatorException { if (serviceLocator == null) { serviceLocator = new ServiceLocator(); }
  • 53. 53 return serviceLocator; } //método que retorna um servico do jndi configurado (um EJB, DataSource, etc...) public Object getService(String jndiName, Class clazz) throws ServiceLocatorException { try { Object ref = initialContext.lookup(jndiName); return PortableRemoteObject.narrow(ref, clazz); } catch (NamingException e) { throw new ServiceLocatorException(e); } } } Com isso, garantimos que os recursos que dependem de localização serão criados através de um único ponto do sistema, deixando o negócio transparente da localização física dos recursos, abstraindo as chamadas de lookup e particularidades de JNDI. Poderíamos ainda incrementar nosso Service Locator com arquivos “properties” associando beans a endereços, ou ainda implementar um mecanismo de cache. 8.3. Business Delegate O papel do Business Delegate é encapsular as chamadas aos objetos de negócio. O Business Delegate pode localizar o recurso na rede, obter o Stub e invocar suas operações, podendo também tratar error de i/o remoto. O Business Delegate remove o acoplamento entre a camada cliente e os objetos de negócio. Desta forma, a camada cliente não precisa se preocupar com localização de objetos, pode reduzir o tráfico na rede agrupando chamadas a objetos e permite ainda a implementação de algum mecanismo de cache.
  • 54. 54 Procedimentos para implementação: • Criar uma classe para representar o Business Delegate, contendo como variável de instância o objeto de negócio que ele encapsulará. • Fornecer um construtor público, que irá localizar o recurso através do Service Locator e guardá-lo na variável de instância. • Fornecer um método para encapsular cada método de negócio que será chamado (não precisa ser necessariamente um-para-um, sempre que possível pode-se, por exemplo, encapsular duas chamadas ao objeto de negócio em apenas uma chamada ao Business Delegate). Exemplo de Implementação: public class LocadoraDelegate { private Locadora locadora; private static final Class clazz = Locadora.class; public LocadoraDelegate() throws DelegateException { try { this.locadora = (Locadora)ServiceLocator.getInstance().getService("java:/Locadora", clazz); } catch(ServiceLocatorException e) { throw new DelegateException(e); } catch(RemoteException e) { throw new DelegateException(e); } } public int alugarFilme(int id) throws DelegateException { try { int protocolo = locadora.alugarFilme(id); return protocolo; } catch(RemoteException e) { throw new DelegateException(e); } } } 8.4. Session Facade Quando distribuímos objetos pela rede, expomos suas interfaces de negócio ao cliente, consequentemente criando uma granularidade muito alta de serviços. Isso força o cliente a realizar muitas chamadas remotas a um objeto distribuído para realizar uma determinada operação, aumentando o tráfego na rede. Além do problema da rede, temos também uma falta de padronização nas chamadas de negócio provenientes de diferentes clientes e alto acoplamento entre o cliente e os objetos distribuídos. Com a criação de um Session Facade, transformamos muitas chamadas remotas complexas em uma única chamada remota, de grossa granularidade, a qual encapsula as chamadas finas que se tornarão locais, diminuindo assim o tráfego na rede. • Sem Session Facade:
  • 55. 55 • Com Session Facade: Como observamos nos diagramas acima, antes da criação do Session Facade, um determinado cliente realiza três chamadas remotas para realizar uma determinada funcionalidade. Após a criação do Session facade, que também é um objeto remoto (o nome “Session” vem de “Session Bean”), é realizada uma única chamada remota, de grossa granularidade e baixa complexidade, onde o Session Facade realiza três chamadas que tornam-se locais, pois ele vive “no mesmo local” que os objetos remotos. Obs.: existem dois tipos de Session Facade: Stateless e Stateful, que analogamente são criados a partir dos respectivos Session Beans, para funcionalidades de negócio sem estado e com estado respectivamente.
  • 56. 56 8.5. Data Transfer Object (DTO) Na especificação EJB 2.1 e anteriores, havia o conceito de Entity Beans, onde entidades persistentes eram implementadas como componentes de negócio EJB, possuindo interfaces de negócio, consequentemente Stub, Skeleton e operação remota. Devido a essa arquitetura, quando um cliente solicitava uma entidade ao container EJB, esta entidade era retornada como um objeto remoto, e cada interação com a mesma resultava em uma chamada custosa ao servidor, deteriorando a performance do sistema. Para resolver este problema foi criado o pattern Data Transfer Object (conhecido também por outros nomes como Transfer Object ou Value Object). O pattern consiste na criação de um POJO contendo os atributos da entidade ou qualquer outro conjunto de informações, o qual será trafegado para o cliente ao invés do Entity Bean. Desta forma o cliente recebe um objeto java simples, preenchido com os dados relevantes da chamada realizada, sem precisar realizar mais chamadas remotas. A partir da criação da versão EJB 3.0, com a introdução da Java Persistence (JPA), muitos autores discutem sobre a necessidade do uso desse pattern, pois como agora as entidades já são POJOs, o servidor pode retorná-las diretamente ao cliente como entidades desacopladas, ou seja, elas já seriam o DTO. Porém, ainda assim há cenários em que seria relevante o uso do pattern DTO. Imagine que você tem uma entidade JPA com oitenta campos, porém sua tela necessita apenas de três deles, ou ainda que sua tela precise de informações provenientes de três entidades distintas, ou então você não deseja nenhum acoplamento entre sua tela e as entidades de negócio. Reflita sobre o uso do DTO nesses casos. 9. JMS e Message Driven Beans Ao decorrer deste livro estudamos alguns componentes da especificação JEE, como Stateless Session Beans, Stateful Session Beans e Entidades JPA. Porém, todos eles têm uma característica em comum: são síncronos. Quando executamos uma operação da interface de negócio de um Session Bean, nós ficamos aguardando a resposta. Outra característica é o forte acoplamento, pois um cliente precisa conhecer bem o componente remoto que está invocando, pois ele é dependente de sua interface de negócio. Porém, em alguns casos seria muito interessante possuir um sistema assíncrono e desacoplado para troca de informações e este é o papel dos Message Driven Beans. 9.1. O que é Mensageria ? Dentro de uma aplicação, existem diversas de se trocar informações entre componentes. Por exemplo, no RMI a troca de mensagens é feita via chamadas de métodos sobre algum protocolo de rede. O componente cliente precisa conhecer cada componente remoto que invoca e aguardar sua resposta para prosseguir o processamento. O componente cliente é completamente dependente do recipiente, pois ele só funcionará se o recipiente estiver online e pronto para responder a chamada. Podemos fazer uma analogia a uma ligação telefônica: quando ligamos para uma pessoa e esta