Fj-31 rmi

Boa noite pessoal.
Venho fazendo alguns cursos da Caelum, via apostilas e recentemente iniciei o estudo do curso FJ-31 Java EE avançado e Web Services.
O 3º capítulo é sobre RMI (Remote Method Invocation).

Bom, até onde entendi, seguindo o material e informações conceituais colhidas na web, o uso do RMI resume-se em compratilhar um objeto entre JVM’s por uma porta/referencia desta instancia.

Vou expor a aplicação desenvolvida até aqui e havendo qualquer informação relevante, por favor comentem.
Dúvidas e sugestões são bem vindas.

O projeto (pacotes e classes):

Classes:


/** TestaEscritaDeObjetos**/

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
import br.com.caelum.loja.rmi.Livro;
public class TestaEscritaDeObjetos{

	public static void main(String[] args) throws IOException{
		
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("livros.txt"));
		Livro l1	=	new Livro();
		Livro l2	=	new Livro();
		l1.setNome("Pais e Filhos");
		l1.setPreco(100.0);
		l2.setNome("Noites Brancas");
		l2.setPreco(200.0);
		List<Livro> livros = new ArrayList<Livro>();
		livros.add(l1);
		livros.add(l2);
		oos.writeObject(livros);
		oos.close();
	}
	
}


/** TestaLeituraDeObjetos **/


import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.List;

import br.com.caelum.loja.rmi.Livro;


public class TestaLeituraDeObjetos {

	public static void main(String[] args) throws IOException, ClassNotFoundException{
		
		ObjectInputStream ois	=	new ObjectInputStream(new FileInputStream("livros.txt"));
		List<Livro> livros = (List<Livro>) ois.readObject();
		for(Livro l: livros){
			System.out.println(l.getNome());
			System.out.println(l.getPreco());
			System.out.println("------------------------");
		}
	}
	
}


/** ClienteLojaCarrinho **/

package br.com.caelum.loja.cliente;

import java.rmi.Naming;
import java.util.ArrayList;
import java.util.List;

import br.com.caelum.loja.rmi.Carrinho;
import br.com.caelum.loja.rmi.Livro;

public class ClienteLojaCarrinho {

	public static void main(String[] args) throws Exception{
			
		Carrinho carrinho = (Carrinho) Naming.lookup("rmi://localhost:1099/loja/carrinho");
		
		Livro l1	=	new Livro();
		Livro l2	=	new Livro();
		l1.setNome("Pais e Filhos");
		l1.setPreco(100.0);
		l2.setNome("Noites Brancas");
		l2.setPreco(500.0);
		carrinho.addLivro(l1);
		carrinho.addLivro(l2);
		
		System.out.println(carrinho.getTotal());
		
	}

}


/** Carrinho **/

package br.com.caelum.loja.rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.List;

public interface Carrinho extends Remote {

	void addLivro(Livro livro) throws RemoteException;
	
	List<Livro> getLivros() throws RemoteException;
	
	double getTotal() throws RemoteException;
	
}

/** CarrinhoBean **/

package br.com.caelum.loja.rmi;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;

public class CarrinhoBean extends UnicastRemoteObject implements Carrinho {

	private static final long serialVersionUID = 1L;

	private double total;
	private List<Livro> livros = new ArrayList<Livro>();
	
	public CarrinhoBean() throws RemoteException {
		super();
	}

	public void addLivro(Livro livro) throws RemoteException {
		this.livros.add(livro);
		this.total	+=	livro.getPreco();
		System.out.println("Livro %s adicionado com sucesso!\n"+livro.getNome());
	}

	public List<Livro> getLivros() throws RemoteException {
		return this.livros;
	}

	public double getTotal() throws RemoteException {
		return this.total;
	}

}

/** Livro **/

package br.com.caelum.loja.rmi;

import java.io.Serializable;

public class Livro implements Serializable{

	private static final long serialVersionUID = 1L;

	private transient String nome;
	
	private double preco;

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public double getPreco() {
		return preco;
	}

	public void setPreco(double preco) {
		this.preco = preco;
	}
	
}

/** RegistraCarrinho **/

package br.com.caelum.loja.rmi;

import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;

public class RegistraCarrinho {

