SOAP Fault in SAP PI: hijack it!
If you’re developing complex integration scenarios with SAP PI that involve third party web service providers (SAP and non-SAP), you need a robust way to handle SOAP Fault messages and, as far as I know and could find on the web, this topic is still vague, and was never really faced.
Scenarios
What are the real use cases you might be interested in?
1 – Synchronous to synchronous
(OK) (e.g. RFC->SOAP or viceversa) – This is the simplest one, and feasible out of the box, as greatly explained by Jin Shin in Handling Web Service SOAP Fault Responses in SAP NetWeaver XI. If you’re familiar with SAP PI (and you should really be if you’re reading this blog since it’s a quite advanced topic), you know that in synchronous service operation mapping you can have 3 different message mapping: Request, Response and Fault. Therefore if you’re sender system has the ability (from a signature point of view) to accept an exception, it’s just matter of deciding the best way to map the receiver system exception (a SOAP Fault, for instance) into the sender’s one.
2 – Synchronous web service call from inside a BPM
(KO) – This is possible to a certain extent, that is you can easily recognize that an error (a SOAP Fault) was thrown by the receiver system by putting an exception branch in the block where you make the synchronous call to the web service, but you completely lose the content of the SOAP Fault (e.g. the severity, the message, some useful variables) and so you’re unable to correctly handle it and eventually propagate the information anyhow.
3 – Asynchronous call to web service
(KO) (e.g. IDoc to web service) – This is also possible but with known and strong limitations, as once again you can find erroneous messages in the RWB Message Monitor, but if you drill down and open the message audit log you have no clue about what really wentwrong in the receiver system, as a system error is always reported.
This is a standard behaviour – but yet a nonsense to me – as explained in note 856597 (SOAP Adapter FAQ), in second question of section 6:
“Prior to SP11, a SOAP fault resulted in the application or system error, depending on whether the SOAP fault contained a detail child element or not. This behavior contradicted the communication model. Therefore, it has been changed so that the adapter generates the system error for any SOAP fault in asynchronous calls.”
The Idea
So how to handle case 2 and 3?
When I was to face this enigma, at least four approaches came to my mind:
- Changing middleware… Naaa, not really! ????
- Hacking standard SAP PI code… This is not the case!
- Implementing web services on the provider side in a different way
- Hijacking the SOAP Fault content to a different route
In the hope the that reader will forgive myself for the jokes of points 1 and 2 above, logically speaking approaches 3 and 4 are really the same, but implemented in different places. We all know that in integration projects several parties and vendors are usually involved, so even if approach 3 could be cheaper, you may not be allowed to put your hands on that code and on that machine. “Hey! Are you a PI developer? Yes? Good, so get this fixed in PI and don’t change the “as is” of satellite systems!!” – How many times have you heard this insane litany? How many will you hear more? ????
So the real idea is to replace the SOAP Adapter and make use of the more flexible Axis Apdater to be able to hijack the Fault message into the Response message, for scenario 2, and to propagate the SOAP Fault message in the message audit log, for scenario 3.
Prerequisites
Frankly speaking, you’ll have to do with what you’ve got in this blog and handle a number of things yourself, as some time has past since I implemented this solution, and I don’t remember a bunch of details. But I guarantee: this thing here actually works (in PI 7.11, but I don’t see any reason why it shouldn’t in 3.0 and 7.0 as well) and everything that I may be missing is documented somewhere in SAP KB. So, don’t be afraid, google at hand, and keep going!
First of all you need to deploy and enable the Axis Adapter, as described in the SAP Help (see this for reference: even if it’s a bit outdated, story is the same).
Then you need the Axis SDK, that can be found in note 1039369 (Axis FAQ, which should be your “bible” from here onwards). I’m gonna tell you the truth: if you are a “fundamentalist” (as much as I am) of correct Java/J2EE development with NWDS, DCs and NWDI, you have to resign yourself: I even opened a customer support request in OSS and the answer was there’s no current standard way to implement this solution such that it can fit into the current SAP Java Implementation model and Software Lifecyle model.
So how to…? You need to code this thing (which is actually nothing more than a single Java class, namely an Axis handler) in a common Java project (with all the correct references to libraries), compile it, manually add it to the aii_af_axisprovider.sda and deploy it. This is ugly, I know, but I couldn’t find any more elegant way.
Implementation
What are we going to do?
If you enable the Axis handler on a SOAP receiver communication channel, you are presented with something like the picture below in the Module tab.
Well, the architecture behind Axis really allows you to put a whole stack of handlers in order to do whatever you wanna do, but here we need to do something more hackerous, therefore we will create a new Transport Handler by enhancing the behaviour of the standard one, namely com.sap.aii.adapter.axis.ra.transport.http.HTTPSender
What does it need to do more? When a SOAP Fault is issued by the web service provider, the HTTP server that contains it usually sends an HTTP 500 error, which is caught by the Adapter Framework (either normal SOAP or Axis) and handled as a mere blind exception – and this is why the aforementioned cases 2 and 3 can’t be really handled out of the box.
So here’s a basic list of things tasks that our new Axis Handler – which we’ll call TolerantHttpSender – needs to do:
(1) avoid raising an exception if an HTTP 500 is sent by the server (i.e. by the web service provider), and handle the SOAP Fault content in two different flavours:
(2) if it’s a synchronous call (case 2), map the content of the SOAP Fault in the SOAP Response (note: a generic and “all season” message format must be agreed here!), so that the content is returned back to PI and can be easily handled in a response mapping
(3) if it’s an asynchronous call (case 3), put the SOAP Fault content into a qualified exception and throw it, so that it is reported back into the message audit log
And, that’s it!
Now take a look at the code (I know it looks messy here, but it’s not even that badly written from a Java perspective…), with particular attention to the hijackSoapFault method, which is called from the readFromSocket, which is called from the main method invoke.
The code is here as a Wiki Code Snippet
In order to compile, you need references at least to axis.jar, commons-logging-1.0.4.jar (both from the Axis standard package) and sapxmltoolkit.jar (used for the mapping with DOM).
Result
When you get to compile, deploy and use this new handler in your SOAP AXIS Receiver Channel in the module stack, you get the ability to handle the SOAP Fault inside a BPM as if the receiver issued a common SOAP Response – but you should be able to catch the difference between a “real” Response and a fake one by using a return code, for instance – and understand the reason why an asynchronous message is in error by looking at its audit log.
This should be a nice step forward in the constant fight for SOAP Fault taming! ????
New NetWeaver Information at SAP.com
Very Helpfull