OpenP2P.com    
 Published on OpenP2P.com (http://www.openp2p.com/)
 See this if you're having trouble printing code examples


Learning the JXTA Shell

by Rael Dornfest
04/25/2001

I want to talk about the implications for that marvelous aspect of the fundamental UNIX design: the pipe, and its ability to connect small independent programs so that they could collectively perform functions beyond the capability of any of them alone. What is the equivalent of the pipe in the age of the Web?
-- Tim O'Reilly, JavaOne Keynote: "The Network Really is the Computer."

The JXTA shell is a command-line interface to Sun's JXTA (pronounced "Juxta") peer-to-peer framework. Originally written as a debugging tool for developers, the JXTA Shell affords a ground-floor view of the JXTA environment, much like a traditional shell drops one into the thick of a *nix operating system.

The JXTA shell is a fine demonstration of some of the key features of the JXTA platform. The shell itself is nothing more than a framework for dynamically loading and binding commands (read: classes) to the JXTA underpinnings. This allows you, the user, to extend the shell to your heart's content. Who'll be the first to write alias and less ;-)

Table of Contents

Login
Old Favorites
Getting to know me
Peers
Peer Groups
P2P Piping
Can we talk?
Logout
Gotchas!

As we'll see in this article, inter-peer messages in JXTA are nothing more than XML documents, a fact that provides various interesting intersections with Web Services (via XML-RPC and SOAP), syndication (via RSS), Instant Messaging a la Jabber, and more.

This article is an introductory tour of the JXTA shell. We'll step through some of its simple commands and move to more interesting examples constructed from these core building blocks. (For an overview of the JXTA platform, see the accompanying article, The JXTA Position.)

Anyone familiar with command-line shells, whether DOS or *nix, will feel right at home in the JXTA shell. There are basic commands: man, cat, env, grep, more, and more. Commands can, of course, be sewed together using pipes to create compound commands: env | wc. Multiple commands on one line are separated by semicolons: clear ; whoami ; man man. All in all, aside from the fact that it's easy to forget that it's not a complete shell (see "Gotchas"), there are few surprises.

Login

Related Articles:

JXTA Takes Its Position

JXTA Shell commands

The JuxtaNet

"Hello, JXTA!"

Joy Announces JXTA


More from the OpenP2P.com

First things first; we'll download, install and launch the JXTA shell.

  1. The JXTA Shell is freely downloadable from the Jxta.org site at http://download.jxta.org/easyinstall/. Installers are available for various platforms, as well as ZIP archives and CVS access.

    Note: At the time of this writing, Windows 2000 users may have trouble with the Windows installer launching and disappearing without doing much of anything, save perhaps hanging around in the background. If this happens, you may want to download the latest nightly build.

  2. Launch the JXTA shell by double-clicking on the jxta.exe icon in the shell subdirectory of wherever you put the installation.
    Launching the JXTA Shell JXTA Application Icon  
  3. The first time you run the shell, the JXTA Configurator dialog will appear. Leave the defaults as they are; all you need do is fill in a name for your peer (anything will do) in the Peer Name field and click the OK button to move on.
    The JXTA Configurator The JXTA Configurator  
  4. The JXTA shell window should appear and you're ready to go.
    The JXTA Shell The JXTA Shell  

    Note: I found a couple of bugs that can cause the shell not to launch. If, after closing the configurator, the shell does not appear momentarily, double-click the jxta.exe icon to relaunch. Windows 2000 users may find this makes no difference and will need to log out (not reboot, mind you) and log in again before continuing.

This article was written using version 0.9 (build 14e, 04-22-2001). For versioning, type version at the command-line.

Old Favorites

We'll start with a few old shell favorites.

If at any point you need help, the standard *nix man provides man(ual) pages for supported functionality. Typing just man displays information about man itself, along with a list of available commands.

JXTA>man
The 'man' command is the primary manual system for the JXTA shell.
The usage of man is:
 
   JXTA> man <commandName>
 
  For instance typing
   JXTA> man Shell
         displays man page about the Shell
 
The following is the list of commands available:
 
 cat        Display the content of an environment variable
 chpgrp     Change the default peer group
