Skip to main content

Web services programming tips and tricks: Build a SOAP response envelope with SAAJ and JAX-RPC

Andre Tost (atost@us.ibm.com), Senior Certified IT Specialist, IBM Software Group
Andre Tost works as a Solution Architect in the WebSphere Business Development group, where he helps IBM Strategic Alliance partners integrate their applications with WebSphere Studio. His special focus is on Web services technology throughout the WebSphere product family. Before his current assignment, he spent ten years in various development and architecture roles in IBM software development, most recently for the WebSphere Business Components product. Originally from Germany, he now lives and works in Rochester, Minnesota. In his spare time, he likes to spend time with his family and play and watch soccer whenever possible. You can reach Andre at atost@us.ibm.com.

Summary:  This tip follows up on a previous tip, "Using the <xsd:any/> element for custom serialization," that described the use of the <xsd:any/> element for custom serialization. While the earlier tip focused on reading and processing a javax.xml.soap.SOAPElement, here the author describes how to create one.

Date:  17 Aug 2004
Level:  Advanced
Activity:  3691 views
Comments:  

In the tip "Using the <xsd:any/> element for custom serialization," (see Resources), I described how you can use the <xsd:any/> element for custom serialization, and how to map this element to a Java object of type javax.xml.soap.SOAPElement. The code example showed how a client can use this interface to manually parse a response that was returned from an existing Web service. In this tip, I focus on the server side. I describe how you can create a response message in a Web service implementation class using the SOAP API for Attachments in Java (SAAJ).

Revisiting the <xsd:any/> element

Let me briefly discuss again how the <xsd:any/> element can help with custom creation and parsing of SOAP messages. This element represents any arbitrary XML content in an XML Schema. In other words, you can think of it as a wildcard in your schema. A JAX-RPC engine cannot know what this content will look like at runtime and hence passes it to the server or client as an instance of one of the core SAAJ interfaces, javax.xml.soap.SOAPElement. You can leverage this behavior by replacing those elements in your schema that you want to process through SAAJ with <xsd:any/>. Typically, you would only do this replacement for the sake of generating the right kind of JAX-RPC helper code, and eventually keep the original version of the schema in your WSDL file.

JAX-RPC version 1.1 mandates that a compliant engine offer tooling that lets the user select whether or not type-mapping should take place. This results in a similar effect as when using the <xsd:any/> element, namely that the engine doesn't try to map XML content into Java content and vice versa, but rather uses the javax.xml.soap.SOAPElement interface.

The following description of how to build a SOAP response message with SAAJ applies equally for both.


The Service Endpoint Interface

In JAX-RPC, each Web service is represented by a Service Endpoint Interface (SEI). It basically maps a WSDL portType into Java types, letting you either consume a Web service through a local Java proxy class or provide a Web service by implementing the SEI.

You can easily detect if SAAJ is to be used for a Web service through any occurrence of the javax.xml.soap.SOAPElement in the SEI. If a method on the SEI uses this interface as an input parameter, it means that the incoming SOAP request message is not mapped into Java types. If a method returns an instance of javax.xml.soap.SOAPElement, it means that the response message is not mapped, respectively.

In this example, you can generate two different SEI's, one for the server side using javax.xml.soap.SOAPElement, and one for the client side using Java type mapping. I focus only on the server side here, but you can download the entire example, including the client, by clicking on the Code icon at the top or bottom of this tip.

Here is an extract from the WSDL file that is used to generate the Service Endpoint Interface:


Listing 1. WSDL extract using the <xsd:any/> element
<wsdl:types>
   <schema elementFormDefault="qualified" 
           targetNamespace="http://any.webservices.ibm.com" 
           xmlns="http://www.w3.org/2001/XMLSchema">
      <element name="getOrder">
         <complexType>
            <sequence>
               <element name="searchCriteria" nillable="true" type="xsd:string"/>
            </sequence>
         </complexType>
      </element>
      <element name="getOrderResponse">
         <complexType>
            <sequence>
               <xsd:any maxOccurs="unbounded"/>
            </sequence>
         </complexType>
      </element>
   </schema>
</wsdl:types>

