Movatterモバイル変換


[0]ホーム

URL:


Document Information

Preface

Part I Introduction

1.  Overview

2.  Using the Tutorial Examples

Part II The Web Tier

3.  Getting Started with Web Applications

4.  Java Servlet Technology

5.  JavaServer Pages Technology

6.  JavaServer Pages Documents

7.  JavaServer Pages Standard Tag Library

8.  Custom Tags in JSP Pages

9.  Scripting in JSP Pages

10.  JavaServer Faces Technology

11.  Using JavaServer Faces Technology in JSP Pages

12.  Developing with JavaServer Faces Technology

13.  Creating Custom UI Components

14.  Configuring JavaServer Faces Applications

15.  Internationalizing and Localizing Web Applications

Part III Web Services

16.  Building Web Services with JAX-WS

17.  Binding between XML Schema and Java Classes

18.  Streaming API for XML

19.  SOAP with Attachments API for Java

Overview of SAAJ

SAAJ Messages

The Structure of an XML Document

What Is in a Message?

SAAJ and DOM

SAAJ Connections

SOAPConnection Objects

SAAJ Tutorial

Creating and Sending a Simple Message

Creating a Message

Parts of a Message

Accessing Elements of a Message

Adding Content to the Body

Getting aSOAPConnection Object

Sending a Message

Getting the Content of a Message

Adding Content to the Header

Adding Content to theSOAPPart Object

Adding a Document to the SOAP Body

Manipulating Message Content Using SAAJ or DOM APIs

Adding Attachments

Creating anAttachmentPart Object and Adding Content

Accessing anAttachmentPart Object

Adding Attributes

Header Attributes

Using SOAP Faults

Overview of SOAP Faults

Creating and Populating aSOAPFault Object

Retrieving Fault Information

Code Examples

Request Example

Header Example

Building and Running the Header Example

DOM and DOMSource Examples

Examining theDOMExample Class

Examining theDOMSrcExample Class

Building and Running the DOM and DOMSource Examples

Attachments Example

Building and Running the Attachments Example

SOAP Fault Example

Building and Running the SOAP Fault Example

Further Information about SAAJ

Part IV Enterprise Beans

20.  Enterprise Beans

21.  Getting Started with Enterprise Beans

22.  Session Bean Examples

23.  A Message-Driven Bean Example

Part V Persistence

24.  Introduction to the Java Persistence API

25.  Persistence in the Web Tier

26.  Persistence in the EJB Tier

27.  The Java Persistence Query Language

Part VI Services

28.  Introduction to Security in the Java EE Platform

29.  Securing Java EE Applications

30.  Securing Web Applications

31.  The Java Message Service API

32.  Java EE Examples Using the JMS API

33.  Transactions

34.  Resource Connections

35.  Connector Architecture

Part VII Case Studies

36.  The Coffee Break Application

37.  The Duke's Bank Application

Part VIII Appendixes

A.  Java Encoding Schemes

B.  About the Authors

Index

 

The Java EE 5 Tutorial

Java Coffee Cup logo
PreviousContentsNext

SAAJ Tutorial

This tutorial walks you through how to use the SAAJ API. First,it covers the basics of creating and sending a simple SOAP message. Thenyou will learn more details about adding content to messages, including how tocreate SOAP faults and attributes. Finally, you will learn how to send amessage and retrieve the content of the response.

After going through this tutorial, you will know how to perform the followingtasks:

In the sectionCode Examples, you will see the code fragments from earlier partsof the tutorial in runnable applications, which you can test yourself. To seehow the SAAJ API can be used in server code, see the SAAJpart of the Coffee Break case study (SAAJ Coffee Supplier Service), which shows an exampleof both the client and the server code for a web service application.

A SAAJ client can send request-response messages to web services that are implementedto do request-response messaging. This section demonstrates how you can do this.

Creating and Sending a Simple Message

This section covers the basics of creating and sending a simple message andretrieving the content of the response. It includes the following topics:

Creating a Message

The first step is to create a message using aMessageFactory object. TheSAAJ API provides a default implementation of theMessageFactory class, thus making iteasy to get an instance. The following code fragment illustrates getting an instanceof the default message factory and then using it to create a message.

MessageFactory factory = MessageFactory.newInstance();SOAPMessage message = factory.createMessage();

As is true of thenewInstance method forSOAPConnectionFactory, thenewInstance methodforMessageFactory is static, so you invoke it by callingMessageFactory.newInstance.

If you specify no arguments to thenewInstance method, it creates a messagefactory for SOAP 1.1 messages. To create a message factory that allows youto 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 orSOAP 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 mightbe of either type.

Parts of a Message

ASOAPMessage object is required to have certain elements, and, as stated previously,the SAAJ API simplifies things for you by returning a newSOAPMessage objectthat already contains these elements. When you callcreateMessage with no arguments, the messagethat is created automatically has the following:

I. ASOAPPart object that contains A. ASOAPEnvelope object that contains 1. An emptySOAPHeader object 2. An emptySOAPBody object

TheSOAPHeader object is optional and can be deleted if it is notneeded. However, if there is one, it must precede theSOAPBody object.TheSOAPBody object can hold either the content of the message or afault message that contains status information or details about a problem with themessage. The sectionUsing SOAP Faults walks you through how to useSOAPFault objects.

Accessing Elements of a Message

The next step in creating a message is to access its partsso that content can be added. There are two ways to do this.TheSOAPMessage objectmessage, created in the preceding code fragment, is theplace to start.

The first way to access the parts of the message is towork your way through the structure of the message. The message contains aSOAPPart object, so you use thegetSOAPPart method ofmessage to retrieveit:

SOAPPart soapPart = message.getSOAPPart();

Next you can use thegetEnvelope method ofsoapPart to retrieve theSOAPEnvelope object that it contains.

SOAPEnvelope envelope = soapPart.getEnvelope();

You can now use thegetHeader andgetBody methods ofenvelope toretrieve its emptySOAPHeader andSOAPBody objects.

SOAPHeader header = envelope.getHeader();SOAPBody body = envelope.getBody();

The second way to access the parts of the message is toretrieve the message header and body directly, without retrieving theSOAPPart orSOAPEnvelope.To do so, use thegetSOAPHeader andgetSOAPBody methods ofSOAPMessage:

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.) BecauseallSOAPElement objects, includingSOAPHeader objects, are derived from theNode interface, youuse the methodNode.detachNode to deleteheader.

header.detachNode();
Adding Content to the Body

TheSOAPBody object contains either content or a fault. To add content tothe body, you normally create one or moreSOAPBodyElement objects to holdthe content. You can also add subelements to theSOAPBodyElement objects byusing theaddChildElement method. For each element or child element, you add contentby using theaddTextNode method.

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


Note -You can useName objects instead ofQName objects.Name objects arespecific to the SAAJ API, and you create them using eitherSOAPEnvelope methods orSOAPFactory methods. However, theName interface may be deprecated at a future release.

TheSOAPFactory class also lets you create XML elements when you are notcreating an entire message or do not have access to a completeSOAPMessageobject. For example, JAX-RPC implementations often work with XML fragments rather than completeSOAPMessageobjects. Consequently, they do not have access to aSOAPEnvelope object, and thismakes using aSOAPFactory object to createName objects very useful. In addition toa method for creatingName objects, theSOAPFactory class provides methods for creatingDetail objects and SOAP fragments. You will find an explanation ofDetailobjects inOverview of SOAP Faults andCreating and Populating aSOAPFault Object.


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

The following code fragment retrieves theSOAPBody objectbody frommessage, constructsaQName object for the element to be added, and adds a newSOAPBodyElement object tobody.

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

At this point,body contains aSOAPBodyElement object identified by theQNameobjectbodyName, but there is still no content inbodyElement. Assuming that youwant to get a quote for the stock of Sun Microsystems, Inc., youneed to create a child element for the symbol using theaddChildElementmethod. Then you need to give it the stock symbol using theaddTextNode method. TheQName object for the newSOAPElement objectsymbol isinitialized with only a local name because child elements inherit the prefix andURI 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 aSOAPPart object mustbe in XML format. The SAAJ API takes care of this foryou, building the appropriate XML constructs automatically when you call methods such asaddBodyElement,addChildElement, andaddTextNode. Note that you can call the methodaddTextNode onlyon an element such asbodyElement or any child elements that are added toit. You cannot calladdTextNode on aSOAPHeader orSOAPBody object becausethey contain elements and not text.

The content that you have just added to yourSOAPBody object will looklike 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 itrelates to your SAAJ code. Note that an XML parser does not careabout indentations, but they are generally used to indicate element levels and therebymake 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, indicatedbySOAP-ENV:Envelope. Note thatEnvelope is the name of the element, andSOAP-ENV is the namespace prefix. The interfaceSOAPEnvelope represents a SOAP envelope.

The first line signals the beginning of the SOAP envelope element, and thelast line signals the end of it; everything in between is partof the SOAP envelope. The second line is an example of an attributefor the SOAP envelope element. Because a SOAP envelope element always contains thisattribute with this value, aSOAPMessage object comes with it automatically included.xmlns standsfor “XML namespace,” and its value is the URI of the namespace associatedwithEnvelope.

The next line is an empty SOAP header. You could remove itby callingheader.detachNode after thegetSOAPHeader call.

The next two lines mark the beginning and end of the SOAP body,represented in SAAJ by aSOAPBody object. The next step is to addcontent 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 theSOAPBodyElementbodyElement in your code represents.GetLastTradePrice is itslocal name,m is its namespace prefix, andhttp://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>

TheString"SUNW" is the text node for the element<symbol>. ThisStringobject is the message content that your recipient, the stock quote service, receives.

The following example shows how to add multipleSOAPElement objects and add textto each of them. The code first creates theSOAPBodyElement objectpurchaseLineItems,which has a fully qualified name associated with it. That is, theQNameobject for it has a namespace URI, a local name, and a namespaceprefix. As you saw earlier, aSOAPBodyElement object is required to have a fullyqualified name, but child elements added to it, such asSOAPElement objects,can haveName 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 theSOAP 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 aSOAPConnection Object

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

To send a message, a SAAJ client can use aSOAPConnection object. ASOAPConnection object is a point-to-point connection, meaning that it goes directly from thesender to the destination (usually a URL) that the sender specifies.

The first step is to obtain aSOAPConnectionFactory object that you can useto create your connection. The SAAJ API makes this easy by providing theSOAPConnectionFactory class with a default implementation. You can get an instance of thisimplementation using the following line of code.

SOAPConnectionFactory soapConnectionFactory =    SOAPConnectionFactory.newInstance();

Now you can usesoapConnectionFactory to create aSOAPConnection object.

SOAPConnection connection = soapConnectionFactory.createConnection();

You will useconnection to send the message that you created.

Sending a Message

A SAAJ client calls theSOAPConnection methodcall on aSOAPConnection objectto send a message. Thecall method takes two arguments: the message being sentand the destination to which the message should go. This message isgoing to the stock quote service indicated by theURL objectendpoint.

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;theSOAPMessage objectresponse 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 agood idea to close a connection as soon as you are finished usingit.

connection.close();
Getting the Content of a Message

The initial steps for retrieving a message’s content are the same as thosefor giving content to a message: Either you use theMessage object toget theSOAPBody object, or you access theSOAPBody object through theSOAPPart andSOAPEnvelope objects.

Then you access theSOAPBody object’sSOAPBodyElement object, because that is theelement to which content was added in the example. (In a later sectionyou will see how to add content directly to theSOAPPart object, inwhich case you would not need to access theSOAPBodyElement object to addcontent or to retrieve it.)

To get the content, which was added with the methodSOAPElement.addTextNode, youcall the methodNode.getValue. Note thatgetValue returns the value of theimmediate child of the element that calls the method. Therefore, in the followingcode fragment, thegetValue method is called onbodyElement, the element on whichtheaddTextNode method was called.

To accessbodyElement, you call thegetChildElements method onsoapBody. PassingbodyNametogetChildElements returns ajava.util.Iterator object that contains all the child elements identifiedby theName objectbodyName. You already know that there is onlyone, so calling thenext method on it will return theSOAPBodyElementyou want. Note that theIterator.next method returns a JavaObject, so youneed to cast theObject it returns to aSOAPBodyElement object before assigningit to the variablebodyElement.

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 namebodyName, you would have touse awhile loop using theIterator.hasNext method to make sure thatyou 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 basicrequest-response message and get the content from the response. The next sections providemore detail on adding content to messages.

Adding Content to the Header

To add content to the header, you create aSOAPHeaderElement object. As withall new elements, it must have an associatedQName object.

For example, suppose you want to add a conformance claim header to themessage to state that your message conforms to the WS-I Basic Profile. Thefollowing code fragment retrieves theSOAPHeader object frommessage and adds a newSOAPHeaderElement object to it. ThisSOAPHeaderElement object contains the correct qualified name and attributefor a WS-I conformance claim header.

SOAPHeader header = message.getSOAPHeader();QName headerName = new QName("http://ws-i.org/schemas/conformanceClaim/",    "Claim", "wsi");SOAPHeaderElement headerElement =    header.addHeaderElement(headerName);headerElement.addAttribute(new QName("conformsTo"),    "http://ws-i.org/profiles/basic/1.1/");

At this point,header contains theSOAPHeaderElement objectheaderElement identified by theQName objectheaderName. Note that theaddHeaderElement method both createsheaderElement andadds it toheader.

A conformance claim header has no content. This code produces the following XMLheader:

<SOAP-ENV:Header>  <wsi:Claim    xmlns:wsi="http://ws-i.org/schemas/conformanceClaim/"    conformsTo="http://ws-i.org/profiles/basic/1.1/"/></SOAP-ENV:Header>

For more information about creating SOAP messages that conform to WS-I, see theConformance Claim Attachment Mechanisms document described in theConformance section of the WS-I Basic Profile.

For a different kind of header, you might want to add contenttoheaderElement. The following line of code uses the methodaddTextNode to dothis.

headerElement.addTextNode("order");

Now you have theSOAPHeader objectheader that contains aSOAPHeaderElement object whosecontent is"order".

Adding Content to theSOAPPart Object

If the content you want to send is in a file, SAAJprovides an easy way to add it directly to theSOAPPart object. Thismeans that you do not access theSOAPBody object and build the XML contentyourself, as you did in the preceding section.

To add a file directly to theSOAPPart object, you use ajavax.xml.transform.Sourceobject from JAXP (the Java API for XML Processing). There are three typesofSource objects:SAXSource,DOMSource, andStreamSource. AStreamSource object holds an XMLdocument in text form.SAXSource andDOMSource objects hold content along with theinstructions for transforming the content into an XML document.

The following code fragment uses the JAXP API to build aDOMSourceobject that is passed to theSOAPPart.setContent method. The first three lines ofcode get aDocumentBuilderFactory object and use it to create theDocumentBuilder objectbuilder. Because SOAP messages use namespaces, you should set theNamespaceAware propertyfor the factory to true. Thenbuilder parses the content file to produceaDocument object.

DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();dbFactory.setNamespaceAware(true);DocumentBuilder builder = dbFactory.newDocumentBuilder();Document document = builder.parse("file:///music/order/soap.xml");DOMSource domSource = new DOMSource(document);

