19 Handling Exceptions Using SOAP Faults

This chapter describes how to handle exceptions that occur when a message is being processed using Simple Object Access Protocol (SOAP) faults for WebLogic web services using Java API for XML Web Services (JAX-WS).

This chapter includes the following sections:

Overview of Exception Handling Using SOAP Faults

When a web service request is being processed, if an error is encountered, the nature of the error needs to be communicated to the client, or sender of the request. Because clients can be written on a variety of platforms using different languages, there must exist a standard, platform-independent mechanism for communicating the error.

The SOAP specification (available at http://www.w3.org/TR/soap/) defines a standard, platform-independent way of describing the error within the SOAP message using a SOAP fault. In general, a SOAP fault is analogous to an application exception. SOAP faults are generated by receivers to report business logic errors or unexpected conditions.

In JAX-WS, Java exceptions (java.lang.Exception) that are thrown by your Java web service are mapped to a SOAP fault and returned to the client to communicate the reason for failure. SOAP faults can be one of the following types:

  • Modeled—Maps to an exception that is thrown explicitly from the business logic of the Java code and mapped to wsdl:fault definitions in the WSDL file, when the web service is deployed. In this case, the SOAP faults are predefined.

  • Unmodeled—Maps to an exception (for example, java.lang.RuntimeException) that is generated at run-time when no business logic fault is defined in the WSDL. In this case, Java exceptions are represented as generic SOAP fault exceptions, javax.xml.ws.soap.SOAPFaultException.

The faults are returned to the sender only if request/response messaging is in use. If a web service operation is configured as one-way, the SOAP fault is not returned to the sender, but stored for further processing.

As illustrated in Figure 19-1, JAX-WS handles SOAP fault processing during SOAP protocol binding. The SOAP binding maps exceptions to SOAP fault messages.

Figure 19-1 How SOAP Faults Are Processed

Description of Figure 19-1 follows
Description of "Figure 19-1 How SOAP Faults Are Processed"

Contents of the SOAP Fault Element

The SOAP <Fault> element is used to transmit error and status information within a SOAP message. The <Fault> element is a child of the body element. There can be only one <Fault> element in the body of a SOAP message.

The SOAP <Fault> element contents for SOAP 1.2 and 1.1 are defined in the following sections:

SOAP 1.2 <Fault> Element Contents

The <Fault> element for SOAP 1.2 contains the subelements defined in Table 19-1.

Table 19-1 Subelements of the SOAP 1.2 <Fault> Element

Subelement Description Required?

env:Code

Information pertaining to the fault error code. The env:Code element consists of the following two subelements:

  • env:Value

  • env: Subcode

The subelements are defined below.

Required

env:Value

Code value that provides more information about the fault. A set of code values is predefined by the SOAP specification, including:

  • VersionMismatch—Invalid namespace defined in SOAP envelope element. The SOAP envelope must conform to the http://schemas.xmlsoap.org/soap/envelope namespace.

  • MustUnderstand—SOAP header entry not understood by processing party.

  • Sender—Message was incorrectly formatted or is missing information.

  • Receiver—Problem with the server that prevented the message from being processed.

  • DataEncodingUnknown—Received message has an unrecognized encoding style value. You can define encoding styles for SOAP headerblocks and child elements of the SOAP body, and this encoding style must be recognized by the web services server.

Required

env:Subcode

Subcode value that provides more information about the fault. This subelement can have a recursive structure.

Optional

env:Reason

Human-readable description of fault.

The <env:Reason> element contains one or more <Text> elements, each of which contains information about the fault in a different language.

Required

env:Node

Information regarding the actor (SOAP node) that caused the fault.

Optional

env:Role

Role being performed by actor at the time of the fault.

Optional

env:Detail

Application-specific information, such as the exception that was thrown.

Optional

The following provides an example of a SOAP 1.2 fault message.

Example 19-1 Example of SOAP 1.2 Fault Message

<?xml version="1.0"?>
<env:Envelope xmlns:env=http://www.w3.org/2003/05/soap-envelope>
   <env:Body>
      <env:Fault>
         <env:Code>
            <env:Value>env:Sender</env:Value>
            <env:Subcode>
               <env:Value>rpc:BadArguments</env:Value>
            </env:Subcode>
         </env:Code>
         <env:Reason>
            <env:Text xml:lang=en-US>Processing error<env:Text>
         </env:Reason>
         <env:Detail>
            <e:myFaultDetails 
               xmlns:e=http://travelcompany.example.org/faults>
               <e:message>Name does not match card number</e:message>
               <e:errorcode>999</e:errorcode>
            </e:myFaultDetails>
         </env:Detail>
      </env:Fault>
   </env:Body>
</env:Envelope>

SOAP 1.1 <Fault> Element Contents

The <Fault> element for SOAP 1.1 contains the subelements defined in Table 19-2.

Table 19-2 Subelements of the SOAP 1.1 <Fault> Element

Subelement Description

faultcode

Standard code that provides more information about the fault. A set of code values is predefined by the SOAP specification, as defined below. This set of fault code values can be extended by the application.

Predefined fault code values include:

  • VersionMismatch—Invalid namespace defined in SOAP envelope element. The SOAP envelope must conform to the http://schemas.xmlsoap.org/soap/envelope namespace.

  • MustUnderstand—SOAP header entry not understood by processing party.

  • Client—Message was incorrectly formatted or is missing information.

  • Server—Problem with the server that prevented message from being processed.

faultstring

Human-readable description of fault.

faultactor

URI associated with the actor (SOAP node) that caused the fault. In RPC-style messaging, the actor is the URI of the web service.

detail

Application-specific information, such as the exception that was thrown. This element can be an XML structure or plain text.

The following provides an example of a SOAP 1.1 fault message.

Example 19-2 Example of SOAP 1.1 Fault Message

<?xml version="1.0"?>
<soap:Envelope 
    xmlns:soap='http://schemas.xmlsoap.org/soap/envelope'>
   <soap:Body>
      <soap:Fault>
         <faultcode>soap:VersionMismatch</faultcode>
         <faultstring, xml:lang='en">
            Message was not SOAP 1.1 compliant
         </faultstring>
         <faultactor>
            http://sample.org.ocm/jws/authnticator
         </faultactor>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

Using Modeled Faults

As described previously, a modeled fault is mapped to an exception that is thrown explicitly from the business logic of the Java code. In this case, the exception is mapped to a wsdl:fault definitions in the WSDL file, when the web service is deployed.

The following sections provide more information about using modeled faults:

Creating and Using a Custom Exception

To use modeled faults, you need to create a custom Java exception and throw it from within your web service.

Example 19-3 provides a simple example of a custom exception being thrown by a web service. The exception is called MissingName and is thrown when the input argument is empty.

Example 19-3 Web Service With Custom Exception

package examples;
import javax.jws.WebService;

@WebService(name="HelloWorld", serviceName="HelloWorldService")
public class HelloWorld {
   public String sayHelloWorld(String message) throws MissingName {
        System.out.println("Say Hello World: " + message);
        if (message == null || message.isEmpty()) {
           throw new MissingName();
        }
      return "Here is the message: '" + message + "'";
      }
}

Example 19-4 shows the he class for the exception, MissingName.java.

Example 19-4 Custom Exception Class (MissingName)

package examples;
import java.lang.Exception;

public class MissingName extends Exception {
    public MissingName() {
        super("Your name is required.");
    }
}

How Modeled Faults are Mapped in the WSDL File

The JAX-WS Java-to-WSDL mapping binds subclasses of java.lang.Exception to wsdl:fault messages. Example 19-4 shows the WSDL that is generated from the annotated web service in Example 19-3.

In this example:

  • The <message name="MissingName"> element defines the parts of the MissingName message, namely fault, and its associated data type, tns:MissingName.

      <message name="MissingName">
        <part name="fault" element="tns:MissingName" /> 
      </message>
    
  • The MissingName SOAP fault is mapped to the sayHelloWorld operation.

        <operation name="sayHelloWorld">
          <input message="tns:sayHelloWorld" /> 
          <output message="tns:sayHelloWorldResponse" /> 
          <fault message="tns:MissingName" name="MissingName" /> 
        </operation>
    

    This <fault> subelement in this example is derived from the throws MissingName clause of the sayHelloWorld() method declaration (see Example 19-3).

    public String sayHelloWorld(String message) throws MissingName {
    ...
    }
  • The fault message is mapped to the sayHelloWorld operation in the <binding> element, as well.

    <fault name="MissingName">
      <soap:fault name="MissingName" use="literal" /> 
    </fault>
    

Example 19-5 Example of WSDL with Modeled Exceptions

<?xml version="1.0" encoding="UTF-8" ?> 
<definitions 
   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:tns="http://examples/" 
   xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
   xmlns="http://schemas.xmlsoap.org/wsdl/" 
   targetNamespace="http://examples/" 
   name="HelloWorldService">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://examples/" 
     schemaLocation="http://localhost:7001/HelloWorld/HelloWorldService?xsd=1"/>
    </xsd:schema>
  </types>
  <message name="sayHelloWorld">
    <part name="parameters" element="tns:sayHelloWorld" /> 
  </message>
  <message name="sayHelloWorldResponse">
    <part name="parameters" element="tns:sayHelloWorldResponse" /> 
  </message>
  <message name="MissingName">
    <part name="fault" element="tns:MissingName" /> 
  </message>
  <portType name="HelloWorld">
    <operation name="sayHelloWorld">
      <input message="tns:sayHelloWorld" /> 
      <output message="tns:sayHelloWorldResponse" /> 
      <fault message="tns:MissingName" name="MissingName" /> 
    </operation>
  </portType>
  <binding name="HelloWorldPortBinding" type="tns:HelloWorld">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http"
      style="document" /> 
    <operation name="sayHelloWorld">
      <soap:operation soapAction="" /> 
      <input>
        <soap:body use="literal" /> 
      </input>
      <output>
        <soap:body use="literal" /> 
       </output>
      <fault name="MissingName">
        <soap:fault name="MissingName" use="literal" /> 
      </fault>
    </operation>
  </binding>
  <service name="HelloWorldService">
    <port name="HelloWorldPort" binding="tns:HelloWorldPortBinding">
      <soap:address 
        location="http://localhost:7001/HelloWorld/HelloWorldService" /> 
    </port>
  </service>

How the Fault is Communicated in the SOAP Message

Example 19-6 shows how the SOAP fault is communicated in the resulting SOAP message when the MissingName Java exception is thrown.

Example 19-6 Example SOAP Fault Message for MissingName Exception

<?xml version = '1.0' encoding = 'UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
         <faultcode>S:Server</faultcode>
         <faultstring>Your name is required.</faultstring>
         <detail>
            <ns2:MissingName xmlns:ns2="http://examples/">
               <message>Your name is required.</message>
            </ns2:MissingName>
            <ns2:exception xmlns:ns2="http://jax-ws.java.net/"
 class="examples.MissingName" note="To disable this feature, set
 com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace system 
 property to false">
               <message>Your name is required.</message>
               <ns2:stackTrace>
                  <ns2:frame class="examples.HelloWorld" file="HelloWorld.java" 
  line="14" method="sayHelloWorld"/>
  ...
               </ns2:stackTrace>
            </ns2:exception>
         </detail>
      </S:Fault>
   </S:Body>
</S:Envelope>

Creating the Web Service Client

When you generate a web service client from a WSDL file that contains mapped faults using clientgen, the required exception classes are generated automatically, including the mapped exception, fault bean, service implementation classes client implementation class, which you must modify, as described in the following sections.

For more information about clientgen, see clientgen in WebLogic Web Services Reference for Oracle WebLogic Server.

Reviewing the Generated Java Exception Class

An example of the generated Java exception class is shown in Example 19-7. The @WebFault annotation identifies the class as a mapped exception.

Example 19-7 Example of Generated Java Exception Class

package examples.client;
 
import javax.xml.ws.WebFault;
 
@WebFault(name = "MissingName", targetNamespace = "http://examples/")
public class MissingName_Exception extends Exception {
  private MissingName faultInfo;
  public MissingName_Exception(String message, MissingName faultInfo) { ... }
  public MissingName_Exception(String message, MissingName faultInfo, 
     Throwable cause) { ... }
  public MissingName getFaultInfo() { ... }
}
Reviewing the Generated Java Fault Bean Class

An example of the generated Java fault bean class is shown in Example 19-8, defining the getters and setters for the fault message.

Example 19-8 Example of Generated Java Fault Bean Class

package examples.client;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
 
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "MissingName", propOrder = {
    "message"
})
public class MissingName {
 