Note that the response message contains only one element, namely the <xsd:any/>. Here is the SEI:


Listing 2. The Service Endpoint Interface
package com.ibm.webservices.any;

import javax.xml.soap.SOAPElement;

public interface OrderManager extends java.rmi.Remote {
    public SOAPElement[] getOrder(java.lang.String searchCriteria) throws 
    java.rmi.RemoteException;
}

As you can see, the response is sent back as an array of javax.xml.soap.SOAPElement instances.


The response message

Before taking a closer look at the service implementation, I describe the structure of the SOAP message that you can create in that implementation. Remember that there is no way to derive the structure of the message from the WSDL extract that I listed above. This definition is contained in the original XML Schema, which you add to the WSDL file before generating the client code:


Listing 3. The complete XML Schema
 <wsdl:types>
  <schema elementFormDefault="qualified" targetNamespace=
  "http://any.webservices.ibm.com" xmlns="http://www.w3.org/2001/XMLSchema">
   <element name="getOrder">
    <complexType>
     <sequence>
      <element name="searchCriteria" nillable="true" type="xsd:string"/>
     </sequence>
    </complexType>
   </element>
   <complexType name="Order">
    <sequence>
     <element name="createDate" nillable="true" type="xsd:dateTime"/>
     <element name="customer" nillable="true" type="xsd:string"/>
     <element maxOccurs="unbounded" name="lineItems" nillable="true" type=
     "impl:LineItem"/>
    </sequence>
   </complexType>
   <complexType name="LineItem">
    <sequence>
     <element name="itemDesc" nillable="true" type="xsd:string"/>
     <element name="itemNumber" nillable="true" type="xsd:string"/>
    </sequence>
   </complexType>
   <element name="getOrderResponse">
    <complexType>
     <sequence>
      <element name="getOrderReturn" nillable="true" type="impl:Order"/>
     </sequence>
    </complexType>
   </element>
  </schema>
 </wsdl:types>

And here is an example SOAP response message that follows the schema above:


Listing 4. A Sample SOAP message
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<getOrderResponse xmlns="http://any.webservices.ibm.com">
<getOrderReturn>
      <createDate>2004-07-03T22:57:45.359Z</createDate>
      <customer>Bill Smith</customer>
      <lineItems>
<itemDesc>This is a line item</itemDesc>
<itemNumber>12345</itemNumber>
      </lineItems>
</getOrderReturn>
</getOrderResponse>
</soapenv:Body>
</soapenv:Envelope>

This is the message that you create in the service implementation class.


The Web service implementation

Typically, the JAX-RPC tool that generates the SEI from the WSDL file also generates a skeleton for the actual service implementation. In the implementation, you need to create the javax.xml.soap.SOAPElement instances that the SEI defines. This leads you deeper into the realm of SAAJ programming.

Here I walk you through each step that is required to build the appropriate response elements. Instances of javax.xml.soap.SOAPElement are created through a factory of type javax.xml.soap.SOAPFactory, so you need to create the factory first. Morever, each element needs a name, which in SAAJ is represented by the javax.xml.soap.Name interface. Name instances are not created through the factory, but instead you need an instance of javax.xml.soap.SOAPEnvelope for this. This instance is again created through a factory, namely one of type javax.xml.soap.MessageFactory. To answer what you are probably asking: yes, you really do need three different factories before you can start creating the actual elements.


Listing 5. Creating SAAJ factory instances
...
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();	
		
SOAPFactory factory = SOAPFactory.newInstance();
...

Now you are ready to create the content of the response message. Note that much of this code is repetitive and you could easily write it more efficiently than shown here. I also do not insert any kind of error handling in this example, but omitting it would be inappropriate for any production level code:


Listing 6. Creating SAAJ elements
...
// use the factory to create a new element
// the Name is created via the SOAPEnvelope, and we must define a 
// namespace for each element in the body (to be WS-I compliant)
SOAPElement getOrderReturn = factory.createElement(envelope.createName(
"getOrderReturn", "","http://any.webservices.ibm.com"));

