SAAJ: SOAP with Attachments API for Java

Abstract

The SOAP with Attachments API for Java (SAAJ) provides a standard way to send XML documents over the Internet from the Java platform. It is an API you can use to write SOAP messaging applications directly rather than using the JAX-RPC. By simple making method calls using SAAJ API, you can read and write SOAP-based XML messages, and you can optionally send and receive these types of messages over the Internet. SAAJ also provides a way to send contents that is not in XML format as attachments of a SOAP message.

Introduction

The SOAP with Attachments API for Java (SAAJ) provides a standard way to send XML documents over the Internet from the Java platform. It provides a convenient API for constructing SOAP messages without having to directly crete the XML by yourself. You can use the SAAJ API to write SOAP messaging applications directly rather than using the JAX-RPC. By simple making method calls using SAAJ API, you can communicate with other web services directly by using SOAP-based XML messages, and you can optionally send and receive these types of messages over the Internet.

The SAAJ API conforms to the Simple Object Access Protocol (SOAP) 1.1 specification and the SOAP with Attachments specification. It is one of the two packages for XML messaging:


  • create a point-to-point connection to a specified endpoint
  • create a SOAP message
  • create an XML fragment
  • add content to the header of a SOAP message
  • add content to the body of a SOAP message
  • create attachment parts and add content to them
  • access/add/modify parts of a SOAP message
  • create/add/modify SOAP fault information
  • extract content from a SOAP message
  • send a SOAP request-response message

Originally, both packages were defined in the JAXM 1.0 specification. The javax.xml.soap package has been separated out and expanded into the SAAJ 1.1 specification so that now it has no dependencies on the javax.xml.messaging package and thus can be used independently. Among other things, SAAJ added the API for creating XML fragments, which makes it especially helpful for developing JAX-RPC applications.  The SAAJ API belongs to javax.xml.soap.* package.

The javax.xml.messaging package, defined in the JAXM 1.1 specification, maintains its dependency on the java.xml.soap package because the soap package contains the API used for creating and manipulating SOAP messages. This means that the SAAJ API can be used by itself, but the JAXM API cannot be used unless the SAAJ API is present.

Using SAAJ, a client can create and send SOAP messages in a point-to-point model. SAAJ clients can only engage in synchronous request/response message exchanges. JAXM defines the API for xml messaging using a messaging provider have access to additional message exchange modes such as asynchronous messaging. JAXM depends on the SOAP with Attachments API for Java (SAAJ), which defines the API for operating on the SOAP with attachments message model in Java.

Please reference to Sun J2EE 1.4 Tutorial Document for more detail about SAAJ.



Types of SAAJ Messages

SAAJ messages follow SOAP standards, which prescribe the format for messages and also specify some things that are required, optional, or not allowed. With the SAAJ API, you can create XML messages that conform to the SOAP specifications simply by making Java API calls. There are two types of SOAP messages that you should be familiar with: those with attachments, and those without attachments. Each of these makes use of the classes inside of the javax.xml.soap package. The simpler of these two are SOAP messages without attachments. The figures showing in this pages come from Sun J2EE 1.4 Tutorial Document.

Messages Without Attachments

A SOAP message that does not have attachments has a structure made up of a SOAP part, a SOAP envelope, an optional SOAP header, and a SOAP body.

SOAP message without attachments

There is a SAAJ class for the entire SOAP message, as well as for each component of the structure. The javax.xml.soap.SOAPMessage class represents a SOAP message, the javax.xml.soap.SOAPPart class represents a SOAP part, the javax.xml.soap.SOAPEnvelope interface represents the SOAP envelope, and so on. When you create a new SOAPMessage object, it automatically creates any subclasses that are required to be in a SOAP message. For example, a new SOAPMessage object has a SOAPPart object that, in turn, contains a SOAPEnvelope object. The SOAPEnvelope object then automatically creates an empty SOAPHeader object followed by an empty SOAPBody object.

The SOAPHeader object can include one or more headers that contain metadata about the message (for example, information about the sending and receiving parties). However, the SOAPHeader object is optional -- it's created by default, but it can be deleted if not needed.

The SOAPBody object, which always follows the SOAPHeader object (if there is one), contains the message content. Another object that may be included in the SOAP message structure is the SOAPFault object. This object contains error and status information. If there is a SOAPFault object, it must be in the SOAPBody object.

Messages With Attachments

A SOAP message can include one or more attachment parts in addition to the SOAP part. The SOAP part must contain only XML content. As a result, if any content in a message is not in XML format, it must be contained in an attachment part. For example, if you want a SOAP message to contain a binary file, the message must have an attachment part for it. An attachment part can contain any kind of content, so it can contain data in XML format as well.

SOAP message with attachments

SAAJ provides the javax.xml.soap.AttachmentPart class to represent an attachment part of a SOAP message. A SOAPMessage object automatically has a SOAPPart object and its required subelements, but because AttachmentPart objects are optional, you have to create and add them yourself. If a SOAPMessage object has one or more attachments, each AttachmentPart object must have a MIME header to indicate the type of data it contains. The AttachmentPart object can also have additional MIME headers to identify it or to give its location. These headers are optional, but can be useful when there are multiple attachments. When a SOAPMessage object has one or more AttachmentPart objects, its SOAPPart object may (or may not) contain message content.


Summary


The SOAPMessage consists of a SOAPPart and zero or more AttachmentPart objects. The SOAPPart represents the SOAP document and includes the SOAPEnvelope objects. The SOAPEnvelope represents the Envelope element in the SOAP document and contains SOAPHeader object and SOAPBody object which represents the Header and Body elements in the SOAP document.  The SOAP part may contain only XML content, The AttachmentPart object, which is a MIME attachment and represents the attachment of a SOAP message, allows the SOAP Message to contain not only the XML data but also non-XML data such as GIFs and PDFs.  And it uses the MIME multipart as container for these non-XML data. The SOAPMessage object automatically has a SOAPPart object and its required subelements, but because AttachmentPart objects are optional, you have to create and add them by yourself.



Send/Receive SOAP  Message with  SAAJ


A SOAP message can be created and sent manually, but SAAJ provides a set of API, such as creating connections or creating and sending the actual SOAP message, to simplify the process for developers.


There are five steps involves to send and receive SOAP message used SAAJ APIs:

  1. Creating a SOAP Connection
  2. Creating  a SOAP message
  3. Populating the meassge
  4. Sending/Receiving SOAP messages
  5. Working with the reply message

