Monday, August 21, 2006

Playing around with J2ME Web Services Optional Package (JSR 172)

Problem at hand:

I have been exploring J2ME for the last few months. One of the things I wanted to do was to check out the J2ME Web Services Optional Package (JSR 172) and write a simple sample POC MIDlet that uses the J2ME Web Service Client APIs to invoke a web service. I had already tried using the third party library ksoap and had been successful at it.

One thing to note about J2ME Web Services Optional Package is that it supports only document/literal type of web services for now. So that meant figuring out how to write a document/literal service using Apache Axis.

The set-up I had at the server side was:
1. Tomcat 5.5
2. Apache Axis 1.2

The set-up at the client side was:
1. Sun Wireless Toolkit for CLDC version 2.5
2. Eclipse 3.2
3. Supported versions: CLDC 1.1 and MIDP 2.0

Server side:

1. Wrote a very simple HelloWorld class in Eclipse, with the following three methods:
   a. String sayHello()
   b. String sayHelloWithTime()
   c. String sayHelloToMe(String me)
2. Exposed this simple HelloWorld class as a web service in Apache Axis 1.2. To make sure the web service is of type document/literal, I made the following settings in the wsdd file (apart from the usual ones): provider="java:RPC" style="document" use="literal"
3. Used to AdminClient tool to deploy the web service onto Axis.

And lo - my web service was deployed and accessible in no time.

Client side:

1. J2ME Web Services Optional Package does not have support for dynamic invocation of a web service (the way ksoap has). Therefore, it is necessary to generate static stubs (which is not that much of a problem really).
2. Sun Wireless Toolkit provides a Stub Generator utility that, given the location of the WSDL file, generates the J2ME client stubs.
3. Once the stub was generated, I wrote a simple MIDlet with only one form to use this stub class (that acts just like a normal local class) to invoke the web service.

Having done all this (of course I had achieved this after having spent some time on the Net), I was expecting things to work fine, although I soon realized that I had just opened a Pandora's box! I kept on hitting problems one after the other, and I kept on solving one at a time. Lately I have realized that I actually enjoy such small struggles, at the end of it they almost invariably give me some sense of an achievement, however small that might be..

OK - so lets see what all came out of the Pandora's box:
1. I kept on getting weird useless exceptions such as: Invalid element in server response, Invalid namespace, found xxx, expected yyy
2. While trying to find some logical explanation to what was happening, my fertile mind came up with the following few conclusions (which obviously proved wrong later):
   a. That Apache Axis Server is generating a different response when the web service is invoked from a J2ME web service client (Yes - so you see, blame it on the JSR 172 implementation!)
   b. The Apache Axis Server is not able to handle methods with the same signature (OK - so if nothing works, I can always pass dummy parameters to have all methods have different signatures, can't I?)
3. Something was definitely going wrong with the response, since I was not getting one that I expected (or rather the one that my stub was expecting), so I decided to use the oh-so-useful SOAPMonitor of Apache Axis.

Enabling the SOAPMonitor:

I enabled the SOAPMonitor by following the steps given here: http://www-scf.usc.edu/~csci571/2006Spring/axisinstall.html

My first conclusion (2 a) was soon proved wrong when I checked out the response I received from the server using both a J2ME and a normal J2SE web service client. In both cases, I was getting a wrong response. To give an example, the response I received was:
<soapenv:Body>
<meReturn xmlns="http://helloworldsample">Hello Arati</meReturn>
</soapenv:Body>

Where as according to the WSDL, I should have got the following: (Note the differences in the element name and the namespace)

<soapenv:Body>
<sayHelloToMeReturn xmlns="http://localhost:8081/axis/services/HelloWorldService">Hello Arati</sayHelloToMeReturn>
</soapenv:Body>

Some desperate attempts to get it working:

1. After cursing Axis 1.2 too much, I moved on to Axis 2. This however, turned out to be a wrong decision - did not really help, Axis 2 has been completed rearchitected, redesigned and I unnecessarily spent almost one day figuring out how to deploy a very simple web service on Axis 2 and then how to enable the SOAPMonitor on it.

2. I posted my queries, my doubts on the J2ME Forums and a few other forums (ex. Artima).

3. Having received no help from there, I moved on to the safe Axis 1.4 version. And then once again started fiddling around with the SOAPMonitor. One thing I realized (which I should have seen earlier) was that the SOAP request itself was not being formatted correctly. For example, on invoking the String sayHelloToMe(String me) method, the SOAP request was as follows:

<soapenv:Body>
<me xmlns="http://helloworldsample">Arati</me>
</soapenv:Body>

Ideally, with my basic knowledge of SOAP, XML et al, I knew that this is wrong. The response should definitely have contained the method name (sayHelloToMe) - how the hell is the Axis server otherwise going to understand which method to invoke?

4. This finally put me on the right track. I then doubted the document/literal support of Axis for the first time (that was a correct doubt) and on reading up a little realized the difference between the style "document" and style "wrapped". Check out this in detail in Axis's user guide at Service styles section

5. I made changes to the wsdd file to use style="wrapped" instead of document style, redeployed the web service, regenerated the stub classes using the stub generator and then checked out the MIDlet once again. This time I had hit the jackpot! The J2ME web service client worked beautifully, and the SOAPMonitor also started showing me expected results!

Well - so after a little fight and desperate searching on the Net for about 2 days (duh - I know I should have got this sooner than this) - I have cracked J2ME Web services + Axis combination, at least for the simple things..

Three cheers for the SOAPMonitor - Hip hip hurray, Hip hip hurray, Hip hip hurray!

3 comments:

Siddhesh said...

I am sure this will be a very useful blog! I like the way you write - so I am definitely going to monitor this one closely :)

Look forward to some cool stuff from you, as always!

Manasee said...

Excellent one! Looking forward for more as good, if not better ones :)

Luks said...

Hey, nicew tutorial. Have you implemented with apache axis 2? It's possible?