Introdução á Computação Distribuída com RMI


A tecnologia RMI - Remote Method Invocation (Invocação de Métodos Remotos), foi
primeiramente introduzida no Java, no JDK versão 1.1, elevando a programação para
redes em um patamar mais elevado. Apesar do RMI ser relativamente fácil, ele põe o
desenvolvedor Java frente à um novo paradigma, o mundo da computação de objectos
distribuídos.




Este guia prático vai lhe introduzir à esta tecnologia versátil, que melhorou muito desde
sua primeira versão.




O principal objectivo 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 objectos trabalham em uma única Java Virtual
Machine (JVM) para um novo modelo de como as classes e objectos trabalhariam num
ambiente distribuído de computação (múltiplas JVMs). Os arquitectos do RMI tentaram
fazer com que o uso dos objectos distribuídos em Java fosse similar ao uso de objectos
Java locais.




Esta secção introduz a arquitectura RMI da perspectiva dos objectos Java remotos
distribuídos, e explora as diferenças de comportamento com objectos locais. A
arquitectura RMI define como os objectos se comportam, como e quando excepções
podem ocorrer, como a memória é gerida e como os parâmetros são passados e
retornados de métodos remotos.


A arquitectura RMI estende a segurança e robustez da arquitectura Java para o mundo
da computação distribuída.




A arquitectura RMI é baseada em um importante princípio: a definição do
comportamento e a implementação do comportamento são conceitos separados. RMI
permite que o código que define o comportamento e o código que implementa o
comportamento permanecerem separados e rodarem em JVMs separadas.


Em RMI, a definição do serviço remoto é codificada usando uma interface Java. A



                                                                             Página 1 de 11
implementação do serviço remoto é codificada em uma classe. Logo, a chave para se
entender o RMI é lembrar que as interfaces definem o comportamento e as classes
definem a implementação.




A classe que implementa o comportamento roda do lado do servidor RMI. A classe que
roda no cliente actua como um Proxy para o serviço remoto. Veja o seguinte diagrama:




O programa cliente faz chamadas de métodos pelo objecto Proxy, o RMI envia a
requisição para a JVM remota e redirecciona para a implementação. Qualquer valor
retornado pela implementação é devolvido ao Proxy e então ao programa cliente.


Com o entendimento da arquitectura RMI num alto nível, vamos dar uma breve olhada
na sua implementação.




A implementação do RMI é essencialmente feita de três camadas de abstracção. A
camada Stub e Skeleton está abaixo dos olhos do desenvolvedor. Esta camada
intercepta as chamadas de métodos feitas pelo cliente para que a variável de referência
da interface redirecione essas chamadas para o serviço RMI remoto.


A próxima camada é a Remote Reference Layer. Esta camada sabe como interpretar e
gerir referências feitas dos clientes para os objectos do serviço remoto. A conexão do
cliente ao servidor é Unicast (uma-para-um).


A camada de transporte é baseada nas conexões TCP/IP entre as maquinas em uma
rede.


Usando essa arquitectura de camadas, cada uma das camadas poderia ser facilmente



                                                                          Página 2 de 11
melhorada ou substituída sem afectar o resto do sistema. Por exemplo, a camada de
transporte poderia ser substituída por uma camada que implemente conexões UDP/IP,
sem afectar as camadas superiores.




Como um cliente acha o serviço remoto RMI?


Os clientes acham os serviços remotos usando o serviço de nomeação ou directório
(naming or directory). Isso parece um pouco redundante, mas o serviço de nomeação
ou directório roda como um endereço bem formado (host:port).


O RMI pode usar diferentes tipos de serviços de directório, incluindo o JNDI. O próprio
RMI inclue um simples serviço, chamado de RMI Registry. O RMI Registry roda em cada
maquina que hospeda o serviço remoto, por definição na porta 1099.


Numa máquina host, um programa servidor cria um serviço remoto, primeiramente
criando o objecto que implemente aquele serviço. Em seguida ele exporta aquele
objecto para o RMI. Quando o objecto é exportado o RMI cria um serviço que aguarda
as conexões do cliente. O servidor registra o objecto no RMI Registry, com um nome
público.


No lado do cliente o RMI Registry é acedido através da classe estática Naming. Ela
provém o método lookup( ), que o cliente usa para requisitar o registro. Esse método
aceita a URL que especifica o nome do servidor e o nome do serviço desejado. O
método retorna uma referência remota para o objecto do serviço. A URL é formada
como seguinte:


rmi://<host_name>[:port_number]/<service_name>




                                                                          Página 3 de 11
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
objecto remoto.


Para tanto não necessitamos de duas máquinas distintas 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




Agora iremos, de fato, criar um sistema que implemente o RMI, utilizando-se de um
programa cliente e um programa servidor. Não utilizaremos um servidor FTP ou HTTP,
no entanto utilizaremos os programas na mesma máquina e uma mesma estrutura de
directórios.


Os passos a serem seguidos agora são:


• Escrever e compilar o código Java da interface
• Escrever e compilar o código Java das implementações das classes
• Gerar as classes Stub e Skeleton das classes de implementação


Crie um directório para salvar todos os seus arquivos de projecto.


Você pode fazer o download do código fonte usado nesse tutorial.


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.



                                                                           Página 4 de 11
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   }




Perceba que esta interface estende a classe Remote, e cada assinatura de método
declara as funcionalidades do serviço, e que podem gerar uma excepção
RemoteException.


Salve este arquivo (Mensageiro.java) no seu directório e compile, com a seguinte linha
de comando:


javac Mensageiro.java




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.




01   import java.rmi.RemoteException;
02   import java.rmi.server.UnicastRemoteObject;
03
04   public class MensageiroImpl extends UnicastRemoteObject implements Mensageiro {
05
06        public MensageiroImpl() throws RemoteException {
07            super();
08        }
09
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   }




Salve este arquivo (MensageiroImpl.java) no seu directório e compile, com a seguinte
linha de comando:



                                                                         Página 5 de 11
javac MensageiroImpl.java




Observe que a classe se utiliza (estende) da classe UnicastRemoteObject para ligar com
o sistema RMI. Neste exemplo a classe estende a classe UnicastRemoteObject
directamente. Isto não é realmente necessário, mas essa discussão fica para uma
próxima etapa.


Quando uma classe estende a classe UnicastRemoteObject, ele deve prover um
construtor que declare que ele pode lançar uma exceção RemoteException, pois quando
o método super( ) é chamado, ele activa o código em UnicastRemoteObject, que
executa a ligação RMI e a iniciação do objecto remoto.




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.


rmic MensageiroImpl




Após a execução deste comando, você deveria ver no seu diretório os arquivos
Mensageiro_Stub.class, Mensageiro_Skeleton.class.


Servidor


O serviço remoto RMI deve ser hospedado em um processo servidor. A classe
MensageiroServer é um servidor bem simples, que provê serviços essenciais. Salve o
arquivo como: MensageiroServer.java.




