As I discussed in the first Wireless Java column, "Java Readies Itself for Wireless Web Services," XML processing capability represents one of the key requirements for wireless Web services applications. However, the standard J2ME/MIDP (Java 2 Platform, Micro Edition/Mobile Information Device Profile) specification lacks standard XML APIs, which aren't included in the upcoming MIDP 2.0 specification either. Thus, we need third party J2ME/CLDC (Connected Limited Device Configuration) libraries that can handle XML, especially those Web services-specific XML protocols.
In this article, I discuss how to process Web services messages using the open source kSOAP package on the J2ME/MIDP platform. As do many other enterprise computing architectures, Web services involve both clients and servers. As do many discussions focus on how to use J2EE (Java 2 Platform, Enterprise Edition) to develop and deploy Web services on the server side, I focus on only the J2ME client side in this article.
The SOAP advantage
An important XML protocol for accessing Web services is SOAP (Simple Object Access Protocol). Compared with competing technologies, SOAP has the following advantages:
- SOAP defines more than 40 standard data types through XML Schema and allows users to custom-define complex data types. Such sophisticated data-type support makes SOAP a powerful and rich language for exchanging information among today's widely deployed object-oriented systems.
- In addition to strong data-type support, SOAP also supports various messaging schemes. Those schemes include synchronous remote procedure calls (RPC), asynchronous messaging, multicast messaging (subscription), and complex message routes with multiple intermediaries.
- Since SOAP has gained mainstream support as a Web services messaging standard, most other Web services protocols must interoperate or bind with SOAP. For example, WSDL (Web Services Description Language), UDDI (Universal Description, Discovery, and Integration), and most XML registries support SOAP; XML Digital Signature, XML Encryption, SAML (Security Assertion Markup Language), and other secure XML protocols all provide standard binding with SOAP. Each binding protocol provides syntax of its own special element inside SOAP messages. SOAP's full support for XML namespaces has made it easy to bind with other protocols.
Because of the above advantages, SOAP is already the most widely used communication protocol for Web services. So, a core requirement for a wireless Web service application is the ability to understand SOAP messages. Now let's look at some simple SOAP examples. Listing 1 illustrates a simple, generic SOAP message:
Listing 1. Hello World SOAP message
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <SOAP-ENV:Body> <message xsi:type="xsd:string">Hello World</message> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
SOAP is most widely used in Web services RPCs. A SOAP response message from a Web services RPC usually contains the return values inside a
Result element under the SOAP
Body element. Listing 2 shows a simple SOAP RPC response message:
Listing 2. Hello World SOAP RPC response message
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2001/12/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <SOAP-ENV:Body> <result> <message xsi:type="xsd:string">Hello World</message> </result> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Since we must access SOAP messages programmatically in our programs, we need a SOAP parser.
What is SOAP parsing?
Every generic XML parser with namespace support understands SOAP messages and can extract information from them. In theory, we can always extract text information from a SOAP message using a generic XML parser and then convert those text strings to Java data objects when we need to use them. For example,
int i = Integer.parseInt("123"); converts a text string
"123" to an integer value 123. But such manual conversion burdens application programmers. Extracting Java data objects directly from a SOAP message would provide a better approach. Enter the SOAP parser.
A SOAP parser is built on a generic XML parser with special type-mapping and text data-marshaling mechanisms. A SOAP parser understands the data-type information in SOAP messages and automatically converts the SOAP message to Java data objects. The parser's real value is that it provides programming transparency between a Java program and a SOAP message. A programmer just feeds Java objects into a SOAP writer, sends the message, waits for the server response, and then reads Java objects directly from the SOAP parser.
As I discussed, SOAP features a rich set of functionalities. Many consider SOAP parsing support on resource-restricted wireless platforms such as J2ME/CLDC as expensive. Practical difficulties also exist:
- The lightweight J2ME/CLDC platform sacrifices many useful standard Java functionalities for size and speed. As a result, the J2ME/CLDC platform has only limited string functionality, a major problem for every wireless Java XML parser.
- SOAP parsing requires the parser to read the whole document into memory. But most J2ME/CLDC parsers are memory-efficient linear SAX parsers, which never construct in-memory object models.
- The J2ME/CLDC platform lacks support for some basic data types, such as the
Fortunately, project kSOAP solves these problems and provides a SOAP solution for small devices.
kSOAP to the rescue
Based on its renowned open source generic XML parser kXML, Enhydra.org has started an open source project for SOAP parsing on J2ME/MIDP platforms—the kSOAP project. Part of the EnhydraME project, kSOAP was written by a group of developers lead by Stefan Haustein. Enhydra released kSOAP's first alpha version in May 2001. After a year of development, kSOAP, now at version 1.2, supports a core set of SOAP 1.2 functionalities. This article's examples and architecture discussions apply to kSOAP version 0.95 and beyond (see Resources for the full source code). The code runs in the MIDP environment; if you are new to MIDP development or need to refresh your skills, refer to Michael Cymerman's series "Device Programming with MIDP."
This code segment parses the Hello World examples using kSOAP:
ByteArrayInputStream bis = new ByteArrayInputStream (mesg.getBytes ()); InputStreamReader reader = new InputStreamReader (bis); XmlParser xp = new XmlParser (reader); // Use default mapping between Java objects and Soap elements SoapEnvelope envelope = new SoapEnvelope (new ClassMap (Soap.VER12)); envelope.parse (xp);
The string variable
mesg stores the entire SOAP document.
Now, we must retrieve the message from the parsed SOAP
envelope. The following code retrieves the first child under the SOAP
// For Hello World Listing 1 String result = (String) envelope.getBody();
When applied to Hello World Listing 1,
result contains string value
This next code segment retrieves the first grandchild under the SOAP
// For Hello World Listing 2 String result = (String) envelope.getResult();
SoapEnvelope.getResult() method conveniently retrieves values from SOAP RPC response messages like the Hello World in Listing 2. However, as I have said, a SOAP parser's core value lies not in its ability to retrieve text strings from a SOAP document, but in its ability to map SOAP XML elements to Java objects. Let's examine how kSOAP achieves that mapping.
kSOAP objects structure
In a SOAP message, an element's
xsi:type attribute specifies the data type of an XML element's content. For example,
<myValue xsi:type="xsd:int">123</myValue> specifies an integer value of 123, and
<myValue xsi:type="xsd:string">123</myValue> specifies a string value of
kSOAP automatically maps four SOAP types to Java types according to the following list: