http://www.developer.com/

Back to article

JXTA-A Messaging System for Wireless Java


October 10, 2002

In the first article of this series, we discussed JXTA, J2ME, and the way these two technologies cooperate with each other. We briefly introduced the JXTA architecture and the idea of J2ME devices acting as JXTA edge peers. We concluded by summarizing what this combination of technologies offers to a Java developer.

This article will take the concept further and explain how J2ME devices will use the services and features offered by JXTA to become part of a heterogeneous messaging system consisting of desktops, PDAs, cell phones, and other devices.

We will start by presenting the basic requirements and characteristics of a messaging architecture. We then will demonstrate how Java caters to messaging requirements. We will also show how JXTA4J2ME implementation provides a simple and easy to use high-level interface for messaging application developers.

Messaging

To elaborate the basic features of messaging, let us consider a common, real-life scenario. Imagine how people talk to each other, either face to face or on the phone.

In this type of live conversation, when one person is talking, the other person is supposed to be listening (and not doing something else) and when one stops talking, the other person is supposed to say something, almost immediately, in response.

Therefore, a telephonic or face to face conversation is real time and synchronized in the sense that each person expects an almost immediate response from the other end. While talking on phone, you cannot delay your response even for a few minutes.

This inherent notion of engaging the two parties in real time is referred to as synchronous communication. Web browsing is also synchronous in nature, just like telephonic conversation. You click on a link and expect the Web server to respond almost immediately, thus engaging the Web browser and the server in real time, at least temporarily.

Now compare this with the dialog that takes place through an exchange of letters or e-mail. What happens when you check your mail in the morning? Normally, you would sort and prioritize incoming mail, write immediate replies to urgent ones, and defer the ones less urgent or less important. A significant characteristic of this type of dialog is that the two communicating parties are hardly ever engaged in real time. When one person is writing an e-mail, the intended recipient is doing something else. Similarly, when the recipient is preparing the response, the sender is busy elsewhere.

We refer to this communication mechanism as asynchronous communication. Messaging systems rely on asynchronous communication. When we talk about messaging, we are actually referring to communication thats occur without ever engaging the communicating parties in real time. This is the biggest fundamental difference between Web browsing and messaging.

It's very logical to conclude that messaging is much more flexible than synchronous communication. You might have read auto-response e-mails from busy professionals and business executives saying something like "Thanks for your e-mail. I will get back to you as soon as possible. If you need my urgent attention, you can reach me at the phone number given below, but rest assured YOU WILL GET A BETTER RESPONSE BY E-MAIL". This is a direct result of the inherent flexibility of asynchronous communication; it allows all concerned parties to act according to their own priorities and convenience.

The same is true about the software components of server side e-commerce solutions (for example, Web Service components). It is easier to build flexible e-commerce solutions using the messaging style of communication rather than using simple client/server synchronous messaging.

Let's see how Java caters to messaging requirements.

Messaging Architecture in Enterprise Java

Java 2 Enterprise Edition (J2EE) version 1.3 includes a messaging API called Java Messaging Service (JMS). Enterprise Java developers can use JMS to build messaging applications that are portable across the different J2EE implementations.

JMS uses the concept of clients and providers. Any messaging application that uses the JMS API is called a JMS client. A JMS provider, on the other hand, is the implementation of the JMS API that will handle all the messaging nuts and bolts needed by a JMS client.

Logically, there are two types of messaging clients: message producers and message consumers. Message producers will author (create or produce) messages, which consumers will receive (consume). A JMS client application will normally have the capability to act both as a message producer and a consumer.

JMS clients (producers and consumers) can use two styles of messaging to communicate with each other through JMS: point-to-point and publishing/subscribing.

Point-to-point messaging is employed when the exchange of messages simply occurs between two communicating parties. A message producer will send messages to a message queue. The queue is the place where the intended recipient (message consumer) will look for his incoming messages.

On the other hand, the publishing/subscribing style of messaging is like a broadcast and is based on topics. A message producer will post his message to a topic. Message consumers who have interest in that topic will subscribe to it to receive all messages posted to that topic.

A JMS provider is responsible for administering queues and topics. A JMS client application does not have to cater to the low-level details (such as how to store/maintain the list of topics and the list of subscribers to each topic) and will simply call methods of the JMS API to utilize the services of a JMS provider.

We do not want to go further into the details of JMS architecture and therefore we have included a link to a collection of articles on JMS in the resources section at the end of this article. Curious readers may follow the link to get complete details of the JMS API.

The point here is that JMS provides comprehensive features that can be used to build reliable messaging applications. However, a JMS provider implementation is a heavy-weight component. It is interesting to note that a J2ME device is too humble in capabilities to host a JMS provider.

So, what if you want to use a J2ME device to act as a JMS client?

A natural solution is to distribute the JMS provider functionality in such a way that only a skeleton high-level abstraction is necessary to be hosted inside the J2ME device. This will leave the heavy lifting for some server that will host the JMS provider. However, doing this will raise the issue of how to connect a mobile wireless device to the server.

Recall what we discussed about early versus late bindings in part 1 of this series of articles. It is not possible to use a simple early-bound mechanism to connect to mobile wireless devices that keep on changing their network bindings.

