Building and Traversing XML are regular tasks for any Web Service developer. We may use DOM, AXIOM or even simple String manipulation functions to do that. Normally this takes a lot of time and effort. And if we are coding in ‘C’ it become more tedious as string manipulation in ‘C’ is not that straight forward.

What ADB does is it generates a set of ‘C’ functions specially for our XML Schema to build and traverse the XML.
Say you have the following XML Schema. (You need to have it inside a WSDL to generate the code).

        <xs:schema targetNamespace="http://dimuthu.org/adb/demo/2008/sept">
            <!-- demonstrating element-->
            <xs:element name="myDemo">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="demo1" type="xs:int"/>
                        <xs:element name="demo2" type="xs:string"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        <xs:schema/>

For this particular element there will be one adb type (adb_myDemo_t), one source (adb_myDemo.c) and one header (adb_myDemo.h) are generated. Don’t ever look at the source file (unless you want to hack it) just go through the header, it will have all the function you need to manipulate your ADB.

It will have following set of functions,

To create and free the object
  • adb_myDemo_create
  • adb_myDemo_free
Getters and Setters to manipulate Data
  • adb_myDemo_get_demo1
  • adb_myDemo_set_demo1
  • adb_myDemo_get_demo2
  • adb_myDemo_set_demo2
Build and Parse XML
  • adb_myDemo_serialize
  • adb_myDemo_deserialize

First we will check how to build a simple XML using an ADB object.

    adb_myDemo_t *mydemo = adb_myDemo_create(env);
    adb_myDemo_set_demo1(mydemo, env, 3); /* some arbitrary value */
    adb_myDemo_set_demo2(mydemo, env, "some arbitrary string");
    axiom_t *xml = adb_myDemo_serialize(mydemo, env, NULL, NULL, AXIS2_TRUE, NULL, NULL);

So now we have the AXIOM representation of the XML which we just build using ADB.

<ns0:myDemo xmlns:ns0="http://dimuthu.org/adb/demo/2008/sept">
    <ns0:demo1>3</ns0:demo1>
    <ns0:demo2>some arbitrary string</ns0:demo2>
</ns0:myDemo>

Anyway ADB is easier when you want to navigate through an XML. (you can read data randomly as you preferred). Here we starting from the AXIOM representation of our XML.

      adb_myDemo_t *mydemo= adb_myDemo_create( env);
      adb_myDemo_deserialize(mydemo, env, &xml, NULL, AXIS2_FALSE))
      int demo1 = adb_myDemo_get_demo1(mydemo, env);
      printf("My Demo1 is: %d\\n", demo1);
      axis2_char_t *demo2 = adb_myDemo_get_demo2(mydemo, env);
      printf("My Demo2 is: %s\\n", demo2);

I have printed the Data contained in the XML with the help of ADB objects.

In ordre to download the Codegen tool with ADB you have to download the Axis2/Java package.

If you want to learn more about ADB, Just go through more Axis2/C Codegen / ADB resources which I have blogged few weeks ago.

SOAP Headers are used in many WS-* standards (for an example WS-Security) to transmit information related to the QOS aspects of the service. So only the SOAP engines which process these QOS parameters are supposed to see these headers. Web Service Developer or Consumer need to care only what is in the SOAP payload (which is what inside the SOAP body element) and not SOAP headers.

But that is theory, In practice we see many places where people uses SOAP headers to transmit what they should have easily sent through SOAP Body. And many SOAP stacks also provide APIs to allow people to send/receive custom headers and standards like WSDL too provide ways to describe services which accept custom headers. So I thought it might worth to discuss how you describe custom headers in a service from a WSDL and how you can consume and serve in real world with SOAP stacks like Axis2/C and WSF/PHP.

In a WSDL 1.1 you first declare your headers in the binding section itself which is the section that is used to provide the messaging and transport protocol information.

  <binding name="RetHeaderBinding" type="tns:RetHeaderPortType">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="echoString">
      <soap:operation soapAction="http://soapinterop.org/" style="document"/>
      <input>
        <soap:body use="literal"/>
        <soap:header message="tns:Header1" part="Header1" use="literal"/>
        <soap:header message="tns:Header2" part="Header2" use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
        <soap:header message="tns:Header1" part="Header1" use="literal"/>
        <soap:header message="tns:Header2" part="Header2" use="literal"/>
      </output>
    </operation>
  </binding>

There you can see we have Header1 and Header2 in both in input and output of the operation. It refers to the message section with the specific part name that represent the header. Here is how message section will look like.

  <message name="Header1">
    <part name="Header1" element="types:Header1"/>
  </message>
  <message name="Header2">
    <part name="Header2" element="types:Header2"/>
  </message>