	public static void main(String[] args) throws Exception{
		
		LocateRegistry.createRegistry(1099);
		
		Naming.rebind("loja/carrinho", new CarrinhoBean());
		
		System.out.println("Carrinho registrado na porta 1099");
		
	}
	
}

Antes de executar as classes, conforme especificado no material do curso, vejam o print das classes que iremos rodar (selecionadas):

A idéia deste laboratório é:

Cria um objeto no servidor representado pela classe br.com.caelum.rmi.RegistraCarrinho.java

Alocar este objeto em uma porta: LocateRegistry.createRegistry(1099);

Recuperar o objeto, pela porta/residencia/servidor, por uma classe cliente br.com.caelum.loja.cliente.ClienteLojaCarrinho.java

Carrinho carrinho = (Carrinho) Naming.lookup("rmi://localhost:1099/loja/carrinho");

Então vamos rodar a classe br.com.caelum.rmi.RegistraCarrinho.java:

O erro informa que a porta 1099 já está sendo utilizada.
Como rodei o mesmo script duas vezes, na segunda vez a porta não estava mais disponível.

Tratativa: Comentar a alocação e dar re-Set no objeto alocado [b]new CarrinhoBean()[/b

//LocateRegistry.createRegistry(1099);
Naming.rebind("loja/carrinho", new CarrinhoBean());

Com o objeto alocado, vamos trabalhar do lado do cliente / pseudo ‘outra JVM’.
Então vamos rodar a Classe: br.com.caelum.loja.cliente.ClienteLojaCarrinho.java:

Resumo:

Instanciamos um objeto e tornamos este publico a outras VMs via registro/locação do mesmo em uma porta: 1099

Demos a ele o nome/path loja/carrinho

Recuperamos um objeto alocado em uma porta a partir do recurso RMI.

 Carrinho carrinho = (Carrinho) Naming.lookup("rmi://localhost:1099/loja/carrinho"); 

Trabalhamos, como clientes, com os métodos deste objeto com se estivesse alocado na nossa (clientes) JVM.

carrinho.addLivro(l1);
carrinho.addLivro(l2);

Assim, fizemos uso do recurso de [color=green]I[/color]nvocação [color=green]R[/color]emota de [color=green]M[/color]étodos.
Estou estudando desde o conceito até possibilidades reais de aplicação do RMI, então, como já foi dito, duvidas, sugestões e comentários são muito bem vindos.

Desde já, Obrigado.

Ref.:


Olá Pessoal.
Ainda estudando, colhendo informações sobre RMI encontrei um bom tópico que aborda a questão.
Acredito que, para quem está iniciando no estudo do RMI, que é uma boa oportunidade, para não dizer ‘premissa’, de entender como funciona o Proxy.

Ref.:
http://www.guj.com.br/article.show.logic?id=37
http://pt.wikipedia.org/wiki/Proxy

Abçs,
Jsign :wink:

Amigo, coincidentemente ontem eu estava estudando RMI, e achei uma coisa curiosa sobre o seu projeto.
Quando você esta criando as classes Stub/Skeleton com o rmic???

Você esta usando o rmiregistry???

Se sim, agradeceria muito se você abordasse estes assuntos com mais detalhes.

[]'s

Boa noite caro ganondorfan,
Hoje não tive tempo pra muita coisa, e não gostaria de te dar uma resposta vaga.
Vou levantar certinho como está ocorrendo o processo e te passo o quão antes.

Abçs.
Jsign.

Agradeço muito.

Se não for abusar, eu gostaria de saber como acionar o registry em um servidor remoto real, uma vez que não temos acesso ao terminal dele.

[]'s

Boa tarde GanonDorfan.
Primeirmante desculpas pela demora na resposta.

Pensando em uma aplicação onde sua aplicação é cliente em objetos de outras aplicações você não deveria registrar estes (objetos) no servidor de cada aplicação servidora.
Teoricamente sua aplicação recolherá objetos remotamente. Cada aplicação servidora será responsável por alocar/subir seus objetos.

No exemplo dado, a classe RegistraCarrinho deve ser acionada pela aplicação do servidor

		...

		Naming.rebind("rmi://127.0.0.1:1099/loja/carrinho", new CarrinhoBean());
		
		LocateRegistry.createRegistry(1099);
		
		Naming.rebind("loja/carrinho", new CarrinhoBean());
		...

Uma vez o objeto disponível no servidor basta acessá-lo e usar seus métodos como cliente, a classe ClienteLojaCarrinho tem esta função.


		...

		Carrinho carrinho = (Carrinho) Naming.lookup("rmi://localhost:1099/loja/carrinho");
		
		Livro l1	=	new Livro();
		Livro l2	=	new Livro();
		l1.setNome("Pais e Filhos");
		l1.setPreco(100.0);
		l2.setNome("Noites Brancas");
		l2.setPreco(500.0);
		carrinho.addLivro(l1);
		carrinho.addLivro(l2);
		
		System.out.println(carrinho.getTotal());

		...

Nota: O RMI não nos devolve um objeto do servidor, sim, uma instancia paralela é criada para a nossa aplicação no momento que referenciamos o objeto a ser copiado.

Carrinho carrinho = (Carrinho) Naming.lookup("rmi://localhost:1099/loja/carrinho");

Neste caso, devemos criar à classe Carrinho na nossa aplicação deve estender uma interface igual à classe alocada no servidor, ou seja, ambas as classes devem ter a mesma interface estendidas. A mesma em tese, ou seja, classes iguais sendo criadas em servidores diferentes (Servidor de Aplicação Cliente RMI & Servidor de Aplicação Fornecedor RMI).

Respondendo as perguntas:

“Se não for abusar, eu gostaria de saber como acionar o registry em um servidor remoto real, uma vez que não temos acesso ao terminal dele.”
Não é abusar, de forma alguma, é um prazer. Apenas entenda que também sou novo em RMI ok. Então o que estou expondo pode não ser uma verdade absoluta.
No exemplo que eu dei eu criei tudo no mesmo servidor usando assim, apenas o Naming.lookup para enxergar o objeto.
Provavelmente se no servidor houver o objeto qual busca, este será retornado sem problemas.
Mas necessitando de maior precisão rode da seguinte forma:

Registry registry = LocateRegistry.getRegistry("http://localhost",1099);
Carrinho carrinho = (Carrinho) Naming.lookup("loja/carrinho");

Onde está o “localhost” aponte o endereço http ou ip do servidor de produção.

“Quando você esta criando as classes Stub/Skeleton com o rmic???”
No capitulo 3 item 6 (3.6) do material da Caelum diz que:
Você pode rodar o rmic (RMI Compliler) para compilar individualmente cada classe rmi, porém, a partir da versão 5.0 não é mais necessário gerar estas classes (cópias). O Java faz isso automaticamente utilizando próxies dinâmicas.

Abraços,

Ref:
http://download.oracle.com/javase/tutorial/rmi/client.html
http://download.oracle.com/javase/1.5.0/docs/guide/rmi/hello/hello-world.html
http://www.javacamp.org/moreclasses/rmi/rmi22.html

Uma outra boa nota sobre o assunto é saber que este transito só é possível por parte do servidor por conta da API JNDI.
Java Naming and Directory Interface
Um pouco mais adiante no material vejo que o Jboss possui um arquivos de configuração de serviços de diretórios.
Um servidor do tipo do Jbos é destinado a aplicações servidoras por suportar funcionalidades de disposição de dados remotamente.
Em teoria o servidor cliente faz uso da JNDI configurada no servidor fornecedor.

Vide:
http://pt.wikipedia.org/wiki/JNDI
Abçs,
Jsign

Obrigado pelos esclarecimentos,

Eu estava estudando RMI com base no livro “Use a Cabeça”, porem o assunto é abordado muito sutilmente lá.

De qualquer forma, obrigado pela atenção.

Continuarei aqui com meus estudos.

[]'s

Legal ganondorfan,
Bons estduos, até uma próxima.

[]'s
Jsign

Esta mandando muito bem! Continue assim empenhado nos exercicios.

Boa noite Paulo.

Quando eu vi a mensagem pensei “Nossa meu! Um elogio publico de um mestre da Caelum. Sério !”.
Me senti vingado dos bugs e exceptions da vida…

Muito obrigado.
[]'s.
Jsign