This article is the final piece in the four-part J2ME 101 series, which consists of a two-part tutorial and two follow-up articles. In this last installment, we'll explore network communication on MIDP, using the Generic Connection Framework (GCF).
As in the previous content in this series, we'll start with the basics (in this case, how to open a connection to a remote resource), but quickly move into more complex territory. Our first MIDlet will demonstrate how to download and display an image that is stored on a server; our second one will use an HTTP connection to download and display a text file from a server; and our final MIDlet will get you started with passing date and time parameters to a servlet.
Please note that this article assumes that you are familiar with MIDlet development in the J2ME environment. You will need to have a J2ME development environment installed on your system in order to compile the code examples. See the Resources section for links to the first three installments in the J2ME 101 series, as well as installation instructions for the J2ME Wireless Toolkit (WTK).
GCF is a set of interfaces defined within the javax.microedition.io package. Figure 1 shows the GCF class hierarchy.
Figure 1. Class hierarchy of the Generic Connection Framework

A total of seven interfaces are defined in GCF, with Connection at the root. Notice that both
datagram (packet) and stream connections are supported. As you would assume, working your way down the hierarchy you'll find interfaces that provide additional functionality. For example, StreamConnection supports both input and output streams, and ContentConnection extends StreamConnection with support for determining the content type, data length, and encoding format of a stream.
The Connector class is used to open every type of connection in GCF. Here you can see the format for the open() method inside the Connector class:
Connector.Open("protocol:address;parameters");
GCF is exceptionally flexible in its support for different connection protocols. When a request is made to open a connection, the Connector class uses its Class.forName() method to search for a class that implements the requested protocol. If found, an object is returned that implements the Connection interface, as shown in Figure 1.
In Listing 1, you can see the code to open various connection types.
Listing 1. Opening various connection types
Connector.Open("socket://www.corej2me.com.com:55");
Connector.Open("http://www.corej2me.com");
Connector.Open("datagram://www.corej2me.com:1000");
Connector.Open("file://makefile.txt");
|
GCF has a total of seven methods for creating a connection. All of them are shown in Listing 2.
Listing 2. Seven methods to create a connection
Connector (public class Connector) public static Connection open(String name) public static Connection open(String name) public static Connection open(String name, int mode, boolean timeouts) public static DataInputStream openDataInputStream(String name) public static DataOutputStream openDataOutputStream(String name) public static InputStream openInputStream(String name) public static OutputStream openOutputStream(String name) |
Listing 3 illustrates one way to open a connection and read data through a stream.
Listing 3. One way to open a connection
// Create a ContentConnection
String url = "http://www.corej2me.com"
ContentConnection connection = (ContentConnection) Connector.open(url);
// With the connection, open a stream
InputStream iStrm = connection.openInputStream();
// ContentConnection includes a length method
int length = (int) connection.getLength();
if (length != -1)
{
byte imageData[] = new byte[length];
// Read the data into an array
iStrm.read(imageData);
}
|
The ContentConnection class isn't the only option we have for creating a connection. We could
also choose to create an InputStream directly. In Listing 4, you can see what might happen if we needed to download an image over a network connection and create an Image based on the downloaded contents.
Listing 4. Creating an input stream directly
InputStream iStrm = (InputStream) Connector.openInputStream(url);
Image img = null;
try
{
ByteArrayOutputStream bStrm = new ByteArrayOutputStream();
int ch;
while ((ch = iStrm.read()) != -1)
bStrm.write(ch);
// Place into image array
byte imageData[] = bStrm.toByteArray();
// Create the image from the byte array
img = Image.createImage(imageData, 0, imageData.length);
}
finally
{
// Clean up
if (iStrm != null)
iStrm.close();
}
|
As you may have noticed, bypassing the ContentConnection leaves us no method to
determine the length of the incoming data. This isn't much of a problem, however, because we can use the ByteArrayOutputStream to read and transfer the data to our destination array.
Let's write a short MIDlet that builds on the code shown in Listing 4. The DownloadImage MIDlet will demonstrate the steps to download and display an image in an MIDP application. The MIDlet will use a ByteArrayOutputStream to download the remote data and then display the resulting image on a Form using an ImageItem.
Take a look at the complete code for the DownloadImage MIDlet and then we'll discuss it in more detail.
Once the MIDlet is running the main user interface should appear in your WTK device emulator, as shown in the figures below. Figure 2 shows a TextBox that prompts for the URL of image. Clicking the View command initiates the download.
Figure 2. A textbox displaying a URL prompt

