# BPEL BluePrint 3

# Fault Handling Using BPEL

Kiran Bhumana, Ryan Kennedy, Shauna Pickett-Gordon

## Problem Description

Built-in support for error handling has evolved into a key feature of many programming languages. Before the advent of error-handling constructs, developers had to manually provide the framework to ensure proper execution in error situations. Now, error-handling constructs are available to support the following patterns:

- Propagate the error and its information
- Ensure that certain code is executed if an error occurs
- Ensure that certain code is executed, whether or not an error occurs

Modern programming languages, including the Business Process Execution Language (BPEL), provide high-level constructs that enable error-handling patterns to be programmed easily and with minimal risk.

Since BPEL is a WSDL-based specification, it refers to these concepts as fault handling. Fault handling in BPEL provides semantics for catching various types of faults, propagating faults, and nesting fault-handling operations.

This document explains some design aspects and usage patterns of BPEL fault handling. It does not attempt an exhaustive list of fault-handling features, but focuses on the most common usage patterns.

## Solution

While a BPEL process is running, it can encounter faults from partner services that are invoked or faults that originate from within the BPEL process itself. Faults that are due to partner service invocations are typically defined on the WSDL operation, whereas faults that originate from within the process are BPEL-defined standard faults and are identified in certain error situations.

BPEL defines a `faultHandler` construct that contains `catch` or `catchAll` constructs to enable the handling of a fault. A `faultHandler`'s `catch` construct defines certain criteria for catching a fault, and the `catch` executes when a fault is thrown and meets those criteria. The `faultHandler`'s `catchAll` construct handles any occurrence of a fault. In the example provided in this BluePrint's design details, a defined `faultHandler` executes a `reply` activity notifying the client that an item is out of stock.

A BPEL developer can isolate sets of related activities within a business process by placing them in a `scope` element. Using `scope` lets the developer control a fault's effect and any consequent action or compensation. The design also isolates other areas of business process execution, and enables better event handling and compensatory actions.

BPEL provides the `faultHandler` construct at three levels:

- As associated with a BPEL process, in short process-level fault handlers
- As associated with a `scope`, in short scope-level fault handlers
- As an inlined short-cut associated with an `invoke` activity

Scopes not only isolate fault handling, but also provide a nesting capability, which suggests that associated fault handlers can form a similar nested hierarchy. A nested `faultHandler` that can't handle a particular fault delegates fault handling to the enclosing `faultHandler`, until it reaches the `faultHandler` at the process level. At that level, either the fault is handled or the instance is terminated. The `throw` and `rethrow` constructs are defined to explicitly cause a fault to happen and propagate throughout the fault-handling chain. A nested `faultHandler` can `rethrow` a fault so that its enclosed scope has the opportunity to handle it. `faultHandler` that are associated with a scope are also used to undo partially completed work within the scope.

## Design Details

The example shown here uses the services discussed in the first BluePrint of this series, Synchronous Web Service Interactions Using BPEL, with added emphasis on fault handling.

The following figure describes the synchronous interaction pattern between the services.

Figure 1: Stateless and Synchronous Service Implementation

In this scenario, the following fault handling patterns are demonstrated:

- Fault handling at the process level
- Explicitly throwing a fault in the BPEL process
- Handling the thrown fault
- Invoking an operation on a partner service that returns a WSDL-defined fault message, causing a BPEL fault.
- Handling the received WSDL-defined fault

To achieve those fault handling patterns, the following BPEL constructs are used:

- `faultHandlers at the process level`
- `throw`, with a fault name and a fault message
- `catch`, with a fault name parameter specified

### Business Logic of the Services

See the first BluePrint in this series for the essential business logic of the services that are used in this example.

### Define the BPEL

This particular example demonstrates two kinds of faults: a fault that is explicitly thrown in `POService`, and a fault that could happen due to the consumption of `InventoryService.`

Fault Explicitly Thrown in BPEL Process
BPEL provides the `throw` construct in order to throw a fault explicitly within a BPEL process.

In this example, `POService` has been modified to check if the incoming purchase order's `orderDescription` value starts with `ThrowPOServiceFault`. If so, `POService uses the `throw` construct` to throw a fault that is to be handled by the process-level faultHandlers.

<if name="Decision">
<condition>starts-with($purchaseOrderRequest.purchaseOrder/orderDescription, 'ThrowPOServiceFault')
</condition>
<sequence name="Sequence1">
<assign name="Assign1">
<copy>
<from>'throwing purchase order fault'</from>
<to part="faultInfo" variable="purchaseOrderFault"/>
</copy>
</assign>
<throw name="Throw"
faultName="pos:cannotCompleteOrder"
faultVariable="purchaseOrderFault"/>
</sequence>
</if>

