Skip Headers
Oracle® Fusion Middleware Developer's Guide for Oracle SOA Suite
11g Release 1 (11.1.1.6.3)

Part Number E10224-15
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
PDF · Mobi · ePub

10 Using Parallel Flow in a BPEL Process

This chapter describes how to use parallel flow in a BPEL process service component. Parallel flows enable a BPEL process service component to perform multiple tasks at the same time. Parallel flow is especially useful when you must perform several time-consuming and independent tasks. This chapter also describes how to customize the number of parallel branches.

This chapter includes the following sections:

For additional information on creating parallel flows in a SOA composite application, see the Fusion Order Demo application, which is described in Chapter 3, "Introduction to the SOA Sample Application."

10.1 Introduction to Parallel Flows in BPEL Processes

A BPEL process service component must sometimes gather information from multiple asynchronous sources. Because each callback can take an undefined amount of time (hours or days), it may take too long to call each service one at a time. By breaking the calls into a parallel flow, a BPEL process service component can invoke multiple web services at the same time, and receive the responses as they come in. This method is much more time efficient.

Figure 10-1 shows the Retrieve_QuotesFromSuppliers flow activity of the Fusion Order Demo application. The Retrieve_QuotesFromSuppliers flow activity sends order information to two suppliers in parallel:

The two warehouses return their bids for the order to the flow activity. Here, two asynchronous callbacks execute in parallel. One callback does not have to wait for the other to complete first. Each response is stored in a different global variable.

Figure 10-1 Parallel Flow Invocation

Description of Figure 10-1 follows
Description of "Figure 10-1 Parallel Flow Invocation"

10.1.1 What You May Need to Know About the Execution of Parallel Flow Branches in a Single Thread

Branches in flow, flowN, and forEach activities are executed serially in a single thread (that is, the Nth branch is executed only after N-1 execution has completed). Execution is not completely parallel. This is because the branches do not execute in concurrent threads in this mode. Instead, one thread starts executing a flow branch until it reaches a blocking activity (for example, an synchronous invoke). At this point, a new thread is created that starts executing the other branch, and the process continues. This creates the impression that the flow branches are executing in parallel. In this mode, however, if the flow branches do not define a blocking activity, the branches still execute serially.

This design is intended for several reasons:

  • To prevent you from accidentally spawning too many threads and overloading the system, single threading is the default method. However, you can tune threads in other places, such as adapter polling threads, BPEL process invoke/service engine threads, and Oracle WebLogic Server work managers.

  • The BPEL process specification does not provide a mechanism to ensure the thread safety of BPEL variables (that is, a lack of a synchronized qualifier such as in Java), which is necessary for true multithreaded programming.

  • The implication of transaction rollbacks in one of the branches is undefined.

To achieve pseudo-parallelism, you can configure invoke activities to be nonblocking with the nonBlockingInvoke deployment descriptor property. When this property is set to true, the process manager creates a new thread to perform each branch's invoke activity in parallel.

For more information about the nonBlockingInvoke property, see Section C.1.1, "How to Define Deployment Descriptor Properties in the Property Inspector" and Section "nonBlockingInvoke" of Oracle Fusion Middleware Performance and Tuning Guide.

10.2 Creating a Parallel Flow

You can create a parallel flow in a BPEL process service component with the flow activity. The flow activity enables you to specify one or more activities to be performed concurrently. The flow activity also provides synchronization. The flow activity completes when all activities in the flow have finished processing. Completion of this activity includes the possibility that it can be skipped if its enabling condition is false.

Note:

Branches in a flow activity are executed serially in a single thread. For more information, see Section 10.1.1, "What You May Need to Know About the Execution of Parallel Flow Branches in a Single Thread."

10.2.1 How to Create a Parallel Flow

To create a parallel flow:

  1. In the Component Palette, expand BPEL Constructs.

  2. Drag a Flow activity into the designer.

  3. Click the + sign to expand the flow activity, as shown in Figure 10-2.

    Figure 10-2 Flow Activity

    Description of Figure 10-2 follows
    Description of "Figure 10-2 Flow Activity"

    The flow activity initially includes two branches, each with a box for functional elements. Populate these boxes as you do a scope activity, either by building a function or dragging activities into the boxes. You can add additional branches by highlighting the flow activity and clicking the Add Sequence icon.

  4. Drag and define additional activities onto each side of the flow to invoke multiple services at the same time. Figure 10-3 provides details.

    Figure 10-3 Expanded Flow Activity

    Description of Figure 10-3 follows
    Description of "Figure 10-3 Expanded Flow Activity"

    When complete, flow activity design can look as shown in Figure 10-4. This example shows the Retrieve_QuotesFromSuppliers flow activity of the Fusion Order Demo application. Two branches are defined for receiving bids: one for InternalWarehouseService and the other for PartnerSupplierMediator.

    Figure 10-4 Flow Activity After Design Completion

    Description of Figure 10-4 follows
    Description of "Figure 10-4 Flow Activity After Design Completion"

10.2.2 What Happens When You Create a Parallel Flow

A flow activity typically contains many sequence activities. Each sequence is performed in parallel. Example 10-1 shows the syntax for two sequences of the Retrieve_QuotesFromSuppliers flow activity in the OrderProcessor.bpel file after design completion. However, a flow activity can have many sequences. A flow activity can also contain other activities. In Example 10-1, each sequence in the flow contains assign, invoke, and receive activities.

Example 10-1 Flow Activity

<flow name="Retrieve_QuotesFromSuppliers">
    <sequence name="Sequence_4">
        <assign name="Assign_InternalWarehouseRequest">
            <copy>
                <from variable="gOrderInfoVariable"
                    query="/ns4:orderInfoVOSDO/ns4:OrderId"/>
                <to variable="lInternalWarehouseInputVariable"
                    part="payload"
                    query="/ns1:WarehouseRequest/ns1:orderId"/>
            </copy>
        </assign>
        <invoke name="Invoke_InternalWarehouse"
            inputVariable="lInternalWarehouseInputVariable"
            partnerLink="InternalWarehouseService"
            portType="ns1:InternalWarehouseService"
            operation="process"/>
        <receive name="Receive_InternalWarehouse"
            createInstance="no"
            variable="lInternalWarehouseResponseVariable"
            partnerLink="InternalWarehouseService"
            portType="ns1:InternalWarehouseServiceCallback"
            operation="processResponse"/>
        <assign name="Assign_InterWHResponse">
            <bpelx:append>
                <bpelx:from variable="lInternalWarehouseResponseVariable"
                       part="payload"
                       query="/ns1:WarehouseResponse"/>
                <bpelx:to variable="gWarehouseQuotes"
                       query="/ns1:WarehouseList"/>
            </bpelx:append>
        </assign>
    </sequence>
    <sequence name="Sequence_4">
        <assign name="Assign_PartnerRequest">
            <copy>
                <from variable="gOrderInfoVariable"
                    query="/ns4:orderInfoVOSDO"/>
                <to variable="lPartnerSupplierInputVariable"
                    part="request" query="/ns4:orderInfoVOSDO"/>
            </copy>
        </assign>
        <invoke name="Invoke_PartnerSupplier"
            partnerLink="PartnerSupplierMediator"
            portType="ns15:execute_ptt" operation="execute"
            inputVariable="lPartnerSupplierInputVariable"/>
        <receive name="Receive_PartnerResponse"
            createInstance="no"
            variable="lPartnerResponseVariable"
            partnerLink="PartnerSupplierMediator"
            portType="ns15:callback_ptt" operation="callback"/>
            <assign name="Assign_PartnerWHResponse">
                <bpelx:append>
                    <bpelx:from variable="lPartnerResponseVariable"
                           part="callback"
                           query="/ns1:WarehouseResponse"/>
                           <bpelx:to variable="gWarehouseQuotes"
                           query="/ns1:WarehouseList"/>
                    </bpelx:append>
            </assign>
    </sequence>
</flow>

10.2.3 Synchronizing the Execution of Activities in a Flow Activity

You can synchronize the execution of activities within a flow activity to ensure that certain activities only execute after other activities have completed. For example, assume you have an invoke activity, verifyFlight, that is executed in parallel with other invoke activities (verifyHotel, verifyCarRental, and scheduleFlight) when the flow activity begins. However, scheduling a flight is necessary only after verifying that a flight is available. Therefore, you can add a link between the verifyFlight and scheduleFlight invoke activities. Links provide a level of dependency indicating that the activity that is the target of the link (scheduleFlight) is only executed if the activity that is the source of the link (verifyFlight) has completed.

