Introduction: WebSphere Process Server Version 6.0 and event handlers
IBM WebSphere® Process Server Version 6.0 includes a Web Services Business Process Execution Language (WS-BPEL) process engine known as Business Process Choreographer. It is the successor of the process engine in WebSphere Business Integration Server Foundation Version 5.1. Among other new features, Business Process Choreographer in Version 6 supports defining and executing event handlers in business processes. This article explains the concept of event handlers and offers several examples of how event handlers can be used to make WS-BPEL processes more dynamic. See Resources for code for the examples.
What is an Event Handler?
Event handlers have become widespread mainly because of the rise of the graphical user interface (GUI). Usually, GUI programs are structured in such a way that the program reacts to external events like the clicking of a mouse button or the dragging of a scrollbar. The custom code in these programs contains event handling methods such as
onClick(), and the infrastructure provides the event dispatching functionality that detects the external events and invokes the corresponding custom event handling methods.
Event handlers differ from other parts of software systems in that they deal with events that happen independent of, and asynchronously to, the execution of the program.
Such events can happen at the following times:
- at any time during the program's lifetime
- any number of times (i.e. 0,1,2,...n times)
In WebSphere Business Integration Server Foundation Version 5.1, Business Process Choreographer supports receive and pick activities as constructs within processes that react to external events. However, these activities are not capable of dealing with events that meet the above criteria. A receive or pick activity must be executed once and only once if a process is to be executed normally. Therefore, at the time you model the process, you must know how many incoming events are expected and at which time during the process execution they are expected if you want to use receive or pick activities.
WS-BPEL specifies another construct to deal with external events: the event handler. Like pick or receive activities, such event handlers can react to external events, and make them more dynamic.
External events in the context of business processes manifest themselves as one of the following:
- An invocation of an operation provided by a process: For example, a claims handling process supports the cancellation of a claim while the process is currently running. This may occur once or not at all. To do this, the client of the process invokes the cancellation operation that is implemented using an event handler.
- Expiration of a timeout: For example, a manager wants to be informed when a process takes longer than a week to be finished.
- Repeated expiration of timeout: For example, a manager wants to be informed when a process takes longer than a week to be finished. After the week is over, the manager wants to be informed each day until the process is finished.
How are event handlers specified in WS-BPEL?
WS-BPEL defines that event handlers can be associated to the whole process and to each scope within the process. A scope is a special activity in WS-BPEL that provides behavior context for the activity it contains. A scope can provide fault handlers, event handlers, a compensation handler, local variables, local partner links, and local correlation sets.
A definition of an event handler has two parts:
- Part 1 defines the conditions under which an event handler is to be invoked; that is, it defines the type of the event handler.
- Part 2 defines the actions the event handler has to take; in this part, the implementation of the event handler, its business logic, is defined.
We'll look at each part of the event handler definition:
Part 1: The conditions under which an event handler is to be invoked
WS-BPEL defines two types of event handlers, as follows:
onEventevent handler handles the occurrence of an external message event. This is the invocation of an operation.
onAlarmevent handler handles the expiration of a timeout.
Further, WS-BPEL defines the following two subtypes of
onAlarm event handler:
<for> | <until>deals with single timeout events.
(<for> | <until>)? <repeatsEvery>deals with repeated timeouts.
Part 2: What actions does the event handler have to take?
Within the body of an event handler you can specify any standard BPEL activity. Composite activities like flow or sequence are especially useful to specify the actions taken within the event handler. We'll see below that it is useful to define a scope as a direct child of an event handler in order to have scoped variables that are local to the event handler instance.
Runtime semantics of event handlers
Each event handler is enabled when the process or scope it is associated with starts. Each event handler is disabled when the process or scope it is associated with ends. Multiple instances of each event handler can be started as long as the event handler is enabled.
Event handlers are enabled when the scope they are associated with starts. Event handlers that are associated with the whole process are enabled as soon as the creating receive or pick activity has received its incoming message. (Note that WS-BPEL creates processes implicitly when a message arrives that is directed to a receive or pick activity with the
createInstance attribute set to
yes. In this article, such activities are called "creating receive or pick activities".) The rationale for this is that the event handler must be able to access the variable that holds the incoming message.
All event handlers associated with a scope are disabled when the normal processing of the scope is complete. If instances of event handlers are still running when a scope ends, then they are allowed to complete. The completion of the scope as a whole is delayed until all running event handlers have completed.
It is important to distinguish between enablement and dispatching. An event handler is said to be enabled once the associated scope starts.
onEvent event handler instance is said to be dispatched under the following conditions:
- the event handler is enabled, and
- the associated operation is invoked on the process
onAlarm event handler instance is dispatched under the following conditions:
- the event handler is enabled, and
- the specified timeout is reached
Relation with fault handling
Event handlers are considered a part of the normal processing of a scope. Faults within event handlers are treated like faults in the associated scope. If a fault occurs within a scope (or in an event handler associated with the scope) the fault handler disables all event handlers associated with the scope and then implicitly terminating all activities directly enclosed within the scope that are currently active. This includes the activities within currently active event handlers.
onAlarm events can occur concurrently and they are treated as concurrent activities. An event handler is permitted to have several simultaneously active instances. A private copy of all process data and control behavior defined within an event handler is provided to each instance of an event handler.
Points to ponder
WS-BPEL defines several restrictions that apply to event handlers. These restrictions must be considered carefully when an event handler is defined. Additionally, the increased concurrency introduced by event handlers can lead to new problems.
WS-BPEL mandates that multiple receive or pick activities with identical port type, operation, correlation set, and partner link must not be activated simultaneously, otherwise a
bpws:conflictingReceive standard fault must be thrown. This applies also to event handlers. That is, an event handler qualifies as receive activity with respect to this restriction. The rationale for this restriction is that if more than one receive activity within a process waits for the same port type, operation, correlation set, and partner link, then the process engine does not know to which receive activity an incoming message should be delivered.
Business Process Choreographer tightens this restriction further, since it cannot distinguish incoming messages based on correlation sets or partner links. Therefore, Business Process Choreographer mandates that within one process instance at most one receive or pick activity or event handler may be active with the same port type and operation.
Examples of this restriction include the following:
- If a receive or pick activity with a certain port type and operation is activated while another pick or receive activity with the same port type and operation is already waiting, a
bpws:conflictingReceivestandard fault is thrown.
- If an event handler with a certain port type and operation is enabled and then a receive or pick activity with the same port type and operation is activated, a
bpws:conflictingReceivestandard fault is thrown.
- If a receive or pick activity with a certain port type and operation is waiting and then an event handler with the same port type and operation is enabled, a
bpws:conflictingReceivestandard fault is thrown.
WS-BPEL imposes an additional restriction to request-response operations. Since a correlation set in WS-BPEL always identifies only a process instance, a client cannot use WS-BPEL means to distinguish between different replies that belong to the same port type, operation, correlation set and partner link. Therefore, WS-BPEL claims that only one request-response operation per process instance may be active at any given time for each port type, operation, correlation set, and partner link. Otherwise, a
bpws:conflictingRequest standard fault exception must be thrown. This restriction is different from the conflicting receive restriction, since a request-response operation is said to be active until the corresponding reply activity has been executed.
Analogous to the case of the
bpws:conflictingReceive fault above, Business Process Choreographer only allows one concurrently active request-response operation per process instance, port type, and operation. The effect of this is that if an event handler implements a request-response operation, then only one instance of such an event handler may be active at any point in time.
Concurrent access to variables
Access to variables from within event handlers is governed by WS-BPEL scoping rules. Let us illustrate this with an example, illustrated in Figure 1.
Figure 1. Variable visibility in WS-BPEL processes
Assume we have a process called
AProcess. The process contains the scope
MainScope, which has an associated event handler. The event handler contains a nested scope called
NestedScope. The following variables are defined:
- On process level, the variable
MainScope, the variable
- The event handler contains an implicitly created variable called
NestedScope, the variable
WS-BPEL defines the following access and visibility rules:
- The process level variable
VPis seen (that is, it can be accessed) by all activities of the whole process
- The variable
MainScopeis seen by all activities within
MainScopeand by all activities inside the event handler associated with
MainScopeand scopes nested inside the event handler
- The variable
VEHthat is defined implicitly in the event handler is seen by all activities inside the event handler and scopes nested inside the event handler. Please note that this variable cannot be accessed from activities within
- The variable
VNS, defined in
NestedScope, can only be seen by activities inside
At runtime, the variables
VM have only one instance per process instance. The variables
VNS have one instance for each event handler instance that is started.
Multiple instances of the event handler may be active, while variables
VM have only one instance. If an activity from within the event handler accesses variable
VM, then it has to share this variable with all other event handler instances that are active at the same time.
Since Business Process Choreographer executes activities within transactions, concurrent access to shared variables is governed by transactional isolation and concurrency control.
Improperly modeled event handlers may lead to deadlock situations or long wait times caused by locks. With Business Process Choreographer it is possible to control the scope of a transaction by setting the
transactionalBehavior attribute on specific activities. You can specify whether an activity participates in a transaction, requires a commit before or after the activity is executed, or requires its own transaction.
To reduce the effect of lock waits, it is useful to execute activities in event handlers that modify global variables in their own transactions.
A scope can be defined as being isolated. According to WS-BPEL, an isolated scope provides concurrency control in governing access to shared variables. An isolated scope extends the control of access to shared variables for situations where this access is distributed over more than one transaction.
The result of this is that if an event handler contains an isolated scope, and multiple instances of this event handler are started, then concurrent execution of these instances is severely constrained. Since this may contradict the whole idea of event handlers, you should use isolated scopes carefully within event handlers.
Please note that you need isolated scopes only if your scope reads a global variable in one transaction and updates the same global variable in another transaction. In most situations it is possible to avoid such a variable access pattern.
Use cases for event handlers
The straightforward usage of event handlers is the reaction to external events. WS-BPEL sketches three such examples, as follows:
- The first example is a car order process, where the explicit cancellation of an order is implemented by an
- The second example is an
onAlarmevent handler in the car order process. In this example, if the order process takes longer than a specific amount of time, an event handler is triggered, that can take specific actions. These actions are not given explicitly in the example.
- The third example deals with a travel booking process that manages travel reservations for a customer. Reservation updates are managed via an event handler; that is an
onEventevent handler is used to receive and handle the update messages from the travel booking system.
An additional example can be found on the Business Process Choreographer examples site. This example deals with a job offering process. Each process corresponds to an active job offering. The job offering is active for a specified period of time. While the job offering is active, the process can receive applications. If an application message arrives, the application is added to a list and a reply message is sent back. When the job offering has expired, the applications are sent to the manager and then the process ends. The expiration of the offering is implemented via an onAlarm event handler and the processing of a single application is implemented via an onEvent event handler. For details refer to the BPEL event handling document at the BPC examples Web site.
The Workflow Patterns Web site maintained by W. van der Aalst and others categorizes various workflow patterns. See the sections Advanced Branching and Synchronization Patterns as well as Patterns Involving Multiple Instances on this page for examples of patterns that can be implemented with the aid of event handlers.
The basic idea for implementing these patterns is to do the following:
- Define a process that executes a specific part of its business logic inside an event handler
- Within the process invoke this event handler multiple times and create in this way a dynamic number of parallel instances of this part of the business logic
A simple example
Let us illustrate this idea. In our example there is a review process where the author of a document starts the review process by specifying all persons who should review the document. There are several issues with this scenario: First, a review is a manual activity that takes a considerable amount of time. Also a reviewer doesn’t depend on the results of the other reviewers. Therefore, it would be beneficial to execute the reviews in parallel. Also, at modeling time, we do not know the number of reviewers required by the process.
A modeler is faced with a problem: he cannot use any native WS-BPEL activity to model this scenario. He could model parallelism using a flow activity, but a flow has the disadvantage that the number of branches must be known at modeling time. Alternatively, he could model the unknown number of branches using a loop activity, but the loop body is executed serially.
The event handler can help with this dilemma. The rough idea is that we model an event handler that triggers one review. In a loop, we start one instance of this event handler for each reviewer. This fulfills both major issues associated with the scenario: the reviews can happen in parallel, and we do not have to know at modeling time the number of reviewers that will be involved.
Figure 2 shows the WS-BPEL activities that constitute the reviewing process just described. To fully understand the discussion, get the workspace for this project from the BPC AdvancedEventHandlers project page and import it into WebSphere Integration Developer. There you can explore all the details, including the Java™ code in the Java Snippets, the data types for the various variables and the staff expression in the event handler. The discussion that follows gives an overview and explanation of the business logic of the process.
Figure 2. Main part of ReviewProcess
- The initial Receive activity creates the process. A document and a list of reviewers are input to the process where they are stored in the process’s input variable.
- The scope
MainScopecontains the logic that starts the various event handler instances for the individual reviews. The red flag shows that
Scope1is associated with an event handler.
InitializeVariablesJava snippet prepares the variables. The following variables are prepared:
numOfReviewers– We set this variable to the number of reviewers. The process uses it in the loop condition as the upper boundary.
activeReviews– We set this variable to the number of reviewers. If a review is finished, the event handler decrements this variable. Once it reaches zero, that instance of the event handler invokes the
ReceiveReviewFinishedNotificationoperation to notifiy
MainScopethat now all reviews are finished.
reviewStartRequest– This is the input variable for the
StartSingleReviewinvoke activity. This invoke activity calls the event handler. The variable contains an index that tells the event handler which reviewer it should use out of the list of reviewers in the process's input variable.
- result – This variable holds all review results in a list. To do so, this list needs to be initialized with empty objects.
- The process iterates WhileLoop once for each reviewer. It loops until the index in the event handler’s input message reaches the number of reviewers.
- The invoke activity invokes an event handler instance for a single review.
incrementIndexincreases the index by one.
ReceiveReviewFinishedNotificationreceive activity waits until the last running event handler instance sends a notification that indicates that all event handlers have been finished. Then navigation in
Although according to WS-BPEL
MainScopemust not be finished before all running event handler instances are finished, the process still needs this activity because event handler operations are request-only operations. Such operations are invoked asynchronously and there is no guarantee about the sequence of these invocations. Without this receive activity,
MainScopecould finish before an event handler has been started. To guarantee that the process executes all event handlers, this receive activity waits until the last active event handler instance sends a notification of completion.
- The review results are evaluated.
- A result message is returned.
Figure 3. Event handler in ReviewProcess
Figure 3 shows the WS-BPEL constructs that constitute the event handler. The following are the constructs, and what they contain:
onEventconstruct represents the event handler. Within this construct, a variable named myReviewStartRequest is implicitly defined; that variable is local to the event handler instance.
- The event handler contains a scope. This scope is required to define local variables so that each event handler instance uses its own data. Without local variables, all event handler instances would work on the same global variable instances. Only when the event handler has finished its business logic, it updates the global variable result in order to return the result to
SetupLocalVariablesJava snippet prepares the local variables that are needed inside the event handler. Most importantly, it sets up the
myDocumentForReviewvariable, which provides input to the
review_papermeans that humans perform the actual review. Execution of the staff assignment expression
%htm:input.\input/reviewer%determines the owner of the task. This expression uses the input message of the task activity.The general structure of this expression is %htm:input.[part]\<xpath-query>%. Please refer to Replacement expressions in descriptions and staff assignments for WebSphere Integration Developer Version 6.1 for reference information on this expression. In our case, we have a single part message, therefore "[part]" can be omitted and the expression reduces to
%htm:input.\<xpath-query>%. The Xpath-query navigates first to the input element of the message where it finds a data object of type
DocumentForReviewand extracts the reviewer property.
SetResultAndDecrementCountercopies the review result from the local variable
myReviewResultto the global variable results. This global variable holds a list of
ResultOfSingleReviewobjects. Also, the
activeReviewscounter is decreased. Since this activity modifies global variables, its transactional behavior attribute is set to the value
RequiresOwn. That is, this activity is executed in a separate transaction.
Choiceactivity only has one case statement – the
AllInstancesFinishedcase. This condition checks whether the
activeReviewsvariable has dropped to zero. If so, the current event handler instance is the last event handler instance, and the event handler invokes the waiting
ReceiveReviewFinishedNotificationreceive activity waiting in
Figure 4. Global variables of ReviewProcess
reviewCycleInput.Receives the input from the external request.
result.The array that contains the comments of all reviewers.
reviewStartRequest.Input variable to the event handler.
activeReviews.Counts the running event handlers.
numOfReviewers.Upper boundary for while loop.
reviewSuccces.Set to true if all reviewers accept the document.
reviewFinishedNotification.Input to ReceiveReviewFinishedNotification.
The local variables within the event handler are composed of the event handler’s input variable
myReviewStartRequest, which is shown in Figure 5, and the variables defined locally in the event handler’s scope, shown in Figure 6.
onEvent definition names the event handler’s input variable
myReviewStartRequest, as shown in Figure 5. This creates a variable that is local to the event handler instance. In Figure 6,
myDocumentForReview points to a local copy of the document for review while
myReviewResult points to a local result of that review.
Figure 6. OnEvent definition
Listings 1 and 2 display the code for the Java snippets
SetResultAndDecrementCounter that run inside the event handler.
Listing 1. Code of the Java snippet
BOCopy copyService = (BOCopy)ServiceManager.INSTANCE.locateService( "com/ibm/websphere/bo/BOCopy"); BOFactory factory = (BOFactory)ServiceManager.INSTANCE.locateService("com/ibm/websphere/bo/BOFactory"); // setup local variable myDocumentForReview so that it can be used as input for review_paper Type type = getVariableType("myDocumentForReview"); myDocumentForReview = factory.createByType(type); // get document from the process level global variable 'reviewCycleInput' DataObject doc = copyService.copy(reviewCycleInput.getDataObject("document")); myDocumentForReview.set("document",doc); // get index from onEvent input variable 'myReviewStartRequest' int i = myReviewStartRequest.getInt("index"); // get the ith user from the 'reviewers' List in 'reviewCycleInput' List reviewers = reviewCycleInput.getList("reviewers"); type = getVariableType("myReviewResult"); myReviewResult = factory.createByType(type); String user = (String) reviewers.get(i); // set the reviewer in the local variable 'myDocumentForRevies' myDocumentForReview.setString("reviewer", user );
Listing 2. Code of the Java snippet
// set the result of this review into the global 'result' variable List resultList = result.getList("results"); int index = myReviewStartRequest.getInt("index"); resultList.set(index,myReviewResult); // this review is done --> decrement the number of active reviews activeReviews = new Integer(activeReviews.intValue() -1 );
The example suggests the following general pattern for parallel processing of a dynamic number of instances:
Problem: Part of a process has to be executed multiple times in parallel, the number of which remains unknown until the process actually runs.
Solution: Define a process that contains a scope with an event handler associated. Place that part of the business logic that is to be processed in parallel inside that event handler.
Within the scope, the event handler is associated with do the following:
- Define a preparation activity that sets up the required variables. Especially, it sets up a global counter that counts the number of active event handlers as well as a variable that holds the results of the event handlers in a list.
- Define a loop that starts the required number of event handlers. Each event handler receives an index as input value.
- After the loop define a receive activity that waits until it is invoked by the last event handler.
Within the event handler, be sure to accomplish the following:
- Do the processing that is required by the business logic. Use the event handler’s index to select the input out of the global input list.
- If the global scope requires the result of the event handler, set the result in the global result variable. Use the event handler’s index to select the appropriate slot in the list of the result variable.
- Once that’s done, decrement the global counter that counts the number of active event handler instances.
- Finally, check whether the global counter reached zero, and if so, invoke the receive activity waiting in the main scope.
Variations from the pattern
The pattern described above can be modified in various ways. It can be used to implement several requirements, as follows
forEach. WS-BPEL 2.0 defines a
forEachconstruct. It allows specifying a parallel attribute. If parallel is set to no, then
forEachis similar to a loop. If parallel is set to
yes, BPEL executes n instances of the loop body in parallel. The
forEachconstruct is not supported in WebSphere Process Server Version 6.0. However, with the pattern described above, parallel
forEachsemantics can already be achieved in Version 6.
- M out of N. The parallel
forEachconstruct has an optional feature -- a
completionConditionthat can be used to terminate the
forEachconstruct before completing all parallel loop instances. As an example, let’s say an author specifies five reviewers, but it is sufficient that three of them review the document. As soon as three reviewers complete their work, the process terminates the whole
The pattern described above can be slightly modified to achieve that. First we have to modify the check for completion of all event handlers to reflect that it is sufficient if three event handlers have finished. Second, in this case it is not sufficient to invoke the waiting receive activity in the main scope, since the main scope will wait until all running event handlers have finished. In this case, instead of invoking the receive activity in the main scope, we have to raise a fault in the event handler. This fault will terminate the scope together with all running event handlers. In order to prevent the scope from propagating this fault to the surrounding scope or process, the main scope needs a fault handler that handles this fault. Fault handling in this context can be as easy as doing nothing -- simply the existence of the custom fault handler prevents the fault from being propagated to the enclosing scope or process. Note that the receive activity in the main scope is still needed to keep the scope alive even that it is not called explicitly in this scenario anymore.
- N parallel requests with deadline. A similar scenario deals with a situation where a specific deadline has to be met. As an example, let’s say the author specifies five reviewers; however the whole review process must not take longer than a specific amount of time. This can be modeled by using an
onAlarmevent handler in parallel to the
onEventevent handlers. The
onAlarmevent handler triggers once the deadline is reached. If the process executes the
onAlarmevent handler, it raises a fault that terminates the currently running
onEventevent handlers. If all
onEventevent handlers complete before the alarm is triggered, the last
onEventevent handler raises a fault to terminate the
onAlarmevent handler. Again, the main scope needs a fault handler in order to prevent the fault from being propagated to the surrounding scope or process.
- N services invoked in parallel. Another variation deals with the activities that are contained in the body of the event handler. In the example above, the event handler contained a human task. But it is perfectly valid to invoke any type of service in the event handler. That might be a Web service, a System Component Architecture (SCA) service, or as special case of the latter, a subprocess that is exposed as an SCA service. The service to be invoked might expose a one-way operation as well as a request-response operation.
- N parallel asynchronous replies from services. Let's say you want to invoke a certain number of one-way services that each invoke a one-way operation as call-back. This can be accomplished by modifying the loop of the example above so that the invoke activity invokes the external service immediately instead of invoking an event handler. You set up the event handler to accept the callback from the service. The rest of the logic remains unchanged -- that is, the main scope uses a receive activity to determine when the last event handler instance signals completion, and the event handler body decrements a counter. Once this counter reaches zero, it signals to the waiting receive activity in the main scope the completion of the last event handler.
Please note that it would not be possible to start multiple event handler instances that contain an invoke-receive sequence to deal with this scenario. If you use this approach a process could experience a situation where multiple receive activities wait for the same port type and operation. This would result in a
- Multiple instances with no a priori runtime knowledge. The patterns described by W. van der Aalst (see Resources) contain a pattern called "MI with no a priori runtime knowledge." In one of our previous examples, the number of instances became known at runtime before the instances were started. In van der Aalst's pattern, the actual number can only be determined after some instances start.
This pattern can be implemented using a slight variation of the general pattern above. Let’s assume that an instance of the event handler detects that an additional instance of the same event handler has to be started. This instance simply has to increment the counter variable and start a new event handler instance using an invoke activity. By doing so, the loop in the main scope and logic in the event handler controls the final number of event handler instances.
This article explains what event handlers are in WS-BPEL, how they are defined, which runtime semantics they have and which special considerations apply for Business Process Choreographer. We introduce a modeling pattern that enables a modeler to use event handlers to create processes with a variable number of parallel branches, the exact number of which is only determined at runtime. Finally, it discusses several modifications and use cases of this pattern.
- Visit the WebSphere Information Center to find documentation for various editions of the application server.
- WebSphere Business Process Management Version 6.0 information center has the information you need to install, maintain, and use IBM WebSphere Business Modeler, IBM WebSphere Integration Developer, IBM WebSphere Enterprise Service Bus, and IBM WebSphere Process Server for Multiplatforms.
- The IBM WebSphere development team maintains a set of Business Process Choreographer Samples.
Get products and technologies
- The workspace for the review process example described in this article and the associated Ear file can be found on the WebSphere Integration Developer 6.0.1 project download page for the BPC project AdvancedEventHandlers. The project code will be maintained on this page to accommodate changes to the code and keep it up to date.