Once the image is received it is displayed on the device as shown in Figure 3.
Figure 3. An example image display screen

Now that you've seen how GCF supports various types of connections and we've developed our first networking MIDlet, it's time to take a closer look at HTTP support in MIDP. We'll start with an updated hierarchy diagram that indicates which class provides support for HTTP connections.
Figure 4. GCF class support for HTTP

The original MIDP 1.0 specification only required that devices support the HTTP connection protocol, whereas the more recent MIDP 2.0 spec requires support for both HTTP and HTTPS, with the latter offering support for more secure network connections. The APIs to work with these protocols are HttpConnection and HttpConnections, respectively. In addition to these mandated protocols, a device manufacturer can choose to support additional communication protocols such as datagrams or sockets. While at times convenient, you should know that using vendor-specific protocols could affect your application's portability to other devices.
Request and response protocols
Both HTTP and HTTPS are request/response protocols. A client sends a request and a server sends a response. We'll look at the stages of both the client request and the server response before we move on.
The client request, sometimes called the request entity, consists of the following three sections:
- Request method
- Header
- Body
We'll look at each of these sections in some detail.
Request method
The request method determines how data will be sent to a remote resource. The three methods available are GET, POST, and HEADER. When using GET, data is sent as part of the URL. With POST, any client data is sent in a separate stream, distinct from the request to establish a connection. HEADER requests do not send any data to a server. Instead, HEADER requests only meta information about the remote resource.
Listing 5 shows how we would open an HTTP connection with a specified request method of GET, passing a parameter with the name size and a value of large.
Listing 5. Opening an HTTP connection with GET
String url = "http://www.corej2me.com?size=large"; HttpConnection http = null; http = (HttpConnection) Connector.open(url); http.setRequestMethod(HttpConnection.GET); |
Header
Header fields let us pass parameters, if you will, from the client to the server. Common fields are If-Modified-Since, Accept, and User Agent. You set header fields as key-value pairs, using the setRequestProperty() method. Listing 6 shows a header request specifying that only data that has been modified since November 11, 2003 be sent back from the server.
Listing 6. A typical header request
String url = "http://www.corej2me.com\somefile.txt";
HttpConnection http = null;
http = (HttpConnection) Connector.open(url);
http.setRequestMethod(HttpConnection.GET);
// Set header field as key-value pair
http.setRequestProperty("If-Modified-Since", "Mon, 12 Jan 2004 12:00:00 GMT");
|
Body
The body contains the actual content that you would like to send from the client to the server. For instance,
Listing 7 shows how to specify the POST request method and send client data over a stream.
Listing 7. Sending data over a stream
String url = "http://www.corej2me.com",
tmp = "test data here";
OutputStream ostrm = null;
HttpConnection http = null;
http = (HttpConnection) Connector.open(url);
http.setRequestMethod(HttpConnection.POST);
// Send client body
ostrm = http.openOutputStream();
byte bytes[] = tmp.getBytes();
for(int i = 0; i < bytes.length; i++)
{
os.write(bytes[i]);
}
os.flush();
|
Oftentimes you will not need to specify any additional information beyond the request method and header fields. If you do need to specify additional information you will include the data in the body.
After the server has received and processed the client request, it must package and send a response. As with the client request, three sections are associated with the server response:
- Status line
- Header
- Body
Status line
As the name implies, the server status line informs the client of the outcome of its request. HTTP classifies the status line codes into the following broad categories:
- 1xx is informational
- 2xx is success
- 3xx is redirection
- 4xx is client error
- 5xx is server error
The server status line includes the protocol version number running on the server, the status code, and a text message representing the return code. Below are several examples of valid status lines:
- "HTTP/1.1 200 OK"
- "HTTP/1.1 400 Bad Request"
- "HTTP/1.1 500 Internal Server Error"
Header
Not unlike the client, the server can send information through header fields. Three of the most common methods for retrieving header information sent from a server are shown in Listing 8.
Listing 8. Three common getHeaderField methods
String getHeaderField(int n) Get header field value looking up by index String getHeaderField(String name) Get header field value looking up by name String getHeaderFieldKey(int n) Get header field key using index |
A server could potentially return more than one header field. In this case, the first method would obtain the value of the header field by specifying its index in the result set and the next one would retrieve a header field value by looking up its key by name. Should you need to get the header field key, you could pass a parameter to the final method representing the index of the entry in the result set you were interested in.
Table 1 shows what each of the three methods in Listing 8 would return if the response in a server header contained the content "content-type=text/plain". Assume for this example that the server results set contains only one entry.
Table 1. Retrieving header field contents
| Method | Return value |
http.getHeaderField(0) | "text-plain" |
http.getHeaderField("content-type") | "text-plain" |
http.getHeaderFieldKey(0) | "content-type" |
Body
Like the client, the server sends the bulk of information in the body of its response. Along similar lines as
Listing 7 (which shows a client sending its body through an output stream), the client would read the server response using an input stream.
As previously mentioned, we use the HttpConnection API to establish connections on MIDP. Table 2 shows all the methods available in the HttpConnection class.
Table 2. All the HttpConnection methods
| Method | Description |
long getDate() | Get header field date |
long getExpiration() | Gets header field expiration |
String getFile()> | Gets filename from the URL |
int getHeaderField(int n) | Gets header field value looking up by index |
String getHeaderField(String name) | Gets header field value looking up by name |
long getHeaderFieldDate(String name, long def) | Gets named field as a long (representing the date) |
int getHeaderFieldInt(String name, int def) | Gets named field as an integer |
String getHeaderFieldKey(int n) | Gets header field key using index |
String getHost() | Gets host from the URL |
long getLastModified() | Gets last-modified field value |
String getPort() | Gets port from the URL |
String getProtocol() | Gets protocol from the URL |
String getQuery() | Gets the query string (only valid with GET request) |
String getRef() | Gets the reference portion of URL |
String getRequestMethod() | Gets the current setting of the request method (GET, POST or HEAD) |
String getRequestProperty(String key) | Gets the current setting of a request property |
int getResponseCode() | Gets the response code (numeric value) |
String getResponseMessage() | Gets the response message (text value) |
String getURL() | Gets the entire URL |
void setRequestMethod(String method) | Sets the request method (GET, POST or HEAD) |
void setRequestProperty(String key, String value) | Sets a request property (header information) |
Our next MIDlet will use an HttpConnection to download and view the contents of a text file. This short example will give you some insight into how we send client information and interpret a server response. The
MIDlet also includes calls to various methods within the HttpConnection class, which help us to gather information about the host server, the port, and the content type returned.
Take a look at the complete code for the FileViewer MIDlet and then we'll discuss it in more detail.
Now, let's view the output of our MIDlet. The left screen shot in Figure 5 shows the interface upon startup. After you select the View command, the file will be downloaded and displayed on the device, as shown on the right screen shot in Figure 5.
Figure 5. Starting up