Example 10-2 provides details. The link name verifyFlight-To-scheduleFlight is assigned to the source verifyFlight and target scheduleFlight invoke activities. If the source verifyFlight completes execution, the target scheduleFlight is then executed.

Example 10-2 Link Between Source and Target Activities

<flow ...>
   <links>
      <link name="verifyFlight-To-scheduleFlight" />
   </links>
   <documentation>
      Verify the availability of a flight, hotel, and rental car in parallel
   </documentation>
   <invoke name="verifyFlight" ...>
      <sources>
         <source linkName="verifyFlight-To-scheduleFlight" />
      </sources>
   </invoke>
   <invoke name="verifyHotel" ... />
   <invoke name="verifyCarRental" ... />
   <invoke name="scheduleFlight" ...>
      <targets>
         <target linkName="verifyFlight-To-scheduleFlight" />
      </targets>
   </invoke>
</flow>

Example 10-2 provides an example of link syntax in BPEL version 2.0. The link syntax between BPEL version 1.1 and BPEL version 2.0 is slightly different.

  • BPEL version 1.1 uses <target> and <source>.

  • BPEL version 2.0 uses <targets> and <sources>.

Table 10-1 provides details.

Table 10-1 Links Syntax in BPEL Version 1.1 and BPEL Version 2.0

BPEL Version 1.1 Example BPEL Version 2.0 Example
<flow>
   <links>
     <link name="XtoY"/>
     <link name="CtoD"/>
   </links>
   <sequence name="X">
      <source linkName="XtoY"/>
      <invoke name="A" .../>
      <invoke name="B" .../>
   </sequence>
   <sequence name"Y">
      <target linkName="XtoY"/>
      <receive name="C" ...>
         <source linkName="CtoD"/>
      </receive>
      <invoke name="E" .../>
   </sequence>
   <invoke partnerLink="D" ...>
     <target linkName="CtoD"/>
   </invoke>
 </flow>
<flow>
      <links>
        <link name="AtoB"/>
      </links>
      <assign name="B">
        <targets>
          <target linkName="AtoB"/>
        </targets>
        <copy>
          <from>concat($output.payload,
            'B')</from>
          <to>$output.payload</to>
        </copy>
      </assign>
      <assign name="A">
        <sources>
          <source linkName="AtoB"/>
        </sources>
        <copy>
          <from>concat($output.payload,
           'A')</from>
          <to>$output.payload</to>
        </copy>
      </assign>
    </flow>

10.2.4 How to Create Synchronization Between Activities Within a Flow Activity

To create synchronization between activities within a flow activity:

Note:

The Sources and Targets tabs are only available in BPEL 2.0 projects. For BPEL 1.1 projects, you must directly edit the BPEL file to use this functionality.

  1. Create a flow activity. For information, see Section 10.2.1, "How to Create a Parallel Flow."

  2. In the General tab of the Flow activity, click the Add icon.

  3. Enter a name for the link, as shown in Figure 10-5.

    Figure 10-5 Link Name Creation

    Description of Figure 10-5 follows
    Description of "Figure 10-5 Link Name Creation"

  4. Click Apply, then OK.

  5. Drag appropriate activities into the flow activity to define as the source with the same link name as defined in Step 3. The value of the link name of the source and target must be the same as the link name declared in the flow activity. For this example, an assign activity named A is defined as the source in Figure 10-6.

    Figure 10-6 Source Activity

    Description of Figure 10-6 follows
    Description of "Figure 10-6 Source Activity"

    Each source activity can specify an optional Transition Condition as a safe guard for following the specified link. Click the row in this column to invoke the Browser icon for accessing the Expression Builder dialog for creating a condition. If the Transition Condition column is left blank, it is assumed to evaluate to true.

  6. Define appropriate copy rules for the assign activity.

  7. Click Apply, then OK.

  8. Drag an additional activity into the flow activity to define as the target with the same link name as defined in Step 3. For this example, another assign activity named B is defined as the target in Figure 10-7.

    Figure 10-7 Target Activity

    Description of Figure 10-7 follows
    Description of "Figure 10-7 Target Activity"

  9. Define appropriate copy rules for the assign activity.

  10. Click Apply, then OK.

  11. Continue design of your BPEL process.

    When complete, design can appear similar to that shown in Figure 10-8.

    Figure 10-8 Three Flow Activities Synchronized with Links

    Description of Figure 10-8 follows
    Description of "Figure 10-8 Three Flow Activities Synchronized with Links"

