Dec. 2, 2009, 2 a.m.
posted by maxidax
Working with SOAP FaultsAs you know from Chapter 4, faults are a special kind of SOAP message that contains error information. SOAP faults are always delivered from the receiver back to the sender. In SAAJ, SOAP fault messages are constructed in basically the same way as a plain SOAP message, except the SOAPBody object contains a SOAPFault instead of a SOAPBodyElement. SOAPFault is actually a subtype of SOAP BodyElement that specializes the behavior to support the structure of a SOAP Fault element. Several interfaces play a role in creating SOAP fault messages with SAAJ. Figure shows these interfaces in the context of all the other SAAJ types. Inheritance Diagram of SAAJ SOAP Fault Types (Fault types are in gray.)
13.4.1 The SOAPFault TypeEvery instance of the SOAPFault type is contained by a SOAPBody element. It describes an error generated by the receiver while processing a SOAP message. The SOAPFault interface (Listing 13-22) defines several methods for setting and getting the faultactor, faultcode, and faultstring (description) elements of the Fault element, as well as creating and accessing detail elements. Listing 13-22 The javax.xml.soap.SOAPFault Interface
package javax.xml.soap;
import java.util.Locale;
public interface SOAPFault extends SOAPBodyElement {
public Detail addDetail() throws SOAPException;
public Detail getDetail();
public String getFaultActor();
public String getFaultCode();
public Name getFaultCodeAsName();
public String getFaultString();
public Locale getFaultStringLocale();
public void setFaultActor(String faultActor) throws SOAPException;
public void setFaultCode(String faultCode) throws SOAPException;
public void setFaultCode(Name faultCode) throws SOAPException;
public void setFaultString(String faultString) throws SOAPException;
public void setFaultString(String faultString, Locale local)
throws SOAPException;
}
As an example, imagine that the ultimate receiver of the BookQuote SOAP message determines that the ISBN number declared in the Body of an incoming message is invalid. The receiver will generate a SOAP Fault message and deliver it to the sender immediately before it in the message path. The Fault message might look like the one in Listing 13-23. -23 A SOAP Fault Message
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>The ISBN contains an invalid character(s)</faultstring>
<faultactor>
http://www.Monson-Haefel.omc/BookQuote_WebService
</faultactor>
<detail>
<mh:InvalidIsbnFaultDetail
xmlns:mh="http://www.Monson-Haefel.com/jwsbook/BookQuote">
<offending-value>19318224-D</offending-value>
<conformance-rules>
The first nine characters must be digits. The last
character may be a digit or the letter 'X'. Case is not
important.
</conformance-rules>
</mh:InvalidIsbnFaultDetail>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
This fault message can be constructed fairly easily using SAAJ, as shown in Listing 13-24, SaajExample_7. -24 Building a Fault Message with SAAJ
package com.jwsbook.saaj;
import javax.xml.soap.*;
public class SaajExample_7 {
public static void main(String [] args) throws SOAPException {
// Create SOAPMessage
MessageFactory msgFactory = MessageFactory.newInstance();
SOAPMessage message = msgFactory.createMessage();
message.getSOAPHeader().detachNode();
// Create Fault message
SOAPBody body = message.getSOAPBody();
SOAPFault fault = body.addFault();
fault.setFaultCode("soap:Client");
fault.setFaultString("The ISBN contains an invalid character(s)");
fault.setFaultActor("http://www.Monson-Haefel.org/BookQuote_WebService");
Detail detail = fault.addDetail();
SOAPFactory soapFactory = SOAPFactory.newInstance();
Name errorName = soapFactory.createName(
"InvalidIsbnFaultDetail","mh",
"http://www.Monson-Haefel.com/jwsbook/BookQuote");
DetailEntry detailEntry = detail.addDetailEntry(errorName);
SOAPElement offendingValue =
detailEntry.addChildElement("offending-value");
offendingValue.addTextNode("19318224-D");
SOAPElement conformanceRules =
detailEntry.addChildElement("conformance-rules");
conformanceRules.addTextNode(
"The first nine characters must be digits. The last character "+
"may be a digit or the letter 'X'. Case is not important.");
SaajOutputter.writeToScreen(message);
}
}
Version 1.2 of SAAJ modified the SOAPFault interface and added a couple of methods that are QName-oriented. For example, when you call the setFault Code() method, you can pass it a Name parameter that represents a proper QName, instead of a String. The following snippet illustrates. SOAPFault fault = body.addFault(); SOAPFactory soapFactory = SOAPFactory.newInstance(); Name faultCode = soapFactory.createName("Client","soap", SOAPConstants.URI_NS_SOAP_ENVELOPE); fault.setFaultCode(faultCode); fault.setFaultString("The ISBN contains an invalid character(s)"); You can also access fault codes as either String values or Name objects. The getFaultCodeAsName() method returns the fault code as a SAAJ Name object, rather than a String value. This book tends to use the String methods because they are easier to read in example code, but use the Name object methods if you wish. To support international applications, the getFaultString() and set FaultString() methods are complemented by java.util.Locale style methods, namely getFaultStringLocale() and an overloading of setFaultString() that expects both a String and a Locale. These methods access or assign an xml:lang attribute to the faultstring value. If you do not use a Locale method, the default locale is used. A java.util.Locale represents a geographic, cultural, or political region (for example, the French-speaking area of Canada, or Simplified Chinese).
The simplest way to add a SOAPFault to a message is to use the overloaded addFault() methods, which allow you to initialize the fault code, fault string, and language (Locale) of the fault string when it's created. For example, the following snippet shows how to create a complete SOAPFault object in one operation.
SOAPFactory soapFactory = SOAPFactory.newInstance();
Name faultCode = soapFactory.createName("Client","soap",
SOAPConstants.URI_NS_SOAP_ENVELOPE);
SOAPFault fault = body.addFault(faultCode,
"The ISBN contains an invalid character(s)",
Locale.US);
If you're using the default Locale, you can just invoke the addFault(Name,String) overloading of the method instead of passing the default Locale object explicitly. 13.4.2 The Detail TypeA SOAPFault object contains an object of type Detail, which in turn contains one or more DetailEntry objects. As shown in Listing 13-25, the Detail type defines two methods: one for adding new DetailEntry objects and one for accessing existing ones. Listing 13-25 The javax.xml.soap.Detail Interface
package javax.xml.soap;
import java.util.Iterator;
public interface Detail extends SOAPFaultElement {
public DetailEntry addDetailEntry(Name name) throws SOAPException;
public Iterator getDetailEntries()
}
The Detail object was used in SaajExample_7, as shown in the following snippet from Listing 13-24. Detail detail = fault.addDetail(); Name errorName = envelope.createName("InvalidIsbnFaultDetail","mh", "http://www.Monson-Haefel.com/jwsbook/BookQuote"); DetailEntry detailEntry = detail.addDetailEntry(errorName); 13.4.3 The SOAPFaultElement TypeSOAPFaultElement is the supertype of SOAPDetail type (see Figure). It defines no methods or fields; it's an empty interface. It provides the same kind of typing benefit that SOAPBodyElement does: some assurance of backward-compatibility if the SOAP protocol changes, and some type safety. Its definition appears in Listing 13-26. Listing 13-26 The javax.xml.soap.SOAPFaultElement Interface
package javax.xml.soap;
public interface SOAPFaultElement extends SOAPElement {}
SOAPFaultElement is not usually used directly in your code, but it has utility because it extends SOAPElement, and thus inherits all the methods of that interface. 13.4.4 The DetailEntry TypeDetailEntry, defined in Listing 13-27, is another empty interface. It has no methods or fields, and is useful only for type safety (the Detail object may contain DetailEntry objects only). Its supertype, SOAPElement, defines all the methods you need to work with detail entries. It also offers some flexibility for the future, if new versions of SOAP add new restrictions on detail elements. Listing 13-27 The javax.xml.soap.DetailEntry Interface
package javax.xml.soap;
public interface DetailEntry extends SOAPElement {}
|
- Comment