The following two lines of code access theSOAPPart object (using theSOAPMessageobjectmessage) and set the newDocument object as its content. TheSOAPPart.setContentmethod not only sets content for theSOAPBody object but also sets theappropriate header for theSOAPHeader object.

SOAPPart soapPart = message.getSOAPPart();soapPart.setContent(domSource);

The XML file you use to set the content of theSOAPPartobject must includeEnvelope andBody elements:

<SOAP-ENV:Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">  <SOAP-ENV:Body>  ...  </SOAP-ENV:Body></SOAP-ENV:Envelope>

You will see other ways to add content to a message inthe sectionsAdding a Document to the SOAP Body andAdding Attachments.

Adding a Document to the SOAP Body

In addition to setting the content of the entire SOAP message tothat of aDOMSource object, you can add a DOM document directly to thebody of the message. This capability means that you do not haveto create ajavax.xml.transform.Source object. After you parse the document, you can add itdirectly to the message body:

SOAPBody body = message.getSOAPBody();SOAPBodyElement docElement = body.addDocument(document);

Manipulating Message Content Using SAAJ or DOM APIs

Because SAAJ nodes and elements implement the DOMNode andElement interfaces,you have many options for adding or changing message content:

  • Use only DOM APIs.

  • Use only SAAJ APIs.

  • Use SAAJ APIs and then switch to using DOM APIs.

  • Use DOM APIs and then switch to using SAAJ APIs.

The first three of these cause no problems. After you have createda message, whether or not you have imported its content from another document, youcan start adding or changing nodes using either SAAJ or DOM APIs.

But if you use DOM APIs and then switch to using SAAJAPIs to manipulate the document, any references to objects within the tree thatwere obtained using DOM APIs are no longer valid. If you must useSAAJ APIs after using DOM APIs, you should set all your DOM typedreferences to null, because they can become invalid. For more information about theexact cases in which references become invalid, see the SAAJ API documentation.

The basic rule is that you can continue manipulating the message content usingSAAJ APIs as long as you want to, but after you startmanipulating it using DOM, you should no longer use SAAJ APIs.

Adding Attachments

AnAttachmentPart object can contain any type of content, including XML. And becausethe SOAP part can contain only XML content, you must use anAttachmentPartobject for any content that is not in XML format.

Creating anAttachmentPart Object and Adding Content

TheSOAPMessage object creates anAttachmentPart object, and the message also mustadd the attachment to itself after content has been added. TheSOAPMessage classhas three methods for creating anAttachmentPart object.

The first method creates an attachment with no content. In this case, anAttachmentPart method is used later to add content to the attachment.

AttachmentPart attachment = message.createAttachmentPart();

You add content toattachment by using theAttachmentPart methodsetContent. This methodtakes two parameters: a JavaObject for the content, and aString object forthe MIME content type that is used to encode the object. Contentin theSOAPBody part of a message automatically has aContent-Type header withthe value"text/xml" because the content must be in XML. In contrast, thetype of content in anAttachmentPart object must be specified because it canbe any type.

EachAttachmentPart object has one or more MIME headers associated with it. Whenyou specify a type to thesetContent method, that type is used forthe headerContent-Type. Note thatContent-Type is the only header that is required.You may set other optional headers, such asContent-Id andContent-Location. Forconvenience, SAAJ providesget andset methods for the headersContent-Type,Content-Id, andContent-Location.These headers can be helpful in accessing a particular attachment when a messagehas multiple attachments. For example, to access the attachments that have particular headers,you can call theSOAPMessage methodgetAttachments and pass it aMIMEHeadersobject containing the MIME headers you are interested in.

The following code fragment shows one of the ways to use themethodsetContent. The JavaObject in the first parameter can be aString,a stream, ajavax.xml.transform.Source object, or ajavax.activation.DataHandler object. The JavaObject beingadded in the following code fragment is aString, which is plain text,so the second argument must be"text/plain". The code also sets a contentidentifier, which can be used to identify thisAttachmentPart object. After you have addedcontent toattachment, you must add it to theSOAPMessage object, something thatis done in the last line.

String stringContent = "Update address for Sunny Skies " +    "Inc., to 10 Upbeat Street, Pleasant Grove, CA 95439";attachment.setContent(stringContent, "text/plain");attachment.setContentId("update_address");message.addAttachmentPart(attachment);

Theattachment variable now represents anAttachmentPart object that contains the stringstringContent and has a header that contains the stringtext/plain. It also has aContent-Id header withupdate_address as its value. Andattachment is now part ofmessage.

The other twoSOAPMessage.createAttachment methods create anAttachmentPart object complete with content. One isvery similar to theAttachmentPart.setContent method in that it takes the same parametersand does essentially the same thing. It takes a JavaObject containing thecontent and aString giving the content type. As withAttachmentPart.setContent, theObjectcan be aString, a stream, ajavax.xml.transform.Source object, or ajavax.activation.DataHandler object.

The other method for creating anAttachmentPart object with content takes aDataHandlerobject, which is part of the JavaBeans Activation Framework (JAF). Using aDataHandlerobject is fairly straightforward. First, you create ajava.net.URL object for the file youwant to add as content. Then you create aDataHandler object initialized withtheURL object:

URL url = new URL("http://greatproducts.com/gizmos/img.jpg");DataHandler dataHandler = new DataHandler(url);AttachmentPart attachment = message.createAttachmentPart(dataHandler);attachment.setContentId("attached_image");message.addAttachmentPart(attachment);

You might note two things about this code fragment. First, it setsa header forContent-ID using the methodsetContentId. This method takes aString thatcan be whatever you like to identify the attachment. Second, unlike the othermethods for setting content, this one does not take aString forContent-Type. Thismethod takes care of setting theContent-Type header for you, something that ispossible because one of the things aDataHandler object does is todetermine the data type of the file it contains.

Accessing anAttachmentPart Object

If you receive a message with attachments or want to change anattachment to a message you are building, you need to access the attachment.TheSOAPMessage class provides two versions of thegetAttachments method for retrieving itsAttachmentPart objects. When it is given no argument, the methodSOAPMessage.getAttachments returns ajava.util.Iteratorobject over all theAttachmentPart objects in a message. WhengetAttachments is givenaMimeHeaders object, which is a list of MIME headers,getAttachments returnsan iterator over theAttachmentPart objects that have a header that matches oneof the headers in the list. The following code uses thegetAttachments methodthat takes no arguments and thus retrieves all theAttachmentPart objects in theSOAPMessage objectmessage. Then it prints the content ID, the content type, andthe content of eachAttachmentPart object.

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.equals("text/plain")) {        Object content = attachment.getContent();        System.out.println("Attachment contains:\n" + content);    }}

Adding Attributes

An XML element can have one or more attributes that give information aboutthat element. An attribute consists of a name for the attribute followed immediatelyby an equal sign (=) and its value.

TheSOAPElement interface provides methods for adding an attribute, for getting the valueof an attribute, and for removing an attribute. For example, in the followingcode fragment, the attribute namedid is added to theSOAPElement objectperson. Becauseperson is aSOAPElement object rather than aSOAPBodyElement object orSOAPHeaderElement object,it is legal for itsQName object to contain only a local name.

QName attributeName = new QName("id");person.addAttribute(attributeName, "Person7");

These lines of code will generate the first line in the followingXML fragment.

<person>  ...</person>

The following line of code retrieves the value of the attribute whose nameisid.

String attributeValue = person.getAttributeValue(attributeName);

If you had added two or more attributes toperson, the preceding lineof code would have returned only the value for the attribute namedid.If you wanted to retrieve the values for all the attributes forperson,you would use the methodgetAllAttributes, which returns an iterator over allthe values. The following lines of code retrieve and print each value ona separate line until there are no more attribute values. Note that theIterator.next method returns a JavaObject, which is cast to aQName object sothat it can be assigned to theQName objectattributeName. (The examplesinDOM and DOMSource Examples use code similar to this.)

Iterator iterator = person.getAllAttributesAsQNames();while (iterator.hasNext()){    QName attributeName = (QName) iterator.next();    System.out.println("Attribute name is " + attributeName.toString());    System.out.println("Attribute value is " +         element.getAttributeValue(attributeName));}

The following line of code removes the attribute namedid fromperson.The variablesuccessful will betrue if the attribute was removed successfully.

boolean successful = person.removeAttribute(attributeName);

In this section you have seen how to add, retrieve, and removeattributes. This information is general in that it applies to any element. Thenext section discusses attributes that can be added only to header elements.

Header Attributes

Attributes that appear in aSOAPHeaderElement object determine how a recipient processes amessage. You can think of header attributes as offering a way to extenda message, giving information about such things as authentication, transaction management, payment, andso on. A header attribute refines the meaning of the header, whereas theheader refines the meaning of the message contained in the SOAP body.

The SOAP 1.1 specification defines two attributes that can appear only inSOAPHeaderElementobjects:actor andmustUnderstand.

The SOAP 1.2 specification defines three such attributes:role (a new name foractor),mustUnderstand, andrelay.

The next sections discuss these attributes.

SeeHeader Example for an example that uses the code shown in this section.

Theactor Attribute

Theactor attribute is optional, but if it is used, it must appearin aSOAPHeaderElement object. Its purpose is to indicate the recipient of aheader element. The default actor is the message’s ultimate recipient; that is, ifno actor attribute is supplied, the message goes directly to the ultimate recipient.

Anactor is an application that can both receive SOAP messages and forwardthem to the next actor. The ability to specify one or more actorsas intermediate recipients makes it possible to route a message to multiple recipientsand to supply header information that applies specifically to each of the recipients.

For example, suppose that a message is an incoming purchase order. ItsSOAPHeader object might haveSOAPHeaderElement objects with actor attributes that route the messageto applications that function as the order desk, the shipping desk, the confirmationdesk, and the billing department. Each of these applications will take the appropriateaction, remove theSOAPHeaderElement objects relevant to it, and send the message on tothe next actor.


Note -Although the SAAJ API provides the API for adding these attributes, it doesnot supply the API for processing them. For example, the actor attribute requiresthat there be an implementation such as a messaging provider service to routethe message from one actor to the next.


An actor is identified by its URI. For example, the following lineof code, in whichorderHeader is aSOAPHeaderElement object, sets the actor to thegiven URI.

orderHeader.setActor("http://gizmos.com/orders");