Creating a SOAP Connection

The SAAJ API is focused primarily on creating messages. Once you have a message, you can send it using various mechanisms (JMS or JAXM, for example). The SAAJ API does, however, provide a simple mechanism for request-response messaging.  In SAAJ, SOAP messages are sent and received over SOAPConnection object. The connection that the SOAPConnection object represents goes from the sender directly to its destination (typically using an HTTP Post). This kind of connection is called a point-to-point connection because it makes a one-way trip from one endpoint to another endpoint.

import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPBody;
import java.net.URL;

public SimpleSAAJ {

    public static void main(String args[]) {

       try {   
           //Create a SOAPConnection   
           SOAPConnectionFactory factory =
                    SOAPConnectionFactory.newInstance();

           SOAPConnection connection =
                    factory.createConnection();
 
           .................
 
 
           // Close the SOAPConnection
           connection.close();

       } catch (Exception e) {
           System.out.println(e.getMessage());
       }
  }
}

A connection can use a lot of resource, so it's a good idea to close a connection as soon as you are finished using it.

Creating a SOAP Message

If you successfully create a SOAPConnection object,  you need to prepare an outgoing SOAP message. To a create a SOAPMessage object, you first need to create a MessageFactory object by invoking the static newInstance() method of the MessageFactory abstract class. The MessageFactory class itself is abstract and cannot be instantiated. Its newInstance() method creates a new MessageFactory object that is an instance of the default implementation. SAAJ provides a default implementation of the MessageFactory class that makes it easy to get an instance of the class.

The following code fragment illustrates getting an instance of the default message factory, and then using it to create a message:

   SOAPMessageFactory messageFactory = MessageFactory.newInstance();
   SOAPMessage message = messageFactory.createMessage();

All MessageFactory objects, regardless of how they are created, will produce SOAPMessage objects that have the following elements by default:

The two lines in the previous code fragment produce the following XML message:

   <SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
     <SOAP-ENV:Header/>
     <SOAP-ENV:Body>
       . . .
     </SOAP-ENV:Body>
   </SOAP-ENV:Envelope>

The SOAPHeader object is optional and may be deleted if it is not needed. However, if there is one, it must precede the SOAPBody object. The SOAPBody object can hold the content of the message and can also contain fault messages that contain status information or details about a problem with the message. The SOAPFault object must be in the SOAPBody object. You can access the SOAP elements by using the following two ways:

   SOAPMessageFactory messageFactory = MessageFactory.newInstance();
   SOAPMessage message = messageFactory.createMessage();
   SOAPHeader header = message.getSOAPHeader();
   SOAPBody body = message.getSOAPBody();
   header.detachNode();

   SOAPMessageFactory messageFactory = MessageFactory.newInstance();
   SOAPMessage message = messageFactory.createMessage();
   SOAPPart  soapPart = messge.getSOAPPart();
   SOAPEnvelope envelope = soapPart.getEnvelope();
   SOAPHeader header = envelope.getHeader();
   SOAPBody body = envelope.getBody();
   header.detachNode();


MessageFactory
objects can be initialized with a JAXM profile. In such a case it will produce messages that also come prepopulated with additional entries in the SOAPHeader object and the SOAPBody object. The content of a new SOAPMessage object depends on which of the two MessageFactory methods is used to create it.


import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPBody;
import java.net.URL;

public SimpleSAAJ {

    public static void main(String args[]) {

       try {   
           //Create a SOAPConnection   
           SOAPConnectionFactory factory =
                    SOAPConnectionFactory.newInstance();

           SOAPConnection connection =
                    factory.createConnection(); 
 
           //Create a SOAPMessage
           SOAPMessageFactory messageFactory = MessageFactory.newInstance();
           SOAPMessage message = messageFactory.createMessage();
           SOAPPart  soapPart = messge.getSOAPPart();
           SOAPEnvelope envelope = soapPart.getEnvelope();
           SOAPHeader header = envelope.getHeader();
           SOAPBody body = envelope.getBody();
           header.detachNode();
 
            .................
  

           // Close the SOAPConnection
           connection.close();

       } catch (Exception e) {
           System.out.println(e.getMessage());
       }
  }
}

The above example shows a SAAJ client does not use a SOAP header, so the last line of code header.detachNode() deletes the header element.  The code fragments produce the following XML message:

   <SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
     <SOAP-ENV:Body>
       . . .
     </SOAP-ENV:Body>
   </SOAP-ENV:Envelope>



Populating SOAP Message


The new SAAJ message has an empty body by default. To add content to the body, you need to create a SOAPBodyElement object to hold the content. When you create an application-specific element, you also need to create an associated Name object so that it is uniquely identified.  A SAAJ interface called Name is provided to wrap an XML name and its namespace, in a way that is more convenient than DOM allows.

Name objects associated with SOAPBodyElement or SOAPHeaderElement objects MUST BE fully qualified; that is, they must be created with a local name, a prefix for the namespace being used, and a URI for the namespace. Specifying a namespace for an element makes clear which one is meant if there is more than one element with the same local name.

One way to create Name objects is by using SOAPEnvelope methods, so you can use the variable envelope from the previous code fragment to create the Name object for your new element.

SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
SOAPBody     body     = envelope.getBody();
 

Name         bodyName = envelope.createName("GetLastTradePrice",
                              "m", "http://wombat.ztrade.com");
SOAPBodyElement bodyElement = body.addBodyElement(bodyName);

The above code fragment produces the following SOAP message:

<SOAP-ENV:Envelope
   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>
    <m:GetLsatTradePrice xmlns:m="http://wombat.ztrade.com"/>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

At this point, body contains a SOAPBodyElement object identified by the Name object bodyName. In this case, GetLastTradePrice is the element's local name, m is its namespace prefix, and http://wombat.ztrade.com is its namespace URI.  

There is still no content in bodyElement. Assuming that you want to get a quote for the stock of Sun Microsystems, Inc., you need to create a child element for the symbol using the method addChildElement. Then you need to give it the stock symbol using the method addTextNode. The Name object for the new SOAPElement object symbol is initialized with only a local name because child elements inherit the prefix and URI from the parent element.

import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPBody;
import java.net.URL;