10.2.5 What Happens When You Create Synchronization Between Activities Within a Flow Activity

Example 10-3 shows the .bpel file after design is complete for three flow activities with links for synchronizing activity execution.

  • Flow_1 shows a link between simple activities.

    Flow_1 includes a link named AtoB. The activity that is the target of the link, assign activity B, is only executed if the activity that is the source of the link, assign activity A, has completed.

  • Flow_2 shows a link between simple activity and composite activity.

    Flow_2 also includes the link named AtoB. The activity that is the target of the link, assign activity B, is only executed if the activity that is the source of the link, scope activity scope1, has completed.

  • Flow_3 shows a link between composite activities.

    Flow_3 also includes the link named AtoB. The activity that is the target of the link, sequence activity Sequence_1, is only executed if the activity that is the source of the link, scope activity scope2, has completed.

Example 10-3 Flow Activities with Links

<!-- link between simple activities -->
<flow name=Flow_1>
      <links>
        <link name="AtoB"/>
      </links>
      <assign name="A">
        <sources>
          <source linkName="AtoB"/>
        </sources>
        <copy>
          <from>concat($output.payload, 'A')</from>
          <to>$output.payload</to>
        </copy>
      </assign>
      <assign name="B">
        <targets>
          <target linkName="AtoB"/>
        </targets>
        <copy>
          <from>concat($output.payload, 'B')</from>
          <to>$output.payload</to>
        </copy>
      </assign>
    </flow>

    <!-- link between simple activity and composite activity -->
    <flow name=Flow_2>
      <links>
        <link name="AtoB"/>
      </links>
      <scope name="scope1">
        <sources>
          <source linkName="AtoB"/>
        </sources>
        <assign name="A">
          <copy>
            <from>concat($output.payload, 'A')</from>
            <to>$output.payload</to>
          </copy>
        </assign>
      </scope>
      <assign name="B">
        <targets>
         <target linkName="AtoB"/>
        </targets>
        <copy>
          <from>concat($output.payload, 'B')</from>
          <to>$output.payload</to>
        </copy>
      </assign>
    </flow>

    <!-- link between composite activities -->
    <flow name=Flow_3>
      <links>
        <link name="AtoB"/>
      </links>
      <scope name="scope2">
        <sources>
          <source linkName="AtoB"/>
        </sources>
        <assign name="A">
          <copy>
            <from>concat($output.payload, 'A')</from>
            <to>$output.payload</to>
          </copy>
        </assign>
      </scope>
      <sequence name="Sequence_1>
        <targets>
          <target linkName="AtoB"/>
        </targets>
        <assign name="B">
          <copy>
            <from>concat($output.payload, 'B')</from>
            <to>$output.payload</to>
          </copy>
        </assign>
      </sequence>
    </flow>
  </sequence>

10.2.6 What You May Need to Know About Join Conditions in Target Activities

You can specify an optional join condition in target activities. The value of the join condition is a boolean expression. If a join condition is not specified, the join condition is the disjunction (that is, a logical OR operation) of the link status of all incoming links of this activity.

Oracle BPEL Designer does not provide design support for adding join conditions. To add a join condition, you must manually add the condition to the .bpel file in Source view in Oracle BPEL Designer.

Example 10-4 provides an example of a join condition.

Example 10-4 Join Condition in Target Activity

<flow>
   <links>
      <link name="linkStatus2"/>
   </links>
   <empty name="E2">
      <sources>
         <source linkName="linkStatus2">
            <transitionCondition>false()</transitionCondition>
         </source>
      </sources>
   </empty>
   <empty name="E2">
      <targets> 
         <joinCondition>bpws:getLinkStatus('linkStatus2')=true()</joinCondition>
         <target linkName="linkStatus2"/>
      </targets>
   </empty>