    protected String message;
 
    public String getMessage() {
        return message;
    }

    public void setMessage(String value) {
        this.message = value;
    }
}
Reviewing the Client-side Service Implementation

An example of the generated client-side service implementation class is shown in Example 19-9.

Example 19-9 Client-side Service Implementation

package examples.client;
...
@WebService(name = "HelloWorld", targetNamespace = "http://examples/")
@XmlSeeAlso({
    ObjectFactory.class
})
public interface HelloWorld {
 
    @WebMethod
    @WebResult(targetNamespace = "")
    @RequestWrapper(localName = "sayHelloWorld", 
       targetNamespace = "http://examples/", 
       className = "examples.client.SayHelloWorld")
    @ResponseWrapper(localName = "sayHelloWorldResponse", 
       targetNamespace = "http://examples/", 
       className = "examples.client.SayHelloWorldResponse")
    public String sayHelloWorld(
        @WebParam(name = "arg0", targetNamespace = "")
        String arg0)
        throws MissingName_Exception;
}
Creating the Client Implementation Class

Create the client implementation class to call the web service method and throw the custom exception. Then, compile and run the client. For more information about creating web service clients, see Invoking Web Services in Developing JAX-WS Web Services for Oracle WebLogic Server.

Example 19-10 shows an example client implementation class.

