A Hands-on Introduction to BPEL, Part 2: Advanced BPEL

Developer: J2EE & Web Services

by Matjaz B. Juric

Learn how to use BPEL to model complex business processes via these hands-on examples.

Downloads for this article:

Business Process Execution Language (BPEL) is ideal for definition and execution of business processes that can be relatively simple or very complex. In the first installment of this series, you learned how to develop a relatively simple business process. This article presents more-advanced concepts that will enable you to use BPEL to model complex processes.

You will become familiar with scopes that enable us you to divide a complex process into several parts, the example used here involves the development of a business process for buying books. The process is asynchronous and involves three Web services. The first, a book-rating Web service, returns a rating of 0 to 5 (best) for a specific book. This Web service is invoked synchronously. The process then queries two bookstores for the book price. For this step it invokes two identical bookstore Web services in asynchronously. Then the process selects the lower price and makes the book purchase (also asynchronously). Schematically, the business process looks like this:

To develop a BPEL process corresponding to the activity diagram, you first have to define the process Web Services Definition Language (WSDL), including the port types, operations, and messages. Because the BPEL process will be asynchronous, you need two port types: The BuyBookPT will serve for client requests, and the ClientCallbackPT will be used to enable the BPEL process to perform callbacks on the client. The BuyBookPT will have only one operation: BuyBook . The ClientCallbackPT will declare two operations: ClientCallback, for signaling successful competition, and ClientCallbackFault, for signaling faults to the client.

Part 1 explained how WSDL is declared, so the details aren't necessary here. The complete example with the WSDL is available in the support file; here is just a WSDL excerpt:

  ... <portType name="BuyBookPT"> <operation name="BuyBook"> <input message="bst:BookPurchaseMessage" /> </operation> </portType> <portType name="ClientCallbackPT"> <operation name="ClientCallback"> <input message="bst:BookResponseMessage" /> </operation> <operation name="ClientCallbackFault"> <input message="bst:FaultMessage" /> </operation> </portType> ... 

In WSDL you also have to declare partner link types. You need two roles:


  • The BuyBookService role, for the BPEL process
  • The BuyBookCustomer role, for BPEL process clients

The declaration follows:

  <plnk:partnerLinkType name="BuyBookLT"> <plnk:role name="BuyBookService"> <plnk:portType name="tns:BuyBookPT" /> </plnk:role> <plnk:role name="BuyBookCustomer"> <plnk:portType name="tns:ClientCallbackPT" /> </plnk:role> </plnk:partnerLinkType> 

Now you are ready to start writing the BPEL source code. The first installment covered this process, so you should already be familiar with the basics of BPEL.

  • The process declaration
  • Declaration of partner links
  • Declaration of variables
  • The process body, which corresponds to the activity diagram shown above.

First, let's address how to handle and signal faults in BPEL processes.

Fault Handling and Signaling

Business processes specified in BPEL will interact with partner processes through operation invocations on Web services. The communication between Web services is usually over internet connections that are not highly reliable. Web services can also raise faults due to logical and execution errors. Therefore, BPEL business processes need to handle faults appropriately and may also need to signal faults themselves.

Faults in BPEL can be from various sources:

  • A BPEL process can explicitly signal (throw) a fault.
  • A fault can occur when the BPEL process invokes a Web service operation. The operation might return a WSDL fault message, which results in a BPEL fault.
  • A fault can be thrown automatically by the BPEL runtime environment, either due to a certain condition in the BPEL process itself (such as a join failure), as a consequence of error conditions in the runtime environment, or related to network communication or other reasons. For such situations, BPEL defines several standard faults.

Signaling Faults

A business process sometimes needs to signal a fault explicitly. Therefore, BPEL provides the <throw> activity, which has the following syntax:

  <throw faultName=" name" /> 

BPEL does not require definition of fault names prior to their use in the <throw> activity. This flexible approach can be error-prone, because there is no compile-time checking of fault names. In the case of typos, misspelled faults will not be handled by the designated fault handler.

Faults can also have an associated variable that contains fault data. If such a variable is required, you have to specify it when throwing a fault, by using the optional faultVariable

  <throw faultName="name" faultVariable="variable-name" /> 

The following example shows the most straightforward use of the <throw> activity, where a CreditCardNotApproved fault is thrown. No variable is needed.

  <throw faultName="buy:CreditCardNotApproved" /> 