public SimpleSAAJ {

    public static void main(String args[]) {

       try {   
           //Create a SOAPConnection   
           SOAPConnectionFactory factory =
                    SOAPConnectionFactory.newInstance();

           SOAPConnection connection =
                    factory.createConnection(); 
 
           //Create a SOAPMessage
           SOAPMessageFactory messageFactory = MessageFactory.newInstance();
           SOAPMessage message = messageFactory.createMessage();
           SOAPPart  soapPart = messge.getSOAPPart();
           SOAPEnvelope envelope = soapPart.getEnvelope();
           SOAPHeader header = envelope.getHeader();
           SOAPBody body = envelope.getBody();
           header.detachNode();
 
           //Create a SOAPBodyElement
           Name bodyName = envelope.createName("GetLastTradePrice"
                              "m", "http://wombat.ztrade.com");
           SOAPBodyElement bodyElement = body.addBodyElement(bodyName);
           //Insert Content
           Name name = envelope.createName("symbol");
           SOAPElement symbol = bodyElement.addChildElement(name);
           symbol.addTextNode("SUNW");
 
               .................
  
           // Close the SOAPConnection
           connection.close();

       } catch (Exception e) {
           System.out.println(e.getMessage());
       }
  }
}

The above code fragment produces the following SOAP message:

<SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>
    <m:GetLastTradePrice xmlns:m="http://wombat.ztrade.com">
       <symbol>SUNW</symbol>
    </m:GetLastTradePrice>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Another way to create Name objects is to use SOAPFactory methods, which are useful if you do not have access to the SOAPEnvelope. The following code fragment is rewrote the previous code fragment:

SOAPMessageFactory messageFactory =
                          SOAPMessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
SOAPBody    body = message.getSOAPBody();
SOAPFactory soapFactory = SOAPFactory.newInstance();
 
//Create a SOAPBodyElement
Name bodyName = soapFactory.createName("GetLastTradePrice",
                            "m", "http://wombat.ztrade.com");
SOAPBodyElement bodyElement = body.addBodyElement(bodyName);
//Insert Content
Name name = soapFactory.createName("symbol");
SOAPElement symbol = bodyElement.addChildElement(name);
symbol.addTextNode("SUNW");

iThe above code fragment produces the same SOAP message as using SOAPEnvelope methods.

The SOAPFactory class also lets you create XML elements when you are not creating an entire message or do not have access to a complete SOAPMessage object. For example, JAX-RPC implementations often work with XML fragments rather than complete SOAPMessage objects. Consequently, they do not have access to a SOAPEnvelope object, which makes using a SOAPFactory object to create Name objects very useful. In addition to a method for creating Name objects, the SOAPFactory class provides methods for creating Detail objects and SOAP fragments.

SOAPElement and its derived classes (SOAPHeaderElement, SOAPBodyElement) can not create any XML elements, they only provide “ADD” methods. The SOAPBody and SOAPHeader classes can not create XML elements either and only have “ADD” methods too.

Sending/Receiving SOAP messsages

A typical message sent using SAAJ is a request-response message. This type of message is sent over a SOAPConnection object, using the call() method (a request). The call blocks until it receives the reply (a response).

import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPBody;
import java.net.URL;

public SimpleSAAJ {

    public static void main(String args[]) {

       try {   
           //Create a SOAPConnection   
           SOAPConnectionFactory factory =
                    SOAPConnectionFactory.newInstance();

           SOAPConnection connection =
                    factory.createConnection(); 
 
           //Create a SOAPMessage
           SOAPMessageFactory messageFactory = MessageFactory.newInstance();
           SOAPMessage message = messageFactory.createMessage();
           SOAPPart  soapPart = messge.getSOAPPart();
           SOAPEnvelope envelope = soapPart.getEnvelope();
           SOAPHeader header = envelope.getHeader();
           SOAPBody body = envelope.getBody();
           header.detachNode();
 
           //Create a SOAPBodyElement
           Name bodyName = envelope.createName("GetLastTradePrice"
                              "m", "http://wombat.ztrade.com");
           SOAPBodyElement bodyElement = body.addBodyElement(bodyName);
           //Insert Content
           Name name = envelope.createName("symbol");
           SOAPElement symbol = bodyElement.addChildElement(name);
           symbol.addTextNode("SUNW");
 
           // Create an endpint point which is either URL or String type
           URL endpoint = new URL("http://wombat.ztrade.com/quotes");
          
           //Send a SOAPMessage (request) and then wait for SOAPMessage (response)
           SOAMessage response= connection.call(message, endpoint);

           // Close the SOAPConnection
           connection.close();

       } catch (Exception e) {
           System.out.println(e.getMessage());
       }
  }
}

A SAAJ client calls the SOAPConnection method call on a SOAPConnection object to send a message. The second argument to the call() method identifies where the message is being sent. The argument can be a String object or a URL object.

Any web service implemented for request-response messaging must be able to handle HTTP Post requests, and must return a response to a message it receives. The response must be a SOAPMessage object, just as the request must be a SOAPMessage object. This allows you to access the content of a response with the same methods that you used to create the message. Note that some messages might not require any response. The service that gets such a message is still required to send back a response because one is needed to unblock the call() method.


Working with the Reply SOAP Message


The initial steps for retrieving a message's content are the same as those for giving content to a message: Either you use the Message object to get the SOAPBody object, or you access the SOAPBody object through the SOAPPart and SOAPEnvelope objects.

Then you access the SOAPBody object's SOAPBodyElement object, because that is the element to which content was added in the example. (In a later section you will see how to add content directly to the SOAPPart object, in which case you would not need to access the SOAPBodyElement object for adding content or for retrieving it.)

To get the content, which was added with the method SOAPElement.addTextNode, you call the method Node.getValue. Note that getValue returns the value of the immediate child of the element that calls the method. Therefore, in the following code fragment, the method getValue is called on bodyElement, the element on which the method addTextNode was called.

In order to access bodyElement, you need to call the method getChildElements on soapBody. Passing bodyName to getChildElements returns a java.util.Iterator object that contains all of the child elements identified by the Name object bodyName. You already know that there is only one, so just calling the method next on it will return the SOAPBodyElement you want. Note that the method Iterator.next returns a Java Object, so it is necessary to cast the Object it returns to a SOAPBodyElement object before assigning it to the variable bodyElement.

