RMI é... velho. É um assunto batido, bem documentado, sem maiores mistérios, mas que é um dos pilares mais importantes do JEE, embora ele esteja caminhando para o esquecimento a passos largos com a chegada de tecnologias como o CDI.
Ainda assim, se você estiver estudando não me custa quase nada dar os toques do que fazer, ;-)
Como imaginado, o assunto aqui é prática. Se quiser teoria, tem aqui.
Comece abrindo o eclipse e criando um projeto chamado rmi_sample1:
Uma vez criado o projeto, vamos criar dois pontos de entrada: um para ser usado quando rodarmos o cliente, outro para quando rodarmos o servidor. Bastam duas classes por hora, cada uma com um método main():
Vamos fazer o seguinte agora: na classe do servidor vamos subir o registro, pois sem ele não poderemos disponibilizar os objetos remotos:
public static void main(String[] args) throws Exception { LocateRegistry.createRegistry(1099); }
Outra forma de fazer é chamar na linha de comando o rmiregistry, mas vamos fingir que isso jamais existiu, ;-)
Falemos um pouco sobre o tal "objeto remoto":
- Deve implementar uma interface que extenda a interface Remote.
- Deve herdar de UnicastRemoteObject.
- Deve sobrescrever e chamar ativamente o construtor padrão.
No nosso exemplo vamos fazer um pequeno cadastro de alunos. Crie uma interface chamada GestorAlunos:
package sample.api; import java.rmi.Remote; public interface GestorAlunos extends Remote { void adicionarAluno(); String removerAluno(); void consultarAluno(); void listar(); }
Você pessoa esperta que é sabe que esta interface não está completa. Mas quando você estiver criando suas coisas você pode ir por esta abordagem também: defina os nomes, para depois definir os detalhes.
Por exemplo, vamos precisar de uma classe chamada Aluno:
Vamos colocar no aluno estes atributos:
package sample; public class Aluno { private int codigo; private String nome; private double nota1,nota2,nota3; private int frequencia; }
Claro, não esqueça de gerar os getters/setters usando o atalho do eclipse:
Feito isso, volte à interface GestorAlunos e modifique-a:
package sample.api; import java.rmi.Remote; import java.util.List; import sample.Aluno; public interface GestorAlunos extends Remote { Aluno adicionarAluno(Aluno aluno) throws RemoteException; String removerAluno(int codigo) throws RemoteException; Aluno consultarAluno(int codigo) throws RemoteException; Listlistar() throws RemoteException; }
Parece bom... muito bom... mas até agora apenas definimos o contrato entre o cliente e o servidor, nada mais.
Esta interface, inclusive, será comum aos seus clientes e ao servidor.
vamos para a diversão, vamos fazer agora a implementação do GestorAlunos:
package sample.impl; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.List; import sample.Aluno; import sample.api.GestorAlunos; public class GestorAlunosImpl extends UnicastRemoteObject implements GestorAlunos { public GestorAlunosImpl() throws RemoteException { super(); } private static final long serialVersionUID = 1179227415408023062L; @Override public Aluno adicionarAluno(Aluno aluno) { return null; } @Override public String removerAluno(int codigo) { return null; } @Override public Aluno consultarAluno(int codigo) { return null; } @Override public Listlistar() { return null; } }
Observe que esta implementação faz nada ainda, apenas implementamos os métodos que a interface obriga bem como herdamos de UnicastRemoteObject.
Vamos deixar assim, uma coisa que chamo de wireframe. Vamos seguir para o MainServer novamente e colocar a nossa implementação no registro:
package sample; import java.rmi.Naming; import java.rmi.registry.LocateRegistry; import sample.api.GestorAlunos; import sample.impl.GestorAlunosImpl; public class MainServer { /** * @param args */ public static void main(String[] args) throws Exception { LocateRegistry.createRegistry(1099); GestorAlunos gestor = new GestorAlunosImpl(); System.out.println("Servidor rodando"); Naming.rebind("//localhost/GestorAlunos", gestor); System.out.println("Objeto publicado"); } }
Feito isso o MainServer passa a ser responsável por subir o registro e em seguida disponibilizar o objeto remoto.
Vamos ao MainClient fazer o código de recuperar a referência pro objeto remoto:
package sample; import java.rmi.Naming; import sample.api.GestorAlunos; public class MainClient { /** * @param args */ public static void main(String[] args) throws Exception { // conseguindo uma referência remota GestorAlunos gestor = (GestorAlunos) Naming// .lookup("//localhost/GestorAlunos"); // fazendo coisas com o gestor Aluno a = new Aluno(); a.setNome("Fulano de tal"); a.setFrequencia(100); a.setNota1(10.0); a.setNota2(9.5); a.setNota3(7.0); a = gestor.adicionarAluno(a); System.out.println(a); } }
Simples né? Vamos rodar. Primeiro rode o MainServer (botão direito nele, Run As > Java Application)
Em seguida faça o mesmo com o MainClient. Mas veja, algo de diferente ocorreu:
Esse erro é comum entre estudantes, e a solução é super simples. Torne a classe Aluno serializável:
package sample; import java.io.Serializable; public class Aluno implements Serializable{ private static final long serialVersionUID = 1728799560066886492L; private int codigo; private String nome; private double nota1,nota2,nota3; private int frequencia; public int getCodigo() { return codigo; } public void setCodigo(int codigo) { this.codigo = codigo; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public double getNota1() { return nota1; } public void setNota1(double nota1) { this.nota1 = nota1; } public double getNota2() { return nota2; } public void setNota2(double nota2) { this.nota2 = nota2; } public double getNota3() { return nota3; } public void setNota3(double nota3) { this.nota3 = nota3; } public int getFrequencia() { return frequencia; } public void setFrequencia(int frequencia) { this.frequencia = frequencia; } }
Salve.
Importante, você vai precisar parar o MainServer novamente, afinal ele ainda está rodando e está com a definição antiga de classe. Agora rode o MainServer novamente. Tudo certo dessa vez, né?
Retornou null, mas não se preocupe ainda: vamos para o GestorAlunosImpl olhar o método adicionarAluno. Vamos modificar essa implementação pra que nos dê algo mais interessante:
package sample.impl; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import java.util.ArrayList; import java.util.List; import sample.Aluno; import sample.api.GestorAlunos; public class GestorAlunosImpl extends UnicastRemoteObject implements GestorAlunos { private int seq = 0; private Listalunos = new ArrayList (); public GestorAlunosImpl() throws RemoteException { super(); } private static final long serialVersionUID = 1179227415408023062L; @Override public Aluno adicionarAluno(Aluno aluno) { aluno.setCodigo(++seq); alunos.add(aluno); System.out.println("Aluno adicionado com código " + aluno.getCodigo()); return aluno; } @Override public String removerAluno(int codigo) { return null; } @Override public Aluno consultarAluno(int codigo) { return null; } @Override public List listar() { return null; } }
Que beleza, né? agora ele adiciona numa lista e retorna com um código.
Entretanto, se você rodar o MainClient de novo, o retorno ainda será null. Por que isso?
Nosso GestorAlunosImpl não tem os stubs gerados.
Classicamente gerar stubs era um saco, mas estamos usando eclipse e portando a vida é boa.
Crie na raiz do projeto eclipse um arquivo chamado build.xml que tenha isso:
Aperte F5 na pasta do projeto e tenha uma surpresa, :-)
Agora, volte ao MainServer e rode-o outra vez. E faça a mesma coisa com o MainClient:
Bacana?
Agora voe sozinho, passarinho, que o resto é simples, e se você usar o que você viu aqui só o sucesso lhe espera, ;-)
Sem mais para o momento, apenas boa sorte!
Nenhum comentário :
Postar um comentário