Remote Method Invocation (RMI): mudanças entre as edições

De Wiki Cursos IFPR Foz
Ir para navegaçãoIr para pesquisar
Sem resumo de edição
Linha 1: Linha 1:
[[Arquivo:Exemplo.jpg]]
== Java RMI (Remote Method Invocation) ==
== Java RMI (Remote Method Invocation) ==



Edição das 19h41min de 10 de fevereiro de 2014

Java RMI (Remote Method Invocation)

Interfaces : Coração do RMI A arquitetura 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 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 atua como um Proxy para o serviço remoto. Veja o seguinte diagrama: 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.

Nomeando Objetos Remotos Como um cliente acha o serviço remoto RMI? Os clientes acham os serviços remotos usando o serviço de nomeação ou diretório (naming or directory). Isso parece um pouco redundante, mas o serviço de nomeação ou diretório roda como um endereço bem formado (host:port). O RMI pode usar diferentes tipos de serviços de diretó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 objeto que implemente aquele serviço. Em seguida ele exporta aquele objeto para o RMI. Quando o objeto é exportado o RMI cria um serviço que aguarda as conexões do cliente. O servidor registra o objeto no RMI Registry, com um nome público. No lado do cliente o RMI Registry é acessado 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 objeto do serviço. A URL é formada como seguinte:

Código: rmi://<host_name>[:port_number]/<service_name>

Usando 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 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. Código:

                   import java.rmi.Remote;  
                     import java.rmi.RemoteException;  
 
                     public interface Mensageiro extends Remote {  
 
                     public void enviarMensagem( String msg ) throws RemoteException;  
                     public String lerMensagem() throws RemoteException;  


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 exceção RemoteException. Salve este arquivo (Mensageiro.java) no seu diretório e compile, com a seguinte linha de comando: 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.

                              import java.rmi.RemoteException;  
                                import java.rmi.server.UnicastRemoteObject;  
 
                                 public class MensageiroImpl extends UnicastRemoteObject implements Mensageiro {  
 
                               public MensageiroImpl() throws RemoteException {  
                                super();  
          }  
 
                                public void enviarMensagem( String msg ) throws RemoteException {  
                                 System.out.println( msg );  
         }  
 
                              public String lerMensagem() throws RemoteException {  
                              return "This is not a Hello World! message";  
         }  
      }  


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


Observe que a classe se utiliza (estende) da classe UnicastRemoteObject para linkar com o sistema RMI. Neste exemplo a classe estende a classe UnicastRemoteObject diretamente. Isto não é realmente necessário, mas essa discusã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 ativa o código em UnicastRemoteObject, que executa o link RMI e a iniciação do objeto remoto. 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. 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.

                              import java.rmi.Naming;  
 
                                public class MensageiroServer {  
 
                                 public MensageiroServer() {  
                                 try {  
                                   Mensageiro m = new MensageiroImpl();  
                                   Naming.rebind("rmi://localhost:1099/MensageiroService", m);  
                              }  
                              catch( Exception e ) {  
                               System.out.println( "Trouble: " + e );  
                           }  
                        }  
 
                           public static void main(String[] args) {  
                             new MensageiroServer();  
                         }  
                     }  

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

                import java.rmi.Naming;  

import java.rmi.RemoteException; import java.rmi.NotBoundException; import java.net.MalformedURLException;

public class MensageiroClient {

   public static void main( String args[] ) {  
       try {  
           Mensageiro m = (Mensageiro) Naming.lookup( "rmi://localhost/MensageiroService" );  
           System.out.println( m.lerMensagem() );  
           m.enviarMensagem( "Hello World!" );  
       }  
       catch( MalformedURLException e ) {  
           System.out.println();  
           System.out.println( "MalformedURLException: " + e.toString() );  
       }  
       catch( RemoteException e ) {  
           System.out.println();  
           System.out.println( "RemoteException: " + e.toString() );  
       }  
       catch( NotBoundException e ) {  
           System.out.println();  
           System.out.println( "NotBoundException: " + e.toString() );  
       }  
       catch( Exception e ) {  
           System.out.println();  
           System.out.println( "Exception: " + e.toString() );  
       }  
   }

}


Rodando o sistema RMI 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 diretório em que estão gravados seus arquivos para rodar o aplicativo. Execute o seguinte comando: java MensageiroServer


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!

É 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. Espero que tenham gostado e aprendido com esse pequeno exemplo de como se usar o RMI.