SOAPBody soapBody = response.getSOAPBody();
java.util.Iterator iterator = soapBody.getChildElements(bodyName);
SOAPBodyElement bodyElement = (SOAPBodyElement)iterator.next();
String lastPrice = bodyElement.getValue();
System.out.print("The last price for SUNW is ");
System.out.println(lastPrice);

i

If there were more than one element with the name bodyName, you would have had to use a while loop using the method Iterator.hasNext to make sure that you got all of them.

while (iterator.hasNext()) {
  SOAPBodyElement bodyElement = (SOAPBodyElement)iterator.next();
  String lastPrice = bodyElement.getValue();
  System.out.print("The last price for SUNW is ");
  System.out.println(lastPrice);
}

At this point, you have seen how to send a very basic request-response message and get the content from the response.




Maniplate SOAP Message with SAAJ



Manipulating Message Content Using SAAJ or DOM APIs


Because SAAJ nodes and elements implement the DOM Node and Element interfaces, you have many options for adding or changing message content:

The first three of these cause no problems. Once you have created a message, whether or not you have imported its content from another document, you can start adding or changing nodes using either SAAJ or DOM APIs.

But if you use DOM APIs and then switch to using SAAJ APIs to manipulate the document, any references to objects within the tree that were obtained using DOM APIs are no longer valid. If you must use SAAJ APIs after using DOM APIs, you should set all of your DOM typed references to null, because they can become invalid. For more information about the exact cases in which references become invalid, see the SAAJ API documentation.

The basic rule is that you can continue manipulating the message content using SAAJ APIs as long as you want to, but once you start manipulating it using DOM, you should not use SAAJ APIs after that.

How to Add Content to the SOAPHeader Object?

To add content to the header, you need to create a SOAPHeaderElement object. As with all new elements, it must have an associated Name object, which you can create using the message's SOAPEnvelope object or a SOAPFactory object.

For example, suppose you want to add a conformance claim header to the message to state that your message conforms to the WS-I Basic Profile 1.0.

The following code fragment retrieves the SOAPHeader object from message and adds a new SOAPHeaderElement object to it. This SOAPHeaderElement object contains the correct qualified name and attribute for a WS-I conformance claim header.

SOAPHeader header = message.getSOAPHeader();
 
Name headerName = soapFactory.createName("Claim",
             "wsi", "http://ws-i.org/schemas/conformanceClaim/");
 
SOAPHeaderElement headerElement = header.addHeaderElement(headerName);
 
Name conformsToName = soapFactory.createName("conformsTo");
 
headerElement.addAttribute(conformsToName,"http://ws-i.org/profiles/basic1.0/");

At this point, header contains the SOAPHeaderElement object headerElement identified by the Name object headerName. Note that the addHeaderElement method both creates headerElement and adds it to header.

A conformance claim header has no content.

This code produces the following XML header:

<SOAP-ENV:Header>
  <wsi:Claim conformsTo="http://ws-i.org/profiles/basic1.0/"
   xmlns:wsi="http://ws-i.org/schemas/conformanceClaim/"/>
</SOAP-ENV:Header>

For more information about creating SOAP messages that conform to WS-I Basic Profile 1.0, see the Messaging section of the WS-I Basic Profile 1.0.

For a different kind of header, you might want to add content to headerElement. The following line of code uses the method addTextNode to do this.

headerElement.addTextNode("order");

Now you have the SOAPHeader object header that contains a SOAPHeaderElement object whose content is "order".

How to Add Content to the SOAPBody Object?

The process for adding content to the SOAPBody object is the same as the process for adding content to the SOAPHeader object. You access the SOAPBody object, add a SOAPBodyElement object to it, and add text to the SOAPBodyElement object. It is possible to add additional SOAPBodyElement objects, and it is possible to add subelements to the SOAPBodyElement objects with the method addChildElement. For each element or child element, you add content with the method addTextNode.

An example shows adding multiple SOAPElement objects and adding text to each of them can be found in Populating SOAP Message sub-section in the previous section.br>

How to Add Content to the SOAPPart Object?

If the content you want to send is in a file, SAAJ provides an easy way to add it directly to the SOAPPart object. This means that you do not access the SOAPBody object and build the XML content yourself, as you did in the previous section.

To add a file directly to the SOAPPart object, you use a javax.xml.transform.Source object from JAXP (the Java API for XML Processing). There are three types of Source objects: SAXSource, DOMSource, and StreamSource. A StreamSource object holds content as an XML document. SAXSource and DOMSource objects hold content along with the instructions for transforming the content into an XML document.

The following code fragment uses the JAXP API to build a DOMSource object that is passed to the SOAPPart.setContent method. The first three lines of code get a DocumentBuilderFactory object and use it to create the DocumentBuilder object builder. Because SOAP messages use namespaces, you should set the NamespaceAware property for the factory to true. Then builder parses the content file to produce a Document object.

DocumentBuilderFactory dbFactory =  DocumentBuilderFactory.newInstance();
dbFactory.setNamespaceAware(true);
DocumentBuilder builder = dbFactory.newDocumentBuilder();
Document document =  builder.parse("file:///music/order/soap.xml");
DOMSource domSource = new DOMSource(document); 

The following two lines of code access the SOAPPart object (using the SOAPMessage object message) and set the new Document object as its content. The method SOAPPart.setContent not only sets content for the SOAPBody object but also sets the appropriate header for the SOAPHeader object.

SOAPPart soapPart= message.getSOAPPart();
soapPart.setContent(domSource);

The XML file you use to set the content of the SOAPPart object must include Envelope and Body elements, like this:

<SOAP-ENV:Envelope
      xmlns="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>
    ...
 
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

You will see other ways to add content to a message in the sections Adding a Document to the SOAP Body and Adding Attachments.

How to Add a Document to the SOAP Body?

In addition to setting the content of the entire SOAP message to that of a DOMSource object, you can add a DOM document directly to the body of the message. This capability means that you do not have to create a javax.xml.transform.Source object. After you parse the document, you can add it directly to the message body:

SOAPBody body = message.getSOAPBody();
SOAPBodyElement docElement = body.addDocument(document);

How to Add Attributes?

An XML element may have one or more attributes that give information about that element. An attribute consists of a name for the attribute followed immediately by an equals sign (=) and its value.

The SOAPElement interface provides methods for adding an attribute, for getting the value of an attribute, and for removing an attribute.

import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPBody;
import java.net.URL;

