XML Web Services for Embedded Devices

An XML Web Services Development Environment for Embedded Devices

Robert van Engelen1
Department of Computer Science
Florida State University, Tallahassee, FL 32306-4530
engelen@cs.fsu.edu

Abstract

The ubiquitous nature of XML makes it a undeniably compelling data interchange format promising universal access to any XML-enabled device by any XML-enabled application. Industry-standard XML-based Web services protocols provide new opportunities to achieve enterprise systems integration, but their use in embedded systems is a challenge.


Contents

Introduction
Web Services Basics
    2.1  Architecture
    2.2  The SOAP Message Exchange Model
    2.3  Example
Why XML Challenges Embedded Systems
The gSOAP Toolkit
    4.1  Design Characteristics
    4.2  Platform Support
XML Serialization
    5.1  XML Serialization of Native C/C++ Types
    5.2  XML Serialization of Library Types
Conclusions
Acknowledgments

1  Introduction

The Extensible Markup Language (XML) has made a steady advancement into the world of information processing. This advancement has created new challenges for embedded systems. Several key factors can be identified that contributed to the popularity of XML. Firstly, XML is a relatively simple, human-readable data format that is platform and programming language independent. Hence, XML is often heralded as easy to use, which is true in part because parsers and translators are readily available for almost every programming language. Secondly, XML models semi-structured data, which is a more natural form of data modeling compared to the flat rectangular data formats imposed by traditional database systems. XML can also be subjected to content-based searches and translations. These properties make XML an ideal vehicle to achieve enterprise systems integration, albeit on the expense of the extra overhead incurred by the parsing and translation of data formatted in XML. This expense is modest at best for today's powerful desktop systems but introduces many new challenges for embedded systems.
Recent developments in Web and Internet protocol standardization have led to the publication of a collection of XML-based protocols that are meant to enhance cross-language and cross-platform interoperability, thereby encouraging systems integration. More specifically, a Web service, as defined by the W3C Web Services Architecture Working Group, is "a software system identified by a URI, whose public interfaces and bindings are defined and described using XML. Its definition can be discovered by other software systems. These systems may then interact with the Web service in a manner prescribed by its definition, using XML based messages conveyed by Internet protocols." [12]. This definition is often refined to the use of the Web Services Description Language (WSDL) [13] for describing and advertising Web services, and SOAP [2] as the XML-based transport-level packaging format.
Web services standards enable applications to actively participate in various forms of Internet transactions without a Web browser, such as receiving up-to-date stock quote information, obtain flight status information, being notified with calendar events, and even perform a Google search using the Google API [4]. The technology also enables applications to be turned into light-weight services, without requiring them to be integrated within a Web server. This means that their internal logic can be exposed and made accessible to other services. This allows for remote steering of embedded devices from any XML capable application connected to the Internet, such as from a remote desktop using the SOAP-capable Mozilla Web browser [8], for example.
This paper discusses the problems and challenges that had to be overcome to implement the gSOAP XML Web services toolkit for embedded devices. The toolkit is WSDL 1.1 and SOAP 1.1/1.2 compliant and includes an embedded Web server, an XML parser/generator, and a RPC (Remote Procedure Call) compiler that emits C/C++ source code for efficient SOAP/XML communications. The gSOAP toolkit [10,11] provides stand-alone XML Web services for C and C/C++ applications and is portable to Linux, virtually all Unix systems, Mac OS X, Windows, Palm (OS 3,4 and 5), Pocket PC, Symbian, and cell phones. Some modifications were made by the IBM alphaWorks team that used gSOAP to develop the Web Services Tool Kit for Mobile Devices (WSTKMD)2 [5] to support Palm and Symbian. gSOAP and IBM's WSTKMD have been used in a number of industrial projects and embedded system products. Other embedded Web servers are available [1,9], but these do not support the SOAP/XML Web services standards. eSOAP [6] developed by EXOR International, is a SOAP toolkit intended for embedded systems, but lacks server support. kSOAP [3] developed by Enhydra, runs on embedded devices that support Sun's KVM (an embedded JVM). Also ASP.NET provides a Web services framework for embedded devices based on WinCE, which is platform dependent.
The remainder of this paper is organized as follows. Section 2 introduces the Web services basics, including the architecture, message exchange model, and an illustrative example. Section 3 details some of the complexity hurdles for deploying Web services on embedded devices. The gSOAP toolkit is introduced in Section 4, with a discussion of the design characteristics that support embedded devices. gSOAP's XML serialization is presented in Section 5. The automation of XML serialization and the efficiency of this process in the context of embedded devices is one of the focus points of this paper. The paper ends with some concluding remarks in Section 6.

