Section 5.3. BPEL in a Nutshell


5.3. BPEL in a Nutshell

The following sections examine the essential language constructs designers will need to understand to create a BPEL process: the basic process structure, variables and assignments, exception handling and compensation, split and join, loops, participant exchange, transactions, and extensions.

5.3.1. Basic Process Structure: Start, End, Activities, Sequence

A developer's first BPEL process is not easy to write. Two puzzles face the beginner:

  • A BPEL process has exactly one activity (which, of course, can consist of any number of subactivities to any level of hierarchy). Which activity should that be? Which are allowed? Which are disallowed? Which are recommended?

  • How is the initial inbound event handler set up? Where do you place the receive or pick in the activity described in the first problem?

The simplest approach, and the one recommended to most developers, is to use a sequence whose first activity is a receive with createInstance="yes", as in the following code example :

     <sequence>        <receive . . . createInstance="yes" . . .> . . . </receive>        <!-- other activities -->     </sequence> 

This process starts when the receive TRiggers, then executes the remaining steps sequentially, and exits when the last activity has completed. Error handling complicates the processing, of course; see the section "Exception Handling and Compensation" for a discussion.

Another approach is to use a receive within a flow. The receive should not have any inbound links. For example:

     <flow>        <receive . . . createInstance="yes" . . .> . . . </receive>        <!-- other activities -->     </flow> 

This process starts when the receive triggers, whereupon the remaining activities in the flow run in parallel, or, if links are used, in a directed-graph style of execution. (See the section "Split and Join" later in this chapter for more on flow.) The process finishes when the flow has merged all its activities.

In the advanced category, the BPEL specification includes an example (Section 16.3 of the BPEL 1.1 specification) with two receive nodes in a flow. The intent is not to choose one or the other events (as with a pick), but to require both in order to proceed with the remainder of the process. Both nodes compete to start the process, but because they are in a flow, when one wins, it must wait for the other to trigger and join it in the process. As the following code example shows, the flow is enclosed in a sequence, so when the flow completes, the other activities in the process run sequentially, and when they complete, the process exits normally:

     <sequence>        <flow>           <receive . . . createInstance="yes" . . .>              <correlations>. . .</correlations> <!-- corr required for multi-start -->           </receive>           <receive . . . createInstance="yes" . . .>              <correlations>. . .</correlations> <!-- corr required for multi-start -->           </receive>        </flow>        <!-- other activities -->     </sequence> 

Here are some novelties to avoid at all costs:

  • Do not put basic activities (e.g., assign, empty, or wait) before the initial receive or pick.

  • Do not use switch or while as the main activity of the process.

  • Do not use a scope as the main activity of the process. The process has everything that a scope hashandlers, variables, correlation sets..

5.3.2. Variables and Assignments

Most processes need to maintain application data during the course of their execution. The data is initialized when the process begins and is subsequently read and modified. A BPEL process can define a set of variables, pass them to web service touchpoints as input or output parameters, and assign all or part of one variable to another.

Formally, a process variable has a name that is unique for its scope and a type that is either a WSDL message type or an XML Schema element or basic type. A variable is set in one of the following ways:

  • Bound to the input of an inbound activity, such as a receive, pick, or eventHandler.

  • Bound to the output of a synchronous invoke.

  • Assigned a value with the assign activity

The assign activity is defined as a copy of data from a source to a target. The source can be a literal value, an expression, the value of the whole or part of another process variable, or part of a process variable. Table 5-2 shows an example for each type.

Table 5-2. Assignment examples

Usage

Code

From literal

     <variable name="x" type="xsd:int"/>     <assign>        <copy>           <from>1</from>           <to variable="x"/>        </copy>     </assign> 

From expression

     <variable name="x" type="xsd:int"/>     <assign>        <copy>           <from            expression="bpws:getVariableData('x') + 1"/>           <to variable="x"/>        </copy>     </assign> 

Whole copy

     <variable name="x" type="xsd:int"/>     <variable name="y" type="xsd:int"/>     <assign>        <copy>           <from variable="y"/>           <to variable="x"/>        </copy>     </assign> 

Partial copy

     In WSDL:     <message name="person">        <part name="name" type="xsd:string"/>        <part name="address" type="xsd:string"/>     </message>     In BPEL process:     <variable name="person" messageType="person"/>     <variable name="personAddress" type="xsd:string"/>     <assign>        <copy>           <from variable="person" part="address"/>           <to variable="personAddress"/>        </copy>     </assign> 


