Escolar Documentos
Profissional Documentos
Cultura Documentos
Objetivo
O principal objetivo para os criadores (designers) do RMI era permitir os
programadores a desenvolverem programas distribuídos em Java com a mesma
sintaxe e semântica usada em programas não-distribuídos. Para isso, eles tiveram
que mapear cuidadosamente como classes Java e objetos trabalham em uma única
Java Virtual Machine (JVM) para um novo modelo de como as classes e objetos
trabalhariam num ambiente distribuído de computação (múltiplas JVMs). Os
arquitetos do RMI tentaram fazer com que o uso dos objetos distribuídos em Java
fosse similar ao uso de objetos Java locais. Esta seção introduz a arquitetura RMI
da perspectiva dos objetos Java remotos distribuídos, e explora as diferenças de
comportamento com objetos locais. A arquitetura RMI define como os objetos se
comportam, como e quando exceções podem ocorrer, como a memória é
gerenciada e como os parâmetros são passados e retornados de métodos remotos.
1
O programa cliente faz chamadas de métodos pelo objeto Proxy, o RMI envia
a requisição para a JVM remota e redireciona para a implementação. Qualquer valor
retornado pela implementação é devolvido ao Proxy e então ao programa cliente.
1. rmi://<host_name>[:port_number]/<service_name>
Usando o RMI
Agora vamos trabalhar com um sistema que realmente implementa um
sistema com RMI. Vamos criar um aplicativo simples, cliente e servidor, que executa
métodos do objeto remoto. Para tanto não necessitamos de duas máquinas distintas
2
ou com IP distintos. O exemplo pode ser rodado na mesma máquina, pois o RMI
sabe como trabalhar com isso, mesmo que o host e o cliente sejam na mesma
localidade. Um sistema RMI é composto de várias partes:
• Definição das interfaces para os serviços remotos
• Implementações dos serviços remotos
• Arquivos de Stub e Skeletons
• Um servidor para hospedar os serviços remotos
• Um serviço de RMI Naming que permite o cliente achar os serviços
remotos
• Um provedor de arquivos de classes (servidor http ou ftp)
• Um programa cliente que necessita os serviços remotos
Interfaces
O primeiro passo, como dito, será criar a interface e compilá-la. A interface define
todas as funcionalidades remotas oferecidas pelo serviço. Nomeio o arquivo como:
Mensageiro.java.
1. import java.rmi.Remote;
2. import java.rmi.RemoteException;
3.
4. public interface Mensageiro extends Remote {
5.
6. public void enviarMensagem( String msg ) throws RemoteException;
7. public String lerMensagem() throws RemoteException;
8. }
1. javac Mensageiro.java
Implementação
Agora, você deverá escrever a implementação para o serviço remoto, ou
seja, o código a ser executado no ambiente remoto. Nomeia o arquivo como:
MensageiroImpl.java.
1. import java.rmi.RemoteException;
2. import java.rmi.server.UnicastRemoteObject;
3.
4. public class MensageiroImpl extends UnicastRemoteObject implements Mensageiro {
3
5.
6. public MensageiroImpl() throws RemoteException {
7. super();
8. }
9.
10. public void enviarMensagem( String msg ) throws RemoteException {
11. System.out.println( msg );
12. }
13.
14. public String lerMensagem() throws RemoteException {
15. return "This is not a Hello World! message";
16. }
17. }
1. javac MensageiroImpl.java
Stubs e Skeletons
Gere os arquivos Stubs e Skeletons da classe de implementação que roda no
servidor. Para tanto, execute o comando rmic, compilador RMI do JDK.
1. rmic MensageiroImpl
1. import java.rmi.Naming;
2.
3. public class MensageiroServer {
4.
5. public MensageiroServer() {
6. try {
7. Mensageiro m = new MensageiroImpl();
8. Naming.rebind("rmi://localhost:1099/MensageiroService", m);
9. }
10. catch( Exception e ) {
11. System.out.println( "Trouble: " + e );
12. }
13. }
14.
15. public static void main(String[] args) {
16. new MensageiroServer();
17. }
18. }
4
Salve este arquivo (MensageiroServer.java) no seu diretório e compile, com a
seguinte linha de comando: > javac MensageiroServer.java
Cliente
O código fonte para o cliente é o seguinte. Salve o arquivo como:
MensageiroClient.java.
1. import java.rmi.Naming;
2. import java.rmi.RemoteException;
3. import java.rmi.NotBoundException;
4. import java.net.MalformedURLException;
5.
6. public class MensageiroClient {
7.
8. public static void main( String args[] ) {
9. try {
10. Mensageiro m = (Mensageiro) Naming.lookup( "rmi://localhost/MensageiroService" );
11. System.out.println( m.lerMensagem() );
12. m.enviarMensagem( "Hello World!" );
13. }
14. catch( MalformedURLException e ) {
15. System.out.println();
16. System.out.println( "MalformedURLException: " + e.toString() );
17. }
18. catch( RemoteException e ) {
19. System.out.println();
20. System.out.println( "RemoteException: " + e.toString() );
21. }
22. catch( NotBoundException e ) {
23. System.out.println();
24. System.out.println( "NotBoundException: " + e.toString() );
25. }
26. catch( Exception e ) {
27. System.out.println();
28. System.out.println( "Exception: " + e.toString() );
29. }
30. }
31. }
1. javac MensageiroClient.java
1. rmiregistry
5
Isso irá iniciar o RMI Registry e rodá-lo. No segundo console vamos executar
o programa servidor. Você deve estar no mesmo diretório em que estão gravados
seus arquivos para rodar o aplicativo. Execute o seguinte comando:
1. java MensageiroServer
1. java MensageiroClient
1. Hellow World!
No console 3 (cliente):
6
Invocação de Métodos Remotos - RMI
As aplicações do RMI compreendem frequentemente dois programas
separados, um servidor e um cliente. Um programa servidor cria alguns objetos
remotos, faz referência a esses objetos, e aguarda os "clients" invocarem os
métodos desses objetos. Enquanto que um programa cliente obtém uma referência
remota ao objetos criados pelo servidor e invoca os métodos desses objetos.
Entendendo o funcionamento
A seguinte ilustração descreve uma aplicação distribuída RMI que utiliza o
"RMI registry" para obter uma referência a um objeto remoto. O servidor chama o
"registry" para associar (bind) um nome com um objeto remoto. O cliente olha o
objeto remoto por seu nome no "registry" do servidor, e invoca então um método
nele. A ilustração mostra também que o sistema do RMI utiliza um web server
existente para carregar definições da classe, do servidor ao cliente e do cliente ao
servidor, para objetos quando necessário.
Como sempre vamos aos códigos fontes, para esse as explicações serão
inseridas na forma de comentários dentro dos próprios arquivos (assim pouparemos
espaço aqui).
7
Ola.java
Interface que será utilizada tanto pelo servidor quanto pelo cliente, é necessária
para fazer a integração de ambos.
import java.rmi.Remote;
import java.rmi.RemoteException;
OlaImpl.java
Classe que será acessada remotamente pelo Client.java
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
try {
// aqui criamos o objeto que sera acessado
// remotamente
OlaImpl obj = new OlaImpl();
Client.java
Classe que irá rodar do lado do cliente e utilizará o método "showMsg" da classe
OlaImpl que estará rodando do lado do servidor.
import java.rmi.Naming;
8
public static void main(String[] args) {
/*
* obj é o identificados que iremos utilizar para fazer
* referencia ao objeto remoto que será implementado
*/
Ola obj = null;
try {
/*
* - o lookup carrega o OlaImpl_Stub do CLASSPATH
* - 127.0.0.1 é o IP da máquina onde o server
* está rodando, no nosso caso é a mesma máquina
* - OlaServidor é o nome que utilizamos para fazer
* referencia ao objeto no servidor
*/
javac *.java
Além da compilação básica devemos criar uma classe do tipo Stub para a
classe que será acessada remotamente, para criar essa classe devemos rodar o
comando:
rmic OlaImpl
4 - Iniciando a aplicação.
Agora vamos rodar nossa aplicação, vamos abrir dois prompts do DOS, no
primeiro colocamos o server para rodar com o comando:
java OlaImpl
9
Com o servidor rodando vamos para a outra janela do DOS e rodamos o
client com o comando:
java Client
Server
Client
Essa é uma forma muito utilizada para criar aplicações distribuídas, embora
esse artigo pareça simples, ele demonstra a base para esse tipo de comunicação.
10