2  Web Services Basics

This section briefly reviews Web services principles for the uninitiated, followed by an example application.

2.1  Architecture

The Web services architecture model is shown in Figure 1. This layered architecture defines the levels at which the Web services protocols are supposed to be used.
services.png
Figure 1: Layered Architecture Model
The transport protocol layer   is at the bottom of the layered architecture model. The firewall-friendly HTTP (HyperText Transfer Protocol) and encrypted HTTPS are commonly used over TCP/IP to invoke Web services over a network. HTTP/1.1 supports request-response style message exchanges. Recent Web services standards aim to support a variety of message exchange patterns.
The packaging layer   uses SOAP, which defines a modular packaging model and the encoding mechanisms for encoding data within XML-based modules. This allows SOAP to be used in any number of systems ranging from message passing systems to remote procedure calls. SOAP is also relatively easy to implement on an embedded device, unlike ORBs (Object Request Brokers). A SOAP message consists of an envelope, which provides the framework for packaging message information, encoding rules that define how messages should be processed, and an RPC representation that defines how to represent remote procedure calls and responses. The SOAP encoding style uses both scalar types (strings, integers, floats, and so on) and compound types (structures and arrays) that can be used to carry application data. The values of these types appear as elements of an XML document. Authentication, digital signatures, routing information, transaction tokens, and other details can be stored in an optional SOAP header element. SOAP also has a built-in fault element that is used to carry error information necessary to transfer remote exceptions.
The information layer   carries XML-formatted data, which may consist of arbitrary XML documents, but more commonly transports XML-encoded application data that is transferred with remote procedure calls and responses. The process of wrapping application data in XML is called XML serialization. The mechanisms of XML serialization consists of XML encoding when preparing outbound messages for transmission and XML decoding after receiving inbound messages. In the setting of RPC request and response messages, these encoding and decoding mechanisms are also known as RPC parameter marshaling and RPC parameter demarshaling, respectively. To establish an RPC request-response message exchange, a proxy is invoked as a local function call, see Figure 2. After a proxy receives this function call, the RPC stub marshals the function parameters in XML, wraps it in a SOAP message, and transmits it over the network to be handled remotely, where the reverse process takes place to unwrap the parameters and return a response. The automation of XML serialization and the complexities that this process poses in the context of embedded devices is one of the focus points discussed in Section 5.
RPC.png
Figure 2: Remote Procedure Calling
The services layer   provides meta-data on the interface to Web services as defined by WSDL. A WSDL document is a description of a Web service that promotes reusability by defining its functionality and access mechanisms.
The discovery layer   offers a way to publish information about web services, as well as provide a mechanism to discover what web services are available through the Universal Description, Discovery, and Integration (UDDI) specification. UDDI allows Web service registration and/or search through the registry for a specific Web service. The result of a successful search includes a link to a WSDL document.

2.2  The SOAP Message Exchange Model

The services layer adopts WSDL documents to describe the access mechanisms, functionality, and the message exchange models of Web services. The SOAP message exchange model requires that applications receiving a SOAP message execute the following sequence of actions [2]:
1.   Identify all the components of the SOAP message that are intended for this particular application. Applications may act as SOAP intermediaries and pass parts of the message on to other applications.
2.   Verify that all the mandatory parts specified in the SOAP message are supported by the application, and process them accordingly.
3.   If the SOAP application is not the end destination of the message, it should remove all the parts that the application consumes and then forward the message to the next application the message is intended for.
In short, the SOAP exchange model allows for the routing of messages through intermediaries. This and other aspects of the model will be illustrated with an example.

2.3  Example

