The SOAP specification describes a way how errors should be returned to a sender of a SOAP message:
- A SOAP fault message should be returned.
In Cloud Integration we provide a SOAP adapter and several SOAP based adapters (SAP RM, IDOC, XI). Those are the ones I am referring to when mentioning SOAP based channels or adapters. Often the receiver adapters used in an integration flow are not SOAP based. That means they return an error that cannot be used directly to create a SOAP fault out of it. The SOAP based sender channels have to convert this error into a SOAP fault message.
This conversion is a generic process. Several attributes of the SOAP fault message are either not set or set to default values. Therefore, information about the error can get lost. Moreover, users might want to enhance the error information by extracting details from the context and enriching the fault message.
Therefore, with the 14-April-2023 release we provide an API that allows setting attributes of a SOAP fault message in a script step. This script step should be the last step in your error handling routine. Changing the resulting exception (e.g., by using an exception subprocess) may cause an undesired result. Also, be aware that Cloud Integration supports two SOAP specifications: SOAP 1.1 and SOAP 1.2. Furthermore, the API here introduced supports both versions as each of them has defined the SOAP fault slightly different.
In this blog, I’ll show you how to use this API to improve the error handling process.
Understanding the API
The main entry point for the API is the factory class SoapFaultFactory which offers three methods that throw an exception the SOAP based sender channels will use to generate the corresponding SOAP fault message:
Method throwSoapFault(SoapFaultParam param)
This method offers the most flexible interface. The SoapFaultParam class provides a large set of attributes to configure all properties of a SOAP fault as defined by the specifications.
Method throwSoapFault(String faultstring, Element detail, Map<String, String> namespaces)
Compared to the first method, the number of properties has been reduced. In this method only text-like properties can be set. I will refer to this method as “throwSoapFault” with a “simple” interface.
Method throwXiSoapFault(XiSoapFaultParam param)
The XI protocol defines additional requirements for the text-like parts of the SOAP fault based on the SOAP 1.1 specification. These are the attributes of the XiSoapFaultParam class.
Examples
I provide two examples how the API can be used. The scenarios are very similar since the use case is restricted.
- A message is received by a sender channel and an error event is used to simulate an error in the integration flow processing. This could be an integration flow step that fails or an error from a receiver system that triggers a corresponding exception in the receiver channel.
- An exception sub process will handle the exception by using a Groovy script step to call a method and return a SOAP fault to the sender system.
Please note: To receive the error message on the sender system, you must modify the error configuration of the integration flow. Select ‘Return Exception to Sender’. Otherwise, you will get the standard message that refers to the MPL.
Method throwSoapFault with “simple” Interface
As a sender system, you can use any tool capable of sending a SOAP message. The integration flow I am using is shown below:
The message “Error End 1” raises an exception that is processed by the exception subprocess “Exception Subprocess 1”. The Groovy script used here is
import com.sap.gateway.ip.core.customdev.util.Message;
import org.apache.cxf.staxutils.StaxUtils;
import org.w3c.dom.Element;
import com.sap.gateway.ip.core.customdev.processor.SoapFaultFactory;
import javax.xml.namespace.QName;
import java.text.MessageFormat;
def Message processData(Message message) {
String xml = "<a><SAP:Error soap:mustUnderstand="1" xmlns:SAP="http://sap.com/xi/XI/Message/30" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><SAP:Category>XIServer</SAP:Category><SAP:Code area="INTERNAL">MESSAGE</SAP:Code><SAP:P1>{0}</SAP:P1><SAP:P2>{1}</SAP:P2><SAP:P3>{2}</SAP:P3><SAP:P4>{3}</SAP:P4><SAP:AdditionalText>{4}</SAP:AdditionalText><SAP:Stack>{5}</SAP:Stack></SAP:Error></a>";
Element detail = StaxUtils.read(new StringReader(MessageFormat.format(xml, "P1", "P2", "P3", "P4", "TEXT", "stack"))).getDocumentElement();
SoapFaultFactory.throwSoapFault("This is a FAULT", detail, null);
return message;
}
This script uses a very simple method to create the ‘detail’ for the API call. It uses a utility class from Apache CXF to convert a string to DOM element. This utility can be replaced by any other comparable utility.
The ‘detail’ parameter in this case refers to the one outlined by the XI specification as part of an XI SOAP fault message and is solely used for demonstrating the API. As the utility produces a DOM representation with all namespaces included, there is no need to add any namespaces, and the parameter is null. The SOAP fault message returned to the sender is
Method throwXiSoapFault
In the second scenario, I demonstrate the same process for an XI sender channel.
As sender application you could either use an ABAP proxy or model a Cloud Integration scenario with a SOAP channel to XI channel where you can utilize any available SOAP client to create a SOAP message. The scenario will convert the SOAP message into an XI message which then can be used in the following scenario:
For simplicity I use Quality of Service BestEffort. The script used is
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import com.sap.gateway.ip.core.customdev.processor.SoapFaultFactory;
import com.sap.gateway.ip.core.customdev.processor.XiSoapFaultParam;
import javax.xml.namespace.QName;
def Message processData(Message message) {
XiSoapFaultParam param = new XiSoapFaultParam();
param.setFaultactor("Actor");
param.setFaultcode(new QName("namespace", "name"));
param.setFaultstring("This is a fault");
param.setSapAdditionalText("TEXT");
param.setSapP1("P1");
param.setSapP2("P2");
param.setSapP3("P3");
param.setSapP4("P4");
param.setSapStack("stack");
SoapFaultFactory.throwXiSoapFault(param);
return message;
}
When you sent a message from an ABAP proxy and check the message monitor (transaction sxi_monitor) in the ABAP system the SOAP fault will appear as an XI error header:
By following these examples, you’ve learned how to set a SOAP Fault message for SOAP and XI sender channels in a script step.