To modify our BPEL process to signal a fault, you first add the Fault variable to the variable declaration part of the BPEL process source:

  ... <!-- fault --> <variable name="Fault" messageType="bst:FaultMessage"/> </variables> 

Now you should modify the last part of the BPEL process. Instead of simply invoking a callback on the client after the book purchase, the process checks whether the credit card has actually been processed. If the credit card has been successfully processed, the process will invoke the client callback. Otherwise, it will first assign the fault reason to the Fault variable and then throw the fault:

  <!-- Check if the credit card is processed --> <switch> <case condition="bpws:getVariableData('BookResponseFinal', 'confirmation', '/bst:confirmation/bst:Approved')='true' "> <!-- Make a callback to the client --> <invoke partnerLink="Client" portType="buy:ClientCallbackPT" operation="ClientCallback" inputVariable="BookResponseFinal" /> </case> <otherwise> <sequence> <!-- Create the fault --> <assign> <copy> <from expression="string('Credit card not approved')" /> <to variable="Fault" part="error" /> </copy> </assign> <!-- Throw fault --> <throw faultName="buy:CreditCardNotApproved" faultVariable="Fault" /> </sequence> </otherwise> </switch> </sequence> </process> 

The faults raised with the <throw> activity have to be handled in the BPEL process. Faults that are not handled will not be automatically propagated to the client, as is the case in modern programming languages such as Java. Rather, the BPEL process will terminate abnormally.

Now let's examine how BPEL processes handle faults.

Handling Faults

When a fault occurs within a business process, the process may not complete successfully. (But it can complete successfully if the fault is handled within a scope, which enables you to divide a complex process into several parts; more on scopes later.) The business process can handle the fault through one or more fault handlers. Within a fault handler, the business process defines custom activities that should recover from the fault and possibly reverse the partial (unsuccessful) work of the activity where the fault has occurred.

The fault handlers are specified before the first activity of the BPEL process, after partner links and variables. The overall structure is shown in the following code excerpt:

  <process ...> <partnerLinks> ... </partnerLinks> <variables> ... </variables> <faultHandlers> <catch ... > <!-- Perform an activity --> </catch> <catch ... > <!-- Perform an activity --> </catch> ... <catchAll> <!-- catchAll is optional --> <!-- Perform an activity --> </catchAll> </faultHandlers> <sequence> ... </sequence> </process> 

Within the fault handlers, you specify several <catch> activities where you indicate which fault you want to catch and handle. Within a fault handler, you must specify at least one <catch> or<catchAll>. The <catchAll> activity can be specified only once within a fault handler.

Usually you specify several<catch> activities where you will handle specific faults and use <catchAll> to handle all other faults. To specify which fault you would like to handle, you must specify at least one of the following:

  • faultName, which specifies the name of the fault to handle
  • faultVariable, which specifies the variable type used for fault data
  The flexibility of<catch> activities is high, and all the following variations are permissible: <faultHandlers> <catch faultName="buy:CreditCardNotApproved" > <!-- First fault handler --> </catch> <catch faultName="buy:CreditCardNotApproved" faultVariable="Fault" > <!-- Second fault handler --> </catch> <catch faultVariable="Fault" > <!-- Third fault handler --> </catch> <catchAll> <!-- Fourth fault handler --> </catchAll> </faultHandlers> Fault handlers in BPEL are similar to try/catch clauses in modern programming languages such as Java 

Selection of a Fault Handler

  Let's consider the fault handlers discussed in the previous section and determine which <catch>activity will be selected by the process for which scenario: 
  • The first <catch> will be selected if the fault buy:CreditCardNotApproved has been thrown and the fault carries no fault data.
  • The second <catch> will be selected if the fault buy:CreditCardNotApproved has been thrown and carries the data whose type matches the type of variable Fault.
  • The third <catch> will be selected if a fault has been thrown whose fault variable type matches the Fault variable type and whose name is not buy:CreditCardNotApproved.
  In all other cases, <catchAll> will be selected. You can see that the selection of the <catch> activity within fault handlers is quite complicated. It is even possible for a fault to match several <catch> activities. Therefore, BPEL specifies exact rules for selecting the fault handler ( <catch>) that will process a fault: 

In the case of faults without associated fault data, the fault name will be matched. The <catch> activity with a matching faultNamewill be selected if present; otherwise, the default <catchAll> handler will be used if present.