Example 19-10 Client Implementation Class

package examples.client;
 
import javax.xml.namespace.QName;
import java.net.MalformedURLException;
import java.net.URL;
import examples.client.MissingName_Exception;
 
public class Main {
 
  public static void main(String[] args) throws MissingName_Exception {
    HelloWorldService service;
 
    try {
      service = new HelloWorldService(new URL(args[0] + "?WSDL"), 
                    new QName("http://examples/", "HelloWorldService") );
    } catch (MalformedURLException murl) { throw new RuntimeException(murl); }
      HelloWorld port = service.getHelloWorldPort();
 
      String result = null;
    try {
      result = port.sayHelloWorld("");
    } catch (MissingName_Exception e) {
      System.err.println("Error: " + e);
    }
      System.out.println( "Got result: " + result );
  }
}

Using Unmodeled Faults

As noted previously, an unmodeled fault maps to an exception (for example, java.lang.RuntimeException) that is generated at run-time when no business logic fault is defined in the WSDL. In this case, Java exceptions are represented as generic SOAP fault exceptions, javax.xml.ws.soap.SOAPFaultException.

The following shows an example of an exception that maps to an unmodeled fault.

Example 19-11 Example of Web Service Using Unmodeled Fault

package examples;
 
import javax.jws.WebService;
@WebService(name="HelloWorld", serviceName="HelloWorldService")
public class HelloWorld {
   public String sayHelloWorld(String message) throws MissingName {
        System.out.println("Say Hello World: " + message);
        if (message == null || message.isEmpty()) {
           throw new MissingName(); // Modeled fault
        } else if (message.equalsIgnoreCase("abc")) {
         throw new RuntimeException("Please enter a name."); //Unmodeled fault
        } 
 
      return "Here is the message: '" + message + "'";
   }
}

