In the first part of this series of articles, we discussed the basic JXTA architecture and elaborated how it can coordinate with J2ME edge devices to become part of an integrated application framework in a truly distributed and heterogeneous environment. Based on this ability of the JXTA and J2ME technologies to work together, we explained why Java Wireless programmers should care about using this combination of technologies.
In the second part, we presented JXTA4J2ME as a messaging framework. We listed the common features of all messaging applications and briefly described how Enterprise Java offers these features. We then showed how a JXTA4J2ME implementation matches the same features and how wireless application developers can use the high-level JXTA4J2ME API in a messaging application.
This installment will take you on a journey into the JXTA4J2ME implementation to see what’s inside. In this article, we will discuss the following issues:
- How classes in the current JXTA4J2ME implementation work.
- The format of communication protocol that JXTA4J2ME uses to talk to a JXTA relay.
- How JXTA4J2ME classes wrap the HTTP-based communication between a JXTA4J2ME client and a JXTA relay.
Readers are encouraged to go through Part 2 of this series before reading this third installment. Part 2 discusses the use of the JXTA4J2ME API, which is important to understand the concepts presented in this article.
The PeerNetwork Class
Recall from our discussion in the last article that PeerNetwork is the main class that wraps almost all JXTA4J2ME functionality. Therefore, this class is a good point to start digging to see what’s inside.
While looking at the details of the PeerNetwork class, we will explain how it works, how it manages communication, what protocol format the JXTA relay expects, what data the relay returns to the PeerNetwork class, and how the PeerNetwork class loads and manages protocol data primitives internally.
Instantiating the PeerNetwork Class
You will always use the PeerNetwork.createInstance static factory method to instantiate a PeerNetwork object. The createInstance method internally calls the PeerNetwork constructor. All PeerNetwork constructors are kept private by the class designers, to control the creation of PeerNetwork objects.
Connecting to the Relay
Once a PeerNetwork object has been instantiated, you will call its connect method as explained in the second part.
The PeerNetwork.connect method in the current JXTA4J2ME implementation internally manages all connection-related issues through a helper class named HttpMessenger. The HttpMessenger class is not exposed directly to a JXTA4J2ME client application, as it only serves as a sandwiched layer between the PeerNetwork API and the underlying J2ME implementation. The main advantage of having a sandwiched layer is depicted in Figure 1.
As shown in Figure 1, the HttpMessenger class comes in two flavors, one for Connected Device Configuration (CDC) and one for Connected Limited Device Configuration (CLDC). CDC and CLDC are two configurations for wireless devices. CLDC, as its name suggests, is meant for devices that are more limited in their resources as compared to CDC devices. Examples of CLDC devices are communicators, automobile entertainment devices, digital refrigerators, and so forth. On the other hand, examples of CLDC devices are mobile phones and pagers.
The HttpMessenger class, therefore, provides a bit of abstraction over the two configurations and takes care of the differences in different J2ME configurations. If more configurations are introduced in the future, you will simply need to re-implement the HttpMessenger class for each configuration and the rest of JXTA4J2ME will work as such.
The HttpMessenger class has a method named connect, which is responsible for creating a connection with the JXTA relay. The PeerNetwork.connect method internally calls the HttpMessenger.connect method, which in turn sends an “obtainLease” request to the relay using the J2ME classes for HTTP communications. Following is a typical obtainLease HTTP request:
POST /relay HTTP/1.1 Host: 220.127.116.11 Connection: keep-alive x-jxta-command: obtainLease Content-length: 0
This is a simple HTTP request that uses the post method and sends the JXTA command named “obtainLease”.
Following is an example of the HTTP response that the relay is expected to return in case of a lease approval:
HTTP/1.1 200 OK Date: Fri, 01 Nov 2002 07:35:18 GMT Server: Jetty/4.0.3 (Linux 2.4.9-6smp i386) Servlet-Engine: Jetty/1.1 (Servlet 2.3; JSP 1.2; java 1.4.0-beta) x-jxta-num-msg: 0 x-jxta-relay: uuid-59616261646162614A787461503250335F148183A71344 AAADB2A724632A2 8F703 x-jxta-client: uuid-59616261646162614A7874615032503384EB6855E3AD4 6E09696871CC17E E24C03 x-jxta-lease: 1800000 Content-Length: 0
The HttpMessenger.connect method, on receipt of the response from the relay, will first check whether the relay has provided the required lease. If so, it will extract the x-jxta-client value from the request and return it to the PeerNetwork.connect method. The PeerNetwork.connect method will eventually return this value to the calling application to be used in subsequent connection requests (recall our discussion related to the PeerNetwork.connect method in Part 2).
Once you have obtained a lease from the relay, you are connected to the JXTA network. You can now start sending different types of messages (for example, search messages) to the JXTA network. Before considering the actual messaging, it is important to understand the format that JXTA4J2ME uses to communicate with the relay. The following section explains the messaging formats involved.
JXTA Message Format
Following is a search message that a JXTA relay will understand and recognize as a search message:
jxmg 0 01 05 proxy 05 jxel 2 0 07 request 06 search jxel 2 0 04 type 04 Peer jxel 2 0 04 attr 04 Name jxel 2 0 05 value 06 Waxsys jxel 2 0 09 requestId 01 1
The actual message does not contain any spaces or line breaks, but we have inserted some spaces and line breaks to improve readability. However, it is still not easy to understand the above message, until we understand the different elements of the message and the different fields of each element.
Now, look at the following form of the same message, where we have inserted some comments and put in numbers to identify individual elements of the message:
// The message header jxmg 0 01 05 proxy 05 // List of elements: 1- jxel 2 0 07 request 06 search 2- jxel 2 0 04 type 04 Peer 3- jxel 2 0 04 attr 04 Name 4- jxel 2 0 05 value 06 Waxsys 5- jxel 2 0 09 requestId 01 1
The first line (starting with the string “jxmg”) is the message header, which marks the start of a message. An explanation of each field of the message header is as follows:
Message header explanation: jxmg // Message header identifier 0 // Message version 01 // Number of namespaces within the element 05 // Length of the first namespace proxy // Name of the first namespace 05 // Number of elements in this message
The order of occurrence of the different fields in the message header should remain the same as shown above. You can gather the following points from the explanation of the message header:
- Each message header starts with the string “jxmg”.
- The message header identifies its version (currently zero).
- The message header contains a list of all namespaces that its elements can use. There’s just one namespace in the example we are using, but there can be any number of namespaces in a single message. This way, the string representation of the namespace needs to be mentioned just once and all elements included in the message will simply refer to the string. This helps reduce the size of the message payload.
- The message header also contains the number of elements in the message. As the message header sits at the beginning of the message and knows how many elements the message contains, the message header effectively acts as a “logical wrapper” for the contents (elements) of the message.
Now let’s have a look at the individual elements of the message. The first element is reproduced below:
1- jxel 2 0 07 request 06 search
Recall from the discussion of the Element class constructor in Part 2 that the Element constructor takes four parameters, namely:
Name (of the element),
Namespace, and the
These four parameters form the four “fields” of an individual element. Mapping of these four parameters to the different fields is explained below (in the same order as the fields appear in an element):
- The string “jxel” marks the start of an element.
- The number “2” is a reference to the namespace (“proxy”). Namespace id is generated incrementally starting from 2. The values 0 and 1 are reserved. 0 refers to empty namespace (no namespace defined) and 1 refers to the “jxta” namespace. This means a namespace reference “2” will refer to the first namespace mentioned in the message header, “3” will refer to the second namespace mentioned in the header, and so on. As our sample message header contains just one namespace definition (“proxy”), all elements that belong to “proxy” namespace will have “2” in the namespace field of the element.
- The number “0” means default MIME type and “1” means MIME type is user provided. In our case, we are using the default MIME type (application/octet-stream), so we don’t need to provide the actual MIME type string. If we were using some other user-defined MIME type, we would have authored a “1” in the MIME type field followed by the MIME type string.
- The number “07” shows the length of the element name.
- The string “request” is the element name.
- The number “06” shows the length of the element data.
- The string “search” is the element data.
The Element and Message classes in the JXTA4J2ME implementation wrap all this functionality. All you need to do is create individual elements by calling the Element constructor, put all the elements in an array, and then pass on the array to the Message constructor. The Message class will automatically generate the completed message payload when required.
Searching on a JXTA Network
As explained in the second part, the search method of the PeerNetwork class performs the searching for you. The PeerNetwork.search method takes two parameters, namely the type of the resource that you want to search (peer, group, or pipe) and a query string (name of the resource that you are looking for).
Internally, the search method performs two steps:
- Authors a search query message.
- Sends the search message to the JXTA relay.
Consider the following search method call:
// Assuming "peerNetwork" is a PeerNetwork instance. int requestId = peerNetwork.search (PeerNetwrok.PEER, "Waxsys");
This method call will internally generate an array of following elements following the message header:
// The message header jxmg 0 01 05 proxy 05 // List of elements: // Identifies the message as a Search request/query 1- jxel 2 0 07 request 06 search // Type of resource to search for 2- jxel 2 0 04 type 04 Peer // Attribute of the source to search for. // It is hard-coded by JXTA4J2ME as "Name" 3- jxel 2 0 04 attr 04 Name // Name of the resource to search for. 4- jxel 2 0 05 value 06 Waxsys // Request identifier to match responses. 5- jxel 2 0 09 requestId 01 1
We have already discussed the details of the format of the message header and the elements. Now let’s see what they mean:
The above message consists of five elements, all of which belong to the “proxy” namespace.
The first element is the request tag that identifies this message as a request query message.
The second element defines the resource that you want to search for. The first parameter that the user supplies (type of the resource to search for) to the PeerNetwork.search method call will be copied as the data field of this element.
The third and fourth elements define a name value pair. The current JXTA4J2ME implementation has hard-coded the data field of the third element as “Name”, which means the search request will always try to match the names of resources (peer, group, or pipe) with the data string of the fourth element.
The fifth element is a request identifier. The relay will include this identifier with the response to identify that the response is for this particular search message. The search message generates a request identifier for each search message call and returns the identifier to the calling application, so that it can keep a record of the identifier to match responses.
The search message now needs to be added to the outgoing messages queue. This is the job of a private method named PeerNetwork.sendMessage. The search method will call the sendMessage method and hand the newly authored search message to it. The sendMessage method adds two new elements to the message and then places the Message object to the outgoing messages queue:
// The message header jxmg 0 01 05 proxy 07 // List of elements 1. jxel 2 0 07 request 06 search 2. jxel 2 0 04 type 04 Peer 3. jxel 2 0 04 attr 04 Name 4. jxel 2 0 05 value 06 Waxsys 5. jxel 2 0 09 requestId 01 1 6. jxel 1 0 27 EndpointDestinationAddress 84 HTTP://127.0.0.1:8080/urn:jxta:uuid-7. DEADBEEFDEAFBABAFEEDBABE0000000E05/CrystalGroup 7. jxel 1 0 22 EndpointSourceAddress 95 http://JxtaHttpClientuuid- 59616261646162614A7874615032503384EB6855E3AD46E09696871CC17E/
The first five elements in the above code are the same as those authored by the search method described above.
The last two elements (sixth and seventh) are added by the sendMessage method. The sixth element is the address of the (destination) JXTA relay, while the seventh element identifies the (source) J2ME device on the JXTA network.
Sending Messages to a JXTA Pipe
Recall the PeerNetwrk.send message call discussed in the last article. This method is used to send messages to specific pipes in the JXTA network. However, JXTA4J2ME cannot send messages directly to the pipe. Rather, we will send the message to the relay and include appropriate elements in the message that will tell the relay which pipe is to be used as the transport for the message to its destination peer(s).
You have seen how a search query message is sent. The message is internally authored and then sent to the JXTA relay. This procedure is similar for sending messages to a pipe. The only difference is that search messages are authored internally inside the PeerNetwork.search method and then a call is made to the sendMessage method. When you want to send your own message to a pipe, you will author it yourself and then call the send method of the PeerNetwork class. The send method will internally call the sendMessage method, which will add its two elements and then adds the message to the outgoing messages queue.
The following message consists of nine elements, out of which only two were authored by the client; the rest of the elements were appended by the message sending procedure.
// Message header jxmg 0 01 05 proxy 09 // Elements authored internally by the PeerNetwoek.send() method: 1. jxel 2 0 07 request 06 send // Send request element 2. jxel 2 0 09 requestId 01 1 // Request identifier 3. jxel 2 0 09 name 08 PipeName // Name of the pipe 4. jxel 2 0 09 id 06 PipeID // Pipe ID 5. jxel 2 0 09 type 11 JxtaUnicast // Type of the pipe // Elements authored by the client application/JXTA4J2ME user. // Notice that here we are using the default (empty) namespace. 6. jxel 0 0 04 Name 06 Waxsys // peer name element 7. jxel 0 0 07 Message 04 Hello WaxSys // message for peer // element // Two elements authored by the PeerNetwork.sendMessage() method. 8. jxel 1 0 27 EndpointDestinationAddress 84 HTTP://127.0.0.1:8080/urn:jxta:uuid-DEADBEEFDEAFBABAFEEDBABE0000000 E05/CrystalGroup 9. jxel 1 0 22 EndpointSourceAddress 95 http://JxtaHttpClientuuid- 59616261646162614A7874615032503384EB6855E3AD46E09696871CC17E/
Polling for incoming messages
The PeerNetwork.poll method call checks for incoming messages on the relay. Internally, it will first check whether there are any outgoing messages in the queue waiting to be sent. It will extract (de-queue) the first message from the queue and append that message to its poll message. If there are no messages, an empty message will be used for polling. It will then call the poll method of the HttpMessenger class, which will send the poll message.
As explained above, the HttpMessenger class is here to provide abstraction for various configurations in J2ME. That’s why the actual HTTP communication is the responsibility of the HttpMessenger class.
Following is a typical HTTP request that will be used for polling:
POST /relay HTTP/1.1 Host: 18.104.22.168 Connection: keep-alive x-jxta-command: poll x-jxta-client: uuid-59616261646162614A7874615032503384EB6855E3AD 46E09696871CC17E x-jxta-timeout: 1000 Content-length: 0
In this article, we have described the internal functioning of JXTA4J2ME classes.
We started with the PeerNetwork class and explained the PeerNetwork operation over the sandwiched HttpMessenger class. We also provided sample HTTP messages that request a leased connection into the JXTA network. We then discussed the format of JXTA messages that are exchanged between relays and J2ME devices. Next, we described how messages are authored internally and queued as outgoing traffic. At the end, we discussed the polling procedure that checks with the relay if there are any incoming messages.
In the next article, we’ll present a list of value-added J2ME applications that can be built using the JXTA set of protocols. We will also discuss the design of a couple of such applications.
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 firstname.lastname@example.org.
- Read the first and the second parts of this series.
- Check out the official JXTA4J2ME page at Sun’s Web site.
- This book on JXTA is available on-line and the author is inviting everyone to steal it for free.
- Compute Power Market, or CPM for short, is a very interesting grid computing application of the JXTA technology. Visit the project’s Web site for details.