Showing posts with label HTTP. Show all posts
Showing posts with label HTTP. Show all posts

Tuesday, March 13, 2012

A J2ME Library and a simple HTTP Service Framework

A J2ME Library and a simple HTTP Service Framework

 J2ME's support for calling a server is rather simple and low level. Not only do you have to deal with the HTTP Connection at a low level, there is no high level support for cookies, authentication or remote procedure calling. So if you want to pass an object to the server and get a response, you need to figure out how to do that. XML over HTTP is one solution, but presents its own problems like the serialisation and deserialisation of objects, not to mention higher network traffic because of the meta-data held within the XML. JAX Binding is certainly not supported in J2ME-land which results in you having to use a SAX parser.

In previous projects I have toyed with a simple way of providing services over JSPs, which take and receive delimited text. The idea is to implement your own simple serialization and deserialisation of simple objects allowing you to make simple calls to the server and receive simple responses. I purposefully used the word "simple" four times in that last sentence to impress upon you the idea that server calls should be kept simple.

Take for example a J2ME application which tracks a GPS location. To send the location of the user it can simply send a line of text like this:

    006.574438|045.453345|11022344843373

What's it mean?

    longitude | latitude | timestamp

The serialising and deserialising of the data is VERY simple using a StringTokenizer (erm, which doesn't exist in J2ME, so see later!). And the server could respond with a simply OK or it might want to take the opportunity to update the client with some traffic information:

 M4|4|6|20|Accident

which means:

    road | from junction | to junction | how many minutes delay | reason

Most server calls really can be that simple, especially when being involved in J2ME applications which tend to be relatively simple themselves.

So the above presents a few questions... How secure is the data and how do you know who the update is coming from? Well the data should be sent over SSL to ensure that its secure and if the data is sent over an authenticated session, then the server knows who the logged in user is. But to get a log in and session to work, you need two things, namely cookies (for the session ID to be passed between client and server) and some form of authentication. Cookies in J2ME aren't too easy to handle since there is no built in API for handling them at a high level. You can set a cookie in the request header, but storing cookies from responses is the hard part. I implemented rudimentary cookie handling by sending the response to a method which checks for any set-cookie headers and adds them to the cache as well as cleaning out expired entries. When a request is sent, I call a method which adds all relevant cookies to the request header. I have not implemented the RfC for cookies and don't handle the differences between Cookie and Cookie2. In fact I didn't even go as far as checking the path of the cookie before sending it to the server, because in my environment, it's not even relevant. A proper cookie implementation would need to do those things and more, and perhaps one day, such a library will exist.. I did manage to find this which refers to the JCookie sourceforge project and J2ME, but checking out its site I couldn't find anything that would work with J2ME.

HTTP authentication I originally handled by adding the "authorization" request header and applying a Base64 encoded basic authentication string to it. This caused its own problems, because J2ME doesn't have a Base64 encoder out of the box. Luckily the org.apache.common.codecs.binary.Base64 class works (which I took from the Apache Codecs 1.3 library. It depends upon the following classes which are in the distributable JAR and also J2ME compatible: BinaryDecoder, BinaryEncoder, Decoder, DecoderException, Encoder, EncoderException, all found in the org.apache.commons.codec package.

I ran into a different problem when I wanted my web application for the web site to be the same as the web application for my services. Namely, for services I wanted to use basic authentication and for the web site I wanted to use form login. The servlet spec doesn't let you define more than one login-config per web-app! So the J2ME class I had written for accessing services (ServerCaller) had to be extended, but that wasn't hard. When a web application using Form Login needs you to authenticate, it simply returns the login form instead of the expected response. If you parse the response and check to see if it is your login form, and then simply submit that form with your username and password, the server then logs you in and returns a 302 code telling you to call the original page again. Assuming you provided the correct login credentials, it all works. So my class recursed into itself if it spotted the login form and that was enough to make it work transparently.

The next problem was the parsing of the responses in order to deserialise them. For this I created a very simple StringTokenizer, since neither CLDC nor MIDP gives you one :-( The implementation is below.

URL encoding and decoding is also important because request parameters (for a GET its the request string, for a POST the request body). Luckily there are some options out there. Catalina has one in its util package, which almost works for J2ME. So I did a quick fix to it to remove the dependency on java.util.BitSet which also doesn't exist in J2ME.

So, finally to some code! The magic class is the ServerCaller which you can download below. It is abstract and to use it you simply need to extend it, for example: 

package uk.co.maxant.cam.c;

import java.util.Vector;

import uk.co.maxant.cam.m.MasterData;
import uk.co.maxant.j2me.core.CredentialsProvider;
import uk.co.maxant.j2me.core.ServerCaller;
import uk.co.maxant.j2me.core.StringTokenizer;

/**
 * calls the server to get master data like roles and the version of the latest available download.
 */
public abstract class MasterDataGetter extends ServerCaller implements ServerCaller.Listener {

 private ExceptionHandler eh;
 
 public MasterDataGetter(CredentialsProvider credentialsProvider, ExceptionHandler eh) {
  super(credentialsProvider, Constants.getBaseUrl(), "ota/getMasterData.jsp");
  this.eh = eh;
  setListener(this);
 }
 
 public void callServer(){
  properties.clear();
  properties.put("installUid", String.valueOf(InstallHelper.getInstallationUid(eh)));

  doCallAsync();
 }
 
 protected void handleSuccess(String str) {
  StringTokenizer lines = new StringTokenizer(str, "|");
  String version = lines.nextToken().trim();
  String sessionId = lines.nextToken().trim();
  String screenName = lines.nextToken().trim();
  String roles = lines.nextToken().trim();
  StringTokenizer rs = new StringTokenizer(roles, ",");
  Vector rolesv = new Vector();
  while(rs.hasMoreTokens()){
   rolesv.addElement(rs.nextToken());
  }
  
  String s = lines.nextToken().trim();
  boolean isSendDebugLog = s.equalsIgnoreCase("true");
  
  MasterData masterData = new MasterData(version, rolesv, sessionId, screenName, isSendDebugLog);
  onSuccess(masterData );
 }
 
}

An example of a JSP for the server is:  








 //we know who they are. if the installUid is known, lets add it to their profile!
 String installUid = request.getParameter("installUid");
 if(installUid != null && installUid.equals("null")) installUid = null;

 String auth = request.getHeader("authorization");

 OrchestrationService os = ServiceLocator.getInstance().getOrchestrationService();
 MasterData md = os.getMasterData(auth, installUid);
 if(md.party != null) user = md.party.getScreenname();
 for(String role : md.roles){
  roles += role + ",";
 }
 String version = VersionHelper.getVersionFromJad(request);
 
 boolean sendDebugLog = true; //change to false if we get swamped. but really, we shouldnt ever get this stuff.
 
 %>OK
 <%=version%>|
 <%=session.getId()%>|
 <%=user%>|
 <%=roles%>|
 <%=sendDebugLog%>|
 <%
}catch(Exception e){
 log.warn("failed to read master data", e);
 %>ERROR
 <%=e.getMessage() %>
 <%
}
%>
The result, is the maxant J2ME library, which runs on CLDC 1.1 and MIDP 2.0, and can be downloaded here. It includes classes for all of the following, and more, and is released under the LGPL Licence:


  • URLEncoder - from Apache Catalina
  • Base64 - from Apache Commons Codec
  • CredentialsProvider - an interface which the ServerCaller uses to get server credentials for logging in
  • Formatter - formats for example decimals nicely
  • GAUploader - loads an event to Google Analytics
  • Math - some math stuff thats not in CLDC
  • Point - a 2 dimensional point in a plane
  • ServerCaller - a high level API for calling a server, as described above
  • StringTokenizer - simple, and a lot like that from J2SE
  • URL - an encapsulation of a protocol, domain, port and page
  • ImageHelper - code taken from the web for scaling images
  • DirectoryChooser - a UI for choosing a local directory on the device
  • FileChooser - a UI for choosing a local file on the device


To use the library, add it to the "lib" folder of your J2ME project, then ensure its on the build path, and in Eclipse Pulsar, you need to also check the box in the build path on the last tab, to ensure the classes in the JAR are exported to your JADs JAR.

Link: http://blog.maxant.co.uk/pebble/2010/02/21/1266791340000.html

Sunday, March 4, 2012

Sending HTTP Requests from a Wireless J2ME Device

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




  • 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. 

    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.
    
    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.

    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.
    
    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.


    Wednesday, February 29, 2012

    Sending HTTP Requests from a Wireless J2ME Device

    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.
    s 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.



    How can a J2ME client send HTTP requests to a Web server or similar HTTP-enabled network server?



    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




  • 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.
    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.
    
    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.
    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.
    
    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.

    Editor's Note: Thanks to DevX reader Marc Palmer for technical assistance.
    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.

    DevX Java Pro Kyle Gabhart is a consultant for Objective Solutions, a high-end engineering services company focusing on the medical, semiconductor, and telecommunications domains. He is an Associate Member of the Worldwide Institute of Software Architects (WWISA), an organization dedicated to promoting and enriching software architecture as a profession. Kyle is a co-author of "Professional Java and XML".