1
Apostila JavaEE 5 Componentes Distribuídos
EJB 3 e JBoss
Autor:
Gilberto Augusto T. de A. Holms
gibaholms85@gmail.com
ht...
2
Sumário
1. Ferramentas Utilizadas .........................................................................................
3
7.6. Cascade Type .............................................................................................47
7.7. L...
4
1. Ferramentas Utilizadas
1.1. Java JDK
Para desenvolver aplicações Java Enterprise Edition, não precisamos de nenhum
fe...
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 l...
6
Note que dentro de uma mesma versão são disponibilidadas para download diversas
distribuições do JBoss, em diversos form...
7
1.4. MySQL
Para os exercícios e projetos do curso, utilizaremos a base de dados MySQL (agora
pertencente à Sun Microsyst...
8
Processamento é distribuído
Uma aplicação pode executar de forma distribuída para ter vantagem de utilizar
múltiplos pro...
9
o Camada Física
É a camada que efetivamente transfere os bits, onde podemos pensar
em placas de rede, roteadores e eleme...
10
2.4. CORBA
Como pudemos observar nos exercícios apresentados em sala de aula, disponibilizar
objetos distribuídos nativ...
11
exception LocadoraException{};
interface Filme {
InformacoesFilme getInformacoesFilme() raises(LocadoraException);
void...
12
O “Internet Inter Orb Protocol” é o protocolo de comunicação da arquitetura CORBA. É
um protocolo de rede (TCP/IP) que,...
13
É uma associação nome-objeto, onde uma referência a um objeto é gravada
associada a um nome, que funciona como uma chav...
14
Orb.object_to_string(objRef)
• Interoperable Naming Service (INS)
É uma referência a um objeto em forma “Human-Readable...
15
Para atender esses requisitos, compilador RMIC foi modificado, adicionando a opção
de geração de Skeletons e Stubs para...
16
Na chamada de métodos remotos sempre trabalhamos com cópias serializadas
(sequência de bytes) dos objetos, tanto os pas...
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 ...
18
Devido a este comportamento comum, a Sun teve a brilhante idéia de desenvolver
uma API genérica, desacoplada, capaz de ...
19
LDAP:
Properties prop = new Properties();
prop.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory")...
20
Lookup
Operação de localizar uma associação nome-objeto em um contexto. Lembrando que
será feito sempre relativo a um c...
21
distribuídos, sistemas de mensageria assíncrona, segurança centralizada,
escalabilidade, pool de recursos, controle tra...
22
Responsável por disponibilizar e gerenciar os componentes de infra-estrutura
referentes a camada web (“Web Tier”), como...
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...
24
http://www.jboss.org/
Já a versão Enterprise é disponibilizada para fins comerciais, mantendo a metodologia
da Red Hat ...
25
“Variáveis do Sistema” > “Nova”
Digitar a variável “JBOSS_HOME”,
informando o diretório onde foi
descompactado o JBoss
...
26
Atenção
Nunca carregue diretamente os templates, pois eles não foram criados para ser
usados. Eles servem como modelo p...
27
Selecione “JBoss v5.0” e clique em “Next” Escolha o JRE desejado e localize a pasta onde
reside o diretório raiz do JBo...
28
Em “Server Configuration”, digite o nome da sua configuração personalizada e finalize
Atenção: nunca utilize os templat...
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...
30
• A passagem de parâmetros e retorno de
objetos é feita por valor
• Devido ao item anterior, os parâmetros e
retornos q...
31
}
• Implementação
@Stateless
public class CalculadoraEJB implements CalculadoraLocal, CalculadoraRemote {
public double...
32
• Implementação
@Stateful
public class CarrinhoDeComprasEJB implements CarrinhoDeComprasLocal {
private double totalCar...
33
cliente ao mesmo bean podem ser atendidas por instâncias diferentes do bean, sem
causar efeitos colaterais na aplicação...
34
Os session beans do tipo Stateful possuem um ciclo de vida um pouco mais complexo,
mas primeiramente devemos falar sobr...
35
Curiosidade – Entendendo o Mecanismo Remoto Do Container
O papel do container é fazer com que o desenvolvedor esqueça o...
36
que funciona como o Skeleton da arquitetura remota (note que o proxy também
implementa a interface de negócio). Esta cl...
37
• Estrutura do EJB-JAR
• Estrutura do EAR
6.3. EJB Timer Service
Em sistemas empresariais é muito comum nos depararmos ...
38
Um sistema de agendamento é um sistema que executa algum tipo de atividade
automatizada, de acordo com um intervalo de ...
39
//cria um timer para executar na data informada
timerService.createTimer(dataDeDisparo, null);
}
@Timeout
public void t...
40
Note a diferença de implementação para especificação: o Hibernate é um produto, um
framework proprietário desenvolvido ...
41
find(Class<T> entityClass, Object pk) : Entidade
getReference(Class<T> entityClass, Object pk) : Entidade
• Retornam um...
42
• New / Nova
Aqui a entidade ainda não tem um estado persistente, ela acabou de ser instanciada
Ex.:
Pessoa p = new Pes...
43
entityManager.clear();
//neste momento, p está “Desacoplada”
• Removed / Removida
Uma entidade torna-se removida quando...
44
• Extended
O tipo “Extended” foi criado para ser utilizado apenas para os EJBs do tipo Stateful.
Significa que o contex...
45
7.4. Configurando uma Aplicação JPA
Um conjunto de entidades JPA pode ser empacotado em um pacote EJB-JAR, como
ilustra...
46
7.5. Mapeando Relacionamentos
Todos os tipos de mapeamento de entidades podem ser realizados com duas
variações: Unidir...
47
7.5.4. Muitos-Para-Um Unidirecional
@Entity
public class Cruise {
...
@ManyToOne
private Ship ship;
...
}
7.5.5. Um-Par...
48
• MERGE
• REMOVE
• REFRESH
Por padrão, quando temos um relacionamento entre entidades, as operações do Entity
Manager s...
49
O carregamento sob demanda funciona apenas se a entidade ainda estiver
gerenciada pelo container. Quando a entidade tor...
50
<persistence-unit name="curso">
<jta-data-source>java:/meuDataSource</jta-data-source>
</persistence-unit>
</persistenc...
51
8. Principais Design Patterns JEE
Em 1994, um grupo de quatro experientes desenvolvedores e arquitetos de software
(Eri...
52
//Construtor privado
private Configuracoes(){
// qualquer código de inicialização da instância
}
//método que retorna a...
53
return serviceLocator;
}
//método que retorna um servico do jndi configurado (um EJB, DataSource, etc...)
public Object...
54
Procedimentos para implementação:
• Criar uma classe para representar o Business Delegate, contendo como
variável de in...
55
• Com Session Facade:
Como observamos nos diagramas acima, antes da criação do Session Facade, um
determinado cliente r...
56
8.5. Data Transfer Object (DTO)
Na especificação EJB 2.1 e anteriores, havia o conceito de Entity Beans, onde
entidades...
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss
Próximos SlideShares
Carregando em…5
×

Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss

795 visualizações

Publicada em

Apostila completa, de minha autoria, de um curso de Java EE que ministrei em 2009.

Publicada em: Software
0 comentários
3 gostaram
Estatísticas
Notas
  • Seja o primeiro a comentar

Sem downloads
Visualizações
Visualizações totais
795
No SlideShare
0
A partir de incorporações
0
Número de incorporações
4
Ações
Compartilhamentos
0
Downloads
34
Comentários
0
Gostaram
3
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

Apostila JavaEE 5 Componentes Distribuídos EJB 3 e JBoss

  1. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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

×