The built-in BPEL function bpws:getVariableData is used to get the value of a variable. For an XSD element type, the function can use an XPath expression to extract a particular data token from the XML document. For a WSDL message type, the function can extract values from any part of the message.

In addition, see the section "The Life Event process" in Chapter 11 for an example of assigning dynamic endpoint information to a partner link.

5.3.3. Exception Handling and Compensation

A scope is a process code block having its own set of activities and corresponding variables; correlation sets; and handlers for fault, compensation, and events. A scope is a localized execution context: its variables are visible only within its boundaries, and its handlers apply only to its activity flow. Scopes are hierarchical; a scope can have multiple nested subscopes, each of which can in turn have additional subscopes, and so on down the chain; a process is itself a top-level scope.

5.3.3.1 Compensation handler

Compensation is a transaction that reverses the effects of a previously completed transaction. In many online transactional applications, updates to one or more systems are made within a local or distributed transaction, and are not finalized until the transaction is committed; to negate the updates, the application simply rolls back the transaction. However, business processes often run for such long periods of time that keeping open transactions for the duration is infeasible. If an earlier step needs to be negated, rather than rolling back its transaction, the process executes its compensation handler. The following code example shows a handler that invokes a rescind web service, presumably informing its partner to cancel some activity. The rescind is intended to reverse the update service invocation in the main flow of the scope block.

     <scope name="s">        <compensationHandler>           <invoke operation="rescind" . . . />        </compensationHandler>        <invoke operation="update" . . ./>     </scope> 

The compensation handler for a scope is invoked, using the compensate activity, from the fault handler or compensation handler of the parent scope. In the following case, the compensation handler for scope inner is called from the compensation handler of its parent scope outer. The operations update and addToStatement are compensated by rescind and removeFromStatement:

     <scope name="outer">        <compensationHandler>           <sequence>              <invoke operation="rescind" . . . />              <compensate scope="s2"/>           </sequence>        </compensationHandler>        <sequence>           <invoke operation="update" . . ./>           <scope name="inner">              <compensationHandler>                 <invoke operation="removeFromStatement" . . ./>              </compensationHandler>              <invoke operation="addToStatement" . . ./>              . . .           </scope>        </sequence>     </scope> 

5.3.3.2 Fault handler

Compensation is the reversal of a completed scope, and fault handling is the processing of a break in a scope that is in-flight. When a fault is generated, either implicitly by the BPEL engine or explicitly by a throw activity, control jumps to the fault handler defined for the given fault type.[5] The fault handler is a set of catch structures, resembling the following:

[5] If no such handler is defined, the fault is propagated to the parent scope. If the parent has no suitable handler, the fault is propagated to the parent's parent, and so on, until the topmost scope levelthat is, the process levelis reached. If the fault is not handled at the process level, the process is terminated.

     <scope name="s1">        <faultHandlers>           <catch faultName="x:invalidAccount">              . . .           </catch>           <catch faultName="x:closedAccount">              . . .           </catch>           <catchAll">              . . .           </catchAll>        </faultHandlers>     </scope> 

BPEL faults are uniquely identified by name. Some are standard error types documented in the BPEL specification, such as uninitializedVariable, which is thrown by the engine when code tries to read the value of an uninitialized part of a variable. Others are application-specific, such as x:invalidAccount and x:closeAccount, which are used in the code example to represent illegitimate accesses of an account. Catch handlers are defined for both of these faults, and the catchall structure handles any faults not accounted for in the other catch structures. Each handler lists the activities to be performed to handle the fault. The handler can swallow the fault, leading to the resumption of processing in the scope, or it can rethrow the fault or throw a different fault, thereby propagating the fault to the parent scope.

The throw activity generates a fault, causing control to be passed to the fault handler defined for the given scope. In the following code example:

     <switch name="routeRequest">        <case name="checking". . .> . . . </case>        <case name="savings". . .>           <switch name="CheckAcctStatus">              <case name="Open" . . .> . . . </case>              <case name="Closed" . . .> <throw faultName="closedAccount"> </case>           </switch>        </case>        <case name="trust". . .> . . . </case>        <otherwise><throw faultName="invalidAccount"/></otherwise>     </switch> 