In this section it refers to the schema element that actually describe the element structure/schema. Here I put a string and an int in each header.

  <s:element name="Header1">
      <s:complexType>
        <s:sequence>
          <s:element name="string" type="s:string"/>
          <s:element name="int" type="s:int"/>
        </s:sequence>
      </s:complexType>
  </s:element>
  <s:element name="Header2">
      <s:complexType>
        <s:sequence>
          <s:element name="int" type="s:int"/>
          <s:element name="string" type="s:string"/>
        </s:sequence>
      </s:complexType>
  </s:element>

Here is a valid SOAP message for the WSDL description.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header>
      <ns1:Header1 xmlns:ns1="http://soapinterop.org/xsd">
         <ns1:string>test1</ns1:string>
         <ns1:int>5</ns1:int>
      </ns1:Header1>
      <ns1:Header2 xmlns:ns1="http://soapinterop.org/xsd">
         <ns1:int>8</ns1:int>
         <ns1:string>test2</ns1:string>
      </ns1:Header2>
   </soapenv:Header>
   <soapenv:Body>
      My payload
   </soapenv:Body>
</soapenv:Envelope>

If you are using Apache Axis2/C WSDL2C Codegen tool (which is shipped with Axis2/Java) you will be able to directly use the API provided with the generated code to deal with custom headers. Here is how the client API is generated for the above WSDL.

         /**
          * auto generated method signature
          * for "echoString|http://ws.dimuthu.org/blog/headers" operation.
          *
          * @param _echoStringParam
          * @param _header1
          * @param _header2
          *
          * @param dp_header10 - output header
          * @param dp_header21 - output header
          * @return adb_echoStringReturn_t*
          */
         adb_echoStringReturn_t*
         axis2_stub_op_RetHeaderService_echoString( axis2_stub_t *stub, const axutil_env_t *env,
                                              adb_echoStringParam_t* _echoStringParam,
                                              adb_Header1E0_t* _header1,
                                              adb_Header2E1_t* _header2,
                                              adb_Header1E0_t** dp_header10 /* output header double ptr*/,
                                              adb_Header2E1_t** dp_header21 /* output header double ptr*/)

Note that the first parameter is the environment variable passed in every function in Axis2/c. The second parameters is the payload. Input headers (input headers for server side) are in 3rd and 4th parameters, you can build them similar to how you build payload object. 5th and 6th are for the output headers which you only need to provide some pointers and the generated code will build you the objects from the response data.

You service will also have a similar API. There you have to create adb objects for output headers (like you build output payload) and assign the pointer to these output header double pointers.

             adb_Header2_t* arg_Header1 = adb_Header1_create(env);
             adb_Header1_set_string(arg_Header1, env, "I m response Header 1");
             adb_Header1_set_int(arg_Header1, env, 1);
             adb_Header10_t* _header1 = adb_Header10_create(env);
             adb_Header10_set_Header1(_header1, env, arg_Header1);
             *dp_header10 = _header1;

Now how about PHP, can you provide the same API form the PHP as well. Yes, PHP has references similar to C pointers. WSF/PHP already have the custom headers support in the SVN and to be released with the 2.0.
Here is the generated API for the service business logic for the above WSDL.

/**
 * Service function echoString
 * @param string $input
 * @param object of Header1 $header_in0 input header
 * @param object of Header2 $header_in1 input header
 * @param reference object of Header1 $header_out0 output header
 * @param reference object of Header2 $header_out1 output header
 * @return string
 */
function echoString($input, $header_in0, $header_in1, &$header_out0, &$header_out1) {

...
}

These tool provides APIs to consume and provide data through custom headers in same easiness you send the data in the payload. Anyway it is really recommended to not to use custom SOAP headers in your Service and try to avoid them as much as possible. Whenever you think there is valid reason to put a custom header (it is relevant to QOS aspects), just try to integrate the header processing logic to the SOAP engine. In Axis2 C or Java you can write Axis2 modules for that. That will really speed up the processing of your service and give consumers a well-designed API.

Here are some list of links that you may find useful to start working with Axis2/C ADB Codegen tool.

  1. Building Axis2/C Web Services with the help of Axis2/Java Tools (Tutorial)
  2. Codegen + ADB Samples (SVN)
  3. 20+ Test cases, how different schemas are constructed in ADB/C
  4. Helper tools to generate demo codes for Axis2/C ADB generated code (Blog)
  5. How Axis2/C ADB Codegen support nillable and minOccurs=0 (Blog)
  6. Simple Type List Support (Blog)
  7. Overview of using Axis2/C ADB (Blog)
  8. adb with base64Binary and xmime.xsd – little howto (Mail)
  9. Latest developers discussion on Axis2/C codegen tool (Mail)
  10. Past User inquiries on Axis2/C Adb Codegen tool (Mail)

© 2007 Dimuthu’s Blog | iKon Wordpress Theme by Windows Vista Administration | Powered by Wordpress