Error Handling

In service-oriented applications, SOAP clients expect a fault message to be returned when an error occurs during processing. A fault message is a SOAP message

A fault message has the following subelements:

Subelement Description
faultcode A code that identifies the fault.
faultstring An explanation of the fault.
faultactor Information about what caused the fault to occur.
detail Application-specific information about the fault.

Fault messages defined in the WSDL file are called declared faults. Fault messages that are not defined in the WSDL file are called undeclared faults. The process for generating a fault message is implementation dependent and typically depends on whether the fault is declared or not.

Declared Faults

When you add a service to a Spring component TIBCO Business Studio generates a fault exception class for each fault declared in the WSDL file that defines the service's port type.

Example WSDL File

The following WSDL fragment shows the getWeather operation with two declared faults: orderFault and orderFault2. The detail element for the orderFault message contains a ZipCodeFault element. The detail element for the orderFault2 message contains a CityFault element.

<wsdl:types>
  <schema xmlns="http://www.w3.org/2001/XMLSchema" 
  xmlns:tns="http://www.example.org/weatherschema" 
  targetNamespace="http://www.example.org/weatherschema" elementFormDefault="unqualified" 
  attributeFormDefault="unqualified">
    <complexType name="WeatherRequestType">
       <sequence>
         <element name="city" type="string"/>
         <element name="state" type="string"/>
         <element name="zip" type="string"/>
       </sequence>
    </complexType>
    <complexType name="WeatherResponseType">
       <sequence>
         <element name="high" type="float"/>
         <element name="low" type="float"/>
         <element name="forecast" type="string"/>
       </sequence>
    </complexType>

    <element name="WeatherRequest" type="tns:WeatherRequestType"/>
    <element name="WeatherResponse" type="tns:WeatherResponseType"/>
    <element name="ZipCodeFault" type="string"/>
    <element name="CityFault" type="string" /> 
  </schema>
</wsdl:types>
<wsdl:message name="invalidZipCodeFault">
  <wsdl:part name="error" element="ns0:ZipCodeFault"/>
</wsdl:message>
<wsdl:message name="invalidCityFault">
  <wsdl:part name="error" element="ns0:CityFault" /> 
</wsdl:message>
<wsdl:portType name="WeatherReportPT">
 <wsdl:operation name="GetWeather">
  <wsdl:input message="tns:GetWeatherRequest"/>
  <wsdl:output message="tns:GetWeatherResponse"/>
  <wsdl:fault name="orderFault" message="tns:invalidZipCodeFault"/>
  <wsdl:fault name="orderFault2" message="tns:invalidCityFault" /> 
 </wsdl:operation>
</wsdl:portType>

Code Generation

When TIBCO Business Studio generates the Spring component implementation invalidCityFault and invalidZipCodeFault are mapped to the exceptions:
public class InvalidCityFaultException extends java.lang.Exception
public class InvalidZipCodeFaultException extends java.lang.Exception

and a throws clause containing the generated exceptions is added to the getWeather method.

To generate the invalidCityFault fault message while processing the getWeather method, throw InvalidCityFaultException. The faultcode and faultactor subelements of the SOAP fault element are predefined as:
Subelement Content
faultcode SOAP-ENV:Server
faultactor DefaultRole

Setting Fault Message Subelements

To customize the values of the faultstring and detail subelements:

  1. Create a string object and set to an informative message. The message is mapped to the SOAP message's faultstring element.
  2. Create a fault document and set the appropriate fault property of the document to the reason for the error. The reason is mapped to the SOAP message detail element.
  3. Create a fault message exception that contains the message and fault document.
For example, if the city element of the request is not set correctly, configure and throw the fault message exception as follows:
public WeatherResponseDocument getWeather(WeatherRequestDocument getWeatherRequest)
  throws org.example.www.WeatherService.InvalidCityFaultException, 
  org.example.www.WeatherService.InvalidCityFaultException {
		WeatherRequestType weatherRequest = getWeatherRequest.getWeather();
		if (weatherRequest.getCity()==null||weatherRequest.getCity().equals("")) {
		 CityFaultDocument cityFaultDocument = CityFaultDocument.Factory.newInstance();

			XmlString msg = XmlString.Factory.newInstance();
			msg.setStringValue("Error processing getWeather.");
		 //  set detail
		 cityFaultDocument.setCityFault("Invalid city for zipcode " + weatherRequest.getZip());
		 // set faultstring
		 InvalidCityFaultException invalidCityFaultException = 
           new InvalidCityFaultException(msg.getStringValue(), cityFaultDocument);
		 throw invalidCityFaultException;
		}
   ...
}

