Technical Articles
Fetch SOAP Fault/Error Response from Receiver in SAP Cloud Platform Integration
Introduction
If you are working on integration development for Cloud Platform Integration (CPI), you have probably already used the SOAP receiver adapter with the request-reply pattern.
As long as everything works fine on the receiver side, it works fine on the CPI side, I get the SOAP response and can work with it. But in case of server errors, I noticed an undesirable behavior. SOAP Faults or error messages were not accessible for me, in the error subprocesses. The message body was simply empty, after the request-reply step.
Context
In my case, I have set up a web service call to a SOAP endpoint from SAP Process Orchestration (PO). The endpoint is configured to send an error message with details to the sender when an error occurs.
To accomplish this on SAP PO site, follow this SAP Note 2293430 – Processing error response at sender SOAP adapter – SAP ONE Support Launchpad
In the CPI I want to process these error details and display them to the responsible user. This did not work out of the box, the message text was always just empty after the error occurred.
First Attempts
The only thing I got was a generic message “Server Error” from the exchange object with the ${exception.message} operation.
Next I’ve tried a script for http error response extraction from ${property.CamelExceptionCaught} , mentioned on this help site:
Script Example for Exception Handling in HTTP Receiver – SAP Help Portal
But this script works only with HTTP exceptions, like
org.apache.camel.component.ahc.AhcOperationFailedException
It doesn’t work because we captured another object in this property during runtime. It is not AhcOperationFailedException, but an object of SoapFault class.
Adjusted Solution
I’ve stickend to the solution with a script and tried to adjust it to SOAP Fault objects.
——————————————————————–
org.apache.cxf.binding.soap
Class SoapFault extends Fault
Element |
getDetail()
Returns the detail node.
|
Element |
getOrCreateDetail()
Returns the detail node.
|
ref.: SoapFault (Apache CXF JavaDoc 3.2.0 API)
——————————————————————–
Those both functions provide an org.w3c.dom.Element, which is (unfortunately) not parsable by the CPI. You can set this Element as a new body and you will see the message body during trace. But operations (like XPath, Content Modifier) won’t work on your new message body. You will receive an error message like:
org.apache.camel.NoTypeConversionAvailableException: No type converter available to convert from type: com.sun.org.apache.xerces.internal.dom.ElementNSImpl to the required type: javax.xml.transform.sax.SAXSource
Serializing the org.w3c.dom.Element object to a simple String and set it as the message body, works great for the CPI.
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import org.w3c.dom.Node;
import groovy.xml.*
def Message processData(Message message) {
def map = message.getProperties();
def ex = map.get("CamelExceptionCaught");
if (ex.getClass().getCanonicalName().equals("org.apache.cxf.binding.soap.SoapFault")) {
def xml = XmlUtil.serialize(ex.getOrCreateDetail());
message.setBody(xml);
}
return message;
}
– Improvements by Thomas Buerki
Conclusion
This script gives me the ability to process the SOAP fault response with the usual XPath operations and even mappings. I can now distinguish between nodes and evaluate them individually.
I hope this script helps someone who is struggling with the same problem.
I am open for improvements, opinions and questions.
Cheers
Dennis Sentler
Hi Dennis,
Thanks for sharing! Nice catch and explanation! My impression is that SAP doesn't want to break anything including scripts so it should be safe to use this method. I hope SAP includes this in the official script examples, it would be even better.
Regards,
Fatih
Thanks for supporting me on my first blog post Fatih Pense
Hi Dennis, great start to your blogging journey! I'm eagerly waiting for more 😉 Feel free to connect if I can help with anything, from discussion to proof-reading 🙂
I have included this script to my community repo here with a reference to this blog post: https://github.com/pizug/cpi-groovy-examples/tree/master/get-soap-error-body
Best regards,
Fatih
Do You have any sample code in groovy to return the root node as output.
Hi Niharika, if you need the XML as it is, I think you still need to use HTTP adapter. This exception class parses the SOAP Exception.
Regards,
Fatih
Hi Fatih,
I just want to read the parent node coming from the soap service. I have a link that explains my requirement but it is in java and I need it in groovy. I am pretty new to groovy to I am missing some methods to add.
https://www.roseindia.net/xml/dom/GetRootNode.shtml
Could You see if I could get any help on code.
Hi Niharika, if you need the XML root element, I think you have to change the receiver adapter to HTTP. I'm not aware of any other solution. Then when an exception happens you can use another script in the exception subprocess.
I have documented the steps to change receiver from SOAP->HTTP here:
https://answers.sap.com/questions/13028235/fetch-soap-fault-message-in-receiver-in-cpi.html
You can also search for similar questions or create a new question for better visibility.
https://community.sap.com/search/?ct=qa&q=cpi%20soap%20exception%20body&qt=all
Regards,
Fatih
Hello Dennis,
Nice write up and helpful one for quick references!
Regards,
Sriprasad Shivaram Bhat
Thank you
Hi Dennis - Good to see the available option to process the soap fault.
I had the similar requirement earlier , but couldn't achieve the same.
Thanks for sharing your findings to the community
Keep exploring and blogging.
Cheers
Rajesh Pasupula
Hi Dennis - Thank you for sharing!
Converting a Node into a XML string could be done simpler in Groovy:
If you need a XML without declaration, you could write:
Regards
Thomas
Hi Thomas,
I’m not very familiar with groovy libraries, so thank you very much for your comment.
It works like a charm!
Do you mind, if I improve the blog post with your code?
Thanks Dennis
Hi Dennis
No, please use my code if you want to use it in your blog post.
Hi Dennis
In my case, this is not working as expected. However, I'm getting the property CamelExceptionCaught as
Also, I've tried modifying this value in equals conditions and still not working.
Suggestions will be appreciated!