public SimpleSAAJ {

    public static void main(String args[]) {

       try {   
           //Create a SOAPConnection   
           SOAPConnectionFactory factory =
                    SOAPConnectionFactory.newInstance();

           SOAPConnection connection =
                    factory.createConnection(); 
 
           //Create a SOAPMessage
           SOAPMessageFactory messageFactory = MessageFactory.newInstance();
           SOAPMessage message = messageFactory.createMessage();
           SOAPPart  soapPart = messge.getSOAPPart();
           SOAPEnvelope envelope = soapPart.getEnvelope();
           SOAPHeader header = envelope.getHeader();
           SOAPBody body = envelope.getBody();
           header.detachNode();
 
           //Create a SOAPBodyElement
           Name bodyName = envelope.createName("GetLastTradePrice"
                              "m", "http://wombat.ztrade.com");
           SOAPBodyElement bodyElement = body.addBodyElement(bodyName);
           //Insert Content
           Name name = envelope.createName("symbol");
           SOAPElement symbol = bodyElement.addChildElement(name);
           symbol.addTextNode("SUNW");
           //Add countryCode attribute to the <symbol> element
           Name attributeName = envelope.createName("countryCode");
           symbol.addAttribute(attributeName, "US");

               .................
  
           // Close the SOAPConnection
           connection.close();

       } catch (Exception e) {
           System.out.println(e.getMessage());
       }
  }
}

The above code fragment produces the following SOAP message:

<SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>
    <m:GetLastTradePrice xmlns:m="http://wombat.ztrade.com">
       <symbol>SUNW</symbol>
    </m:GetLastTradePrice>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The symbol is a SOAPElement object rather than a SOAPBodyElement object or SOAPHeaderElement object; it is legal for its Name object to contain only a local name.

The following line of code retrieves the value of the attribute whose name is countryCode.

String attributeValue = 
person.getAttributeValue(attributeName);

If you had added two or more attributes to person, the previous line of code would have returned only the value for the given attribute named.

If you wanted to retrieve the values for all of the attributes under an element, you would use the method getAllAttributes, which returns an iterator over all of the values. The following lines of code retrieve and print out each value on a separate line until there are no more attribute values. Note that the method Iterator.next returns a Java Object, which is cast to a Name object so that it can be assigned to the Name object attributeName.

Iterator iterator = person.getAllAttributes();
while (iterator.hasNext()){
  Name attributeName = (Name) iterator.next();
 
  System.out.println("Attribute name is " +                        
                     attributeName.getQualifiedName());
 
  System.out.println("Attribute value is " +
    element.getAttributeValue(attributeName));
}

 

The following line of code removes the attribute named id from person. The variable successful will be true if the attribute was removed successfully.

boolean successful = symbol.removeAttribute(attributeName);

In this section you saw how to add, retrieve, and remove attributes. This information is general in that it applies to any element.

Header Attributes

Attributes that appear in a SOAPHeaderElement object determine how a recipient processes a message. You can think of header attributes as offering a way to extend a message, giving information about such things as authentication, transaction management, payment, and so on. A header attribute refines the meaning of the header, while the header refines the meaning of the message contained in the SOAP Body.

The SOAP 1.1 specification defines two attributes that can appear only in SOAPHeaderElement objects: actor and mustUnderstand. The next two sections discuss these attributes.

The Actor Attribute

The attribute actor is optional, but if it is used, it must appear in a SOAPHeaderElement object. Its purpose is to indicate the recipient of a header element. The default actor is the message's ultimate recipient; that is, if no actor attribute is supplied, the message goes directly to the ultimate recipient.

An actor is an application that can both receive SOAP messages and forward them to the next actor. The ability to specify one or more actors as intermediate recipients makes it possible to route a message to multiple recipients and to supply header information that applies specifically to each of the recipients.

For example, suppose that a message is an incoming purchase order. Its SOAPHeader object might have SOAPHeaderElement objects with actor attributes that route the message to applications that function as the order desk, the shipping desk, the confirmation desk, and the billing department. Each of these applications will take the appropriate action, remove the SOAPHeaderElement objects relevant to it, and send the message on to the next actor.

An actor is identified by its URI. For example, the following line of code, in which orderHeader is a SOAPHeaderElement object, sets the actor to the given URI.

orderHeader.setActor("http://gizmos.com/orders");

Additional actors may be set in their own SOAPHeaderElement objects. The following code fragment first uses the SOAPMessage object message to get its SOAPHeader object header. Then header creates four SOAPHeaderElement objects, each of which sets its actor attribute.

SOAPHeader header= message.getSOAPHeader();
SOAPFactory soapFactory = SOAPFactory.newInstance();
String nameSpace = "ns";
String nameSpaceURI = "http://gizmos.com/NSURI";
 
Name order = soapFactory.createName("orderDesk",                       
                       nameSpace, nameSpaceURI);
 
SOAPHeaderElement orderHeader = header.addHeaderElement(order);
 
orderHeader.setActor("http://gizmos.com/orders");
 
Name shipping = soapFactory.createName("shippingDesk",
                  nameSpace, nameSpaceURI);
 
SOAPHeaderElement shippingHeader = header.addHeaderElement(shipping);
shippingHeader.setActor("http://gizmos.com/shipping");
 
Name confirmation = soapFactory.createName("confirmationDesk",
                     nameSpace, nameSpaceURI);
SOAPHeaderElement confirmationHeader = header.addHeaderElement(confirmation);
confirmationHeader.setActor("http://gizmos.com/confirmations");
 
Name billing = soapFactory.createName("billingDesk",
                  nameSpace, nameSpaceURI);
SOAPHeaderElement billingHeader = header.addHeaderElement(billing);
billingHeader.setActor("http://gizmos.com/billing");

The SOAPHeader interface provides two methods that return a java.util.Iterator object over all of the SOAPHeaderElement objects with an actor that matches the specified actor. The first method, examineHeaderElements, returns an iterator over all of the elements with the specified actor.

java.util.Iterator headerElements =       
         header.examineHeaderElements("http://gizmos.com/orders");

The second method, extractHeaderElements, not only returns an iterator over all of the SOAPHeaderElement objects with the specified actor attribute but also DETACHES them from the SOAPHeader object. So, for example, after the order desk application has done its work, it would call extractHeaderElements to remove all of the SOAPHeaderElement objects that applied to it.

java.util.Iterator headerElements =
         header.extractHeaderElements("http://gizmos.com/orders");

