Java/RMI: diferenças entre revisões

Conteúdo apagado Conteúdo adicionado
Conteúdo retirado do [http://knol.google.com/k/andr%C3%A9-luiz-alves-moraes/java-rmi/n6m12v5sl0jh/1# Knol]; Autor: André Luiz Alves Moraes; Licença original: Creative Commons Attribution 3.0
(Sem diferenças)

Revisão das 22h56min de 26 de outubro de 2009

1- Introdução A tecnologia Java RMI (Remote Method Invocation) consiste em uma biblioteca capaz de permitir que um programa rodando em uma dada máquina efetue chamadas à objetos instanciados em outra máquina. Apesar de ser desenvolvida focando principalmente a chamada de procedimentos à objetos localizados em máquinas distintas ela também pode ser utilizada para efetuar a comunicação entre dois processos rodando na mesma máquina (desde que ambos utilizem a JVM), muito embora tecnologias como XPCOM e outras possam disponibilizar perforance e integração melhores.

2- Tenologias semelhantes Existem duas outras tecnologias que se assemelham muito com a RMI: CORBA e .NET Remoting (que no .NET 3.0 foi incorporada pela WCF). A tecnologia .NET Remoting é pode ser vista como a resposta Microsoft à tecnologia RMI, e possui quase as mesmas características. Já a tecnologia CORBA é divulgada à mais tempo e possui a vantagem de possuir bibliotecas em diversas linguagens, assim um objeto corba pode ser utilizado em vários programas escritos em linguagens diferentes (a tecnologia RMI foi feita exclusivamente para a plataforma Java).

3- Um exemplo rápido Para demonstrar a facilidade da linguagem, vou criar um exemplo bem simples que irá utilizar a tecnologia RMI. Um pequeno aplicativo para postar mensagens em um fórum e listar as mesmas

Primeiro devemos criar uma interface que será utilizada para exibir aos usuários dos serviço as operações

package rmiknolexample;

import java.rmi.RemoteException; import java.rmi.Remote;

/**

*
* @author Andre
*/

public interface IForum

       extends Remote {
   public void postMessage(String author, String aMessage) throws RemoteException;
   public String[] readPosts() throws RemoteException;
   public String[] readPosts(int beginAt) throws RemoteException;

}


Depois devemos criar uma classe que irá implementar a interface e disponibilizar a funcionalidade.

package rmiknolexample;

import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.Vector;

/**

*
* @author Andre
*/

public class ForumImpl

       extends UnicastRemoteObject 
       implements IForum {
   
   private Vector posts;
   
   // O construtor padrão deve gera a exeção RemoteException
   public ForumImpl() throws RemoteException {
       posts = new Vector();
   }
   public void postMessage(String author, String aMessage) throws RemoteException {
       posts.add(author + " disse uma vez: " + aMessage);
   }
   public String[] readPosts() throws RemoteException {
       String[] result = new String[posts.size()];
       posts.toArray(result);
       return result;
   }
   public String[] readPosts(int beginAt) throws RemoteException {
       String[] results = readPosts();
       String[] copy = new String[results.length - beginAt];
       System.arraycopy(results, beginAt, copy, 0, copy.length);
       return copy;
   }


Feito isso vamos implementar a classe que irá disponibilizar o serviço ao usuário

package rmiknolexample;

import java.rmi.Naming; import java.rmi.RemoteException;

/**

*
* @author Andre
*/

public class ForumService {

   public static void main(String[] args) {
       try {
           ForumImpl forumObj = new ForumImpl();
           Naming.rebind("forumService", forumObj);
           System.err.println("Rodando");
       } catch(RemoteException e) {
           System.err.println("Ocorreu um erro relativo ao RMI: " + e.getMessage());
           e.printStackTrace();
           System.exit(0);
       } catch(Exception e) {
           System.err.println("Ocorreu um erro desconhecido: " + e.getMessage());
           e.printStackTrace();
           System.exit(0);
       }
   }

}


Na classe acima observe a linha:

Naming.rebind("forumService", forumObj);

Ela é responsável por associar um nome ao seu objeto. É através deste nome que os computadores e processos remotos irão encontrar e utilizar o seu objeto. Este nome é único para um dado host, ou seja, mesmo se duas aplicações criarem objetos distintos (até mesmo de classes distintas) o mesmo nome não poderá ser utilizado.

Por último vamos implementar a classe que irá utilizar o serviço disponibilizado

package rmiknolexample;

import java.rmi.Naming; import java.rmi.RemoteException;

/**

*
* @author Andre
*/

public class ForumClient {

   public static void main(String[] args) {
       try {
           IForum forumObj = (IForum)Naming.lookup("rmi://localhost/forumService");
           forumObj.postMessage("autor", "Java RMI é muito legal");
           forumObj.postMessage("autor", "Nunca poste no fórum sem buscar");
           String[] posts = forumObj.readPosts();
           
           int x = 1;
           for(String s: posts)
               System.err.println(x++ + ": "+ s);
           
           int offset = 1;
           posts = forumObj.readPosts(offset);
           for(String s: posts)
               System.err.println((x++ + offset) + ": "+ s);                        
           
       } catch(RemoteException e) {
           System.err.println("Ocorreu um erro relativo ao RMI: " + e.getMessage());
           e.printStackTrace();
           System.exit(0);
       } catch(Exception e) {
           System.err.println("Ocorreu um erro desconhecido: " + e.getMessage());
           e.printStackTrace();
           System.exit(0);
       }        
   }

}


A linha:

IForum forumObj = (IForum)Naming.lookup("rmi://localhost/forumService");

Efetua uma consulta no host informado (neste caso o localhost) e solicita o objeto associado ao nome: forumService.

O resto do código fala por si só, e graças ao RMI as chamadas são idênticas á chamadas locais. Melhorando um pouco o design da aplicação é possível criar um objeto local ou então um remoto dependendo da ocasião.

Para facilitar o teste, a classe abaixo foi criada apenas para permitir rodar o serviço através da linha de comando: "java -jar arquivoJar.jar "

package rmiknolexample;

/**

*
* @author Andre
*/

public class Main {

   /**
    * @param args the command line arguments
    */
   public static void main(String[] args) {
       if (args[0].equals("server"))
           ForumService.main(args);
       else if (args[0].equals("client"))
           ForumClient.main(args);
       else
           System.err.println("Usage: ");
   }

}

pronto! Para executar basta compilar as classes, iniciar o aplicativo rmiregistry que é o responsável por encontrar e disparar as chamadas aos objetos corretos e iniciar o servidor em um terminal ou prompt.

Após isso feito abra outro terminal ou prompt e inicie a aplicação cliente.

Observação importante: neste caso o teste é apenas local mas quando utiliza-se um ambiente com diversas máquinas é muito importante iniciar a aplicação servidor com a opção: -Djava.rmi.server.hostname=<nome_ou_ip_do_host>. Caso não seja feito o objeto pode ser exportado com o host errado e a aplicação cliente pode tentar disparar o procedimento em um endereço diferente do solicitado.

Existem diversas outras características da tecnologia RMI que não foram abordadas, como por exemplo a capacidade de baixar o código de uma determinada classe de modo transparente. Assim mesmo que o contexto local não reconheça uma classe esta será trasnferida do servidor e poderá ser utilizada pela aplicação.

Para mais informações sobre a tecnologia rmi, viste: Remote Method Invocation Home[1]