the terminate activity is used to immediately abort the process, skipping any defined fault handling:

     <terminate name="Unrecoverable condition met"> 

5.3.3.3 Event handler

An event handler enables the scope to react to events, or to the expiration of timers, at any point during the scope's execution. Two obvious uses are:


Cancellation

The scope defines a handler for a cancellation event. If it receives it, the scope can be terminated, no matter where it is in its execution.


Escalation

A timer is set on the scope. If it expires, special activities are executed to perform "business escalation."

The next code example demonstrates these uses. Cancellation is triggered by the message defined by partner link Customer, port type controller and operation cancel; the handler throws a fault to terminate the scope. Escalation occurs after two days (PT2D), at which point the handler performs logic through an invoke.

     <scope name="s1">        <eventHandlers>           <onMessage partnerLink="Customer" portType="controller"              operation="cancel" variable="cancelEvent">              <correlations>                 <correlation set="controllerSet" initiate="no"/>              </correlations>              <throw faultName="x:cancelled"/>           </onMessage>           <onAlarm until="PT2D">              <invoke name="escalation" . . ./>           </onAlarm>        </eventHandlers>     </scope> 

5.3.4. Split and Join

BPEL's two activities for split and join switch and flowexhibit contrasting styles. switch is a traditional programmatic control structure for conditional logic. flow is an unusual graph structure with support for parallel activities connected by guarded links.

5.3.3.4 switch

switch is an exclusive-OR structured activity that consists of one or more case structures, each having a conditional expression and an associated activity. The activity performed by the switch is that of the first case whose condition evaluates to true. An optional otherwise clause can be defined with an activity but no condition; that activity is run only if none of the preceding cases have a true condition.

In the following example, a flow activity is performed if the first condition (variable i has value 1) holds; a sequence with an assign and switch is executed if the second condition (i = 2) is true. An invoke is run by default:

     <switch>        <case condition="bpws:getVariableData('i')=1">           <flow> . . . </flow>        </case>        <case condition="bpws:getVariableData('i')=2">           <sequence>              <assign . . . />              <switch> . . . </switch>           </sequence>        </case>        <otherwise>           <invoke . . ./>        </otherwise>     </switch> 

5.3.3.5 flow

The flow activityBPEL's most interesting, unusual, and pedantic constructmodels parallel activity execution and activity synchronization. Depending on how it is configured, flow exhibits a variety of behaviors; to understand flow, it is best to learn each casethe parallel split and join behavior, link synchronization and dependencies behaviors, and dead path elimination behaviorusing an example and a diagram.

5.3.3.5.1 Parallel split and join

The first case for flow is perfectly suited to the P4 patterns for parallel split and join. In the following example (see Figure 5-4 and the following code), the process invokes in parallel (i.e., splits) web services for partner links A, B, and C respectively; the order of execution is unpredictable. The flow waits for each contained activity to complete (i.e., joins them) before exiting. The invocation of the service for partner link D does not occur until each of the three previous invocation finishes.

Figure 5-4. BPEL flow parallel split and join


     <flow>        <invoke partnerLink="A" . . ./>        <invoke partnerLink="B" . . ./>        <invoke partnerLink="C" . . ./>     </flow>     <invoke partnerLink="D" . . ./> 

5.3.3.5.2 Links and synchronization dependencies

The BPEL flow mechanism offers several features to model the situation where one activity cannot start until one or more activities on which it depends complete. Specifically, a flow can define a set of links, each originating from a source activity in the flow and terminating at a target activity in the flow. An activity can be the source as well as the target of multiple links. In Figure 5-5, for example, A has links to B and C, X has links to B and C, B has a link to D, and C has a link to E.

Figure 5-5. BPEL synchronization


Understanding flow in BPEL requires understanding the order in which such activities are executed, and whether a particular activity is executed at all.

In the current example, initially X and A are run in parallel. Activities B and C must wait for both X and A to complete because, according to BPEL's flow rules, an activity must wait for each of its incoming links. To complicate matters, a source activity can define a transition condition on any of its outgoing links (if not defined for a given link, the condition defaults to true), and a target activity can define a join condition evaluated based on the transition conditions each of its incoming links. The join condition is optional; if not defined, it defaults to an OR condition, which is true if any of the link transition conditions is true. The target activity executes only if its join condition evaluates to true. (The behavior when the join condition is false is examined in the next section.)

Continuing with the example, C does not define a join condition, and hence defaults to OR. That is, C executes if either X or A (or both) has a true transition condition on its link. Note that C must wait for both source activities to complete, even though it requires only one to send out a true link. Activity B defines an explicit join condition, requiring both of its incoming links, from X and A, to be true; B executes only if both X and A have a true transition condition. The link from A to B has an explicit transition condition (it is "guarded"), whereas the link from X to B is implicitly true. As for activities D and E: D waits for B to complete, and E waits for C.

The BPEL encoding of this scenario is as follows:

     <flow>        <links>           <link name="AB"/>           <link name="AC"/>           <link name="XB"/>           <link name="XC"/>           <link name="BD"/>           <link name="CE"/>        </links>        <invoke partnerLink="A". . .>           <source linkName="AB" transitionCondition=". . ."/>           <source linkName="AC"/>        </invoke>        <invoke partnerLink="X". . .>           <source linkName="XB" />           <source linkName="XC" />        </invoke>        <invoke partnerLink="B". . .         joinCondition="bpws:getLinkStatus('XB') and bpws:getLinkStatus('AB')">           <source linkName="BD" />           <target linkName="AB" />           <target linkName="XB" />        </invoke>        <invoke partnerLink="C" . . ./>           <source linkName="CE" />           <target linkName="AC" />           <target linkName="XC" />        </invoke>        <invoke partnerLink="D" . . .>           <target linkName="BD"/>        </invoke>        <invoke partnerLink="E" . . .>           <target linkName="CE"/>        </invoke>     </flow> 

A link can cross activity boundaries. In Figure 5-6, activity S2 is the second activity in the sequence of S1-S2-S3, but it is also the target of a link from activity X. According to BPEL's flow rules, S2 cannot execute until both S1 and X have executed. The overall order of execution is S1-X-S2-S3 or X-S1-S2-S3.

Figure 5-6. BPEL cross-boundary link


5.3.3.5.3 Dead path elimination

By default, if an activity's join condition evaluates to false, BPEL generates a fault called bpws:joinFailure; the activity is not executed, and control is diverted to a fault handler. In the first of the examples presented in the previous section, B's join condition fails if either X or A sends a false link to B.

BPEL also supports the semantics of dead path elimination: if the join condition of an activity is false, the activity doesn't execute but completes immediately and sends false on each of its outgoing links. For example, if B's join condition fails, and dead path elimination is enforced, B doesn't execute, and its outgoing link to D is set of false, which, because D's implicit join condition requires the link from B to be true, in turn prevents D's execution. In this case, the execution sequence is either X-A-C-E or A-X-C-E.

Deciding whether to use dead path elimination semantics is as simple as setting a flag. The attribute suppressJoinFailure can be set to yes or no (default is no) for any activity. If set to "yes", that activity uses dead path elimination semantics; otherwise, it uses the semantics of join fault. In the following code example, the flag is enabled for the entire flow, which means that B, a part of that flow, will use dead path elimination if its join condition is false.

     <flow suppressJoinFailure="yes">        <links>           <link name="AB"/>           <link name="AC"/>           <link name="XB"/>           <link name="XC"/>           <link name="BD"/>           <link name="CE"/>        </links>        <invoke partnerLink="A". . .>           <source linkName="AB" transitionCondition=". . ."/>           <source linkName="AC"/>        </invoke>        <invoke partnerLink="X". . .>           <source linkName="XB" />           <source linkName="XC" />        </invoke>        <invoke partnerLink="B". . .         joinCondition="bpws:getLinkStatus('XB') and bpws:getLinkStatus('AB')">           <source linkName="BD" />           <target linkName="AB" />           <target linkName="XB" />        </invoke>        <invoke partnerLink="C" . . ./>           <source linkName="CE" />           <target linkName="AC" />           <target linkName="XC" />        </invoke>        <invoke partnerLink="D" . . .>           <target linkName="BD"/>        </invoke>        <invoke partnerLink="E" . . .>           <target linkName="CE"/>        </invoke>     </flow> 

The semantics of dead path elimination are discussed further in Chapter 3.

5.3.5. Loops