Modern office equipment typically includes a set of printers which are connected to a LAN (Local Area Network) for network printing. The printer connections are used to receive data for print jobs and to exchange status information with printer-specific protocols, such as the Printer Access Protocol (PAP). The example demonstrates how Web services can enable printers to actively notify users of the status of print jobs and even call for a technician via email when a malfunction was detected.
Figure 3 shows an example SOAP request message originating from a printer controller detecting a malfunction. The controller contacts a notification server that is responsible for relaying the message via the WS-Routing protocol [7] to the technician's email address. The notification service also logs a copy of the message for verification. The HTTP/1.1 header, SOAP Envelope, SOAP Header with routing information, SOAP Body with the remote procedure name event, and its parameters source and description are shown.


POST /NotificationService HTTP/1.1
Host: www.xyz.com
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction: NotificationService#event
 
<s:Envelope
 xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:r="http://schemas.xmlsoap.org/rp"
 xmlns:n="http://www.xyz.com/notification.xsd">
   <s:Header>
      <r:path>
         <r:to>smtp://technician@xyz.com</r:to>
         <r:id>cid:ticket12345</r:id>
      </r:path>
   </s:Header>
   <s:Body s:encodingStyle
      "http://schemas.xmlsoap.org/soap/encoding/">
      <n:event>
         <source>Printer12</source>
         <description>DriveMotorFailure</description>
      </n:event>
   </s:Body>
</s:Envelope>

Figure 3: Example Request Message
The notification service's response message is shown in Figure 4. In this example, the response is an acknowledgment returned to the printer controller.


HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: mmmm
 
<s:Envelope
 xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:n="http://www.xyz.com/notification.xsd">
   <s:Body s:encodingStyle
      "http://schemas.xmlsoap.org/soap/encoding/">
      <n:eventResponse>
         <status>OK</status>
      </n:eventResponse>
   </s:Body>
</s:Envelope>

Figure 4: Example Response Message

3  Why XML Challenges Embedded Systems

XML Web services technology brings a whole new set of design tradeoffs and issues. Embedded systems exacerbate the problem in the areas of complexity, constraints, and the verbosity of the protocols. The processing and memory limitations of embedded devices may severely compromise the usability of XML, unless several optimizations are considered.
Complexity   of networking with HTTP, XML parsing, and SOAP packaging can be intimidating. However, much of the complexity can be abstracted away through the use of proxies that are invoked as local function calls, see Figure 2.
Constraints   imposed by the embedded system architecture. Embedded systems rarely have enough memory, processing power, and other resources. Adding an XML parser and SOAP-encoding engine to a system seems problematic.
Verbosity   of HTTP and XML increases RAM usage, bandwidth requirements, and operating costs. Text-based systems are inherently less efficient than binary systems, which leads to more data being transmitted and larger buffers being required to both prepare outbound messages and receive inbound messages.
Web service protocol compliance raises a number of complexity concerns for embedded devices and XML serialization is just one of the complexities of the SOAP message exchange model.

4  The gSOAP Toolkit

gSOAP fully automates the XML serialization process. Several optimization strategies were incorporated in the toolkit's design to ensure that this process is efficient.

4.1  Design Characteristics