In the case of faults with associated fault data, a <catch> activity specifying a matching faultName value and a faultVariablewhose type matches the type of the fault data will be selected if present. Otherwise, a <catch> activity with no specified faultNameand with a matching faultVariable will be selected if present. Otherwise, the default <catchAll> handler will be used if present (<catchAll> will execute only if no other <catch> activity has been selected).

  If no <catch> is selected and <catchAll> is not present, the process will terminate abnormally. This situation is similar to explicitly terminating the process by using the <terminate> activity. Next you add a fault handler section to our example, using two <catch> blocks. In the first, you handle the CreditCardNotApproved fault with the corresponding Fault variable. The second is the<catchAll>, where you handle all other faults. For simplicity, you should signal all faults to the client. In real-world processes, you could do other things to recover from a fault, such as invoking an alternative Web service. Shown below is the fault handler section: <faultHandlers> <catch faultName="buy:CreditCardNotApproved" faultVariable="Fault"> <!-- Make a callback to the client --> <invoke partnerLink="Client" portType="buy:ClientCallbackPT" operation="ClientCallbackFault" inputVariable="Fault" /> </catch> <catchAll> <sequence> <!-- Create the Fault variable --> <assign> <copy> <from expression="string('Other fault')" /> <to variable="Fault" part="error" /> </copy> </assign> <invoke partnerLink="Client" portType="buy:ClientCallbackPT" operation="ClientCallbackFault" inputVariable="Fault" /> </sequence> </catchAll> </faultHandlers> To start the example, you first have to deploy the example, using the obant utility: 

  Next you use the BPEL Console in Oracle BPEL Process Manager to invoke the process: 

  If the credit card is not processed, you can see that a fault is thrown that is handled in the fault handler and returned to the client: 

  In complex BPEL processes, many faults can occur. Handling them in a single <faultHandlers> section can become quite complex. It would be useful if you could specify more than one <faultHandlers>section in a BPEL process. Particularly incomplex processes, it would be great if you could specify different fault handler sections for different parts of the process. This is possible with scopes. 

Scopes

  Scopes are hierarchically organized parts into which a complex business process can be divided. They provide behavioral contexts for activities. In other words, scopes enable you to define different fault handlers for different activities (or sets of activities gathered under a common structured activity such as <sequence> or <flow>). In addition to defining fault handlers, you can declare variables that are visible only within a scope. Scopes also let you define local correlation sets, compensation handlers, and event handlers. (I discuss these topics in my book Business Process Execution Language for Web Services, from Packt Publishing.) The following code excerpt shows how scopes are defined in BPEL. You can specify <variables>, <correlationSets>, <faultHandlers>, <compensationHandlers>, and <eventHandlers> locally for scopes: <scope> <variables> <!-- Variables definitions local to scope --> </variables> <correlationSets> <!-- Correlation sets will be discussed in a later article --> </correlationSets> <faultHandlers> <!-- Fault handlers local to scope --> </faultHandlers> <compensationHandler> <!-- Compensation handlers will be discussed in a later article --> </compensationHandler> <eventHandlers> <!-- Event handlers will be discussed later in this article --> </eventHandlers> activity </scope> Each scope has a primary activity, much like the overall process structure, in which a BPEL process also has a primary activity. The primary activity, often a <sequence> or a <flow>, defines the behavior of a scope for normal execution. Fault handlers and other handlers define the behavior for abnormal execution scenarios. The primary activity of a scope can be a basic activity such as <invoke<, or it can be a structured activity such as <sequence> or <flow>. If the primary activity of a scope is a structured activity, it can have many nested activities, in which the nesting depth is arbitrary. The scope is shared by all the nested activities. A scope can also have nested scopes with arbitrary depth.The variables defined within a scope are visible only within that scope. Fault handlers attached to a scope handle faults of all the nested activities of the scope. Faults not caught in a scope are rethrown to the enclosing scope. Scopes in which faults have occurred are considered to have ended abnormally even if a fault handler has caught the fault and not rethrown it. To add scopes to our example, you create three scopes: 
  • 1. For retrieving the book rating
  • 2. For selecting the best book price and buying the book
  • 3. For checking whether the credit card has been processed and making the callback to the client
  In each scope, you add the fault handler section and declare those variables that are used only locally in the scope. This makes the BPEL code more readable. Because scopes are relatively easy to understand, this article shows only the first scope, called RetrieveBookRating: <scope name="RetrieveBookRating"> <variables> <!-- input for the Book Rating Web service --> <variable name="BookRatingRequest" messageType="bkr:BookRatingRequestMessage"/> <!-- output from the Book Rating Web service --> <variable name="BookRatingResponse" messageType="bkr:BookRatingResponseMessage"/> </variables> <faultHandlers> <catchAll> <sequence> <assign> <copy> <from expression="string('Unable to retrieve book rating')" /> <to variable="Fault" part="error" /> </copy> </assign> <invoke partnerLink="Client" portType="buy:ClientCallbackPT" operation="ClientCallbackFault" inputVariable="Fault" /> </sequence> </catchAll> </faultHandlers> <sequence> <!-- Prepare the input for the Book Rating --> <assign> <copy> <from variable="BookPurchase" part="book"/> <to variable="BookRatingRequest" part="book"/> </copy> </assign> <!-- Synchronously invoke the Book Rating Web Service --> <invoke partnerLink="BookRating" portType="bkr:BookRatingPT" operation="BookRating" inputVariable="BookRatingRequest" outputVariable="BookRatingResponse" /> <!-- Prepare the input for Bookstores --> <assign> <copy> <from variable="BookPurchase" part="book"/> <to variable="BookRequest" part="book"/> </copy> <copy> <from variable="BookPurchase" part="quantity"/> <to variable="BookRequest" part="quantity"/> </copy> </assign> </sequence> </scope> You can see the other two scopes in the source code of the example. If you start the example with scopes, you can see how activities are gathered into scopes in the visual flow: 