BPEL 's sole looping construct is the while activity. Unlike BPML, BPEL does not offer a foreach loop, but an example of how to iterate through a repeating XML element, a typical use of foreach, is provided in this section.

5.3.5.1 while

The while activity executes a child activity in a loop and evaluates the continuation condition before each iteration. The child activity is executed if the condition is true; otherwise, the loop exits.

In the following example, the loop iterates over a counter variable i. The integer variable is initially set to 0 and is incremented by 1 at the end of each loop iteration. The loop runs until i is 5, executing as part of a sequence an invoke activity and the assign to increment i:

     <variable name="i" type="xsd:integer"/>     <assign>        <copy>           <from expression="0"/>           <to variable="i"/>        </copy>     </assign>     . . .     <while condition="bpws:getVariableData(i) != 5">        <sequence>           <invoke . . . />           <assign>              <copy>                 <from expression="bpws:getVariableData(i) + 1"/>                 <to variable=";"i"/>              </copy>           <assign>        </sequence>     </while> 

5.3.5.2 Implementing foreach

Iterating over a set of XML data in BPEL is a comparatively difficult development chore, thanks to BPEL's omission of, or decision not to include, a foreach loop. The following example shows how iterate over all instances of the input element described by the following schema:

     <element name="ForLoopRequest">        <complexType>           <sequence>              <element name="input" type="string" maxOccurs="5" />           </sequence>        </complexType>     </element> 

Here is an XML document based on this schema:

     <ForLoopRequest>        <input>Foreach</input>        <input> is</input>        <input> possible</input>        <input> after all</input>     </ForEachRequest> 

Example 5-2 is an excerpt of a BPEL process that iterates over the repeating elements of such a document.

Example 5-2. Iterating BPEL process
 1    <!-- input is a ForLoopRequest. 2              numItems is a count of the "input" elements in the input message 3              currItem is a loop counter that starts at 0 and increases by 1 to numItems 4              theItem is used in the loop to store the value in the currItem position 5              tempExpr is a string used to build XPath in the loop --> 6        <variables> 7           <variable name="input" messageType="tns:ForLoopRequestMessage"/> 8           <variable name="numItems" type="xsd:int"/> 9           <variable name="currItem" type="xsd:int"/> 10           <variable name="theItem" type="xsd:string"/> 11           <variable name="trace" type="xsd:string"/> 12           <variable name="tempExpr" type="xsd:string"/> 13        </variables> 14        . . . 15        <!-- Initialize currItem to 0 and use XPath count(  ) function to get the number of 16           "input" elements. --> 17      <assign name="getNumItems"> 18         <copy> 19            <from expression="bpws:getVariableData(&quot;input&quot;,&quot;payload&quot;, 20               &quot;count(/tns:ForLoopRequest/tns:input)&quot;)"></from> 21            <to variable="numItems"/> 22         </copy> 23         <copy> 24            <from expression="number(0)"></from> 25            <to variable="currItem"/> 26         </copy> 27      </assign> 28      . . . 29      <!-- the while loop, ironically named "foreach" 30           It runs until currItem = numItems --> 31      <while name="foreach" 32         condition="bpws:getVariableData('currItem') &lt; 33         bpws:getVariableData('numItems')"> 34         <sequence> 35            <assign name="doForEach"> 36               <!-- Increment currItem. Need this for loop condition, as well 37                    as XPath index --> 38               <copy> 39                  <from expression="bpws:getVariableData(&quot;currItem&quot;) 40                     + 1"></from> 41                  <to variable="currItem"/> 42               </copy> 43               <!-- The Xpath expression is of the form: 44                    "/tns:ForLoopRequest/tns:input[currItem]" (index is 1-based) 45                    Build it and store in tempExpr. --> 46               <copy> 47                  <from expression="concat(&quot;/tns:ForLoopRequest/tns:input[&quot;, 48                     bpws:getVariableData(&quot;currItem&quot;), &quot;]&quot;)"></from> 49                  <to variable="tempExpr"/> 50               </copy> 51               <!- - Evaluate the expresion and store in "theItem" --> 52               <copy> 53                  <from expression="bpws:getVariableData(&quot;input&quot;, 54                    &quot;payload&quot;,bpws:getVariableData(&quot;tempExpr&quot;))"> 55                  </from> 56                  <to variable="theItem"/> 57               </copy> 58            </assign> 59            <!-- Now, do something with "theItem" --> 60         </sequence> 61      </while> 