</flow>

10.3 Customizing the Number of Parallel Branches

This section describes how to customize the number of parallel branches with the following activities:

Note:

Branches in flowN and forEach activities are executed serially in a single thread. For more information, see Section 10.1.1, "What You May Need to Know About the Execution of Parallel Flow Branches in a Single Thread."

10.3.1 Customizing the Number of Flow Activities with the flowN Activity in BPEL 1.1

In the flow activity, the BPEL code determines the number of parallel branches. However, often the number of branches required is different depending on the available information. The flowN activity creates multiple flows equal to the value of N, which is defined at runtime based on the data available and logic within the process. An index variable increments each time a new branch is created, until the index variable reaches the value of N.

The flowN activity performs activities on an arbitrary number of data elements. As the number of elements changes, the BPEL process service component adjusts accordingly.

The branches created by flowN perform the same activities, but use different data. Each branch uses the index variable to look up input variables. The index variable can be used in the XPath expression to acquire the data specific for that branch.

For example, suppose there is an array of data. The BPEL process service component uses a count function to determine the number of elements in the array. The process then sets N to be the number of elements. The index variable starts at a preset value (zero is the default), and flowN creates branches to retrieve each element of the array and perform activities using data contained in that element. These branches are generated and performed in parallel, using all the values between the initial index value and N. flowN terminates when the index variable reaches the value of N. For example, if the array contains 3 elements, N is set to 3. Assuming the index variable begins at 1, the flowN activity creates three parallel branches with indexes 1, 2, and 3.

The flowN activity can use data from other sources as well, including data obtained from web services.

Figure 10-9 shows the runtime flow of a flowN activity in Oracle Enterprise Manager Fusion Middleware Control that looks up three hotels. This is different from the view, because instead of showing the BPEL process service component, it shows how the process has actually executed. In this case, there are three hotels, but the number of branches changes to match the number of hotels available.

Figure 10-9 Oracle Enterprise Manager Fusion Middleware Control View of the Execution of a flowN activity

Description of Figure 10-9 follows
Description of "Figure 10-9 Oracle Enterprise Manager Fusion Middleware Control View of the Execution of a flowN activity"

10.3.1.1 How to Create a flowN Activity

To create a flowN activity:

  1. In the Component Palette, expand Oracle Extensions.

  2. Drag a FlowN activity into the designer.

  3. Click the + sign to expand the FlowN activity.

  4. Double-click the FlowN activity.

    Figure 10-10 shows the flowN dialog.

    Figure 10-10 FlowN Dialog

    Description of Figure 10-10 follows
    Description of "Figure 10-10 FlowN Dialog"

    The flowN dialog enables you to:

    • Name the activity

    • Enter a value or an expression for calculating the value of N (the number of branches to create)

    • Define the index variable (the time to wait in each branch)

  5. Drag and define additional activities in the flowN activity.

    Figure 10-11 shows how a FlowN activity appears with additional activities.

    Figure 10-11 FlowN Activity with Additional Activities

    Description of Figure 10-11 follows
    Description of "Figure 10-11 FlowN Activity with Additional Activities "

10.3.1.2 What Happens When You Create a FlowN Activity

The following code shows the .bpel file that uses the flowN activity to look up information on an arbitrary number of hotels. The following actions take place.

Example 10-5 shows the sequence name.

Example 10-5 Sequence Name

<sequence name="main">
  <!-- Received input from requester. 
    Note: This maps to operation defined in NflowHotels.wsdl
    The requester sends a set of hotels names wrapped into the "inputVariable"
    -->

A receive activity calls the client partner link to get the information that the flowN activity must define N times and look up the hotel information. Example 10-6 provides an example.

Example 10-6 Receive Activity

<receive name="receiveInput" partnerLink="client"
 portType="client:NflowHotels" operation="initiate" variable="inputVariable"
 createInstance="yes"/>
    <!-- 
       The 'count()' Xpath function is used to get the number of hotelName
       noded passed in.
       An intermediate variable called "NbParallelFlow" is
       used to store the number of N flows being executed
       -->
    <assign name="getHotelsN">
      <copy>
        <from 