Figure 6 shows the fields returned from the server, with the values written to the console.
Figure 6. FileViewer's console output

Note that the status line (message and code) and all the header field key-value pairs are displayed. HttpConnection also includes the methods shown in Listing 9 to obtain server information, including the host, port, and content type returned. These values for the FileViewer MIDlet are shown near the bottom of Figure 6.
Listing 9. Methods to obtain server information
String getHost() String getPort() String getType() |
We're going to develop one last MIDlet together before we close the J2ME 101 series. The DateFormat MIDlet (see the complete source code) will demonstrate the steps necessary to access a Java servlet from within a MIDlet. This is a fairly complex operation compared to the others you've learned so far, but we'll walk through it together in the sections that follow.
We'll start by passing parameters to a servlet requesting a specified date and time format to be returned. The servlet will create a properly formatted string based on the parameters and send the result to the client, where it will be displayed on the WTK device emulator. Table 3 lists the available parameters and their meanings, along with a brief example.
Table 3. Servlet parameters
| Symbol | Meaning | Example |
G | Era designator | AD |
y | Year | 1996 |
M | Month in year | 07 |
d | Day in month | 10 |
h | Hour in am/pm (1~12) | 12 |
H | Hour in day (0~23) | 0 |
m | Minute in hour | 30 |
s | Second in minute | 55 |
S | Millisecond | 978 |
E | Day in week | Tuesday |
D | Day in year | 189 |
F | Day of week in month | 2 (2nd Wed in July) |
w | Week in year | 27 |
W | Week in month | 2 |
a | am/pm marker | PM |
k | Hour in day (1~24) | 24 |
K | Hour in am/pm (0~11) | 0 |
z | Time zone | Pacific Standard Time |
' | Escape character for text | 'at' |
'' | Display single quote | ' |
Figures 7 and 8 show two properly formatted parameters and the results returned from the servlet.
Figure 7. Results for the format string yyyy.MM.dd+'at'+hh:mm:ss+zzz"

Figure 8. Results for the format string MMMM.dd.yyyy+'-'+hh:mm+aa"