Performance enhancing strategies   include the use of an XML pull parsing technique to support efficient XML serialization. gSOAP's application-driven approach to XML decoding enables a mapping of XML to native application data structures. The decoding routines are pre-compiled from a specification of the application's data types. The decoding routines directly deserialize data into these application-specific data structures. Since these data structures are native to the C/C++ application being developed, additional data conversion and wrapping are unnecessary. By pre-compiling the decoding routines with the gSOAP RPC compiler, the protocol stack (TCP/IP, HTTP, SOAP/XML) is effectively collapsed, which avoids the overhead of message exchanges through multiple protocol layer APIs (Application Programming Interfaces).
Static proxy generation   is supported by gSOAP to reduce memory requirements and run-time processing overhead. Dynamic proxy generation usually takes place interactively, for example when a user attempts to access a service on the fly (the automation of the analysis of the properties of a dynamic proxy class requires an entity that is knowledgeable about the proxy's model.
Scalability   is achieved with linear-time XML serialization algorithms by utilizing hash tables for analyzing pointer structures such as cyclic graphs. The XML decoding time is linear when receiving gSOAP-generated XML. However, the decoding time of an XML message produced by another SOAP toolkit may depend on the structure of the XML message, because the SOAP/XML representation of a message is not unique.
Limit memory usage   by dynamically allocating data only when necessary, such as the XML-decoded application data that is extracted from an XML message, which must be placed on the heap. When dealing with XML it is difficult to avoid dynamic allocation altogether, except possibly for the simplest uses of XML (but such limitations may break SOAP/XML compliance). gSOAP's approach to XML parsing requires only the decoded application data to be stored in memory, which obviously is a minimal requirement. The toolkit avoids the used of prohibitively large generic XML tree-like representations such as XML DOM (XML Document Object Model) to store intermediate forms of XML. The toolkit further limits dynamic allocation by utilizing non-dynamically allocated buffers and dynamically allocated look-aside buffers when parsing and generating XML content. Memory is also conserved for effective HTTP transfers. HTTP messages require content-length headers or chunking of the message3. As a result, HTTP content-length header must be set to the message size before the message is actually send. This usually means that the entire message body has to be cashed to determine its length. To avoid this overhead, gSOAP serializes a message twice, the first time to determine the message length and a second time to send the XML after the HTTP header.
Pure C   code can be generated by the gSOAP compiler when required, which is useful to integrate legacy systems.
Required libraries   are limited to the usual standard C libraries and a socket library. As an alternative, the I/O layer can be entirely replaced by implementing callback functions to implement open, close, read, and write operations.
Read-only data   can be serialized in XML without coping to RAM. The XML serialization routines generated by the gSOAP compiler encode data directly into XML.
Built-in library data types   can be serialized. The latest gSOAP version 2.3 supports the generation of XML serialization routines for externally defined data types, such as those exported by built-in libraries. This feature saves programmers precious development time since they don't need to spend efforts to develop a separate XML interface for an existing application. There are some limitations on the serializability of some of the C and C/C++ types. For example, unions cannot be serialized. So-called void pointers can only be serialized when they are used within a C struct or C++ class and when preceded with a special type specifier field.
Ensuring the preservation of the logical structure of data   serialized in XML. The serialization of pointer-based native C/C++ data structures while preserving their logical coherence is important. Unfortunately, SOAP 1.1 RPC encoding has a specific format that cannot guarantee that the logical structure of a data structure graph will be preserved. The reason is that SOAP 1.1 RPC encoding enforces a serialization format that detaches the serialized multi-referenced objects from the message body. However, SOAP 1.2 RPC encoding and literal encoding can be used to serialize data structures in a format that preserves their logical coherence. This means that gSOAP can be used to safely exchange graph-like data structures. Furthermore, the gSOAP compiler can be used separately to produce serialization routines that can be used by an application to store and retrieve pointer-based data structures in XML format, including lists, trees, and cyclic graphs. These data structures can be retrieved from XML and fully restored to their original logical structure. This is further explained in more detail in Section 5.
Feature-rich   with an embedded HTTP Web server (which supports keep-alive connections, compression, cookie-based state-management, basic authentication, and SSL security), an RPC compiler to produce XML serialization routines for native C and C/C++ application data types, support for event-driven message exchange patterns, WSDL 1.1 support to develop services, and support for streaming binary media with DIME (Direct Internet Message Encapsulation). The RPC compiler is typically used together with the embedded Web server to build complete SOAP/XML Web services applications with a minimal code size of under 100K, with a total memory footprint of about 150K4. The toolkit components can be used independently. For example, the RPC compiler can be used to add XML serialization capabilities to an application's native data types.

4.2  Platform Support

The gSOAP toolkit runs on most systems such as Linux, BSD Unix, HPUX, Solaris, Irix, AIX, Mac OS X, Cygwin, and Windows. Customized modifications were incorporated into the gSOAP release using the usual #ifdef conditional compilation constructs to specifically support a variety of embedded systems. The operating systems of embedded devices have certain limitations such as code mapping limitations and the absence of multi-tasking capabilities, for example. The gSOAP toolkit supports Palm OS 3 and 4, which are a non-multi-tasking operating systems (multi-tasking is not required to run gSOAP applications). Palm OS 3 or 4 usually run on a Motorola 68K processor with typically 4-16 MB memory and 256KB dynamic heap. Palm OS 5 supports multi-tasking (but is not made available to developers) and runs on an ARM processor and supports an adjustable dynamic heap of 2MB maximum size.

5  XML Serialization

The XML serialization with gSOAP was designed to meet architectural constraints. To achieve this, a compiled approach is used. The gSOAP RPC compiler takes a header file with type definitions and generates serialization routines to encode and decode these types in XML at run time.

5.1  XML Serialization of Native C/C++ Types

When small-scale systems are deployed with Web services, one can argue that most SOAP/XML message exchanges will be limited to messages that contain simple data structures, such as strings, integers, and floats. However, Web services protocol compliance requires that more complicated data structures must be supported when necessary. This does not mean that a Web service application must deal with arbitrarily complicated data types at run time. The data types used with the SOAP/XML invocations are determined from the WSDL document that describes the service. These types are fixed when the proxies are generated at compile time.
There are many ways in which data can be serialized in XML. gSOAP's serialization method is compatible with SOAP RPC encoding, which supports the encoding of primitive types such as strings, integers, floats, enumerations, and so on, and the compound data types structs and arrays. SOAP encoding also supports polymorphism through XML schema extension, which is useful to C++ applications. The SOAP/XML type mapping mechanism is complete and sufficiently powerful to encode native C and C/C++ data types with SOAP RPC encoding. In addition, gSOAP provides features to serialize data in customized XML formats, such as with XML attribute values, in order to support more flexible XML serialization rules, such as SOAP literal encoding styles. Special care was taken for the serialization of pointers and pointer-based structures. XML enables the cross referencing of elements using id and href attributes, which are exploited to serialize linked lists, trees, and arbitrary (cyclic) graphs.
The gSOAP serialization algorithm uses two phases. Each phase completely traverses the data structure to be serialized. The first pass determines which data components belong to the data structure and which pointers are used to reference them. The second pass emits the XML encoded form of the entire data structure, with all sub-components of the structure serialized recursively.
Phase 1:   traverse the data structure graph by visiting each node and by following the pointer references to all sub-nodes. For each pointer that was followed to a sub-node, store the pointer's target address in a hash table together with an identification of the data type referenced by the pointer. The hash table key is a pair of < PtrLoc,PtrType > , where PtrLoc is the pointer's target address and PtrType is the type of data referenced by the pointer. Node pointers are only followed through to visit sub-nodes when the key < PtrLoc,PtrType > is not already contained in the hash table. When the key is already contained in the hash table, then the hash table entry is marked RefType=multi to indicate that a multi-referenced sub-node has been found. Entries in the hash table are marked RefType=embedded when a data element that is pointed to is embedded in larger structure, such as a field of a struct or class, or an element of an array. It is noteworthy to mention that a hash table entry is created at run time only for each pointer in a pointer-based data structure. No additional space is required to serialize non-pointer-based structures.
Phase 2:   emit the XML encoded data by visiting each node in the data structure graph and by following the pointer references to the sub-nodes for recursive serialization. Multi-referenced nodes (those whose hash table entry is marked RefType=multi) are serialized separately, as required by SOAP 1.1 encoding. The serialization settings can be changed to override SOAP 1.1 encoding to serialize data in a more generic XML format. In that case, also special care is taken to serialize data elements that are referenced by pointers and which are embedded within structs or arrays (that is, the hash table entry for these elements are marked RefType=embedded). The embedded property of data elements affects the id-href element cross referencing produced in the encoded form of XML. The cross referencing produced ensures that the receiving side of the XML message can accurately reconstruct the serialized data structure from the XML content alone.
graph.png
Figure 5: Data Structure Graph
The two-phase serialization is illustrated with the example data structure shown in Figure 5. The structure consists of three nodes, two structs located at addresses A and B, and a node that contains a single integer value stored at address C. The data type declaration of the node struct with the val, ptr, and next fields is shown in Figure 6.


struct Node
{
   int val;
   int *ptr;
   struct Node *next;
};

Figure 6: The Node Structure
The serialization starts at the root struct stored at location A. The first phase consists of a pass over the entire data structure to collect the properties of the pointers used in the data structure graph and to store these in the hash table for analysis. Table 1 lists the properties of the pointers used in the data structure graph shown in Figure 5. Each entry has a unique index ID, the hash table key < PtrLoc,PtrType > with target pointer address PtrLoc and target type pointed to PtrType, an indication of the number of references made to this target address, PtrCount, which is either "1" or " > 1", and the type of the reference RefType, which is either "single", "multi", or "embedded".


ID PtrLoc PtrType PtrCount RefType
1 A Node > 1 multi
2 B int 1 embedded
3 B Node 1 single
4 C int 1 single

Table 1: Properties of the Pointers used in the Data Structure Graph
The phase 1 marking routine that is generated by gSOAP to serialize the Node structure is shown in Figure 7. The marking routine checks for fields that should be marked "embedded" and calls the marking routines for all the pointer-based fields to traverse the data structure graph. Such serialization routines are produced for all data types encountered in a header file parsed by the gSOAP RPC compiler.


void soap_mark_Node(struct soap *soap, const struct Node *a)
{
   soap_embedded(soap, &a->val, SOAP_TYPE_int);
   soap_embedded(soap, &a->ptr, SOAP_TYPE_PointerToint);
   soap_mark_PointerToint(soap, &a->ptr);
   soap_embedded(soap, &a->next, SOAP_TYPE_PointerToNode);
   soap_mark_PointerToNode(soap, &a->next);
};

Figure 7: Marking Routine for Node
The second phase of the serialization of the data structure graph shown in Figure 5 traverses the graph while emitting XML. Element cross referencing with id and href attributes ensures that the logical coherence of the data structure is preserved in XML. The phase 2 output routine that is generated by gSOAP to serialize the Node structure is shown in Figure 8. The code starts with the printing of the begin of a new XML element, followed by the output of the Node struct fields as XML sub elements, and the final closing of the XML element. The soap_embedded_id function call determines whether the Node struct element should carry an id attribute for cross referencing.


int soap_out_Node(struct soap *soap, const char *tag, int id, const struct Node *a, const char *type)
{
   soap_element_begin_out(soap, tag, soap_embedded_id(soap, id, a, SOAP_TYPE_Node), type);
   soap_out_int(soap, "val", -1, &a->val, "");
   soap_out_PointerToint(soap, "ptr", -1, &a->ptr, "");
   soap_out_PointerToNode(soap, "next", -1, &a->next, "");
   soap_element_end_out(soap, tag);
   return SOAP_OK;
}

Figure 8: XML Printer for the Node Structure
The serialized output is shown in Figure 9. The root node is serialized with id="_1", because it is multi-referenced. The second struct at location B is serialized in XML as a nested element of the first node struct, because it has only a single reference. Note that the ptr field in the first struct points to the val field in the second struct, which is at location B. Because the val field is embedded within a struct, the ptr is serialized with a forward pointing href="#_2" attribute. This ensures that the receiving side can decode the XML and backpatch the ptr pointer field to point to the val field after the contents of the second struct are decoded that contains the value of val. The ptr field in the second struct points to a single-referenced integer located at C. The XML serialized value is placed directly in an ptr element without an href attribute, because it is a single reference.


<Node id="_1">
   <val>123</val>
   <ptr href="#_2"/>
   <next>
      <val id="_2">456</val>
      <ptr>789</ptr>
      <next href="#_1"/>
   </next>
</Node>

Figure 9: XML Serialized Output of the Data Structure Graph


struct Node *soap_in_Node(struct soap *soap, const char *tag, struct Node *a, const char *type)
{
   short soap_flag_val = 1, soap_flag_ptr = 1, soap_flag_next = 1;
   if (soap_element_begin_in(soap, tag)) return NULL;
   if (soap_match_tag(soap, soap->type, type)) {
      soap->error = SOAP_TYPE_MISMATCH;
      return NULL;
   }
   if (soap->null) return a;
   if (!*soap->href) {
      a = (struct Node *)soap_id_enter(soap, soap->id, a, SOAP_TYPE_Node, sizeof(struct Node), 0);
      if (!a) return NULL;
      if (soap->alloced) soap_default_Node(soap, a);
      if (soap->body) {
         for (;;) {
            soap->error = SOAP_TAG_MISMATCH;
            if (soap_flag_val && soap->error == SOAP_TAG_MISMATCH)
               if (soap_in_int(soap, "val", &a->val, ""))
                  { soap_flag_val = 0; continue; }
            if (soap_flag_ptr && soap->error == SOAP_TAG_MISMATCH)
               if (soap_in_PointerToint(soap, "ptr", &a->ptr, ""))
                  { soap_flag_ptr = 0; continue; }
            if (soap_flag_next && soap->error == SOAP_TAG_MISMATCH)
               if (soap_in_PointerToNode(soap, "next", &a->next, ""))
                  { soap_flag_next = 0; continue; }
            if (soap->error == SOAP_TAG_MISMATCH)
               soap->error = soap_ignore_element(soap);
            if (soap->error == SOAP_NO_TAG) break;
            if (soap->error) return NULL;
         }
         if (soap_elemen_end_in(soap, tag)) return NULL;
      }
   }
   else {
      a = (struct Node *)soap_id_forward(soap, soap->href, (void**)soap_id_enter(soap, soap->id, a, SOAP_TYPE_Node, sizeof(struct Node), 0), SOAP_TYPE_Node, sizeof(struct Node));
      if (soap->alloced) soap_default_Node(soap, a);
      if (soap->body && soap_element_end_in(soap, tag)) return NULL;
   }
   return a;
}

Figure 10: XML Parser for the Node Structure
The resulting XML document shown in Figure 9 can be parsed and its contents decoded to restore the original data structure graph it models. The XML parser for the Node structure is shown in Figure 10. This code is generated by the gSOAP compiler to parse and decode Node structs from an XML document. The code calls lower-level routines to perform the scan operations on the XML input, such as detecting the beginning and ending of an XML element, compare namespace-qualified element and attribute names, handle XML attributes, and so on. The generated code is a micro-parser for the Node struct, although it was designed to handle multiple alternative XML representations for the Node struct to ensure interoperability with other SOAP/XML toolkits. For example, it detects the presence of an XML xsi:nil attribute, indicating that this node is NULL. The parser further detects whether the content is defined elsewhere in the XML document and referenced via an href attribute. In that case, its contents have to be retrieved from another location in memory when the the contents were parsed earlier, or its contents have yet to be parsed. In the latter case some book-keeping is necessary to handle the forwarded data and move it to the appropriate location in memory at a later stage (function soap_id_forward). Because the fields of the Node struct are fetched one by one from the XML stream and decoded on the fly, the entire parsing process is streamlined and quite efficient.

5.2  XML Serialization of Library Types

The direct serialization of built-in library types is a useful feature, because it does not require the wrapping of the library data into another data structure for data exchange. This saves development time and avoids any run-time data conversion overhead that would be incurred with wrapping.
To demonstrate the serialization of a built-in library type, we chose the the tm structure defined in < time.h > . We took a snapshot of the tm structure from in a man page and copied it into a new header file for parsing by the gSOAP compiler. We qualified the structure volatile, as is shown in Figure 11. The volatile qualifier is special to gSOAP and indicates that this structure provides (part of) a view of an external type imported from a library rather than being defined by the header file it was parsed from. In this way, the tm structure can be serialized even when the fields it contains varies between platforms (the fields shown in Figure 11 are all mandatory).
Compiling the header file shown in Figure 11 with gSOAP produces the XML encoding and decoding routines for the structure. Each field will be serialized as an XML element. With a simple trick we can make the XML serialization more pretty by serializing the tm_mon, tm_wday, and tm_isdst fields with enumerations. Most C compilers support the conversion of int into enum and vice versa, so we can safely replace the int type of tm_mon with an enumeration of the months, replace the int type of tm_wday with an enumeration of the weekdays, and replace the int type of tm_isdst as an enumeration of {NO_DST, DST}. Figure 12 shows the serialized output of the contents of a tm structure in XML.


volatile struct tm
{
   int tm_sec; /* seconds (0 - 60) */
   int tm_min; /* minutes (0 - 59) */
   int tm_hour; /* hours (0 - 23) */
   int tm_mday; /* day of month (1 - 31) */
   int tm_mon; /* month of year (0 - 11) */
   int tm_year; /* year - 1900 */
   int tm_wday; /* day of week (Sunday = 0) */
   int tm_yday; /* day of year (0 - 365) */
   int tm_isdst; /* is summer time in effect? */
   char *tm_zone; /* abbreviation of timezone name */
   long tm_gmtoff; /* offset from UTC in seconds */
};

Figure 11: The tm Structure


<tm>
   <tm-sec>58</tm-sec>
   <tm-min>18</tm-min>
   <tm-hour>11</tm-hour>
   <tm-mday>18</tm-mday>
   <tm-mon>June</tm-mon>
   <tm-year>103</tm-year>
   <tm-wday>Wednesday</tm-wday>
   <tm-yday>168</tm-yday>
   <tm-isdst>DST</tm-isdst>
   <tm-zone>EDT</tm-zone>
   <tm-gmtoff>-14400</tm-gmtoff>
</tm>

Figure 12: XML Serialized tm Structure

6  Conclusions

The apparent ubiquitous nature of XML makes it a undeniably compelling data interchange format promising universal access to any XML-enabled device by any XML-enabled application. The use of XML Web services in embedded systems remains challenging. However, the absence of an XML-enabled interface to a system is likely to dampen future deployment plans for an embedded system, because enterprise applications are quickly moving to the Web services model. There is no reason for concern about the lack of support for XML in the future. Despite a few drawbacks, such as the verbosity of XML content, the popularity of XML and the absence of a better alternative suggests that XML is here to stay.

7  Acknowledgments

The author would like to thank Robert Goodman from IBM Emergent Technologies and his team for valuable discussions and the changes he and his team made to gSOAP to support Palm and Symbian devices.

References

[1]
G. Borriello and R. Want. Embedded computation meets the World Wide Web. Communications of the ACM, 43(5):59-66, May 2000.
[2]
D. Box et al. Simple object access protocol 1.1, 2000. http://www.w3.org/TR/SOAP.
[3]
Enhydra. ksoap. http://ksoap.enhydra.org/.
[4]
Google. Google Web API. http://www.google.com/apis/.
[5]
IBM alphaWorks. Web services tool kit for mobile devices, 2002. http://www.alphaworks.ibm.com/tech/wstkMD.
[6]
E. International. esoap. http://www.embedding.net/eSOAP/.
[7]
Microsoft. WS-Routing specification. Technical report, Microsoft, 2001. http://msdn.microsoft.com/ws-security.
[8]
Mozilla. Mozilla and web services. http://www.mozilla.org/projects/webservices/.
[9]
D. Tennenhouse. Proactive computing. Communications of the ACM, 43(5):43-50, May.
[10]
R. van Engelen and K. Gallivan. The gSOAP toolkit for web services and peer-to-peer computing networks. In 2nd IEEE International Symposium on Cluster Computing and the Grid, 2002.
[11]
R. van Engelen, G. Gupta, and S. Pant. Developing web services for C and C++. IEEE Internet Computing, pages 53-61, March 2003.
[12]
W3C. Web services architecture requirements. http://www.w3.org/TR/wsa-reqs.
[13]
W3C. WSDL specification. http://www.w3.org/TR/wsdl.

Footnotes:

1Supported in part by NSF grants CCR-9904943, CCR-0105422, CCR-0208892, and DOE grant DEFG02-02ER25543.
2IBM's WSTKMD includes gSOAP and a Java component based on kSOAP.
3HTTP chunking appears to be asymmetric. For example, the Apache Web server returns HTTP chunked messages, yet it does not accept chunked messages.
4These measurements were taken from a stand-alone console-based Web services application that retrieves up-to-date stock quote information running on an Intel Pentium IIItm with Red Hat Linux 8.0 and compiled with gcc 3.2 option -O2


File translated from TEX by TTH, version 3.39.
On 19 Jun 2003, 11:08.