expression="count($InputVariable.payload/client:HotelName);"/>
        <to variable="NbParallelFlow"/>
      </copy>
    </assign>
    <!-- Initiating the FlowN activity
        The N value is initialized with the value stored in the
 "NbParallelFlow" variable
        The variable call "Index" is defined as the index variable
        NOTE: Both "NbParallelFlow" and "Index" variables have to be declared
        -->

The flowN activity begins next. After defining a name for the activity of flowN, N is defined as a value from the inputVariable, which is the number of hotel entries. The activity also assigns index as the index variable. Example 10-7 provides an example.

Example 10-7 FlowN Activity

<bpelx:flowN name="FlowN" N="bpws:getVariableData('NbParallelFlow')
indexVariable="Index'>
      <sequence name="Sequence_1">
        <!-- Fetching each hotelName by indexing the "inputVariable" with the
 "Index" variable.
            Note the usage of the  "concat()" Xpath function to create the
 expression accessing the array element.
            -->

The copy rule shown in Example 10-8 then uses the index variable to concatenate the hotel entries into a list:

Example 10-8 Assign Activity

<assign name="setHotelId">
  <copy>
    <from expression=
"bpws:getVariableData('inputVariable','payload',concat('/client:Nflo
wHotelsProcessRequest/client:ListOfHotels/client:HotelName[',
bpws:getVariableData('Index'),']'))"/>
            <to variable="InvokeHotelDetailInputVariable" part="payload"
 query="/ns2:hotelInfoRequest/ns2:id"/>
          </copy>
        </assign>

Using the hotel information, an invoke activity looks up detailed information for each hotel through a web service. Example 10-9 provides an example.

Example 10-9 Invoke Activity

<!-- For each hotel, invoke the web service giving detailed information
 on the hotel -->
        <invoke name="InvokeHotelDetail" partnerLink="getHotelDetail"
 portType="ns2:getHotelDetail" operation="process"
 inputVariable="InvokeHotelDetailInputVariable"
 outputVariable="InvokeHotelDetailOutputVariable"/>
      </sequence>
    </bpelx:flowN>

Finally, the BPEL process sends detailed information on each hotel to the client partner link. Example 10-10 provides an example.

Example 10-10 Invoke Activity

<invoke name="callbackClient" partnerLink="client"
 portType="client:NflowHotelsCallback" operation="onResult"
 inputVariable="outputVariable"/>
  </sequence>
  </sequence>

10.3.2 Processing Multiple Sets of Activities with the forEach Activity in BPEL 2.0

You can use a forEach activity to process multiple sets of activities sequentially or in parallel. The forEach activity executes a contained (child) scope activity exactly N+1 times, where N equals a final counter value minus a starting counter value that you specify in the Counter Values tab of the For Each dialog. While other structured activities such as a flow activity can have any type of activity as its contained activity, the forEach activity can only include a scope activity.

When the forEach activity is started, the expressions you specify for the starting counter and final counter values are evaluated. Once the two values are returned, they remain constant for the lifecycle of the activity. Both expressions must return a value containing at least one character. If these expressions do not return valid values, a fault is thrown. If the starting counter value is greater than the final counter value, the contained scope activity is not performed and the forEach activity is considered complete.

During each iteration, the variable specified in the Counter Name field on the General tab is implicitly declared in the forEach activity's contained scope. During the first iteration of the scope, the counter variable is initialized with the starting counter value. The next iteration causes the counter variable to be initialized with the starting counter value, plus one. Each subsequent iteration increments the previously initialized counter variable value by one until the final iteration, where the counter is set to the final counter value. The counter variable is local to the enclosed scope activity. Although its value can be changed during an iteration, that value is lost after each iteration. Therefore, the counter variable value does not impact the value of the next iteration's counter.