Additional actors can be set in their ownSOAPHeaderElement objects. The following codefragment first uses theSOAPMessage objectmessage to get itsSOAPHeader objectheader. Thenheader creates fourSOAPHeaderElement objects, each of which sets itsactor attribute.

SOAPHeader header = message.getSOAPHeader();SOAPFactory soapFactory = SOAPFactory.newInstance();String nameSpace = "ns";String nameSpaceURI = "http://gizmos.com/NSURI";QName order = new QName(nameSpaceURI, "orderDesk", nameSpace);SOAPHeaderElement orderHeader = header.addHeaderElement(order);orderHeader.setActor("http://gizmos.com/orders");QName shipping = new QName(nameSpaceURI, "shippingDesk", nameSpace);SOAPHeaderElement shippingHeader = header.addHeaderElement(shipping);shippingHeader.setActor("http://gizmos.com/shipping");QName confirmation = new QName(nameSpaceURI, "confirmationDesk", nameSpace);SOAPHeaderElement confirmationHeader = header.addHeaderElement(confirmation);confirmationHeader.setActor("http://gizmos.com/confirmations");QName billing = new QName(nameSpaceURI, "billingDesk", nameSpace);SOAPHeaderElement billingHeader = header.addHeaderElement(billing);billingHeader.setActor("http://gizmos.com/billing");

TheSOAPHeader interface provides two methods that return ajava.util.Iterator object over alltheSOAPHeaderElement objects that have an actor that matches the specified actor.The first method,examineHeaderElements, returns an iterator over all the elements that have thespecified actor.

java.util.Iterator headerElements =    header.examineHeaderElements("http://gizmos.com/orders");

The second method,extractHeaderElements, not only returns an iterator over all theSOAPHeaderElementobjects that have the specified actor attribute but also detaches them from theSOAPHeader object. So, for example, after the order desk application did its work,it would callextractHeaderElements to remove all theSOAPHeaderElement objects that applied toit.

java.util.Iterator headerElements =    header.extractHeaderElements("http://gizmos.com/orders");

EachSOAPHeaderElement object can have only one actor attribute, but the same actorcan be an attribute for multipleSOAPHeaderElement objects.

Two additionalSOAPHeader methods,examineAllHeaderElements andextractAllHeaderElements, allow you to examine or extractall the header elements, whether or not they have an actor attribute. Forexample, you could use the following code to display the values ofall the header elements:

Iterator allHeaders = header.examineAllHeaderElements();while (allHeaders.hasNext()) {    SOAPHeaderElement headerElement = (SOAPHeaderElement)allHeaders.next();    QName headerName = headerElement.getElementQName();    System.out.println("\nHeader name is " + headerName.toString());    System.out.println("Actor is " + headerElement.getActor());}
Therole Attribute

Therole attribute is the name used by the SOAP 1.2 specification forthe SOAP 1.2actor attribute. TheSOAPHeaderElement methodssetRole andgetRole perform thesame functions as thesetActor andgetActor methods.

ThemustUnderstand Attribute

The other attribute that must be added only to aSOAPHeaderElement objectismustUnderstand. This attribute says whether or not the recipient (indicated by theactor attribute) is required to process a header entry. When the value ofthemustUnderstand attribute istrue, the actor must understand the semantics of theheader entry and must process it correctly to those semantics. If the valueisfalse, processing the header entry is optional. ASOAPHeaderElement object with nomustUnderstand attribute is equivalent to one with amustUnderstand attribute whose value isfalse.

ThemustUnderstand attribute is used to call attention to the fact that thesemantics in an element are different from the semantics in its parent orpeer elements. This allows for robust evolution, ensuring that a change in semanticswill not be silently ignored by those who may not fully understand it.

If the actor for a header that has amustUnderstand attribute set totrue cannot process the header, it must send a SOAP fault back tothe sender. (SeeUsing SOAP Faults.) The actor must not change state or cause anyside effects, so that, to an outside observer, it appears that the faultwas sent before any header processing was done.

For example, you could set themustUnderstand attribute totrue for theconfirmationHeaderin the code fragment inTheactor Attribute:

QName confirmation = new QName(nameSpaceURI, "confirmationDesk", nameSpace);SOAPHeaderElement confirmationHeader = header.addHeaderElement(confirmation);confirmationHeader.setActor("http://gizmos.com/confirmations");confirmationHeader.setMustUnderstand(true);

This fragment produces the following XML:

<ns:confirmationDesk  xmlns:ns="http://gizmos.com/NSURI"  SOAP-ENV:actor="http://gizmos.com/confirmations"  SOAP-ENV:mustUnderstand="1"/>

You can use thegetMustUnderstand method to retrieve the value of themustUnderstandattribute. For example, you could add the following to the code fragment atthe end of the preceding section:

System.out.println("mustUnderstand is " + headerElement.getMustUnderstand());
Therelay Attribute

The SOAP 1.2 specification adds a third attribute to aSOAPHeaderElement,relay.This attribute, likemustUnderstand, is a boolean value. If it is settotrue, it indicates that the SOAP header block must not be processedby any node that is targeted by the header block, but must onlybe passed on to the next targeted node. This attribute is ignored onheader blocks whosemustUnderstand attribute is set to true or that are targetedat the ultimate receiver (which is the default). The default value of thisattribute isfalse.