01 import java.rmi.Naming;
02
03 public class MensageiroServer {
04
05     public MensageiroServer() {
06         try {
07             Mensageiro m = new MensageiroImpl();
08             Naming.rebind("rmi://localhost:1099/MensageiroService", m);



                                                                        Página 6 de 11
09           }
                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 }




                Salve este arquivo (MensageiroServer.java) no seu diretório e compile, com a seguinte
                linha de comando:


                > javac MensageiroServer.java


                O código fonte para o cliente é o seguinte. Salve o arquivo como:
                MensageiroClient.java.




01   import   java.rmi.Naming;
02   import   java.rmi.RemoteException;
03   import   java.rmi.NotBoundException;
04   import   java.net.MalformedURLException;
05
06   public class MensageiroClient {
07
08       public static void main( String args[] ) {
09           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   }




                                                                                        Página 7 de 11
Salve este arquivo (MensageiroClient.java) no seu diretório e compile, com a seguinte
linha de comando:


javac MensageiroClient.java




Agora que todos os arquivos do projeto de exemplo foram criados e devidamente
compilados, estamos prontos para rodar o sistema! Você precisará abrir três diferentes
consoles do MS-DOS no seu Windows, ou outro, caso utilize um diferente sistema
operacional.


Em um dos consoles vai rodar o programa servidor, no outro o cliente e no terceiro o
RMI Registry.


Inicie com o RMI Registry. Você deve estar no mesmo diretório em que estão gravados
seus arquivos para rodar o aplicativo. Execute a seguinte linha de comando:


rmiregistry




Isso irá iniciar o RMI Registry e rodá-lo.


No segundo console vamos executar o programa servidor. Você deve estar no mesmo
directório em que estão gravados seus arquivos para rodar o aplicativo. Execute o
seguinte comando:


java MensageiroServer




Isso irá iniciar, carregar a implementação na memória e esperar pela conexão cliente.


No último console, rode o programa cliente. Você deve estar no mesmo directório em
que estão gravados seus arquivos para rodar o aplicativo. Execute o comando:


java MensageiroClient




                                                                         Página 8 de 11
Se tudo correr bem, que é o que esperamos e o que deveria acontecer, a seguinte saída
será gerada nos consoles 2 (servidor) e 3 (cliente).
No console 2 (servidor):


Hellow World!




No console 3 (cliente):


This is not a Hello World! message



É isso aí. Você acabou de criar um sistema utilizando a tecnologia RMI. Apesar de você
ter rodado os programas na mesma máquina, o RMI usa a pilha de rede TCP/IP para se
comunicar entre as três diferentes instâncias da JVM.

Exercício:

    1. Defina a Interface Remota
        import java.rmi.Remote;
        import java.rmi.RemoteException;
        import java.math.BigInteger;


        public interface Operator extends Remote {
          BigInteger add(BigInteger b1, BigInteger b2) throws RemoteException;
          BigInteger subtract(BigInteger b1, BigInteger b2) throws RemoteException;
          BigInteger divide(BigInteger b1, BigInteger b2) throws RemoteException;
          BigInteger multiply(BigInteger b1, BigInteger b2) throws RemoteException;
        }

    2. Compile a Interface
       Javac Operator.java

    3. Implementer a Interface Remota

        import   java.rmi.RemoteException;
        import   java.math.BigInteger;
        import   java.rmi.server.UnicastRemoteObject;
        import   java.rmi.Naming;

        public class OperatorServer extends UnicastRemoteObject implements Operator
        {
          public OperatorServer() throws RemoteException { }
          public BigInteger add(BigInteger b1, BigInteger b2) throws RemoteException {
            return b1.add(b2);
          }




                                                                        Página 9 de 11
public BigInteger subtract(BigInteger b1, BigInteger b2) throws
   RemoteException {
       return b1.subtract(b2);
     }
     public BigInteger divide(BigInteger b1, BigInteger b2) throws RemoteException
   {
       return b1.divide(b2);
     }
     public BigInteger multiply(BigInteger b1, BigInteger b2) throws
   RemoteException {
       return b1.multiply(b2);
     }
    public static void main(String []args) {
       String name = "//localhost/OperatorServer";
       try {
         OperatorServer os = new OperatorServer();
         Naming.rebind(name,os);
         System.out.println(name + " bound");
       } catch (Exception e) {
         System.err.println("OperatorServer exception: " + e.getMessage());
         e.printStackTrace();
       }
     }
   }


4. Compile a classe servidor
   javac OperatorServer.java

5. Crie o Stub e o Skeleton
   rmic OperatorServer

6. Verifique se as seguintes classes estão criadas

   OperatorServer.class
   OperatorServer.java
   OperatorServer_Skel.class
   OperatorServer_Stub.class

7. Crie a classe cliente

   import java.rmi.Naming;
   import java.math.BigInteger;

   public class OperatorClient {

     public static void main(String args[]) {
      String name = "//localhost/OperatorServer";
      try {
      Operator o = (Operator)Naming.lookup (name);

      BigInteger b1 = new BigInteger("1234567");
      BigInteger b2 = new BigInteger("1");
      BigInteger b3 = o.add(b1, b2);
      System.out.println("b3: " + b3);

      } catch( Exception e) {
        System.out.println(e); e.printStackTrace();
      }




                                                                  Página 10 de 11
}
   }

8. Compile a classe cliente
   Javac OperatorClient.java

9. Abra um consola do MS DOS
    rmiregistry
10. Abra a 2ª consola do MS DOS – execução da aplicação servidor
    java OperatorServer

    Vais mostrar: //localhost/OperatorServerbound
11. Abra a 3ª consola do MS DOS – execução da aplicação cliente
    java OperatorClient

   Vais mostrar: 1234568




                                                                   Página 11 de 11

Computacao distribuida com rmi

  • 1.
    Introdução á ComputaçãoDistribuída com RMI A tecnologia RMI - Remote Method Invocation (Invocação de Métodos Remotos), foi primeiramente introduzida no Java, no JDK versão 1.1, elevando a programação para redes em um patamar mais elevado. Apesar do RMI ser relativamente fácil, ele põe o desenvolvedor Java frente à um novo paradigma, o mundo da computação de objectos distribuídos. Este guia prático vai lhe introduzir à esta tecnologia versátil, que melhorou muito desde sua primeira versão. O principal objectivo 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 objectos trabalham em uma única Java Virtual Machine (JVM) para um novo modelo de como as classes e objectos trabalhariam num ambiente distribuído de computação (múltiplas JVMs). Os arquitectos do RMI tentaram fazer com que o uso dos objectos distribuídos em Java fosse similar ao uso de objectos Java locais. Esta secção introduz a arquitectura RMI da perspectiva dos objectos Java remotos distribuídos, e explora as diferenças de comportamento com objectos locais. A arquitectura RMI define como os objectos se comportam, como e quando excepções podem ocorrer, como a memória é gerida e como os parâmetros são passados e retornados de métodos remotos. A arquitectura RMI estende a segurança e robustez da arquitectura Java para o mundo da computação distribuída. A arquitectura RMI é baseada em um importante princípio: a definição do comportamento e a implementação do comportamento são conceitos separados. RMI permite que o código que define o comportamento e o código que implementa o comportamento permanecerem separados e rodarem em JVMs separadas. Em RMI, a definição do serviço remoto é codificada usando uma interface Java. A Página 1 de 11
  • 2.
    implementação do serviçoremoto é codificada em uma classe. Logo, a chave para se entender o RMI é lembrar que as interfaces definem o comportamento e as classes definem a implementação. A classe que implementa o comportamento roda do lado do servidor RMI. A classe que roda no cliente actua como um Proxy para o serviço remoto. Veja o seguinte diagrama: O programa cliente faz chamadas de métodos pelo objecto Proxy, o RMI envia a requisição para a JVM remota e redirecciona para a implementação. Qualquer valor retornado pela implementação é devolvido ao Proxy e então ao programa cliente. Com o entendimento da arquitectura RMI num alto nível, vamos dar uma breve olhada na sua implementação. A implementação do RMI é essencialmente feita de três camadas de abstracção. A camada Stub e Skeleton está abaixo dos olhos do desenvolvedor. Esta camada intercepta as chamadas de métodos feitas pelo cliente para que a variável de referência da interface redirecione essas chamadas para o serviço RMI remoto. A próxima camada é a Remote Reference Layer. Esta camada sabe como interpretar e gerir referências feitas dos clientes para os objectos do serviço remoto. A conexão do cliente ao servidor é Unicast (uma-para-um). A camada de transporte é baseada nas conexões TCP/IP entre as maquinas em uma rede. Usando essa arquitectura de camadas, cada uma das camadas poderia ser facilmente Página 2 de 11
  • 3.
    melhorada ou substituídasem afectar o resto do sistema. Por exemplo, a camada de transporte poderia ser substituída por uma camada que implemente conexões UDP/IP, sem afectar as camadas superiores. Como um cliente acha o serviço remoto RMI? Os clientes acham os serviços remotos usando o serviço de nomeação ou directório (naming or directory). Isso parece um pouco redundante, mas o serviço de nomeação ou directório roda como um endereço bem formado (host:port). O RMI pode usar diferentes tipos de serviços de directório, incluindo o JNDI. O próprio RMI inclue um simples serviço, chamado de RMI Registry. O RMI Registry roda em cada maquina que hospeda o serviço remoto, por definição na porta 1099. Numa máquina host, um programa servidor cria um serviço remoto, primeiramente criando o objecto que implemente aquele serviço. Em seguida ele exporta aquele objecto para o RMI. Quando o objecto é exportado o RMI cria um serviço que aguarda as conexões do cliente. O servidor registra o objecto no RMI Registry, com um nome público. No lado do cliente o RMI Registry é acedido através da classe estática Naming. Ela provém o método lookup( ), que o cliente usa para requisitar o registro. Esse método aceita a URL que especifica o nome do servidor e o nome do serviço desejado. O método retorna uma referência remota para o objecto do serviço. A URL é formada como seguinte: rmi://<host_name>[:port_number]/<service_name> Página 3 de 11
  • 4.
    Agora vamos trabalharcom um sistema que realmente implementa um sistema com RMI. Vamos criar um aplicativo simples, cliente e servidor, que executa métodos do objecto remoto. Para tanto não necessitamos de duas máquinas distintas 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 Agora iremos, de fato, criar um sistema que implemente o RMI, utilizando-se de um programa cliente e um programa servidor. Não utilizaremos um servidor FTP ou HTTP, no entanto utilizaremos os programas na mesma máquina e uma mesma estrutura de directórios. Os passos a serem seguidos agora são: • Escrever e compilar o código Java da interface • Escrever e compilar o código Java das implementações das classes • Gerar as classes Stub e Skeleton das classes de implementação Crie um directório para salvar todos os seus arquivos de projecto. Você pode fazer o download do código fonte usado nesse tutorial. 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. Página 4 de 11
  • 5.
    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 } Perceba que esta interface estende a classe Remote, e cada assinatura de método declara as funcionalidades do serviço, e que podem gerar uma excepção RemoteException. Salve este arquivo (Mensageiro.java) no seu directório e compile, com a seguinte linha de comando: javac Mensageiro.java 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. 01 import java.rmi.RemoteException; 02 import java.rmi.server.UnicastRemoteObject; 03 04 public class MensageiroImpl extends UnicastRemoteObject implements Mensageiro { 05 06 public MensageiroImpl() throws RemoteException { 07 super(); 08 } 09 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 } Salve este arquivo (MensageiroImpl.java) no seu directório e compile, com a seguinte linha de comando: Página 5 de 11
  • 6.
    javac MensageiroImpl.java Observe quea classe se utiliza (estende) da classe UnicastRemoteObject para ligar com o sistema RMI. Neste exemplo a classe estende a classe UnicastRemoteObject directamente. Isto não é realmente necessário, mas essa discussão fica para uma próxima etapa. Quando uma classe estende a classe UnicastRemoteObject, ele deve prover um construtor que declare que ele pode lançar uma exceção RemoteException, pois quando o método super( ) é chamado, ele activa o código em UnicastRemoteObject, que executa a ligação RMI e a iniciação do objecto remoto. 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. rmic MensageiroImpl Após a execução deste comando, você deveria ver no seu diretório os arquivos Mensageiro_Stub.class, Mensageiro_Skeleton.class. Servidor O serviço remoto RMI deve ser hospedado em um processo servidor. A classe MensageiroServer é um servidor bem simples, que provê serviços essenciais. Salve o arquivo como: MensageiroServer.java. 01 import java.rmi.Naming; 02 03 public class MensageiroServer { 04 05 public MensageiroServer() { 06 try { 07 Mensageiro m = new MensageiroImpl(); 08 Naming.rebind("rmi://localhost:1099/MensageiroService", m); Página 6 de 11
  • 7.
    09 } 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 } Salve este arquivo (MensageiroServer.java) no seu diretório e compile, com a seguinte linha de comando: > javac MensageiroServer.java O código fonte para o cliente é o seguinte. Salve o arquivo como: MensageiroClient.java. 01 import java.rmi.Naming; 02 import java.rmi.RemoteException; 03 import java.rmi.NotBoundException; 04 import java.net.MalformedURLException; 05 06 public class MensageiroClient { 07 08 public static void main( String args[] ) { 09 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 } Página 7 de 11
  • 8.
    Salve este arquivo(MensageiroClient.java) no seu diretório e compile, com a seguinte linha de comando: javac MensageiroClient.java Agora que todos os arquivos do projeto de exemplo foram criados e devidamente compilados, estamos prontos para rodar o sistema! Você precisará abrir três diferentes consoles do MS-DOS no seu Windows, ou outro, caso utilize um diferente sistema operacional. Em um dos consoles vai rodar o programa servidor, no outro o cliente e no terceiro o RMI Registry. Inicie com o RMI Registry. Você deve estar no mesmo diretório em que estão gravados seus arquivos para rodar o aplicativo. Execute a seguinte linha de comando: rmiregistry Isso irá iniciar o RMI Registry e rodá-lo. No segundo console vamos executar o programa servidor. Você deve estar no mesmo directório em que estão gravados seus arquivos para rodar o aplicativo. Execute o seguinte comando: java MensageiroServer Isso irá iniciar, carregar a implementação na memória e esperar pela conexão cliente. No último console, rode o programa cliente. Você deve estar no mesmo directório em que estão gravados seus arquivos para rodar o aplicativo. Execute o comando: java MensageiroClient Página 8 de 11
  • 9.
    Se tudo correrbem, que é o que esperamos e o que deveria acontecer, a seguinte saída será gerada nos consoles 2 (servidor) e 3 (cliente). No console 2 (servidor): Hellow World! No console 3 (cliente): This is not a Hello World! message É isso aí. Você acabou de criar um sistema utilizando a tecnologia RMI. Apesar de você ter rodado os programas na mesma máquina, o RMI usa a pilha de rede TCP/IP para se comunicar entre as três diferentes instâncias da JVM. Exercício: 1. Defina a Interface Remota import java.rmi.Remote; import java.rmi.RemoteException; import java.math.BigInteger; public interface Operator extends Remote { BigInteger add(BigInteger b1, BigInteger b2) throws RemoteException; BigInteger subtract(BigInteger b1, BigInteger b2) throws RemoteException; BigInteger divide(BigInteger b1, BigInteger b2) throws RemoteException; BigInteger multiply(BigInteger b1, BigInteger b2) throws RemoteException; } 2. Compile a Interface Javac Operator.java 3. Implementer a Interface Remota import java.rmi.RemoteException; import java.math.BigInteger; import java.rmi.server.UnicastRemoteObject; import java.rmi.Naming; public class OperatorServer extends UnicastRemoteObject implements Operator { public OperatorServer() throws RemoteException { } public BigInteger add(BigInteger b1, BigInteger b2) throws RemoteException { return b1.add(b2); } Página 9 de 11
  • 10.
    public BigInteger subtract(BigIntegerb1, BigInteger b2) throws RemoteException { return b1.subtract(b2); } public BigInteger divide(BigInteger b1, BigInteger b2) throws RemoteException { return b1.divide(b2); } public BigInteger multiply(BigInteger b1, BigInteger b2) throws RemoteException { return b1.multiply(b2); } public static void main(String []args) { String name = "//localhost/OperatorServer"; try { OperatorServer os = new OperatorServer(); Naming.rebind(name,os); System.out.println(name + " bound"); } catch (Exception e) { System.err.println("OperatorServer exception: " + e.getMessage()); e.printStackTrace(); } } } 4. Compile a classe servidor javac OperatorServer.java 5. Crie o Stub e o Skeleton rmic OperatorServer 6. Verifique se as seguintes classes estão criadas OperatorServer.class OperatorServer.java OperatorServer_Skel.class OperatorServer_Stub.class 7. Crie a classe cliente import java.rmi.Naming; import java.math.BigInteger; public class OperatorClient { public static void main(String args[]) { String name = "//localhost/OperatorServer"; try { Operator o = (Operator)Naming.lookup (name); BigInteger b1 = new BigInteger("1234567"); BigInteger b2 = new BigInteger("1"); BigInteger b3 = o.add(b1, b2); System.out.println("b3: " + b3); } catch( Exception e) { System.out.println(e); e.printStackTrace(); } Página 10 de 11
  • 11.
    } } 8. Compile a classe cliente Javac OperatorClient.java 9. Abra um consola do MS DOS rmiregistry 10. Abra a 2ª consola do MS DOS – execução da aplicação servidor java OperatorServer Vais mostrar: //localhost/OperatorServerbound 11. Abra a 3ª consola do MS DOS – execução da aplicação cliente java OperatorClient Vais mostrar: 1234568 Página 11 de 11