O RMI (Remote Method Invocation) é uma interface de programação que permite a execução de chamadas remotas no estilo RPC em aplicações desenvolvidas em Java[1]. É uma das abordagens da plataforma Java para prover as funcionalidades de uma plataforma de objetos distribuídos. Esse sistema de objetos distribuídos faz parte do núcleo básico de Java desde a versão JDK 1.1, com sua API sendo especificada através do pacote java.rmi e seus subpacotes[2].

Através da utilização da arquitetura RMI, é possível que um objeto ativo em uma máquina virtual Java possa interagir com objetos de outras máquinas virtuais Java, independentemente da localização dessas máquinas virtuais.[3]

A API RMI fornece ferramentas para que seja possível ao programador desenvolver uma aplicação sem se preocupar com detalhes de comunicação entre os diversos possíveis elementos (hosts) de um sistema.

Funcionamento editar

O funcionamento de RMI consiste basicamente em dois programas, segundo a arquitetura cliente-servidor, onde um seria o cliente e outro o servidor. O servidor instancia objetos remotos, o referencia com um nome e faz um "vinculo" dele numa porta, onde este objeto espera por clientes que invoquem seus métodos. Já o cliente referencia remotamente um ou mais métodos de um objeto remoto. RMI fornece os mecanismos para que a comunicação entre cliente e servidor seja possível. Esse tipo de aplicação geralmente é denominada como Aplicação de Objeto Distribuído.

Aplicações distribuídas precisam, portanto, executar as seguintes ações[4]:

  • Localizar Objetos Remotos - Uma aplicação pode usar dois mecanismos para obter referências de objetos remotos. Ela pode registrar o objeto remoto com a ferramenta de nomes do RMI, que se chama "rmiregistry", ou ela pode passar e retornar referências aos objetos remotos como parte de sua operação normal.
  • Se Comunicar com Objetos Remotos - Os detalhes de comunicação entre objetos remotos são tratados pelo RMI, ou seja, para o programador, a comunicação remota é semelhante a uma chamada ao método localmente.
  • Carregar "bytecodes" de objetos móveis - Como o RMI permite que objetos remotos sejam passados como parâmetros numa função, ele fornece os mecanismos necessários para carregar o código dos objetos remotos.

Vantagens do RMI editar

Uma das principais vantagens do RMI é sua capacidade de baixar o código de um objeto, caso a classe desse objeto não seja definida máquina virtual do receptor. Os tipos e o comportamento de um objeto, previamente disponíveis apenas em uma máquina virtual, agora podem ser transmitidos para outra máquina virtual, possivelmente remota. Essa funcionalidade do RMI permite que o código da aplicação seja atualizado dinamicamente, sem a necessidade de compilar novamente o código.

Interfaces, objetos e métodos remotos editar

Toda aplicação Java é construida a partir de interfaces e classes, logo, da mesma forma é uma aplicação distribuída construida com Java RMI. A interface declara métodos. As classes implementam os métodos declarados na interface e possivelmente conterá métodos adicionais. Numa aplicação distribuída, algumas implementações podem permanecer em alguma Java VM mas não em outras. Objetos com métodos que podem ser invocados entre Java VM são chamados de Objetos Remotos.

Para se tornar um Objeto Remoto, a classe deve implementar uma interface remota:

  • A interface remota deve estender a interface java.rmi.Remote.
  • Todo método em sua declaração deve conter no throws a excecão java.rmi.RemoteException.

Nomeando Objetos Remotos editar

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 inclui 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:

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

Serialização editar

A capacidade de armazenar e recuperar objetos em JAVA é essencial quando se fala de RMI. A maneira encontrada para armazenar esses objetos em uma forma serializada sem ocupar muita memória foi representar os estados do objeto suficientes para reconstruí-lo.

Objetos serializados em Java devem ser capazes de identificar e verificar a classe Java da qual eles derivam e recuperar seu conteúdo para criar uma nova instância.

Freqüentemente, objetos armazenados fazem referência a outros objetos. Esses outros objetos também devem ser armazenados e na recuperação, todos devem ser desarmazenados ao mesmo tempo, para que as relações entre ele não se percam.

Camadas de Software do Sistema RMI editar

A implementação do RMI é essencialmente feita de três camadas de abstração[5]. 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 gerenciar referências feitas dos clientes para os objetos 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 arquitetura de camadas, cada uma das camadas poderia ser facilmente melhorada ou substituída sem afetar o resto do sistema. Por exemplo, a camada de transporte poderia ser substituída por uma camada que implemente conexões UDP/IP, sem afetar as camadas superiores.

