In series of articles, I discuss some challenges you may face when upgrading Oracle Integration Gen2 (OIC 2) Process (PCS) to Gen3 (OIC 3) Oracle Process Automation (OPA) applications. In this episode I discuss a challenge with the Boundary Error event handling. The previous article can be found here.
Disclaimer: The below provides a snapshot at the time of writing. Things may have changed by the time you read it. It is also important to mention that this does not necessarily represent the view of Oracle.
Specifically for PCS to OPA migration you are also referred to the following:
In OIC Process there are two ways to handle faults with integrations:
· Use the out-of-the-box fault policies (the default when activating),
· Model fault handling and deactivate fault policies.
As I already argued in the article that describes the Custom Fault Handling Pattern [http://kettenisblogs.blogspot.com/2022/10/oic-structured-process-custom-fault.html], the first option is probably not what is required. Instead, you may prefer using an Error Boundary event and model explicit fault handling as part of the process flow.
This is what I have done in a small PCS application to demo the working. First, I have modeled a Business Type with the name Fault that has attributes to hold fault information:
Next to the pretty standard code, summary and detail attributes, I also have attributes for a (unique) businessId and a timestamp for when the fault occurred. I then created a Business Exception with name IntegrationFault, based on the Fault Business Type. I then used the Business Exception to throw, catch and handle any fault in the process, like I did in the below Reusable Subprocess (applying the Service Handler pattern as I first introduced in an article about describing how to do “multi-threading” in PCS [http://kettenisblogs.blogspot.com/2022/02/oic-parallel-gateway-and-multi.html]):
Not shown in detail, but one of the Boundary Errors catches the RemoteFault and the other the BindingFault. Both are then forwarded to an Error End event raising the IntegrationFault Business Exception. Mind, the Service Handler does not handle the exception itself, which therefore is thrown back to the calling process:
As you can see, the calling process has an Event Subprocess that catches all IntegrationFaults. Granted, a bit overcomplicated for such a simple process, but in a real process application you probably have 2 or more integration calls and soon you will appreciate the Service Handler and Custom Fault Handling patterns 😉.
To easily showcase the result, I have put a Human Task in the Fault Handler, displaying the fault details.
For an APIInvocationError for a Bad Request this looks like this:
And for a Not Found like this:
In case of a 401 Unauthorized or 403 Forbidden, it looks like this:
Mind, this won’t return the 401 but instead a 500, which makes sense as this fault is caused by using wrong credentials as configured in OIC, so there is no point for the consumer to try again until this has been fixed on the OIC side (hence the 500). However, the actual, useful information is dug down in [CDATA] and it is not trivial to return in a easy-to-read way.
In case of the Integration not being available this looks like this:
As you can
see, in this case the error is returned (by OIC) as an HTML page.
The challenge
When migrating an application handling Business Exceptions from PCS to OPA, you will find that the specific Exception caught by the Boundary Error events is not supported by OPA. This implies that any PCS process with a Boundary Error event that is configured to catch a specific error, cannot be (in-place) upgraded and instead must be refactored / migrated. I did not check the situation where you chose to catch all business and system exceptions, assuming you make all this effort to catch the error as specific as possible to simplify analyzing issues (compare with Java Exception versus NullPointerException, NumberFormatException, etc.).
The remedy
The good news is that this challenge can be addressed by introducing (what even results in) a simplification of the process, as unlike OIC 2 with its RemoteFault and BindingFault, in case of OIC 3 you only need to catch a single Service Invocation Failure to handle both.
So, in this model that got invalid after the import:
I can delete one of the Boundary Errors events and configure the other to catch the Service Invocation Failure:
The original IntegrationFault Business Exception has been migrated, although the result is not exactly the same. Any Business Exception has a code, message, and details attribute. The first two are fixed, but for details you can choose what type it should have, and when migrating from OIC 2 this became the Fault Business Type I created before. That Fault already had a code and message attribute of its own but that cannot be used in mappings (as you can see in the next picture).
You will find that the data association also became invalid as all source fields are different:
Completely new are the errorName and details.payload and details.uri elements, of which the payload contains the detailed error information. Not to lose the errorName along the way, I added it to my custom Fault Business Type. So, the mappings can be remedied as follows:
I don’t need to fix the mapping to the Error End event as for me that is just fine. Note how the fault is mapped 1:1 to the input.errorInfo.details, as that attribute is based on the same Business Type. The only data I need to add to it, are the businessId and the timestamp.
So, now my Service Handler is done, and I also don’t need to reconfigure the Event Subprocess as that catches the IntegrationFault that was migrated as-is, with its mapping based on the Fault Business Type:
Now let’s see how that works out runtime. I will skip discussing the change I had to make to the UI, as that is just to showcase the result. As you saw before, on OIC 2 I handled the 400 Bad Request. That gives practically the same result on OIC 3:
A 404 Not Found thrown by the backend, for example because it can’t find an city having a specific id, can also be handled the same way (picture concerning a Service Request but the idea is the same):
But from
here one it has changed to what I consider to be an improvement. A 401
Unauthorized raised by the Integration’s Trigger connection is returned as a Service
Invocation Failure which I can handle as the same way as all other faults. Notice
though that there are payload details because the Integration never started:
An Invoke to a back-end using wrong credentials results in a oracle.cloud.connector.api.CloudInvocationException. When returned to the calling process using Fault Return, this also results in a Service Invocation Failure, this time with details (because the Integration was started, and I used the mapping to the Fault Return to propagate the details):
Another improvement (at least in my opinion) is the way that a deactivated or non-deployed Integration call is handled. This now results in a 404 Not Found, instead of the 503 Service Unavailable that OIC 2 used to return. You might consider not showing the detailed message, as that gives away the Integration’s URI:
Previous articles on the subject:
- Part 1 Starting a Process Instance as a Webservice & Consuming SOAP Integrations
- Part 2 Multiple Start Events & Synchronous Process Start
- Part 3 /tasks API challenges
- Part 4 Process Instance and Task Properties
- Part 5 Multi-instance Embedded Subprocess, Current Date ('now'), Process Correlation
- Part 6 Receive and Message Start Interface
- Part 7 Task Assignment to an Individual