Each SOAPHeaderElement object may have only one actor attribute, but the same actor may be an attribute for multiple SOAPHeaderElement objects.

Two additional SOAPHeader methods, examineAllHeaderElements and extractAllHeaderElements, allow you to examine or extract all the header elements, whether or not they have an actor attribute. For example, you could use the following code to display the values of all the header elements:

Iterator allHeaders =   header.examineAllHeaderElements();
while (allHeaders.hasNext()) {
    SOAPHeaderElement headerElement = (SOAPHeaderElement)allHeaders.next();
    Name headerName = headerElement.getElementName();
 
    System.out.println("\nHeader name is " +
                headerName.getQualifiedName());
    System.out.println("Actor is " +
           headerElement.getActor());
}

The mustUnderstand Attribute

The other attribute that must be added only to a SOAPHeaderElement object is mustUnderstand. This attribute says whether or not the recipient (indicated by the actor attribute) is required to process a header entry. When the value of the mustUnderstand attribute is true, the actor must understand the semantics of the header entry and must process it correctly to those semantics. If the value is false, processing the header entry is optional. A SOAPHeaderElement object with no mustUnderstand attribute is equivalent to one with a mustUnderstand attribute whose value is false.

The mustUnderstand attribute is used to call attention to the fact that the semantics in an element are different from the semantics in its parent or peer elements. This allows for robust evolution, ensuring that the change in semantics will not be silently ignored by those who may not fully understand it.

If the actor for a header that has a mustUnderstand attribute set to true cannot process the header, it must send a SOAP fault back to the sender. The actor must not change state or cause any side-effects, so that to an outside observer, it appears that the fault was sent before any header processing was done.

The following code fragment creates a SOAPHeader object with a SOAPHeaderElement object that has a mustUnderstand attribute.

SOAPHeader header = message.getSOAPHeader();
Name name = soapFactory.createName("Transaction", "t",
              "http://gizmos.com/orders");
SOAPHeaderElement transaction = header.addHeaderElement(name);
transaction.setMustUnderstand(true);
transaction.addTextNode("5");

This code produces the following XML:

<SOAP-ENV:Header>
  <t:Transaction xmlns:t="http://gizmos.com/orders" 
    SOAP-ENV:mustUnderstand="1">
  5 
  </t:Transaction>
</SOAP-ENV:Header>

You can use the getMustUnderstand method to retrieve the value of the MustUnderstand attribute. For example, you could add the following to the code fragment at the end of the previous section:

System.out.println(“MustUnderstand is “ +
            headerElement.getMustUnderstand());

Note: Although the SAAJ API provides the API for adding these attributes, it does not supply the API for processing them. For example, the actor attribute requires that there be an implementation such as a messaging provider service to route the message from one actor to the next.



The SOAP Attachment


It is often necessary to send binary data (encrypted documents, images, signatures, spreadsheets, etc.) with a business message. A SOAP message is XML, which means it can hold Unicode text, but not raw binary data.  It is possible, but impractical, to encode binary data as text in base64 or hexadecimal format, but encoding and decoding these formats is a significant overhead. In most cases, an XML document cannot even hold another XML document.

A SOAP message package with attachments is constructed using the MIME multipart/related type.  Soap With Attachments (SwA) is the usual solution for attaching arbitrary data to SOAP messages.SwA appends documents to a SOAP message using the MIME format. There is a drawback to solutions of this kind; the attachments remain outside of the XML therefore XML techologies (such as digital signatures) cannot be applied to the attachments. SwA generates a standard MIME compound object where the first part is the original SOAP message, and subsequent parts are attached document.

SAAJ supports SwA through the class AttachmentPart. A SOAPMessage contains a SOAPPart (the actual SOAPmessage) and any number of AttachmentParts. The wire format of the object changes from SOAP to MIME as soon as the first attachment is added. An AttachmentPart can be initialized with data from a string, a stream, a Source or a DataHandler. The programmer must also set the Content-Type and Content-Id headers. SAAJ allows specific attachments to be retrieved from messages y specifying their MIME headers.

An AttachmentPart object can contain any type of content, including XML. And because the SOAP part can contain only XML content, you must use an AttachmentPart object for any content that is not in XML format.

Creating an AttachmentPart Object and Adding Content

The SOAPMessage object creates an AttachmentPart object, and the message also has to add the attachment to itself after content has been added. The SOAPMessage class has three methods for creating an AttachmentPart object.

The first method creates an attachment with no content. In this case, an AttachmentPart method is used later to add content to the attachment.

AttachmentPart attachment = message.createAttachmentPart();

You add content to attachment with the AttachmentPart method setContent. This method takes two parameters, a Java Object for the content, and a String object that gives the content type. Content in the SOAPBody part of a message automatically has a Content-Type header with the value "text/xml" because the content has to be in XML. In contrast, the type of content in an AttachmentPart object has to be specified because it can be any type.

Each AttachmentPart object has one or more headers associated with it. When you specify a type to the method setContent, that type is used for the header Content-Type. Content-Type is the only header that is required. You may set other optional headers, such as Content-Id and Content-Location. For convenience, SAAJ provides get and set methods for the headers Content-Type, Content-Id, and Content-Location. These headers can be helpful in accessing a particular attachment when a message has multiple attachments. For example, to access the attachments that have particular headers, you call the SOAPMessage method getAttachments and pass it the header or headers you are interested in.

The following code fragment shows one of the ways to use the method setContent. This method takes two parameters, the first being a Java Object containing the content and the second being a String giving the content type. The Java Object may be a String, a stream, a javax.xml.transform.Source object, or a javax.activation.DataHandler object. The Java Object being added in the following code fragment is a String, which is plain text, so the second argument must be "text/plain". The code also sets a content identifier, which can be used to identify this AttachmentPart object. After you have added content to attachment, you need to add it to the SOAPMessage object, which is done in the last line.

SOAPMessageFactory messageFactory =
                   SOAPMessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
SOAPBody    body = envelope.getBody();
 
//Create a SOAPBodyElement
Name bodyName = envelope.createName("GetLastTradePrice",
                            "m", "http://wombat.ztrade.com");
SOAPBodyElement bodyElement = body.addBodyElement(bodyName);
//Insert Content
Name name = envelope.createName("symbol");
SOAPElement symbol = bodyElement.addChildElement(name);
symbol.addTextNode("SUNW");
 
