Time for action – appending multiple values to a variable

Carry out the following steps:

  1. Drag-and-drop an <assign> activity after the <invoke> activity named invoke_search_web_search, double-click on it, and go to the Copy Rules tab. Create a new copy rule and then choose $invoke_search_web_service_search_OutputVariable.output as the From expression and $outputVariable.payload as the To expression. Then right-click on that copy rule and go to Change rule type and select Append. Then click on Apply and then on OK, as shown in the following screenshot:
    Time for action – appending multiple values to a variable
  2. The BPEL is ready for testing and deployment:
    Time for action – appending multiple values to a variable

What just happened?

In the preceding section, we collated all the responses from repetitive web service invocations into a single variable called outputVariable.

Understanding the <forEach> loop

Frequently in real life, we need to perform some tasks repeatedly. This typical behavior is common for computer programs, as well. Almost all the programming languages define language constructs that support to execute repetitive tasks. Similarly, WS-BPEL 2.0 also provides <while>, <repeatUntil>, and <forEach> activities to support repetitive execution in different ways. In contrast, the <forEach> activity supports repetitive execution of the contained activity in a parallel manner for a predefined number of times. Let's discuss the <forEach> activity in detail in the coming sections.

Required elements and attributes of a <forEach> activity

As we introduced the <forEach> activity in the previous section, in order to determine the number of repetitions, there are two elements named <startCounterValue> and <finalCounterValue>, as shown:

<forEach counterName="BPELVariableName" parallel="yes|no">
  <startCounterValue>
    unsigned-integer-expression
  </startCounterValue>
  <finalCounterValue>
    unsigned-integer-expression
  </finalCounterValue>
  <scope>
    ...
  </scope>
</forEach>

The contained activity is executed N + 1 times, where N is equal to value of <finalCounterValue> minus the value of <startCounterValue>.

Note

N = expression value of <finalCounterValue> - expression value of <startCounterValue>

Number of Iterations = N + 1

When the <forEach> activity is started, the expression values of <startCounterValue> and <finalCounterValue> are evaluated and those values remain constant during the lifespan of the activity.

Declaring the invocation logic of a <forEach> activity

One important thing to notice is that the <forEach> activity can only contain the <scope> activity as the top-level structured activity. All the activities that are supposed to be executed within the <forEach> activity should be included within the top-level <scope> activity.

Additionally, the <forEach> activity has an attribute named counterName. The attribute refers to a variable that is implicitly declared in the contained scope of the <forEach> activity. The variable has the value of current counter during the repetitive execution. In other words, the contained <scope> can refer to the current counter value during each execution by accessing the variable referred by counterName. In other words, at each repetition, the contained <scope> sees a different value for this variable. During the first iteration, the contained <scope> activity sees the value of the variable referred by counterName, as the value of the <startCounterValue> element. Similarly, during the final iteration, the contained activity sees the value of the variable referred by counterName, as the value of <finalCounterValue> element.

Configuring a parallel <forEach> activity

The remaining attribute in the <forEach> activity is the attribute named parallel. This attribute enables to execute the contained <scope> activity in parallel or serial. This is very important and one significant difference between other activities such as <while> and <repeatUntil> that support repetitive executions. If the attribute value is yes, then all the repetitive executions start in parallel. Otherwise, the loop branches are executed one after the other. The <forEach> activity has one important advantage of simple definition of parallel executions. We discuss more about this parallel <forEach> loop in the next section.

Declaring a customized completion condition in a <forEach> activity

We discussed the attributes of the <forEach> activity and the top-level child activities such as <startCounterValue> and <finalCounterValue>. These parameters are required enough to define a simple repetitive behavior that is executed serially or in parallel. There is one optional top-level child element left that can be used to define completion condition for the <forEach> activity, which is the <completionCondition> element. This element is defined as follows:

<forEach counterName="BPELVariableName" parallel="yes|no">
  <startCounterValue>
    unsigned-integer-expression
  </startCounterValue>
  <finalCounterValue>
    unsigned-integer-expression
  </finalCounterValue>
  <completionCondition>
    <branches successfulBranchesOnly="yes|no">
      unsigned-integer-expression
    </branches>
  </completionCondition>
  <scope>
   ...
  </scope>
</forEach>

The <completionCondition> element enables us to terminate the repetitive execution even before completing all the loop branches. The <forEach> activity completes when all the loop branches are completed unless there is a <completionCondition> element. If the <completionCondition> exists, we can specify that only specific number of loop branches get completed in order to complete the <forEach> activity. We can configure this by the value of the <branches> element that is defined within the <completionCondition> element. The value is an unsigned integer, which can be defined using an XPath expression.

However, what if we only need to complete the <forEach> activity when only a specific number of successful loop branches are completed rather counting both successful and failed loop branches. This can be configured using the attribute named successfulBranchesOnly within the <branches> element. We discussed the configuration parameters of the <completionCondition> element. Now, we discuss how it affects the behavior of the <forEach> activity. At the end of each iteration, the <forEach> activity evaluates the <completionCondition> element and if the completion condition is met, the <forEach> activity does not trigger further iterations.