The servlet is hosted at http://www.mycgiserver.com. This is a free hosting service based in Austria, so you shouldn't be surprised if the date format isn't familiar to your native language. For example, in Figure 7, the time zone is shown as CET, Central European Time, which we requested by specifying a time zone parameter of "zzz". However, if we change the time zone parameter to "zzzz" to get the full-text version of the time zone, the output may no longer be what you expect, as shown in Figure 9.
Figure 9. Results for the format string yyyy.MM.dd+'at'+hh:mm:ss+zzzz"

The request to call a servlet begins inside the commandAction() method when the command cmRqst is invoked, as shown in Listing 10.
Listing 10. Event handling
/*--------------------------------------------------
* Call the servlet
*-------------------------------------------------*/
public void commandAction(Command c, Displayable s)
{
if (c == cmRqst)
{
try
{
serverMsg = null;
callServlet();
if (serverMsg != null)
fmMain.append(serverMsg);
}
catch (Exception e)
{
System.err.println("Msg: " + e.toString());
}
}
else if (c == cmExit)
{
destroyApp(false);
notifyDestroyed();
}
}
|
The code for callServlet is shown in Listing 11. Notice the code for the client side consists only of setting the request method to GET. No header or body information is necessary for this MIDlet. You'll learn how to interpret the server response in just a moment from Listing 11 below.
Listing 11: Calling a servlet and processing the response
/*--------------------------------------------------
* Call the servlet
*-------------------------------------------------*/
private void callServlet() throws IOException
{
HttpConnection http = null;
InputStream iStrm = null;
boolean ret = false;
// Examples - Data is passed at the end of url for GET
String url = "http://www.mycgiserver.com/servlet/corej2me.DateFormatServlet?
format=MMMM.dd.yyyy+'-'+hh:mm+aa";
// String url = "http://www.mycgiserver.com/servlet/corej2me.DateFormatServlet?
// format=yyyy.MM.dd+'at'+hh:mm:ss+zzz";
try
{
http = (HttpConnection) Connector.open(url);
//----------------
// Client Request
//----------------
// 1) Send request method
http.setRequestMethod(HttpConnection.GET);
// 2) Send header information - none
// 3) Send body/data - data is at the end of URL
//----------------
// Server Response
//----------------
iStrm = http.openInputStream();
// Three steps are processed in this method call
ret = processServerResponse(http, iStrm);
}
finally
{
// Clean up
if (iStrm != null)
iStrm.close();
if (http != null)
http.close();
}
// Process request failed, show alert
if (ret == false)
showAlert(errorMsg);
}
|
The two lines of code that specify the URL show how to call our DateFormatServlet servlet from within the MIDlet. Simply
looking at how the servlet is invoked gives us a hint that we will be using a GET request method, because all parameters are passed as part of the URL rather than being sent in a separate stream.
In Listing 12 you can see how we pass a parameter with the name format from the client to the server. The servlet will extract the value of this parameter to determine how to format the requested date.
Listing 12. Passing a format parameter
http://www.mycgiserver.com/servlet/corej2me.DateFormatServlet?format= MMMM.dd.yyyy+'-'+hh:mm+aa; http://www.mycgiserver.com/servlet/corej2me.DateFormatServlet?format= yyyy.MM.dd+'at'+hh:mm:ss+zzz; |
The servlet code is quite trivial. The bulk of what we are after is inside the method doPost(). We first store the format requested by the client in the variable format. Next, we call SimpleDateFormat to create an instance of our preferred date formatting object and follow this with a call to create a new Date object. We create a PrintWriter object as our output stream, set the content type to text/html and output the date in the requested format, as shown in Listing 13.
Listing 13. The servlet code
package corej2me;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.Locale;
public class DateFormatServlet extends HttpServlet
{
public void init(ServletConfig config) throws ServletException
{
super.init(config);
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String format = request.getParameter("format");
SimpleDateFormat simpleDate = new SimpleDateFormat(format);
Date dt = new Date();
PrintWriter out = response.getWriter();
response.setContentType("text/html");
out.println(simpleDate.format(dt));
out.close();
}
public String getServletInfo()
{
return "DateFormatServlet";
}
}
|
The code for interpreting the server response is shown in Listing 14. The first check is to determine if the status line indicates the client request was successfully processed and a result returned (HTTP_OK). There is no header information, so we move directly to reading the server data from an input stream, storing the results in the variable serverMsg.
Listing 14. Parsing the servlet results
/*--------------------------------------------------
* Process a response from a server
*-------------------------------------------------*/
private boolean processServerResponse(HttpConnection http, InputStream iStrm)
throws IOException
{
//Reset error message
errorMsg = null;
// 1) Get status Line
if (http.getResponseCode() == HttpConnection.HTTP_OK)
{
// 2) Get header information - none
// 3) Get body (data)
int length = (int) http.getLength();
String str;
if (length != -1)
{
byte servletData[] = new byte[length];
iStrm.read(servletData);
str = new String(servletData);
}
else // Length not available...
{
ByteArrayOutputStream bStrm = new ByteArrayOutputStream();
int ch;
while ((ch = iStrm.read()) != -1)
bStrm.write(ch);
str = new String(bStrm.toByteArray());
bStrm.close();
}
// Save the server message
serverMsg = str;
return true;
}
else
// Use message from the servlet
errorMsg = new String( http.getResponseMessage());
return false;
}
|
For our next step we need to head back to the code inside commandAction(). After a successful call to callServlet() we append the saved string returned from the server onto the Form (our primary user interface component), which in turn displays the results on the device, as shown in Listing 15.
Listing 15. A closer look at commandAction()
/*--------------------------------------------------
* Call the servlet
*-------------------------------------------------*/
public void commandAction(Command c, Displayable s)
{
if (c == cmRqst)
{
try
{
serverMsg = null;
callServlet();
if (serverMsg != null)
fmMain.append(serverMsg);
}
...
}
|
Again, here's the complete source code for the DateFormat MIDlet.
In this final article in the J2ME 101 series, you've had a chance to explore network communication support in MIDP. We began with an introduction to the Generic Connection Framework, the foundation for creating networked applications in MIDP. This was followed by a discussion of HTTP support, including how to package a client request, as well as interpret a server response. To demonstrate the concepts presented up to this point, we wrote a file-viewer MIDlet that downloaded and displayed a text file.
In the final section of this article we wrote a comprehensive MIDlet to access a Java servlet. This included a broad range of network communication operations, such as passing parameters to the servlet, interpreting and processing the parameters on the server side and, finally, retrieving and displaying the server response on the client.
In this four-part series, we've had a chance to take a close look at all the primary components of MIDP, namely, high-level and low-level user interface components, persistent storage, and network support. With the completion of this comprehensive overview, you now have a baseline of information to begin exploring and developing your own J2ME applications!
- Download the J2ME Wireless Toolkit version 2.0.
- Don't miss the other content in the J2ME 101 series:
- Part 1 provides an introduction to the MIDP high-level interface.
- Part 2 details MIDP s low-level interface.
- Part 3 goes inside the Record Management System.
- If you are new to the Wireless Toolkit, "MIDlet
development with the Wireless Toolkit" (developerWorks, March 2003) provides an excellent starting point for learning to use it.
- "Extend J2ME to Wireless Messaging" (developerWorks, February 2003) explores Short Message Service (SMS) and Cell Broadcast Service (CBS)
message support in J2ME.
- Learn more about getting Java applications to network on small devices, with Soma Ghosh's "Networking with J2ME" (developerWorks, September 2002).
- Keep on learning about J2ME, with the latest tutorial, "Work with sprites in J2ME" (developerWorks, December 2003), where you'll learn how
to spice up your applications with more complex, malleable images.
- The KVM mailing list is an excellent resource for J2ME developers, offering a searchable archive and an active email discussion area.
- Sun Microsystems CLDC
and MIDP wireless forum lets you post questions and search for J2ME-related information.
- Core J2ME (Prentice Hall PTR, 2002) by John W. Muchow is a comprehensive guide to J2ME development. You can also visit the Core J2ME Web site for additional articles, tutorials and developer resources.
- The WebSphere Micro Environment provides an end-to-end solution connecting cellular phones, PDAs, and other pervasive devices to e-business.
- The alphaWorks Web Services Toolkit for Mobile Devices provides
tools and a runtime environments for developing applications that use Web services on small mobile devices, gateway
devices, and intelligent controllers.
- Visit www.timeanddate.com
for additional information about the CET and CEST time zones.
- The official PNG Web site will get you started with learning about the Portable Network Graphics image format.
- The developerWorks Wireless zone
offers a wealth of technical content on pervasive computing.
- You'll find hundreds of articles about every aspect of Java programming in the developerWorks Java technology zone.
- Also see the Java
technology zone tutorials page for a complete listing of free tutorials from developerWorks.
John Muchow, author of Core J2ME technology and MIDP, is a freelance technical writer and developer, with extensive experience in J2ME, Java technology, JSP, C, and ColdFusion. Visit Core J2ME for additional source code, articles, and developer resources. Send John an e-mail for additional information about writing or software development projects.
Comments (Undergoing maintenance)