Intuitively, this code performs the following logic:

     numItems = count(/ForLoopRequest/input)     for currItem = 1 to numItems        theItem = /ForLoopRequest/input[currItem] 

Table 5-5 maps this intuitive code to the corresponding section in the thorny BPEL code.

Table 5-3. ForEach logic

Intended code

Actual code

numItems = count(/ForLoopRequest/input)

Assign rule, lines 19-20.

For currItem = 1 to numItems

First, currItem is assigned to 0, lines 24-25. The while condition appears in lines 32-33. currItem is incremented in lines 39-41.

theItem = /ForLoopRequest/input[currItem]

Two assign copies in lines 46-57.


5.3.6. Participant Exchange

One of BPEL's strongest notions is that processes communicate with each other as business partners. The partnering relationships are represented declaratively in the definition of process links, as well as in the actual communication touch points of the process flow.

5.3.6.1 Partner link types

To begin with, in the WSDL, partner link types map web service port types to partner roles. More formally, a partner link type has a name and one or two roles, each of which has a name and a reference by name to a port type. A partner link type with two roles represents a relationship in which partners, such as a buyer and seller, exchange service calls:

     <partnerLinkType name="BuyerSeller">        <role name="buyer"> <portType name="buyerPT"/> </role>        <role name="seller"> <portType name="sellerPT"/> </role>     </partnerLinkType> 

A partner link type with one role is suitable for interactions where the service does not need to know about its callers:

     <partnerLinkType name="Server">        <role name="server"> <portType name="serverPT"/> </role>     </partnerLinkType> 

5.3.6.2 Partner links

In the BPEL process definition, partner links declare which partner link type roles defined in the WSDL are performed by the process and which are performed by partners. For example, a buyer process defines the link BuyerSellerLink, referencing the type BuyerSeller, with myRole set to buyer and partnerRole to seller:

     <partnerLink name="BuyerSellerLink" partnerLinkType="BuyerSeller"        myRole="buyer" partnerRole="seller"/> 

If the process invokes the server service, it declares a partner link called ServerLink with partnerRole set to server:

     <partnerLink name="ServerLink" partnerLinkType="Server" partnerRole="server"/> 

NOTE

In most BPEL examples, a partner link is mapped statically to a particular service endpoint. See Chapter 11 (the section "The Life Event process") for an example of a dynamic partner link, whose endpoint information is determined at runtime.

5.3.6.3 Partners

BPEL also offers a construct known as a business partner, which has a name and a set of partner links. For example, a given process participant that is both a seller and a shipper can be defined as SellerShipper:

     <partner name="SellerShipper">        <partnerLink name="Seller"/>        <partnerLink name-"Shipper"/>     </partner> 

5.3.6.4 Partner interactions

BPEL process flow contains the activities receive, reply, invoke, and pick, which implement the actual interpartner communication . receive and pick represent links implemented by the process and called by partners (e.g., the buyer). reply and invoke represent partner services called by this process (e.g., the seller, the server).

Table 5-4 describes the possible types of partner interactions . The pronoun my is used to distinguish a process from its partners.

Table 5-4. Partner communication patterns

Pattern

Partner roles

Description

Async receive

MyRole = receiveWS

A partner calls my web service, which triggers logic in my process. The partner resumes control immediately.

Sync receive-reply

MyRole = receive WS PartnerRole = reply WS

A partner calls my web service, which triggers logic in my process. My process eventually sends back a response to the partner. The partner blocks for the duration; to the partner, the entire interaction is a single two-way web service invocation.

Async receive-invoke

MyRole = receive WS PartnerRole = invoke WS

A partner calls my web service, which triggers logic in my process; the partner resumes control immediately. My process eventually calls the partner's callback web service through an invoke.

Sync invoke

PartnerRole = invoke WS

My process calls the partner's web service with an invoke. The two-way web service returns a result.

Async invoke

PartnerRole = invoke WS

My process calls the partner's web service with an invoke. The "one-way" web service does not return a result.

Async invoke-receive

MyRole = receive WS PartnerRole = invoke WS

My process calls the partner's web service with an invoke. The web service later calls back by triggering my receive.