...
 who        Display member identity in a peer group
 whoami     Display peer and peer-group information
 
JXTA>

(For a complete list of JXTA shell commands, see "JXTA Commands.")

env, as expected, displays all defined shell environment variables.

JXTA>env
peer0 = stored local peer advertisement 
        (class net.jxta.impl.protocol.PeerGroupAdv)
stdout = Default OutputPipe (class net.jxta.impl.shell.ShellOutputPipe)
stdin = Default InputPipe (class net.jxta.impl.shell.ShellInputPipe)
Shell = Root Shell (class net.jxta.impl.shell.bin.Shell.Shell)
consout = Default Console OutputPipe 
          (class net.jxta.impl.shell.ShellOutputPipe)
consin = Default Console InputPipe (class net.jxta.impl.shell.ShellInputPipe)
stdgroup = Default Group (class net.jxta.impl.peergroup.StdPeerGroup)

Comment on this articleHave you explored JXTA? Tell us your first impressions and let others know what you've learned so far.
Post your findings

One thing to note in the above readout is that standard input (reading keyboard input) and output (displaying output to the console) are JXTA pipes, the same conduits by which peers communicate with each other. The same is true for the shell console's consin/consout. We'll delve more into pipes in a bit.

Here are a few more simple commands to try for fun:

Getting to know me

Let's get to know ourselves a little, shall we? The whoami command functions as expected, albeit a little more interesting than the standard printing of my username.

JXTA>whoami
<Peer>milne</Peer>
<Keywords>NetPeerGroup by default</Keywords>
<PeerId>jxta://59616261646162614A78746150325033237B7161401449269
6789EFFBC49968B0000000000000000000000000000000000000000000000000000000
000000301</PeerId>
<TransportAddress>tcp://1.2.3.4:6001/</TransportAddress>
<TransportAddress>http://JxtaHttpClient59616261646162614A7874615
0325033237B71614014492696789EFFBC49968B0000000000000000000000000000000
000000000000000000000000000000301/</TransportAddress>

JXTA>whoami -g
<PeerGroup>NetPeerGroup</PeerGroup>
<Keywords>NetPeerGroup by default</Keywords>
<PeerGroupId>jxta://59616261646162614A757874614D5047000000000000
0000000000000000000000000000000000000000000000000000000000000000000000
00000000000201</PeerGroupId>
<Service>jxta.service.resolver</Service>
<Service>jxta.service.membership</Service>
<Service>jxta.service.discovery</Service>
<Service>jxta.service.pipe</Service>
<Service>jxta.service.peerinfo</Service>
</code></pre>

The first whoami claims that I am a peer named "milne" with the unique identifier, "jxta://596162..." I am, by default, a member of the "NetPeerGroup" -- more on groups in a moment. I am communicating via TCP directly at IP address 1.2.3.4, port 6001, and via an HTTP proxy if behind a firewall/NAT. Note that even though I may be using HTTP to get past my firewall, direct TCP communication is still useful for peers on my LAN. The second whoami provides a little more detail about my current peer-group membership, including group identifier and available services.

For more details, there's whoami -l . This is but a pretty representation of the actual peer advertisement, viewable in its native XML by printing the "peer0" environment variable we saw above.

JXTA>whoami -l | more
jxta:PeerGroupAdvertisement : 
  Name : NetPeerGroup
  PeerName : milne
  Keywords : NetPeerGroup by default
  Pid : jxta://59616261646162614A78746150325033237B7161401449269
        6789EFFBC49968B0000000000000000000000000000000000000000
        00000000000000000000301
  Gid : jxta://59616261646162614A757874614D504700000000000000000
        00000000000000000000000000000000000000000000000000000000
        00000000000000000000201
  isRendezvous : false
  Services : 
    jxta:ServiceAdvertisement : 
      Name : jxta.service.resolver
      Version : JXTA1.0
      Keywords : resolver
      PipeService : 
      Params : http://216.15.60.14:6002
      Params : tcp://129.144.36.190:6001
      Params : http://209.25.154.239:6002
      Params : http://63.115.99.228:6002
      Params : http://206.132.188.132:6002
      Uri : http:/www.jxta.org/download/jxta.jar
      Provider : sun.com
