JXTA – Parte II

 

Peer Rendezvous Protocol (PRP)

Esse protocolo é utilizado para propagar mensagens dentro de um peergroup e gerenciar a maneira como essas mensagens são roteadas. Um peer Rendezvous se comunica com outros peer Rendezvous para propagar as mensagens de forma que esse controle não fique centralizado. O conjunto de peers Rendezvous de um peeergroup é conhecido como PeerView.

 

Para efetuar o controle de propagação das mensagens, esse protocol pode utilizar os seguintes controles:

·         Loop: Se uma mensagem propagada já foi processada por um peer eleé discartada;

·         Time To Live: Tempo para expirar a mensagem. Toda vez que a mensagem é recebida por um peer, o Time To Live é decrementado.

 

Importante lembrar que as mensagens pelo peer Rendezvous utilizam diretamente o Peer Endpoint Protocol e não o Peer Resolver Protocol, e um peer pode dinamicamente se tornar um Rendezvous peer.

 

Peer Discovery Protocol (PDP)

O Peer Discovery Protocol (PDP) foi projetado para permitir a publicação e pesquisa de advertisements dentro de um peergroup. Porém um peer não tem garantias que receberá uma Discovery Response Message. O PDP utiliza o Resolver Protocol para rotear suas mensagens para outros peers.

 

Os peer groups são muito importantes no processo de descoberta, pois limitam o escopo da busca. Isto significa que um peer descobrirá somente advertisements de recursos que também fazem parte do(s) grupo(s) a que pertence.

 

O objetivo do protocolo é fornecer a infra-estrutura necessária para implementação de serviços de Discovery, capazes de utilizar essa infra-estrutura para aprimorar a busca de um recurso, utilizando mecanismos de caching e controle do tempo de expiração de advertisements, por exemplo. Porém, quando um peer entra no NetPeerGroup o protocolo PDP é o serviço padrão para discovery.

 

Discovery Query Message é o protocolo utilizado pelos peers para fazer uma query.

 

A Discovery Response Message é o protocol utilizado para responder uma Discovery Query Message, ou para publicar um recurso quando a Discovery Response não é a resposta de nenhuma Discovery Query.

 

Um das maneiras de se descobrir/publicar recursos no peergroup é através do envio de mensagens a um Rendezvous.

 

Endpoint Routing Protocol (ERP)

Conforme citado anteriormente, as redes P2P são ad-hoc. As rotas de comunicação podem mudar frequentemente, peers podem entrar e sair da rede rapidamente.

 

Esse protocolo define um conjunto de mensagens de query e request para que um peer envie mensagens ao peer de destino, independente da sua localização na rede, ou se estão separados por firewall, ou ainda estão utilizando endereços de IP privados incompatíveis.

 

Para se comunicar através de uma firewall, os peers que estão dentro dela devem conhecer ao menos um peer que está fora da firewall, e vice-versa, e ambos devem também suportar protocolo HTTP. Quando necessário um ou mais peers roteadores são utilizados para garantir a troca de mensagens entre o peer e o peer destino. Nesse caso, o peer está sendo utilizado como roteador é chamado de Relay Peer.

 

Quando um peer quer enviar mensagem a outro peer, primeiramente ele procura no seu cachê local se já não há nenhuma rota conhecida (advertisemente de uma rota). Caso ele não ache, envia uma mensagem aos peers roteadores perguntando informações sobre a rota. Se o peer roteador souber, ele retorna a rota para o peer que enviou a query. Com a dinamicidade da rede, algumas vezes a rota que o peer roteador conhece já na é mais válida. Nesse caso ele deve descobrir uma nova rota de acesso. As mensagens de roteamento são enviadas utilizando o Resolver Protocol:

 

Resolver Query Message e Resolver Response Message.

 

O endereço de um peer destino é identificado através de um EndPoint Address. Abaixo segue um exemplo:

http://192.168.0.11:9700/endpoint/resolver

 

urn:jxta:uuid-59616261646162614E50472050325033D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D104?
pipeService

 

urn:jxta:jxta-NetGroup?relay/uuid-59616261646162614A7874615032503369D1041721754AD18D7
D9137C06F77DD03

 

Pipe Binding Protocol (PBP)

O Pipe Advertisement é utilizado justamente para criar uma associação entre o Output Pipe e o Input Pipe. Ele se divide em três tipos:

·         JxtaUnicast: Pipe utilizado para comunicar dois peers entre si;

·         JxtaUnicastSecure: Pipe seguro utilizado para comunicar dois peers entre si;

·         JxtaPropagate: Pipe usado para propagar mensagens de um peer para vários outros peers.

 