JXTA4J2ME: A Messaging Solution

Well, JXTA4J2ME is the perfect solution to this problem. Following is a point-wise analysis to support our claim:

  1. liJXTA4J2ME provides a skeleton, small-footprint API, suitable to be hosted in a J2ME device. JXTA4J2ME can connect to JXTA relays. The relay provides all heavy lifting functionality, such as XML authoring and processing.
  2. The JXTA virtual network overlay solves the problems associated with early bindings. The JXTA4J2ME peer only needs to connect to ANY relay (that is in turn connected to the JXTA network of rendezvous peers) and the network will automatically adjust itself to the changes in network topology.
  3. The JXTA set of protocols provides both types of messaging features that we discussed above (point-to-point and publishing/subscribing). For example, a JXTA unicast pipe connects two end points for a simple point-to-point message exchange. On the other hand, a JXTA propagate pipe is used to accomplish broadcasting of messages to all interested peers. Moreover, the act of joining a peer group is inherently similar to subscribing to a JMS topic.

In addition to the JMS style functionality, the JXTA4J2ME-based messaging offers additional features, such as the ability to discover peers and peer groups.

In order to demonstrate how a messaging application will work using JXTA4J2ME connected to a JXTA network through a relay, let us consider the basic things that you will most likely do in any messaging application. The next section is a brief tutorial that will take you through the major steps of using JXTA4J2ME in a generic messaging application.

A Generic JXTA4J2ME-based Messaging Application

No matter what you want to accomplish in a JXTA4J2ME-based messaging application, the first step is always to instantiate the PeerNetwork class, which is part of the JXTA4J2ME implementation. This is accomplished by calling the static createInstance method of the PeerNetwork class. The createInstance method takes only one parameter, which is the name of the peer trying to connect:

PeerNetwork peerNetwork = PeerNetwork.createInstance(peerName);

In the preceding line of code, we assume that the peerName is a String type object that contains the name with which user wants to identify himself. You will perhaps have this name stored in J2ME's Record Management System (RMS) and read it from there as and when needed. (In the resources section, we have included a link to an article on how to use RMS.)

The second step is to connect to a relay:

String relayURL = getRelayURLPerhapsFromRMS();
Byte[] connectionState = null;
connectionState = peereNetwork.connect(relayURL, connectionState);

The peerNetwork.connect method in the preceding code takes two parameters. The first string type parameter is the URL of the relay that we would like to connect to. Normally, the relay address will be stored in the J2ME RMS and some helper method (such as the getRelayURLPerhapsFromRMS method shown above) will fetch the URL from RMS. Note that the getRelayURLPerhapsFromRMS method is only shown as an example to demonstrate that the URL needs to be fetched from somewhere, perhaps from the RMS, depending on the application design. This method is neither part of JXTA4J2ME implementation nor the J2ME MIDP itself. J2ME application developers will need to implement it themselves.

The second parameter, which is a byte array, represents the state of connection to the relay. If you pass on null as the value of the state parameter, a new connection will be established.

The connect method returns the state of the connection after the method call. This value identifies the connection, so that the next time when the same peer connects to the relay, the relay will identify the peer. This way, the peer will be able to receive any messages collected while the peer was away (not connected). Therefore, you will need to store the connection state somewhere (most likely, in the RMS).

Now you are connected and ready to do some serious messaging. There are various ways you can proceed from here:

  1. Search for a specific resource. You can search for three types of resources using JXTA4J2ME: peers, peer groups, and pipes.
  2. You already know the resource, so you don't need to search. You would like to start sending in messages.
  3. You don't feel like sending any messages. You just want to listen to what other people are saying. So you will just poll for incoming messages.
  4. Any combination of the above.

Let's see how to do these tasks using JXTA4J2ME.

Searching on a JXTA network

The search method call of the PeerNetwork class will do the searching for you. This is accomplished as follows:

int requestId = peerNetwork.search (PeerNetwrok.PIPE, "hockey*");

The first parameter specifies the resource that you want to search. Possible values of this parameter are PeerNetwork.GROUP, PeerNetwork.PEER, and PeerNetwork.PIPE, which are the three static fields defined by the PeerNetwork class to specify peer groups, peers, and pipes respectively.

The second parameter is a simple search string. Therefore, the line of code shown above will search for all pipes whose names begin with "hockey" (meaning that you are trying to find communication pipes that are relevant to hockey).

The search method returns an integer type identifier, which will be used to match responses. This is necessary because of the asynchronous nature of messaging (refer to the earlier discussion on synchronous versus asynchronous messaging). You are not sure when you will receive the response to a particular message. In fact, other peers connected to the JXTA network will respond according to their own convenience (a convenience only possible with asynchronous communication).

Therefore, you can receive a variable number of responses from the JXTA network to each request. You can send any number of different search queries and expect the responses all mixed up with each other. There will be an identifier associated with each response, which will be used to match a particular request with the corresponding response.

As an example, we would like to show a typical response to the pipe search request shown above (the response has been simplified for readability):

