Download FAQ History |  | API Search Feedback

> ## Tutorial

> This tutorial will walk you through how to use the SAAJ API. First, it covers the basics of creating and sending a simple SOAP message. Then you will learn more details about adding content to messages, including how to create SOAP faults and attributes. Finally, you will learn how to send a message and retrieve the content of the response. After going through this tutorial, you will know how to perform the following tasks:

> - Creating and Sending a Simple Message
> - Adding Content to the Header
> - Adding Content to the SOAP Body
> - Adding Content to the SOAPPart Object
> - Adding a Document to the SOAP Body
> - Manipulating Message Content Using SAAJ or DOM APIs
> - Adding Attachments
> - Adding Attributes
> - Using SOAP Faults

> In the section Code Examples, you will see the code fragments from earlier parts of the tutorial in runnable applications, which you can test yourself. To see how the SAAJ API can be used in server code, see the SAAJ part of the case study (SAAJ Distributor Service), which shows an example of both the client and server code for a Web service application.

> A SAAJ client can send request-response messages to Web services that are implemented to do request-response messaging. This section demonstrates how you can do this.

> ### Creating and Sending a Simple Message

> This section covers the basics of creating and sending a simple message and retrieving the content of the response. It includes the following topics:

> - Creating a Message
> - Parts of a Message
> - Accessing Elements of a Message
> - Adding Content to the Body
> - Getting a SOAPConnection Object
> - Sending a Message
> - Getting the Content of a Message

> #### Creating a Message

> The first step is to create a message, which you do using a `MessageFactory` object. The SAAJ API provides a default implementation of the `MessageFactory` class, thus making it easy to get an instance. The following code fragment illustrates getting an instance of the default message factory and then using it to create a message.

>     MessageFactory factory = MessageFactory.newInstance();
>     SOAPMessage message = factory.createMessage();

> As is true of the `newInstance` method for `SOAPConnectionFactory`, the `newInstance` method for `MessageFactory` is static, so you invoke it by calling `MessageFactory.newInstance`.

> #### Parts of a Message

> A `SOAPMessage` object is required to have certain elements, and, as stated previously, the SAAJ API simplifies things for you by returning a new `SOAPMessage` object that already contains these elements. So `message`, which was created in the preceding line of code, automatically has the following:

> I. A `SOAPPart` object that contains

> A. A `SOAPEnvelope` object that contains

> 1. An empty `SOAPHeader` object

> 2. An empty `SOAPBody` object

> 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 section Using SOAP Faults walks you through how to use `SOAPFault` objects.

> #### Accessing Elements of a Message

> The next step in creating a message is to access its parts so that content can be added. There are two ways to do this. The `SOAPMessage` object `message`, created in the previous code fragment, is the place to start.

> The first way to access the parts of the message is to work your way through the structure of the message. The message contains a `SOAPPart` object, so you use the `getSOAPPart` method of `message` to retrieve it:

>     SOAPPart soapPart = message.getSOAPPart();

> Next you can use the `getEnvelope` method of `soapPart` to retrieve the `SOAPEnvelope` object that it contains.

>     SOAPEnvelope envelope = soapPart.getEnvelope();

> You can now use the `getHeader` and `getBody` methods of `envelope` to retrieve its empty `SOAPHeader` and `SOAPBody` objects.

>     SOAPHeader header = envelope.getHeader();
>     SOAPBody body = envelope.getBody();

> The second way to access the parts of the message is to retrieve the message header and body directly, without retrieving the `SOAPPart` or `SOAPEnvelope`. To do so, use the `getSOAPHeader` and `getSOAPBody` methods of `SOAPMessage`:

>     SOAPHeader header = message.getSOAPHeader();
>     SOAPBody body = message.getSOAPBody();

> This example of a SAAJ client does not use a SOAP header, so you can delete it. (You will see more about headers later.) Because all `SOAPElement` objects, including `SOAPHeader` objects, are derived from the `Node` interface, you use the method `Node.detachNode` to delete `header`.

>     header.detachNode();

> #### Adding Content to the Body

> To add content to the body, you need to create a `SOAPBodyElement` object to hold the content. When you create any new element, you also need to create an associated `Name` object so that it is uniquely identified.

> 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. Another way to create `Name` objects is to use `SOAPFactory` methods, which are useful if you do not have access to the `SOAPEnvelope`.

> Note: 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. You will find an explanation of `Detail` objects in the SOAP Fault sections Overview of SOAP Faults and Creating and Populating a SOAPFault Object.

