Use the SAAJ APIs to create and manipulate a SOAP message.

SAAJ - SOAP with Attachments API for Java - contains APIs for creating and populating SOAP messages which might or might not contain attachments. It also contains APIs for sending point to point, non-provider-based, request and response SOAP messages.

SOAP message is made of SOAP Envelope and zero or more attachments. The SOAP Envelope is then made of SOAP Header and SOAP Body. SOAP attachment allows the SOAP message to contain not only the XML data but also non-XML data such as JPG file. And it uses the MIME multipart as container for these non-XML data.

The SAAJ API provides the SOAPMessage class to represent a SOAP message, the SOAPPart class to represent the SOAP part, the SOAPEnvelope interface to represent the SOAP envelope, and so on.

When you create a new SOAPMessage object, it will automatically have the parts that are required to be in a SOAP message. In other words, a new SOAPMessage object has a SOAPPart object that contains a SOAPEnvelope object. The SOAPEnvelope object in turn automatically contains an empty SOAPHeader object followed by an empty SOAPBody object. If you do not need the SOAPHeader object, which is optional, you can delete it. The rationale for having it automatically included is that more often than not you will need it, so it is more convenient to have it provided. The SOAPHeader object may contain one or more headers with information about the sending and receiving parties. The SOAPBody object, which always follows the SOAPHeader object if there is one, provides a simple way to send information intended for the ultimate recipient. For example, if there is a SOAPFault object, it must be in the SOAPBody object.

A SOAP message may include one or more attachment parts in addition to the SOAP part. The SOAP part may contain only XML content; as a result, if any of the content of a message is not in XML format, it must occur in an attachment part. So, if for example, you want your message to contain a binary file, your message must have an attachment part for it. Note that an attachment part can contain any kind of content, so it can contain data in XML format as well.

The SAAJ API provides the AttachmentPart class to represent the attachment part of a SOAP message. A SOAPMessage object automatically has a SOAPPart object and its required subelements, but because AttachmentPart objects are optional, you have to create and add them yourself.

SAAJ API belongs to javax.xml.soap.* package. SOAPConnection provides request/response SOAP message exchange. SOAPMessage creates and populates SOAP message (consists of SOAPPart and AttachmentPart).

javax.xml.soap.MessageFactory is a factory for creating SOAP 1.1-based messages.

public abstract class MessageFactory {
    public static MessageFactory newInstance() throws SOAPException { ... }
    public abstract SOAPMessage createMessage() throws SOAPException;
    ...
}					
					

javax.xml.soap.SOAPMessage is a Java technology abstraction for a SOAP 1.1 message. Contains EXACTLY ONE SOAPPart and ZERO OR MORE AttachmentParts.

public abstract class SOAPMessage {
    public abstract SOAPPart getSOAPPart();
    public abstract Iterator getAttachments();
    public abstract Iterator getAttachments(MimeHeaders headers);
    ...
}					
					

javax.xml.soap.SOAPPart is the first part of a multi-part message when there are attachments.

public abstract class SOAPPart implements org.w3c.dom.Document {
    public abstract SOAPEnvelope getEnvelope() throws SOAPException;
    ...
}					
					

javax.xml.soap.AttachmentPart can contain any data (for example: JPEG images, XML business documents, etc.) If a SOAPMessage object has one or more attachments, each AttachmentPart object must have a MIME header to indicate the type of data it contains. It may also have additional MIME headers to identify it or to give its location, which are optional but can be useful when there are multiple attachments. When a SOAPMessage object has one or more AttachmentPart objects, its SOAPPart object may or may not contain message content.

