Peer-to-peer applications made easy

Get started developing cross-platform P2P applications using Jxta and its Java binding

1 2 Page 2
Page 2 of 2
  • Both peers read in the same pipe advertisement from a file
  • The pipe ID is hard-coded into the applications
  • Publish and discover the pipe ID at runtime
  • Pipe ID is generated from a well-known ID

If you are creating input pipes, the first two approaches can be dangerous, because more then one peer can create an input pipe from the same pipe advertisement, causing you to communicate with the wrong peer. If you use the third technique and have a mechanism to discover the specific pipe from a desired peer, this problem shouldn't surface.

For a peer to discover a pipe advertisement from another, it needs to know something about what the advertisement will contain; usually, it knows the Name attribute. When creating pipe advertisements, keep in mind how other peers will try to discover the pipes you create. Another thing that certainly needs to be considered when using discovery to find pipes is the lifetime of the advertisement to be published. By default, advertisements stay in the local cache for 365 days and in the remote cache for 2 hours. If you are creating new pipe advertisements, then you certainly need to decrease these values.

After the advertisement is published, we use the pipe service to create the pipe. In addition, a pipe advertisement needs to be created and published for the newly created pipe.

Consider the following code that creates a new input pipe and publishes the advertisement (Note: Though I don't discuss it here, there is a technique that generates the pipe ID from a well-known ID to bind to the pipe, which would prevent us from having to publish the pipe advertisement.):

 private void   createPublishInputPipe(PeerGroup peerGroup)
{
    System.out.println("Creating new input pipe advertisement");
    //We need to create a new PipeId, create an InputPipe then 
        //publish it
    DiscoveryService discoService = 
        peerGroup.getDiscoveryService();
        
    //Get the pipe service for the peer group
    PipeService pipeService = peerGroup.getPipeService();
    //Create the advertisement for the pipe
    PipeAdvertisement pipeAdv = 
        (PipeAdvertisement) AdvertisementFactory.newAdvertisement( 
            PipeAdvertisement.getAdvertisementType() );
    //We want a point-to-point pipe
    pipeAdv.setType( PipeService.UnicastType );
    ID pipeId = IDFactory.newPipeID( peerGroup.getPeerGroupID() );
    pipeAdv.setPipeID( pipeId );        
    pipeAdv.setName( "JxtaDemoPipe" );
    pipeAdv.setDescription( "Jxta demo pipe example" );
               
    try
    {
        //Create the input pipe and register the listener
        //pipeMessageListener assumed to be initalized
        pipeService.createInputPipe(pipeAdv, 
            pipeMessageListener );
            
        //Now let's publish the pipe in the peerGroup
        discoService = peerGroup.getDiscoveryService();
        //DEFAULT_PIPE_LIFETIME is static class (type long) 
              //variable value = 1000*60*5 = 5 minutes
        //Publish locally
        discoService.publish( pipeAdv, DEFAULT_PIPE_LIFETIME, 
            DEFAULT_PIPE_LIFETIME );
        //Publish to other peers
        discoService.remotePublish(pipeAdv,DEFAULT_PIPE_LIFETIME);
    }
    catch (IOException e)
    {
        System.out.println("IOException occurred");
        e.printStackTrace();
    }
        
    System.out.println("Input pipe published locally/remotely.");
}

In the above example, a new pipe advertisement is created with a brand new pipe ID. It publishes remotely and locally, using the discovery service, with a 5-minute lifetime. Now that we have set up the peer to receive messages, the sending peer can discover the pipe advertisement and bind to it. In the next section, I discuss how to discover an advertisement; since we know the pipe's name, we use this to discover the pipe.

Advertisements

Advertisements are the means for describing and publishing resources. When published, advertisements have an associated lifetime, which enables stale advertisements to be identified and thrown away. As previously mentioned, the default lifetime, in the current implementation, is 365 days for locally published resources and 2 hours for remotely published resources. Keep that in mind as you create and publish advertisements. Sometimes it may be helpful to shorten, or even lengthen, these default values.

When discovering advertisements, Jxta uses multicast to send the messages to the local subnet that the peer lies in. If you need to send messages outside this region, make sure you are connected to a rendezvous peer, which will send the messages for you. Also, if you are behind a firewall or if your network uses Network Address Translation, then to communicate with outside peers, you will also have to specify a relay peer. To discover peer resources, we use the Jxta platform's discovery service, which is an asynchronous means of discovering resources. We send out discovery queries and, hopefully, gather some responses.

Two approaches accomplish the task of discovering advertisements:

  1. Make a call to discover remote advertisements, then later look in the local cache for found advertisements
  2. Make a call to discover remote advertisements and register a listener to be activated when an advertisement is received

Let's now look at how we actually make discovery requests. Here are the signatures for the getRemoteAdvertisement() methods in the net.jxta.Discovery.DiscoverService interface:

 

int getRemoteAdvertisements(String peerid, int type, String attribute, String value, int threshold)

int getRemoteAdvertisements(String peerid, int type, String attribute,String value, int threshold, DiscoveryListener listener)

The only attributes that may need clarification are listed below:

  • attribute: The name of the attribute that must be contained in the advertisement. If you'd rather not use attribute, you can use null instead. If supplied, attribute must match exactly an attribute contained in the advertisement. A typical example is Name, because typically you know the name of the advertisement you are looking for.
  • value: The value of the attribute you are looking for. If null is specified, then all matching advertisements are returned. In this attribute, you can use the '*' wildcard. For example: JxtaDemoPipe*.
  • threshold: This is the maximum number of responses you want to receive from each peer. Keep this to a minimum to ensure you don't waste network resources.

Though using the discovery service may seem straightforward, you must be careful. Sometimes the results of these queries may not turn out to be what you expect. If you publish your advertisements with an appropriate lifetime, you are more likely to find the resources you are looking for. If you are getting unexpected results, look at some of the documents in Resources for more specific information regarding the details behind the discovery service.

Conclusion

This article has provided you with the essential knowledge of Jxta needed to start creating your own P2P applications. As you continue to learn Jxta, examine some of the existing projects; they are a great way to find good examples. While creating your applications, also refer to the sources listed in Resources. I also encourage users to join the wonderful Jxta mailing list located at the Jxta homepage. Jxta has a great community, and new users will find these mailing lists invaluable.

Special thanks to Daniel Brookshier, Sayed Y. Hashimi, Robert Bird, and "Magic" Mike Murphy.

Sayed Ibrahim Hashimi is a software engineer for Icarus Software. He will receive a BS in computer engineering from the University Of Florida in August 2005. His interests include Novel P2P applications, testing distributed systems, computer graphics, virtual humans, end-user assisted programming, human-computer interaction, 3D surface parameterization, and coffee. Hashimi is active in the Jxta community mailing lists.

Learn more about this topic

1 2 Page 2
Page 2 of 2