The forEach activity supports the following looping iterations:

  • Sequential (default)

    The forEach activity performs looping iterations sequentially N times over a given set of activities defined within a scope activity. As an example, the forEach activity iterates over an incoming purchase order message where the purchase order message consists of N order items. The enclosed scope activity must be executed N+1 times, with each instance starting only after the previous iteration has completed.

  • Parallel

    All looping iterations are started at the same time and processed in parallel. Parallel iterations are useful in environments in which sets of independent data are processed or independent interaction with different partners is performed in parallel. To enable parallel looping, you select the Parallel Execution checkbox on the General tab. In these scenarios, execution of the N+1 instances of the contained scope activity occurs in parallel. Each copy of the scope activity has the same counter variable that you specify in the Counter Name field of the General tab declared in the same way as specified for a sequential forEach activity. Each instance's counter variable must be uniquely initialized in parallel with one of the integer values beginning with the starting counter value and proceeding up to and including the final counter value.

    Unlike a flow activity, the number of parallel branches is not known at design time with the forEach activity. The specified counter variable iterates through the number of parallel branches, controlled by the starting counter value and final counter value.

You can also specify a completion condition on the Completion tab. This condition enables the forEach activity to execute the condition and complete without executing or finishing all the branches specified. As an example, you send out parallel requests and a sufficient subset of the recipients have responded. A completion condition is optionally specified to prevent the following:

  • Some children from executing (in the sequential case)

  • To force early termination of some of the children (in the parallel case)

If you do not specify a completion condition, the forEach activity completes when the contained scope has completed.

If a premature termination occurs (due to a fault or the completion condition evaluating to true), then the N+1 requirement does not apply.

Example 10-11 shows the forEach activity syntax.

Example 10-11 forEach Activity

<forEach counterName="MyVariableName" parallel="yes|no"
   standard-attributes>
   standard-elements
   <startCounterValue expressionLanguage="anyURI"?>
      unsigned-integer-expression
   </startCounterValue>
   <finalCounterValue expressionLanguage="anyURI"?>
      unsigned-integer-expression
   </finalCounterValue>
   <completionCondition>?
      <branches expressionLanguage="anyURI"?
         successfulBranchesOnly="yes|no"?>?
         unsigned-integer-expression
      </branches>
   </completionCondition>
   <scope ..>...</scope>
</forEach>

Note:

The successfulBranchesOnly attribute is not supported for this release.

10.3.2.1 How to Create a forEach Activity

To create a forEach activity:

  1. In the Component Palette, expand BPEL Constructs.

  2. Drag a For Each activity into the designer, as shown in Figure 10-12.

    Note the contained scope activity in the forEach activity.

    Figure 10-12 Contained Scope Activity in a forEach Activity

    Description of Figure 10-12 follows
    Description of "Figure 10-12 Contained Scope Activity in a forEach Activity"

  3. Double-click the ForEach activity.

  4. In the Counter Name field of the General tab, enter a counter value name, as shown in Figure 10-13.

    Note the Parallel Execution checkbox. If this checkbox is selected, all looping iterations are started at the same time and processed in parallel. The next branch starts even if the previous branch has not completed. If not selected, the next branch does not start until the previous branch has completed.

    Figure 10-13 General Tab of the forEach Activity

    Description of Figure 10-13 follows
    Description of "Figure 10-13 General Tab of the forEach Activity"

  5. Click the Counter Values tab.

  6. Enter the starting counter value and final counter value, as shown in Figure 10-14.

    Figure 10-14 Counter Values Tab of the forEach Activity

    Description of Figure 10-14 follows
    Description of "Figure 10-14 Counter Values Tab of the forEach Activity"

  7. Click the Completion tab.

  8. If you want to specify a completion condition that enables the forEach activity to execute the condition and complete without executing or finishing all the branches specified, click the XPath Expression Builder icon in the Expression field to enter a condition. Figure 10-15 provides details.

    Figure 10-15 Completion Tab of the forEach Activity

    Description of Figure 10-15 follows
    Description of "Figure 10-15 Completion Tab of the forEach Activity"

  9. Click Apply, then OK.

  10. Expand the contained Scope activity of the ForEach activity.

  11. Design the enclosed Scope activity.

    When complete, the forEach and contained scope activity can appear similar in structure to that shown in Figure 10-16.

    Figure 10-16 forEach Activity with Contained and Expanded Scope Activity

    Description of Figure 10-16 follows
    Description of "Figure 10-16 forEach Activity with Contained and Expanded Scope Activity"

