Wednesday, 29 April 2020

SOA Suite: SOAP Faults in BPEL and Mediator

In the past few months, at our current customer we are having a "robustness project" to improve our SOA Suite implementation. We had a lot of duplication and it turned out that we had a lot of WSDLs in our composite projects. Many of those are a result of BPEL projects from 10g. But some of them weren't possible to move because it would break the project.

The first projects where I encountered the problem were projects with Mediators. After moving the WSDLs to MDS, most of our SoapUI/ReadyAPI unit test worked, except for those simulating a SOAP Fault. It seemed that the Mediator could not map the SOAP Fault. I searched "me an accident", we would say in Holland. But without any luck.

Actually, I can't find any documents that talks about catching SOAP Faults in SOASuite. Which is a weird thing, because in BPM Suite, sharing the same soa-infra and process engine, there is a preference for SOAP Faults. Because BPM can react with specific exception transitions on SOAP Faults.

So what is this weird behavior? Well actually, SOA Suite, apparently both BPEL and Mediator, interpret SOAP Faults as Remote Faults! So, in BPEL you can't catch it as a SOAP Fault and Mediator can't route it in the correct way. What you would suggest from the UI.

However, just now I found a solution. That is, I found it earlier for Mediator, but couldn't explain it. Since the same behavior can be seen in BPEL as well, I can write down my story.

Normally, if you would add a reference to your composite, it would look like something as follows in the composite.xml source:
  <reference name="ManagedFileService"
             ui:wsdlLocation="oramds:/apps/Generiek/WSDLs/ManagedFileUtilProcess.wsdl">
    <interface.wsdl interface="http://xmlns.darwin-it.nl/soa/wsdl/Generiek/ManagedFileService/ManagedFileProcess#wsdl.interface(managedfile_ptt)"/>
    <binding.ws port="http://xmlns.darwin-it.nl/soa/wsdl/Generiek/ManagedFileService/ManagedFileProcess#wsdl.endpoint(managedfile_ptt/managedfile_pttPort)"
                location="oramds:/apps/Generiek/WSDLs/ManagedFileUtilProcess.wsdl" soapVersion="1.1">
      <property name="endpointURI">http://soa.hostname:soa.port/soa-infra/services/default/ManagedFileService/managedfileprocess_client_ep</property>
      <property name="weblogic.wsee.wsat.transaction.flowOption" type="xs:string" many="false">WSDLDriven</property>
    </binding.ws>
  </reference>

What you see here is a ui:wsdlLocation, which should point to a WSDL in the MDS. under binding.ws there is a location attribute that at many customers would point to your concrete WSDL. At my current customer we work with an endpointURI property that is overwritten using the config plan. In any way, the service element of the WSDL is in the MDS or on the Remote Server, if your refer to an external service.

If the external service would raise an SOAP Fault, it can't be caught, other than through a Catch all:




This makes it also hard to interact in the correct way with the fault, to interpret the underlying problem. This service should rename or move a file on the filesystem. And in this case the file couldn't be found. But the remote fault would suggest something else.

But, there is a real easy workaround. I wouldn't call it a solution, since I think SOA Suite should just handle SOAP Faults correctly.

In the composites WSDLs folder make a copy of the concrete WSDL and strip it down as follows:
<?xml version= '1.0' encoding= 'UTF-8' ?>
<wsdl:definitions name="ManagedFileProcess"
                  targetNamespace="http://xmlns.darwin-it.nl/soa/wsdl/Generiek/ManagedFileService/ManagedFileProcess"
                  xmlns:tns="http://xmlns.darwin-it.nl/soa/wsdl/Generiek/ManagedFileService/ManagedFileProcess"
                  xmlns:mfs="http://xmlns.darwin-it.nl/soa/xsd/Generiek/ManagedFileService/ManagedFileProcess"
                  xmlns:plnk="http://docs.oasis-open.org/wsbpel/2.0/plnktype"
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
  <wsdl:import location="oramds:/apps/Generiek/WSDLs/ManagedFileUtilProcess.wsdl"
               namespace="http://xmlns.darwin-it.nl/soa/wsdl/Generiek/ManagedFileService/ManagedFileProcess"/>
  <wsdl:service name="managedfile_ptt">
    <wsdl:port name="managedfile_pttPort" binding="tns:managedfile_pttSOAP11Binding">
      <soap:address location="http://soa.hostname:soa.port/soa-infra/services/default/ManagedFileService/managedfileprocess_client_ep"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>
In the service element there is a reference to the SOAP endpoint of the service, in this case simply a local SOA Suite service.

In the composite you need to change the reference:
  <reference name="ManagedFileService"
             ui:wsdlLocation="oramds:/apps/Generiek/WSDLs/ManagedFileUtilProcess.wsdl">
    <interface.wsdl interface="http://xmlns.darwin-it.nl/soa/wsdl/Generiek/ManagedFileService/ManagedFileProcess#wsdl.interface(managedfile_ptt)"/>
    <binding.ws port="http://xmlns.darwin-it.nl/soa/wsdl/Generiek/ManagedFileService/ManagedFileProcess#wsdl.endpoint(managedfile_ptt/managedfile_pttPort)"
                location="WSDLs/ManagedFileUtilProcess.wsdl" soapVersion="1.1">
      <property name="endpointURI">http://soa.hostname:soa.port/soa-infra/services/default/ManagedFileService/managedfileprocess_client_ep</property>
      <property name="weblogic.wsee.wsat.transaction.flowOption" type="xs:string" many="false">WSDLDriven</property>
    </binding.ws>
  </reference>
Here you change the binding.ws location to refer to the local stripped WSDL. the endpointURI property does not make much sense anymore, but it does not gets in the way.

You also need to change your config plan to contain the following WSDL Replacement:
 <wsdlAndSchema name="*">
  <searchReplace>
   <search>http://soa.hostname:soa.port/soa-infra/services/default/ManagedFileService/managedfileprocess_client_ep</search>
   <replace>http://soasuite12c.soa.darwin-it.nl:8001/soa-infra/services/default/ManagedFileService/managedfileprocess_client_ep</replace>
  </searchReplace>
 </wsdlAndSchema>

This will do a replacement of the endpoint in the WSDL that can be used.


If you deploy this, using the config plan, then amazingly, SOAP Faults are correctly interpreted:


Now, we get a neat SoapFault caught by a specific catch, based on the fault in the WSDL of the partner link.

Again, this works similarly for Mediator.