RMI: Servidor J2SE e Clientes SuperWaba ou J2ME. (Tutorial aqui!)  XML
Índice dos Fóruns » Google Android e Java Micro Edition (ME)
Autor Mensagem
arec_metafora
JavaBaby
[Avatar]

Membro desde: 14/01/2008 08:51:10
Mensagens: 82
Offline

Olá Pessoal. Estou iniciando o desenvolvimento no mundo móvel e me deparei com uma situação desafiadora. Como transmitir dados de um cliente móvel para um servidor Java. A única solução que eu tinha achado era através de sockets. Porém, eu consegui achar uma solução que usasse RMI.

Portanto, para quem enfrenta o mesmo problema que eu, vou postar um minitutorial sobre como conseguir tal facenha.
RMI, Invicação de Métodos Remotos, demonstra um cenário aonde é possível acessar métodos de um objeto que não estão localizados na máquina ou dispositivo aonde se está rodando a aplicação. Para quem deseja saber um pouco mais sobre RMI, acesse o tutorial Introdução ao RMI aqui do GUJ.

A solução RMI para J2ME (MIDP 2.0) foi proposta pelo projeto Arcademis, e a solução para o SW foi feita pelo mesmo projeto, por mim, porém apenas recompilando o código alterando as classes de sockets e outras coisinhas... Créditos totais ao pessoal do Arcademis!
Para começar, efetue o download das três APIS que seguem no fim do tutorial:
arcademis_J2SE.jar: API para o servidor J2SE ou EE
arcademis_J2ME.jar: API para o cliente J2ME
arcademis_SW.jar: API para o cliente SuperWaba

Para testes, a seguinte aplicação vai ser desenvolvida: um cliente pede ao servidor os seus dados (nome do SO, versão, etc) e ele retorna uma string contendo esses dados. Vamos começar implementando a interface remota:



Em seguida, vamos implementar essa interface remota



Se vc entende um pouco da arquitetura do RMI, sabe que essa comunicação exige que vc tenha compilado os stubs e skeletons da implementação da interface remota, pois eles vão servir de elo de ligação e sincronização. Para esse projeto, vc vai ter que efetuar isso no braço. Não é nada complicado. Adiaremos esse passo.
Agora vamos implementar o servidor. Adicione o jar do servidor ao classpath do seu projeto e mãos a obra!



Observe que o servidor possui um método main, mais ele só serve para gerarmos os stubs e skeletons. Coloquei ele aí para facilitar apenas isso. Aquela classe RmeC é a responsável pela geração dos stubs e skeletons. Simples, execute do jeito que está ali, que se o seu projeto tem uma pasta de fontes chamada src, ele vai pro local certo! Só tome cuidado com o último parâmetro: deve ser o nome da classe que possui a implementação da interface remota (sem o .java) e precedido da hierarquia de pacotes. Nesse caso, a classe está dentro do pacote rmi.
Agora faça alguma interfacizinha bem bonitinha e inicie o servidor:



Pronto. Servidor rodando. Agora vamos implementar o cliente. A única diferença da implementação entre J2ME e SW é o jar que vc inclui no seu classpath e os imports. O código é exatamente o mesmo!
Copie pro projeto de app móvel as classes de interface remota e o Stub da implementação remota, no caso teste, os arquivos SystemInformation.java e SimpleSystemInformation_Stub.java. O importante é que elas estejam no mesmo pacote que estavam no servidor, senão dá erro!

Agora, finalmente, a implementação do cliente:



Pronto! Agora faça a chamada do cliente em alguma outra interfacizinha bonita pelo código abaixo:


Abaixo, seguem os jars...
Um abraço a todos, algum problema é só postar!
Até a próxima, pessoal!
 Nome do arquivo arcademis_J2SE.jar [Disk] Download
 Descrição Servidor J2SE
 Tamanho 111 Kbytes
 Baixado:  203 vez(es)

 Nome do arquivo arcademis_J2ME.jar [Disk] Download
 Descrição Cliente J2ME
 Tamanho 47 Kbytes
 Baixado:  183 vez(es)

 Nome do arquivo arcademis_SW.jar [Disk] Download
 Descrição Cliente SuperWaba
 Tamanho 67 Kbytes
 Baixado:  166 vez(es)

This message was edited 7 times. Last update was at 19/09/2008 15:46:36

[Email] [MSN]
dtondo
Entusiasta Java

Membro desde: 30/04/2008 13:17:37
Mensagens: 24
Offline

Cara, muito obrigado pela iniciativa em fazer um tutorial parabéns! Embora ainda não tenha utilidade para mim, um dia pode vir a ter.

This message was edited 1 time. Last update was at 08/09/2008 14:35:08

esbruno
What is classpath?

Membro desde: 02/03/2009 18:47:41
Mensagens: 6
Offline