Inline Fault Handling

  In BPEL processes, invocation of operations on Web services can be particularly error-prone. There are numerous situations-such as broken connections, unavailability of Web services, or changes in the Web services WSDL-that can prevent a BPEL process from successfully invoking a partner Web service operation. Such faults can be handled in the <faultHandlers> section of the corresponding scope. In our example, you create a scope for the invocation of the book-rating Web service and handle the possible faults: <scope name="BookRatingInvoke"> <faultHandlers> <catchAll> <!-- If book rating is not available assign 0 --> <assign> <copy> <from expression="number(0)"/> <to variable="BookRatingResponse" part="rating"/> </copy> </assign> </catchAll> </faultHandlers> <invoke partnerLink="BookRating" portType="bkr:BookRatingPT" operation="BookRating" inputVariable="BookRatingRequest" outputVariable="BookRatingResponse" /> </scope> Defining a scope requires a lot of typing, however, so the<invoke>activity provides a shortcut: inline fault handlers. The syntax for inlining fault handlers in the <invoke> activity is equivalent to the syntax of the <faultHandlers>section. As shown in the following code excerpt, you can specify zero or more <catch> activities and can also specify a <catchAll< handler. The difference in the <faultHandlers> section is that for inline <catch< activities, you have to specify the fault name. Optionally, you can specify the fault variable: <invoke ... > <catch faultName=" fault-name" > <!-- Perform an activity --> </catch> ... <catch faultName=" fault-name" faultVariable=" fault-variable" > <!-- Perform an activity --> </catch> ... <catchAll> <!-- Perform an activity --> </catchAll> </invoke> The following code excerpt shows an inline fault handler for invoking the book-rating Web service. If a fault occurs when this Web service is invoked, you create a book rating of 0 in the <catchAll< fault handler: <!-- Synchronously invoke the Book Rating Web Service --> <invoke partnerLink="BookRating" portType="bkr:BookRatingPT" operation="BookRating" inputVariable="BookRatingRequest" outputVariable="BookRatingResponse" > <catchAll> <!-- If book rating is not available assign 0 --> <assign> <copy> <from expression="number(0)"/> <to variable="BookRatingResponse" part="rating"/> </copy> </assign> </catchAll> </invoke> Unfortunately, the current version of Oracle BPEL Process Manager does not support inline fault handlers. Until support becomes available, you have to use scopes. 

Event Management

  Although fault handlers and scopes improve the robustness of BPEL processes considerably, you can also manage events. BPEL supports two types of events: 
  • 1. Message events are triggered by incoming messages through operation invocation on port types.
  • 2. Alarm events are time-related and are triggered either after a certain duration or at a specific time.
  Managing message events is particularly important when the business process is waiting for callbacks from partner Web services. The previous examples have used the <receive> activity, which lets you wait for only a single (exactly specified) message on a port type. Often, however, it is more useful to wait for more than one message, of which only one will occur. In our example, after invoking the BookPriceQuery operation, you have used <receive> to wait for BookPurchaseCallback. In a real-world scenario, it would be very useful to wait for several messages, BookPurchaseCallback being one of them. The other messages could include BookNotAvailable, OutOfStock, and the like. Alarm events are useful when you want the process to wait for a callback for a certain period of time, such as 15 minutes. If no callback is received, the process flow continues as designed. This approach is particularly useful in loosely coupled service-oriented architectures, where you cannot rely on Web services being available all the time. This way, the process flow can proceed even if one of the bookstores does not return an offer. 