10.3.2.2 What Happens When You Create a forEach Activity

Example 10-12 shows the .bpel file after design is complete for a sequential forEach activity.

Example 10-12 forEach Activity - Sequential

<faultHandlers>
    <catch faultName="bpel:invalidBranchCondition">
<sequence>
  <assign>
    <copy>
      <from>'invalidBranchCondition happened'</from>
      <to>$output.payload</to>
    </copy>
  </assign>

  <reply name="replyOutput" partnerLink="client"
      portType="tns:Test" operation="process" variable="output"/>
</sequence>
    </catch>
  </faultHandlers>
  <sequence>
    <!-- pick input from requester -->
    <receive name="receive" createInstance="yes"
             partnerLink="client" portType="tns:Test"
             operation="process" variable="input"/>
    <assign>
      <copy>
        <from>3</from>
        <to>$request.payload</to>
      </copy>
      <copy>
        <from>''</from>
        <to>$output.payload</to>
      </copy>
    </assign>

    <forEach counterName="i" parallel="no">
      <startCounterValue>$input.payload/tns:startCounter+1</startCounterValue>
      <finalCounterValue>$input.payload/tns:finalCounter+1</finalCounterValue>
      <completionCondition>
        <branches>$input.payload/tns:branches+1</branches>
      </completionCondition>
      <scope name="scope1">
        <partnerLinks>
          <partnerLink name="DummyService" partnerLinkType="tns:DummyService"
              myRole="DummyServiceClient" partnerRole="DummyServiceProvider"/>
        </partnerLinks>
        <sequence>
          <assign>
            <copy>
              <from>concat($output.payload, $i, 'A')</from>
              <to>$output.payload</to>
            </copy>
          </assign>
          <invoke name="invokeDummyService" partnerLink="DummyService"
              portType="tns:DummyPortType"
              operation="initiate" inputVariable="request"/>
          <receive name="receiveFromDummyService" partnerLink="DummyService"
              portType="tns:DummyCallbackPortType"
              operation="onResult" variable="response"/>          <assign>
            <copy>
              <from>concat($output.payload, $i, 'B')</from>
              <to>$output.payload</to>
            </copy>
          </assign>
        </sequence>
      </scope>
    </forEach>

    <!-- respond output to requester -->
    <reply name="replyOutput" partnerLink="client"
        portType="tns:Test" operation="process" variable="output"/>
  </sequence>

Example 10-13 shows the .bpel file after design is complete for a parallel forEach activity.

Example 10-13 forEach Activity - Parallel

<sequence>
    <!-- pick input from requester -->
    <receive name="receive" createInstance="yes"
             partnerLink="client" portType="tns:Test"
             operation="process" variable="input"/>
    <assign>
      <copy>
        <from>$input.payload/tns:value1</from>
        <to>$request.payload</to>
      </copy>
      <copy>
        <from>''</from>
        <to>$output.payload</to>
      </copy>
    </assign>
    <forEach counterName="i" parallel="yes">
      <startCounterValue>($input.payload/tns:value1 + 1)</startCounterValue>
      <finalCounterValue>($input.payload/tns:value2 + 2)</finalCounterValue>
      <scope name="scope1">
        <partnerLinks>
          <partnerLink name="DummyService" partnerLinkType="tns:DummyService"
              myRole="DummyServiceClient" partnerRole="DummyServiceProvider"/>
        </partnerLinks>
        <sequence>
          <assign>
            <copy>
              <from>concat($output.payload, 'A')</from>
              <to>$output.payload</to>
            </copy>
          </assign>
          <invoke name="invokeDummyService" partnerLink="DummyService"
              portType="tns:DummyPortType"
              operation="initiate" inputVariable="request"/>
          <receive name="receiveFromDummyService" partnerLink="DummyService"
              portType="tns:DummyCallbackPortType"
              operation="onResult" variable="response"/>
          <assign>
            <copy>
              <from>concat($output.payload, 'B')</from>
              <to>$output.payload</to>
            </copy>
          </assign>
        </sequence>
      </scope>
    </forEach>
    <!-- respond output to requester -->
    <reply name="replyOutput" partnerLink="client"
        portType="tns:Test" operation="process" variable="output"/>
  </sequence>