-----More-----

JXTA>cat peer0 | more
<?xml version="1.0"?>
<!DOCTYPE jxta:PeerGroupAdvertisement>
<jxta:PeerGroupAdvertisement>
  <Name>NetPeerGroup</Name>
  <PeerName>milne</PeerName>
  <Keywords>NetPeerGroup by default</Keywords>
  <Pid>jxta://59616261646162614A78746150325033237B7161401449269
       6789EFFBC49968B00000000000000000000000000000000000000000
       00000000000000000000301</Pid>
  <Gid>jxta://59616261646162614A757874614D504700000000000000000
       00000000000000000000000000000000000000000000000000000000
       00000000000000000000201</Gid>
  <isRendezvous>false</isRendezvous>
-----More-----

These settings reflect the initial JXTA configurator settings we breezed through earlier. To reconfigure your JXTA peer from within the shell, take a gander at the peerconfig command (type: man peerconfig).

So much, then, for the preamble; let's get on to the interesting P2P pieces.

Peers

Each application tapping into JXTA is a peer. Your JXTA shell running on your desktop right now is a peer, as is mine on my laptop. The peers command displays all peers already known to my peer, initially only myself and possibly a peer I'm using as an intermediary outside my firewall/NAT.

JXTA>peers
peer0: name = milne
peer1: name = DIOXINE.NET

JXTA>peers -l [the -l option provides more detail]
peer0: ID = 38e6af70 name = milne 
  addr = http://JxtaHttpClient59616261646162614A787461503250337E00F
  24A221C48BD8C09B1B5BA37BC9600000000000000000000000000000000000000
  00000000000000000000000301/
peer1: ID = 796f3ac4 name = DIOXINE.NET 
  addr = http://jxta.dioxine.net:6002/

Discovering other peers, peers of peers and so on, is just a matter of propagating a remote discovery request using peers -r.

JXTA>peers -r
peer discovery message sent

[time passes]

JXTA>peers
JXTA>peers
peer0: name = piglet
peer1: name = Platform PeerGroup
peer2: name = Platform PeerGroup
peer3: name = milne
peer4: name = NetPeerGroup by default
peer5: name = pooh
peer6: name = Platform PeerGroup
...

Discovered peers (technically, their peer announcements) are cached locally, stored in environment variables "peer#" where # is the sequential integer associated with a particular peer. To flush all known peers and begin again, use peers -f.

Peer Groups

Each peer belongs to a peer group. By default, each peer is a member of the global "NetPeerGroup" group, analagous to a world without area codes, where every phone number is globally unique. The majority of the time, however, we function within a particular community and can assume the presence of a limited number of appropriate peers. A peer group logically limits the scope of peers with whom you will be communicating, analagous to your local telephone area code. Upon joining a peer group, one sees only other member peers.

As with peers, to find out what groups are known to your peer, use the groups command; to propagate a group remote discovery request, use groups -r

JXTA>groups
group0: name = NetPeerGroup

JXTA>groups -l [the -l option provides more detail]
group0: GID = 12274c77 name = NetPeerGroup 
  addr = http://JxtaHttpClient59616261646162614A787461503250337E00F
  24A221C48BD8C09B1B5BA37BC9600000000000000000000000000000000000000
  00000000000000000000000301/

JXTA>groups -r
group discovery message sent

[time passes]

JXTA>groups
group0: name = piglets
group1: name = tiggers
group2: name = test
group3: name = NetPeerGroup
group4: name = foo
group5: name = foofoo
...

To join a group, simply use join -d group# where "group#" is the environment variable in which the group advertisement is stored. You are prompted for an identity; technically a UUID, anything will do. To leave, use (surprisingly enough) leave. Here I join the "tiggers" group, look around for peers and leave.

JXTA>join -d group1

