SOAP-enabling Mobile Devices with KSOAP-2

A lightweight SOAP client library that's ideal for mobile devices


June 23, 2008
URL:http://www.drdobbs.com/mobile/soap-enabling-mobile-devices-with-ksoap-/208800166

Don MacVittie is technical marketing manager at F5 Networks.


While the explosion of mobile devices has created an unprecedented opportunity for application developers to extend their reach beyond the desktop, the advent of Web Services has provided a handy interface to remote libraries. These two items combined offer the promise of a thin client with high functionality on lightweight platforms.

But the promise is not the reality. Even though Apache Axis 2 is billed as being designed from the ground up to be lighter, in this case lighter is not less filling. The libraries required to run Axis2 on a client are massive considering the space available. Enter KSOAP2, a lightweight SOAP client library that totals about 100K in client-side space requirements when compiled for either JAR or COD format. Utilizing kSOAP2, a six man-month development cycle delivered a stable Blackberry web services application that could be retargeted for any Java ME capable device with a recompile.

Utilizing kSOAP2 is relatively easy once you know a few basic concepts: How to establish a connection, how to send a request, and how to access the objects in a parsed a response.

The first thing necessary -- particularly on the Blackberry platform -- is to build the libraries from source. For our project we did this in the JDE, but it doesn't really matter where you build them. A JAR to COD converter is included with the Blackberry Java Development Environment (JDE) but I don't recommend it primarily because building provides full debug information with source link-in, and some kSOAP errors are just easier to debug by stepping through the parser.

Once the libraries are built-in the environment, create a new project and include all of the libraries -- kSOAP, kXML, kObjects, and XMLPullParser. These are all required for even the simplest of kSOAP calls to work correctly.

kSOAP is lightweight, and as such the library only supports HTTP and HTTPS, both with and without basic authentication.

Connections

The first step is to establish connection parameters to begin communicating with the server the web service is on. There are two possible calls to establish this connection:

HttpTransport httpt = new HttpTransport("http://" + IPorHostname + "Path/To/Webservice/function");
HttpTransportBasicAuth httpt = new HttpTransportBasicAuth("https://" + IPorHostname + "Path/To/Webservice/function", username, password);

In the first case, the connection is made with no authorization, and in the second HTTP Basic Auth is used. The only real difference is that the second call is using HTTPS and it is passed a username and password.

Requests

Once a connection is established, you can format the request and indicate where kSOAP should put the response. All SOAP communications have an envelope that wraps the SOAP request or response. To reflect this, kSOAP uses the SOAP envelope as the top-level object of all requests.

SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);

The valid values of the single parameter are SoapEnvelope.VER10, SoapEnvelope.VER11, and SoapEnvelope.VER12, indicating the use of SOAP 1.0, 1.1, or 1.2.

The next step is to tell kSOAP which operation will be invoked on the endpoint (URL) sent in the call to create the connection.

SoapObject request = new SoapObject("urn:iControl:LocalLB/VirtualServer", "get_list");

The first parameter is the SOAP namespace, and the second is the operation you wish to invoke. In object terms this would be iControl.LocalLB.VirtualServer.get_list(). This is one of the web service operations available on F5's BIG-IP load balancers. Replace the path with the path for your web service.

Then you have to tell kSOAP to use request as the outgoing object:

 
envelope.setOutputSoapObject(request);

If your web service requires parameters, this is where you create them. You can also set miscellaneous parameters for the call The most useful parameter is the debug parameter of the transport object:

httpt.debug = true; 

tells kSOAP to keep a copy of the text input and output buffers so that you can see what was actually sent and received over the SOAP interface.

You can add request parameters using the addProperty method. For example, to set the call parameter vlans to the values in the Vector variable named portList you would use:

request.addProperty("vlans",portList);

Thus the SOAP call will include a complex element named vlans with the values in portList.

The format of the addProperty method is:

addProperty(SOAP Parameter Name, variable or value)

You can use any valid kSOAP object, a Vector, or any Java primitive as the value.

Making the Call

Once all the setup work is complete, the actual call is simple:

httpt.call("", envelope);

That means "make a call to the web service specified in the transport using the information in envelope". If your web service interface had several subinterfaces on it, in theory they could be differentiated with the first parameter, but the implementation of this functionality seems broken, so we send the full path into the constructor for the transport.

That one simple call tells kSOAP to build (serialize) an XML request, send that request to the target specified in the httpTransport object, receive a response, and parse (deserialize) that response into kObject objects.

Parsing the Response

At this point, kSOAP has the response stored as objects in a field of SoapSerializationEnvelope called bodyIn. We need to get that value out so that we can work with it:

 
SoapObject body = (SoapObject)envelope.bodyIn;


The actual response data is represented as properties attached to the bodyIn instance. The best way to access it is to use the index of the return parameter. The first return value is property number 0, and it counts up from there. So if all your web service returned was a list of names, the following code would give you access to those names, assuming you had assigned bodyIn to the variable body.

Vector names = (Vector)body.getProperty(0);

Just remember that kSOAP makes no assumptions about your data, so while you might expect the Vector (or any return value) to contain String variables, it will actually contain SOAPObject variables that you will have to translate to Strings before using.

Complex Data Types

While the above information will help you if you can map your complex data types into simple data types, it does not help you much if you need to represent complex data types natively in the request, or they are returned natively in the response. The kSOAP library has a mechanism to deal with this.

To work with complex data types natively, you need to implement the KvmSerializable interface. This requires the following methods:

getPropertyCount()
getPropertyInfo(int index, Hashtable properties, PropertyInfo info)
getProperty(int index)
setProperty(int index, Object v)
register(SoapSerializationEnvelope envelope)

The method getPropertyCount is used to tell kSOAP how many properties are required to represent the members of this class. So a class with name, address, phone should return three when getPropertyCount() is called.

The method getPropertyInfo takes the property index you assigned (you assign an index to each property -- so in case we used for get PropertyCount(), name could be zero, address one, and phone two), and you return the name of the object and what type it is. The type is an enumeration provided in the kSOAP libraries -- specifically in the PropertyInfo class of the serialization library. If the member variable being referenced is itself a complex object, then its members will be in the properties hash table.

The method getProperty simply returns an instance of Object that represents the member referred to in the index parameter.

The method setProperty sets the property referred to by index to the value of v. Type checking in this one case is your responsibility, which makes sense since kSOAP has no way of knowing what you intended.

The method register tells kSOAP that when it sees a specific XML tag, it should assume that this class is the one that represents that XML element, and should serialize the XML into an instance of this class. To do this, you need to call one more kSOAP method:

envelope.addMapping(Namespace, XML Tag, Java Class);

After register is called, any time kSOAP sees the XML tag within the appropriate Namespace, it will create an instance of the Java Class passed in, and use setProperty()to fill the data in. The class must implement kvmSerializable for this to work without errors.

For most uses, since envelope.addMapping() is called inside the register routine of the class implementing kvmSerializable, you can just send this.getClass() as the third parameter.

Then you call register after you create your request object, and you do not have to think about it again. You can use the get/setProperty to access the variables, or you can create accessors that are more user-friendly to get and set from within your own code.

So the steps to create a kvmSerializable interface are fill in the get and set routines, create the register routine -- with addMapping as the core of the routine. Then in your main routine, you can call register to map from an XML type to your class.

Conclusion

That's really is all there is to harnessing the power of SOAP from your mobile devices. The kSOAP architecture takes care of serialization and deserialization of XML, handles all communications, and presents you with SoapObject elements to use. The only part that is tough to get your head around is that you must know what's coming back from the Web Service call before execution so that you can handle the response accordingly.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.