"proxy:response" "application/octet-stream" dlen=6 "result"
"proxy:requestId" "application/octet-stream" dlen=1 "1"
"proxy:type" "application/octet-stream" dlen=4 "PIPE"
"proxy:name" "application/octet-stream" dlen=12 "SearchPipe"
"proxy:id" "application/octet-stream" dlen=80 "a unique identifier"
"proxy:arg" "application/octet-stream" dlen=11 "JxtaUnicast"
"jxta:EndpointDestinationAddress" "application/octet-stream" dlen=93
                                  "destination address"
"jxta:EndpointSourceAddress" "application/octet-stream" dlen=27
                             "source address"

This is not the actual HTTP response; it has been simplified to show the various components of a response message. We will demonstrate and explain the actual HTTP responses in the next article of this series. For the moment, just notice that the response contains several elements. Each element has been shown on a separate line in the preceding response.

Each element, in turn, consists of four components or fields. The first field is the name of the element. For example, the name of the first element is "proxy:response". This name resembles the name of an XML element because it contains a namespace prefix (proxy) and an element name (response). You can create your application specific namespaces and use them to create messaging logic.

The second field (application/octet-stream) is the MIME type of the data. The third field is the length of the data field, and the fourth field is the data itself. For example, the MIME type of proxy:response data is "application/octet-stream", data length is 6, and the actual data stream is "result".

Just look at the various elements. The proxy:requestId element specifies the identifier of the request that corresponds to this response. The other three important elements of this search query response are the id (proxy:id), name (proxy:name), and type (proxy:arg) of the pipe that you searched for. You will need these three elements when you want to send messages to this pipe.

Sending Messages

Sending messages is a two-step procedure. First, you author a message and then send it to the relay.

// Author a message.
Element[] elementArray = new Element[2];
String data = "Bilal";
elementArray[0] = new Element("SenderName", data.getBytes(),
                               null, null);
data = "Hello from Bilal";
elementArray[1] = new Element("SenderMessage", data.getBytes(),
                               null, null);
Message message = new Message (elementArray);

The Element and Message classes used in the preceding code are part of the JXTA4J2ME implementation.

As we've already seen, a JXTA4J2ME message consists of elements. So during message authoring, we'll need to author each element separately (by calling the Element constructor), put all those elements in an array, and then pass on the element array to the Message constructor, which will pack them together to form the complete message.

The Element constructor takes four parameters:

  1. Name of the element (String)
  2. Data to be sent (array of bytes)
  3. Namespace identifier (String)
  4. MIME type of the data (String)

We have only specified the first two fields in the preceding code, passing null as the value of the third and fourth fields. The result will be that an empty namespace string ("") and the default MIME type ("application/octet-stream") will be sent in the element.

After you have finished authoring the individual elements of the message array, you will simply pass on the elements array to the message constructor.

The second step is to send the message to the relay. You simply will call the send method of the PeerNetwork class for this purpose, passing the authored message along with the method call:

//Send the authored message to the relay.
int messageID = peerNetwork.send(pipeName, pipeID, pipeType);

The send method call takes four parameters. The first three are the name, id, and type of the pipe that you want to use to send the message. All the three parameters are of the String type. Recall that these three parameters were received in response to the pipe search query discussed above. The fourth parameter is the message we just authored.

Checking for Responses

Have a look at the following lines of code:

Message message = null;
while (1) {
  message = peerNetwork.poll(1000);
  if (message == null) break;

  //Here is the place to add logic to store or process the
  //incoming message.
} //while

The while block will keep on polling until the poll method returns null, which happens only when the relay has no more messages to return.

The poll method takes just one parameter, which is the time in milliseconds to wait for the response. If the response from the relay is not received within this time interval, the method will return null. Specifying zero as the value of this parameter will mean that it waits forever.

Summary

In this article, we discussed the features that are common to all messaging applications. We also elaborated how JMS provides messaging features and how JXTA4J2ME matches the same functionality for J2ME devices. At the end, we followed a step-by-step how-to tutorial, explaining how to perform the basic tasks in a JXTA4J2ME-based messaging application.

Next time, we will go into the details of the three classes in the JXTA4J2ME implementation (PeerNetwork, Message, and Element). We will also see how a JXTA relay coordinates with edge devices to provide the heavy lifting part of a messaging application.

About the Author

Bilal Siddiqui is an Electronics Engineer, an XML consultant, and the co-founder of WaxSys, a company focused on simplifying e-Business. After graduating in Electronics Engineering from the University of Engineering and Technology, Lahore, in 1995, he began designing software solutions for industrial control systems. Later, he turned to XML and used his experience programming in C++ to build Web- and WAP-based XML processing tools, server-side parsing solutions, and service applications. He is a technology evangelist and a frequently published technical author. Bilal has also contributed to a couple of books, namely Java P2P Unleashed and Web Services Business Strategies and Architectures. Readers may contact Bilal at bsiddiqui@waxsys.com.

Resources

JXTA4J2ME (http://jxme.jxta.org/) comes with sample programs. Try the demo chat application that is included in the JXME zip (http://download.jxta.org/stablebuilds/libs/jxme.zip) and read a document (http://jxme.jxta.org/Chat_Demo.html) that shows how the demo works.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date