Pick Activity

BPEL provides the <pick> activity, through which you can specify that the business process should await the occurrence of one event in a set of events. Events can be message events handled with the <onMessage> activity or alarm events handled with the <onAlarm> activity. For each event, you specify an activity or a set of activities that should be performed.

The syntax of the <pick> activity looks like this:

  <pick> <onMessage partnerLink=" name" portType=" name" operation=" name" variable=" name"> <!-- Perform an activity or a set of activities enclosed by <sequence>, <flow>, etc. or throw a fault --> </onMessage> <onMessage ...> <!-- Perform an activity --> </onMessage> ... <onAlarm ...> <!-- Perform an activity --> </onAlarm> ... </pick> 
  Within <pick> you can specify several <onMessage> elements and several <onAlarm> elements. The<onAlarm> elements are optional (you can specify zero or more), but you have to specify at least one<onMessage> element. 

The <onMessage> element is identical to the <receive> activity and has the same set of attributes. You must specify the following attributes:

partnerLink: Specifies which partner link will be used for the invoke, receive, or reply, respectively

portType: Specifies the used port type

operation: Specifies the name of the operation whose invocation to wait for

variable: Specifies the variable name used to store the incoming message

  Using the <onAlarm> element, you can specify a 

Duration expression, using a for attribute

Deadline expression, using an until attribute

Most often you use the <onAlarm> event to specify duration. A typical example is for a business process to wait for the callback for a certain amount of time, such as 15 minutes. If no callback is received, the business process invokes another operation or throws a fault. The deadline approach is useful, for example, if the business process should wait for a callback until a specified time and then throw a fault or perform a backup activity.

To specify deadline and duration expressions, BPEL uses lexical representations of corresponding XML Schema datatypes. For deadlines these datatypes are dateTime or date, and for duration you use the duration datatype. The lexical representation of expressions should conform to that of XPath 1.0 expressions (or expressions in any other selected query language). The evaluation of such expressions should result in values that are of corresponding XML Schema types: dateTime and date for deadline and duration for duration expressions.

Examples of deadline expressions are shown in the following code excerpts:

  '2004-03-18T21:00:00+01:00' '18:05:30Z' To specify a duration of 1 month, 3 days, 4 hours, and 10 minutes, you use the following duration expression: 'P1M3DT4H10M'" The following expression specifies a duration of 1 year, 11 months, 14 days, 4 hours, 10 minutes, and 30 seconds: 'P1Y11M14DT4H10M30S' Returning to our example-to the part where you invoke the BookPurchase operation-replace the <receive> activity with the <pick> activity. You will handle four message events- BookPurchaseCallback, BookNotAvailable, OutOfStock, and InvalidCreditCard-and an alarm event for which you use a duration expression of 15 minutes: <pick> <onMessage partnerLink="BookStore1" portType="bst:BookPurchaseCallbackPT" operation="BookPurchaseCallback" variable="BookResponseFinal" > <empty/> </onMessage> <onMessage partnerLink="BookStore1" portType="bst:BookPurchaseCallbackPT" operation="BookNotAvailable" variable="Fault" > <!-- Here we could recover or simply throw the fault --> <throw faultName="buy:BookNotAvailable" faultVariable="Fault" /> </onMessage> <onMessage partnerLink="BookStore1" portType="bst:BookPurchaseCallbackPT" operation="OutOfStock" variable="Fault" > <!-- Here we could recover or simply throw the fault --> <throw faultName="buy:OutOfStock" faultVariable="Fault" /> </onMessage> <onMessage partnerLink="BookStore1" portType="bst:BookPurchaseCallbackPT" operation="InvalidCreditCard" variable="Fault" > <!-- Here we could recover or simply throw the fault --> <throw faultName="buy:InvalidCreditCard" faultVariable="Fault" /> </onMessage> <onAlarm for="'PT15M'"> <throw faultName="buy:Timeout" faultVariable="Fault" /> </onAlarm> </pick> 