Steps of SAAJ Programming

  1. Creating a message (SOAPMessage)

    Use MessageFactory as a factory of messages. SOAPMessage object has the following:

    • SOAPPart object

      • SOAPEnvelope object

        • empty SOAPHeader object

        • empty SOAPBody object

    Example:
    MessageFactory factory = MessageFactory.newInstance();
    SOAPMessage message = factory.createMessage();								
    								
    Result:
    
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
        <SOAP-ENV:Header/>
        <SOAP-ENV:Body/>
    </SOAP-ENV:Envelope>
    								
    								

  2. Accessing elements of a message

    Approach 1: from SOAPEnvelope object:

    SOAPPart soapPart = message.getSOAPPart();
    SOAPEnvelope envelope = soapPart.getEnvelope();
    SOAPHeader header = envelope.getHeader();
    SOAPBody body = envelope.getBody();								
    								

    Approach 2: from SOAPMessage object:

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

  3. Adding contents to the body

    Example:

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

    Example:

    Name name = soapFactory.createName("symbol");
    SOAPElement symbol = bodyElement.addChildElement(name);
    symbol.addTextNode("SUNW");								
    								
    Generates XML fragment like following:
    
    <symbol>SUNW</symbol>
    								
    								

  4. Getting a SOAPConnection object

    SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
    SOAPConnection connection = soapConnectionFactory.createConnection();								
    								

    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. This kind of connection is called a point-to-point connection because it goes from one endpoint to another endpoint. Messages sent using the SAAJ API are called request-response messages. They are sent over a SOAPConnection object with the method call, which sends a message (a request) and then blocks until it receives the reply (a response).

  5. Sending a message

    // Create an endpint point which is either URL or String type
    java.net.URL endpoint = new URL("http://wombat.ztrade.com/quotes");
    
    // Send a SOAPMessage (request) and then wait for SOAPMessage (response)
    SOAPMessage response = connection.call(message, endpoint);								
    								

    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.

  6. Getting the content of a message

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

    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.

Adding content to SOAPHeader

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.

XML fragment generated:


<SOAP-ENV:Header>
    <wsi:Claim conformsTo="http://ws-i.org/profiles/basic1.0/" 
                xmlns:wsi="http://ws-i.org/schemas/conformanceClaim/"/>
</SOAP-ENV:Header>
					
					
A conformance claim header has no content.

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 SOAPBody

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:

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");					
					
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.

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>
</PO:PurchaseLineItems>
					
					

Adding and accessing attachments

Create from AttachmentPart object:

AttachmentPart attachment = message.createAttachmentPart();					
					
AttachmentPart is made of two parts: application-specific content and associated MIME headers (Content-Type):
attachment.setMimeHeader("Content-Type", "application/xml");					
					

Adding contents to attachment (Option 1: Setting 'Content' and 'ContentId'):

String stringContent = "Update address for Sunny Skies " 
stringContent += "Inc., to 10 Upbeat Street, Pleasant Grove, CA 95439";
attachment.setContent(stringContent, "text/plain");
attachment.setContentId("update_address");
message.addAttachmentPart(attachment);										
					
The code fragment above 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.

As with AttachmentPart.setContent(...), the Object may be a String, a stream, a javax.xml.transform.Source object, or a javax.activation.DataHandler object.

Adding Contents to Attachment (Option 2: Using DataHandler):

// Create DataHandler object
URL url = new URL ("http://greatproducts.com/gizmos/img.jpg");
DataHandler dataHandler = new DataHandler(url);

AttachmentPart attachment = message.createAttachmentPart(dataHandler);

// Note that there is no need to set Content Type
attachment.setContentId("attached_image");
message.addAttachmentPart(attachment);
					
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: 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 attachments:

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

SOAP Header attributes: actor and mustUnderstand

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.

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 two SOAPHeaderElement objects, each of which sets its actor attribute and mustUnderstand 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");
orderHeader.setMustUnderstand(true);

Name shipping = soapFactory.createName("shippingDesk", nameSpace, nameSpaceURI);
SOAPHeaderElement shippingHeader = header.addHeaderElement(shipping);
shippingHeader.setActor("http://gizmos.com/shipping");
shippingHeader.setMustUnderstand(true);
					

Retrieving all SOAPHeaderElements with a particular Actor

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:

