Menu

Low Bandwidth SOAP

August 19, 2003

Jeff McHugh

Introduction

With the mobile phone industry reporting better than expected sales, and news that, by the end of this year, smart phones are expected to outsell hand-held computers, it should come as no surprise that wireless application development is on the rise. Sun recently announced that by the end of 2004 there may well be more than 200,000,000 Java-enabled mobile handsets. Yet, with all the attention being paid to these microdevices (i.e., low resource mobile devices), it's surprising to learn that a developer wishing to build a wireless application using XML, SOAP, and web services is left behind.

Why is this? First, a microdevice by definition has an extremely limited amount of memory. Second, traditional packages such as Xerces (for XML) and Axis (for SOAP) are far too large and resource-intensive to work on microdevices. A examination of Xerces.jar file should adeptly demonstrate this fact; it's over one megabyte in size. Microdevices are simply too small to be expected to work with packages originally designed for desktop clients and servers.

Fortunately this issue is well recognized by the larger wireless community. Sun, in particular, is currently in the stage of finalizing JSR172, a specification that addresses the use of XML, SOAP, and web services on microdevices. The downside is that, given past experience, it's not unreasonable to expect at least ten to twelve months to pass before finalization and widespread implementation. But that shouldn't deter anyone wishing to create a wireless application today, for doing so is quite possible using a powerful, free, and open source package readily available from Enhydra.org.

This article explains the basics of building web service servers and clients using Enhydra's KSOAP implementation.

Introducing KSOAP

A key ingredient for any web services application is SOAP. The problem with developing a wireless SOAP/XML application -- and the reason for the above-mentioned JSR172 -- revolves around the following issues. First, the common XML and SOAP packages currently available are quite large and contain hundreds of classes. Second, these packages depend on features of the Java runtime that simply don't exist on a microdevice. I'm thinking specifically about the Connected Limited Device Configuration (CLDC) specification which did away with nearly the entire core set of Java classes normally present in the J2EE and J2SE distributions: AWT, Swing, Beans, Reflection, and most java.util and java.io classes have simply disappeared. The purpose of this "bare bones" Java runtime is to accommodate the limited footprint of the KVM -- a low-memory virtual machine running on a microdevice.

This is where Enhydra.org comes to the rescue. KSOAP and KXML are two packages available from the web site designed to enable SOAP and XML applications to run within a KVM. They are thin, easy to use, and well documented. Combined into a single jar file, they take up less than 42K.

KSOAP begins with a class called SoapObject. This is a highly generic class which allows a wireless application to build SOAP calls. A quick look at the documentation reveals that the methods getProperty() and setProperty() are used to accomplish this functionality.

You might immediately notice the conflict with traditional Java programming inherent in this design model; it detracts from the use of static typing. Ideally, application development goes more smoothly if the data structures are defined statically and are able to be marshaled/unmarshaled across the network, just as if they were running within the same runtime environment. In other words, imagine having to rely solely on the Hashtable for all your data structures, assigning each property a key for access and retrieval and then having to remember each property's unique key and given type.

By having your data model defined statically, a developer can forget all that and rely on the compiler, not the runtime, to catch the type-mismatch errors. Further, casting is kept to a minimum, and it is easier to take advantage of tool support that depends on static typing to help the programmer.

Fortunately, the developers behind KSOAP recognized the importance of statically defined data structures; they've provided the necessary interface. By implementing KvmSerializable, a developer can continue to use his or her own data objects. Using this interface becomes even more important within large-scale enterprise environments where the data models might be numerous and previously defined.

An Example Application

In an effort to explain how to take advantage of KSOAP, I have put together a sample application. For the purpose of clarity I have made this application simple and straightforward. It is a wireless-app that enables a fictitious manager to receive, by way of a mobile phone, system alerts that are periodically generated by some anonymous back-end system during the normal course of the day. Upon receiving such an alert he or she might decide to call an administrator, or notify their department, or perhaps even dial-in from home and fix the problem.

This sample application involves just four classes.

  • SystemAlert.java
    The data model

  • AlertService.java
    The Service module generating SystemAlerts.

  • AlertServlet.java
    The HTTP interface that sends and receives SOAP Messages.

  • AlertClient.java
    The MIDLet application residing on the Mobile Phone

The components work together as illustrated below.

Component diagram.

There are three basic tasks involved in working with KSOAP.

  • Implement the serialization logic of your data objects via the KvmSerializable interface.
  • Register your data objects with the KSOAP ClassMap. (This needs to done on both the client and server side.)
  • Integrate your services with the KSoapServlet. (Optionally, you can create your own servlet to suit your given needs -- all of the KSOAP source code is freely available.)

Let's begin by taking a look at the SystemAlert class before it has been modified to work with KSOAP.

