Operação com objetos remotos em RMI

No primeiro exemplo de operação de aplicações distribuídas usando RMI, assumiu-se que as aplicações clientes, servidor e de registro eram processos distintos mas que estavam executando em uma mesma máquina. Além disto, considerou-se também que todas as classes necessárias para a operação das aplicações estavam localizadas em algum diretório do CLASSPATH.

No caso de execução em máquinas separadas, há duas formas de fazer a distribuição das classes de modo que clientes e servidores possam executar corretamente. Na primeira forma, a estratégia é distribuir explicitamente as classes necessárias e incluí-las em diretórios onde elas possam ser localizadas quando necessário. No lado cliente, essas classes complementares seriam a interface do serviço e o stub para a implementação do serviço. No lado servidor, seriam essas as classes de implementação do serviço (e o correspondente skeleton, para versões anteriores à 1.2).

A outra forma é utilizar os mecanismos de carregamento dinâmico de classes distribuídas, em alternativa ao class loader padrão da máquina virtual Java. Por exemplo, se a execução do cliente se dá através de um applet, o AppletClassLoader oferece as funcionalidades necessárias para localizar uma classe que está localizada no mesmo diretório de onde foi carregada a classe original.

Em RMI, há uma alternativa adicional de se utilizar o RMIClassLoader, que permite o carregamento de stubs e skeletons a partir de um URL (especificado através da propriedade java.rmi.server.codebase). Essa propriedade deve ser estabelecida para a máquina virtual Java que irá executar o servidor, como em

      > java -Djava.rmi.server.codebase=http://meuhost/meudir/ CountServer
    

Deste modo, quando o servidor realizar o cadastro do serviço no registry, esse codebase será embutido na referência do objeto. Quando o cliente obtiver a referência ao objeto remoto do registry e seu class loader falhar em localizar a classe stub no CLASSPATH local, sua máquina virtual Java fará uma conexão HTTP com meuhost para obter a classe correspondente (assim como outras classes eventualmente necessárias para execução do serviço no lado cliente).

De forma similar, caso o rmiregistry estivesse operando em outra máquina, distinta daquela onde as aplicações clientes e servidor estivessem executando, seria necessário especificar no código das aplicações a máquina que executa rmiregistry, seja através do método getRegistry() da classe LocateRegistry ou através da especificação de URL no protocolo RMI nos métodos da classe Naming.

Como para qualquer situação na qual a máquina virtual Java irá carregar classes localizadas de forma distribuída, é preciso adicionalmente estabelecer qual a política de segurança para operar com código proveniente das outras máquinas. Essa política será enforçada pelo gerenciador de segurança, que pode ser definido pela invocação do método correspondente antes de qualquer invocação a métodos de RMI:

        System.setSecurityManager(new RMISecurityManager());
    

O uso dessas facilidades pode ser apreciado nos exemplos modificados para o código do servidor e cliente da aplicação do contador distribuído. A especificação da interface e a implementação do serviço permanecem inalteradas para esses exemplos.