SCDJWS Study Guide: SAAJ


Printer-friendly version Printer-friendly version | Send this 
article to a friend Mail this to a friend


Previous Next vertical dots separating previous/next from contents/index/pdf Contents

Using SOAP Faults

In this section, you will see how to use the API for creating 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 that gives you status information, error information, or both. There can be only one SOAP Fault element in a message, and it must be an entry in the SOAP Body. Further, if there is a SOAP Fault element in the SOAP Body, there can be no other elements in the SOAP Body. This means that when you add a SOAP Fault element, you have effectively completed the construction of the SOAP Body. The SOAP 1.1 specification defines only one Body entry, which is the SOAP Fault element. Of course, the SOAP Body may contain other kinds of Body entries, but the SOAP Fault element is the only one that has been defined.

A SOAPFault object, the representation of a SOAP Fault element in the SAAJ API, is similar to an Exception object in that it conveys information about a problem. However, a SOAPFault object is quite different in that it is an element in a message's SOAPBody object rather than part of the try/catch mechanism used for Exception objects. Also, as part of the SOAPBody object, which provides a simple means for sending mandatory information intended for the ultimate recipient, a SOAPFault object only reports status or error information. It does not halt the execution of an application the way an Exception object can.

If you are a client using the SAAJ API and are sending point-to-point messages, the recipient of your message may add a SOAPFault object to the response to alert you to a problem. For example, if you sent an order with an incomplete address for where to send the order, the service receiving the order might put a SOAPFault object in the return message telling you that part of the address was missing.

Another example of who might send a SOAP fault is an intermediate recipient, or actor. As stated in the previous section, an actor that cannot process a header that has a mustUnderstand attribute with a value of true must return a SOAP fault to the sender.

A SOAPFault object contains the following elements:

·         A fault code -- always required

The fault code must be a fully qualified name, which means that it must contain a prefix followed by a local name. The SOAP 1.1 specification defines a set of fault code local name values in section 4.4.1, which a developer may extend to cover other problems. The default fault code local names defined in the specification relate to the SAAJ API as follows:

·         VersionMismatch -- the namespace for a SOAPEnvelope object was invalid

·         MustUnderstand -- an immediate child element of a SOAPHeader object had its mustUnderstand attribute set to true, and the processing party did not understand the element or did not obey it

·         Client -- the SOAPMessage object was not formed correctly or did not contain the information needed to succeed

·         Server -- the SOAPMessage object could not be processed because of a processing error, not because of a problem with the message itself

·         A fault string -- always required

A human-readable explanation of the fault

·         A fault actor -- required if the SOAPHeader object contains one or more actor 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, see the section The Actor Attribute.

·         A Detail object -- required if the fault is an error related to the SOAPBody object

If, for example, the fault code is Client, indicating that the message could not be processed because of a problem in the SOAPBody object, the SOAPFault object must contain a Detail object that gives details about the problem. If a SOAPFault object does not contain a Detail object, it can be assumed that the SOAPBody object was processed successfully.

Creating and Populating a SOAPFault Object

You have already seen how to add content to a SOAPBody object; this section will walk you through adding a SOAPFault object to a SOAPBody object and then adding its constituent parts.

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

SOAPBody body = message.getSOAPBody();

With the SOAPBody object body in hand, you can use it to create a SOAPFault object. The following line of code both creates a SOAPFault object and adds it to body.

SOAPFault fault = body.addFault();

The SOAPFault interface provides convenience methods that create an element, add the new element to the SOAPFault object, and add a text node all in one operation. For example, in the following lines of code, the method setFaultCode creates a faultcode element, adds it to fault, and adds a Text node with the value "SOAP-ENV:Server" by specifying a default prefix and the namespace URI for a SOAP envelope.

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

The SOAPFault object fault, created in the previous lines of code, indicates that the cause of the problem is an unavailable server and that the actor at http://gizmos.com/orders is having the problem. If the message were being routed only to its ultimate destination, there would have been no need for setting a fault actor. Also note that fault does not have a Detail object because it does not relate to the SOAPBody object.

The following code fragment creates a SOAPFault object that includes a Detail object. Note that a SOAPFault object may have only one Detail object, which is simply a container for DetailEntry objects, but the Detail object may have multiple DetailEntry objects. The Detail object in the following lines of code has two DetailEntry objects added to it.

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

 

Retrieving Fault Information

Just as the SOAPFault interface provides convenience methods for adding information, it also provides convenience methods for retrieving that information. The following code fragment shows what you might write to retrieve fault information from a message you received. In the code fragment, newMessage is the SOAPMessage object that has been sent to you. Because a SOAPFault object must be part of the SOAPBody object, the first step is to access the SOAPBody object. Then the code tests to see if the SOAPBody object contains a SOAPFault object. If so, the code retrieves the SOAPFault object and uses it to retrieve its contents. The convenience methods getFaultCode, getFaultString, and getFaultActor make retrieving the values very easy.

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

Next the code prints out the values it just retrieved. Not all messages are required to have a fault actor, so the code tests to see if there is one. Testing whether the variable actor is null works because the method getFaultActor returns null if a fault actor has not been set.

System.out.println("SOAP fault contains: ");
System.out.println("  Fault code = " +  code.getQualifiedName());
System.out.println("  Fault string = " + string);
if ( actor != null ) {
   System.out.println("  Fault actor = " + actor);
}

The final task is to retrieve the Detail object and get its DetailEntry objects. The code uses the SOAPFault object newFault to retrieve the Detail object newDetail, and then it uses newDetail to call the method getDetailEntries. This method returns the java.util.Iterator object entries, which contains all of the DetailEntry objects in newDetail. Not all SOAPFault objects are required to have a Detail object, so the code tests to see whether newDetail is null. If it is not, the code prints out the values of the DetailEntry objects as long as 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 a SOAPFault object and its contents to a message as well as how to retrieve the contents. A SOAPFault object, which is optional, is added to the SOAPBody object to convey status or error information. It must always have a fault code and a String explanation of the fault. A SOAPFault object must indicate the actor that is the source of the fault only when there are multiple actors; otherwise, it is optional. Similarly, the SOAPFault object must contain a Detail object with one or more DetailEntry objects only when the contents of the SOAPBody object could not be processed successfully.

 


Previous Next vertical dots separating previous/next from contents/index/pdf Contents

  |   |