Recursion in Activities
Limitations of Recursion in Pega Activities
Implementing recursion in an activity involves invoking the activity within a step in the activity itself. The following limitations need to be considered:
- Parameters are in a single, shared page. Parameters passed from the invoking activity to the invoked activity (which happen to be the same) are contained in a single page that is shared among invocations. This is the result of having to “pass the current parameter page” so that the value of the output parameter can be obtained from the invoked activity.
- The loop counter is in the single, shared parameter page. Wondering how Pega keeps the loop counter (yes, that <CURRENT> value and the value of each step loop)? A special parameter called “pyForEachCount” keeps that value. Which means that, when loops are nested or the same parameter page is passed along an activity, special caution needs to be taken in order to restore the value at the end of every loop- otherwise unexpected results may arise. Recursion typically involves looping; thus, this is an important limitation to consider.
- Clipboard pages are global objects. Each clipboard page is uniquely identified by a name, which is global within the same thread. Thus, any page used within a recursive activity is visible (and modifiable) at any recursion level. When clipboard pages are used in recursive activity invocations, this limitation needs to be considered.
Overcoming the Limitations
The limitations presented above can be overcome using the following techniques:
- Save/Restore the value of “pyForEachCount”. Use a local variable (preferably of type Integer) to save the value of “pyForEachCount” at the beginning of each loop; then restore it at the end of the loop.
- Copy/Restore each clipboard page using a “random name”. Before invoking a recursion, make sure that each clipboard page used in the activity is copied to a temporary page. The name of that page should be unique- this uniqueness can be ensured using a random name generated by the OOTB function “pxGetRandomName”. Use a local variable (e.g. “savedPage”) to store the name of the temporary page. Use this name to restore the page from the temporary page after the recursion is invoked.
- Remove temporary pages: As always, it is a best practice to remove clipboard pages that will not be used again, using the Page-Remove method. Use the local variable that stores the name (“ savedPage” in our example) to remove the page.
An Example
Let’s illustrate these ideas with an example. The data class “Tree” represents both a tree and a node in a tree (like the formal definition of a tree structure implies). To represent a tree using this class, each instance is a record that contains:
- The name of the parent tree/node (ParentName)
- The name of the node (MyName)
The following is an example of a tree and its representation as records of the Tree class:
To illustrate a recursion example, we implemented the activity “GetDepthFirstTraversal”, which returns in its “result” output parameter the result of doing a depth-first traversal of the tree. For our example, that would be “root1-child1-grandchild1-grandchild2-child2-grandchild21”.
An overview of the activity is presented in the next figure. In this implementation, we use the class FSG-Data-Tree to represent the “Tree” class. The activity takes only one parameter called “root”, which is the name of the root node; and has a single output parameter called “result”, which contains the result of the traversal.
To avoid boring you with details, we shall focus on the aspects pertaining to the recursion itself.
In Step 2, all the records whose “ParentName” matches the “parent” parameters are retrieved from the data class. The results are saved in the clipboard page “Children”.
In Step 3, we iterate over the elements of the “Children” clipboard page (which is a page list).
In Step 3.1, we set the parameters for the recursive invocation and the name of the temporary page that will be used to save the clipboard page (to overcome the limitation). It is worth to show the expansion of this step:
Notice the following:
- The value of the “root” parameter is now the name of the child (which becomes the root in the next recursion, as typically in depth-first traversals).
- The value of “pyForEachCount” is saved into the local variable “idx” .
The value of the local variable “savedPage” is obtained with the OOTB function pxGetRandomName- this is the name of the temporary clipboard page.
In Step 3.2, we copy the clipboard page “Children” to the page named by the local variable “savedPage” (whose value we obtained randomly in the previous step).
In Step 3.3, we do the recursive invocation of the activity.
Steps 3.4 and 3.5 take care of restoring the clipboard page and removing the temporary page, respectively.
Conclusion
We have presented a technique to implement a recursive activity that does iteration over clipboard pages, while overcoming the limitations of Pega activities in implementing recursion. The idea is to save clipboard pages in temporary pages and the value of the loop counter in a local variable.