Exception handling is an essential requirement while building any robust application. It is true for the application that is built using BPEL also. As you would know, Oracle BPEL supports both business specific exceptions (they are declared in the service WSDL) and run time exceptions (Needless to say, they are NOT declared in the WSDL). This post is about supporting run time exception.
Assume that as part of your BPEL flow, you are invoking a SOAP service that is hosted remotely. When the remote service is not up and running, then BPEL flow will send back a fault to the client. The fault message will be something similar to the following: -
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<env:Fault>
<faultcode>env:Server</faultcode>
<faultstring>oracle.fabric.common.FabricInvocationException: Unable to access the following endpoint(s): http://localhost:9090/axis2/services/StockQuoteService.StockQuoteServiceHttpSoap11Endpoint/</faultstring>
<faultactor/>
<detail>
<exception>Unable to access the following endpoint(s): http://localhost:9090/axis2/services/StockQuoteService.StockQuoteServiceHttpSoap11Endpoint/</exception>
</detail>
</env:Fault>
</env:Body>
</env:Envelope>
This is not a correct behaviour for a good application. The application should catch the exceptions and handle it properly depending on the application requirement. Assume that, in this case, you have to return a default value, say -1, instead of sending exception message.
Oracle BPEL supports this by having 'Add Catch' construct which can be added to the 'Scope' construct where in you actually have defined the 'Invoke' activity. In Oracle SOA suite 11g, when you add 'Catch' construct, it will import a WSDL (namely RuntimeFault.wsdl) that defines the structure of the runtime message automatically. The definition is as given below: -
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="RuntimeFault"
targetNamespace="http://schemas.oracle.com/bpel/extension"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<message name="RuntimeFaultMessage">
<part name="code" type="xsd:string"/>
<part name="summary" type="xsd:string"/>
<part name="detail" type="xsd:string"/>
</message>
</definitions>
The above message will support catching code, summary and details of the remote exception thrown because of the downtime of the remote service. In this example, we are not going to use any of these three parts (however, it is possible to do that). Alternatively, we are going to catch the exception and return a default value, say -1.
When you define the 'Catch' construct, it will add a line as given below in your .bpel file: -
<variable messageType="bpelx:remoteFault" name="FaultVar"/>
- where FaultVar is the name of the fault variable using which you can access its child elements - code, summary and detail
After adding Catch construct, now do a 'Deploy' to application server. But you will get an error as given below: -
Error(67): WSDL messageType "{http://schemas.oracle.com/bpel/extension}remoteFault" of variable "" is not defined in any of the WSDL files
So, what went wrong?
Take a look at these two :-
a) FaultVar variable declaration in the bpel file and
b) RuntimeFaultMessage message definition in the RuntimeFault.wsdl.
The FaultVar is of 'bpelx:remoteFaul' type which is not defined anywhere. Instead, RuntimeFault.wsdl defines another messgae type which is of "RuntimeFaultMessage" type. So, solution is simple - just replace 'remoteFault' by 'RuntimeFaultMessage'. It will do the necessary MAGIC!!!
Now, recompile and deploy to application server. The BPEL service will get deployed onto the application server. When you access the service, now you will get the expected response
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<env:Body>
<processResponse xmlns="http://xmlns.oracle.com/StockApps/StockMarket/StockMarketProcess">
<result>-1</result>
</processResponse>
</env:Body>
</env:Envelope>
Hope this is useful to you.
Happy Fault Handling!
Assume that as part of your BPEL flow, you are invoking a SOAP service that is hosted remotely. When the remote service is not up and running, then BPEL flow will send back a fault to the client. The fault message will be something similar to the following: -
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<env:Fault>
<faultcode>env:Server</faultcode>
<faultstring>oracle.fabric.common.FabricInvocationException: Unable to access the following endpoint(s): http://localhost:9090/axis2/services/StockQuoteService.StockQuoteServiceHttpSoap11Endpoint/</faultstring>
<faultactor/>
<detail>
<exception>Unable to access the following endpoint(s): http://localhost:9090/axis2/services/StockQuoteService.StockQuoteServiceHttpSoap11Endpoint/</exception>
</detail>
</env:Fault>
</env:Body>
</env:Envelope>
This is not a correct behaviour for a good application. The application should catch the exceptions and handle it properly depending on the application requirement. Assume that, in this case, you have to return a default value, say -1, instead of sending exception message.
Oracle BPEL supports this by having 'Add Catch' construct which can be added to the 'Scope' construct where in you actually have defined the 'Invoke' activity. In Oracle SOA suite 11g, when you add 'Catch' construct, it will import a WSDL (namely RuntimeFault.wsdl) that defines the structure of the runtime message automatically. The definition is as given below: -
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="RuntimeFault"
targetNamespace="http://schemas.oracle.com/bpel/extension"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<message name="RuntimeFaultMessage">
<part name="code" type="xsd:string"/>
<part name="summary" type="xsd:string"/>
<part name="detail" type="xsd:string"/>
</message>
</definitions>
The above message will support catching code, summary and details of the remote exception thrown because of the downtime of the remote service. In this example, we are not going to use any of these three parts (however, it is possible to do that). Alternatively, we are going to catch the exception and return a default value, say -1.
When you define the 'Catch' construct, it will add a line as given below in your .bpel file: -
<variable messageType="bpelx:remoteFault" name="FaultVar"/>
- where FaultVar is the name of the fault variable using which you can access its child elements - code, summary and detail
After adding Catch construct, now do a 'Deploy' to application server. But you will get an error as given below: -
Error(67): WSDL messageType "{http://schemas.oracle.com/bpel/extension}remoteFault" of variable "" is not defined in any of the WSDL files
So, what went wrong?
Take a look at these two :-
a) FaultVar variable declaration in the bpel file and
b) RuntimeFaultMessage message definition in the RuntimeFault.wsdl.
The FaultVar is of 'bpelx:remoteFaul' type which is not defined anywhere. Instead, RuntimeFault.wsdl defines another messgae type which is of "RuntimeFaultMessage" type. So, solution is simple - just replace 'remoteFault' by 'RuntimeFaultMessage'. It will do the necessary MAGIC!!!
Now, recompile and deploy to application server. The BPEL service will get deployed onto the application server. When you access the service, now you will get the expected response
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<env:Body>
<processResponse xmlns="http://xmlns.oracle.com/StockApps/StockMarket/StockMarketProcess">
<result>-1</result>
</processResponse>
</env:Body>
</env:Envelope>
Hope this is useful to you.
Happy Fault Handling!