// Note that an Actor is identified by an URL
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:
// All headers with defined Actor are detached from the SOAPHeader object
Iterator headerElements = header.extractHeaderElements("http://gizmos.com/orders");					
					

Creating SOAPHeaderElement with mustUnderstand attribute

The Java code:

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");
					
The XML fragment:

<SOAP-ENV:Header>
	<t:Transaction xmlns:t="http://gizmos.com/orders"
			SOAP-ENV:mustUnderstand="1">
		5
	</t:Transaction>
</SOAP-ENV:Header>
					
					

SOAPFault object

Represents SOAP Fault element in SOAP body. Parties that can generate SOAPFault (for example):

SOAPFault object contains:

  1. Fault Code (mandatory)

    Required in SOAPFault object (VersionMismatch, MustUnderstand, Client, Server).

  2. Fault String (mandatory)

    Human readable explanation of the fault

  3. Fault Actor (conditional)

    Required if SOAPHeader object has one or more actor attributes and fault was caused by header processing.

  4. Detail object (conditional)

    Required if the fault is error related to the SOAPBody object. If not present in Client fault, SOAPBody is assumed to be OK.

SOAPFault with no Detail object:

// Create SOAPBody object
SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
SOAPBody body = envelope.getBody();

// Create and fill up SOAPFault object.
// Note that Detail object is not being set here since the fault has
// nothing to do with SOAPBody
SOAPFault fault = body.addFault();
fault.setFaultCode("Server");
fault.setFaultActor("http://gizmos.com/orders");
fault.setFaultString("Server not responding");										
					

SOAPFault with Detail object:

// Create SOAPFault object
SOAPFault fault = body.addFault();

// Set fault code and fault string
fault.setFaultCode("Client");
fault.setFaultString("Message does not have necessary info");

// Detail object contains two DetailEntry's
Detail detail = fault.addDetail();
Name entryName = envelope.createName("order", "PO", "http://gizmos.com/orders/");
DetailEntry entry = detail.addDetailEntry(entryName);
entry.addTextNode("quantity element does not have a value");
Name entryName2 = envelope.createName("confirmation", "PO", "http://gizmos.com/confirm");
DetailEntry entry2 = detail.addDetailEntry(entryName2);
entry2.addTextNode("Incomplete address: no zip code");					
					

Retrieving SOAPFault:

// Get SOAPBody object
SOAPBody body = newmsg.getSOAPPart().getEnvelope().getBody();

// Check if SOAPFault is present in the message
if ( body.hasFault() ) {
	SOAPFault newFault = body.getFault();
	String code = newFault.getFaultCode();
	String string = newFault.getFaultString();
	String actor = newFault.getFaultActor();
	if ( actor != null ) { System.out.println(" fault actor = " + actor); }
}					
					

Retrieving Detail Object:

// Get Detail object
Detail newDetail = newFault.getDetail();

// Get the list of DetailEntry's
if ( newDetail != null) {
	Iterator it = newDetail.getDetailEntries();
	while ( it.hasNext() ) {
		DetailEntry entry = (DetailEntry)it.next();
		String value = entry.getValue();
		System.out.println(" Detail entry = " + value);
	}
}					
					

Professional hosting     Belorussian informational portal         Free SCWCD 1.4 Study Guide     Free SCBCD 1.3 Study Guide     SCDJWS 1.4 Quiz     Free IBM Certified Associate Developer Study Guide     Free SCJP 5.0 (Tiger) Study Guide     Free Mock Exam Engine     IBM Test 000-287. Enterprise Application Development with IBM WebSphere Studio, V5.0 Study Guide     IBM Test 000-255. Developing with IBM Rational Application Developer for WebSphere Software V6 Study Guide


Hosting provided by PerfoHost: KVM VPS provider. See PefoHost's KVM VPS vs OpenVZ/Virtuozzo vs XEN VPS comparative chart.
CRM-exporter: Vehicle Database Script 1999-2011