Olá, achei o seu tutorial e estou tentando testar. sempre que tento compilar recebo as seguites mensagens de erro: (alguma sugestão?)
SimpleSystemInformation.java:12: cannot find symbol
symbol: class SystemInformation
implements SystemInformation {
^
Servidor.java:28: cannot find symbol
symbol : method bind(java.lang.String,rmi.SimpleSystemInformation)
location: class rme.naming.RmeNaming
RmeNaming.bind("rmeTeste",infoObj);
^
RMIClient.java:16: cannot find symbol
symbol : class SystemInformation
location: class RMIClient
SystemInformation info = null;
^
RMIClient.java:23: cannot find symbol
symbol : class SystemInformation
location: class RMIClient
info = (SystemInformation)RmeNaming.lookup("rmeTeste");
^
boone
JWizard
[Avatar]

Membro desde: 21/09/2003 16:01:35
Mensagens: 2140
Offline

arec_metafora wrote:Olá Pessoal. Estou iniciando o desenvolvimento no mundo móvel e me deparei com uma situação desafiadora. Como transmitir dados de um cliente móvel para um servidor Java. A única solução que eu tinha achado era através de sockets. Porém, eu consegui achar uma solução que usasse RMI.


Tá, e qual vantagem que Maria leva em usar RMI e não Socket direto ?

Na verdade usando RMI vc estará usando Socket, pois não existe mágica, já que a conexão ou é TCP (Socket) ou UPD (Datagrama). Quando se usa HTTP no J2ME, no fundo se está usando Socket, sendo o HTTP apenas uma casca, um protocolo, usando o Socket como meio para mensagem chegar até seu destino.

Desculpe, mas não vi ganhos para se partir para algo mais complexo e trabalhoso que provavelmente custará mais, que é usar RMI, pois ele deve adicionar sua própria gordura ao Socket, como o próprio HTTP faz.

Quem transfere dados em J2ME sabe que é fundamental usar bem a banda para não ficar pagando rios de dinheiro para a operadora sem necessidade.

Nesta tarefa, algumas abordagens são usadas:

Compressão do conteúdo antes do envio
Transmissão de registros de tamanho fixo e não delimitados
Não uso de formatos "verbosos" como XML
Evitar transmitir informações picadas em vários requisições HTTP; ao invés disto, juntar sempre o máximo possível em 1
etc...etc...etc...
arec_metafora
JavaBaby
[Avatar]

Membro desde: 14/01/2008 08:51:10
Mensagens: 82
Offline

Qual a vantagem em se usar RMI ao invés de sockets????
Se não houvesse nenhuma, tenho certeza que não existira RMI em Java.

1° - Esse tutorial eu postei porque eu fiz um projeto para PDAs (utilizando o SW), que pode acessar a rede através de uma conexão banda-larga, tornando a transmissão de dados tão rápida quanto um desktop.
2° - É claro que a conexão via RMI utiliza sockets, já que é a base da transmissão de dados. Isto é obvio para todo mundo!
3° - A chamada de métodos remotos é uma coisa tão útil, que vale a pena o overhead de informações transmitidas. Imagine se você quer inserir um objeto (tabela) no banco de dados em um servidor. Pela chamada de método remoto, você apenas dá um Server.insert(nome, idade, etc) e se der certo ele retorna true, se der errado retorna um exception que você declara por interface remota, e por aí vai. Imagine o trabalho que isto daria para vc controlar apenas pelos sockets crus. byte a byte sendo enviado, tratamento de sincronismo dos dados (pq a conexão TCP garante que a stream envia os dados corretamente, mas não garante sincronia entre as transmissões, já que você deve tratar timeout, e trocentas outras coisas mais (que se você já estudou protocolos de rede, como Stop-And-Wait ARC, vai saber o que estou dizendo.)

Enfim, é inadimitível que uma solução RMI para alguns casos j2mE (QUE não tem foco APENAS para celulares) não sirva para nenhum proposto.


esbruno, verifique se você esqueceu de adicionar os jars, referente ao projeto, e as classes de implementação da interface remota.
[Email] [MSN]
boone
JWizard
[Avatar]

Membro desde: 21/09/2003 16:01:35
Mensagens: 2140
Offline

arec_metafora wrote:
Enfim, é inadimitível que uma solução RMI para alguns casos j2mE (QUE não tem foco APENAS para celulares) não sirva para nenhum proposto.


Não estou metendo o pau no RMI, apenas acho que pra quem usa J2ME (que não é apenas para celulares, apenas uns 95%), não vai se beneficiar disto, visto que é um overhead alto para a capacidade destes dispositivos e soluções "cruas" como Socket ou HTTP ainda são as mais adequadas.

Desenvolvimento em PDA pra mim se faz com ferramenta de gente, que é em C++, SW, .Net Compact Framework,etc..não J2ME. Difícel encontrar um louco por aí cujo projeto em produção roda em PDA com J2ME.
arec_metafora
JavaBaby
[Avatar]

Membro desde: 14/01/2008 08:51:10
Mensagens: 82
Offline

Por isso mesmo.
Se você leu todo o post, viu que o meu projeto se destinava a SW, tanto é que eu usei um projeto feito em J2ME e fiz modificações para serem usadas no SW.


A solução RMI para J2ME (MIDP 2.0) foi proposta pelo projeto Arcademis, e a solução para o SW foi feita pelo mesmo projeto, por mim, porém apenas recompilando o código alterando as classes de sockets e outras coisinhas...


Com algumas adaptações, consegui que ele rodasse no SW (que não é 100%, mas quase 99% Java (não J2ME), dado que os bytecodes gerados são o mesmo)

Com relação ao uso de J2ME em dispositivos de baixa capacidade, eu trabalho em uma empresa que desenvolve aplicações para dispositivos que suportam WM e Java.
E metade da demanda do J2ME são para bleckberries e Nokia série 60, que suportam conexeão banda-larga sem fio.

Mas é claro que é muito mais útil usar RMI com o SW. Este é o foco do Post
[Email] [MSN]
esbruno
What is classpath?

Membro desde: 02/03/2009 18:47:41
Mensagens: 6
Offline

Segui todos os passos escritos no tutorial, apatentemente é como se o java não encontrasse a classe SystemInformation na hora de compilar o código, ai todas as classes que dependem dela não "compilam".
arec_metafora
JavaBaby
[Avatar]

Membro desde: 14/01/2008 08:51:10
Mensagens: 82
Offline

esbruno, verifique o seguinte...

Na hora de copiar a classe para o projeto cliente (app móvel), faça a mesma estrutura de pacotes que você fez na aplicação server.

Por exemplo, se vc criou um package rmi, e dentro dele criou a classe SystemInformation, na app cliente crie uma pasta rmi e copie a classe dentro desta pasta.
Você também já verificou se não esqueceu de adicionar os jars à sua aplicação cliente?
[Email] [MSN]
esbruno
What is classpath?

Membro desde: 02/03/2009 18:47:41
Mensagens: 6
Offline

Caro amigo, obrigado pela paciencia. Posso está fazendo besteira mas eu coloquei todos arquivos no mesmo diretório e estou tentando simular a execução numa mesma máquina. O erro está acontecendo na compilação, não estou coneguindo compilar porque o java acusa falta do SystemInfomation.class , mesmo existindo no diretorio.
arec_metafora
JavaBaby
[Avatar]

Membro desde: 14/01/2008 08:51:10
Mensagens: 82
Offline

Você tomou o cuidado de colocar os diretórios em hierarquia, dependendo do pacote?

Por exemplo, rmi.SystemInformation no server...
Você deve criar uma pasta rmi e adicionar o .java dentro dela, do mesmo modo que foi feito no servidor.
[Email] [MSN]
esbruno
What is classpath?

Membro desde: 02/03/2009 18:47:41
Mensagens: 6
Offline

Removi a declaração package dos arquivos de modo a todos ficarem no mesmo pacote, diretorio atual.
arec_metafora
JavaBaby
[Avatar]

Membro desde: 14/01/2008 08:51:10
Mensagens: 82
Offline

Você fez o mesmo no servidor?

Que eu me lembre, as interfaces remotas nunca poderiam ficar na raiz. Não me lembro o motivo, mas não podem.
Tente refazer o tutorial, sem removê-las dos diretórios.
[Email] [MSN]
esbruno
What is classpath?

Membro desde: 02/03/2009 18:47:41
Mensagens: 6
Offline

Refiz o prcedimento seguindo extamente como sugerido e a aplicação rodou. A dúvida é a seguinte: A classe RMIClient recebe o endereço do host ao qual ela vai solicitar a informação , public String getSystemInfo(String host throws Exception ... mas não utiliza essa variavel internamente. Como o cliente direciona que maquina que ele vai fazer a consulta? no caso o SimpleSystemInformation.

Testei configurando qualquer IP na classe que invoca o metodo abaixo e sempre dá o mesmo resultado.
RMIClient client = new RMIClient();
try {
System.out.println(client.getSystemInfo(127.0.0.0)
arec_metafora
JavaBaby
[Avatar]

Membro desde: 14/01/2008 08:51:10
Mensagens: 82
Offline

É verdade, você tem razão.
Este projeto foi uma parte de um TCC para concusão de curso.
Eu fiz as alterações para usar IP externo.
No sábado eu viajo para minha cidade (estou morando fora) e aí eu passo as correções, ok?

Mas eu acho que as alterações foi no método lookup do RmeNaming no cliente



Tente achar alguma coisa...
Sábado eu postarei as modificações

Abraços, att
[Email] [MSN]
 
Índice dos Fóruns » Google Android e Java Micro Edition (ME)
Ir para:   
Powered by JForum 2.1.8 © JForum Team