SCDJWS Study Guide: SAAJ


Printer-friendly version Printer-friendly version | Send this 
article to a friend Mail this to a friend


Previous Next vertical dots separating previous/next from contents/index/pdf Contents

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:

  • A SOAPPart object
  • A SOAPEnvelope object
  • A SOAPBody object
  • A SOAPHeader object
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:

  • One can access the parts of the message is to retrieve the message header and body directly:

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

  • Also, one can access the parts of the message is to work your way through the structure of the message:

   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.

  • createMessage() -- message has no content;  This is the method clients would normally use to create a request message.
  • createMessage(MimeHeaders, java.io.InputStream) -- message has content from the InputStream object and headers from the MimeHeaders object; This method can be used internally by a service implementation to create a message that is a response to a request.

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.




Previous Next vertical dots separating previous/next from contents/index/pdf Contents

  |   |