|
|
|
|
JXTA in a NutshellBy Scott Oaks, Bernard Traversat, Li GongSeptember 2002 0-596-00236-X, Order Number: 236X 416 pages, $34.95 US $54.95 CA #24.95 UK |
Chapter 2
Getting Started with JXTAIn this chapter, we'll see how to get started with JXTA. Although JXTA is a language- and platform-neutral specification, we'll focus on using the standard JXTA applications for the Java platform. The basic concepts that you'll learn in this chapter are applicable to any JXTA implementation using any language; we chose to illustrate the concepts of JXTA using the Java platform because it allows for the simplest discussion of JXTA concepts, and because the Java platform gives us a common basis for our examples, regardless of the computer on which you might run them.
We'll start by discussing how to set up a Java environment to run JXTA programs. Then we'll look in depth at one particular program: the JXTA Shell. Examining the shell will allow us to look in depth at each of the protocols and techniques that JXTA defines; working through the examples in this chapter should provide you with a working knowledge of the key concepts of the JXTA platform and how programs operate within that platform.
Setting Up a Java Environment
The first step in using JXTA is to set up your environment. In this case, that means setting up a Java environment to run JXTA, for which you'll need three things: a Java platform, the JXTA Java class libraries, and any JXTA programs that you want to run.
The Java Platform
For the Java platform, you'll need the Java 2 Standard Edition (J2SE), Version 1.3.1 or later (Version 1.4 is preferred). Work is ongoing in the JXTA community to allow JXTA to run on the Java 2 Micro Edition platform (J2ME); once that work is complete, then the steps we discuss here should work on a J2ME platform as well.
This chapter focuses on running and explaining existing JXTA applications. Therefore, if you're using the Java 2 platform, you need only the Java 2 runtime environment (J2RE). If you plan on programming with JXTA (using the examples in subsequent chapters), then you'll need the Java 2 Software Developer's Kit (SDK).
There are a number of ways to obtain current releases of the Java platform. If your system is running Solaris, Microsoft Windows, or Linux, the simplest way is to download the SDK from http://java.sun.com/j2se/. For other operating systems, check with your system vendor. More commonly, many integrated development environments (IDEs) come with support for Java (and hence a Java platform).
Once you've obtained and installed Java, you must make sure that the
javaexecutable is in your standard path.The JXTA Class Files and Programs
You can obtain all the JXTA files you need at http://download.jxta.org/easyinstall/install.html. On this page, you can obtain the JXTA demo package for a variety of platforms. In fact, the JXTA demo implementation at this site is written completely in Java; the difference between the platforms lies only in how the parts of the implementation are packaged and how they are installed. Therefore, for Microsoft Windows, download an executable (.exe) file; for Solaris, download a shell script, and so on.
When you execute the installation program, you are prompted for a directory in which to install the code. On Unix systems, the default directory is ./JXTA_Demo; on Microsoft Windows, the default directory is C:\Program Files\JXTA_Demo. Within the directory you select, the installation creates the following:
- lib
- This directory contains a set of jar files that contains the JXTA implementation and another set that contains implementations of the JXTA demo applications.
- Shell
- The JXTA Shell is an interactive application that lets you look at the JXTA environment and try out basic JXTA functionality. We'll examine the shell in detail later in this chapter.
- InstantP2P
- This is another sample JXTA application; it contains functionality to chat one-on-one, chat with a group, and share files. This application uses all of the standard facilities of JXTA, so it is a good example on which to model other JXTA P2P applications.
This is all you need to use JXTA technology, both as an end user and as a developer. If you're going to do JXTA development, you should add each of the jar files in the lib directory to your classpath. If you're simply going to run the sample applications, there are scripts in each application directory that set up the classpath and run the application.
In our examples throughout this book, we assume that you've installed this hierarchy into /files/JXTA_Demo (C:\files\JXTA_Demo). We'll also assume that your classpath contains the current directory and the necessary jar files from the lib directory:
/files/JXTA_Demo/lib/jxta.jar/files/JXTA_Demo/lib/beepcore.jar/files/JXTA_Demo/lib/cryptix-asn1.jar/files/JXTA_Demo/lib/cryptix32.jar/files/JXTA_Demo/lib/jxtaptls.jar/files/JXTA_Demo/lib/jxtasecurity.jar/files/JXTA_Demo/lib/log4j.jar/files/JXTA_Demo/lib/minimalBC.jarAs you become more familiar with JXTA, you may want to get involved with other JXTA projects, use other JXTA applications, or examine the JXTA source code. You can download all of these things from http://www.jxta.org/project/www/download.html.
Basic JXTA Concepts
Now that we have all of this software, we'll use it to explain a little more about the basic JXTA concepts we outlined in Chapter 1, including how a JXTA application is constructed. We'll use the JXTA Shell as the basis for our exploration, since it provides us with an interactive tool that uses the JXTA platform to perform its operations.
JXTA Shell Syntax
Before we dive into the shell, here are some notes on its syntax. Like any shell, the JXTA Shell issues a prompt (
JXTA>) at which you type in commands.Shell commands have two kinds of output. Most of them simply send their output to the screen. Some commands, however, produce an object as their output. These objects should be saved in a shell variable. If you do not save the object, most commands will create a new object with a default name to hold the return value; if you're going to need the object, it's easier to assign a name to it yourself. Shell variables are created in JXTA by assigning a new name to the output of such a command.
Here are some simple examples. The
envcommand produces as its output a list of all the shell variables and their values:JXTA>envstdin = Default InputPipe (class net.jxta.impl.shell.ShellInputPipe)parentShell = Root Shell (class net.jxta.impl.shell.bin.Shell.Shell)Shell = Root Shell (class net.jxta.impl.shell.bin.Shell.Shell)stdout = Default OutputPipe (class net.jxta.impl.pipe.NonBlockingOutputPipe)consout = Console OutputPipe (class net.jxta.impl.shell.ShellOutputPipe)consin = Default Console InputPipe (class net.jxta.impl.shell.ShellInputPipe)stdgroup = Default Peergroup (class net.jxta.impl.peergroup.StdPeerGroup)Shell variables are created by assigning a new name to the output of a command that creates an object.
mkadvis such a command; here we store the object it creates in themyadvshell variable:JXTA>myadv = mkadv -pYou can print out the content of certain variables by using the
catcommand. If the variable has structured data,catwill print it out:JXTA>cat myadv<?xml version="1.0"?><!DOCTYPE jxta:PipeAdvertisement><jxta:PipeAdvertisement><id>jxta://59616261646162614A757874614D50474168B1395E034DEA90F3BC8CD7D361840000000000000000000000000000000000000000000000000000000000000401</id></jxta:PipeAdvertisement>A list of all shell commands can be obtained via the
mancommand; themancommand can also print out help for a specific command (e.g.,man mkadv). A complete shell reference appears in Chapter 12.JXTA Peers
We'll start our examination of JXTA's key concepts with the notion of a peer. As defined in the JXTA specification, a peer is a device that implements one or more JXTA protocols. The key idea is that something implements the protocols. Don't get too hung up on the notion of a device--a device is not necessarily a machine. A single machine can host multiple JXTA programs, each of which is really a peer. The program is really a virtual device.
Of course, peers normally communicate with each other over a network, so a JXTA community typically has many different machines within it. However, some of these machines could be running multiple JXTA peers. A single JXTA peer could be a distributed application running across multiple machines. And if you're following the example in this chapter at home on your own single computer, you'll end up running many peers on your local system.
To start our first peer, we'll execute the JXTA Shell. On Microsoft Windows systems, you can do this by selecting Programs
Jxta
JXTA Shell from the start menu. On other platforms, you can do this by executing these commands:
piccolo% cd /files/JXTA_Demo/Shellpiccolo% sh shell.shWhen you first start the shell, you'll see the window displayed in Figure 2-1. This allows you to configure the shell for the network on which it will run. We explain the configurator in detail later in this chapter. For now, we'll just step through the two required elements that you must configure.[1]
Figure 2-1. The JXTA configurator tool
![]()
First, fill in the peer name with a string of your choice (we chose "Test Shell 1") and press the OK button. On the next screen, fill in the username you'd like to use and a password for that username. In Figure 2-2, we've specified
myusernameand entered a password.
Figure 2-2. Entering a username into the configurator
![]()
The next window that comes up is the JXTA Shell itself. This is the first JXTA peer that we've created. The shell is interactive; its command prompt is
JXTA>, and it accepts more than 40 commands. For now, we'll just look at the commands that illustrate the basic JXTA concepts.One of these commands is the
peerscommand; it displays a list of all the peers that the shell knows about. If you execute that command now, you'll see the following:JXTA>peerspeer0: name = Test Shell 1peer1: name = JXTA.ORG 237peer2: name = JXTA.ORG 235More information can be printed this way:
JXTA>peers -lpeer0: ID = uuid-59616261646162614A78746159325933A69CA85997D6433D82BDA4A4D0953AC603 name= Test Shell 1 addr = tcp://192.168.1.101:9701/peer1: ID = uuid-59616261646162614A787461593259336ACC981CFAF047CFA name =JXTA.ORG 237 addr = tcp://209.25.154.237:9701/peer2: ID = uuid-59616261646162614A7874FAEDBB84753E1E16503C14495AE name =JXTA.ORG 235 addr = tcp://209.25.154.235:9701/All peers have names (in the case of our peer, "Test Shell 1"). In addition, peers carry other important pieces of information: the peergroup to which they belong (which we'll explain later in this chapter), a unique peer ID, and information about what network addresses can be used to contact the peer. You can see this information in the shell with the
whoamicommand:JXTA>whoami<Peer>Test Shell 1</Peer><PeerId>urn:jxta:uuid-59616261646162614A78746159325933A69CA85997D6433D82BDA4A4D0953AC603</PeerId><TransportAddress>tcp://192.168.1.101:9701/</TransportAddress><TransportAddress>jxtatls://uuid-59616261646162614A78746159325933A69CA85997D6433D82BDA4A4D0953AC603/TlsTransport/jxta-WorldGroup</TransportAddress><TransportAddress>jxta://uuid-59616261646162614A78746159325933A69CA85997D6433D82BDA4A4D0953AC603/</TransportAddress><TransportAddress>http://JxtaHttpClientuuid-59616261646162614A78746159325933A69CA85997D6433D82BDA4A4D0953AC603/</TransportAddress>The peer ID is unique across all JXTA peers. The transport addresses contain the information about how the peer may be contacted.
You can discover a peer explicitly using its peer ID like this:
JXTA> peers -p jxta://59616261646162614A78746150325033D13E08EF231549AD99C7997EAAC80A5000000000000000000000000000000000000000000000000000000000301This technique is easier to imagine programatically, where you wouldn't have to type in the entire string. You can, for example, save a peer ID and use it in later sessions as the default peer to provide a service (assuming that the program can handle the fact that the default peer may no longer be available); in fact, peer IDs are often saved by the JXTA platform itself when it performs caching.
Peers keep configuration information within their current directory. If you want to start a second instance of the shell on the same machine, you cannot do so from the same directory. Instead, you must follow the instructions on advanced configuration that we give later in this chapter.
Peergroups
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
- 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.
- Create scoping
- 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:
- 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.
- 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 -gcommand: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.
Peergroup Services
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:
- Discovery service
- Membership service
- Access service
- Pipe service
- Resolver service
- Monitoring service (sometimes called the "purines" service)
- Rendezvous service
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:
- The membership service is necessary to enforce a policy for new peers to join a peergroup.
- The discovery service is necessary for a peer to discover new network resources (so a peer can expand its capabilities).
- The resolver service provides the essential infrastructure for services to communicate.
- The pipe service provides the ability for one or more peers to exchange messages.
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.
Creating Peergroups
Any peer can create a peergroup. The shell creates a peergroup with these commands:
JXTA>mygroupadv = mkadv -g mygroupJXTA>mkpgrp -d mygroupadvThe first of these commands creates an advertisement (
mygroupadv) of a new group with a symbolic name ofmygroup(advertisements are discussed in more detail later in this chapter). Themkpgrpcommand 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:
- When a new group is created, an announcement of that group is broadcast, and peers who are listening will discover the new group.
- A peer can initiate discovery to find groups. In the shell, this is accomplished with the
groups -rcommand:JXTA>groups -rgroup discovery message sentYou can see which groups the shell knows about by using the
groupscommand:JXTA>groupsgroup0: mygroupgroup1: anothergroupIn this last example, we know about
mygroupbecause that's the group that we created; we know aboutanothergroupbecause 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.
Joining Groups
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
joincommand:JXTA>join -d group0Enter the identity you want to use when joining this peergroup (nobody)1Identity: jraAfter executing this command, the shell is a member of the group
mygroup. A quick note about syntax here:group0comes from the list of groups we obtained with thegroupscommand. 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 asanothergroup), however, you must use thegroup#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 thegroup#that the shell has assigned.A peer can join multiple groups by executing another
joincommand; thejoincommand can also be used to determine which groups the peer has joined:JXTA>join -d group1Enter the identity you want to use when joining this peergroup (nobody)1Identity: sdoJXTA> joinJoined group : mygroupJoined group : anothergroup (current)Commands that the shell executes will be associated with the current group (
anothergroup); the current group can be changed with thechpgrpcommand:JXTA>chpgrp mygroupn 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 thewhoamicommand.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.
Canceling Group Membership
A peer can cancel its membership in a group. The shell cancels its membership in a group with the
leavecommand:JXTA>leaveThis command cancels membership in the current group. You cannot leave the NetPeerGroup.
Discovery
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.
Dynamic Discovery
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).
The
peers -rcommand 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 (if you must start a second shell on the same machine as the first, skip ahead to "JXTA Application Configuration" to see how to do this).Now in the original shell window you can execute commands to discover the second peer:
JXTA>peerspeer0: name = Test Shell 1JXTA>peers -rpeer discovery message sentJXTA>peerspeer0: name = Test Shell 1peer1: name = Test Shell 2If 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-rcommand 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.Static Discovery Through Rendezvous Peers
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
peerscommand, 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 209.25.154.235 and 209.25.154.237. 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
rdvstatuscommand within the shell to see if the shell has successfully contacted a rendezvous peer:JXTA>rdvstatusRendezvous Connection Status:----------------------------Is Rendezvous : [false]Rendezvous Connections:Rendezvous name: JXTA.ORG 237Rendezvous name: JXTA.ORG 235Rendezvous 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.
Other Discovery Mechanisms
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.
Figure 2-3. 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.
Relay Peers
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.
JXTA Application Configuration
The dialog box that we showed in Figure 2-1 should make a little more sense now. That box is called the JXTA configurator tool, and it's a basic feature of the JXTA platform. All JXTA applications use this tool when they are first configured.
Configuration information is stored by this tool in the local directory. The configuration information also includes a local port number on which the JXTA application will listen. For that reason, you cannot run two instances of the shell (or any other application) on the same machine from the same directory. Instead, you must do the following:
- Create a new directory in which to hold the configuration information (e.g., /files/JXTA_Demo/Shell.2).
- Copy the shell.sh or shell.bat script into that directory.
cdto that directory.
- Execute the startup script.
When this shell starts, you will again be presented with the configuration box from Figure 2-1. You'll need to perform some advanced configuration in order for this second shell to run.
The configurator has four panels:
- Basic
- The basic panel of the configurator allows you to assign a name to your peer. Any string can be entered (we chose "Test Shell 1"): it can represent a person's name, a hostname, or any other identifier. The name you enter is not guaranteed to be unique. No centralized naming service is used by the configurator; therefore, two peers may end up with the same name. This is okay, since the peer name is intended to be used only as a hint for searching or identifying peers. Also, each peer is assigned a peer ID that is guaranteed to be unique for every peer in the JXTA network.
- This panel also allows you to specify whether your machine is behind a firewall. If you are behind a firewall, select the option to use a proxy server and enter the proxy server's name and port into the given boxes. When a proxy server is enabled, requests to the rendezvous peers will be wrapped into HTTP messages before they are sent to the peer.
- Advanced
- The advanced panel allows you to set up network information about the peer. JXTA v1.0 supports two transports: TCP/IP and HTTP. By default, the configurator tool preconfigures both a TCP/IP and HTTP transport to communicate with other peers.
- You should enable the TCP settings if there are other JXTA peers on your local network that you want to discover through the broadcast mechanism of PDP. The choice menu lists all the networks that the machine knows about; these are the networks on which the shell could listen for broadcast messages from other peers. Note, however, that you can select only one network on which to listen for messages.
- The text box in the TCP/IP configuration section contains the network port that will be used for application-level messages to other peers. If you are running multiple instances of the JXTA platform on a single computer, you must change the port number parameter: each JXTA application needs to have its own port number to bind a listening socket to the port.
- Similarly, enable the HTTP settings if you want to make connections to the rendezvous hosts we listed above. Note that you enable this to use HTTP to rendezvous to those hosts regardless of whether you're behind a firewall or use Network Address Translation (NAT). The message here is a little misleading. If you're behind a firewall, then you should enable the proxy server on the basic panel and fill in its name and port number as appropriate. Making connections through the HTTP rendezvous ports can take some time; while you're experimenting with JXTA on your local network, it's more efficient to disable this feature (though you'll lose the ability to interact with other peers on the Internet while this feature is disabled). If you are not connected to the Internet, you must disable the HTTP settings.
- One more note about the TCP port. Peers on a local TCP network discover each other through a multicast message. However, once they've discovered each other, they communicate directly over a specific port (known as the endpoint). The value of the endpoint is embedded within the PDP messages that the peers exchange. A peer listens for connections on this port; one peer contacts another by making a connection to the second peer's endpoint. That's why we had to change the port number when we started a second shell on the same machine: each shell needs an unused port number on the machine. If you run two shells on different machines, changing the port isn't necessary.
- Rendezvous/relays
- The rendezvous/relays panel allows you to specify specific hosts to be used as rendezvous and/or relay peers. By default, JXTA peers will download the lists of HTTP rendezvous peers by connecting to http://rdv.jxtahosts.net/cgi-bin/httpRdvsProd.cgi and HTTP relay peers by connecting to http://rdv.jxtahosts.net/cgi-bin/routersProd.cgi. If you press the Download relay and rendezvous lists button at the bottom of this panel, you can specify a different location from which to load these lists. When the lists are loaded, you'll see that the default addresses for JXTA.ORG 235 and 237 have been added as both rendezvous and relay peers. You may delete either of these peers or add any other peers through the fields on this panel.
- Note that if you disabled the HTTP transport on the advanced panel that the HTTP rendezvous and relay settings are not available.
- Security
- The final panel is one we've seen: it requires you to enter a name and password for access to this peer. Whenever the peer is restarted from this directory, you will be prompted for the values you entered into this panel.
Re-Entering Configuration Information
Network configuration information that you enter in the configurator is stored in the PlatformConfig file of the current directory. When a JXTA application starts, it consults this file to determine how it should configure itself. Information about your username and password is stored in files within the ./pse directory.
The first time that you start an application in a directory, the configurator will run and automatically create those files. After that, if you need to change the configuration information, you must remove the PlatformConfig file (to change the network information) and/or the pse directory (to change the username and password). Alternately, you can create a file called reconf in the current directory, in which case the configurator will run, and you'll be allowed to change the network information (but not the username and password).
From the shell, you can create the reconf file with the
peerconfigcommand:JXTA>peerconfigpeerconfig: Please exit restart the jxta shell to reconfigure !!!!!Then exit the shell and restart it; the configurator will reappear, and you can enter new network information.
Firewall and NAT Traversal
A fundamental problem P2P systems such as JXTA need to address is the ability to create a connection between two peers located at the edges of the Internet. Firewalls and NAT solutions currently deployed on the Internet create logical partitioned zones that preclude peers from talking directly with each other.
Firewall solutions are primarily deployed to create protected regions and to limit incoming traffic from the outside world. Many companies on the Internet today use firewall software to protect their internal networks from unwanted external intruders and traffic; home firewalls are becoming increasingly popular for individual users as well.
NAT solutions address the limitation on the number of IP addresses that can be assigned on a particular local network. These limitations stem from two areas. First, the sheer number of devices that are connected to the Internet is greater than the present address space of IP addresses. Second, many users (particularly home users with small networks) prefer to use NAT to shield information about their network topology from the outside world and to limit the number of IP addresses they must purchase from their service provider. IPv6 will eventually solve the first of these issues, but not the second.
So both firewalls and NAT address real problems; they will be a reality of public networks for the foreseeable future. P2P networks such as JXTA need to provide traversal and piercing capabilities to enable any peer on the network to talk with any other peer. JXTA assumes uniform reachability between peers, independently of their physical location in the network (e.g., behind a firewall or NAT).
Therefore, JXTA implementations must support firewall traversal and NAT piercing. This is accomplished in JXTA 1.0 using HTTP; it's important to set the fields of the configurator correctly to take advantage of these features.
Command Line-Based Configuration
In certain environments, it may not be convenient to configure the JXTA platform via a graphical interface. In that case, you must configure the environment by hand. There are two issues here: the network configuration and the security configuration.
The network configuration information is stored within the PlatformConfig file located in the current directory. If you want to change network parameters, you can edit this file by hand before starting your JXTA application. If you are running a brand new JXTA application, you can copy an existing PlatformConfig file, make any necessary changes to it, and then run your application. Alternately, if no windowing system is available when the JXTA application starts, it will prompt you as to whether it should continue:
The window-based configurator does not seem to be usable.Do you want to stop and edit the current configuration ? [no]:Using the current configuration.If you answer this question with anything other than the string "yes," JXTA will create a default PlatformConfig file and run with the network parameters set in that file. If you do answer "yes," the application will throw an exception and exit, allowing you to edit the PlatformConfig file.
You must configure the username and password differently. The username and password information is stored within the pse directory. If that directory does not exist, then the platform will always attempt to run the configurator. If the configurator cannot run, you will get the same prompt as above, but there is no default username or password, and the application will ultimately fail.
What you must do in this case is specify the desired username and password on the command line by setting these two properties:
-Dnet.jxta.tls.password=********-Dnet.jxta.tls.principal=myusernameNote that the password must be specified in "the clear"; it will not echo as a series of asterisks. Using these properties will initialize the correct entries in the pse directory and allow your application to continue.
The username and password must be specified every time a JXTA application runs; the second time you run the shell, you'll get a pop-up window asking you to specify the username and password. To avoid this pop-up window, you may specify these properties when you start the application.
There's an interesting difference here: if the application prompts you for the username and password, you will not be able to proceed unless you type in the correct values. If you specify the username and password via command-line properties, the application will continue to function until those values are needed. In most JXTA applications, the username and password are needed only to create secure (encrypted) pipes. Therefore, unless your application uses secure pipes, it will work perfectly even if you specify the incorrect username and password via the command line. We'll explore this a little bit further in Chapter 7.
Caching
The JXTA Shell caches information about peers it has discovered in the ./cm directory. If you shut down a shell and then restart it, you'll notice that it still knows about the same peers, even before you execute a
peers -rcommand. This caching feature is used by many JXTA applications, though it is not a requirement of JXTA: it's up to the application to determine how (or if) it should cache information about previously discovered peers.So when the JXTA Shell restarts, it still knows about all of the previously discovered peers. But what happens if these peers have disconnected? In that case, you need to flush the list of peers. This is done with the
peers -fcommand:JXTA>peerspeer0: name = Test Shell 1peer1: name = Test Shell 2JXTA>peers -fJXTA>peerspeer0: name = Test Shell 1The point is that peers are strictly transient by nature, and you cannot assume that a peer will continue to exist if you restart a session (or even during the same session). Peers come, peers go, and it's up to JXTA applications to be prepared to deal with this fact.
The caching of peer information by the shell is a specific case of advertisement caching. Every network resource in JXTA is described by an advertisement. Advertisements are XML documents that publish the availability of a resource and specify how to access the resource (we'll discuss them in more detail later in this chapter). When we discovered a peer, what we really discovered was the advertisement for that peer.
Advertisements may be cached by peers. Caching advertisements facilitates advertisement discovery, as more peers are likely to cache the requested advertisement. Without caching, peers would have to crawl through the entire network to find the advertisement they are looking for. Thus, caching reduces the exponential growth of messages sent within the network to discover a resource.
Each advertisement contains a time-to-live value that specifies the lifetime of the advertisement in the JXTA network. The lifetime is specified as a time relative to when the advertisement was published; when the lifetime expires, the advertisement is purged from the cache. This enables the network to maintain itself without centralized control.
As we mentioned, the JXTA specification does not specify how peers cache information; each peer is free to use a caching policy appropriate for its own environment. A PDA may cache very few advertisements only for its own usage. An enterprise server may cache more advertisements and supply them to other peers in the network. However, the standard JXTA API bindings that we discuss in later chapters automatically perform this caching. So by default, most JXTA applications will cache their advertisements.
Pipes
One of the most powerful of JXTA's services is the pipe service. The idea of a pipe is familiar to users of Unix systems: a pipe is used to connect the output from one command to the input of another command. On a Unix system, if you want to count the number of unique exceptions that occur in a log file, you might use this command:
piccolo% cat log | grep "Exception" | sort | uniq | wc -lThe
catcommand prints the log file to its standard output. Thegrepcommand reads this file from its standard input and searches for lines containing the string "Exception"; it prints matching lines to its standard output. Thesortcommand reads these lines from its standard input and sends the sorted list to its standard output, where it is read by theuniqcommand, which removes duplicate lines. The unduplicated lines are sent to its standard output, where they are read by thewccommand, which counts the number of lines and finally prints that number.Pipes are quite useful in that they allow you to build complex functionality from a number of simple building blocks. JXTA takes the familiar idea of pipes and extends their functionality to the network.
Peer Endpoints
JXTA pipes are defined in terms of the endpoints available to a peer. A peer endpoint is a logical abstraction of an address on a network transport that is capable of sending and receiving network messages. In the examples we've seen so far, the network transport has always been IP-based: the shell peer we've looked at has a TCP endpoint (port 9701 by default) and can have an HTTP endpoint. However, JXTA does not make this assumption and allows an endpoint to be an address on any network transport as long as the network is capable of sending and receiving datagram-style (i.e., unreliable packet-based) messages.
In the shell, the available endpoints are established when the configurator runs. The TCP endpoint is based on the network address selected from the pull-down menu and the port number entered into the TCP port text box; the HTTP endpoint is enabled by selecting support for HTTP.
Pipe Abstraction
In JXTA, pipes provide a unidirectional, virtual connection between two pipe endpoints: input pipe (receiving end) and output pipe (sending end). Pipe connections are established independently of the pipe endpoints peer location. For example, the input pipe endpoint can be located behind a firewall or NAT while the output endpoint can be located on a peer on the Internet. The endpoints may even be on physically different networks: the input pipe endpoint could be on a TCP network while the output pipe endpoint is on a token ring network. As long as there are available JXTA relay peers between the two endpoints, a logical pipe between them may be defined.
Therefore, pipes enable connections without any consideration of connectivity. Two peers may require an intermediary routing peer to communicate between each other. Pipes virtualize peer connections to homogenize and provide an abstraction of the full connectivity available within the JXTA network.
Pipe connections are layered on top of the peer endpoint connections, as we show in Figure 2-4. This figure shows a set of peer endpoint connections: Peer B, for example, has two HTTP endpoint connections while Peer D has two HTTP endpoint connections and one TCP/IP endpoint connection.
Figure 2-4. Pipe connections over peer endpoints
![]()
Note that some peers sit behind a firewall. HTTP proxy connections are used to connect to a peer outside the firewall (a TCP/IP Socks connection could also have been used). Peer C and Peer A can act as router peers for peers behind firewalls.
A pipe connection may involve multiple peer endpoint transport connections (multi-hops). The pipe connection between Peer B and Peer E involves an HTTP connection between Peer B and Peer C, an HTTP connection between Peer C and Peer D, and a TCP/IP connection between Peer D and Peer E. On the other hand, if a pipe connection is established between Peer A and Peer C, a single peer endpoint connection will implement the pipe, as Peer A and Peer C have a direct TCP/IP connection.
Pipes may send messages in different ways, each of which may provide a different quality of service. Some examples of this include:
- Unidirectional, asynchronous
- The pipe endpoint sends a message, and no guarantee of delivery is made.
- Synchronous request/response (RPC)
- The pipe endpoint sends a message and receives a correlated answer.
- Publish/subscribe
- A pipe endpoint subscribes to messages sent from a publisher endpoint.
- Bulk data transfer
- The pipe provides reliable data transfer of binary data.
- Streaming
- The pipe provides efficient data transfer over a flow-controlled channel.
The default service provided by a JXTA pipe is unidirectional, asynchronous communication. All other pipe services can be implemented by the developer either directly on top of the peer endpoints or over the default pipe abstraction. The unidirectional and asynchronous pipe service was selected as the minimum common denominator service easily implementable on a wide variety of non-IP transports. The asynchronous model was also selected since it fits well with the unreliable nature of a P2P network such as JXTA, in which peers or connections may disappear at any moment. Asynchronous models are also known to be more scalable (as the number of peers increase) than synchronous models. Finally, an asynchronous model provides an easier fault recovery and garbage collection mechanism when network connections fail.
Nonlocalized Connections
Pipes provide a nonlocalized communication abstraction. Applications and services create pipe endpoints (an input pipe and an output pipe) to communicate independently of the pipe endpoints' peer location. Due to the unreliability and the interchangeable nature of peers in the JXTA network, pipes provide a powerful mechanism to build fault-tolerant applications. When creating a connection to a service, the pipe abstraction permits the peer to bind the pipe endpoints dynamically to the best or more appropriate instance of the service independent of the peer location. This hides the location of a service peer from the application, which is extremely important on an unreliable network.
Fault-Tolerant Constructs
The indirection introduced by pipes also allows applications to bind to the most appropriate instance of a service: perhaps the closest service or the best performing service. JXTA presents a novel approach to address application reliability. By building and proliferating interchangeable services on peers, applications can adapt to the unreliable network environment by connecting to or changing to the most available or efficient service; the application can do this at any time and with no regard to the location of the service.
Pipes are an essential tool to build such services and applications. JXTA pipes introduce a fundamental network programming shift in which developers should not write applications that connect to a specific peer to access a unique service, but should write applications that discover the closest available service regardless of which peer is running the service.
Pipe Endpoint Binding
Pipe endpoints are dynamically bounded to a peer endpoint at runtime via the Pipe Binding Protocol (PBP). The pipe-binding process consists of searching for and connecting two or more pipe endpoints. When a message is sent over a pipe, it is sent by the local output pipe to the destination input pipe endpoint that is currently listening to the pipe. The set of currently listening peers (that is, the location of the input pipe endpoint) is resolved using the PBP.
Pipes are uniquely identified by a pipe advertisement. The pipe advertisement contains a unique pipe ID and an optional pipe name. Pipe advertisements are a resource within the JXTA network; they may be discovered just as we discovered peers and peergroups. Each pipe advertisement is associated with a unique pipe.
Applications use a pipe service to create pipe endpoints (both input and output) associated with a particular pipe advertisement. The pipe service uses pipe advertisements to identify the pipe and resolve the input pipe and output pipe endpoints.[2]
Pipe Communication Mode
Pipes support two modes of communication (see Figure 2-5):
- Point-to-point
- A point-to-point pipe connects exactly two pipe endpoints: an input pipe receives messages sent from an output pipe. No reply or acknowledgment is supported. Additional information in the message payload (such as a unique ID) is required to determine the sequence of messages sent over the pipe. The message payload may also contain a pipe advertisement that can be used to open a pipe to reply to the sender.
- Propagate pipe
- A propagate pipe connects one output pipe to multiple input pipes. Messages flow into the input pipes from the output pipe (propagation source). A message sent over a propagate pipe is sent to all listening input pipes; this process may create multiple copies of the message. On a TCP/IP network, IP multicasting is used as an implementation for propagate pipes when the propagate scope maps to an underlying physical subnet in a one-to-one fashion. Propagate pipes can also be implemented using point-to-point communication on transports that do not support multicasting.
Figure 2-5. Pipe communication modes
![]()
Pipes and Peergroups
Pipe connectivity is related to the concept of peergroups: only pipe endpoints that are located in the same peergroup can be mutually resolved by a pipe service. Each peergroup has its own pipe service, so to open a pipe connection between two peers, the two peers must have joined the same peergroup.
Of course, since all peers are part of the NetPeerGroup, any peer can open a pipe to any other peer. The difference is in which pipe service will resolve the pipe. In Figure 2-5, Peer 1 can use the pipe service of either the NetPeerGroup or of Peergroup A to resolve its pipe connections to Peers 2 and 3. Peers 2 and 4 can use only the pipe service of the NetPeerGroup to resolve their mutual pipe connection. The context of the pipe resolution is important because of the security context that may be enforced by the pipe service of a peergroup: Peer 1 may decide that it does not want to send data to any peer that has not been authenticated into Peergroup A. It then advertises only its pipe endpoint within that peergroup.
A peer can maintain different pipe connections to the same peer, holding each of them in a different peergroup context for security reasons. Messages can be sent to the peer with different security levels depending on the pipe used.
Pipe Examples
Pipes are used behind the scenes for many shell services. One such service is the talk service, which allows users in two different shells to send simple string messages to each other.
To use the talk service, you must register two users (either in the same or -- ideally -- different shells). One registration looks like this:
JXTA>talk -register sdo......User: sdo is now registeredJXTA>talk -login sdoNow repeat the process in a second shell with a different user:
JXTA>talk -register jra......User: jra is now registeredJXTA>talk -login jraIn the first shell, you can then send a message from
sdotojra:JXTA>talk -u sdo jrafound user's advertisement attempting to connecttalk is connected to user jraType your message. To exit, type "." at beginning of lineHello!In the second shell, you'll see this message:
talk: from sdo to jraMessage: Hello!Behind the scenes, this example uses a number of JXTA services; the one that concerns us for now is the pipe service. The message from
sdotojrais sent via a pipe. What happens is this:
- A user is registered. This creates an advertisement that the peer will accept talk messages.
- The user logs in. This creates the actual input pipe. A thread is set up to read continually from the input pipe, which is why the message from
sdotojraappeared asynchronously in the second shell window. This is why logging in is a necessary step in this service; without it, there would be no input pipe to accept messages.
- The user sends a message. This creates an output pipe; whatever data is written to this output pipe will be read on the input pipe of the user to whom the message is directed.
We can explore some other shell commands to understand a little more about how JXTA pipes work. To create a pipe, we must make a pipe advertisement and use it to create the pipes:
JXTA>pipeadv = mkadv -pJXTA>inpipe = mkpipe -i pipeadvJXTA>outpipe = mkpipe -o pipeadvThis creates both an input and output pipe. In order for the pipes to be connected to each other, they must be created with the same advertisement that we created here. In the talk service (and in other JXTA applications), you discover input pipe advertisements that are created by the shell in response to the
talk -registercommand. The shell uses this pipe advertisement to create the input pipe in response to thetalk -logincommand; it uses this pipe advertisement to create the output pipe in response to thetalkuser command.In this example, we've created the input and output pipes in the same peer. Later, we'll see how to create the pipes in different peers.
Messages
The information transmitted through pipes is messages. Messages define an envelope to transfer any kind of data: text, code, and so on. Furthermore, a message may contain an arbitrary number of uniquely named sections. Each section has an associated MIME type and can hold any form of data. Binary data may be encoded using the Base64 encoding scheme in the body of a section; a CDATA section may also be used. Some sections may contain XML-structured documents. Applications and services communicate by constructing messages and sending and/or receiving messages through the input and output pipe endpoints.
JXTA messages use a binary format to enable the efficient transfer of binary and XML data. A JXTA binary message format is composed of a sequence of elements. Each element has a name and a MIME type and can contain either binary or XML data. The form of a JXTA message is shown in Figure 2-6.
Figure 2-6. A JXTA message
![]()
In order to send data over a pipe (or to any JXTA peer), the data must be encapsulated in a message. In the shell, this can be done by importing an existing file that contains the message body and using the
mkmsgcommand to convert the data into a message. When this is done, the imported data will be associated in the message with a tag of your choosing.First, we need to create a file containing the message data. Such a file would contain a set of arbitrary XML tags; a simple example is the file containing the single line:
<Data>Hello, world!</Data>If this file is named data, then we can import it into the shell like this:
JXTA>importfile -f data mydataThe
mydatavariable now contains the data read in from the file. In fact, it contains other information as well, since the shell has embedded some additional XML into it.You can create the actual message like this:
JXTA>mymsg = mkmsgJXTA>put mymsg mytag mydataThe first command creates an empty message named
mymsg; the second populates this message with the data from themydataobject, associating it with themytagtag.If you've made the pipes and message, you can then send and receive data like this:
JXTA>send outpipe mymsgJXTA>newmsg = recv inpiperecv has received a messageThe message is sent on the output pipe. The input pipe then reads the message and stores it in a new message variable,
newmsg. The contents ofnewmsgare the same as those ofmymsg; they have a tag ofmytagand an associated message body that contains the structured XML document created by reading the datafile. The message body can be extracted with thegetcommand:JXTA>newdata = get newmsg mytagJXTA>cat newdata<?xml version="1.0"><ShellDoc><Item><Data>Hello, world!</Data></Item></ShellDoc>Advertisements
We've mentioned advertisements in passing a number of times in this chapter; we even created advertisements for pipes and groups using the shell's
mkadvcommand. Advertisements are one of the basic building blocks of JXTA: they help peers discover any kind of service, including peergroups, other peers, and pipes. In fact, at a basic level, the JXTA infrastructure is simply about sending advertisements for various resources around to interested parties. A JXTA application simply searches for advertisements it is interested in and responds to requests for advertisements that it has published. The basic protocols we've mentioned all use advertisements as the mechanism by which they send data. Advertisements provide a platform-independent representation of platform objects that can be exchanged between different platform implementations (Java, C, etc.).Advertisements are structured XML documents. The JXTA infrastructure defines six such documents:
- Peer advertisement
- Peergroup advertisement
- Pipe advertisement
- Service advertisement
- Content advertisement
- Endpoint advertisement
Developers may subclass these advertisements when they create their own services. For example, a content advertisement could announce that a peer has a particular item (such as a PDF file of this chapter). A JXTA application may create a subclass of the content advertisement to refer only to PDF files of this book. Peers who are interested in generic content can look for standard content advertisements; peers who are interested in only the PDF files of this book can look for the content subclass. Both peers will find the PDF of this chapter, but the second will find less extraneous content.
Obtaining Advertisements
There are three ways to obtain advertisements. First, peers create advertisements for services they are interested in supplying. For example, in the previous section we used the
mkadv -pcommand to create an advertisement for a peer endpoint. Second, peers discover some kinds of advertisements. Advertisements for other peers, for instance, are broadcast through a network, where peers will discover them. Finally, peers can search for advertisements: they can query other peers for advertisements that have specific attributes.In our previous pipe example, we set up both ends of the pipe within the same peer. Now we'll see how advertisements allow us to set up the ends of the pipe in different peers. To follow along with this example, you'll need to start two shells (preferably on different machines).
First, one peer must create the pipe advertisement. In the first shell, execute this command:
JXTA>pipeadv = mkadv -pNow this advertisement must be published--i.e., made available to other peers. In the first shell, this is done with the
sharecommand:JXTA>share pipeadvOther peers must obtain this pipe advertisement. In the second shell, this is done with the
searchcommand:JXTA>search -rJXTA>searchJXTA Advertisement adv0JXTA Advertisement adv1JXTA Advertisement adv2JXTA Advertisement adv3The first command tells the shell to search for advertisements using discovery (e.g., by broadcasting a message to other peers in the peergroup in order to see what shared advertisements they have). The second command prints out a list of all the advertisements that the peer has obtained (advertisements that the peer itself created will also appear in this list). Note that it may take a while between when the
search -rcommand is issued and when the remote advertisement is discovered; you may need to wait a minute or two before the desired advertisement shows up in the list.You may also see multiple advertisements listed; in order to determine which is the desired pipe advertisement, you must
cateach advertisement. The pipe advertisement we're interested in looks something like this:JXTA>cat adv3<?xml version="1.0"?><!DOCTYPE jxta:PipeAdvertisement><jxta:PipeAdvertisement xmlns:jxta="http://jxta.org?"><Id>urn:jxta:uuid-59616261646162614E5947295932593319469D7BC74B47438A0FB4EBAEA6237804</Id><Type>JxtaUnicast</Type></jxta:PipeAdvertisement>If you
catthepipeadvvariable in the first shell, you can determine the ID to look for in the list of advertisements in the second shell.Now we can set up the actual pipes. In the first shell, set up the input pipe:
JXTA>inpipe = mkpipe -i pipeadvIn the second shell, set up the output pipe:
JXTA>outpipe = mkpipe -o adv3Note that in the first shell, we used the
pipeadvvariable to create the pipe; in the second shell, we must use the variable that the shell assigned when it discovered the pipe advertisement.At this point, you can create a message in the second shell and use the
sendcommand to deliver the message to the first shell (which reads it using therecvcommand). This procedure is unchanged from our previous example.Summary
In this chapter, we used the JXTA Shell to explore the underpinnings of the JXTA framework. Each instance of the shell is a peer, and we've seen how multiple peers can use a variety of techniques to discover other peers. As implemented in the shell, these techniques are tied to a particular network binding (e.g., TCP), though the PDP is designed to run over any network.
Similarly, we've seen how the shell peers organize themselves into peergroups, another key JXTA concept. Peergroups allow for the segregation of services so that peers can more easily manage their relationships with other peers.
The communication between peers in JXTA is based on the notion of an endpoint. One key example of an endpoint is a pipe, which can provide either input or output for a peer and allows complex behavior to be built from several simple peers. Pipes form the basis of communication in JXTA; peers depend on advertisements to locate pipes and other endpoints with which they want to communicate.
The shell provides a mechanism by which we can explore and test many of these features. In the next few chapters, we'll look into how we can develop our own JXTA applications that include these same features.
1. This default configuration assumes that your computer is directly connected to the Internet. If you are not connected to the Internet directly or connect to the Internet through a proxy, then you must take additional steps as outlined in the detailed section on the configurator tool later in this chapter.
2. In order to send a message to an output pipe endpoint, the corresponding input pipe endpoint must have been created first. This is a limitation of the current JXTA v1.0 implementation; it is expected to be removed in the future.
Back to: JXTA in a Nutshell
© 2001, O'Reilly & Associates, Inc.
webmaster@oreilly.com