JXTA4J2ME Implementation Architecture
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: 18.104.22.168 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.