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
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.
Setting Fault Message Subelements
To customize the values of the faultstring and detail subelements:
- Create a string object and set to an informative message. The message is mapped to the SOAP message's faultstring element.
- 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.
- Create a fault message exception that contains the message and fault document.
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>
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
<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>
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;
}