JXTA>whoami -g
<PeerGroup>tiggers</PeerGroup>
<Keywords>myhost</Keywords>
<PeerGroupId>jxta://3FEAEE2E776F4670AC5E81EB9B5BA4800000000000000000000
  000000000000000000000000000000000000000000000000000000000000000000000
  00000201</PeerGroupId>
<Service>jxta.service.resolver</Service>
<Service>jxta.service.membership</Service>
<Service>jxta.service.discovery</Service>
<Service>jxta.service.pipe</Service>
<Service>jxta.service.peerinfo</Service>

JXTA>peers -r

[time passes]

JXTA>peers
peer0: name = tigger
peer1: name = milne
...

JXTA>leave
JXTA>

Discovered group announcements, like peers, are cached locally; flush them using groups -f.

P2P Piping

The JXTA shell extends the concept of the piping between local commands (as in man | wc) to inter-peer communication. JXTA pipes are unidirectional and asynchronous.

Since JXTA pipes are asynchronous, an output pipe connection can be dynamically disconnected and reconnected to a different input pipe. This disconnection operation can be performed multiple times over the lifetime of the pipe. The ability to transparently redirect output of pipes is an essential feature to build highly available services in a loosely coupled and unreliable environment such as peer-to-peer networks. -- JXTA Shell Documentation (PDF)

While not quite as elegant as using the | character, piping from one peer to another in JXTA is almost trivial. As an example, we'll open two shell windows (call them Pooh and Piglet) and pipe a couple of simple text messages between them (from Piglet to Pooh). Pretend for a moment that these are two separate peers running on machines on opposite sides of the Hundred Acre Wood.

JXTA>pipeadv = mkadv -p apipe
JXTA>inpipe = mkpipe -i pipeadv
JXTA>Shell -s
JXTA>pigletmsg = recv inpipe

First, Pooh creates a pipe advertisement and gives it a name ("pipeadv"). He uses this pipe advertisement to create an input pipe ("inpipe") -- the receiving end. After launching another shell window (Shell -s) for Piglet, an environment variable ("pigletmsg") is readied to receive input from our input pipe. We leave this shell window in a waiting state and wander over to Piglet's.

JXTA>opipe = mkpipe -o pipeadv
JXTA>mymsg = mkmsg
JXTA>importfile -f hellopooh file1
JXTA>put mymsg hello file1
JXTA>importfile -f byepooh file2
JXTA>put mymsg bye file2
JXTA>send opipe mymsg

Piglet uses the same pipe advertisement to create an output pipe ("opipe"). A new message is created and stored in the environment variable "mymsg." Now Piglet has created a couple of text files named hellopooh and byepoo containing one line of text apiece. In turn, each file is imported and stuffed into the variables "file1" and "file2." The contents are packed into "mymsg" with an associated arbitrary tag, so as to be able to sort them at the other end. Finally, Piglet sends his message via the output pipe and ...

recv has received a message
JXTA>cat pigletmsg
Tag: hello
Body:
<?xml version="1.0"?>

<ShellDoc>
  <Item>
    Hello, Pooh!
  </Item>
</ShellDoc>
Tag: bye
Body:
<?xml version="1.0"?>

<ShellDoc>
  <Item>
    Goodbye, Pooh!
  </Item>
</ShellDoc>

JXTA>data1 = get pigletmsg hello
JXTA>cat data1
<?xml version="1.0"?>

<ShellDoc>
  <Item>
    Hello, Pooh!
  </Item>
</ShellDoc>
JXTA>data2 = get pigletmsg bye
JXTA>cat data2
<?xml version="1.0"?>

<ShellDoc>
  <Item>
    Goodbye, Pooh!
  </Item>
</ShellDoc>

Instantly (or so the theory goes), Pooh receives Piglet's message. Simply printing the value of the "pigletmsg" variable reveals a message composed of a couple of XML documents and the associated tags given to them by Piglet. Instead of simply being displayed, individual documents can be extracted from the message and assigned to a variable using the get command.

Since inter-peer messages are nothing more than XML documents, this provides various interesting intersections with Web Services (via XML-RPC and SOAP), syndication (via RSS), Instant Messaging a la Jabber, and more.

Can we talk?