For example, you could set therelay element totrue for thebillingHeader in the code fragment inTheactor Attribute (also changingsetActor tosetRole):

QName billing = new QName(nameSpaceURI, "billingDesk", nameSpace);SOAPHeaderElement billingHeader = header.addHeaderElement(billing);billingHeader.setRole("http://gizmos.com/billing");billingHeader.setRelay(true);

This fragment produces the following XML:

<ns:billingDesk  xmlns:ns="http://gizmos.com/NSURI"  env:relay="true"  env:role="http://gizmos.com/billing"/>

To display the value of the attribute, callgetRelay:

System.out.println("relay is " + headerElement.getRelay());

Using SOAP Faults

In this section, you will see how to use the API forcreating and accessing a SOAP fault element in an XML message.

Overview of SOAP Faults

If you send a message that was not successful for some reason,you may get back a response containing a SOAP fault element, which givesyou status information, error information, or both. There can be only one SOAPfault element in a message, and it must be an entry in theSOAP body. Furthermore, if there is a SOAP fault element in the SOAPbody, there can be no other elements in the SOAP body. This meansthat when you add a SOAP fault element, you have effectively completed theconstruction of the SOAP body.

ASOAPFault object, the representation of a SOAP fault element in the SAAJAPI, is similar to anException object in that it conveys information abouta problem. However, aSOAPFault object is quite different in that it isan element in a message’sSOAPBody object rather than part of thetry/catch mechanism used forException objects. Also, as part of theSOAPBody object,which provides a simple means for sending mandatory information intended for the ultimaterecipient, aSOAPFault object only reports status or error information. It does nothalt the execution of an application, as anException object can.

If you are a client using the SAAJ API and are sendingpoint-to-point messages, the recipient of your message may add aSOAPFault object to theresponse to alert you to a problem. For example, if you sentan order with an incomplete address for where to send the order, theservice receiving the order might put aSOAPFault object in the return message tellingyou that part of the address was missing.

Another example of who might send a SOAP fault is an intermediaterecipient, or actor. As stated in the sectionAdding Attributes, an actor that cannot processa header that has amustUnderstand attribute with a value oftrue mustreturn a SOAP fault to the sender.

ASOAPFault object contains the following elements:

  • Fault code: Always required. The fault code must be a fully qualified name: it must contain a prefix followed by a local name. The SOAP specifications define a set of fault code local name values, which a developer can extend to cover other problems. (These are defined in section 4.4.1 of the SOAP 1.1 specification and in section 5.4.6 of the SOAP 1.2 specification.)Table 19-1 lists and describes the default fault code local names defined in the specifications.

    A SOAP 1.2 fault code can optionally have a hierarchy of one or more subcodes.

  • Fault string: Always required. A human-readable explanation of the fault.

  • Fault actor: Required if theSOAPHeader object contains one or moreactor attributes; optional if no actors are specified, meaning that the only actor is the ultimate destination. The fault actor, which is specified as a URI, identifies who caused the fault. For an explanation of what an actor is, seeTheactor Attribute.

  • Detailobject: Required if the fault is an error related to theSOAPBody object. If, for example, the fault code isClient, indicating that the message could not be processed because of a problem in theSOAPBody object, theSOAPFault object must contain aDetail object that gives details about the problem. If aSOAPFault object does not contain aDetail object, it can be assumed that theSOAPBody object was processed successfully.

Creating and Populating aSOAPFault Object

You have seen how to add content to aSOAPBody object; this sectionwalks you through adding aSOAPFault object to aSOAPBody object and thenadding its constituent parts.

As with adding content, the first step is to access theSOAPBodyobject.

SOAPBody body = message.getSOAPBody();

With theSOAPBody objectbody in hand, you can use it to createaSOAPFault object. The following line of code creates aSOAPFault object andadds it tobody.

SOAPFault fault = body.addFault();

TheSOAPFault interface provides convenience methods that create an element, add the newelement to theSOAPFault object, and add a text node, all in oneoperation. For example, in the following lines of SOAP 1.1 code, the methodsetFaultCode creates afaultcode element, adds it tofault, and adds aText node with the value"SOAP-ENV:Server" by specifying a default prefix and thenamespace URI for a SOAP envelope.

QName faultName = new QName(SOAPConstants.URI_NS_SOAP_ENVELOPE, "Server");fault.setFaultCode(faultName);fault.setFaultActor("http://gizmos.com/orders");fault.setFaultString("Server not responding");

The SOAP 1.2 code would look like this:

QName faultName = new QName(SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE, "Receiver");fault.setFaultCode(faultName);fault.setFaultRole("http://gizmos.com/order");fault.addFaultReasonText("Server not responding", Locale.US);

To add one or more subcodes to the fault code, call themethodfault.appendFaultSubcode, which takes aQName argument.

TheSOAPFault objectfault, created in the preceding lines of code, indicates thatthe cause of the problem is an unavailable server and that the actorathttp://gizmos.com/orders is having the problem. If the message were being routed onlyto its ultimate destination, there would have been no need to set afault actor. Also note thatfault does not have aDetail object because itdoes not relate to theSOAPBody object. (If you use SOAP 1.2, youcan use thesetFaultRole method instead ofsetFaultActor.)

