SOAP with Attachments API for Java (SAAJ) provides a standard way to send XML documents over the Internet from the Java platform. SAAJ enables you to produce and consume messages conforming to the SOAP 1.1 and 1.2 specifications and SOAP with Attachments note.
When you choose to write SOAP messaging applications directly rather than use JAX-WS, you can use SAAJ. (JAX-WS is a more general Java API for creating Web services.) For some Web services, SAAJ is often useful to directly program to that lower-level messaging layer.
For instance, if you wish to invoke a Web service that consumes a purchase order document and returns a receipt, you can easily model that document exchange as a single request/response message exchange. Instead of making remote method invocations, you would construct XML messages, send those messages directly to a Web service, and process the service's XML response (if any exists).
SAAJ provides a convenient library to construct and read SOAP messages; it also lets you send and receive SOAP messages across the network.
The SAAJ 1.3 specification defines the javax.xml.soap package, which contains the API for creating and populating a SOAP message. This package has all the API necessary for sending request/response messages. In this article, I will demonstrate the process of using SAAJ.
Why attachments are needed for SOAP
SOAP messages require considerable processing power and memory. All parts of a SOAP message must conform to XML rules for allowed characters and character sequences, so binary data cannot be directly included.
In addition, SOAP implementations typically parse the entire SOAP message before deciding what to do with the contents, so large data fields could easily exceed available memory. For these reasons, SOAP requires some mechanism for carrying large payloads and binary data as an attachment rather than inside the SOAP message envelope.
The obvious mechanism to use is the same one used for attachments to e-mail messages -- the multipart MIME approach in which a collection of message parts are identified by headers and separators. The first part is always a complete SOAP message envelope, while the following parts depend on the application.
Making SOAP message with SAAJ
The SAAJ API has the interface Node, which is the base class for all the classes and interfaces that represent XML elements in a SOAP message.
There are two main types of SOAP messages: ones with attachments and ones that do not have attachments. At the very high level, this is the structure of a SOAP message: the SOAPPart includes the SOAPEnvelope, which includes SOAPHeader (optional) and a body. Logically, the essential parts of a SOAP message each have corresponding Java classes in SAAJ.
The SAAJ API provides the SOAPMessage class to represent a SOAP message; it provides the SOAPPart class to represent the SOAP part; and it provides the SOAPEnvelope interface to represent the SOAP envelope. Many SAAJ API interfaces extend DOM interfaces. In a SAAJ message, the SOAPPart class is also a DOM document.
Inside the Envelope element, a SOAP message is required to have a Body element and may have one Header element. SAAJ provides the SOAPBody and SOAPHeader objects to enable you to manipulate the content of these elements. SAAJ provides the mechanism, but it's up to you to create the contents of the SOAPBody and SOAPHeader objects.
A SOAPMessage object may have zero, one, or many additional AttachmentPart objects with any MIME content type such as an XML document, plain text, or an image. If it has zero attachments, the message will be transmitted as a plain XML document. If you add one or more attachments, it automatically causes transmission as a collection of MIME parts. Attachments are added using the AttachmentPart class, which requires a data source (typically an InputStream) and a MIME content type. Since the Java standard library provides many ways to create an InputStream, this approach is extremely flexible.Figure A shows the high-level structure of a SOAP message that has two attachments. The SAAJ API provides the AttachmentPart class to represent an attachment part of a SOAP message. A SOAPMessage object automatically has a SOAPPart object and its required subelements, but you must create and add them yourself because AttachmentPart objects are optional. Figure A
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. 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);SOAPMessage message = factory.createMessage();
When you call createMessage with no arguments, the message that is created automatically has: a SOAPPart object that contains a SOAPEnvelope object that contains an empty SOAPHeader object and an empty SOAPBody object.
The SOAPHeader object is optional and can be deleted if it isn't necessary; 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 next step in creating a message is to access its parts so that you can add content:
SOAPHeader header = message.getSOAPHeader(); SOAPBody body = message.getSOAPBody();
To add content to the body, you normally create one or more SOAPBodyElement objects to hold the content. You can 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 a new element, you also need to create an associated javax.xml.namespace.QName object so that it is uniquely identified.
QName objects associated with SOAPBodyElement or SOAPHeaderElement objects must be fully qualified.
The following code fragment retrieves the SOAPBody object body from message, constructs an 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://site.org",
"ElementName", "m");SOAPBodyElement bodyElement = body.addBodyElement(bodyName);
To fill the new element with content, you need to create a child element using the addChildElement method. Then you need to fill the element with the text using the addTextNode method. All of the work is done according to DOM document construction, which is outside the scope of this article. For more information about DOM document construction, please refer to Java XML APIs (JAXP, JAX-RPC, JAXM, etc.).
An AttachmentPart object may contain any type of content, including XML. Also, because the SOAP part can only contain XML content, you must use an AttachmentPart object for any content that is not in XML format. You add content to attachment by using the AttachmentPart method setContent. This method takes two parameters: a Java Object for the content, and a String object for the MIME content type that is used to encode the object.
Content in the SOAPBody part of a message automatically has a Content-Type header with the value "text/xml" because the content must be in XML. In contrast, the type of content in an AttachmentPart object must be specified because it can be any type. For more information on how to make more complex attachments (with binary data, for example), please refer to SAAJ API JavaDocs.
Communicating with the peer
All SOAP messages are sent and received over a connection. With the SAAJ API, the connection is represented by a SOAPConnection object, which goes from the sender directly to its destination.
The following code fragment creates the SOAPConnection object connection and then, after creating and populating the message, uses connection to send the message. As stated previously, all messages sent over a SOAPConnection object are sent with the call method, which sends the message and blocks it until receiving a response. Thus, the return value for the call method is the SOAPMessage object, which is the response to the message that was sent. The request parameter is the message being sent; endpoint represents where it is being sent.
SOAPConnectionFactory factory =
SOAPConnection connection = factory.createConnection();
java.net.URL endpoint =
new URL("http://site.org/url/of/webservice");SOAPMessage response = connection.call(request, endpoint);
A Web service implemented for request/response messaging must return a response to any message it receives. The response is a SOAPMessage object, just as the request is a SOAPMessage object. The initial steps for retrieving a message's content are the same as those for giving content to a message: You use the Message object to get the SOAPBody object, or you access the SOAPBody object through the SOAPPart and SOAPEnvelope objects. As long as SOAPMessage inherits DOM structure, you browse the received XML document with the DOM API.
Where to find SAAJ
The J2EE version 1.4 contains the 1.2 version of SAAJ, which only handles SOAP 1.1 messages. The latest Enterprise Edition 5 contains SAAJ version 1.3. If you don't want to use the full Enterprise Edition, the latest edition of the Java Web Services Developer Pack contains an implementation of SAAJ 1.3 with full documentation and examples. The open source GlassFish project also contains SAAJ 1.3.
Additional SAAJ resources
- SAAJ Standard Implementation Project
- Java Web Services tutorial
- Metro Web Service Stack implementation
Peter V. Mikhalenko is a Sun certified professional who works as a business and technical consultant for several top-tier investment banks.
---------------------------------------------------------------------------------------Get Java tips in your inbox Delivered each Thursday, our free Java Developer newsletter provides insight and hands-on tips you need to unlock the full potential of this programming language. Automatically subscribe today!