Tutorial RMI - Invocação remota de métodos

por Paulo César M. Jeveaux
Extraído do site : http://www.portaljava.com.br


RMI (Remote Method Invocation) é uma forma que Java adotou para trabalhar com objetos Java/Java distribuídos. A idéia básica do RMI é obter um conjunto de objetos colaboradores que se comuniquem através de uma rede.
Para entender as aplicações RMI, vamos analisar um problema: supondo a existência de sistema bancário implementado em Java. Neste sistema, cada terminal bancário pode requerer informações dos clientes do banco para um centro de informações. Estas informações, uma vez obtidas, devem retornar ao terminal. Sob o ponto de vista de programação, pode se pensar que o terminal bancário é o cliente e o centro de informações é o servidor.

A implementação deste problema pode ser realizada de várias formas, tais como:
* Abrir uma conexão através de sockets para o envio de dados puros;
* Utilizar JDBC caso o servidor tenha as informações implementadas em um banco de dados relacional;
* Utilizar outras tecnologias como CORBA (Common Object Request Broker Architecture), caso se esteja trabalhando com aplicativos Java/Java e Java/outras linguagens como C++ e SmallTalk;
* Ou implementar o pedido e a resposta da informação como objetos. Neste modelo, através de RMI, os objetos podem ser transportados entre o cliente e o servidor.

Com RMI é possível transportar objetos pela rede e também chamar métodos que estejam em outro computador, mantendo o objeto na máquina remota.
Supondo que o código do computador cliente invoca um método de um objeto no servidor. Para um cliente invocar um método RMI, ele cria um objeto stub que encapsula o pedido do cliente em um pacote de bytes composto por:

* Um identificador do objeto remoto a ser usado;
* Um número de operação para descrever o método a ser invocado;
* Um conjunto de parâmetros codificados (marshalling – processo de codificação dos parâmetros para um formato apropriado para o transporte de rede).

Para o servidor receber a informação que está no stub, ele cria um objeto skeleton. O skeleton executa as seguintes ações:

* Decodifica os parâmetros;
* Chama o método desejado;
* Captura o valor de retorno ou exceção e codifica (marshalling);
* Retorna o valor codificado para o cliente.

O stub decodifica o valor de retorno do servidor, que pode ser uma exceção, mas que em geral é o retorno da chamada do método remoto.
Deve-se ter um cuidado especial no momento em que não estão mais sendo utilizados os objetos remotos. Isto porque o Garbage Collection não pode detectar ligações de objetos remotos não referenciados. Desta forma as ligações devem ser explicitamente quebradas pelo programador.
Sempre que é evocado um método remoto, as classes stub e skeleton serão carregadas com um gerenciador de segurança, que determina o que uma classe pode fazer. Semelhante aos gerenciadores de segurança dos browsers. O gerenciador de segurança é definido pelo programador, no momento da implementação do programa. Java já dispõe de gerenciadores de segurança bastante eficazes, porém, o programador pode criar novos gerenciadores, caso ache necessário.
Para realizar uma operação RMI, é preciso criar, tanto do lado do cliente, quanto do lado do servidor, uma interface para o objeto que será referenciado. Isto porque o cliente, embora não tenha o objeto real, que está no servidor, deve saber as ações que pode executar sobre este objeto (o protocolo).

Primeiro Programa RMI



O primeiro arquivo a analisar é a interface apresentada no arquivo Hello.java. Esta interface informa a existência de um único método: sayHello(), este método tem a função de retornar uma String para um objeto remoto.
Todas as interfaces RMI, devem ser derivadas da classe java.rmi.Remote e devem ter o tratamento de suas exceções realizadas através da java.rmi.RemoteException, para que as exceções sejam repassadas remotamente.

public interface Hello extends java.rmi.Remote {

        String sayHello() throws java.rmi.RemoteException;

}


O arquivo HelloImpl.java contém a classe HelloImpl, que implementa a interface Hello no servidor.
HelloImpl é uma subclasse da classe UnicastRemoteObject que é derivada da classe RemoteServer. A RemoteServer é uma classe abstrata, utilizada para a implementação de RMI pela linguagem Java. Esta classe inicia uma thread, que metem o objeto HelloImpl ativo, a fim de que clientes possam se conectar ao programa.