The following SOAP 1.1 code fragment creates aSOAPFault object that includes aDetail object. Note that aSOAPFault object can have only oneDetail object,which is simply a container forDetailEntry objects, but theDetail object can havemultipleDetailEntry objects. TheDetail object in the following lines of code hastwoDetailEntry objects added to it.

SOAPFault fault = body.addFault();QName faultName = new QName(SOAPConstants.URI_NS_SOAP_ENVELOPE, "Client");fault.setFaultCode(faultName);fault.setFaultString("Message does not have necessary info");Detail detail = fault.addDetail();QName entryName = new QName("http://gizmos.com/orders/", "order", "PO");DetailEntry entry = detail.addDetailEntry(entryName);entry.addTextNode("Quantity element does not have a value");QName entryName2 = new QName("http://gizmos.com/orders/", "order", "PO");DetailEntry entry2 = detail.addDetailEntry(entryName2);entry2.addTextNode("Incomplete address: no zip code");

SeeSOAP Fault Example for an example that uses code like that shown in thissection.

The SOAP 1.1 and 1.2 specifications define slightly different values for a faultcode.Table 19-1 lists and describes these values.

Table 19-1 SOAP Fault Code Values

SOAP 1.1

SOAP 1.2

Description

VersionMismatch

VersionMismatch

The namespace or local namefor aSOAPEnvelope object was invalid.

MustUnderstand

MustUnderstand

An immediate child element of aSOAPHeader object haditsmustUnderstand attribute set totrue, and the processing party did not understandthe element or did not obey it.

Client

Sender

TheSOAPMessage object was not formedcorrectly or did not contain the information needed to succeed.

Server

Receiver

TheSOAPMessage object couldnot be processed because of a processing error, not because of a problemwith the message itself.

N/A

DataEncodingUnknown

A SOAP header block or SOAP body child elementinformation item targeted at the faulting SOAP node is scoped with a dataencoding that the faulting node does not support.

Retrieving Fault Information

Just as theSOAPFault interface provides convenience methods for adding information, it alsoprovides convenience methods for retrieving that information. The following code fragment shows whatyou might write to retrieve fault information from a message you received. Inthe code fragment,newMessage is theSOAPMessage object that has been sent toyou. Because aSOAPFault object must be part of theSOAPBody object, thefirst step is to access theSOAPBody object. Then the code teststo see whether theSOAPBody object contains aSOAPFault object. If itdoes, the code retrieves theSOAPFault object and uses it to retrieve its contents.The convenience methodsgetFaultCode,getFaultString, andgetFaultActor make retrieving the values very easy.

SOAPBody body = newMessage.getSOAPBody();if ( body.hasFault() ) {    SOAPFault newFault = body.getFault();    QName code = newFault.getFaultCodeAsQName();    String string = newFault.getFaultString();    String actor = newFault.getFaultActor();

To retrieve subcodes from a SOAP 1.2 fault, call the methodnewFault.getFaultSubcodes.

Next the code prints the values it has just retrieved. Not allmessages are required to have a fault actor, so the code tests tosee whether there is one. Testing whether the variableactor isnull works becausethe methodgetFaultActor returnsnull if a fault actor has not been set.

    System.out.println("SOAP fault contains: ");    System.out.println("  Fault code = " + code.toString());    System.out.println("  Local name = " + code.getLocalPart());    System.out.println("  Namespace prefix = " +        code.getPrefix() + ", bound to " + code.getNamespaceURI());    System.out.println("  Fault string = " + string);    if ( actor != null ) {        System.out.println("  Fault actor = " + actor);    }

The final task is to retrieve theDetail object and get itsDetailEntryobjects. The code uses theSOAPFault objectnewFault to retrieve theDetailobjectnewDetail, and then it usesnewDetail to call the methodgetDetailEntries. Thismethod returns thejava.util.Iterator objectentries, which contains all theDetailEntry objects innewDetail. Not allSOAPFault objects are required to have aDetail object, sothe code tests to see whethernewDetail isnull. If it isnot, the code prints the values of theDetailEntry objects as longas there are any.

Detail newDetail = newFault.getDetail();if (newDetail != null) {    Iterator entries = newDetail.getDetailEntries();    while ( entries.hasNext() ) {        DetailEntry newEntry = (DetailEntry)entries.next();        String value = newEntry.getValue();        System.out.println("  Detail entry = " + value);    }}

In summary, you have seen how to add aSOAPFault object and itscontents to a message as well as how to retrieve the contents.ASOAPFault object, which is optional, is added to theSOAPBody object toconvey status or error information. It must always have a fault codeand aString explanation of the fault. ASOAPFault object must indicate the actorthat is the source of the fault only when there are multiple actors;otherwise, it is optional. Similarly, theSOAPFault object must contain aDetail objectwith one or moreDetailEntry objects only when the contents of theSOAPBody object could not be processed successfully.

SeeSOAP Fault Example for an example that uses code like that shown in thissection.

PreviousContentsNext

Copyright © 2010, Oracle and/or its affiliates. All rights reserved.Legal Notices


[8]ページ先頭

©2009-2025 Movatter.jp