Sending HTTP Requests from a Wireless J2ME Device
Learn to use the J2ME networking classes found in the javax. microedition.io package to send HTTP requests to a Web server or similar HTTP-enabled network server.
As more and more cellular phones and PDAs
begin to merge onto the information superhighway, it becomes
increasingly interesting to access Web sites from mobile devices. Since
Java was initially created for consumer appliances with a small memory
footprint, it is the perfect language for developing applications for
phones, pagers, and other micro devices.
In this 10-Minute Solution, we will learn how to send an HTTP GET
request and an HTTP POST request to a server from a J2ME client.
Although this is a rather introductory discussion, it is assumed that
the reader is accustomed to working with Java, J2ME, and Java midlets
(MIDP applications). We will use the MIDP profile for J2ME and compile,
deploy, and test our application using Sun's J2ME Wireless Toolkit.
For the HTTP server, any WWW address may be accessed, but by default we
will use a simple Java servlet that will return the details about our
HTTP request.
The Problem
How can a J2ME client send HTTP requests to a Web server or similar HTTP-enabled network server?
The Solution
Using the Java 2 Micro Edition networking classes found in the javax.microedition.io package.
Overview:
Wireless Network Programming with J2ME
Sending an HTTP GET Request
Sending an HTTP POST Request
The networking capabilities of Java are quite robust. The Java 2 Standard Edition (J2SE) defines well over 100 interfaces, classes, and exceptions between the java.io and java.net packages. The functionality made available through these libraries is great for traditional computer systems with substantial CPU power, active memory, and persistent data storage, but not for most wireless devices. Consequently, the Java 2 Micro Edition (J2ME) defines a subset of this functionality and provides a consolidated package for networking and file access—the javax.microedition.io package. Due to the wide variety of mobile devices, this package merely defines a set of interfaces, leaving the actual implementation up to each vendor. This provides an optimum balance between portability and the utilization of device specific features.
The abstract networking and file I/O framework defined by the
javax.microedition.io classes are referred to as the Generic Connection
Framework (GCF). The GCF defines a set of related abstractions to
represent different communication methods. The top-level abstraction is
called Connection, from which six more interfaces are declared (four
direct, and two indirect). These seven interfaces are declared as a part
of J2ME's Connected Limited Device Configuration (CLDC), which is the
configuration used by most Java-enabled wireless devices. This is
designed to provide common networking and file I/O capabilities for all
CLDC devices (cell phones, two-way pagers, low-end PDAs, etc.).
Although the purpose behind the GCF is to provide a common networking and file I/O framework, device manufacturers are not compelled to implement all of the interfaces declared in the GCF. The manufacturer may decide to only support socket connections (used with circuit-switched wireless networks), while others may choose to only support datagram-based communication (used with packet-switched networks). In order to promote portability across similar devices the Mobile Information Device Profile (MIDP) specification requires that all MIDP devices implement the HttpConnection interface. HttpConnection is not part of the GCF, but it does derive from one of the GCF interfaces, ContentConnection. We will use the HttpConnection interface to build our sample application.
Sending an HTTP GET Request
The code that will be explained in this section and the next section will only address the Generic Connection Framework interfaces and the HttpConnection interface used for sending an HTTP request and retrieving the response returned by the server. The code for creating the MIDP user interface can be downloaded at the end of the article.
We will begin by defining a method to house the code for sending an HTTP GET request. Since several of the operations contained in the method can potentially throw an IOException, we will throw such exceptions to the calling method.
Copy the sendHttpGet() method we just created, paste it into the same class file, and rename it to sendHttpPost(). Now we will modify this new method to send an HTTP POST request to the server.
Add two new variable declarations to the top of the method. Declare a variable of type DataOutputStream and declare another variable of type String. We will use the DataOutputStream object to push our POST request body (contained in the String) to the server.
Learn to use the J2ME networking classes found in the javax. microedition.io package to send HTTP requests to a Web server or similar HTTP-enabled network server.
The Problem
How can a J2ME client send HTTP requests to a Web server or similar HTTP-enabled network server?
The Solution
Using the Java 2 Micro Edition networking classes found in the javax.microedition.io package.
Overview:
Wireless Network Programming with J2ME
The networking capabilities of Java are quite robust. The Java 2 Standard Edition (J2SE) defines well over 100 interfaces, classes, and exceptions between the java.io and java.net packages. The functionality made available through these libraries is great for traditional computer systems with substantial CPU power, active memory, and persistent data storage, but not for most wireless devices. Consequently, the Java 2 Micro Edition (J2ME) defines a subset of this functionality and provides a consolidated package for networking and file access—the javax.microedition.io package. Due to the wide variety of mobile devices, this package merely defines a set of interfaces, leaving the actual implementation up to each vendor. This provides an optimum balance between portability and the utilization of device specific features.
Although the purpose behind the GCF is to provide a common networking and file I/O framework, device manufacturers are not compelled to implement all of the interfaces declared in the GCF. The manufacturer may decide to only support socket connections (used with circuit-switched wireless networks), while others may choose to only support datagram-based communication (used with packet-switched networks). In order to promote portability across similar devices the Mobile Information Device Profile (MIDP) specification requires that all MIDP devices implement the HttpConnection interface. HttpConnection is not part of the GCF, but it does derive from one of the GCF interfaces, ContentConnection. We will use the HttpConnection interface to build our sample application.
Sending an HTTP GET Request
The code that will be explained in this section and the next section will only address the Generic Connection Framework interfaces and the HttpConnection interface used for sending an HTTP request and retrieving the response returned by the server. The code for creating the MIDP user interface can be downloaded at the end of the article.
We will begin by defining a method to house the code for sending an HTTP GET request. Since several of the operations contained in the method can potentially throw an IOException, we will throw such exceptions to the calling method.
public String sendHttpGet( String url ) throws IOException {
HttpConnection hcon = null;
DataInputStream dis = null;
StringBuffer message = "";
try {
The first step is to open a connection to the
server using the Connector class, the crux of the GCF. We will then cast
this connection to the specific type needed, in this case the HttpConnection type.
hcon = ( HttpConnection ) Connector.open( url );
Next, we obtain a DataInputStream on our HttpConnection, allowing us to read the server's response data, character by character.
dis = new DataInputStream( hcon.openInputStream() );
Using the read() method of DataInputStream, each character of the server's response is collected and appended to the StringBuffer object.
int ch;
while ( ( ch = dis.read() ) != -1 ) {
message = message.append( ( char ) ch );
}
Finally (no pun intended), the connection objects
are cleaned up to preserve resources, and the message is returned from
the method.
} finally {
if ( hcon != null ) hcon.close();
if ( dis != null ) dis.close();
}//end try/finally
return message.toString();
}//end sendGetRequest( String )
How to Send an HTTP POST Request
As you might imagine, sending an HTTP POST request is a very similar process to sending a GET request. We'll modify one of the existing commands, add a handful of new commands, and add one additional object from the Generic Connection Framework and one additional StringBuffer object to push the content in the POST body to the server. The rest of the commands will remain unchanged.
As you might imagine, sending an HTTP POST request is a very similar process to sending a GET request. We'll modify one of the existing commands, add a handful of new commands, and add one additional object from the Generic Connection Framework and one additional StringBuffer object to push the content in the POST body to the server. The rest of the commands will remain unchanged.
Add two new variable declarations to the top of the method. Declare a variable of type DataOutputStream and declare another variable of type String. We will use the DataOutputStream object to push our POST request body (contained in the String) to the server.
DataOutputStream dos = null;
String requestBody = null;
Modify the Connector.open()
command to include another argument, indicating that the connection
should allow the client to both read and write data to the server over
the connection.
hcon = ( HttpConnection ) Connector.open( url, Connector.READ_WRITE );
Set the request method used by the HttpConnection object to POST (the method is GET by default).
hcon.setRequestMethod( HttpConnection.POST );
Obtain a DataOutputStream object for the existing HTTP connection.
dos = hc.openDataOutputStream();
Declare an array of bytes and initialize that array by retrieving a byte array from the requestBody string. Then write the contents of the byte array to the buffer of the DataOutputStream.
byte[] byteRequest = requestBody.getBytes();
for( int i = 0; i < byteRequest.length; i++ ) {
dos.writeByte(byteRequest[i]);
}//end for( int i = 0; i < byteRequest.length; i++ )
The next line is a bit controversial.
dos.flush(); //Including this line may produce undesiredresults on certain devices
If you call c.flush(), some devices will send
the request in HTTP 1.1 "chunked" encoding by adding a
"Transfer-encoding: chunked" header to the request and writing the size
of each block of data in hexadecimal form as a text line before the data
bytes themselves. This is repeated for any number of blocks you send,
usually demarcated by calls to flush().
If you have a HTTP 1.1-compliant Web server this should be transparent
to your server side scripts, but if you do not, you will either want to
avoid calling flush() (though some devices may
still chunk for you automatically) or write some HTTP 1.1 chunk handling
code in your server scripts. All you will need to do in the latter case
is read the first text line of the response, extract the size from it
(i.e. "C\r\n" where C means 12 bytes of chunk follow), and then read 12
bytes of response data. Then read another line to see if there is
another chunk size, and repeat until stream is closed or your script has
all the data it needs. See the HTTP 1.1 specification for more details.
The rest of the method remains the same, except that the DataOutputStream object must be closed inside the finally{} block.
} finally {
if ( hc != null ) hc.close();
if ( dis != null ) dis.close();
if ( dos != null ) dis.close();
}//end try/finally
That's all there is to it! Remember that you can obtain the full source
code for this HTTP-enabled MIDP application by clicking on the
appropriate link at the end of this article (the bottom of the page).
As Internet-ready and network-enabled wireless devices continue
to grow in popularity, the importance of Java and the Java 2 Micro
Edition will also continue to grow. Since the HTTP protocol is the only
current networking protocol that is supported by all MIDP-compliant
devices, it is the best candidate for developing wireless networked
applications.
In this article we have explored the basic architecture and a few of
the core issues associated with wireless network programming, and we've
seen how to invoke the two most common HTTP request methods, GET and
POST. J2ME is still in its infancy, and wireless devices are very close
to a "tipping point" of popularity. The next few months and years should
be very interesting.
No comments:
Post a Comment