Let's explore all the discussed parameters with a simple example.

Suppose you needed to collect ten random images from a set of hundred image sources. However, out of those hundred image sources, some of them can be unreliable at some times. The BPEL process should invoke all those image sources and retrieve ten images from images sources that are reliable at that time. This problem can be easily implemented using the <forEach> activity with a completion condition as follows:

<forEachcounterName="BPELVariableName" parallel="no">
  <startCounterValue>
    fn:number('1')
  </startCounterValue>
  <finalCounterValue>
    fn:number('100')
</finalCounterValue>
  <completionCondition>
    <branches successfulBranchesOnly="yes">
      fn:number('10')
    </branches>
  </completionCondition>
  <scope>
    <invoke... /><!-- Invoking the image source and retrieve the image-->
    <sequence... /><!-- Necessary steps to persist the retrieved image -->
  </scope>
</forEach>

Counter for the <forEach> activity starts from 1 and it increments until 100. During the start of each execution, the BPEL runtime evaluates the completion condition. In this example, the BPEL runtime checks whether there is at least ten successful branches completed at the time of evaluation. If so, the execution of the <forEach> activity is marked as completed. In the example, the loop branches are executed in a serial order. In the next section, we discuss the behavior of the <forEach> activity when the loop branches are executed in parallel.

Understanding the parallel <forEach>

In the preceding section, we discussed all the parameters that configure the behavior of the <forEach> activity. One parameter that can make a significant impact on the behavior of the <forEach> activity is the attribute named parallel. This is because if the attribute's value is set to be true, the loop branches are executed in parallel. Also, the resultant behavior, when the completion condition meets, also changes.

Also, in some cases, a BPEL developer has to implement the activities within the enclosed scope differently based on the execution manner (that is, serial or parallel). One example would be, if the enclosed scope reads and modifies a global variable, then the scopes should be implemented as isolated scopes (we discussed about isolated scopes in the preceding chapter) to avoid unexpected behavior. In a serial execution, the scope can be either isolated or not. However, we will not go into details on this in this book.

In the upcoming subsections, we discuss the behavior of the parallel <forEach> activity.

What happens when starting the <forEach> activity

At the start of a parallel <forEach> activity, the expression values of <startCounterValue> and <finalCounterValue> are evaluated and based on those values, the required number of iterations are determined. Then based on those required number of iterations, the enclosed <scope> is executed concurrently. Even though, the behavior of the variable specified by counterName is similar to the serial <forEach> execution. Each enclosed <scope> execution sees a variable specified by the counterName attribute with a unique integer value. This unique integer value spans from the expression value of <startCounterValue> to the expression value of <finalCounterValue>.

What happens when the completion condition is met

The completion condition is evaluated at the end of each iteration. The interesting fact in a parallel <forEach> activity is, at the end of an iteration, we do not know whether the other concurrent enclosed scopes are completed or not. However, in a serial <forEach> activity, we know that there is no instance of enclosed <scope> activities at the end of an iteration. So unlike in a serial <forEach>, if the completion condition is met, then all the running enclosed <scope> activities should be terminated. Consequently, the termination handler of each enclosed <scope> is triggered.

Understanding the difference between <flow> and parallel <forEach>

In the previous section, we discussed the behavior of the parallel <forEach> activity. Also, we already discussed about the <flow> activity in Chapter 2, Service Invocation. Both these constructs support parallel execution of its enclosed activities. The BPEL developer have the option of using the <flow> activity or <forEach> activity to implement the parallel execution. Let's discuss what is lacking in the <forEach> activity compared to the <flow> activity in terms of parallel execution.

Lack of synchronization dependencies

When there are concurrent executions happening, sometimes the BPEL developer needs to define some coordination among those executions. The <flow> activity utilizes constructs (for example, <links>, <sources>, <targets>, and so on), which support to define synchronization dependencies. However, the parallel <forEach> doesn't have such support. Rather, it executes the enclosed <scope> activity concurrently without any concern of synchronization among such iterations. The <flow> activity should be used when there is a requirement of a coordinated execution.

Repeating the same activity rather than different activities

The parallel <forEach> activity is very useful when implementing inherently parallel set of similar tasks. Those tasks have no dependency among themselves. Also, the tasks should be similar, for example, invoking a web service. In such a scenario, using the <flow> activity just only incurs an excess amount work.

So based on those reasons, the BPEL developer should choose the better option among the parallel <forEach> activity and <flow>activity.

Pop quiz

Q1. What are the values that do not change over the time of an execution of a <forEach> loop?

  1. Counter variable (value of the variable referred by the counterName attribute)
  2. Start counter value (value evaluated from the expression in <startCounterValue>)
  3. Final counter value (value evaluated from the expression in <finalCounterValue>)
  4. Branches value (value evaluated from the expression in <branches>)

Q2. What will happen if the <startCounterValue> is larger than the <finalCounterValue>?

Q3. What will happen if the value of <branches> exceeds the possible number of iterations?

Q4. What can be the child activity of a <forEach> activity?

  1. <sequence>
  2. <flow>
  3. <scope>
  4. <invoke>
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset