Channels ▼
RSS

JVM Languages

Java's Generic Connection Framework

Source Code Accompanies This Article. Download It Now.


Apr02: Programmer's Toolchest

Paul is a software developer with AudioAudit and author of Instant Wireless Java With J2ME (McGraw-Hill). Paul can be reached at ptremblett@earthlink.net.


When applications require greater performance, one of the first things you often think of is adding MIPS or memory. However, this is often not practical with mobile information devices (MIDs). You could try tapping into server resources, but this requires networking. And since networking is a specialized form of I/O, you then must know how I/O is implemented on the mobile device. Sun Microsystems's Connected Limited Device Configuration specification (CLDC; http://java.sun.com/products/cldc/) addresses this issue. CLDC is the foundation of a run-time environment for mobile phones, pagers, PDAs, and other limited-resource devices. CLDC works with 16/32-bit RISC/CISC-based systems that have as little as 160 KB of memory. When used with device-specific APIs such as the Mobile Information Device Profile (MIDP; http://java.sun.com/products/midp/), CLDC provides a Java 2 Micro Edition (J2ME) run-time environment for small resource-constrained devices. In this article, I'll focus on the Java Generic Connection Framework, which is part of the CLDC specification. All of the examples I'll present were developed with the J2ME Wireless Toolkit; http://www.java.sun.com/j2mewtoolkit/.

A Different Approach to Input/Output

The Java 2 Standard Edition (J2SE) provides a rich API for I/O. In JDK 1.4, for instance, the java.io, java.nio, java.nio.channels, and java.net packages contain approximately 120 classes, 30 interfaces, 1100 methods, and 50 exceptions. Clearly, a full implementation of the J2SE API on mobile devices is out of the question. Consequently, the MIDP spec defined the minimum requirements for MIDs with 128 KB of nonvolatile memory for the MID components and 32 KB of volatile memory for the Java run time. Besides, even if memory weren't a problem, not all of the functionality in the J2SE API is applicable to MIDs. Designing a spec that addressed these issues presented the CDLC authors with a challenge. Their solution was the Generic Connection Framework (GCF).

Rather than using a collection of completely different abstractions, the GCF uses a set of related abstractions at the API level. All connections are created by invoking a single static method in the system class Connector. The method, which takes a single argument, is the open method. The argument is a String that takes the form:

"<protocol>:<address>;<parameter(s)>"