As Figure 5-7 shows, each interaction, considered from the perspective of the current process, has a corresponding partner interaction. A partner async invoke is an async receive for my process, whereas a partner sync invoke is a sync receive-reply for my process. A partner async invoke-receive is asymmetrically an async receive-invoke for my process.

Figure 5-7. Partner interactions


The four partner interaction activities are discussed in the following sections.

5.3.6.4.1 invoke

The invoke activity calls a partner web service either synchronously or asynchronously. The web service is identified by partner link type and WSDL port type and operation. A synchronous web service requires both input and output variables to be passed in; an asynchronous service requires only an input variable. In case the service generates a fault, the invoke activity can define one or more fault handlers, and it can also specify a compensation handler.

The following example shows a call to a synchronous web service:

     <invoke partnerLink="myPartner"  portType="service" operation="syncRequest"      inputVariable="request" outputVariable="response"/> 

5.3.6.4.2 receive

Whereas invoke lets a process call a partner's web service's operation, receive is a web service operation implemented by the process for use by partners. The idea, as was discussed previously, is that partners trigger the execution of a process by calling its services; for the process, the service is an event that set it in action.

Like invoke, receive uses partner link type and WSDL port type and operation to identify the service. The arguments passed in by the caller are bound to a specified variable. The following code example implements the initialRequest service, whose input is bound to the request variable. The createInstance attribute indicates that when this service is called, a new instance of the process is launched:

     <receive partnerLink="myPartner" portType="service" operation="initialRequest"      variable="request" createInstance="yes" /> 

The next example shows the secondRequest service, which does not create a new instance but listens for an event in an existing instance:

     <receive partnerLink="myPartner" portType="service" operation="secondRequest"      variable="request" createInstance="no" /> 

5.3.6.4.3 reply

The reply activity sends back a response synchronously to an earlier receive. The effect is that of a single web service call in which the receive accepts the input, and the reply passees back the output; the process can perform arbitrary processing logic in between. As the following code sample shows, the reply matches the partnerLink, portType, and operation attributes of the receive; the output is specified in the variable attribute

     <reply partnerLink="client" portType="c:AccountOpenPT" operation="submitApplication"      variable="request" />     <!-- do stuff in between -->     <reply partnerLink="client" portType="c:AccountOpenPT" operation="submitApplication"      variable="confirmationNumber " /> 

5.3.6.4.4 pick

pick waits for one of several events to occur, then executes the activity associated with that event. Like receive, pick has a createInstance attribute that determines whether to start a new process instance when the event occurs. pick also has an optional timer (onAlarm) that executes a specified activity if none of the specified events occurs within a given duration or until a given deadline. The list of candidate events is a set of onMessage elements; the event is defined as a web service operation for a given port type and partner link, similar to the receive event definition earlier.

In the following example, the pick triggers a new process instance when it gets events ev1 or ev2. In each case, it executes some sequence of activities. The onAlarm condition fires if neither event occurs in 3 days and 10 hours. (The XPath 1.0 syntax is P3DT10H.)

     <pick createInstance="yes">        <onMessage partnerLink="pl" portType="pt" operation="ev1"         variable="v">           <sequence>. . .</sequence>        </onMessage>        <onMessage partnerLink="pl" portType="pt" operation="ev2"         variable="v">           <sequence>. . .</sequence>        </onMessage>        <onAlarm for="P3DT10H">           <sequence> . . . </sequence>        </onAlaram>     </pick> 

5.3.6.5 Properties

A standard WSDL extension allows for the definition of message properties, which can be thought of as macros to access parts of WSDL messages. The definition of a message property has two parts: a property, which has a name and a WSDL message or XML schema type; and a property alias , which stipulates from which WSDL message and part the property comes. The property alias includes an XPath expression that extracts data to be represented by the property from the WSDL message. In the following code example, the property nameProp represents the name of a person message type:

     <property name="nameProp" type="xsd:string"/>     <propertyAlias propertyName="nameProp" messageType="person" part="name"        query="/personalData/name"/> 

5.3.6.6 Correlation

The main use of properties in BPEL is message correlation , a large topic in its own right, as will be apparent shortly. The definition of a process can specify any number of correlation sets , each of which has a name and a list of message properties . In the following code sample, the correlation set USPersonCorrSet includes properties nameProp and SSNProp:

     <correlationSets>        <correlationSet name="USPersonCorrSet" properties="nameProp SSNProp"/>     </correlationSets> 