Abaixo segue um exemplo de um Pipe Advertisement enviando mensagem para vários peers.

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jxta:PipeAdvertisement>
<jxta:PipeAdvertisement xmlns:jxta="http://jxta.org">
  <Id>
     urn:jxta:uuid-94AB61B99C14AB694D5BFD56C66E512FF7980EA1E6F4C238A26BB362B34D1F104              </Id>
  <Type>JxtaUnicast</Type>
  <Name>Hello World</Name>
</jxta:PipeAdvertisement>

 

Peer Information Protocol (PIP)

Uma vez que um peer foi localizado é possível obter informações sobre ele. Esse protocolo fornece uma série de mensagens para se obter o status de um peer. O PIP é um protocolo opcional do JXTA. Sendo assim, os peers não são obrigados a responder as mensagens do PIP.

 

Esse protocolo utiliza o Peer Resolver Protocol para enviar suas mensagens.

 

Para uma mensagem enviada é retornado: tempo de resposta, tráfego na rede, etc.

 

Construindo Aplicações em JXTA

A primeira vez que uma aplicação JXTA é executada, é aberto a ferramenta JXTAConfigurator, para auto-configuração do peer. Nela é possível fazer configurações de HTTP, TCP/IP, Rendezvous, Relay, etc. As configurações são armazenadas , por padrão, no arquivo .jxta/PlataformConfig. Caso deseje mudar o caminho desse diretório configure a variável -DJXTA_HOME="diretorio".

 

Configurando a plataforma JXTA

    configurator = NetworkConfigurator.newRdvRelayConfiguration(new File(instanceHome).toURI());
    try {
        configurator.save();
       }catch(IOException e) {
           e.printStackTrace();
           System.exit(1);
       }

 

O valor padrão da String instanceHome é “.jxta”, mas outros diretórios podem ser informados. Neste diretório será adicionado o diretório cm, que é o gerenciador de cache da plataforma JXTA, e o arquivo PlatformConfig, que é um arquivo XML contendo as configurações da plataforma.

 

O NetworkConfigurator, é a classe mais indicada para se configurar a plataforma JXTA. Neste caso, criou-se um peer com configuração padrão para ser ao mesmo tempo um Rendezvous e um Relay. Por outro lado, a chamada abaixo permite criar um peer com configuração padrão para ser um edge peer.

 

NetworkConfigurator.newEdgeConfiguration(new File(instanceHome).toURI());

A escolha de qual dos métodos utilizar irá depender do papel desempenhado por aquele peer na rede JXTA. É aconselhável que cada aplicação tenha pelo menos um Rendezvous, mas o número de Rendezvous mantido deve ser mínimo. Se existir peers dentro e fora de firewalls, NATs, DHCPs, Proxy então o uso de um peer Relay é imprescindível.

 

A chamada ao método save() faz com que o arquivo PlatformConfig seja salvo no diretório padrão do JXTA. 

 

Caso o arquivo PlatformConfig já exista no diretório padrão do JXTA então o código abaixo instanciame carrega o arquivo PlatformConfig.


     configurator = new NetworkConfigurator();
     try {
         configurator.load(new File(instanceHome + File.separator +      “PlatformConfig”).toURI());
     } catch (IOException e) {
         e.printStackTrace();
     } catch (CertificateException e) {
         e.printStackTrace();
     }

 

Instanciando a plataforma JXTA


Após a criação do objeto de configuração, NetworkConfigurator, o próximo passo é efetivamente instanciar a plataforma JXTA, que pode ser feito mediamente o código abaixo:

    NetPeerGroupFactory factory = new NetPeerGroupFactory( (ConfigParams)configurator.getPlatformConfig(), new File(instanceHome).toURI());

    PeerGroup peerGroup = factory.getInterface();

 

O objeto peerGroup será utilizado para acessar os serviços do JXTA e enviar mensagens pela rede.

 

Criando pipes 

Para se enviar e receber mensagens utilizando-se a plataforma JXTA é necessário criar um pipe. O trecho abaixo é encarregado de criar um PipeID, utilizando o objeto peergroup e um vetor de bytes atuando como semente de inicialização do pipe, a String seed. Para criar o pipe que será utilizado pelos 2 peers que irãos e comunicar é necessário utilizar sempre o mesmo vetor de bytes. Abaixo o Pipe Advertisement e o PipeID deste Advertisement são configurados:


    String seed = “___293430af2221923930__”;
    PipeID pipeID = IDFactory.newPipeID(peerGroup.getPeerGroupID(), seed.getBytes());
    PipeAdvertisement pipeAdv = PipeUtilities.createNewPipeAdvertisement(peerGroup, PipeService.UnicastType);
    pipeAdv.setPipeID(pipeID);

 