// now start adding children and build the full response message
// hardcode the text content for the sakes of simplicity
SOAPElement createDate = getOrderReturn.addChildElement(envelope.createName(
"createDate", "", "http://any.webservices.ibm.com"));
createDate.addTextNode("2004-07-03T22:57:45.359Z");
SOAPElement customer = 
getOrderReturn.addChildElement(envelope.createName(
"customer", "", "http://any.webservices.ibm.com"));
customer.addTextNode("Bill Smith");
SOAPElement lineItems = 
getOrderReturn.addChildElement(envelope.createName(
"lineItems", "", "http://any.webservices.ibm.com"));
SOAPElement itemDesc = 
lineItems.addChildElement(envelope.createName(
"itemDesc", "", "http://any.webservices.ibm.com"));
itemDesc.addTextNode("This is a line item");
SOAPElement itemNumber = 
lineItems.addChildElement(envelope.createName(
"itemNumber", "", "http://any.webservices.ibm.com"));
itemNumber.addTextNode("12345");
...

Finally, you add the element named getOrderReturn to an array of javax.xml.soap.SOAPElement (remember that you defined the <xsd:any/> element with a maxOccurs attribute value of "unbounded"):


Listing 7. Building the return array
...
SOAPElement[] elements = new SOAPElement[1];
elements[0] = getOrderReturn;
return elements;
...


Creating a response from an existing DOM document

In many cases, you want to create a service implementation that does not build the response message one element at a time, but rather takes advantage of an already existing XML document that might have been retrieved from an existing backend. In this case, you wouldn't want to parse that existing piece of XML, simply to construct it back into a new XML message.

The SAAJ 1.2 specification introduced a new method on the javax.xml.soap.SOAPBody interface called addDocument(). Moreover, as of SAAJ 1.2 (which is also included in J2EE version 1.4), several of the SAAJ interfaces inherit from the respective DOM interface. For example, javax.xml.soap.SOAPElement extends the org.w3c.dom.Element interface, letting you use regular DOM programming to build your message. Since there is no widespread support for SAAJ 1.2 in the market yet, I used SAAJ 1.1 interfaces above.


Summary

The SAAJ specification defines interfaces and classes that let you build a SOAP message from scratch. You can use this to avoid using any type mapping from XML to and from Java types as defined in JAX-RPC. The typical use case for this is in cases where custom (de-)serialization is needed (for example, if the XML Schema for the required message is not fully supported by your JAX-RPC engine), or when existing code already handles XML artifacts, making type mapping obsolete or at least redundant.

This tip showed an example for a server-side service implementation that builds its response message in an element-wise manner. SAAJ 1.2 introduces additional methods to make handling of existing XML parts easier.



Download

NameSizeDownload method
ws-saajcode.ear HTTP

Information about download methods


Resources

  • Read the first tip, "Using the <xsd:any/> element for custom serialization," describing the use of the <xsd:any/> element (developerWorks, January 2004).

  • Get hands on training on the use of SAAJ in the tutorial "SAAJ" (Sun Developer Network).

  • Find a number of tips related to Web services programming on developerWorks.

  • Get the WS-I Basic Profile from the Web Services Interoperability Organization Web site.

  • Access Web services knowledge, tools, and skills with Speed-start Web services, which offers the latest Java-based software development tools and middleware from IBM (trial editions), plus online tutorials and articles, and an online technical forum.

  • Browse for books on these and other technical topics.

  • Want more? The developerWorks SOA and Web services zone hosts hundreds of informative articles and introductory, intermediate, and advanced tutorials on how to develop Web services applications.

About the author

Andre Tost works as a Solution Architect in the WebSphere Business Development group, where he helps IBM Strategic Alliance partners integrate their applications with WebSphere Studio. His special focus is on Web services technology throughout the WebSphere product family. Before his current assignment, he spent ten years in various development and architecture roles in IBM software development, most recently for the WebSphere Business Components product. Originally from Germany, he now lives and works in Rochester, Minnesota. In his spare time, he likes to spend time with his family and play and watch soccer whenever possible. You can reach Andre at atost@us.ibm.com.

Comments



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services
ArticleID=15059
ArticleTitle=Web services programming tips and tricks: Build a SOAP response envelope with SAAJ and JAX-RPC
publish-date=08172004
author1-email=atost@us.ibm.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers