Tuesday, August 22, 2006

J2ME and Mappoint integration

I happened to read a very good article by Michael Yuan, titled: Let the mobile games begin. It is a pretty old article actually, but contains a nice comparison of J2ME and .Net CF platforms for mobile application development. One example in this article is about using Microsoft's Mappoint web service for getting directions, routes and maps for desired locations, thus providing location based services from the convenience of a mobile phone.

I decided to try it out, with my basic knowledge of J2ME and especially about web services support in J2ME. As described in the article, I did the following:

1. Generated Java stubs using WSDL2Java tool of Apache Axis from the Mappoint Staging WSDL (available at http://staging.mappoint.net/standard-30/mappoint.wsdl
2. Wrote a wrapper class MappointClient that used these stubs to invoke the Mappoint web service
3. Exposed this wrapper class as a web service on Apache Axis (This is a nice idea actually that helps save a lot of wireless bandwidth and time. Explained well in the article. This wrapper class serves as a facade, which in turn makes multiple calls to the Mappoint web service to get the required information, over the relatively faster wired network).
4. Used custom Axis HTTP Connection handler that supports digest authentication (required by Mappoint web service, but not supported by default by Axis, again explained well in the article)
5. Used a third party library ksoap to invoke the facade web service from a J2ME MIDlet.

Well, you will think that things should just work fine, since they are explained so well in the article.. Yes - they should have, but they did not.

When I ran the whole set up, and invoked the facade web service from my J2ME MIDlet using ksoap, I got the following exception, that made no sense to me for a very long time:

Server redirected too many times (20)

To debug the problem then, I added a few debug statements to the custom HTTP Connection handler to check out the values of the HTTP headers. I realized that I was getting a text/html response back, where as I should have been getting a text/xml content in the response. On digging a little deeper, I figured that I was getting a Proxy-Authenticate header in the response with the following HTTP status code:

407 Proxy Authentication Required

Thus, this clearly was a proxy server issue. My machine was behind my company's firewall, and something was going wrong with the proxy settings.

First Try:

I set the system properties: http.proxyHost, http.proxyPort, http.proxyUser and http.proxyPassword to the correct values.

Did not work.

Second Try:

May be, my tomcat server was not picking up the System properties, hence I explicitly passed these values as runtime parameters to Tomcat. (In Tomcat 5.5, you do this by opening the Java tab and specifying the runtime parameters)

This did not work either.

Third and a successful try:

Stumbled upon this link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html that explained the meaning of the various HTTP status codes.

The explanation of error code 407, as given in the site mentioned above:

"Indicates that the client must first authenticate itself with the proxy. The proxy MUST return a Proxy-Authenticate header field containing a challenge applicable to the proxy for the requested resource. The client MAY repeat the request with a suitable Proxy-Authorization header field."

So, this clearly was how the proxy server was behaving in my case. I included a small fix given below in the custom HTTPConnection handler's writeConnection method:

String userPassword = "username:password";
String encoded = Base64Coder.encode(userPassword);
conn.setRequestProperty("Proxy-Authorization", "Basic "+encoded);

Tested with:
1. Apache Axis 1.2 (but should work just fine with Axis 1.4)
2. J2ME: CLDC 1.1 and MIDP 2.0
3. ksoap for web services support
4. Tomcat 5.5

It was fun doing this exercise. Learnt quite a few things and in the end got a nice looking, impressing J2ME MIDlet up and running - one which shows turn by turn directions given the start and end locations and shows a nice map with the route highlighted :-)

No comments: