Iterable ForEach Extension
This extension simplifies a common usage pattern in which forEach is used to iterate over a selected sequence of nodes. The common use case involves selecting a sequence of nodes, storing it in a scope variable, and using forEach to iterate over that sequence using the current counter value to extract and operate on the indexed value from the sequence. This extension captures the pattern in a form that's easier to author and debug, by replacing counter with iterator and eliminating the use of temporary variables.
Processing Multiple Branches - ForEach
The <forEach> activity will execute its contained <scope> activity exactly n times where n is the number of items in the <sequenceValue>.
<forEachrangeName="BPELVariableName"parallel="yes|no" standard-attributes> standard-elements <sequenceValueexpressionLanguage="anyURI"? instanceOf="sequenceType"> unsigned-integer-expression </sequenceValue> <completionCondition>? <branchesexpressionLanguage="anyURI"?successfulBranchesOnly="yes|no"?>? unsigned-integer-expression </branches> </completionCondition> <scope ...>...</scope> </forEach>
When the <forEach> activity is started, the expression in <sequenceValue> is evaluated. Once that value is returned, it remains constant for the entire lifespan of the activity. The expression in <sequenceValue> must return a sequence of items (meaning it comprises nodes, texts or atomic values), where each item can be validated to be the type specified by the instanceOf attribute. If this expression does not return a valid sequence value, a bpel:invalidExpressionValue fault will be thrown (refer http://docs.oasis-open.org/wsbpel/2.0/OS/wsbpel-v2.0-OS.html#_Toc164738497 for expressions). If the <sequenceValue> is empty, then the child <scope> activity must not be performed and the <forEach> activity should be complete.
The child activity of a <forEach> must be a <scope> activity. The <forEach> construct introduces an implicit range variable, and also introduces dynamic parallelism (i.e. having parallel branches of which, the amount is not known ahead of time). The <scope> activity provides a well-defined scope snapshot semantic and a way to name the dynamic parallel work for compensation purposes (For scope snapshot description, refer to section 12.4.2 un Process State Usage in Compensation Handlers).
If the value of the parallel attribute is "no", then the activity is a serial <forEach>. The enclosed <scope> activity must be executed n times with each instance starting only after the previous repetition is completed. If premature termination occurs due to a fault for example, or the completion condition evaluates to "true", then the requirement to execute n number if time does not apply. During each repetition, a variable of type specified by the "instanceOf" attribute is implicitly declared in the <forEach> activity's child <scope>. This implicit variable has the name specified in the "rangeVariableName" attribute. The first iteration of the scope will see the range variable initialized to the first item in <sequenceValue>. The next iteration will cause the range variable to be initialized to the second item in <sequenceValue>. Each subsequent iteration will move the range variable to the next item in the sequence, until the final iteration where the range will be set to the last item in <sequenceValue>. The range variable is local to the enclosed <scope>. Although its value can be changed during an iteration, that value will be lost at the end of each iteration. Therefore, the range variable value does not affect the value of the next iteration's range.
If the value of the parallel attribute is "yes", then the activity is a parallel <forEach>. The enclosed <scope> activity must be concurrently executed n times. In essence, an implicit <flow> is dynamically created with n copies of the <forEach> element's enclosed <scope> activity as children. Each copy of the <scope> activity will have the same range variable declared in the same manner as specified for serial <forEach>. Each instance's range variable must be uniquely initialized in parallel to one of the item values starting with first and up to and including the last item in <sequenceValue>, as a part of <scope> instantiation.
If a variable of the same name as the value of the rangeName attribute is declared explicitly in the enclosed scope, it will be considered a case of duplicate variable declaration and must be reported as an error during static analysis.
The <forEach> activity without a <completionCondition> completes when all of its child <scope> elements have completed. The <completionCondition> element is optionally specified to prevent some of the children from executing (in the serial case), or to force early termination of some of the children (in the parallel case).
The <branches> element represents an unsigned-integer expression (see section 8.3.4. Unsigned Integer Expressions) used to define a completion condition of the "at least N out of M" form. The actual value B of the expression is calculated once, at the beginning of the <forEach> activity. It will not change as the result of the <forEach> activity's execution. At the end of execution of each directly enclosed <scope> activity, the number of completed children is compared to B, the value of the <branches> expression. If at least B children have completed, the <completionCondition> is triggered: No further children will be started, and currently running children will be terminated (Refer to http://docs.oasis-open.org/wsbpel/2.0/OS/wsbpel-v2.0-OS.html#_Toc164738528 for Termination Handlers). Note that enforcing the semantic of "exactly m out of n" in parallel <forEach> would involve a race condition, and is therefore not specified.
When the completion condition B is calculated, if its value is larger than the number of directly-enclosed activities, the standard bpel:invalidBranchCondition fault must be thrown. Both B and n may be constant expressions, and in such cases, static analysis should reject processes when "B is greater than n" is detected.
The <branches> element has an optional "successfulBranchesOnly" attribute with the default value as "no". If the value of "successfulBranchesOnly" is "no", all <scope> elements which have completed (successfully or not) must be counted. If "successfulBranchesOnly" is "yes", only <scope> elements which have completed successfully must be counted.
The <completionCondition> is evaluated each time a directly-enclosed <scope> activity completes. If the <completionCondition> evaluates to true, the <forEach> activity completes:
- When the <completionCondition> is fulfilled for a parallel <forEach> activity, all still running directly enclosed <scope> activities must be terminated.
- When the <completionCondition> is fulfilled for a serial <forEach> activity, further child <scope> elements must not be instantiated, and the <forEach> activity completes.
If upon completion of a directly enclosed <scope> activity, it can be determined that the <completionCondition> can never be true, the standard bpel:completionConditionFailure fault must be thrown. When a <completionCondition> does not have any sub-elements or attributes understood by the WS-BPEL processor, it must be treated as if the <completionCondition> does not exist.