which would generate the following SOAP fault message if getCity does not return a valid value:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring>Error processing getWeather.</faultstring>
<faultactor>DefaultRole</faultactor>
<detail>
<CityFault xmlns="http://www.example.org/weatherschema">
  Invalid city for zipcode 95070.</CityFault>
</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
A consumer invoking getWeather should handle the exception as follows:
public WeatherResponseDocument getWeather(WeatherRequestDocument getWeatherRequest) { 
  try {
    return getWeatherReportPT().getWeather(getWeatherRequest); 
  }
  catch(Exception e) {
    if (e instanceof InvalidCityFaultException)
      throw (InvalidCityFaultException)e;
    else{
      System.out.println("Error occured.");
      throw new RuntimeException(e.getMessage(),e);
    }
  }
 ...
}

Undeclared Faults

When an undeclared fault occurs, the TIBCO ActiveMatrix runtime returns a SOAP fault with the following subelements:
Subelement Content
faultcode SOAP-ENV:Server
faultstring java.lang.RuntimeException
faultactor DefaultRole
detail A stack trace indicating where the exception occurred.
If a runtime exception occurs while processing getWeather, the following SOAP fault would be generated:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
 <SOAP-ENV:Fault>
  <faultcode>SOAP-ENV:Server</faultcode>
  <faultstring>java.lang.RuntimeException: Undeclared fault....</faultstring>
  <faultactor>DefaultRole</faultactor>
   <detail>
     <tibco:myFaultDetail xmlns:tibco="http://tibcouri/">
     org.osoa.sca.ServiceRuntimeException: java.lang.RuntimeException: Undeclared fault....
     at com.tibco.amf.platform.runtime.componentframework.internal.proxies.
      ProxyInvocationHandler.invoke(ProxyInvocationHandler.java:473)
     at $Proxy21.invoke(Unknown Source)
     at com.tibco.amf.binding.soap.runtime.transport.http.SoapHttpInboundEndpoint.
       processHttpPost(SoapHttpInboundEndpoint.java:250)
     at com.tibco.amf.binding.soap.runtime.transport.http.SoapHttpServer.doPost(
       SoapHttpServer.java:103)  
     ...
    Caused by: java.lang.RuntimeException: Undeclared fault....
     at com.sample.faultservice.Component1.getWeather(Component1.java:50)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
     at java.lang.reflect.Method.invoke(Method.java:585)
     at com.tibco.amf.platform.runtime.componentframework.internal.proxies.
       ProxyInvocationHandler.invoke(ProxyInvocationHandler.java:426)
     ... 20 more
     </tibco:myFaultDetail>
   </detail>
  </SOAP-ENV:Fault>
 </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
To specify SOAP fault subelements for undeclared faults, convert the runtime exception into a com.tibco.amf.platform.runtime.extension.SOAPException class. The following code fragment illustrates how to modify the subelements of the SOAP fault:
import com.tibco.amf.platform.runtime.extension.exception.SOAPException;
import com.tibco.amf.platform.runtime.extension.exception.SOAPDetail;
import com.tibco.amf.platform.runtime.extension.exception.SOAPCode;
import java.net.URI;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
...
    URI role = null;
    try {
      role = new URI("http://soapexception.role");
    } catch (URISyntaxException e) {
      e.printStackTrace();
    }
    WeatherRequestType weatherRequest = getWeatherRequest.getWeatherRequest();
    Node domNode = weatherRequest.getDomNode();
    //Set the original request as the fault detail
    SOAPDetail<Element> soapDetail = new SOAPDetail<Element>(Element.class, (Element)domNode);
    SOAPCode soapCode = new SOAPCode(new QName("fault code"));

    SOAPException soapException = new SOAPException(soapCode, "reason", role, soapDetail);
    throw soapException;
...
The following example illustrates how to catch the SOAPException exception returned by an invocation of a referenced service:
public WeatherResponseDocument getWeather(WeatherRequestDocument getWeatherRequest)
  throws org.example.www.WeatherService.InvalidZipCodeFaultException {
  try {
    return getWeatherReportPT().getWeather(getWeatherRequest);
  } catch (InvalidZipCodeFaultException e) {
    System.out.println("=========InvalidZipcodeFaultException========");
    throw e;
  } catch(Exception e) {
    System.out.println("===========Runtime Exception===========");
    if(e instanceof ServiceRuntimeException) {
      ServiceRuntimeException sre = (ServiceRuntimeException) e;
      Throwable cause = sre.getCause();
      if(cause instanceof SOAPException) {
         SOAPException soapex = (SOAPException) cause;
         if (soapex.getCode()!=null) {
           System.out("Fault code: " + soapex.getCode().toString());
         if (soapex.getRole()!=null) {
           System.out("Fault role: " + soapex.getRole().toString());
         throw soapex;
      }
    }
    throw new RuntimeException(e);
  ...
  return null;
}