In this example, if the string "abc" is passed to the method, the following SOAPFaultException and RuntimeException messages are returned in the log file:

Example 19-12 Example of Log File Message for Unmodeled Fault

...
run:
  [java] Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: Please
enter a name.
...
Caused by: java.lang.RuntimeException: Please enter a name.\
...

Customizing the Exception Handling Process

You can customize the SOAP fault handling process using SOAP message handlers. A SOAP message handler provides a mechanism for intercepting the SOAP message in both the request and response of the web service. You can create SOAP message handlers to enable web services and clients to perform additional processing on the SOAP message. For more information, see Creating and Using SOAP Message Handlers.

Disabling the Stack Trace from the SOAP Fault

Note:

The com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace property is supported as an extension to the JDK 6.0. Because this API is not provided as part of the JDK 6.0 kit, it is subject to change.

By default, the entire stack trace, including nested exceptions, is included in the details of the SOAP fault message. For example, the following shows an example of a SOAP fault message that includes the stack trace:

You can disable the inclusion of the stack trace in the SOAP fault message by setting the com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace Java startup property to false.

To disable the stack trace:

  1. Locate the following entry in the ORACLE_HOME/user_projects/domains/domainName/startWebLogic.cmd file, where ORACLE_HOME is the directory you specified as the Oracle Home when you installed Oracle WebLogic Server:
    set JAVA_OPTIONS=%SAVE_JAVA_OPTIONS%
    
  2. Edit the entry as follows:
    set JAVA_OPTIONS=-Dcom.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace=false %SAVE_JAVA_OPTIONS%
    
  3. Save the startWebLogic.cmd file.