"Stubs" editar

O "stub" funciona semelhante a um proxy para o objeto remoto. Quando um objeto local invoca um método num objeto remoto, o "stub" fica responsável por enviar a chamada ao método para o objeto remoto.

Passos do "stub" quando é invocado:

  • Iniciar conexão com a "Virtual Machine" que contém o objeto remoto.
  • Escrever e transmitir os parâmetros para a "Virtual Machine" remota.
  • Esperar pelos resultados da invocação do método.
  • Ler os resultados retornados.
  • Retornar os valores ao objeto que executou a chamada .

O "stub" esconde a serialização dos parâmetros e toda a comunicação em nível de rede, com o objetivo de simplificar o mecanismo de realização da chamada.

"Skeletons" editar

Na "Virtual Machine" remota, cada objeto deve ter um "skeleton" correspondente ao "stub". O "skeleton" é responsável por enviar a chamada ao objeto remoto.

Passos do "skeleton" quando recebe uma chamada:

  • Ler os parâmetros enviados pelo "stub"
  • Invocar o método no objeto remoto
  • Escrever e transmitir o resultado ao objeto que executou a chamada

Camada de Referências Remotas editar

Esta camada mantém as referência entre os clientes e os objectos remotos e estabelece a semântica da ligação RMI. As referências mantidas referem-se a ligação unicast, ou seja um proxy para um objecto remoto (i.e. um Stub para um Skeleton). Esta camada funciona como um router entre o cliente e os (eventuais) vários objectos remotos. Por enquanto, o RMI não suporta directamente outras semânticas de comunicação como por exemplo multi-cast. Numa situação de multi-cast, um único proxy poderia chamar em simultâneo várias instâncias de objectos remotos (localizadas eventualmente em diferentes computadores) e esperar pela primeira resposta retornada.

Camada de Transporte editar

Esta camada lida diretamente com a comunicação entre as várias JVM's, usando TCP/IP. É importante referir que mesmo que as JVM's sejam executadas no mesmo computador, o RMI recorre sempre à comunicação TCP/IP. Isto significa que é sempre é necessário possuir uma interface de rede funcional para se poder utilizar RMI (mesmo tendo a aplicação cliente e a aplicação servidora a executar no mesmo computador). Sobre a pilha TCP/IP o RMI possui um protocolo denominado JRMP, Java Remote Method Protocol e que permite ultrapassar alguns obstáculos que podem surgir na comunicação de rede via TCP/IP. Por exemplo, o JRMP permite multiplexar várias ligações TCP/IP numa única ligação TCP/IP ultrapassando imposições de utilização de apenas uma ligação em alguns ambientes (ex.: certos browsers a correr Applets RMI)

Segurança editar

Em relação a segurança, o RMI fornece o "RMISecurityManager", sem o qual objetos locais se tornam incapazes de baixar código ou utilizar métodos remotos. O RMISecurityManager Segue o modelo de segurança do JDK 1.6. No modelo de segurança do JDK 1.6, o código, independentemente se é local ou remoto, é sempre executado sob uma política de segurança. A política de segurança define um conjunto de permissões disponíveis para o código. Cada permissão define um acesso a um recurso em particular, como por exemplo, permissão de leitura ou escrita a um diretório específico ou permissão de conexão para um host e porta.

O sistema de execução organiza o código em domínios individuais, cada domínio possui seu conjunto de classes, sendo que as instâncias dessas classes possuem o mesmo conjunto de permissões. Um domínio pode ser configurado de forma que applets rodem em um ambiente restrito, de acordo com o administrador da rede. As aplicações "stand alone" rodam sem nenhuma restrição, porém elas podem ser submetidas a uma política de segurança. No caso do RMI, os objetos remotos são obrigados a implementar uma política de segurança.

SSL em RMI editar

O RMI permite ao programador usar "sockets" personalizados, ou seja, com RMI, é possível que cada objeto use um tipo diferente de "socket" para sua conexões RMI[6]. Caso o programador queira adicionar mais segurança ao seu sistema, ele pode usar SSL como protocolo de comunicação abaixo do RMI, ou caso não esteja interessado, pode usar simplesmente TCP com os mecanismos de segurança providos pelo próprio RMI.

Ver também editar

Ligações externas editar

Referências