SCDJWS Study Guide: SAAJ
Printer-friendly version |
Mail this to a friend
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:
- Creating a SOAP Connection
- Creating a SOAP message
- Populating the meassge
- Sending/Receiving SOAP messages
- 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
<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.