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:
- 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.
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>
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; }