RMI/JNDI - Fundamentos



Documentos relacionados
Java 2 Standard Edition. Fundamentos de. Objetos Remotos. Helder da Rocha

Invocação de Métodos Remotos

SISTEMAS DISTRIBUÍDOS

Sistemas Distribuídos

Invocação de Métodos Remotos RMI (Remote Method Invocation)

Tutorial RMI (Remote Method Invocation) por Alabê Duarte

Sistemas Distribuídos

Laboratório de Computação VI JAVA IDL. Fabricio Aparecido Breve

Sistemas Distribuídos

Sistemas Distribuídos Métodos de Invocação Remota II. Prof. MSc. Hugo Souza

Chamadas Remotas de Procedimentos (RPC) O Conceito de Procedimentos. RPC: Programa Distribuído. RPC: Modelo de Execução

3 Um Framework Orientado a Aspectos para Monitoramento e Análise de Processos de Negócio

Adriano Reine Bueno Rafael Barros Silva

MIDDLEWARE Aplicativos RMI, RPC e eventos Camadas Protocolo Requesição-Respostal Middleware Representação Externa dos Dados Sistemas Operacionais

Objetos Distribuídos - Programação Distribuída Orientado a Objetos. Luiz Affonso Guedes

Sistemas Paralelos e Distribuídos /2004 Curso: Matemática /Informática Sistemas Distribuídos /2004 Curso: Ensino da Informática

Sistemas Distribuídos

Enterprise Java Beans

Uma Introdução à Arquitetura CORBA. O Object Request Broker (ORB)

Num sistema de objectos distribuídos, dois conceitos são fundamentais.

Prototype, um Design Patterns de Criação

SISTEMAS DISTRIBUIDOS

Web Services. Autor: Rômulo Rosa Furtado

Sistemas Distribuídos: Conceitos e Projeto Java RMI

Introdução ao Modelos de Duas Camadas Cliente Servidor

Como criar um EJB. Criando um projeto EJB com um cliente WEB no Eclipse

UNIVERSIDADE. Sistemas Distribuídos

CURSO DE PROGRAMAÇÃO EM JAVA

ADMINISTRAÇÃO DE SISTEMA OPERACIONAL DE REDE (AULA 4)

Sistemas Distribuídos Métodos de Invocação Remota IV. Prof. MSc. Hugo Souza

3 SCS: Sistema de Componentes de Software

MINICURSO WINDOWS SERVER 2008 UTILIZANDO O VMWARE PLAYER

INE Sistemas Distribuídos

Middleware de Aplicações Paralelas/Distribuídas

Descrição. Implementação. Departamento de Informática e Estatística Universidade Federal de Santa Catarina LAB 4 Transferência de Arquivos

Sistemas Distribuídos

Entendendo como funciona o NAT

Programação Orientada a Objetos com PHP & MySQL Cookies e Sessões. Prof. MSc. Hugo Souza

Introdução à Linguagem Java

Informática UFRGS. Programação com Objetos Distribuídos (C. Geyer) C# Remote V0 1

Orientação a Objetos

Parte I. Demoiselle Mail

A ) O cliente terá que implementar uma interface remota. . Definir a interface remota com os métodos que poderão ser acedidos remotamente

Intranets. FERNANDO ALBUQUERQUE Departamento de Ciência da Computação Universidade de Brasília 1.INTRODUÇÃO

Aspectos técnicos do desenvolvimento baseado em componentes

Conceitos de relação de confiança

Implementando uma Classe e Criando Objetos a partir dela

Prática em Laboratório N.01 Criando um Serviço Web via Console

Princípios de Sistemas Distribuídos. Tecnologias utilizadas em sistemas distribuídos Aula 5

INF1013 MODELAGEM DE SOFTWARE

SUMÁRIO 1. AULA 6 ENDEREÇAMENTO IP:... 2

Arquitetura de Rede de Computadores

Capítulo 4. Packages e interfaces

Microsoft Access XP Módulo Um

Sistemas Distribuídos

HIBERNATE EM APLICAÇÃO JAVA WEB


Máscaras de sub-rede. Fórmula

Prática da Disciplina de Sistemas Distribuídos Serviços Web IFMA DAI Professor Mauro Lopes C. Silva

UFG - Instituto de Informática