The purpose of the correlation set is to tie together a partner conversation. A fundamental principal of BPEL is that instances of partner processes communicate with each other simply by calling each other's web services, passing application data whose structure is transparent to the BPEL engine. In BPEL, partners do not address each other by ID, but rather pass around messages containing key fields that can be correlated for the lifetime of the exchange.

The protocol governing a correlation set, from the perspective of one of the participating processes, is as follows:

  • The first step in the conversation is the initiating step. This step is normally a receive or an invoke. The correlation set is populated with values based on the initiating message. In the case of a receive, the values come from the inbound message. For an invoke, the values are those sent to the partner, those received back (if the invocation is synchronous), or both.

  • Each subsequent step matches the data in the set with the initialized data. A receive is triggered only if the data in the message matches the correlation set. An invoke or reply must send out data that agrees with the data in the set.

The following example illustrates the protocol. Assuming that the conversation in question is the opening of an account, the first step is a receive that, as the code shows, initiates the USPersonCorrSet set with contents of the variable request. The attribute initiate is set to Yes, indicating that this step is the first in the conversation. The createInstance attribute is also set to Yes, indicating that this step is the first in the process. If it is set to No, this activity can still begin a conversation because a process can have multiple conversations; of course, a fundamental rule of BPEL is that every process begins with the initiation of a new conversation.

        variable="request" createInstance="Yes">        <correlations>           <correlation set="USPersonCorrSet" initiate="Yes"/>        </correlations>     </receive> 

The conversation is continued with the following asynchronous invoke. The initiate attribute is set to No. BPEL requires that the data sent match the correlation set of the previous set.

     <invoke partnerLink="l" portType="pt" operation="approveAccount"        inputVariable="request" >        <correlations>           <correlation set="USPersonCorrSet" initiate="No" pattern="out"/>        </correlations>     </invoke> 

The final step in the conversation is a receive that retrieves the asynchronous response to the previous invoke. BPEL triggers this activity only if the data in the message matches the correlation set.

     <receive partnerLink="l" portType="pt" operation="accountApproval"        variable="accountApproval" >        <correlations>           <correlation set="USPersonCorrSet" initiate="No"/>        </correlations>     </receive> 

Based on this information, it is clear that any implementation of a BPEL engine requires a router component that, upon receipt of a message from a web service invocation, triggers the process instance that correlates the message. The engine is depicted in Figure 5-8. Different name/SSN combinations are routed to different process instances; process A, not yet initiated, is started by the message with name=Pete and SSN=112; subsequent messages matching those criteria are routed to process A.

Figure 5-8. BPEL correlation routing


5.3.7. Transactions

Several factors make transactions hard to manage in a business process. First, a process that is long-running cannot run in a single ACID transaction; instead, it must necessarily divide its function into a number of smaller transactions. Second, the specification of standards for distributing transactions across multiple partner web services and processes is a work in progress. BPEL 1.1 anticipates, but does not support, distributed transaction coordination protocols such as WS-Transaction. Consequently, if a partner invokes a BPEL process, or a BPEL process invokes a partner, the BPEL process cannot, using a standard protocol, work together with the partner in the event of an error to reverse the effects of the interaction. The best that can be achieved is for the partners to agree on particular cancellation operations.

BPEL's strategy for the first problem is compensation (described earlier in the section "Exception Handling and Compensation"), which provides a structured and application-directed way to reverse the effects of the smaller activities that have already completed. This happens strictly locally; the second problem remains an open issue. The BPEL specification uses the term Long Running Transaction (LRT) to refer to the use of a hierarchical nesting of scoped compensation handlers to unwind previously committed work in a controlled fashion. An LRT is not a specific language feature but rather a way to describe the use of compensation to undo work performed over potentially a long period of time.

BPEL developers beware: the LRT strategy helps guide the effort, but the actual design and coding of compensation logic is still a difficult chore. The hard work is application-specific!

5.3.8. Extensions

Core BPEL is extended by adding attributes or elements, qualified by namespace, to BPEL elements that support extensibility. An important new BPEL extension, called BPELJ, is discussed in the next section.



    Essential Business Process Modeling
    Essential Business Process Modeling
    ISBN: 0596008430
    EAN: 2147483647
    Year: 2003
    Pages: 122
    Authors: Michael Havey

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net