Here’s our first
implementation of the RestoPeer
class (the code
that provides the restaurant service). A RestoPeer is responsible for
discovering and joining the RestoNet peergroup; if the peer cannot
find the RestoNet peergroup, the peer will create it.
The RestoPeer class has a simple structure:
Discover the existing RestoNet peergroup advertisement.
Look for any previously discovered advertisements in the local cache.
Send the PDP request to discover the advertisement.
This may be done using a broadcast-type mechanism or by contacting known rendezvous peers, either of which is a synchronous call to the developer. Behind the scenes, the API will create a new thread that will listen for responses. As these responses come back, the background thread will read them and insert the responses into the peer’s local cache of advertisements.
Wait a while for any responses to come back.
Look again for responses in the local cache.
If the existing RestoNet is not found, create a peergroup advertisement for it. Then create the peergroup based on that advertisement.
If the existing RestoNet is found, use the discovered advertisement to join the peergroup.
Here’s the code necessary to perform these steps:
import java.io.*; import java.net.*; import java.util.*; import net.jxta.peergroup.PeerGroup; import net.jxta.peergroup.PeerGroupFactory; import net.jxta.peergroup.PeerGroupID; import net.jxta.exception.PeerGroupException; import net.jxta.discovery.DiscoveryService; import net.jxta.id.IDFactory; import net.jxta.pipe.PipeService; import net.jxta.protocol.PeerGroupAdvertisement; import net.jxta.protocol.ModuleImplAdvertisement; // RestoPeer represents a restaurant that receives auction requests // for food from HungryPeers. The RestoPeer will discover and join // the RestoNet and publish itself as a provider for HungryPeers public class RestoPeer { private PeerGroup netpg = null; // The NetPeerGroup private PeerGroup restoNet = null; // The RestoNet peergroup private String brand = "Chez JXTA"; // Brand of my restaurants private int timeout = 3000; // Time-out; can be adjusted // Services within the RestoNet peergroup private DiscoveryService disco; // Discovery service private PipeService pipes; // Pipe service static String groupURL = "jxta:uuid-4d6172676572696e204272756e6f202002"; public static void main(String args[]) { RestoPeer myapp = new RestoPeer( ); myapp.startJxta( ); System.exit(0); } // Start the JXTA application private void startJxta( ) { try { // Discover and join (or start) the default peergroup netpg = PeerGroupFactory.newNetPeerGroup( ); } catch (PeerGroupException e) { // Couldn't initialize; can't continue System.out.println( "Fatal error : creating the net PeerGroup:); System.exit(1); } // Discover (or create) and join the RestoNet peergroup try { joinRestoNet( ); } catch (Exception e) { System.out.println("Can't join or create RestoNet"); System.exit(1); } // Wait for HungryPeers System.out.println("Waiting for HungryPeers"); while (true) { // In later examples, HungryPeer requests are processed here // For now, we'll just block indefinitely synchronized(this) { try { wait( ); } catch (InterruptedException ie) {} } } } // Discover (or create) and join the RestoNet peergroup private void joinRestoNet( ) throws Exception { int count = 3; // Maximun number of attempts to discover System.out.println( "Attempting to Discover the RestoNet PeerGroup"); // Get the discovery service from the NetPeergroup DiscoveryService hdisco = netpg.getDiscoveryService( ); Enumeration ae = null; // Holds the discovered peers // Loop until we discover the RestoNet or // until we've exhausted the desired number of attempts while (count-- > 0) { try { // Search first in the peer's local cache to find // the RestoNet peergroup advertisement ae = hdisco.getLocalAdvertisements( DiscoveryService.GROUP, "Name", "RestoNet"); // If we found the RestoNet advertisement, we are done if ((ae != null) && ae.hasMoreElements( )) break; // If we did not find it, we send a discovery request hdisco.getRemoteAdvertisements(null, DiscoveryService.GROUP, "Name", "RestoNet", 1, null); // Sleep to allow time for peers to respond to the // discovery request try { Thread.sleep(timeout); } catch (InterruptedException ie) {} } catch (IOException e) { // Found nothing! Move on. } } PeerGroupAdvertisement restoNetAdv = null; // Check if we found the RestoNet advertisement. If we didn't, then // either we are the first peer to join or no other RestoNet peers // are up. In either case, we must create the RestoNet peergroup. if (ae == null || !ae.hasMoreElements( )) { System.out.println( "Could not find the RestoNet peergroup; creating one"); try { // Create a new, all-purpose peergroup ModuleImplAdvertisement implAdv = netpg.getAllPurposePeerGroupImplAdvertisement( ); restoNet = netpg.newGroup( mkGroupID( ), // Assign new group ID implAdv, // The implementation // advertisement "RestoNet", // Name of peergroup "RestoNet, Inc."); // Description of peergroup // Get the peergroup advertisement restoNetAdv = netpg.getPeerGroupAdvertisement( ); } catch (Exception e) { System.out.println( "Error in creating RestoNet Peergroup"); throw e; } } else { // The RestoNet advertisement was found in the cache; // this means we can join the existing RestoNet peergroup try { restoNetAdv = (PeerGroupAdvertisement) ae.nextElement( ); restoNet = netpg.newGroup(restoNetAdv); System.out.println( "Found the RestoNet Peergroup advertisement; " + "joined existing group"); } catch (Exception e) { System.out.println("Error in creating RestoNet " + "PeerGroup from existing adv"); throw e; } } try { // Get the discovery and pipe services for the RestoNet // peergroup (unused in this example) disco = restoNet.getDiscoveryService( ); pipes = restoNet.getPipeService( ); } catch (Exception e) { System.out.println("Error getting services from RestoNet"); throw e; } System.out.println( "RestoNet Restaurant (" + brand + ") is on-line"); return; } private PeerGroupID mkGroupID( ) throws Exception { return (PeerGroupID) IDFactory.fromURL( new URL("urn", "", groupURL)); } }
As with all JXTA applications, the
first thing the RestoPeer must do is discover and join the
NetPeerGroup. Once it has joined this peergroup, it can use the
services of this peergroup. In this case, it uses the discovery
service (hdisco
) of the NetPeerGroup object to
look for the RestoNet peergroup advertisement. We follow the standard
steps outlined above. Check the local cache. If nothing is found, use
the PDP to find the advertisement and sleep for a while to give the
advertisement a chance to be discovered.
We try to discover the advertisement three times. Due to the unpredictable nature of the network, there is no way to tell how long it will take to find an advertisement. The number of attempts depends on your network environment: you may have to adjust the number of tries if you are running through multiple hops, or you may need to sleep longer to allow the message to come back. In general, these decisions must be made on an application-specific basis.
Note that this example uses JXTA’s synchronous discovery API. The JXTA API also provides an asynchronous mechanism that an application can use to be notified when a resource is discovered (we show this API in Chapter 5). The synchronous discovery API provides a fine-grained control over the discovery process, while the asynchronous API is easier to manage.
Since we are looking for a peergroup
advertisement, the Discovery.GROUP
type is used in
the getLocalAdvertisements( )
method. The
Name
tag field of the peergroup
advertisement is used to search for the peergroup. We are looking for
a peergroup advertisement in which the
Name
tag has a value equal to
“RestoNet.” Any peergroup
advertisements held in the local cache and with a matching type and
attribute/value pair will be returned by this method. If such an
advertisement is found, we are done, and we exit from the discovery
loop.
If we did
not find the advertisement in the local cache, a discovery request is
sent within the NetPeerGroup via the
getRemoteAdvertisements( )
method to find the
RestoNet advertisement. Since the peer ID is null
,
the discovery request is propagated to all peers in the current
subnet and to the known rendezvous peers for the NetPeerGroup. The
threshold argument for the request is set to 1
,
since there is only one RestoNet peergroup advertisement.
After the discovery request is sent, we sleep for a while before checking the cache to see if some responses were received. When a response is received, the advertisement is automatically stored in the local cache, but we need to allow some time for that process to happen.
Note that a new remote discovery request is sent during each iteration. We must send multiple requests since the JXTA network does not guarantee that a discovery request will be processed by any peers. A rendezvous peer may be overloaded and discard the request. A new rendezvous may be available at the time of the request; as the JXTA network grows, more peers may be willing to respond.
If after three iterations the RestoNet advertisement was not found, then we continue on and create the RestoNet peergroup. We may be the first peer trying to join the RestoNet group, or all the other peers that know about the RestoNet group may be down or unreachable. We don’t know how many other peers are out there, or the state of any previous RestoNet peers; we simply know that, at this point in time, we cannot find the RestoNet peergroup.
If the RestoNet advertisement is not
found, we must create a new RestoNet peergroup. We use the
getAllPurposePeerGroupImplAdvertisement( )
method
of the PeerGroup
class to create a peergroup
advertisement. This creates a generic advertisement; it automatically
sets all of the attributes of the peergroup advertisement based on
the NetPeerGroup (or, more generally, based on whichever peergroup is
being used as the parent of the new peergroup).
The
peergroup advertisement can then be passed to the newGroup( )
method of the NetPeerGroup. This method will create the
new peergroup and send information about the new peergroup to the
JXTA network (so that other peers can discover the newly created
group). This is called publishing the
advertisement; the newGroup( )
method publishes
automatically, but you generally must explicitly publish other
advertisements.
If we discovered an existing RestoNet advertisement, then the
procedure is slightly altered: the RestoNet advertisement itself is
used to instantiate the peergroup (though it still calls the
newGroup( )
method of the NetPeerGroup). In this
case, the newGroup( )
method will join the
existing RestoNet peergroup; it will not need to publish the RestoNet
advertisement as that advertisement has already been published.
It is important to point out that if peers cannot find the RestoNet peergroup, they need to create the same RestoNet peergroup; we don’t want the situtation in which different peers create different versions of the RestoNet peergroup. This is done by ensuring that the peergroup ID generated by each peer is the same.
In our
examples, we do this by using the makeGroupID( )
method in conjunction with a predefined string from which the URL
defining the peergroup ID is generated. The string can be obtained
via the mkpgrp
command of the JXTA Shell by
following these commands:
JXTA>mkpgrp dummygroup
JXTA>groups
group0: name = dummygroup JXTA>cat group0
<?xml version="1.0"?> <!DOCTYPE jxta:PGA> <jxta:PGA xmlns:jxta="http://jxta.org"> <GID> urn:jxta:uuid-4d6172676572696e204272756e6f202002 </GID> <MSID> urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE000000010306 </MSID> <Name> dummygroup </Name> <Desc> Created by mkpgrp </Desc> </jxta:PGA>
Get JXTA in a Nutshell now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.