Example 19-13 Example of Stack Trace in SOAP Fault Message

<?xml version = '1.0' encoding = 'UTF-8'?>
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope">
   <S:Body>
      <S:Fault xmlns:ns4="http://schemas.xmlsoap.org/soap/envelope/">
         <S:Code>
            <S:Value>S:Receiver</S:Value>
         </S:Code>
         <S:Reason>
            <S:Text xml:lang="en">String index out of range: 3</S:Text>
         </S:Reason>
         <S:Detail>
            <ns2:exception xmlns:ns2="http://jax-ws.java.net/" 
             class="java.lang.StringIndexOutOfBoundsException" note="To disable this feature, set
             com.sun.xml.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace system property 
             to false">
               <message>String index out of range: 3</message>
               <ns2:stackTrace>
                  <ns2:frame class="java.lang.String" file="String.java" line="1934"
                    method="substring"/>
                  <ns2:frame class="ratingservice.CreditRating" file="CreditRating.java"
                    line="21" method="processRating"/>
                  <ns2:frame class="sun.reflect.NativeMethodAccessorImpl"
                    file="NativeMethodAccessorImpl.java" line="native" method="invoke0"/>
                  <ns2:frame class="sun.reflect.NativeMethodAccessorImpl"
                    file="NativeMethodAccessorImpl.java" line="39" method="invoke"/>
                  <ns2:frame class="sun.reflect.DelegatingMethodAccessorImpl"
                    file="DelegatingMethodAccessorImpl.java" line="25" method="invoke"/>
                  <ns2:frame class="java.lang.reflect.Method" file="Method.java" line="597"
                    method="invoke"/>
                  ...
               </ns2:stackTrace>
            </ns2:exception>
         </S:Detail>
      </S:Fault>
   </S:Body>
</S:Envelope>

Other Exceptions

Note that in addition to the custom exceptions that are thrown explicitly in your web service and the SOAPFaultExceptions that are used to map exceptions that are not caught by your business logic, there are two other exceptions that might be communicated to the web service client, and that you should be aware of.

Table 19-3 Other Exceptions

Exception Description

javax.xml.ws.WebServiceException

Base exception for all JAX-WS API runtime exceptions, used when calls to JAX-WS Java classes fail, such as Service.BindingProvider and Dispatch.

java.util.concurrent.ExecutionException

Used by JAX-WS asynchronous calls, when a client tries to get the response from an asynchronous call.