In part two of this series of book excerpts on getting started with JXTA, from JXTA in a Nutshell, learn about peergroups and discovery, which are important for understanding peer-to-peer Web services.
Peers self-organize into groups. JXTA does not define what these groups are, nor why they exist: the JXTA framework supports the creation of groups and the definition of group membership, but it is up to cooperating peers to define groups, join groups, and leave groups. Among other purposes, peergroups serve to:
Define a set of services and resources
In order to participate in an auction, a peer must find a JXTA peergroup that provides an auction service. The peer must join that group; only peers that have joined the group can use the services available in the group.
There are a number of important resources that exist within each peergroup. A service is a specific type of JXTA resource. A peer that wants to use the resources of a particular peergroup must join that peergroup. Similarly, peers can communicate only with each other if they have joined the same group (although, as we'll see, all peers belong to the NetPeerGroup, so they can always communicate with each other).
Provide a secure region
In This Series
Because of their membership requirement, peergroups form an entity with a logical boundary. Peergroups may strongly enforce a membership requirement so that the boundaries define a secure environment as well: content within a peergroup can be accessed only by peers belonging to that group, so a peergroup with strict membership requirements can secure its content from the rest of the world.
The underlying network topologies of peers within a peergroup do not necessarily reflect physical network boundaries, such as those imposed by routers and firewalls. A peergroup can consist of peers on completely disparate networks. Peergroups virtualize the notion of routers and firewalls, subdividing the network in secure regions without respect to actual physical network boundaries.
Peergroups are typically formed and self-organized based on the mutual interest of peers. No particular rules are imposed on how peergroups are formed. Peers with the same interests tend to join the same peergroups. Therefore, the abstract regions defined by a peergroup provide an implicit scoping mechanism for peergroup operations. Peergroup boundaries delimit the search horizon when looking for peergroup resources. Peergroup scopes help scalability by reducing network traffic explosion within the JXTA network. Messages within a peergroup are propagated only to peers that are members of the peergroup.
Create a monitoring environment
Peergroups enable peers to monitor members, interactions (traffic introspection, accountability, traceability, etc.).
The JXTA platform defines two kinds of peergroups:
1. The NetPeerGroup
This is the default peergroup a peer joins after booting the JXTA network; it is sometimes called the World Peergroup. Configuration of the NetPeerGroup is typically done by the administrator in charge of the network domain on which the peer is located. The NetPeerGroup defines the initial scope of operations of a peer and the default services it provides.
2. User peergroups
Users (and applications) can create new peergroups with their own set of customized services and membership policies. User peergroup services are created by either cloning and extending the NetPeerGroup services or by creating new ones. All user peergroups are subsets of the NetPeerGroup.
All peers are automatically members of the NetPeerGroup peergroup; they do not need to take any special actions to join the group, and they cannot leave the group. Peers may opt to join and leave other groups at will. In order to join a group, a peer must discover the group and then ask to join it. Depending on the group, the peer may have to present authentication credentials, and the group will vote on the peer's application.
Let's see how this all works in the context of the shell. When the shell starts, it automatically joins the NetPeerGroup. One way that you can find the group that a shell belongs to is with the
whoami -g command:
JXTA>whoami -g <PeerGroup>NetPeerGroup</PeerGroup> <Description>NetPeerGroup by default</Description> <PeerGroupId>urn:jxta:jxta-NetGroup</PeerGroupId>
Any peer can create a peergroup. Peergroups are typically composed of peers that have either a common set of interests (e.g., music or baseball peergroups) or that interact with each other to exchange contents.
Peergroups allow us to introduce the notion of protocols and services in the JXTA platform. A peergroup provides a set of services that peers can utilize. The JXTA platform defines seven core services:
This set of core services is used to "seed" the peer so it can discover and find enough resources to support itself. The NetPeerGroup services provide sufficient functionality for allowing this dynamic bootstrapping mechanism. The core services were selected to enable a peer to have enough functionality to create and join a large variety of peergroups:
User peergroups can extend, replace, or add new services, allowing a variety of peergroups to be created.
A peergroup does not need to provide all of these services; it can provide only those that are necessary to support the peers within the group. Most peergroups, however, will provide at least a membership service. Since peers are always members of the NetPeerGroup, they can always obtain these services from the NetPeerGroup.
The NetPeerGroup provides all seven of these services. In general, each of these services defines a specific protocol used to access the service.
Any peer can create a peergroup. The shell creates a peergroup with these commands:
JXTA>mygroupadv = mkadv -g mygroup JXTA>mkpgrp -d mygroupadv
The first of these commands creates an advertisement (
mygroupadv) of a new group with a symbolic name of
mygroup (advertisements are discussed in more detail later in this chapter). The
mkpgrp command actually creates the group.
When you create a group in this manner, information about the group is broadcast to other peers using a discovery protocol that we discuss in the next section. In general, a peer can find a peergroup in two ways:
1. When a new group is created, an announcement of that group is broadcast, and peers who are listening will discover the new group.
2. A peer can initiate discovery to find groups. In the shell, this is accomplished with the
groups -r command:
JXTA>groups -r group discovery message sent
You can see which groups the shell knows about by using the
JXTA>groups group0: mygroup group1: anothergroup
In this last example, we know about
mygroup because that's the group that we created; we know about
anothergroup because another peer on the network created that group and we discovered it. Note that the NetPeerGroup does not show up in this list, even though it is also a peergroup.
Each peergroup is uniquely identified by a unique peergroup ID. The peergroup ID is guaranteed to be unique within the entire JXTA network.
Once a peer has discovered or created a group, it must join the group. This entails sending an application (with any necessary credentials) to the group and awaiting a response. The membership service of the group will vote on the new application and send back either an acceptance or a rejection.
A shell joins a particular group by using the
JXTA>join -d group0 Enter the identity you want to use when joining this peergroup (nobody) 1Identity: jra
After executing this command, the shell is a member of the group
mygroup. A quick note about syntax here:
group0 comes from the list of groups we obtained with the
groups command. You can use the symbolic group name (e.g.,
mygroup) to join a group only if that shell created the group. To join a group that the shell discovered (such as
anothergroup), however, you must use the
group# that the shell has assigned. Because the shell caches information about groups, it might have created the group, exited, and restarted. In that case, you must also use the
group# that the shell has assigned.
A peer can join multiple groups by executing another
join command; the
join command can also be used to determine which groups the peer has joined:
JXTA>join -d group1 Enter the identity you want to use when joining this peergroup (nobody) 1Identity: sdo JXTA> join Joined group : mygroup Joined group : anothergroup (current)
Commands that the shell executes will be associated with the current group (
anothergroup); the current group can be changed with the
n this command, you always use the symbolic group name rather than the
group# name. The current group is used to find any service that the shell needs; it is also the group printed by the
Membership in any group created by the shell is automatic, so these examples work well when dealing with groups created by two different shells. A shell might also discover a different group, however: one that has membership criteria and requires the shell to present some special credentials. Membership in such groups requires that you know how to fill out a credential request, which is group-specific; we'll look at how this works in Chapter 7.
A peer can cancel its membership in a group. The shell cancels its membership in a group with the
This command cancels membership in the current group. You cannot leave the NetPeerGroup.
So far, our shell does not have a peer. In the JXTA world, this is not a good thing, as a peerless JXTA application is not very useful. The first thing it must do, therefore, is find other peers with whom it can exchange information. The process of finding other peers is called discovery.
The process of discovery applies to any JXTA resource: peers discover other peers, and they also discover peergroups, pipes, advertisements, and other resources. There are two ways in which peers discover resources: peers discover resources dynamically, and they use special, statically configured peers to tell them about JXTA resources. Discovery occurs within the context of a peergroup: a peer attempts to discover resources within a specific peergroup.
Peers use the JXTA Peer Discovery Protocol (PDP) to discover JXTA resources dynamically. The PDP defines the lowest-level technique that is available for peers to discover resources. On an IP network, it consists of two parts: a multicast message that is sent on the local network and the use of rendezvous peers to discover peers beyond the scope of the local network. Other network bindings will behave differently, but the essential operation of the PDP is that the requesting peer sends a message, and resources that hear the request will respond directly to the peer. Therefore, a peer using PDP will discover all JXTA resources that are on the local network or are known by the peer's rendezvous peers.
The implementation of discovery is actually a feature of the peergroup in which the peer is running. Certain peergroups may define other protocols by which peers can discover resources within the peergroup. The PDP is implemented by the discovery service that runs within the NetPeerGroup (and most other peergroups).
peers -r command of the JXTA Shell implements the PDP; it will discover all other JXTA peers on the local network. Before executing this command, you may want to start a shell on another machine on your network (the next part of this series will show you how to start a second shell on the same machine as the first).
Now in the original shell window you can execute commands to discover the second peer:
JXTA>peers peer0: name = Test Shell 1 JXTA>peers -r peer discovery message sent JXTA>peers peer0: name = Test Shell 1 peer1: name = Test Shell 2
If you execute the same commands from the second shell, you'll notice that it numbers the peers differently. The peer numbers are used only internally by the shell application; peers are not numbered in a JXTA sense (except for their unique IDs).
It can take some time for the shell to discover other peers; executing the
peers -r command may not necessarily report all of the peers on the network until the shell has completed its discovery process. In addition, some peers may not respond because they miss the multicast message; no reliable network protocol is used to discover peers. On the other hand, as more peers are added to the network, discovery is faster: that's because when a peer responds to a discovery message, it sends information about itself and about all other peers that it has already discovered.
There are special JXTA peers known as rendezvous peers. These peers are like lookup services: they keep a list of peers (and other JXTA resources) that they know about, and other peers query them for that list.
If you've been following along with our example, and you're on a computer connected to the Internet, when you first executed the
peers command, you received a list of peers. This is because the shell is configured to contact certain known rendezvous peers on the Internet; by default, it will automatically contact the hosts 126.96.36.199 and 188.8.131.52. These hosts showed up in our earlier example as peers JXTA.ORG 235 and JXTA.ORG 237.
These hosts are the boostrapping set of rendezvous peers for the NetPeergroup. Peers may discover rendezvous peers dynamically and use them in place of these; the intent of the bootstrapping rendezvous peers is to initiate the discovery process of dynamic rendezvous peers.
When the shell contacts the peer at one of these hosts, it will get back a list of all other peers that have discovered that same rendezvous peer. Therefore, a JXTA Shell running on a machine connected to the Internet may automatically discover many peers.
You can use the
rdvstatus command within the shell to see if the shell has successfully contacted a rendezvous peer:
JXTA>rdvstatus Rendezvous Connection Status: ---------------------------- Is Rendezvous : [false] Rendezvous Connections: Rendezvous name: JXTA.ORG 237 Rendezvous name: JXTA.ORG 235 Rendezvous Disconnections: [None]
In this case, the shell itself is not acting as a rendezvous peer; the shell has made contact with two rendezvous peers.
There can be as many rendezvous peers as peers in the network, although a certain ratio between rendezvous peers and other peers is expected to be maintained, depending on the peergroup discovery policy. Some peergroups will have a few rendezvous peers; others will have many. Smaller peergroups typically need fewer rendezvous peers. Larger peergroups tend to need more rendezvous peers to reduce the chance of creating islands of peers that do not communicate with others.
A peer can dynamically advertise itself or remove itself from the list of rendezvous peers. Peers can discover new rendezvous peers dynamically and add them to their list of known rendezvous peers. As with the shell, any peer can be preconfigured to know about a fixed number of rendezvous peers. Each peergroup can define its own ratio of peers to rendezvous peers to support the peergroup-specific requirements.
Because a peer knows the address of a rendezvous peer, it can use whatever network protocol it wants to contact it (assuming, of course, that the rendezvous peer also supports that protocol). In the shell, the preconfigured rendezvous peers are all defined as using HTTP as their transport mechanism.
JXTA services and applications are free to use any other technique to find each other. The shell, for example, can be configured to pass its requests to the rendezvous peers through a proxy; this is useful if you must pass through a firewall to get to the Internet. In this case, the shell wraps the standard PDP message into an HTTP request that it sends to the proxy server; the proxy forwards it just as it would any other HTTP message. When the rendezvous peer receives the request, it puts its answer back into the HTTP response and sends it to the proxy, which returns it to the shell.
Any variation on this technique is valid, as long as all the peers agree on the technique. At a minimum, peers will always be able to discover each other using the basic PDP (assuming, of course, that their network topology supports the discovery we described above).
Consider the peers shown in Figure 2-3. When the JXTA Shell joins its local network, it will send out a broadcast version of the PDP. It will get back two responses. One response will come from the JXTA searching service, and the shell will now know about the searching service. The other response will come from the JXTA rendezvous peer. Because the rendezvous peer is sitting on a machine that is attached to both the local and corporate networks, it has previously discovered the searching peer and the file-sharing peer. When the rendezvous peer receives the PDP broadcast method from the shell, it will tell the shell about these two peers.
The shell will then send a PDP message via HTTP directly to JXTA.ORG 237. The rendezvous peer at JXTA.ORG 237 will then tell the shell about all the peers that JXTA.ORG 237 has discovered; this is how the shell can discover the JXTA auction service. In Figure 2-3, the HTTP message passes through a proxy in order to pass through the firewall.
JXTA peers and discovery
Passing through the proxy is a value-added feature of how the JXTA Shell is programmed (and a value-added feature of the standard Java language bindings that we use throughout this book). At a basic level, the PDP works over HTTP; if we were to remove the firewall from this network, then the JXTA file-sharing service could use PDP directly to contact JXTA.ORG 237 and discover the JXTA auction service.
Also note how peer discovery is improved as more peers are added to this example. When a new peer is connected to the local area network and executes the basic PDP to find peers dynamically, it will immediately find the JXTA auction and file-sharing services. That's because the shell has already found these services. When the new peer sends its discovery message, the shell will respond with all the peers it knows about.
JXTA peers can elect to become relay peers. Relay peers send dynamic discovery requests across different networks.
In Figure 2-3, the JXTA rendezvous peer sits on two different networks. The JXTA Shell discovered the JXTA file-sharing service because it knew about the rendezvous peer and contacted it directly. If the JXTA rendezvous peer was a JXTA relay peer instead, then when the JXTA Shell performed its multicast discovery, the JXTA relay peer would have seen the multicast message and routed it onto the corporate network. This would have been seen by the JXTA file-sharing service, which would have sent a message back to the shell.
The end result here is the same: the shell discovers the service, but the procedure is quite different. In the case of the rendezvous peer, the shell had to have explicit knowledge of the rendezvous peer in order to contact it. In the case of the relay peer, the discovery would happen dynamically.
In practice, peers often serve as both relay and rendezvous peers.
In the next installment, learn JXTA application configuration.
Scott Oaks is a Java Technologist at Sun Microsystems, where he has worked since 1987. While at Sun, he has specialized in many disparate technologies, from the SunOS kernel to network programming and RPCs.
Bernard Traversat is a well-known developer in the Java Community and an active member of the Project JXTA. Bernard is the Engineering Manager for the JXTA CORE.
Li Gong is a well-known developer in the Java Community and an active member of the Project JXTA. Li is the JXTA Engineering Director for the JXTA CORE.
Return to ONJava.com.
Copyright © 2009 O'Reilly Media, Inc.