The Java EE 5 Tutorial

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

The first step is to create a message 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.

If you specify no arguments to the newInstance method, it creates a message factory for SOAP 1.1 messages. To create a message factory that allows you to create and process SOAP 1.2 messages, use the following method call:

MessageFactory factory = 
    MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);

To create a message factory that can create either SOAP 1.1 or SOAP 1.2 messages, use the following method call:

MessageFactory factory =
    MessageFactory.newInstance(SOAPConstants.DYNAMIC_SOAP_PROTOCOL);

This kind of factory enables you to process an incoming message that might be of either type.

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. When you call createMessage with no arguments, the message that is created 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 can be deleted if it is not needed. However, if there is one, it must precede the SOAPBody object. The SOAPBody object can hold either the content of the message or a fault message that contains 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 preceding 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

The SOAPBody object contains either content or a fault. To add content to the body, you normally create one or more SOAPBodyElement objects to hold the content. You can also add subelements to the SOAPBodyElement objects by using the addChildElement method. For each element or child element, you add content by using the addTextNode method.

When you create any new element, you also need to create an associated javax.xml.namespace.QName object so that it is uniquely identified.


Note –

You can use Name objects instead of QName objects. Name objects are specific to the SAAJ API, and you create them using either SOAPEnvelope methods or SOAPFactory methods. However, the Name interface may be deprecated at a future release.

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, and this 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 Overview of SOAP Faults and Creating and Populating a SOAPFault Object.


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

The following code fragment retrieves the SOAPBody object body from message, constructs a QName object for the element to be added, and adds a new SOAPBodyElement object to body.

SOAPBody body = message.getSOAPBody();
QName bodyName = new QName("http://wombat.ztrade.com", "GetLastTradePrice", "m");
SOAPBodyElement bodyElement = body.addBodyElement(bodyName);

At this point, body contains a SOAPBodyElement object identified by the QName 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 addChildElement method. Then you need to give it the stock symbol using the addTextNode method. The QName 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.

QName name = new QName("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 and 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.

Here is the SAAJ code:

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

Here is the 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. Note that 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. You 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.

Here is the SAAJ code:

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

Here is the 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.

Here is the SAAJ code:

QName name = new QName("symbol");
SOAPElement symbol = bodyElement.addChildElement(name);
symbol.addTextNode("SUNW");

Here is the 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.

The following example shows how to add multiple SOAPElement objects and add 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 QName object for it has a namespace URI, a local name, and a namespace prefix. 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, can have Name objects with only the local name.

SOAPBody body = message.getSOAPBody();
QName bodyName = 
    new QName("http://sonata.fruitsgalore.com", "PurchaseLineItems", "PO");
SOAPBodyElement purchaseLineItems =
    body.addBodyElement(bodyName);

QName childName = new QName("Order");
SOAPElement order = purchaseLineItems.addChildElement(childName);

childName = new QName("Product");
SOAPElement product = order.addChildElement(childName);
product.addTextNode("Apple");

childName = new QName("Price");
SOAPElement price = order.addChildElement(childName);
price.addTextNode("1.56");

childName = new QName("Order");
SOAPElement order2 = purchaseLineItems.addChildElement(childName);

childName = new QName("Product");
SOAPElement product2 = order2.addChildElement(childName);
product2.addTextNode("Peach");

childName = soapFactory.new QName("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://sonata.fruitsgalore.com">
  <Order>
    <Product>Apple</Product>
    <Price>1.56</Price>
  </Order>

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

Getting a SOAPConnection Object

The SAAJ API is focused primarily on reading and writing messages. After you have written a message, you can send it using various mechanisms (such as JMS or JAXM). The SAAJ API does, however, provide a simple mechanism for request-response messaging.

To send a message, a SAAJ client can 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 using 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 finished 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 to add content or to retrieve 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 getValue method is called on bodyElement, the element on which the addTextNode method was called.

To access bodyElement, you call the getChildElements method on soapBody. Passing bodyName to getChildElements returns a java.util.Iterator object that contains all the child elements identified by the Name object bodyName. You already know that there is only one, so calling the next method on it will return the SOAPBodyElement you want. Note that the Iterator.next method returns a Java Object, so you need 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 more than one element had the name bodyName, you would have to use a while loop using the Iterator.hasNext method 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.