The Web Services Resource Framework (WSRF) provides a recommended basic fault message element type from which you can derive all service-specific faults. The advantage of a common basic type is that all faults can, by default, contain common information. This behavior is useful in complex systems where faults might be systematically logged, or forwarded through several layers of software before being analyzed.
<wsrf-bf:BaseFault> <wsrf-bf:Timestamp>2005-05-31T12:00:00.000Z</wsrf-bf:Timestamp> <wsrf-bf:Originator> <wsa:Address> http://www.example.org/Printer </wsa:Address> <wsa:ReferenceParameters> <pr:pr-id>P1</pr:pr-id> </wsa:ReferenceParameters> </wsrf-bf:Originator> <wsrf-bf:Description>Offline for service maintenance</wsrf-bf:Description> <wsrf-bf:FaultCause>OFFLINE</wsrf-bf:FaultCause> </wsrf-bf:BaseFault>
WebSphere Application Server provides Java code mappings for all the base fault element types that are defined by the WSRF specifications, forming an exception hierarchy where each Java exception extends the com.ibm.websphere.wsrf.BaseFault class. Each fault class follows a similar pattern.
package com.ibm.websphere.wsrf; public class BaseFault extends Exception { public BaseFault() { ... } public BaseFault(EndpointReference originator, ErrorCode errorCode, FaultDescription[] descriptions, IOSerializableSOAPElement faultCause, IOSerializableSOAPElement[] extensibilityElements, Attribute[] attributes) { ... } ... }
Because the BaseFault class extends the java.lang.Exception class, the BaseFault class must implement the java.io.Serializable interface. To meet this requirement, all properties of a BaseFault instance must be serializable. Because the javax.xml.soap.SOAPElement class is not serializable, WebSphere Application Server provides an IOSerializableSOAPElement class, which you can use to wrap a javax.xml.soap.SOAPElement instance to provide a serializable form of that instance.
// Get an instance of the IOSerializableSOAPElementFactory class IOSerializableSOAPElementFactory factory = IOSerializableSOAPElementFactory.newInstance(); // Create an IOSerializableSOAPElement from a javax.xml.soap.SOAPElement IOSerializableSOAPElement serializableSOAPElement = factory.createElement(soapElement); // You can retrieve the wrapped SOAPElement from the IOSerializableSOAPElement SOAPElement soapElement = serializableSOAPElement.getSOAPElement();
Any application-specific BaseFault instances must also adhere to this serializable requirement.
<xsd:complexType name="PrinterFaultType"> <xsd:complexContent> <xsd:extension base="wsrf-bf:BaseFaultType"/> </xsd:complexContent> </xsd:complexType>
import com.ibm.websphere.wsrf.BaseFault; import com.ibm.websphere.wsrf.*; import javax.xml.soap.SOAPFactory; ... public void print(PrintRequest req) throws PrinterFault, ResourceUnknownFault { // Determine the identity of the target printer instance. PrinterState state = PrinterState.getState (); if (state.OFFLINE) { try { // Get an instance of the SOAPFactory SOAPFactory soapFactory = SOAPFactory.newInstance(); // Create the fault cause SOAPElement SOAPElement faultCause = soapFactory.createElement("FaultCause"); faultCase.addTextNode("OFFLINE"); // Get an instance of the IOSerializableSOAPElementFactory IOSerializableSOAPElementFactory factory = IOSerializableSOAPElementFactory.newInstance(); // Create an IOSerializableSOAPElement from the faultCause SOAPElement IOSerializableSOAPElement serializableFaultCause = factory.createElement(faultCause); FaultDescription[] faultDescription = new FaultDescription[1]; faultDescription[0] = new FaultDescription("Offline for service maintenance"); throw new PrinterFault( state.getPrinterEndpointReference(), null, faultDescription, serializableFaultCause, null, null); } catch (SOAPException e) { ... } } ...
import com.ibm.websphere.wsrf.BaseFault; import com.ibm.websphere.wsrf.*; ... try { printer1.print(job1); } catch (ResourceUnknownFault exc) { System.out.println("Operation threw the ResourceUnknownFault”); } catch (PrinterFault exc) { System.out.println("Operation threw PrinterFault”); } catch (BaseFault exc) { System.out.println("Exception is another BaseFault”); } catch (Exception exc) { System.out.println("Exception is not a BaseFault”); }
When you define a new application-level base fault, for example the PrinterFault fault with the PrinterFaultType type shown previously, you must provide a custom binder to define how the Web services run time serializes the Java class into an appropriate XML message, and conversely how to deserialize an XML message into an instance of the Java class.
<customdatabinding:provider xmlns:customdatabinding="http://www.ibm.com/webservices/customdatabinding/2004/06" xmlns:pr="http://example.org/printer.xsd" xmlns="http://www.ibm.com/webservices/customdatabinding/2004/06"> <mapping> <xmlQName>pr:PrinterFaultType</xmlQName> <javaName>PrinterFault</javaName> <qnameScope>complexType</qnameScope> <binder>PrinterFaultTypeBinder</binder> </mapping> </customdatabinding:provider>
WebSphere Application Server provides a BaseFaultBinderHelper class, which provides support for serializing and deserializing the data that is specific to a root BaseFault class, which all specialized BaseFault classes must extend. If a custom binder uses the BaseFaultBinderHelper class, the custom binder then needs to provide only the additional logic for serializing and deserializing the extended BaseFault data.
import com.ibm.wsspi.wsrf.BaseFaultBinderHelper; import com.ibm.wsspi.wsrf.BaseFaultBinderHelperFactory; import com.ibm.wsspi.webservices.binding.CustomBinder; import com.ibm.wsspi.webservices.binding.CustomBindingContext; ... public PrinterFaultTypeBinder implements CustomBinder { // Get an instance of the BaseFaultBinderHelper private BaseFaultBinderHelper baseFaultBinderHelper = BaseFaultBinderHelperFactory.getBaseFaultBinderHelper(); public SOAPElement serialize(Object data, SOAPElement rootNode, CustomBindingContext context) throws SOAPException { // Serialize the BaseFault specific data baseFaultBinderHelper.serialize(rootNode, (BaseFault)data); // Serialize any PrinterFault specific data ... // Return the serialized PrinterFault return rootNode; } public Object deserialize(SOAPElement rootNode, CustomBindingContext context) throws SOAPException { // Create an instance of a PrinterFault PrinterFault printerFault = new PrinterFault(); // Deserialize the BaseFault specific data - any additional data which // forms the PrinterFault extension will be returned as a SOAPElement[]. SOAPElement[] printerFaultElements = baseFaultBinderHelper.deserialize(printerFault, rootNode); // Deserialize the PrinterFault specific data contained within the printerFaultElements SOAPElement[] ... // Return the deserialized PrinterFault return printerFault; } ... }