IP significa Internet Protocol. A Internet é uma rede, e assim como ocorre em qualquer tipo de rede, os seus nós (computadores, impressoras, etc.

Análise e Desenvolvimento de Sistemas ADS Programação Orientada a Obejeto POO 3º Semestre AULA 03 - INTRODUÇÃO À PROGRAMAÇÃO ORIENTADA A OBJETO (POO)

PARANÁ GOVERNO DO ESTADO

Serviços Web: Introdução

Professor: Macêdo Firmino Disciplina: Sistemas Operacionais de Rede

ENTERPRISE JAVABEANS 3. Msc. Daniele Carvalho Oliveira

INTRODUÇÃO 12. DOCUMENTAÇÃO INTRODUÇÃO INTRODUÇÃO

Tutorial de Active Directory Parte 3

UFG - Instituto de Informática

Um pouco do Java. Prof. Eduardo

4 Um Exemplo de Implementação

Java para Desenvolvimento Web

Entrar neste site/arquivo e estudar esse aplicativo Prof. Ricardo César de Carvalho

Visão geral híbrida de Serviços Corporativos de Conectividade do SharePoint 2013

Documento de Análise e Projeto VideoSystem

Enterprise Java Bean. Enterprise JavaBeans

Modelos de Arquiteturas. Prof. Andrêza Leite

Android e Bancos de Dados

Usando Borland DELPHI para implementar aplicações CORBA

Escritório Virtual Administrativo

Senado Federal Questões 2012

Java Laboratório Aula 1. Divisões da Plataforma. Introdução a Plataforma Java. Visão geral da arquitetura da

Fundamentos da Plataforma Java EE. Prof. Fellipe Aleixo

Gerenciamento de Arquivos e Pastas. Professor: Jeferson Machado Cordini jmcordini@hotmail.com

Introdução ao Active Directory AD

SISTEMAS OPERACIONAIS

ATRIBUTOS PRIVADOS 6. ENCAPSULAMENTO MÉTODOS PRIVADOS MÉTODOS PRIVADOS

DarkStat para BrazilFW

Noções de. Microsoft SQL Server. Microsoft SQL Server

Para funcionamento do Netz, alguns programas devem ser instalados e alguns procedimentos devem ser seguidos. São eles:

CONCEITOS INICIAIS. Agenda A diferença entre páginas Web, Home Page e apresentação Web;

AULA 6: SERVIDOR DNS EM WINDOWS SERVER

O que são DNS, SMTP e SNM

Sistemas Distribuídos. Professora: Ana Paula Couto DCC 064

Desenvolvendo Websites com PHP

Capítulo VI CORBA. Common Object Request Broker Architecture. [Cardoso2008] Programação de Sistemas Distribuídos em Java, Jorge Cardoso, FCA, 2008.

Introdução a Java. Hélder Nunes

Transcrição:

c o l u n a Professor J RMI/JNDI - Fundamentos Um exemplo prático do que são e de como funcionam RMI e JNDI Roberto Vezzoni (roberto.vezzoni@gmail.com): SCJP, faz Ciência da Computação na Faesa e atua como assessor/instrutor de TI. A API RMI (Remote Method Invocation) é o mecanismo em Java que permite a manipulação de objetos distribuídos. Com RMI, é possível realizar chamadas de métodos em objetos remotos (numa outra VM, talvez no mesmo host). Como é necessário vasculhar outra VM para a tentativa de encontrar um objeto remoto, nós precisamos fornecer meios para que aquele objeto seja, de fato, encontrado. É através da API JNDI (Java Naming and Directory Interface) que conseguimos registrar e encontrar objetos remotos para que estes sejam utilizados por RMI. Odiretor de compras de uma empresa, por conta de suas viagens a negócios, solicita ao departamento de TI a possibilidade de acessar e manipular informações sobre pedidos de compras e estoque disponível através de seu smartphone. Como já existe um sistema de gestão para pedidos de compras que foi desenvolvido em duas camadas (cliente/servidor) e sendo este um sistema desktop para janelas mais ricas em recursos de entrada pelo usuário, será necessário quebrar o processo de pedido de compras em três camadas lógicas para evitar a duplicação do código na camada de negócios da nova aplicação. O cenário que possuímos é de que ainda será possível realizar a manipulação dos pedidos de compras no sistema de gestão já implantado e temos um novo sistema que permite acesso através daquele smartphone e demais dispositivos móveis compatíveis. A arquitetura deste cenário está demonstrada na figura 1. O padrão de projeto Façade (ou Fachada, em português) é responsável por fornecer um acesso padronizado e unificado a um subsistema mais complexo. Imagine, por exemplo, o processo de cadastro de nota fiscal de entrada por compra para comercialização. Será necessário além de fazer entrada em estoque das mercadorias envolvidas, fazer um lançamento de contas a pagar ao fornecedor em questão. Assim, o programador se vê em meio a várias regras de negócio. Para resolver essa situação, pode ser fornecido ao programador um objeto responsável por fazer o fechamento daquela nota fiscal, realizando apenas uma chamada, em vez de implementar um código com várias instâncias de objetos diferentes que se relacionam entre si. A esse novo objeto, se dá o nome de Façade. Num paralelo com tecnologias para este fim, além da RMI, temos como exemplos os padrões COM e DCOM (Microsoft) e o padrão CORBA (Common Object Request Broken Architeture) do OMG (Object Management Group). Como os objetos em RMI trafegam entre diferentes VMs, é necessário o uso de protocolos para a comunicação entre as aplicações cliente e servidor, e o protocolo padrão é o JRMP (Java Remote Method Protocol). Para se obter interoperabilidade entre diferentes linguagens de programação orientadas a objetos que seguem o padrão do OMG, o protocolo utilizado é o IIOP (Internet Inter-ORB Protocol) no qual esse ORB (Object Request Broker) atua fazendo o "meio de campo" entre o cliente e o servidor. Quando é citado RMI-IIOP, significa explicitar que os objetos trafegados por RMI estão sobre o protocolo IIOP. EJBs (Enterprise JavaBeans) utilizam RMI- IIOP por "trás das cenas". Para que tudo isso funcione, nós precisamos de arquivos auxiliares que serão responsáveis por, de fato, realizar chamadas em métodos de objetos remotos. Com esses arquivos disponíveis em nosso classpath, realizamos chamadas em objetos remotos como se fossem locais, pois eles atuam como proxies. Esses arquivos são conhecidos como skeleton e stub e ficam no servidor e cliente, respectivamente. Mais adiante veremos como gerar tais arquivos. Um proxy é responsável por gerenciar o tráfego de informações entre as aplicações cliente e servidor. 22 www.mundoj.com.br

você tenha permissão para escrita de seu sistema de arquivos (os arquivos de código-fonte já inclusos nesta árvore serão criados por nós neste arquivo). Passagem de argumentos Quando usamos RMI devemos estar atentos ao tratamento das passagens de argumentos, pois em Java passagens de argumentos se dão por cópia de valor. Mas o que acontece quando passamos objetos como argumentos em RMI? A referência de um determinado objeto local (endereço na memória heap local) pode não existir na VM remota e se existir não significa que seja o que esperamos ser, então caímos numa exceção na passagem de argumentos em Java: passagem de argumentos por referência. Tudo bem, na verdade é uma pseudopassagem por referência, pois o objeto utilizado como argumento é enviado para a outra VM. Isso acontece por meio de serialização, ou seja, devemos fazer com que esse objeto que deve ser trafegado implemente a interface java.io.serializable. Caso o objeto não deva ser enviado para que o volume de dados trafegados seja menor, basta não implementar aquela interface. Mas como não existe almoço grátis, ao não implementarmos a interface java. io.serializable, deixamos de trafegar um objeto pela rede, porém agora para cada mudança de estado desse objeto deverá ser realizada uma chamada de rede. Objetivo: Hello World Bom, mãos à obra! Nossa intenção é construir uma aplicação RMI stand alone, ou seja, ela deve executar fora de um container JEE (Java Enterprise Edition). Ela nos mostrará como as coisas funcionam exibindo o nosso já bem conhecido Hello World. Configuração do ambiente A primeira coisa a fazer é criar uma estrutura de diretórios em nosso sistema de arquivos para organizar de forma adequada nossos artefatos. Crie a árvore de diretórios conforme a figura 2 em qualquer parte que Servidor Figura 2. Árvore de diretórios para nosso exemplo. Para começar a programação, iremos montar um objeto que contenha uma operação simples e, seguindo uma máxima para encapsulamento e baixo acoplamento na orientação a objetos, vamos programar para interfaces. Não faremos isso apenas por uma boa prática, em RMI não temos escolha, é impossível fazer chamadas diretamente ao objeto que mantém a implementação. Devido a essa regra, precisamos construir uma interface que estenda java.rmi. Remote, com os métodos desejados. Salve o código da Listagem 1 em um arquivo chamado FacadeIntf.java em / rmi_home/server/src/mj/rmiserver/intf. Listagem 1. mj.rmiserver.intf.servidorintf.java. package mj.rmiserver.intf; public interface FacadeIntf extends java.io.serializable, java.rmi.remote { String JNDI_NAME = Server ; String sayhello() throws java.rmi.remoteexception; Todas as operações declaradas em nossa interface remota devem lançar java. rmi.remoteexception, pois a RMI força-nos a considerar a possibilidade de instabilidades de rede, travamentos em máquinas remotas, etc. Agora devemos implementar nossa interface montando nosso objeto remoto. Para tal, precisamos estender uma classe especial: javax.rmi.portableremote- Object. Salve o código da Listagem 2 em um arquivo com o nome FacadeImpl.java em rmi_home/server/src/mj/rmiserver/impl. 23

Professor J Listagem 2. mj.remiserver.impl.facadeimpl.java. package mj.rmiserver.impl; import mj.rmiserver.intf.facadeintf; public class FacadeImpl extends javax.rmi.portableremoteobject implements FacadeIntf { Agora nos resta montar uma classe que seja responsável por levantar nosso servidor (todos os artefatos deste artigo estão disponíveis no site da revista Mundoj). Ela é mostrada na Listagem 3. Agora devemos compilar as classes do nosso servidor. Para isso, basta compilar o arquivo ServerRMI.java que todas as outras classes utilizadas por ele também serão compiladas. Entre no diretório rmi_home/server/src e execute o seguinte comando: javac -d../bin/ -cp. mj/rmiserver/serverrmi.java Para complementar nosso servidor, precisamos apenas gerar um arquivo auxiliar para que a RMI saiba como lidar com nosso objeto remoto. O utilitário rmic, que vem junto com o JDK, deve ser usado para gerar arquivos auxiliares para cada um dos objetos registrados na VM e deve ser executado sobre o bytecode. Entre no diretório rmi_home/server/bin e execute o seguinte comando: rmic -classpath. mj.rmiserver.impl.facadeimpl De posse do arquivo auxiliar FacadeImpl_Stub.class gerado no diretório rmi_ home/server/bin/impl, devemos disponibilizá-lo nos classpaths das aplicações cliente e servidor. Assim, podemos executar nosso servidor. Entre no diretório rmi_home/server/ bin e execute o seguinte comando: java -cp. mj.rmiserver.serverrmi A seguinte saída lhe será apresentada: esperando por requisições... (Uau, 'tá funcionando mesmo! :o) Resumo Esse servidor, em execução, criará um registro na VM local esperando por requisições na porta 1099. E também terá uma instância da classe mj.rmiserver.impl. FacadeImpl.java amarrada ao nome Server (ainda falaremos desse nome, por favor, não me deixe esquecer). Cliente public FacadeImpl() throws java.rmi.remoteexception { super(); public String sayhello() { return Hello World! ; Agora daremos início à construção de uma aplicação RMI cliente para o servidor que acabamos de desenvolver juntos. Na Listagem 4, é apresentada a classe cliente. Listagem 3. mj.rmiserver.serverrmi. package mj.rmiserver; public class ServerRMI { public ServerRMI() { * cria um registro (responsável por aceitar requisições) na VM * local na porta padrão * para distribuição de objetos sobre RMI - 1099. * Assim, sempre que a máquina, em que reside o nosso servidor * em execução, * receber solicitações na porta 1099, * essa solicitação será encaminhada para o nosso servidor. java.rmi.registry.locateregistry.createregistry( java.rmi.registry.registry.registry_port ); mj.rmiserver.impl.facadeimpl facade = new mj.rmiserver.impl.facadeimpl(); * amarra a instância de nosso objeto remoto a um nome * (examinaremos esse nome mais adiante) * e armazenamos isso no registro. * A classe java.rmi.naming é responsável por fornecedor métodos * para armazenar e obter objetos remotos no registro. java.rmi.naming.bind( mj.rmiserver.intf.facadeintf.jndi_name, facade ); synchronized (facade) { * chamada ao método wait() herdado de java.lang.object * para que nosso servidor fique esperando por requisições. * E fazemos isso dentro de um bloco sincronizado * pois queremos nosso servidor trabalhando de forma thread-safe. System.out.println( esperando por requisições... ); facade.wait(); catch (InterruptedException ie) { ie.printstacktrace(); catch (java.rmi.remoteexception re) { re.printstacktrace(); catch (Exception e) { e.printstacktrace(); public static void main(string[] args) { new ServerRMI(); 24 www.mundoj.com.br

Copie o arquivo FacadeIntf.class para rmi_home/client/bin/mj/rmiserver/ intf para que possamos compilar a nossa classe cliente. Entre no diretório rmi_home/client/src e execute o seguinte comando: javac -cp.:../bin/ -d../bin/ mj/rmiclient/clientrmi.java Falta apenas um processo a fazer antes de executar nosso cliente: disponibilizar no classpath da aplicação cliente o stub gerado para o servidor que desenvolvemos há pouco. Ou seja, você deve copiar o artefato FacadeImpl_Stub para rmi_home/client/bin/mj/rmiserver/impl. Isso tornará a nossa árvore de diretórios para o cliente e servidor nas seguintes estruturas demonstradas nas figuras 3 e 4, respectivamente. Figura 3. Estrutura de diretórios e arquivos da nossa aplicação cliente. Listagem 4: mj.rmiclient.clientrmi package mj.rmiclient; public class ClientRMI { public ClientRMI(String host) { * procura por uma instância no servidor, passado na URL, * através de um nome (que mistério!) * utilizando o método lookup() da classe java.rmi.naming. Object remoteobject = java.rmi.naming.lookup( host + mj.rmiserver.intf.facadeintf.jndi_name ); * fazemos um casting do objeto retornado pela instrução * demonstrada na listagem 11. * Para essa operação precisamos utilizar a classe * javax.rmi.portableremoteobject para realizar uma chamada ao * seu método narrow(). * A Classe javax.rmi.portableremoteobject é a super classe do * nosso objeto remoto * ou foi utilizada para exportar o objeto para o registro no servidor. * O método narrow() assegura que o objeto retornado pelo lookup() * está de acordo com a interface passada no segundo argumento, * se a conversão não for apropriada, uma exceção será lançada. mj.rmiserver.intf.facadeintf facade = (mj.rmiserver.intf.facadeintf) javax.rmi.portableremoteobject.narrow( remoteobject, mj.rmiserver.intf.facadeintf.class ); * realizamos uma chamada como se tivéssemos uma instância local. System.out.println( Diga olá: + facade.sayhello() ); catch (Exception e) { e.printstacktrace(); public static void main(string[] args) { if (args.length < 1) { System.out.println( Uso: java ClientRMI <host> ); System.exit( 0 ); new ClientRMI( // + args[0] + / ); Figura 4. Estrutura de diretórios e arquivos da nossa aplicação servidora. Pronto! Com o servidor em funcionamento, basta entrar no diretório rmi_home/client/bin e executar o seguinte comando:: java -cp. mj/rmiclient/clientrmi localhost Caso tudo tenha ocorrido como o esperado, você deve ter a seguinte saída: Diga olá: Hello World! (Woohoo! Funcionou! :o) Melhorando o nosso exemplo Empacotando o servidor Para facilitar a disponibilização de nosso servidor RMI, podemos empacotar os bytecodes gerados em um arquivo JAR. Com esse propósito, vamos criar um arquivo para explicitar qual classe deve ser executada. Crie um arquivo texto de nome MANIFEST.MF dentro de rmi_home/server/ com o seguinte conteúdo: Main-Class: mj.rmiserver.serverrmi Agora vamos criar o pacote com a aplicação servidora. Entre no diretório 25

Professor J rmi_home/server/bin e execute o seguinte comando: jar -cvfm server.jar../manifest.mf. O comando acima criará o arquivo JAR server.jar dentro de rmi_home/server/bin. Resta-nos executar o arquivo JAR que acabamos de criar. Entre no diretório rmi_home/server/bin e execute o seguinte comando: java -jar server.jar Empacotando o cliente Para facilitar a disponibilização de nosso cliente RMI, podemos empacotar os bytecodes gerados em um arquivo JAR. Com esse propósito, vamos criar um arquivo para explicitar qual classe deve ser executada. Crie um arquivo-texto de nome MANIFEST.MF dentro de rmi_home/client/ com o seguinte conteúdo: Main-Class: mj.rmiclient.clientrmi Agora vamos criar o pacote com a aplicação cliente. Entre no diretório rmi_ home/client/bin e execute o seguinte comando: jar -cvfm client.jar../manifest.mf. O comando acima criará o arquivo JAR client.jar dentro de rmi_home/client/ bin. Resta-nos executar o arquivo JAR que acabamos de criar. Entre no diretório rmi_home/client/bin e execute o seguinte comando: java -jar client.jar localhost E novamente, caso tudo tenha ocorrido como o esperado, você deve ter a seguinte saída: Diga olá: Hello World! Nós poderíamos não adicionar os artefatos do nosso servidor (FacadeIntf e FacadeImpl_Stub) diretamente no pacote cliente (client.jar), disponibilizando-os em um pacote separado para facilitar a manutenção e redistribuição de ambas as aplicações: cliente e servidor. Mas isso nos levaria a um assunto paralelo à intenção inicial deste artigo. Java Naming and Directory Interface A JNDI API é responsável por fornecer um padrão para definição e localização através de um nome de recursos como EJBs, conexões JDBC, usuários, entre outros dentro de um determinado ambiente. A JNDI resolve o que deveria ser um problema para programadores Java: fornecedores diferentes com técnicas diferentes para trabalho sobre o serviço de nomes e diretórios. Usando unicamente a JNDI fazemos operações sobre serviços de nomes e diretórios de forma transparente. Isso significa que não nos importa saber se estamos acessando um Lightweight Diretory Access Protocol (LDAP) ou Network Information System (NIS) ou ainda Network Directory System (NDS). Com isso, basta aprender uma única API para acessar informações que estejam nos mais variados tipos de serviços de nomes e diretórios. Serviço de nomes Um nome se refere a uma entidade como pessoa ou objeto. O fato de se usar um nome é devido a ser mais usual e fácil. Quando você faz uma solicitação, por exemplo, ao website www.mundoj.com. br um Domain Name System (DNS) é responsável por traduzir aquela URL ao endereço IP amarrado àquele nome. Outro bom exemplo é quando você solicita à sua operadora telefônica o número do telefone de uma determinada pessoa que você tem o nome. Então o serviço de nomes (naming service) permite que seja amarrada alguma coisa a um nome e também permite que seja feita uma busca por essa coisa através de seu nome. Serviço de diretórios Um diretório é um tipo de objeto (coisa) de atenção particular, pois ele pode conter atributos. Você pode procurar por um objeto que seja um diretório, como por exemplo, um usuário de rede que possui como atributos o seu nome de usuário e senha. Exemplos de serviços de diretórios (directory service) são o Microsoft Active Directory e o OpenLDAP. A sua estrutura de trabalho é organizar os diretórios em uma hierarquia conhecida como árvore. Um organograma é um exemplo dessa estrutura. Um serviço de diretórios se parece muito com bancos de dados. Em ambos, podemos armazenar informações e/ou consultar informações já previamente definidas. Muitos dos serviços de diretórios são implementados por bancos de dados por trás das cenas. Conclusão A intenção era apresentar-lhe o uso prático da RMI e para tal nós tínhamos que ter uma noção básica da API JNDI. Com este exemplo, foi mostrado que nada além da JDK, que possuímos, é necessário para construir uma aplicação distribuída em Java. Claro, dessa forma, é dever do programador implementar códigos para tratamento de transações, segurança, requisições simultâneas e balanceamento de carga, entre outros, fugindo um pouco de manter a atenção apenas no negócio do sistema. Por isso, além de outras coisas, existem os containers. Eles permitem que fiquemos focados apenas no negócio do sistema em questão. Agradecimentos A Henrique Winckler (henriquew@gmail.com) e a equipe da Mundoj pela Referências man. 26 www.mundoj.com.br