faultHandlers are used in much the same way as try/catch blocks found in modern programming languages. Within the faultHandlers, one or more catch activities are defined allowing you to handle different faults that may occur within the business process.``

In this scenario, POService contains a process-level fault handler with a `catch` activity to handle the `pos:cannotCompleteOrder` fault. Here, the `catch` clause is defined so that the faults are handled by the fault name.

<faultHandlers>
<catch faultName="pos:cannotCompleteOrder">
<sequence>
<reply name="sendPurchaseOrder.Fault"
partnerLink="POServicePLink"
portType="pos:purchaseOrderPT"
operation="sendPurchaseOrder"
variable="purchaseOrderFault"
faultName="pos:cannotCompleteOrder"/>
</sequence>
</catch>
...
</faultHandlers>

Fault Thrown Due to the Consumption of Partner Service
The inventory service provider has business logic to check the availability of an item. In this BluePrint, additional behavior has been defined so that `InventoryService` can return a WSDL-defined fault when a requested item is not available in inventory. Within `InventoryService`, if the incoming purchase order's `orderDescription` value starts with `ThrowInventoryFault`, a `reply` activity is used to return a fault message to the consumer of the service, `POService`. ``

<if name="checkAvailability">
<condition>starts-with($purchaseOrder.purchaseOrder/orderDescription, 'OrderVal')</condition>
<assign name="Case1">
<copy>
<from>true()</from>
<to>$inventoryStatus.inventoryPart/inventoryStatus</to>
</copy>
<copy>
<from>'available'</from>
<to>$inventoryStatus.inventoryPart/inventoryStatusMessage</to>
</copy>
</assign>
<elseif>
<condition>starts-with($purchaseOrder.purchaseOrder/orderDescription, 'ThrowInventoryFault')</condition>
<sequence name="Case3">
<assign name="Assign2">
<copy>
<from>concat('Inventory Fault thrown for PurchaseOrder ID ', $purchaseOrder.purchaseOrder/orderId, ' customer ID ', $purchaseOrder.purchaseOrder/customerId)</from>
<to part="faultInfo" variable="inventoryService_Fault"/>
</copy>
</assign>
<reply name="inventoryService.Reply_1"
partnerLink="inventorySevicePLink"
portType="invs:inventoryPortType"
operation="inventoryService"
variable="inventoryService_Fault" faultName="invs:inventoryFaultType"/>
</sequence>
</elseif>
<else>
<assign name="Case2">
<copy>
<from>false()</from>
<to>$inventoryStatus.inventoryPart/inventoryStatus</to>
</copy>
<copy>
<from>'currently out of stock'</from>
<to>$inventoryStatus.inventoryPart/inventoryStatusMessage</to>
</copy>
</assign>
</else>
</if>

A `invs:inventoryFaultType` fault is then caught in a second catch activity defined within the `POService` fault handler. This particular fault is handled at the process level and causes `POService` to return a WSDL-defined fault to its consumer.

<faultHandlers>
...
<catch faultName="invs:inventoryFaultType" faultVariable="inventoryServiceFault" faultMessageType="invs:inventoryFault">
<sequence>
<assign name="Assign1_1">
<copy>
<from variable="inventoryServiceFault"
part="faultInfo"/>
<to variable="purchaseOrderFault"
part="faultInfo"/>
</copy>
</assign>
<reply name="sendPurchaseOrder.Fault"
partnerLink="POServicePLink"
portType="pos:purchaseOrderPT"
operation="sendPurchaseOrder"
variable="purchaseOrderFault"
faultName="pos:cannotCompleteOrder"/>
</sequence>
</catch>
...
</faultHandlers>

Since the fault handling is at the process level, the BPEL process instance is terminated after the fault is handled.

The following diagram illustrates how a process-level fault handler is used in the `POService` BPEL process.

Figure 2: POService BPEL Process

The next diagram shows the corresponding fault-handling activities in the `InventoryService` BPEL process.

Figure 3: InventoryService BPEL Process

See the first BluePrint in this series for further details on the BPEL artifacts used in each process.

### Define the WSDL

The following `POService` WSDL operation defines a fault named cannotCompleteOrder:

        <portType name="purchaseOrderPT">
            <operation name="sendPurchaseOrder">
                <input name="sendPurchaseOrderRequest" message="tns:POMessage"></input>
                <output name="sendPurchaseOrderReply" message="tns:POMessage"></output>
                <fault name="cannotCompleteOrder" message="tns:orderFaultType"></fault>
            </operation>
        </portType>