SystemAlert.java (before adding KSOAP)

As you can see the class is intended to be serialized; however, since the CLDC specification has done away with DataObjectStreams and the Introspection classes, the traditional mechanism for passing objects over the network can't be utilized, and a new process of (de)serialization must be used. KvmSerializable provides the mechanisms to accomplish this task. Examine the same class definition after the changes have been made.

SystemAlert.java (after adding KSOAP)

As you can see, the methods getProperty() and setProperty() handle all the logic necessary for serialization and deserialization. These methods are called behind-the-scenes by the SOAP engine rather than by the application itself, and they provide all the logic necessary to map the binary data to its string representation. The simple types such as String, long, and int are taken care of for you by the KSOAP framework. Complex types are handled by implementing the mapping logic in a similar fashion.

While implementing mapping logic for each and every object can quickly become a tedious exercise, I have created a helpful Ant task to speed the process along. Using this Ant task, a developer need not bother with any of the mapping logic at all; it is created and added automatically. This will save time for the large-scale projects with scores of data objects needing to be serialized.

Servlet

The next piece to examine is the servlet that will function as the interface between your service and outside world (i.e. the mobile phone or some other microdevice). This can be best accomplished by extending KSoapServlet, which is available in the KSOAP package, and overriding its init() method as shown below.

public void init(ServletConfig cfg) throws ServletException {
    super.init(cfg);
    ClassMap classMap = getClassMap ();
    classMap.addMapping("localNameSpace", "SystemAlert",
        new SystemAlert().getClass());
    AlertService alertService = new AlertService();
    instanceMap = new HashMap();
    instanceMap.put("AlertService", alertService);
}

By registering the SystemAlert class with the ClassMap, the SOAP engine knows to expect a class of that given type, what it should be named and what namespace to assign it (though the namespace assignment is curiously non-standard.) Have a quick look at the associated SOAP message below.

<SOAP-ENV:Envelope
        xmlns:n0="examples.soapservice" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
        xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
        <SOAP-ENV:Body 
          SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
              <n0:getNextSystemAlertResponse id="o0" SOAP-ENC:root="1">
                 <return xsi:type="n0:SystemAlert">
                   <timeStamp xsi:type="xsd:long">1057726422543</timeStamp>
                   <message xsi:type="xsd:string">Sample Error Message</message>
                 </return>
              </n0:getNextSystemAlertResponse>
        </SOAP-ENV:Body>
</SOAP-ENV:Envelope> 

Further down the init() method, a HashMap is created to store the given instance of our AlertService. When the client makes a request it will send along with it an "AlertService" parameter so that the servlet executes the desired service. The getInstance() methods show how this is key is utilized and how the service object is retrieved. As a conscientious developer you may wish to enforce stronger security and access control. This is essentially the location to achieve that; all your database and encryption logic can branch off from here.

protected Object getInstance (HttpServletRequest req) {
    Object result = instanceMap.get(req.getParameter("service"));
    return result; 
}

Client

This brings us to the final piece, the client. In order to execute on a mobile phone, a developer might choose to use the MIDlet framework, as I have. Interacting with the AlertServlet amounts to just a few lines of code. Below is a snippet of code from AlerterClient.java (available from the example code.) For the purposes of this example assume the service resides on a host running at http://somehost.com:8181/services.

public SystemAlert makeRequestToServer() throws Exception {
     ClassMap classMap = new ClassMap();
     classMap.addMapping("localNameSpace", "SystemAlert", 
        new SystemAlert().getClass() ); 
 
     SoapObject rpc = new SoapObject("urn:xmethods-AlertService",
        "getNextSystemAlert");
     HttpTransport tx = new 
        HttpTransport('HTTP:// somehost.com:8181/services' +
            "?service=AlertService", 
			"urn:xmethods-AlertService");
 
    tx.setClassMap( classMap );
    SystemAlert alert = (SystemAlert) tx.call( rpc );

    return alert;
}

Once again, we register the SystemAlert class with the ClassMap. Secondly, we create a SoapObject for the sole purpose of making the request -- your application might wish to send some custom KvmSerializable object instead. We then create an HttpTransport object passing it the destination address for our Service; notice that the "service" parameter is also appended. Lastly, we initiate the transaction via method tx.call(). If all is well a SystemAlert object is returned; and if something should go wrong, the SOAP message will contain a SOAPFault element instead of its normal payload. Subsequently, an exception will be thrown from within the call() method.

As you can see, developing an application like this is not so difficult. By leveraging KSOAP for your wireless application, you can help make it a more powerful and reliable one. Since much of the infrastructure is provided, you as the developer can spend more time focusing on the important aspects of development such as the business logic.