//Attach an attachment ..
AttachmentPart attachment = message.createAttachmentPart();
String stringContent = "Update address for Sunny Skies " +
                       "Inc., to 10 Upbeat Street, Pleasant Grove, CA 95439";
attachment.setContent(stringContent, "text/plain");
attachment.setContentId("update_address");
message.addAttachmentPart(attachment);
  

The above code fragment produces the following SOAP message:

------=_Part_0_914691.1118020615054
Content-Type: text/xml; charset=utf-8

 
<SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
     <SOAP-ENV:Body>
       <m:GetLastTradePrice xmlns:m="http://wombat.ztrade.com">
         <symbol>SUNW</symbol>
       </m:GetLastTradePrice>
     </SOAP-ENV:Body>
   </SOAP-ENV:Envelope>
 
------=_Part_0_914691.1118020615054
Content-Type: text/plain
Content-Id: update_address
 
Update address for Sunny Skies Inc., to 10 Upbeat Street, Pleasant Grove, CA 95439
------=_Part_0_914691.1118020615054--

The variable attachment now represents an AttachmentPart object that contains the string stringContent and has a header that contains the string "text/plain". It also has a Content-Id header with "update_address" as its value. And attachment is now part of message.

The other two SOAPMessage.createAttachment methods create an AttachmentPart object complete with content. One is very similar to the AttachmentPart.setContent method in that it takes the same parameters and does essentially the same thing. It takes a Java Object containing the content and a String giving the content type. As with AttachmentPart.setContent, the Object may be a String, a stream, a javax.xml.transform.Source object, or a javax.activation.DataHandler object.

The other method for creating an AttachmentPart object with content takes a DataHandler object, which is part of the JavaBeans Activation Framework (JAF). Using a DataHandler object is fairly straightforward. First you create a java.net.URL object for the file you want to add as content. Then you create a DataHandler object initialized with the URL object:

URL url = new URL("http://greatproducts.com/gizmos/img.jpg");
DataHandler dataHandler = new DataHandler(url);
AttachmentPart attachment = message.createAttachmentPart(dataHandler);
attachment.setContentId("attached_image");
message.addAttachmentPart(attachment);

You might note two things about the previous code fragment. First, it sets a header for Content-ID with the method setContentId. This method takes a String that can be whatever you like to identify the attachment. Second, unlike the other methods for setting content, this one does not take a String for Content-Type. This method takes care of setting the Content-Type header for you, which is possible because one of the things a DataHandler object does is determine the data type of the file it contains.

Accessing an AttachmentPart Object

If you receive a message with attachments or want to change an attachment to a message you are building, you will need to access the attachment. The SOAPMessage class provides two versions of the method getAttachments for retrieving its AttachmentPart objects. When it is given no argument, the method SOAPMessage.getAttachments returns a java.util.Iterator object over all the AttachmentPart objects in a message.

The following code uses the getAttachments method that takes no arguments and thus retrieves all of the AttachmentPart objects in the SOAPMessage object message. Then it prints out the content ID, content type, and content of each AttachmentPart object.

//Get Iterator of Attchments from given SOAPMessage
java.util.Iterator iterator = message.getAttachments();

 
while (iterator.hasNext()) {
  try {
      //get next attachment
      AttachmentPart attachment = (AttachmentPart)iterator.next();
      String id = attachment.getContentId();
      String type = attachment.getContentType();
      System.out.print("Attachment " + id +
                   " has content type " + type);
      if (type == "text/plain") {
        Object content = attachment.getContent();
        System.out.println("Attachment " +
              "contains:\n" + content);
      }
  } catch (SOAPException se) {
      System.out.println(se.getMessage());
  }
 
}

When getAttachments is given a MimeHeaders object, which is a list of MIME headers, it returns an iterator over the AttachmentPart objects that have a header that matches one of the headers in the list.

MimeHeaders headers = new MimeHeaders();
headers.addHeader("Content-Id", "update_address");
java.util.Iterator iterator = message.getAttachments(headers);
while (iterator.hasNext()) {
  AttachmentPart attachment = (AttachmentPart)iterator.next();
  String id = attachment.getContentId();
  String type = attachment.getContentType();
  System.out.print("Attachment " + id +
            " has content type " + type);
  if (type == "text/plain") {
        Object content = attachment.getContent();
        System.out.println("Attachment " +
          "contains:\n" + content);
  }
}


Using SOAP Faults

In this section, you will see how to use the API for creating and accessing a SOAP Fault element in an XML message.

Overview of SOAP Faults

If you send a message that was not successful for some reason, you may get back a response containing a SOAP Fault element that gives you status information, error information, or both. There can be only one SOAP Fault element in a message, and it must be an entry in the SOAP Body. Further, if there is a SOAP Fault element in the SOAP Body, there can be no other elements in the SOAP Body. This means that when you add a SOAP Fault element, you have effectively completed the construction of the SOAP Body. The SOAP 1.1 specification defines only one Body entry, which is the SOAP Fault element. Of course, the SOAP Body may contain other kinds of Body entries, but the SOAP Fault element is the only one that has been defined.

A SOAPFault object, the representation of a SOAP Fault element in the SAAJ API, is similar to an Exception object in that it conveys information about a problem. However, a SOAPFault object is quite different in that it is an element in a message's SOAPBody object rather than part of the try/catch mechanism used for Exception objects. Also, as part of the SOAPBody object, which provides a simple means for sending mandatory information intended for the ultimate recipient, a SOAPFault object only reports status or error information. It does not halt the execution of an application the way an Exception object can.

If you are a client using the SAAJ API and are sending point-to-point messages, the recipient of your message may add a SOAPFault object to the response to alert you to a problem. For example, if you sent an order with an incomplete address for where to send the order, the service receiving the order might put a SOAPFault object in the return message telling you that part of the address was missing.

Another example of who might send a SOAP fault is an intermediate recipient, or actor. As stated in the previous section, an actor that cannot process a header that has a mustUnderstand attribute with a value of true must return a SOAP fault to the sender.

A SOAPFault object contains the following elements:

·         A fault code -- always required

The fault code must be a fully qualified name, which means that it must contain a prefix followed by a local name. The SOAP 1.1 specification defines a set of fault code local name values in section 4.4.1, which a developer may extend to cover other problems. The default fault code local names defined in the specification relate to the SAAJ API as follows:

·         VersionMismatch -- the namespace for a SOAPEnvelope object was invalid