In a similar fashion, you can replace the other <receive> activities where you wait for a Web service callback. The screen shot below shows the visual execution flow of the pick example:

Using Pick as the Initial Activity

You can use the <pick> activity instead of the initial <receive> activity. You can specify several operations, and receiving one of these messages will result in the creation of a business process instance. Then you have to use a special form of the <pick> activity. You specify the createInstance attribute for the <pick> activity, but you can specify only <onMessage> events; <onAlarm> events are not permitted in this specific form.

To understand the use of this special form of the <pick> activity, consider the bookstore Web service, implemented as a simple BPEL process. This Web service accepts the following operations: BookPriceQuery, BookPurchase, and CancelBookPurchase:

  <sequence> <!-- Receive the initial request --> <pick createInstance="yes"> <onMessage partnerLink="BookStore" portType="bst:BookPurchasePT" operation="BookPriceQuery" variable="BookQuery"> ... </onMessage> <onMessage partnerLink="BookStore" portType="bst:BookPurchasePT" operation="BookPurchase" variable="BookDetails"> ... </onMessage> <onMessage partnerLink="BookStore" portType="bst:BookPurchasePT" operation="CancelBookPurchase" variable="BookDetails"> ... </onMessage> </pick> ... 

Event Handlers

The <pick> activity is very useful when you have to specify that the business process should wait for events. Sometimes, however, you want to react to events that occur while the business process executes. In other words, you do not want the business process to wait for the event (and do nothing else but wait). Instead, the process should execute while listening to events and handling them whenever they occur.

For this purpose, BPEL provides event handlers. If the corresponding events occur, event handlers are invoked concurrently with the business process. A typical usage of event handlers is to handle a cancellation message from a client. For example, in our travel process, you could define an event handler that would allow the BPEL process client to cancel the travel anytime.

You can specify event handlers for the whole BPEL process as well as for each scope. Event handlers are specified immediately after the compensation handlers and before the main activity, as shown below:

  <process ...> <partnerLinks> ... </partnerLinks> <variables> ... </variables> <faultHandlers> ... </faultHandlers> <compensationHandler> ... </compensationHandler> <eventHandlers> <onMessage ...> <!-- Perform an activity --> </onMessage> ... <onAlarm ...> <!-- Perform an activity --> </onAlarm> ... </eventHandlers> activity </process> 

The syntax of the event handler section is similar to the syntax of the <pick> activity. The only difference is that within the event handler, you can specify zero or more <onMessage> events and/or zero or more <onAlarm> events.

Message events in event handlers can occur multiple times, even concurrently, while the corresponding scope is active.

Returning to the example, you can define the event handler that allows the BPEL process client to cancel the book purchase anytime. The difficult part here is to define the appropriate activities to be performed when the client does the cancellation. The simplest solution is to terminate the process. Besides the message event handler, add an alarm event handler that generates a timeout after 15 minutes. The code excerpt is shown in the following example:

  <process ... > ... <eventHandlers> <onMessage partnerLink="Client" portType="buy:BuyBookPT" operation="CancelBuy" variable="BookPurchase"> <terminate/> </onMessage> <onAlarm for="'PT15M'"> <throw faultName="buy:Timeout" faultVariable="Fault" /> </onAlarm> </eventHandlers> 

Using this event handler, you can remove the <onAlarm> section from the <pick> activities, because timeouts are now handled centrally. In real-world situations, you could use variable data instead of hard-coding to specify the duration.

Event handlers can also be defined in scopes. The event handlers associated with the scopes are enabled when the associated scope starts, and the event handlers associated with the global BPEL process are enabled as soon as the process instance is created.

Conclusion

This article has covered more-advanced BPEL concepts. You have seen how to handle faults and events from BPEL processes, which makes the processes more robust and thus more useful in real-world scenarios. You have also learned how to divide complex processes into several scopes.

The next, and final, installment examines how to invoke resources other than Web services from BPEL processes, using Web Services Invocation Framework (WSIF).

Matjaz B. Juric holds a Ph.D. in computer and information science. He is the author of the bookBusiness Process Execution Language for Web Services (Packt Publishing). Juric is also the coauthor ofProfessional J2EE EAI, Professional EJB, J2EE Design Patterns Applied, and VB.NET Serialization Handbook, all published by Wrox Press, and has contributed to Java Developer's Journal, Java Report,Java World, and other publications.