Aplicações distribuídas em Java Parte I: RPC e

Propaganda
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
Aplicações distribuídas em Java
Parte I: RPC e Messaging
4
1
argonavis.com.br
Objetivos
•Explorar as APIs do Java que implementam
RPC, troca de mensagens e serviços de nomes
•Java Remote Method Invocation (Java RMI)
•Java RMI sobre IIOP
•Java Naming and Directory Interface (JNDI)
•Java Message Service (JMS)
•JAX-RPC (Web Services)
•Este capítulo ilustra as principais tecnologias
de sistemas distribuídos aplicadas a Java
argonavis.com.br
© 2003 Helder L. S. da Rocha
2
4-1
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Resumo: objetos distribuídos em Java
Interface de programação
• Java RMI sobre JRMP
• Protocolo Java nativo (Java Remote
Method Protocol) - Java-to-Java
• Serviço de nomes não-hierárquico
e centralizado
• Modelo de programação Java: interfaces
Java
OMG IDL
Java IDL
(CORBA)
RMI-IIOP
IIOP
RMI-JRMP
JRMP
• Java IDL: mapeamento OMG IDL-Java
• Protocolo OMG IIOP (Internet Inter-ORB
Interface de
comunicação
Protocol) independente de plataforma/linguagem
em rede
• Serviço de nomes (COS Naming) hierárquico,
distribuído e transparente quanto à localização dos objetos
• Modelo de programação CORBA: OMG IDL (language-neutral)
• Java RMI sobre IIOP
• Protocolo OMG IIOP, COS Naming, transparência de localidade, etc.
• Modelo de programação Java com geração automática de OMG IDL
argonavis.com.br
3
Como criar uma aplicação RMI
1. Criar subinterface de java.rmi.Remote para cada objeto remoto
• Interface deve declarar todos os métodos visíveis remotamente
• Todos os métodos devem declarar java.rmi.RemoteException
2. Implementar e compilar os objetos remotos
• Criar classes que implementem a interface criada em (1) e
estendam java.rmi.server.UnicastRemoteObject (ou Activatable*)
• Todos os métodos (inclusive construtor) provocam RemoteException
3. Gerar os stubs e skeletons
• Rodar a ferramenta rmic sobre a classe de cada objeto remoto
4. Implementar a aplicação servidora
• Registrar os objetos remotos no RMIRegistry usando Naming.bind()
• Definir um SecurityManager (obrigatório p/ download de cód. remoto)
5. Implementar o cliente
• Definir um SecurityManager e conectar-se ao codebase do servidor
• Recuperar os objetos remotos usando (Tipo)Naming.lookup()
6. Compilar servidor e cliente
argonavis.com.br
© 2003 Helder L. S. da Rocha
4
4-2
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Construção de aplicação RMI
extends
java.rmi.Remote
Hello.java
interface Hello extends Remote{
void sayHello() throws RemoteException;
1
}
java.rmi.server.UnicastRemoteObject
implements
extends
5
4
HelloClient.java
HelloServer.java
Hello h =(Hello)
HelloImpl rf =
Naming.lookup("hello");
new HelloImpl();
h.sayHello();
Naming.bind(rf, "hello");
2
HelloImpl.java
...
void sayHello throws
RemoteException {
System.out.println("Hello");
}
HelloImpl_Skel
HelloImpl_Stub
Stub
Skel
3
6
HelloClient
lookup()
Java
compiler
RMIRegistry
RMIC
2
bind()
HelloServer
HelloImpl
HelloImpl_Stub
argonavis.com.br
JRMP
HelloImpl_Skel
(obj remoto)
5
Interface Remote
•Interface de comunicação entre cliente e servidor
•Stub e objeto remoto implementam esta interface de
forma que cliente e esqueleto enxergam a mesma fachada
•Declara os métodos que serão visíveis remotamente
•Todos devem declarar provocar RemoteException
package hello.rmi;
import java.rmi.*;
public interface HelloRemote extends Remote {
public String sayHello()
throws RemoteException ;
public void sayThis(String toSay)
throws RemoteException;
}
argonavis.com.br
© 2003 Helder L. S. da Rocha
6
4-3
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Implementação do objeto remoto
package hello.rmi;
Principal classe base para objetos
remotos RMI (outra opção é Activatable*)
import java.rmi.*;
public class HelloImpl
extends java.rmi.server.UnicastRemoteObject
implements HelloRemote {
private String message = "Hello, World!";
public HelloImpl() throws RemoteException { }
public String sayHello()
throws RemoteException {
return message;
}
public void sayThis(String toSay)
throws RemoteException {
message = toSay;
}
Construtor declara
que pode provocar
RemoteException!
}
* javax.rmi.activatable.Activatable (modelo de implementação não abordado neste curso)
argonavis.com.br
7
Geração de Stubs e Skeletons
•Tendo-se a implementação de um objeto remoto, pode-se
gerar os stubs e esqueletos
> rmic hello.rmi.HelloImpl
•As classes são automaticamente compiladas (e as fontes são
descartadas)
•Resultados
•_HelloImpl_Stub.class
•_HelloImpl_Skel.class
•Para preservar (e visualizar) o código-fonte gerado (.java) use
a opção -keep:
> rmic -keep hello.rmi.HelloImpl
argonavis.com.br
© 2003 Helder L. S. da Rocha
8
4-4
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Servidor e rmi.policy
package hello.rmi;
import java.rmi.*;
import javax.naming.*;
SecurityManager viabiliza
download de código
Associando o objeto com
public class HelloServer {
um nome no RmiRegistry
public static void main (String[] args) {
if (System.getSecurityManager() == null)
System.setSecurityManager(new RMISecurityManager());
try {
HelloRemote hello = new HelloImpl();
Naming.rebind("hellormi", hello);
System.out.println("Remote object bound to 'hellormi'.");
} catch (Exception e) {
if (e instanceof RuntimeException)
throw (RuntimeException)e;
System.out.println("" + e);
}
}
}
Arquivo de politicas de segurança para uso pelo SecurityManager
rmi.policy
grant {
permission java.net.SocketPermission "*:1024-65535", "connect, accept, resolve";
permission java.net.SocketPermission "*:80", "connect, accept, resolve";
permission java.util.PropertyPermission "*", "read, write";
};
argonavis.com.br
9
Cliente
package hello.rmi;
import java.rmi.*;
import javax.naming.*;
public class HelloClient {
public static void main (String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
HelloRemote hello = (HelloRemote) Naming.lookup("hellormi");
System.out.println(hello.sayHello());
hello.sayThis("Goodbye, Fred!");
System.out.println(hello.sayHello());
} catch (Exception e) {
if (e instanceof RuntimeException)
throw (RuntimeException)e;
System.out.println("" + e);
}
Obtenção do objeto com
associado a"hellormi" no
serviço de nomes
Chamadas de métodos remotos
}
}
argonavis.com.br
© 2003 Helder L. S. da Rocha
10
4-5
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Execução
• Inicie o RMIRegistry
O diretório onde você
instalou os exemplos
> rmiregistry &
• Rode o servidor
> java hello.rmi.HelloServer
-Djava.rmi.server.codebase=file:///webmidia/exemplos/build/
-Djava.security.policy=../lib/rmi.policy
Remote object bound to 'hellormi'.
• Rode o cliente
> java hello.rmiop.HelloClient
-Djava.rmi.server.codebase=file:///webmidia/exemplos/build/
-Djava.security.policy=../lib/rmi.policy
Hello, World!
Goodbye!
• Você pode rodar esta aplicação no usando o Ant. Mude para o subdiretório*
exemplos/ e monte uma aplicação semelhante a esta com
> ant buildrmi
• Depois, em janelas diferentes, inicie os servidores e cliente digitando
> ant runrmiserver
> ant runrmiclient
* informe antes no arquivo build.properties o caminho completo para este diretório
argonavis.com.br
11
Necessidade de RMI-IIOP
• Queremos programar em Java
• Não queremos aprender outra linguagem (IDL)
• Não queremos escrever linhas e linhas de código para transformar,
registrar e localizar objetos CORBA (queremos transparência)
• Queremos comunicação IIOP por causa de
• integração com objetos em outras linguagens
• vantagens do modelo ORB (transparência de localidade, escalabilidade,
serviços, etc.)
• comunicação com clientes escritos em outras linguagens
• Solução: RMI sobre IIOP
• Principal benefício: comunicação com mundo CORBA
• Desvantagens: limitações de CORBA
• Não faz download de bytecode
• Não faz Distributed Garbage Collection - DGC
argonavis.com.br
© 2003 Helder L. S. da Rocha
12
4-6
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Como criar uma aplicação RMI-IIOP
1. Criar subinterface de java.rmi.Remote para cada objeto remoto
• Interface deve declarar todos os métodos visíveis remotamente
• Todos os métodos devem declarar java.rmi.RemoteException
2. Implementar e compilar os objetos remotos
• Criar classes que implementem a interface criada em (1) e
estendam javax.rmi.PortableRemoteObject
• Todos os métodos (inclusive construtor) provocam RemoteException
3. Gerar os stubs e skeletons (e opcionalmente, os IDLs)
• Rodar a ferramenta rmic -iiop sobre a classe de cada objeto remoto
4. Implementar a aplicação servidora
• Registrar os objetos remotos no COSNaming usando JNDI
• Definir um SecurityManager
5. Implementar o cliente
• Definir um SecurityManager e conectar-se ao codebase do servidor
• Recuperar objetos usando JNDI e PortableRemoteObject.narrow()
6. Compilar
13
argonavis.com.br
Construção de aplicação RMI-IIOP
Hello.java
interface Hello extends Remote{
void sayHello() throws RemoteException;
1
}
java.rmi.Remote
javax.rmi.PortableRemoteObject
implements
2
HelloImpl.java
5
4
HelloClient.java
Hello h =(Hello)
ctx.lookup("hello");
h.sayHello();
HelloServer.java
HelloImpl rf =
new HelloImpl();
ctx.bind(rf, "hello");
...
void sayHello throws
RemoteException {
System.out.println("Hello");
}
HelloImpl_Tie
_HelloImpl_Stub
Stub
Skel
3
HelloClient
6
Java
compiler
lookup()
JNDI
(CosNaming)
argonavis.com.br
© 2003 Helder L. S. da Rocha
2
bind()
IIOP
RMIC
HelloServer
ORB
ORB
_HelloImpl_Stub
IDL
HelloImpl_Tie
HelloImpl
(obj remoto)
14
4-7
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Interface Remote
•Declara os métodos que serão visíveis remotamente
•Todos devem declarar provocar RemoteException
•Indêntica à interface usada em RMI sobre JRMP
package hello.rmiop;
import java.rmi.*;
public interface HelloRemote extends Remote {
public String sayHello()
throws RemoteException ;
public void sayThis(String toSay)
throws RemoteException;
}
15
argonavis.com.br
Implementação do objeto remoto
package hello.rmiop;
Classe base para todos os objetos
remotos RMI-IIOP
import java.rmi.*;
public class HelloImpl
extends javax.rmi.PortableRemoteObject
implements HelloRemote {
private String message = "Hello, World!";
public HelloImpl() throws RemoteException { }
public String sayHello()
throws RemoteException {
return message;
}
public void sayThis(String toSay)
throws RemoteException {
message = toSay;
}
Construtor declara
que pode provocar
RemoteException!
}
argonavis.com.br
© 2003 Helder L. S. da Rocha
16
4-8
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Geração de Stubs e Skeletons
•Tendo-se a implementação de um objeto remoto, pode-se
gerar os stubs e esqueletos
> rmic -iiop hello.rmiop.HelloImpl
•Resultados
• _HelloRemote_Stub.class
• _HelloImpl_Tie.class - este é o esqueleto!
•Para gerar, opcionalmente, uma (ou mais) interface IDL
compatível use a opção -idl
> rmic -iiop -idl hello.rmiop.HelloImpl
•Resultado
HelloRemote.idl
argonavis.com.br
#include "orb.idl"
Tipos definidos em orb.idl
module hello {
(equivalem a wstring)
module rmiop {
interface HelloRemote {
::CORBA::WStringValue sayHello( );
void sayThis(in ::CORBA::WStringValue arg0 );
};
};
};
17
JNDI
• RMI-IIOP usa JNDI como interface para o serviço de nomes
CORBA (COS Naming)
• Java Naming and Directory Interface é uma ponte sobre
os diversos serviços de nomes e diretórios diferentes
• Vantagens
•Isola a aplicação dos detalhes específicos do protocolo
•Pode ser usada para ler objetos Java (serializados) que
estejam armazenados em um diretório
•Pode combinar diferentes tipos de diretório (federação) e
tratá-los como um diretório único
• Componentes
• API - Application Programming Interface
• SPI - Service Provider Interface que permite que novos serviços
sejam plugados transparentemente
argonavis.com.br
© 2003 Helder L. S. da Rocha
18
4-9
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Arquitetura JNDI
Aplicação Java
JNDI API
Pacote
javax.naming
Naming Manager
JNDI Service Provider Interface (SPI)
NDS
SP
FileSystem
SP
LDAP
SP
DNS
SP
RMI
SP
NDS
Sistema de
Arquivos
LDAP
DNS
RMI
Registry
Corba
SP
WinReg
SP
COS
Windows
Naming Registry
Service
Providers
Sistemas de
Nomes e
Diretórios
19
Fonte: argonavis.com.br
JNDI Tutorial
Contexto inicial
• Precisa ser obtido antes de qualquer operação. Passos:
• 1: selecionar o provedor de serviços
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"classe.do.ProvedorDeServicos");
• 2: configurar o acesso ao serviço
env.put(Context.PROVIDER_URL, "ldap://xyz.com:389");
env.put(Context.OUTRA_PROPRIEDADE, "valor"); (...)
• 3: criar um objeto para representar o contexto
Context ctx = new InitialContext(env);
• A configuração (1, 2) pode ser feita via propriedades do sistema
• Passadas em linha de comando via argumento -Dprop=valor
• Carregados via arquivos de propriedades
• Principais propriedades
java.naming.factory.initial:
java.naming.provider.url:
argonavis.com.br
© 2003 Helder L. S. da Rocha
Context.INITIAL_CONTEXT_FACTORY
Context.PROVIDER_URL
20
4 - 10
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Arquivo jndi.properties
• Uma outra forma de definir propriedades usadas pelos clientes
JNDI, é através de um arquivo jndi.properties
• Um arquivo com este nome deve ser colocado no CLASSPATH da
aplicação cliente
• Ao inicializar o ambiente com InitialContext(), não passe nenhum
parâmetro no construtor. O class loader irá procurar um arquivo
jndi.properties no CLASSPATH e carregará as propriedades que
estiverem definidas dentro dele
• Por exemplo, um arquivo pode conter
java.naming.factory.initial=\
com.sun.jndi.fscontext.RefFSContextFactory
java.naming.provider.url=file:/cap02/lab/filesys
• Para inicializar o sistema com essas propriedades, use
Context ctx = new InitialContext();
21
argonavis.com.br
Recuperação de objetos (lookup)
• Para obter a referência para um objeto de um contexto usa-se
o método lookup()
• Para usar o objeto retornado é preciso conhecer o seu tipo e fazer o
cast (ou narrow, se objeto remoto) para promover a referência
• Se o objeto for um contexto, lookup() age como um método para
mudar de contexto (como o chdir, em Unix)
• Exemplo
• O método lookup() usando com o provedor de serviço fscontext
retorna um java.io.File pelo nome de arquivo
Serviço de nomes para
sistema de arquivos
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL,
Diretório raiz do serviço
"file:/cap02/lab/filesys");
Context ctx = new InitialContext(env);
File f = (File)ctx.lookup("report.txt");
argonavis.com.br
© 2003 Helder L. S. da Rocha
Arquivo localizado
na raiz do serviço
22
4 - 11
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Provedores de serviços para objetos
•Pode-se usar JNDI para mapear nomes a objetos
•Objetos localizáveis por nome podem ser abstraídos do
contexto ou até linguagem em que são usados
•Aplicações diferentes podem compartilhar objetos
•Dois drivers JNDI estão disponíveis para acesso a
objetos distribuídos no J2SDK
•SPI CORBA (COS Naming): permite localização de objetos
CORBA (serializados em um formato independende de
linguagem) - usado em RMI-IIOP (EJB)
com.sun.jndi.cosnaming.CNCtxFactory
•SPI RMI: permite a localização de objetos Java serializados
(objetos pode ser usados por outras aplicações Java)
com.sun.jndi.rmi.registry.RegistryContextFactory
23
argonavis.com.br
Objetos RMI
• Pode-se usar JNDI para acesso a Java RMI. Para isto é preciso
antes configurar o contexto inicial com suas propriedades
• Propriedades a definir
java.naming.factory.initial ou Context.INITIAL_CONTEXT_FACTORY
com.sun.jndi.rmi.registry.RegistryContextFactory
java.naming.provider.url ou Context.PROVIDER_URL
rmi://nome_do_host:1099 (endereço e porta do RMI Registry)
• Como fazer mapeamento
Context ctx = new InitialContext();
Fruit fruit = new Fruit("orange");
ctx.bind("favorite", fruit);
• Como localizar
Context ctx = new InitialContext();
Fruit fruit = (Fruit) ctx.lookup("favorite");
argonavis.com.br
© 2003 Helder L. S. da Rocha
24
4 - 12
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Objetos CORBA (RMI sobre IIOP)
• Usado em RMI-IIOP. Proprieades a definir
java.naming.factory.initial ou Context.INITIAL_CONTEXT_FACTORY
com.sun.jndi.cosnaming.CNCtxFactory
java.naming.provider.url ou Context.PROVIDER_URL
iiop://nome_do_host:1900 (endereço e porta do ORB)
• Mapeamento
Context ctx = new InitialContext();
Fruit fruit = new Fruit("orange");
ctx.bind("favorite", fruit);
• Localização
Converte objeto CORBA
em objeto Java
Context ctx = new InitialContext();
Object corbaFruit = ctx.lookup("favorite");
Object javaFruit =
javax.rmi.PortableRemoteObject.narrow(corbaFruit,
Fruit.class);
Fruit fruit = (Fruit)javaFruit;
25
argonavis.com.br
Servidor e rmi.policy
package hello.rmiop;
import java.rmi.*;
import javax.naming.*;
SecurityManager viabiliza
download de código
public class HelloServer {
public static void main (String[] args) {
if (System.getSecurityManager() == null)
System.setSecurityManager(new RMISecurityManager());
try {
HelloRemote hello = new HelloImpl();
Context initCtx = new InitialContext();
initCtx.rebind("hellormiop", hello);
System.out.println("Remote object bound to 'hellormiop'.");
} catch (Exception e) {
if (e instanceof RuntimeException)
Associando o objeto com
throw (RuntimeException)e;
System.out.println("" + e);
um nome no serviço de nomes
}
}
}
Arquivo de politicas de segurança para uso pelo SecurityManager
rmi.policy
grant {
permission java.net.SocketPermission "*:1024-65535", "connect, accept, resolve";
permission java.net.SocketPermission "*:80", "connect, accept, resolve";
permission java.util.PropertyPermission "*", "read, write";
};
argonavis.com.br
26
© 2003 Helder L. S. da Rocha
4 - 13
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Cliente
package hello.rmiop;
import java.rmi.*;
import javax.naming.*;
Obtenção do objeto com
associado a"hellormiop" no
contexto inicial do
serviço de nomes
public class HelloClient {
public static void main (String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
Context initCtx = new InitialContext();
Object obj = initCtx.lookup("hellormiop");
HelloRemote hello = (HelloRemote)
javax.rmi.PortableRemoteObject.narrow(obj,
hello.HelloRemote.class);
System.out.println(hello.sayHello());
hello.sayThis("Goodbye, Helder!");
System.out.println(hello.sayHello());
} catch (Exception e) {
if (e instanceof RuntimeException)
throw (RuntimeException)e;
Não basta fazer cast! O objeto retornado
System.out.println("" + e);
é um objeto CORBA (e não Java) cuja raiz
}
}
}
argonavis.com.br
não é java.lang.Object mas org.omg.CORBA.Object
narrow transforma a referência no tipo correto
27
Execução
• Inicie o ORB
> orbd -ORBInitialPort 1900 -ORBInitialHost localhost &
• Rode o servidor
O diretório onde você
instalou os exemplos
> java hello.rmiop.HelloServer
-Djava.rmi.server.codebase=file:///webmidia/exemplos/build/
-Djava.security.policy=../lib/rmi.policy
-cp ../lib
Remote object bound to 'hellormiop'.
• Rode o cliente
> java hello.rmiop.HelloClient <mesmas propriedades do servidor>
Hello, World!
Goodbye!
• Alternativas para reduzir a quantidade de parâmetros de execução
• Defina as propridades no código ou crie um arquivo rmi.properties (melhor!)
• Use um script shell, .bat ou o Ant
• Ant: no subdiretório* exemplos/, monte aplicação semelhante a esta com
> ant buildrmiop
• Depois, em janelas diferentes, inicie os servidores e cliente digitando
“ant orbd", "ant runrmiopserver" e "ant runrmiopclient"
* informe antes no arquivo build.properties o caminho completo para este diretório
argonavis.com.br
© 2003 Helder L. S. da Rocha
28
4 - 14
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Java Message Service
•Interface Java única para unir as MOMs
incompatíveis
•API que permite que aplicações criem, enviem,
recebam e leiam mensagens através de um MOM
•API consiste principalmente de interfaces
(implementadas pelo fabricante do MOM)
•Parte integral da plataforma J2EE (acrescenta
possibilidade de comunicação assíncrona a EJBs)
29
argonavis.com.br
Arquitetura JMS
Cliente JMS
Cliente JMS
Mensagens: objetos que
Mensagem passam informações Mensagem
entre clientes JMS
Clientes: produzem e
consomem mensagens
JNDI
lookup()
JMS API
Destinos
tipo Canal
Destinos
tipo Fila
Destinos
tipo Canal
Provedor JMS oferece:
- Sistema de mensagens
- Serviços administrativos
- Sistemas de controle
argonavis.com.br
© 2003 Helder L. S. da Rocha
Ferramentas de
administração
do provedor
Espaço de
nomes JNDI
Destinos
tipo Fila
Fábricas de
Conexões
JNDI bind()
Toda a comunicação
com o provedor JMS é
realizada através de
JNDI e da API JMS
Objetos gerenciados
acessíveis
via JNDI
Fábricas de
Conexões
30
4 - 15
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Domínio ptp (ponto-a-ponto)
•Baseado no conceito de filas, remetentes e destinatários
•Um ou muitos para um: cada mensagem é enviada para uma
fila específica e é consumida por um destinatário (que pode
ou não estar disponível no momento)
•Destinatário confirma que a mensagem foi recebida e
processada corretamente (acknowledgement)
•Filas retém mensagens até que sejam
QueueReceiver r;
consumidas (ou expirem) Provedor JMS
Message m =
Remetente s
m1
Consome
Destinatário r
Confirma Recebimento
m4
Envia
argonavis.com.br
r.receive();
FIFO
QueueSender s;
s.send(m1);
...
s.send(m5);
m5
Fila (queue)
Message m5
31
Domínio pub/sub (publica/inscreve)
• Baseado em canais (tópicos)
• Muitos para muitos: mensagens são
enviadas a um canal onde todos os
assinantes do canal podem retirá-la
Canal
Fila
TopicPublisher p;
p.publish(m1);
...
p.publish(m5);
m2
m3
TopicSubscriber s1;
MessageListener k =
new MessageListener() {
public void
onMessage(Message m){...}
};
s1.setMessageListener(k);
Inscreve-se em Tópico
m1
Fornece
Assinante s1
s1.onMessage(m1);
s2.setMessageListener(k);
m4
m5
Publicador p
Publica
argonavis.com.br
© 2003 Helder L. S. da Rocha
Inscreve-se em Tópico
m1
Provedor JMS
Fornece
Assinante s2
s2.onMessage(m1);
32
4 - 16
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Consumo síncrono e assíncrono
•Mensagens podem ser retiradas do destino através de
uma chamada receive()
•Esta é a forma síncrona de retirar mensagens
•Cliente bloqueia enquanto mensagem não chega
•Mensagens também podem ser enviadas ao
destinatário quando chegarem
•Esta é a forma assíncrona de retirar mensagens
•Para ser notificado, destinatário precisa ser implementado
como um ouvinte e cadastrado para receber notificações
•Nos exemplos anteriores, o modelo P2P foi
implementado com destinatário síncrono e o modelo
publish-subscribe com destinatário assíncrono
33
argonavis.com.br
Desenvolvimento de aplicações JMS
• Para escrever aplicações que enviam ou recebem mensagens
é preciso realizar uma série de etapas
• Obter um destino e uma fábrica de
conexões via JNDI
• Usar a fábrica para obter uma conexão
• Usar a conexão para obter uma ou
mais sessões
• Usar a sessão para criar uma mensagem
• Iniciar a sessão
• Depois, pode-se
• Enviar mensagens
• Receber mensagens
• Cadastrar ouvintes para
receber mensagens
automaticamente
Fonte da ilustração: JMS Tutorial
argonavis.com.br
© 2003 Helder L. S. da Rocha
Message
Producer
Connection
Factory
ctx.lookup(nome)
createConnection()
Connection
createSession()
Session
create()
Message
Consumer
create()
receive()
send()
createMessage()
Message
Destination
Destination
ctx.lookup(nome)
34
4 - 17
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Interfaces: dois domínios
• É preciso escolher um domínio
• Para cada domínio há um destino, fábrica de conexões, conexão,
sessão, produtor e consumidor
• Interfaces são semelhantes
Destination
Objetos
gerenciados
ConnectionFactory
MessageProducer
Topic
TopicConnectionFactory
TopicPublisher
Queue
QueueConnectionFactory
QueueSender
Connection
Session
MessageConsumer
TopicConnection
TopicSession
TopicSubscriber
QueueConnection
QueueSession
QueueReceiver
?Domínio
pub/sub ?Domínio ptp
argonavis.com.br
35
Há dois tipos de destinos JMS
• Filas (Queue)
• Retêm todas as mensagens que recebem até que sejam retiradas
ou expirem
• Para cada mensagem enviada, apenas um cliente pode retirá-la
Queue fila = (Queue) ctx.lookup("jms/Queue");
• Canais (Topic)
• Cada canal pode ter vários clientes assinantes
• Cada assinante recebe uma cópia das mensagens enviadas
• Para receber uma mensagem publicada em um canal, clientes
precisam já ser assinantes dele antes do envio.
• Em canais "duráveis", assinantes não precisam estar ativos no
momento do envio. Retornando, receberão mensagens nao lidas.
Topic canal = (Topic) ctx.lookup("jms/Topic");
argonavis.com.br
© 2003 Helder L. S. da Rocha
36
4 - 18
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Fábricas de conexões
• Antes que se possa
• enviar uma mensagem para uma fila,
• publicar uma mensagem em um canal,
• consumir uma mensagem de uma fila ou
• fazer uma assinatura de um canal
é preciso obter uma conexão ao provedor JMS
• Isto é feito através de uma fábrica de conexões. Há duas:
• TopicConnectionFactory - para conexões no domínio Topic
• QueueConnectionFactory - para conexões no domínio Queue
• É preciso conhecer o nome JNDI
String nomeJRI = "TopicConnectionFactory"; //default J2EE-RI
String nomeJBoss = "ConnectionFactory"; // default JBossMQ
Precisa ser definido (geralmente
Context ctx = new InitialContext();
arquivo jndi.properties no CPATH)
TopicConnectionFactory factory =
(TopicConnectionFactory) ctx.lookup(nomeJBoss);
37
argonavis.com.br
Conexões
•Encapsulam uma conexão virtual com o provedor JMS
•Suportam múltiplas sessões (threads)
•Uma vez obtida uma fábrica de conexões, pode-se
obter uma conexão
QueueConnection queueCon =
queueConnectionFactory.createQueueConnection();
TopicConnection topicCon =
topicConnectionFactory.createTopicConnection();
•Quando a conexão terminar, é preciso fechá-la
•O fechamento fecha todas as seções, produtores e
consumidores associados à conexão
queueCon.close();
topicCon.close();
argonavis.com.br
© 2003 Helder L. S. da Rocha
38
4 - 19
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Sessões
• Contexto onde se produz e se consome mensagens
• Criam produtores, consumidores e mensagens
• Processam a execução de ouvintes
• Single-threaded
• Podem ser configuradas para definir
• forma de acknowledgement
• uso ou não de transações (tratar uma série de envios/recebimentos
como unidade atômica e controlá-la via commit e rollback)
• Exemplos
Sem transações
Confirmação automática
após recebimento correto
TopicSession topicSession =
topicCon.createTopicSession(false,
Session.AUTO_ACKNOWLEDGE);
Sessão controlada
por transações
QueueSession queueSession =
queueCon.createQueueSession(true, 0);
Tratamento
de confirmações não
especificado
39
argonavis.com.br
Produtores de mensagens
• Objeto criado pela sessão e usado para enviar mensagens
para um destino
• QueueSender: domínio ponto-a-ponto
• TopicPublisher: domínio pub/sub
QueueSender sender =
queueSession.createSender(fila);
TopicPublisher publisher =
topicSession.createPublisher(canal);
• Uma vez criado o produtor, ele pode ser usado para enviar
mensagens
Durante o envio cliente pode
definir qualidade do serviço
como modo (persistente ou
sender.send( message );
não), prioridade (sobrepõe
• publish() no domínio pub/sub
comportamento FIFO) e
publisher.publish( message ); tempo de vida (TTL)
• send() no domínio ponto-a-ponto
argonavis.com.br
© 2003 Helder L. S. da Rocha
40
4 - 20
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Consumidores de mensagens
• Objeto criado pela sessão e usado para receber mensagens
• QueueReceiver e QueueBrowser: domínio ponto-a-ponto
• TopicSubscriber: domínio pub/sub
QueueReceiver receiver =
queueSession.createReceiver(fila);
TopicSubscriber subscriber =
topicSession.createSubscriber(canal);
• É preciso iniciar a conexão antes de começar a consumir:
topicCon.start();
• Depois, pode consumir mensagens de forma síncrona (método
é o mesmo para domínios PTP e pub/sub
Message queueMsg = receiver.receive();
Message topicMsg = subscriber.receive(1000);
• Para consumir mensagens de forma assíncrona é preciso criar
um MessageListener
argonavis.com.br
41
MessageListener
• Event handler que detecta o recebimento de mensagens
• Para usar, implemente MessageListener e seu método onMessage():
public class MyListener implements MessageListener {
public void onMessage(Message msg) {
TextMessage txtMsg = (TextMessage) msg;
System.out.println( "Mensagem recebida: " +
txtMsg.getText() )
}
}
• Método onMessage() não deve deixar escapar exceções
• Código acima deve estar em um bloco try-catch
• Para que objeto seja notificado, é preciso registrá-lo em um
QueueReceiver ou TopicSubscriber
subscriber.setMessageListener( new MyListener() );
topicCon.start(); // iniciar a conexão
argonavis.com.br
© 2003 Helder L. S. da Rocha
42
4 - 21
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Mensagens
•Mensagens são compostas de três partes
•Propriedades (opcionais): pares nome/valor (nomes e
valores arbitrários definidos pela aplicação); contém tipos
primitivos Java (int, boolean, etc.) ou String.
•Cabeçalhos: propriedades com nomes e tipos de valores
padrão definidos na especificação JMS
•Corpo: conteúdo que não pode ser representado através
de propriedades
•Os tipos de mensagem correspondem a formatos de
dados armazenados no corpo de mensagem
•Texto, objetos serializados, bytes, valores primitivos, etc.
•Mensagens são criadas a partir de uma Session
43
argonavis.com.br
Seis tipos de mensagens
• Message
• Mensagem genérica sem corpo (contendo
apenas cabeçalho e possíveis propriedades)
• TextMessage
• Objeto do tipo String (ex: conteúdo XML)
• MapMessage
• Conjunto de pares nome/valor onde nomes
são Strings e valores são tipos primitivos
• BytesMessage
• Stream de bytes não interpretados
• StreamMessage
• Seqüência de tipos primitivos Java
• ObjectMessage
Message
TextMessage
MapMessage
BytesMessage
StreamMessage
ObjectMessage
• Objeto Java serializado
argonavis.com.br
© 2003 Helder L. S. da Rocha
44
4 - 22
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Criação de mensagens
• Para cada tipo de mensagem, Session fornece método create()
• createMessage(), createTextMessage(), createBytesMessage(),
createObjectMessage(), createMapMessage(), createStreamMessage()
TextMessage message =
queueSession.createTextMessage();
message.setText(msg_text); // msg_text é String
sender.send(message);
• Após receber uma mensagem, via receive() ou onMessage(), é
preciso fazer o cast para ter acesso aos métodos específicos de
cada tipo de mensagem
Message m = receiver.receive();
if (m instanceof TextMessage) {
TextMessage message = (TextMessage) m;
System.out.println("Recebido: " + message.getText());
}
45
argonavis.com.br
Exemplos de aplicações
•Os exemplos são do capítulo 4 do JMS Tutorial (Sun)
•As versões em exemplos/jms foram alteradas
•Todas estão nos pacotes jmstut.topic ou jmstut.queue
•Há alvos prontos no Ant. Rode-os em duas ou três
janelas e mude a ordem (rode o produtor antes e
depois inverta)
•Aplicação ponto-a-ponto (rode em janelas diferentes)
> ant create-messages-queue
> ant receive-messages-queue (leitura síncrona)
•Aplicação pub/sub
> ant create-messages-topic
> ant receive-messages-topic (leitura assíncrona)
argonavis.com.br
© 2003 Helder L. S. da Rocha
46
4 - 23
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
JAX-RPC (Web Services)
• Implementação de SOAP-RPC em Java
•SOAP: protocolo de comunicação baseado em XML que usa
HTTP ou SMTP como transporte
•SOAP: padrão da indústria - permite a comunicação entre
plataformas diferentes (ex: J2EE e .NET)
• Parte integrante do Java Web Services Development Pack
• Principais componentes do JWSDP
•API SOAP-RPC: javax.xml.rpc.* e javax.xml.soap
•API SOAP Messaging (JAXM): javax.xml.messaging
•Registro UDDI: javax.xml.registry
•Servlet que funciona como servidor UDDI 2
•Servlets que controlam serviços JAX-RPC e JAXM
47
argonavis.com.br
WSDL
•Web Service Description Language
•É um documento XML que descreve o serviço
•É possível criar um serviço a partir de um WSDL.
•É possível criar um cliente a partir de um WSDL
•Exemplo de WSDL
<description>
<types> ... XML Schema ... </types>
<message name="..."> ... </message>
<message name="..."> ... </message> ...
<portType name="..."> ... </portType>
<binding ...> ...</binding>
<service name="..."> ...
</description>
argonavis.com.br
© 2003 Helder L. S. da Rocha
</service>
48
4 - 24
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Mapeamento WSDL
•WSDL serve apenas para descrever interfaces
•Não serve para ser executada
•Nenhuma aplicação precisa da WSDL (não faz parte da
implementação - é só descrição de interface)
•WSDL pode ser mapeada a linguagens (binding)
•Mapeamento: tipos de dados, estruturas, etc.
•Compiladores SOAP geram código de cliente e servidor a
partir de documentos WSDL (stubs para o cliente,
handlers para o servidor)
•Pode-se gerar a parte do cliente em uma plataforma (ex:
.NET) e a parte do servidor em outra (ex: J2EE),
viabilizando a comunicação entre arquiteturas diferentes.
49
argonavis.com.br
Do WSDL a um Web Service
1
É preciso
implementar
...
Hello.wsdl
<operation
name="sayHello">
...
wsdl to
java
É preciso
implementar
wsdl to
C#
3
5
HelloClient.java
Hello h =(Hello)
ctx.lookup("hello");
h.sayHello();
2
Stub
Stub
Stubs
Java
compiler
HelloClient
lookup()
Stub
Stub
Handlers
6
UDDI
HelloImpl.cpp
void sayHello {
print("Hello");
}
C++ compiler
& linker
register()
Servlet
WSDL
stub
argonavis.com.br
© 2003 Helder L. S. da Rocha
SOAP
HelloImpl
handler
(serv remoto)
50
4 - 25
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Compilação do WSDL (JWSDP 1.0)
? O WSDL pode ser compilado para gerar todas as classes
necessárias (cliente e servidor) ou apenas um dos lados
> xrpcc -client hello.wdsl
> xrpcc -server hello.wsdl
<?xml
<?xml version="1.0"
version="1.0" encoding="UTF-8"?>
encoding="UTF-8"?>
(só classes essenciais para o cliente)
(só classes essenciais para o servidor)
? Ex: Classes geradas no cliente
<definitions
<definitions name="HelloService"
name="HelloService" ...
... >>
<types/>
<types/>
<message
<message name="HelloIF_sayHello">
name="HelloIF_sayHello">
<part
<part name="String_1"
name="String_1" type="xsd:string"/>
type="xsd:string"/>
</message>
</message>
<message
<message name="HelloIF_sayHelloResponse">
name="HelloIF_sayHelloResponse">
<part
<part name="result"
name="result" type="xsd:string"/>
type="xsd:string"/>
</message>
</message>
<portType
<portType name="HelloIF">
name="HelloIF">
<operation
<operation name="sayHello"
name="sayHello" ...
... >>
<input
<input message="tns:HelloIF_sayHello"/>
message="tns:HelloIF_sayHello"/>
<output
message="tns:HelloIF_sayHelloResponse"/>
<output message="tns:HelloIF_sayHelloResponse"/>
</operation>
</operation>
</portType>
</portType>
<binding
<binding ...>
...> ...</binding>
...</binding>
example/
service/
HelloIFStub.class
HelloIF.class
HelloIF_Impl.class
HelloService.class
HelloService_Impl.class
HelloService_SerializerRegistry.class
Hello_sayHello_RequestStruct.class
Hello_sayHello_ResponseStruct.class
Hello_sayHello_RequestStruct
_SOAPSerializer.class
Hello_sayHello_ResponseStruct
_SOAPSerializer.class
<service
<service name="HelloService">
name="HelloService">
<port
<port name="HelloIFPort"
name="HelloIFPort" ...>
...>
<soap:address
<soap:address location="http://localhost:8080/jaxrpc-hello/hellopoint/HelloIF"/>
location="http://localhost:8080/jaxrpc-hello/hellopoint/HelloIF"/>
</port>
</port>
</service>
</service>
</definitions>
hello.wsdl
</definitions>
argonavis.com.br
51
Criação de um Web Service com JAX-RPC
1. Escrever uma interface RMI para o serviço
package
package example.service;
example.service;
public
interface
public interface BookstoreIF
BookstoreIF extends
extends java.rmi.Remote
java.rmi.Remote {{
public
public BigDecimal
BigDecimal getPrice(String
getPrice(String isbn)
isbn)
throws
throws java.rmi.RemoteException;
java.rmi.RemoteException;
}}
2. Implementar a interface
package
package example.service;
example.service;
public
public class
class BookstoreImpl
BookstoreImpl implements
implements BookstoreIF
BookstoreIF {{
private
private BookstoreDB
BookstoreDB database
database == DB.getInstance();
DB.getInstance();
public
BigDecimal
getPrice(String
public BigDecimal getPrice(String isbn)
isbn) {{
return
database.selectPrice(isbn);
return database.selectPrice(isbn);
}}
}}
argonavis.com.br
© 2003 Helder L. S. da Rocha
52
4 - 26
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Criação de um Web Service com JAX-RPC
3. Escrever arquivo de configuração*
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
<service name="BookstoreService" targetNamespace="http://mybooks.org/wsdl"
typeNamespace="http://mybooks.org/types"
packageName="example.service">
<interface name="example.service.BookstoreIF"
servantName="example.service.BookstoreImpl"/>
</service>
</configuration>
config_rmi.xml
4. Compilar classes e interfaces RMI
> javac -d mydir BookstoreIF.java BookstoreImpl.java
5. Gerar código do servidor
gendir/
> xrpcc -classpath mydir
-server -keep
-d gendir
config_rmi.xml
* Não faz parte da especificação - procedimento pode mudar no futuro
argonavis.com.br
53
Criação de um Web Service com JAX-RPC
•6. Criar web deployment descriptor web.xml
<web-app>
<servlet>
Nosso
<servlet-name>JAXRPCEndpoint</servlet-name>
"container"
<servlet-class>
com.sun.xml.rpc.server.http.JAXRPCServlet
</servlet-class>
<init-param>
<param-name>configuration.file</param-name>
<param-value>
/WEB-INF/BookstoreService_Config.properties
</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
Nome do arquivo
</servlet>
<servlet-mapping>
gerado pelo xrpcc
<servlet-name>JAXRPCEndpoint</servlet-name>
<url-pattern>/bookpoint/*</url-pattern>
</servlet-mapping>
subcontexto que será
</web-app>
o endpoint do serviço
argonavis.com.br
© 2003 Helder L. S. da Rocha
54
4 - 27
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Criação de um Web Service com JAX-RPC
•7. Colocar tudo em um WAR
8. Deployment no
servidor
Copiar arquivo para
diretório webapps
do Tomcat
webapps/
jaxrpc-bookstore.war
argonavis.com.br
55
Construção e instalação do serviço
com o Ant
•Script do Ant para compilar as classes RMI, compilálas com xrpcc, gerar o WSDL, empacotar no WAR e
copiar para o diretório webapps/ do Tomcat
> ant BUILD.ALL.and.DEPLOY
•Teste para saber se o serviço está no ar
•Inicie o Tomcat do JWSDP
•Acesse: http://localhost:8080/jaxrpc-bookstore/bookpoint
argonavis.com.br
© 2003 Helder L. S. da Rocha
56
4 - 28
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Clientes JAX-RPC
Cliente de implementação estática
+ performance, + acoplamento
2. Chama o serviço
Service
endpoint
stub (1)
WSDL
Clientes de implementação dinâmica
proxy (3)
1. Obtém informações
sobre o serviço
dynamic (2)
- performance, - acoplamento
argonavis.com.br
57
Conclusão (sobre soluções Java)
• Use RMI sobre JRMP se
• Sua aplicação é 100% Java e sempre vai ser 100% Java
• Você não precisa de um sistema de nomes distribuído e hierárquico
• Os seus objetos nunca mudam de servidor
• Quiser usar recursos exclusivos do RMI (activation, DGC, download)
• Use RMI sobre IIOP se você
• Prefere o modelo de desenvolvimento Java RMI
• Quer usufruir da escalabilidade e interoperabilidade do CORBA
• Use Java IDL se você
• Já tem um sistema especificado através de IDLs e precisa criar clientes
ou servidores que se comuniquem via IIOP
• Use JMS (Messaging) para
• Serviços assíncronos e pouco acoplados
• Use JAX-RPC se você
• Precisa de integração dinâmica com outras plataformas (ex: .NET)
argonavis.com.br
© 2003 Helder L. S. da Rocha
58
4 - 29
UNIFACS Pós-graduação em Sistemas e Aplicações Web
Plataformas para Aplicações Distribuídas
4 - Aplicações Distribuídas em Java: Parte I
Fontes
[1] Sun
Microsystems. RMI-IIOP Tutorial. http://java.sun.com/j2se/1.4/docs/guide/rmi-iiop/
Ponto de partida para tutoriais e especificações sobre RMI-IIOP (documentação do J2SDK 1.4)
[2]
Ed Roman et al. Mastering EJB 2, Appendixes A and B: RMI-IIOP, JNDI and Java IDL
http://www.theserverside.com/books/masteringEJB/index.jsp
[3]
Jim Farley. Java Distributed Computing. O'Reilly and Associates, 1998. Esta é a primeira edição
Contém um breve e objetivo tutorial sobre os três assuntos
(procure a segunda). Compara várias estratégias de computação distribuída em Java.
Helder da Rocha, Análise Comparativa de Dempenho entre Tecnologias Distribuídas Java.
UFPB, 1999, Tese de Mestrado.
[5] Qusay H. Mahmoud Distributed Java Programming with RMI and CORBA
http://developer.java.sun.com/developer/technicalArticles/RMI/rmi_corba/ Sun, Maio 2002. Artigo que
[4]
compara RMI com CORBA e desenvolve uma aplicação que transfere arquivos remotos em RMI e CORBA
[6]
David Flanagan et al. Java Enterprise in a Nutshell, 2nd. edition. Abril 2002 (O'Reilly). Oferece
tutoriais sobre as tecnologias Java para ambientes distribuídos, incluindo RMI, RMI-IIOP e Java IDL
Kim Haase. The JMS Tutorial. Sun Microsystems, 2002 http://java.sun.com/products/jms/tutorial/
[8] Sun Microsystems. The Java Message Service Specification
[7]
http://www.javasoft.com/products/jms/docs.html
[9] JSR-101
Expert Group. Java™ API for XML-based RPC: JAX-RPC 1.0 Specification. Java
Community Process: www.jcp.org.
[10] Sun Microsystems. Java™ Web Services Tutorial. java.sun.com/webservices/. Coleção de
tutoriais sobre XML, JSP, servlets, Tomcat, SOAP, JAX-RPC, JAXM, etc.
argonavis.com.br
59
Plataformas para Aplicações Distribuídas
Versão 1.0
© 2003, Helder da Rocha
www.argonavis.com.br
argonavis.com.br
© 2003 Helder L. S. da Rocha
60
4 - 30
Download