Last week, we looked at the assign and other basic activities, and studied flow. This week, we'll be examining more sturctured activities, and fault handling. This article, the fifth in a six-part series, is excerpted from chapter 12 of Building Web Services with Java: Making sense of XML, SOAP, WSDL, and UDDI, written by Steve Graham et al. (Sams; ISBN: 0672326418).
Fault Handling with Web Services - Fault Handler Example (Page 3 of 4 )
SkatesTown's purchase order process has multiple places that deal with faults and fault handling. As an example, the process outline in Figure 12.6 shows the invocation of the order validation step and a flow to subsequent activities. Transition conditions on the links determine whether the validation result is OK or considered failed. In the latter case, a fault is thrown explicitly. The associated fault handler sends a fault reply message back to the customer.
Figure 12.6 Faults and fault handlers
If a fault handler throws a fault itself, then this fault can be caught by the next higher enclosing scope. This applies to explicitly rethrown faults and to unexpected faults that occur during processing of the fault handler.
Not every scope has a fault handler specified for every possible type of fault. When a fault isn't caught by a fault handler, then a default fault handler applies. The default fault handler runs all available compensation handlers for immediately enclosed scopes in the reverse order of completion of the corresponding activities, and then rethrows the fault to the next enclosing scope.
The fault-handling concept in BPEL is similar to exception-handling in Java and other programming languages. However, business processes require additional error- handling steps. When intermediate results are made persistent, they must be reversed explicitly. Let's now take a closer look at such compensation steps.
In the previous section, we discussed fault handlers as a means to catch faults and respond to exceptional situations with appropriate business logic. As part of such logic, a common need is to undo activities that happened prior to the occurrence of the fault in order to correct the situation. For example, suppose a fault happens during the processing of a purchase order after stock has already been allocated in SkatesTown's local warehouse. When handling this fault, the allocation is to be reversed to reestablish a consistent state from which the processing of the purchase order can continue.
To do that, BPEL introduces the notion of compensation handlers that let you specify compensation logic to undo successfully completed activities in the case of a fault. The unit of compensation is, in its simplest form, one activity. It can also be a BPEL scope that forms a logical unit of work consisting of several activities and therefore needs to be compensated as such. A compensation handler specifically defines how to reverse the result of the particular unit it's associated with.
The following BPEL snippet specifies compensation logic for one particular activity of the PurchaseOrderProcess sample, the allocation of stock in SkatesTown's local warehouse. The checkAndAllocateLocalStock activity has an associated compensation handler that is implemented by another invoke activity. The deallocateLocalStock activity undoes what happened during the allocation of items for a purchase order:
During runtime processing, compensation handlers become active once the corresponding invoke activity or scope has completed successfully. In addition, a snapshot of the data accessible to the invoke activity or scope at that point in time is taken. This ensures that the compensation activity will ultimately have access to the same data that was current upon invocation of the original activity, so it can reverse what the original activity did. A compensation handler never becomes active, however, for an invoke activity or scope that terminated abnormally (for example, by means of a fault). If an invoke activity fails, BPEL presumes that no compensation is needed for the invoked service. In the case where a scope terminated abnormally, its fault handler must have taken care of compensating its nested activities already.
Having discussed how compensation handlers are defined and when they become active, the question remains how compensation handlers are triggered. If you don't specify a fault handler or compensation handler for your activity or scope, there will be a default implementation: As part of the default implementation for fault handlers and compensation handlers, all active compensation handlers of activities enclosed by that scope are triggered. The compensation handlers are called in the reverse order of the invocation of their respective activities.
BPEL also provides a special activity, the compensate activity, to explicitly trigger compensation handlers. This construct can only be used from within a fault handler or compensation handler. It's applicable to immediately enclosed invoke activities and scopes only. Using the scope attribute of the compensate activity, you select the unit to be compensated—that is, the name of the scope or invoke activity. Here's an example:
The specification of the scope attribute is optional. If the scope specification is omitted, all immediately enclosed activities are compensated:
In summary, through compensation handlers and compensate activities, compensation logic becomes part of the business logic of a process. Compensation is purely local to a single business process instance.