While the example above provided some insight into message passing via pipes under JXTA, the shell does actually have some rudimentary instant-messaging functionality. More a piping demonstration than anything else, talk resembles the *nix write functionality, with each peer establishing its own talk connection to the other.

JXTA>talk -register pooh
......
User : pooh is now registered
JXTA>talk -login pooh
JXTA>talk piglet
......
talk: piglet is not a registered user
JXTA>Shell -s

Pooh registers a talk user (read: talk advertisement) "pooh" and logs in (read: starts a listener daemon). He tries to find Piglet, who has not yet registered as a talk user. We use Shell -s to create a new shell for Piglet.

JXTA>talk -register piglet
......
User : piglet is now registered
JXTA>talk -login piglet

Piglet creates a talk user "piglet" and logs in.

JXTA>talk piglet
found user's advertisement attempting to connect
talk is connected to user piglet
Type your message. To exit, type "." at begining of line
Hello, Piglet!

Pooh tries again, this time successful in finding Piglet and sending him a greeting.

JXTA>talk: from jxta://59616261646162614A787461503250333DA927976125
4559B209922BACA69E190000000000000000000000000000000000000000000000000
000000000000301 to piglet
Message: Hello, Piglet!

JXTA>talk -u piglet pooh
found user's advertisement attempting to connect
talk is connected to user pooh
Type your message. To exit, type "." at begining of line
And a hello to you too, Pooh.

Piglet receives Pooh's message -- albeit in rather ugly form. Now, Piglet can't simply reply to Pooh, as talk is a one-way piped message. So Piglet establishes his own talk session to Pooh. You'll notice the slightly different form of talk -u piglet pooh, resulting in a much cleaner message with proper attribution in Pooh's shell.

JXTA>talk piglet
found user's advertisement attempting to connect
talk is connected to user piglet
Type your message. To exit, type "." at begining of line
Hello, Piglet!

talk: from piglet to pooh
Message: And a hello to you too, Pooh.

.
JXTA>talk -logout pooh
JXTA>talk: stop listening for user :pooh

Once our friends are ready to conclude their chat, each enters a period on a line by itself and optionally logs out. Note that talk advertisements created by talk -register hang around between shell sessions; before one can chat, however, one must talk -login to start a new listener.

Incidently, as I mentioned a moment ago, a talk registration is simply a JXTA advertisement stored in a local environment variable. We can take a closer look using our old friends, env and cat.

JXTA>env
stdout = Default OutputPipe (class net.jxta.impl.shell.ShellOutputPipe)
stdin = Default InputPipe (class net.jxta.impl.shell.ShellInputPipe)
...
adv0 = local jxta advertisement (class net.jxta.impl.protocol.PipeAdv)
stdgroup = Default Group (class net.jxta.impl.peergroup.StdPeerGroup)

JXTA>cat adv0
<?xml version="1.0"?>

<!DOCTYPE jxta:PipeAdvertisement>

<jxta:PipeAdvertisement>
  <id>
    jxta://59616261646162614A787461503250333DA9279761254559B209922
    BACA69E1900000000000000000000000000000000000000000000000000000
    00000000301
  </id>
  <name>
    JxtaTalkUserName:pooh
  </name>
</jxta:PipeAdvertisement>

Hardly user-friendly in its shell implemention, such talk functionality has already been implemented in InstantP2P, a Java AWT-based GUI chat/file-sharing demonstration application.

Logout

To log out of the JXTA shell, type exit at the prompt or just close the shell window. Quite a bit of information is retained between shell sessions including settings, cached peers, groups and other advertisements. To clear your peer or group caches, use the -f option mentioned earlier. To start from scratch, delete the following files/directories: PlatformConfig, PlatformPeerGroup, jxtaConfig, and cm.

Gotchas!

Bear in mind that the JXTA shell is only for demonstration and debugging purposes and should not be relied upon to be absolutely stable or emulate a full shell. At the time of this writing, there are a few gotchas and bugs:

Where to go for more...


Disclosure: The author has been a member of the JXTA's Technical Advisory Committee during its pre-launch development.

Copyright © 2009 O'Reilly Media, Inc.