> `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.

> The code fragment that follows retrieves the `SOAPBody` object `body` from `message`, uses a `SOAPFactory` to create a `Name` object for the element to be added, and adds a new `SOAPBodyElement` object to `body`.

>     SOAPBody body = message.getSOAPBody();
>     SOAPFactory soapFactory = SOAPFactory.newInstance();
>     Name bodyName = soapFactory.createName("GetLastTradePrice",
>         "m", "http://wombat.ztrade.com");
>     SOAPBodyElement bodyElement = body.addBodyElement(bodyName);

> At this point, `body` contains a `SOAPBodyElement` object identified by the `Name` object `bodyName`, but 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.

>     Name name = soapFactory.createName("symbol");
>     SOAPElement symbol = bodyElement.addChildElement(name);
>     symbol.addTextNode("SUNW");

> You might recall that the headers and content in a `SOAPPart` object must be in XML format. The SAAJ API takes care of this for you, building the appropriate XML constructs automatically when you call methods such as `addBodyElement`, `addChildElement`, and `addTextNode`. Note that you can call the method `addTextNode` only on an element such as `bodyElement` or any child elements that are added to it. You cannot call `addTextNode` on a `SOAPHeader` or `SOAPBody` object because they contain elements, not text.

> The content that you have just added to your `SOAPBody` object will look like the following when it is sent over the wire:

>     <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>

> Let's examine this XML excerpt line by line to see how it relates to your SAAJ code. Note that an XML parser does not care about indentations, but they are generally used to indicate element levels and thereby make it easier for a human reader to understand.

> SAAJ code:

>     SOAPMessage message = messageFactory.createMessage();
>     SOAPHeader header = message.getSOAPHeader();
>     SOAPBody body = message.getSOAPBody();

> XML it produces:

>     <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 outermost element in this XML example is the SOAP envelope element, indicated by `SOAP-ENV:Envelope`. `Envelope` is the name of the element, and `SOAP-ENV` is the namespace prefix. The interface `SOAPEnvelope` represents a SOAP envelope.

> The first line signals the beginning of the SOAP envelope element, and the last line signals the end of it; everything in between is part of the SOAP envelope. The second line is an example of an attribute for the SOAP envelope element. Because a SOAP Envelope element always contains this attribute with this value, a `SOAPMessage` object comes with it automatically included. `xmlns` stands for "XML namespace," and its value is the URI of the namespace associated with `Envelope`.

> The next line is an empty SOAP header. We could remove it by calling `header.detachNode` after the `getSOAPHeader` call.

> The next two lines mark the beginning and end of the SOAP body, represented in SAAJ by a `SOAPBody` object. The next step is to add content to the body.

> SAAJ code:

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

> XML it produces:

>     <m:GetLastTradePrice
>      xmlns:m="http://wombat.ztrade.com">
>      . . . .
>     </m:GetLastTradePrice>

> These lines are what the `SOAPBodyElement` `bodyElement` in your code represents. `GetLastTradePrice`"is its local name, `m` is its namespace prefix, and `http://wombat.ztrade.com` is its namespace URI.

> SAAJ code:

>     Name name = soapFactory.createName("symbol");
>     SOAPElement symbol = bodyElement.addChildElement(name);
>     symbol.addTextNode("SUNW");

> XML it produces:

>     <symbol>SUNW</symbol>

> The `String` `"SUNW"` is the text node for the element `<symbol>`. This `String` object is the message content that your recipient, the stock quote service, receives.

> #### Getting a SOAPConnection Object

> 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.

> To send a message, a SAAJ client may use a `SOAPConnection` object. A `SOAPConnection` object is a point-to-point connection, meaning that it goes directly from the sender to the destination (usually a URL) that the sender specifies.

> The first step is to obtain a `SOAPConnectionFactory` object that you can use to create your connection. The SAAJ API makes this easy by providing the `SOAPConnectionFactory` class with a default implementation. You can get an instance of this implementation with the following line of code.

>     SOAPConnectionFactory soapConnectionFactory =
>         SOAPConnectionFactory.newInstance();

> Now you can use `soapConnectionFactory` to create a `SOAPConnection` object.

>     SOAPConnection connection =
>         soapConnectionFactory.createConnection();

> You will use `connection` to send the message that you created.

> #### Sending a Message

> A SAAJ client calls the `SOAPConnection` method `call` on a `SOAPConnection` object to send a message. The `call` method takes two arguments, the message being sent and the destination to which the message should go. This message is going to the stock quote service indicated by the `URL` object `endpoint`.