Enviando e recebendo mensagens via JxtaSockets

Uma das formas mais convenientes de se enviar e receber mensagens via Jxta é através do uso de JxtaSockets, que são uma implementação em Jxta da interface Sockets presentes em Java.

 

O JxtaServerSocket é um pipe bi-direcional que funciona como se fosse um ServerSocket. Ele cria um InputPipe e aguarda por conexões de outros peers.


     
JxtaServerSocket server = new JxtaServerSocket(peerGroup, pipeAdv);
   server.setSoTimeout(0);
   JxtaSocket client = (JxtaSocket) server.accept();
   OutputStream os = client.getOutputStream();
   os.write(“Hello from server”.getBytes());
   os.flush();


Para se criar o objeto JxtaServerSocket é necessário passar como parâmetro o peerGroup e o pipeAdv criados anteriormente. O timeout é definido como zero, o que significa que o peer aguardará eternamente por uma conexão. As linhas seguintes esperam pela conexão de um peer, recuperam um OutputStream e enviam uma String de response. É importante observar ao se utilizar Jxta não se deve esperar que a plataforma envie os dados antes que o buffer esteja preenchido, por isso chamamos o método os.flush().
 

Antes de tentar conectar-se com um peer para enviar dados é necessário verificar se o peer encontra-se conectado a um Rendezvous. Isto é importante, pois os Rendezvous são responsáveis pela organização dos peers na rede Jxta, e roteamento dos dados. O método isConnectedToRendezVous cumpre a função de verificar se o peer encontra-se conectado a um Rendezvous antes de tentar enviar uma mensagem.


   while (!peerGroup.getRendezVousService().isConnectedToRendezVous()) {}
   JxtaSocket client = new JxtaSocket(peerGroup, null, pipeAdv, 60 * 1000);
   InputStream is = client.getInputStream();
   byte[] buf = new byte[256];
   int read = is.read(buf); 

 

Após conectado a um Rendezvous é criado o objeto JxtaSocket, passando-se como parâmetro o peerGroup e pipeAdv criados anteriormente. O segundo parâmetro do método construtor especifica a qual peer o JxtaSocket deve tentar se conectar. O fato de ser null indica que o cliente deseja se conectar a qualquer peer que esteja escutando no Pipe Advertisement pipeAdv. Por esse motivo que é utilizado o mesmo pipeAdv para criar o JxtaSocket dos 2 peers. Por fim, o tempo de expiração máximo da espera será de 1 minuto (60 * 1000). 

    
As linhas seguintes recuperam um InputStream , e lêem o conteúdo da response em um vetor de bytes. 

 

Fechando a plataforma JXTA

Para que se possa fechar a plataforma JXTA de forma limpa, isto é, enviando as mensagens de fechamento dos pipes e conexões com o Rendezvous. Isto garante uma integridade e consistência das conexões posteriores com o mesmo Rendezvous. Desta forma, é aconselhável chamar o método unref() do objeto peerGroup conforme abaixo: 

    peerGroup.unref();

 

Conclusão

Nesse artigo procuramos introduzir os conceitos básicos da tecnologia JXTA e mostrar um pequeno exemplo de comunicação entre 2 peers.

 

Características como dinamicidade, independência de linguagem e dispositivo estão tornando JXTA cada vez mais utilizado no mercado. Empresas como Nokia, Siemens, entre outras que já utilizam essa tecnologia, como alternativa de solução para sistemas distribuídos.

 

Como o próprio nome sugere: JXTA vem da palavra Juxtapose, que significa lado-a-lado, considerando-se assim que essa tecnologia caminha lado-a-lado com os modelos mais conhecidos hoje como Web e cliente-servidor.

Referências

   1. JXTA Project - http://www.jxta.org
   2. JXTA Protocols Specification - http://spec.jxta.org/nonav/v1.0/docbook/JXTAProtocols.html
   3. Bondolo Blog - http://blogs.sun.com/bondolo/
   4. JXTA Blog - http://weblogs.java.net/weblogs/project/238
   5.
JXTA Wiki - http://wiki.java.net/bin/view/Jxta/WebHome
   6. ALEM - http://component-oriented.dev.java.net/

 

Autores 

Gabriel Nascimento é arquiteto de soluções corporativas. Trabalha com Java a 5 anos. Atualmente, é responsável pela área de sistemas de alta disponibilidade J2EE para canais lotéricos da Caixa Econômica Federal.

 

Edward Ribeiro, especialista em aplicações distribuídas.

 

Pedro Henrique, SCJP, analista de sistemas da CONAB.

Leia também