·         MustUnderstand -- an immediate child element of a SOAPHeader object had its mustUnderstand attribute set to true, and the processing party did not understand the element or did not obey it

·         Client -- the SOAPMessage object was not formed correctly or did not contain the information needed to succeed

·         Server -- the SOAPMessage object could not be processed because of a processing error, not because of a problem with the message itself

·         A fault string -- always required

A human-readable explanation of the fault

·         A fault actor -- required if the SOAPHeader object contains one or more actor attributes; optional if no actors are specified, meaning that the only actor is the ultimate destination

The fault actor, which is specified as a URI, identifies who caused the fault. For an explanation of what an actor is, see the section The Actor Attribute.

·         A Detail object -- required if the fault is an error related to the SOAPBody object

If, for example, the fault code is Client, indicating that the message could not be processed because of a problem in the SOAPBody object, the SOAPFault object must contain a Detail object that gives details about the problem. If a SOAPFault object does not contain a Detail object, it can be assumed that the SOAPBody object was processed successfully.

Creating and Populating a SOAPFault Object

You have already seen how to add content to a SOAPBody object; this section will walk you through adding a SOAPFault object to a SOAPBody object and then adding its constituent parts.

As with adding content, the first step is to access the SOAPBody object.

SOAPBody body = message.getSOAPBody();

With the SOAPBody object body in hand, you can use it to create a SOAPFault object. The following line of code both creates a SOAPFault object and adds it to body.

SOAPFault fault = body.addFault();

The SOAPFault interface provides convenience methods that create an element, add the new element to the SOAPFault object, and add a text node all in one operation. For example, in the following lines of code, the method setFaultCode creates a faultcode element, adds it to fault, and adds a Text node with the value "SOAP-ENV:Server" by specifying a default prefix and the namespace URI for a SOAP envelope.

Name faultName = soapFactory.createName("Server",
                        "", SOAPConstants.URI_NS_SOAP_ENVELOPE);
fault.setFaultCode(faultName);
fault.setFaultActor("http://gizmos.com/orders");
fault.setFaultString("Server not responding");

The SOAPFault object fault, created in the previous lines of code, indicates that the cause of the problem is an unavailable server and that the actor at http://gizmos.com/orders is having the problem. If the message were being routed only to its ultimate destination, there would have been no need for setting a fault actor. Also note that fault does not have a Detail object because it does not relate to the SOAPBody object.

The following code fragment creates a SOAPFault object that includes a Detail object. Note that a SOAPFault object may have only one Detail object, which is simply a container for DetailEntry objects, but the Detail object may have multiple DetailEntry objects. The Detail object in the following lines of code has two DetailEntry objects added to it.

SOAPFault fault = body.addFault();
Name faultName = soapFactory.createName("Client",
              "", SOAPConstants.URI_NS_SOAP_ENVELOPE);
fault.setFaultCode(faultName);
fault.setFaultString("Message does not have necessary info");
Detail detail =  fault.addDetail();
Name entryName = soapFactory.createName("order", "PO",
            "http://gizmos.com/orders/");
DetailEntry entry =  detail.addDetailEntry(entryName);
entry.addTextNode("Quantity element does not have a value");
Name entryName2 = soapFactory.createName("confirmation",
              "PO", "http://gizmos.com/confirm");
DetailEntry entry2 = detail.addDetailEntry(entryName2);
entry2.addTextNode("Incomplete address: no zip code");

 

Retrieving Fault Information

Just as the SOAPFault interface provides convenience methods for adding information, it also provides convenience methods for retrieving that information. The following code fragment shows what you might write to retrieve fault information from a message you received. In the code fragment, newMessage is the SOAPMessage object that has been sent to you. Because a SOAPFault object must be part of the SOAPBody object, the first step is to access the SOAPBody object. Then the code tests to see if the SOAPBody object contains a SOAPFault object. If so, the code retrieves the SOAPFault object and uses it to retrieve its contents. The convenience methods getFaultCode, getFaultString, and getFaultActor make retrieving the values very easy.

SOAPBody body = newMessage.getSOAPBody();
if ( body.hasFault() ) {
  SOAPFault newFault = body.getFault();
  Name code = newFault.getFaultCodeAsName();
  String string = newFault.getFaultString();
  String actor = newFault.getFaultActor();
}

Next the code prints out the values it just retrieved. Not all messages are required to have a fault actor, so the code tests to see if there is one. Testing whether the variable actor is null works because the method getFaultActor returns null if a fault actor has not been set.

System.out.println("SOAP fault contains: ");
System.out.println("  Fault code = " +  code.getQualifiedName());
System.out.println("  Fault string = " + string);
if ( actor != null ) {
   System.out.println("  Fault actor = " + actor);
}

The final task is to retrieve the Detail object and get its DetailEntry objects. The code uses the SOAPFault object newFault to retrieve the Detail object newDetail, and then it uses newDetail to call the method getDetailEntries. This method returns the java.util.Iterator object entries, which contains all of the DetailEntry objects in newDetail. Not all SOAPFault objects are required to have a Detail object, so the code tests to see whether newDetail is null. If it is not, the code prints out the values of the DetailEntry objects as long as there are any.

Detail newDetail = newFault.getDetail();
if ( newDetail != null) {
     Iterator entries = newDetail.getDetailEntries();
     while ( entries.hasNext() ) {
         DetailEntry newEntry =
             (DetailEntry)entries.next();
         String value = newEntry.getValue();
         System.out.println("  Detail entry = " + value);
     }
}

In summary, you have seen how to add a SOAPFault object and its contents to a message as well as how to retrieve the contents. A SOAPFault object, which is optional, is added to the SOAPBody object to convey status or error information. It must always have a fault code and a String explanation of the fault. A SOAPFault object must indicate the actor that is the source of the fault only when there are multiple actors; otherwise, it is optional. Similarly, the SOAPFault object must contain a Detail object with one or more DetailEntry objects only when the contents of the SOAPBody object could not be processed successfully.

 


Reference:

 
http://www.javaworld.com/javaworld/jw-09-2003/jw-0912-webservices.html

http://java.boot.by/wsd-guide/ch05s04.html

http://cermics.enpc.fr/doc/java/j2eetutorial-1.4/doc/SAAJ2.html#63942

http://www.ti5.tu-harburg.de/manual/Java/j2ee-tutorial-1.4/doc/SAAJ3.html