>     java.net.URL endpoint = new URL(
>         "http://wombat.ztrade.com/quotes");

>     SOAPMessage response = connection.call(message, endpoint);

> The content of the message you sent is the stock symbol SUNW; the `SOAPMessage` object `response` should contain the last stock price for Sun Microsystems, which you will retrieve in the next section.

> A connection uses a fair amount of resources, so it is a good idea to close a connection as soon as you are through using it.

>     connection.close();

> #### Getting the Content of a 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);

> 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. The next sections provide more detail on adding content to messages.

> ### Adding Content to the Header

> 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.

> 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);
>     headerElement.addAttribute(soapFactory.createName(
>         "conformsTo"), "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, see the Messaging section of the ``WS-I Basic Profile.

> 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"`.

> ### Adding Content to the SOAP Body

> 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`.

> The following example shows adding multiple `SOAPElement` objects and adding text to each of them. The code first creates the `SOAPBodyElement` object `purchaseLineItems`, which has a fully qualified name associated with it. That is, the `Name` object for it has a local name, a namespace prefix, and a namespace URI. As you saw earlier, a `SOAPBodyElement` object is required to have a fully qualified name, but child elements added to it, such as `SOAPElement` objects, may have `Name` objects with only the local name.

>     SOAPBody body = soapFactory.getSOAPBody();
>     Name bodyName = soapFactory.createName("PurchaseLineItems",
>         "PO", "http://sonata.fruitsgalore.com");
>     SOAPBodyElement purchaseLineItems =
>         body.addBodyElement(bodyName);

>     Name childName = soapFactory.createName("Order");
>     SOAPElement order =
>         purchaseLineItems.addChildElement(childName);

>     childName = soapFactory.createName("Product");
>     SOAPElement product = order.addChildElement(childName);
>     product.addTextNode("Apple");

>     childName = soapFactory.createName("Price");
>     SOAPElement price = order.addChildElement(childName);
>     price.addTextNode("1.56");

>     childName = soapFactory.createName("Order");
>     SOAPElement order2 =
>         purchaseLineItems.addChildElement(childName);

>     childName = soapFactory.createName("Product");
>     SOAPElement product2 = order2.addChildElement(childName);
>     product2.addTextNode("Peach");

>     childName = soapFactory.createName("Price");
>     SOAPElement price2 = order2.addChildElement(childName);
>     price2.addTextNode("1.48");

> The SAAJ code in the preceding example produces the following XML in the SOAP body:

>     <PO:PurchaseLineItems
>      xmlns:PO="http://www.sonata.fruitsgalore/order">
>       <Order>
>         <Product>Apple</Product>
>         <Price>1.56</Price>
>       </Order>

>       <Order>
>         <Product>Peach</Product>
>         <Price>1.48</Price>
>       </Order>
>     </PO:PurchaseLineItems>

> ### Adding 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.

> ### Adding 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);

> ### 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:

> - Use only DOM APIs
> - Use only SAAJ APIs
> - Use SAAJ APIs and then switch to using DOM APIs
> - Use DOM APIs and then switch to using SAAJ APIs

> 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.

> ### Adding Attachments

> 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.

>     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 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. 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. 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.

>     java.util.Iterator iterator = message.getAttachments();
>     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);
>         }
>     }

> ### Adding 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. For example, in the following code fragment, the attribute named `id` is added to the `SOAPElement` object `person`. Because `person` 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.

>     Name attributeName = envelope.createName("id");
>     person.addAttribute(attributeName, "Person7");

> These lines of code will generate the first line in the following XML fragment.

>     <person id="Person7">
>       ...
>     </person>

> The following line of code retrieves the value of the attribute whose name is `id`.

>     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 attribute named `id`. If you wanted to retrieve the values for all of the attributes for `person`, 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`. (The examples in DOMExample.java and DomSrcExample.java use code similar to this.)

>     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 = person.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. The next section discusses attributes that may be added only to header elements.

> #### 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.

> See HeaderExample.java for an example that uses the code shown in this section.

> ##### 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.

> 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.

> 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. (See the section Using SOAP Faults for information.) 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());

> ### 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 section Adding Attributes, 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");

> See SOAPFaultTest.java for an example that uses code like that shown in this section.

> #### 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.

> See SOAPFaultTest.java for an example that uses code like that shown in this section.

Download FAQ History |  | API Search Feedback

All of the material in The Java(TM) Web Services Tutorial is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.