import java.rmi.*;

import java.rmi.server.UnicastRemoteServer;

 

public class HelloImpl extends UnicastRemoteServer implements Hello {

        private String nome;

        public HelloImpl(String s) throws java.rmi.RemoteException {

               super();
               nome = s;

        }

        public String sayHello() throws RemoteException {

               return “Hello World !!!”;

        }

        public static void main(String[] args) {

               System.setSecurityManager(new RMISecurityManager());

               try {

                       HelloImpl obj = new HelloImpl(“HelloServer”);

                       Naming.rebind(“HelloServer”, obj);

                       System.out.println(“HelloImpl foi criado e registrado”);
               }

               catch(Exception e) {

                       System.out.println(“Ocorreu uma exceção no servidor”);

                       e.printStacktrace();

               }

        }

}


Ao ser criada a classe HelloImpl, o gerenciador de segurança RMI (RMISecurityManager) é criado e instalado através do código:
System.setSecurityManager(new RMISecurityManager());
O objeto obj, passa a ser construído, com o construtor da classe, e cadastrado no sistema operacional, através do método rebind(String str, Remote r) da classe Naming. A classe Naming fornece um mecanismo para obter referencias a objetos remotos baseados na sintaxe da URL. Onde uma URL para objetos remotos é usualmente especificada pelo Host, porta e nome: rmi://host:porta/nome.

Naming.rebind(“HelloServer”, obj);

O cliente RMI está implementado através de um applet, na classe HelloApplet.

import java.awt.*;

import java.rmi.*;

 

public class HelloApplet extends java.Applet.Applet {

        String mensagem = “”;

        Public void init() {

               try {

                       Hello obj = (Hello)Naming.lookup(“//”+getCodeBase().getHost()                  + “/HelloServer”);

                       mensagem = obj.sayHello();

               }

               catch(Exception e) {

                       System.out.println(“Ocorreu uma exceção”);

                       e.printStackTrace();

               }

        }

        public void paint(Graphics g) {

               g.drawString(mensagem, 25, 50);

        }

}


O applet, ao ser inicializado, chama o método init(). Este por sua vez cria um objeto Hello, a partir de um cadastro em uma máquina Remota (servidor). Para tanto, fornece a URL deste objeto para o método lookup(String url). Como este método retorna genericamente um objeto do tipo Remote, deve ser colocado um cast explícito para o objeto que está sendo criado, no caso (Hello).

Hello obj = (Hello)Naming.lookup(“//”+getCodeBase().getHost() + “/HelloServer”);

Através da interface, a classe cliente pode ter conhecimento dos métodos que pode evocar remotamente. Neste caso apenas o método abaixo:

mensagem = obj.sayHello();
A mensagem será exibida através do método drawString(String s, int x, int y), sempre que o browser chamar o método paint(Graphics g).
Para executar o programa, foi criado um arquivo de batch chamado de Run.bat. Este arquivo contém as seguintes linhas:

javac *.java
start /min rmiregistry
rmic HelloImpl
start java HelloImpl
pause
appletviewer cliente.html

A instrução javac *.java força a compilação de todos os arquivos .java para gerar os arquivos .class.
A instrução start /min rmiregistry, serve para ativar o serviço de registros de S.O. para que a classe possa ser registrada no servidor.
A instrução rmic HelloImpl cria automaticamente as classes necessárias para gerar os objetos stub e skeleton. Neste caso em específico serão geradas as classes: HelloImpl_Stub.class e HelloImpl_Skel.class.
A instrução start java HelloImpl inicia o servidor em um processo separado. Para terminar o processo basta pressionar CTRL-C.
A instrução appletviewer cliente.html inicia o cliente através da chamada de uma página HTML eu contém o applet descrito acima. Este applet, por sua vez, chamará o método remoto.

IMPORTANTE: Para trabalhar com RMI, mesmo em um único computador, é necessário que o computador tenha disponível os serviços de rede TCP/IP.