The `InventoryService` WSDL operation also defines a fault named inventoryFaultType:

        <portType name="inventoryPortType">
            <operation name="inventoryService">
                <input name="purchaseOrder" message="tns:POMessage"></input>
                <output name="inventoryStatus" message="tns:InventoryMessage"></output>
                <fault name="inventoryFaultType" message="tns:inventoryFault"></fault>
            </operation>
        </portType>

See the first BluePrint in this series for further details on these WSDL artifacts.

### Additional Design Details

Also consider the following when you are designing fault handling into your BPEL processes.

- Various ways of handling faults. In this particular scenario, the `catch` section of a fault handler handles a fault by only the fault name. Refer to the BPEL specification for other ways of handling faults.

- Scope in fault handling. In this particular design, scopes could have been defined around the regions where fault handling is necessary. This would be beneficial if a lot of fault handling code were needed, and if fault handling code were not required to be shared.

- Invoke-related fault handling. An inlined or embedded fault handler can be defined for `invoke`, which would handle faults related to that `invoke`. This would target the fault-handling code over the areas where the fault occurs. The advantage is that all the necessary fault handling is handled where it is expected to occur. However, `invoke` related fault handling isn't the ideal approach if fault handling code needs to be shared or must be duplicated.

- Localized usage of fault handling. Fault handling at the scope or `invoke` level lets the developer take appropriate compensatory action based on the fault. This pattern is more applicable to a BPEL process, which is an orchestration of many services that might still need to continue despite the occurrence of a fault in one area.

- Trade-offs in level-specific design. Fault handling must be designed appropriately at the level of process, scope, or invoke activity level. Consider the pros and cons of isolation, compensation, and sharing of the fault handling code.

- Use of `reply` to send faults. A `reply` activity can be used to send a WSDL-defined fault to the consumer of the service. A `faultName` attribute on the `reply` activity gives a clue to the `faultType`.

### Input Data XML for Different Scenarios

The following input XML instance gives a valid response.

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns="http://manufacturing.org/xsd/purchase"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/ http://schemas.xmlsoap.org/soap/envelope/">
      <soapenv:Body>
        <sendPurchaseOrder>
          <purchaseOrder>
            <purchaseOrder xmlns="http://manufacturing.org/xsd/purchase">
              <orderId>00012343</orderId>
    	  <customerId>9876</customerId>
    	  <orderDescription>OrderVal_Any_Description</orderDescription>
    	  <price></price>
            </purchaseOrder>
          </purchaseOrder>
        </sendPurchaseOrder>
      </soapenv:Body>
    </soapenv:Envelope>

The next input XML instance causes a `cannotCompleteOrder` fault to be thrown to the client. The fault is due to the execution of a `throw` activity within the `POService` BPEL process.

    <soapenv:Envelope xmlns="http://manufacturing.org/xsd/purchase"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/ http://schemas.xmlsoap.org/soap/envelope/">
      <soapenv:Body>
        <sendPurchaseOrder>
          <purchaseOrder>
            <purchaseOrder xmlns="http://manufacturing.org/xsd/purchase">
              <orderId>00012342</orderId>
              <customerId>9876</customerId>
              <orderDescription>ThrowPOServiceFault_Val_Any_Description</orderDescription>
              <price></price>
            </purchaseOrder>
          </purchaseOrder>
        </sendPurchaseOrder>
      </soapenv:Body>
    </soapenv:Envelope>

The following input XML instance causes a `cannotCompleteOrder` fault to be thrown to the client. This fault is due to a fault sent by the inventory service.

    <soapenv:Envelope xmlns="http://manufacturing.org/xsd/purchase"
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/ http://schemas.xmlsoap.org/soap/envelope/">
      <soapenv:Body>
        <sendPurchaseOrder>
          <purchaseOrder>
            <purchaseOrder xmlns="http://manufacturing.org/xsd/purchase">
              <orderId>00012341</orderId>
              <customerId>9876</customerId>
              <orderDescription>ThrowInventoryFault_Any_Description</orderDescription>
              <price></price>
            </purchaseOrder>
          </purchaseOrder>
        </sendPurchaseOrder>
      </soapenv:Body>
    </soapenv:Envelope>

## References

- Browse the source code for this BluePrint, including the BPEL process files and WSDL files.
- See the BPEL BluePrint sample projects included in the NetBeans Enterprise Pack 5.5 Beta IDE.
- For general information on BPEL, see Business Process Execution Language, Part 1: An Introduction.

© Sun Microsystems 2006. All of the material in The Java BluePrints Solutions Catalog is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.