Syntactically, this string is similar to a Uniform Resource Indicator (URI), as defined in IETF Standard RFC2396 (http://www.ietf.org/rfc/rfc2396.txt).

At run time, the implementation uses the portion of the parameter up to the first ":" to instruct the system to obtain an appropriate protocol implementation. This late binding permits dynamic run-time adoption to different protocols. The single-method/single-uniform string approach also simplifies setup for programmers.

In addition to the Connector class, the GCF is implemented as a hierarchy of seven Connection interfaces that group similar classes of protocols together. Figure 1 illustrates this hierarchy, which, along with HttpConnection, form the MIDP spec. The interfaces increase in capability from the top of the hierarchy to the bottom.

The Connection interface represents the most basic connection type and can only be opened and closed. Its open method is not invoked directly by programmers, but via the static open method in the Connector class. All of the interfaces I examine here are subinterfaces of Connection.

The InputConnection Interface

The InputConnection interface represents a device from which data can be read. DaytimeClient.java (available electronically; see "Resource Center," page 5) is an example of this interface being used to read data from a daytime server. The MIDlet (that is, a "mobile information device application") establishes a socket connection to the server, which listens on port 13, accepts a connection, and sends the date/time back to the MIDlet. The MIDlet reads the data a byte at a time into a byte array until all the data has been read. It then uses the byte array to create a string containing the current date and time, which it displays; see Listing One.

You create the connection by passing "socket://127.0.0.1:13" to the open method of the Connector class and casting the Connection object that is returned to an InputConnection. You then invoke openInputStream against the InputConnection object. This method returns an instance of InputStream that you use to read data. Figure 2 is the MIDlet running under the early release of MIDP For Palm using the Palm OS Emulator (POSE). The .prc file that runs on the Palm was created using the converter utility distributed with MIDP For Palm. Input to the utility is DayTimeClient.jad (available electronically).

The counterpart of InputConnection is OutputConnection. These two are combined to form the StreamConnection interface, which is the logical starting point for classes that implement communications interfaces.

The StreamConnectionNotifier Interface

You use the StreamConnectionNotifier interface when you need to listen for incoming connections. SimpleMessaging.java (available electronically) contains a MIDlet that uses this interface. This MIDlet starts a thread that creates a StreamConnectionNotifier using Listing Two.

The reason for invoking this method in a separate thread is that the run method contains the blocking call sc = scn.acceptAndOpen(); which returns only when it receives an incoming connection on port 9191. While it is waiting for a connection, the application displays a message such as the one shown in Figure 3. After the connection has been received, data is read from the input stream and displayed as in Figure 4.

MessageSender.java (available electronically) is J2SE code to send a message to the MIDlet. It accepts input from the console and uses the networking classes in the java.net package to establish a socket connection and transmit the data.

The ContentConnection Interface

The ContentConnection interface is a subinterface of StreamConnection that provides methods for handling content. These methods are getEncoding, getLength, and getType. The MIDlet in PhotoClient .java (available electronically) uses this interface. In this example, you create a connection using the string http://localhost/DDJ/images/thatguy.png. Since the connection is a ContentConnection, you can determine the length of the data that is available, allocate a byte array to hold the data, and read the data into the array using a single invocation of the read method. Figure 5 shows the output from the MIDlet. As a defensive programming measure, you should assume that the server might not send back the content length. If this is the case, getContentLength returns -1. In this case, you read 1 byte at a time into a byte array until all bytes have been read. You initially create an array that holds 24 KB. If the array fills up, you create a new array that is 1 KB larger than the previous array, copy the contents of the previous array into the new array, and continue reading data. You repeat the process of creating larger arrays as often as is necessary. When the read operation has completed, pass the byte array containing the data to the static method createImage of class Image. You pass the Image object that is returned to the setImage method of the ImageItem object image. Finally, you display the Form that contains the ImageItem.

The HttpConnection Interface

The MIDP specification states that MIDP implementations must provide support for accessing HTTP 1.1 servers and services. The HttpConnection interface, which is a subinterface of ContentConnection, provides the functionality needed to set request headers, parse response headers, and perform HTTP-specific functions.

The connection exists in one of three states: setup, connected, and closed. In the setup state, no connection has been made to the server. In this state, you can invoke the setRequestMethod to specify whether the request is GET (the default), POST, or HEAD. In setup state, you can also invoke setRequestProperty to specify one or more keys and their values. The connection transitions from the setup state to the connected state when you invoke any method that requires data to be sent to or received from the server. The closed state is entered when the close method is invoked. Any method invoked against a connection that has been closed results in an IOException being thrown.

SessionDemo.java (available electronically) includes a MIDlet that uses the HttpConnection interface to participate in a session with a servlet that delivers output to the MIDlet using Java Server Pages (JSPs). The MIDlet creates an HttpConnection using Listing Three(a). After the connection has been created and while it is in setup state, the MIDlet executes Listing Three(b).

In the first line of code of Listing Three(b), you use the setRequestMethod to specify that the request be a POST request. You then set the request property User-Agent to a value that identifies this request as originating from a MIDP application and not from a browser. You may have already written servlets that used the value of this property to forward a request to a JSP that generates WML instead of HTML when the request originated from a WAP device. When the request originates from an MID, the easiest way to handle output is to forward the request to a JSP that sets the content type to "text/plain" and sends back untagged data. There is nothing, however, to prevent you from sending back XML if you wish because some XML parsers have been modified to work under MIDP.

When you have finished executing the setup code, you invoke the getContentHeader method. Because this method requires that data be read from the server, the connection transitions to the connected state. If the Vector cookies is null, indicating that it has not yet been created, you invoke getCookies. In this method, you instantiate a Vector in which you save the values of all header fields with a name of "Cookie." If cookies is not null, you invoke setCookies. In this method, you retrieve all of the elements from the Vector and concatenate them together separated by a semicolon (;). When the entire string has been formed, you use the setRequestProperty method to assign the property Cookie the value contained in the concatenated string. Among the cookies sent back to the server is one named JSESSIONID. As described in the servlet specification, the servlet container uses the value of this cookie to maintain session objects. The CountServlet.java servlet (available electronically) uses the session object to store a counter containing the number of times the client has visited. It uses the JSP shown in DisplayVisitsCount.jsp (available electronically) to send the value of this counter to the MIDlet. Figure 6 shows this counter after several visits.

Conclusion

The Generic Connection Framework is as powerful as it is simple. The fact that the MIDlets I present here talk to an existing server without modification to that server, as well as a servlet that was no different from any other servlet, demonstrates that the framework can be used to develop applications that are a transparent, integral part of an enterprise.

DDJ

Listing One

try {
  socket = (InputConnection)Connector.open("socket://127.0.0.1:13",
             Connector.READ, true);
  is = socket.openInputStream();
}
catch (Exception e) {
}
try {
  int b;
  StringBuffer sb = new StringBuffer();
  while ( (b = is.read()) != -1) {
    sb.append((char)b);
  }
  socket.close();
  dt.setText(sb.toString());
  display.setCurrent(outputForm);
}
catch (Exception e) {
}

Back to Article

Listing Two

String url = "serversocket://:9191";
public MessageThread() {
  try {
    scn = (StreamConnectionNotifier)Connector.open(url);
  }
  catch (IOException e) {
  }
}

Back to Article

Listing Three

(a)

String url = "http://localhost/J2MEBOOK/servlet/CountServlet";

(b)
<pre>conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty("User-Agent", 
  "Profile/MIDP-1.0 Configuration/CLDC-1.0");
conn.setRequestProperty("Content-type", 
  "application/x-www-form-urlencoded");







Back to Article


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video