Creating an index or iterator controlled loop in an MDM workflow.

Creating an index or iterator controlled loop in an MDM workflow.

book

Article ID: KB0093365

calendar_today

Updated On:

Products Versions
TIBCO MDM -
Not Applicable -

Description

Description:
It is sometimes required to create an index or iterator controlled loop in an MDM workflow. To assist in this process, this knowledge article provides a template of how this can be achieved for various scenarios. Each scenario follows the same basic (template) pattern.

Issue/Introduction

Creating an index or iterator controlled loop in an MDM workflow.

Resolution

Template Pattern: Creating an index or iterator controlled loop in an MDM workflow is made possible by use of the InterpretCommand activity. The pattern used follows.

Activities:
<Activity Name="InitializeLoop">...</Activity>
<Activity Name="LoopPoint">...</Activity>
<Activity Name="NextRecord">...</Activity>
<Activity Name="MovePointer">...</Activity>

Transitions:
<Transition FromActivity="...lead in activity..." ToActivity="InitializeLoop"/>
<Transition FromActivity="InitializeLoop" ToActivity="LoopPoint"/>
<Transition FromActivity="LoopPoint" ToActivity="NextRecord">
  <Rule>
    <Parameter direction="in" name="Counter" eval="variable" type="long">Counter</Parameter>
    <Parameter direction="in" name="Limit" eval="variable" type="long">Limit</Parameter>
    <Parameter name="result" type="boolean" direction="out" />
    <Condition format="bsh"><![CDATA[result = Counter.intValue() < Limit.intValue();]]></Condition>
  </Rule>   
</Transition>
<Transition FromActivity="LoopPoint" ToActivity="SetStatusToSuccess"/><!-- Exit if Counter >= Limit -->
<Transition FromActivity="NextRecord" ToActivity="...first activity in loop body..."/>
...
<Transition FromActivity="...last activity in loop body..." ToActivity="MovePointer"/>
<Transition FromActivity="MovePointer" ToActivity="LoopPoint"/>

Scenario 1:
Suppose there is a need to iterate over two arrays VALUE_ARRAY_ID, and VALUE_ARRAY_IDEXT, extracting the (String) values from each arrays for the current position each time, and using them in some loop body activities.  For simplicity, this loop assumes that VALUE_ARRAY_ID and VALUE_ARRAY_IDEXT are the same length.  

<!-- Loop Activities : Start -->
<Activity Name="InitializeLoop">
  <Action>InterpretCommand</Action>
  <Description lang="en">Set counter=0 and limit=VALUE_ARRAY_ID.length</Description>
  <Parameter direction="in" name="ValueArrayID" eval="variable" type="arraylist">VALUE_ARRAY_ID</Parameter>
  <Parameter direction="out" name="Counter" eval="variable" type="long">Counter</Parameter>
  <Parameter direction="out" name="Limit" eval="variable" type="long">Limit</Parameter>
  <Script format="bsh"><![CDATA[Counter = new java.lang.Long(0L);Limit = new java.lang.Long(ValueArrayID.length);]]></Script>
</Activity>
<Activity Name="LoopPoint">
  <Action>NoOperation</Action>
  <Description lang="en">Loop point to enable single test point for loop</Description>
</Activity>
<Activity Name="NextRecord">
  <Action>InterpretCommand</Action>
  <Description lang="en">Get Next Value from two arrays - assumes two arrays the same length</Description>
  <Parameter direction="in" name="ValueArrayID" eval="variable" type="arraylist">VALUE_ARRAY_ID</Parameter>
  <Parameter direction="in" name="ValueArrayIDEXT" eval="variable" type="arraylist">VALUE_ARRAY_IDEXT</Parameter>
  <Parameter direction="in" name="Counter" eval="variable" type="number">Counter</Parameter>
  <Parameter direction="out" name="NextID" eval="variable" type="string">NEXT_ID</Parameter>
  <Parameter direction="out" name="NextIDEXT" eval="variable" type="string">NEXT_IDEXT</Parameter>
  <Script format="bsh">
  <![CDATA[NextID = (java.lang.String) ValueArrayID.get(Counter.intValue());NextIDEXT = (java.lang.String) ValueArrayIDEXT.get(Counter.intValue());]]>
  </Script>
</Activity>
<!-- Start user-specific loop body -->
  <Activity Name="...first activity in loop body...">
  <Action>...</Action>
  <Description>...</Description>
   ...
  <Parameter name="NextId" direction="in" eval="variable" type="string">NEXT_ID</Parameter>
  <Parameter name="NextIdExt" direction="in" eval="variable" type="string">NEXT_IDEXT</Parameter>
   ...
  </Activity>
   ...
  <Activity Name="...last activity in loop body...">
  <Action>...</Action>
  <Description>...</Description>
   ...
  <Parameter name="NextId" direction="in" eval="variable" type="string">NEXT_ID</Parameter>
  <Parameter name="NextIdExt" direction="in" eval="variable" type="string">NEXT_IDEXT</Parameter>
   ...
  </Activity>
<!-- End user-specific loop body -->
<Activity Name="MovePointer">
  <Action>InterpretCommand</Action>
  <Description lang="en">counter = counter + 1</Description>
  <Parameter direction="in" name="CounterIn" eval="variable" type="number">Counter</Parameter>   
  <Parameter direction="out" name="CounterOut" eval="variable" type="number">Counter</Parameter>
  <Script format="bsh"><![CDATA[CounterOut = new java.lang.Long(CounterIn.longValue() + 1L);]]></Script>
</Activity>
<!-- Loop Activities : End -->
...
<!-- Loop Transitions : Start -->
<Transition FromActivity="...lead in activity..." ToActivity="InitializeLoop"/>
<Transition FromActivity="InitializeLoop" ToActivity="LoopPoint"/>
<Transition FromActivity="LoopPoint" ToActivity="NextRecord">
  <Rule>
    <Parameter direction="in" name="Counter" eval="variable" type="long">Counter</Parameter>
    <Parameter direction="in" name="Limit" eval="variable" type="long">Limit</Parameter>
    <Parameter name="result" type="boolean" direction="out" />
    <Condition format="bsh"><![CDATA[result = Counter.intValue() < Limit.intValue();]]></Condition>
  </Rule>   
</Transition>
<!-- Counter >= Limit, so Exit -->
<Transition FromActivity="LoopPoint" ToActivity="SetStatusToSuccess"/>
<!-- Start user-specific loop body -->
  <Transition FromActivity="NextRecord" ToActivity="...first activity in loop body..."/>
   ...
  <Transition FromActivity="...last activity in loop body..." ToActivity="MovePointer"/>
<!-- End user-specific loop body -->
<Transition FromActivity="MovePointer" ToActivity="LoopPoint"/>
<!-- Loop Transitions : End -->
...


Scenario 2:
Suppose there is a need to iterate over one array VALUE_ARRAY, extracting a Structure (in this case, ID String/IDEXT String) from the array for the current position each time, and using it in some loop body activities.  

<!-- Loop Activities : Start -->
<Activity Name="InitializeLoop">
  <Action>InterpretCommand</Action>
  <Description lang="en">Set counter=0 and limit=VALUE_ARRAY.length</Description>
  <Parameter direction="in" name="ValueArray" eval="variable" type="arraylist">VALUE_ARRAY</Parameter>
  <Parameter direction="out" name="Counter" eval="variable" type="long">Counter</Parameter>
  <Parameter direction="out" name="Limit" eval="variable" type="long">Limit</Parameter>
  <Script format="bsh"><![CDATA[Counter = new java.lang.Long(0L);Limit = new java.lang.Long(ValueArray.length);]]></Script>
</Activity>
<Activity Name="LoopPoint">
  <Action>NoOperation</Action>
  <Description lang="en">Loop point to enable single test point for loop</Description>
</Activity>
<Activity Name="NextRecord">
  <Action>InterpretCommand</Action>
  <Description lang="en">Get Next Value from array</Description>
  <Parameter direction="in" name="ValueArray" eval="variable" type="arraylist">VALUE_ARRAY</Parameter>
  <Parameter direction="in" name="Counter" eval="variable" type="number">Counter</Parameter>
  <Parameter direction="out" name="NextID" eval="variable" type="string">NEXT_ID</Parameter>
  <Parameter direction="out" name="NextIDEXT" eval="variable" type="string">NEXT_IDEXT</Parameter>
  <Script format="bsh">
  <![CDATA[NextID = (java.lang.String) (ValueArrayID.get(Counter.intValue())).ID;NextIDEXT = (java.lang.String) (ValueArrayID.get(Counter.intValue())).IDEXT;]]>
  </Script>
</Activity>
<!-- Start user-specific loop body -->
  <Activity Name="...first activity in loop body...">
  <Action>...</Action>
  <Description>...</Description>
   ...
  <Parameter name="NextId" direction="in" eval="variable" type="string">NEXT_ID</Parameter>
  <Parameter name="NextIdExt" direction="in" eval="variable" type="string">NEXT_IDEXT</Parameter>
   ...
  </Activity>
   ...
  <Activity Name="...last activity in loop body...">
  <Action>...</Action>
  <Description>...</Description>
   ...
  <Parameter name="NextId" direction="in" eval="variable" type="string">NEXT_ID</Parameter>
  <Parameter name="NextIdExt" direction="in" eval="variable" type="string">NEXT_IDEXT</Parameter>
   ...
  </Activity>
<!-- End user-specific loop body -->
<Activity Name="MovePointer">
  <Action>InterpretCommand</Action>
  <Description lang="en">counter = counter + 1</Description>
  <Parameter direction="in" name="CounterIn" eval="variable" type="number">Counter</Parameter>   
  <Parameter direction="out" name="CounterOut" eval="variable" type="number">Counter</Parameter>
  <Script format="bsh"><![CDATA[CounterOut = new java.lang.Long(CounterIn.longValue() + 1L);]]></Script>
</Activity>
<!-- Loop Activities : End -->
...
<!-- Loop Transitions : Start -->
<Transition FromActivity="...lead in activity..." ToActivity="InitializeLoop"/>
<Transition FromActivity="InitializeLoop" ToActivity="LoopPoint"/>
<Transition FromActivity="LoopPoint" ToActivity="NextRecord">
  <Rule>
    <Parameter direction="in" name="Counter" eval="variable" type="long">Counter</Parameter>
    <Parameter direction="in" name="Limit" eval="variable" type="long">Limit</Parameter>
    <Parameter name="result" type="boolean" direction="out" />
    <Condition format="bsh"><![CDATA[result = Counter.intValue() < Limit.intValue();]]></Condition>
  </Rule>
</Transition>
<!-- Counter >= Limit, so Exit -->
<Transition FromActivity="LoopPoint" ToActivity="SetStatusToSuccess"/>
<!-- Start user-specific loop body -->
  <Transition FromActivity="NextRecord" ToActivity="...first activity in loop body..."/>
   ...
  <Transition FromActivity="...last activity in loop body..." ToActivity="MovePointer"/>
<!-- End user-specific loop body -->
<Transition FromActivity="MovePointer" ToActivity="LoopPoint"/>
<!-- Loop Transitions : End -->
...

Scenario 3:
Scenario 3 is the same as scenario 2 except that Java iterators are now being used - this may not work in MDM as it currently stands as of MDM 8.3.2 hotfix 1 or lower versions of CIM/MDM - it depends on whether Iterator, when specified as a "recordlist" parameter, will actually be treated as a java.lang.Object.

<!-- Loop Activities : Start -->
<Activity Name="InitializeLoop">
  <Action>InterpretCommand</Action>
  <Description lang="en">Fetch iterator for VALUE_ARRAY</Description>
  <Parameter direction="in" name="ValueArray" eval="variable" type="arraylist">VALUE_ARRAY</Parameter>
  <Parameter direction="out" name="Iterator" eval="variable" type="recordlist">Iterator</Parameter>
  <Script format="bsh"><![CDATA[java.util.ListIterator<java.util.List> Iterator = (java.util.ListIterator<java.util.List>) ValueArray.iterator();]]></Script>
</Activity>
<Activity Name="LoopPoint">
  <Action>NoOperation</Action>
  <Description lang="en">Loop point to enable single test point for loop</Description>
</Activity>
<Activity Name="NextRecord">
  <Action>InterpretCommand</Action>
  <Description lang="en">Get Next Value from array</Description>
  <Parameter direction="in" name="Iterator" eval="variable" type="recordlist">Iterator</Parameter>
  <Parameter direction="out" name="NextID" eval="variable" type="string">NEXT_ID</Parameter>
  <Parameter direction="out" name="NextIDEXT" eval="variable" type="string">NEXT_IDEXT</Parameter>
  <Script format="bsh">
  <![CDATA[java.util.List<java.lang.String> NextValue = Iterator.next();NextID = (java.lang.String) NextValue.get(0);NextIDEXT = (java.lang.String) NextValue.get(1);]]>
  </Script>
</Activity>
<!-- Start user-specific loop body -->
  <Activity Name="...first activity in loop body...">
  <Action>...</Action>
  <Description>...</Description>
   ...
  <Parameter name="NextId" direction="in" eval="variable" type="string">NEXT_ID</Parameter>
  <Parameter name="NextIdExt" direction="in" eval="variable" type="string">NEXT_IDEXT</Parameter>
   ...
  </Activity>
   ...
  <Activity Name="...last activity in loop body...">
  <Action>...</Action>
  <Description>...</Description>
   ...
  <Parameter name="NextId" direction="in" eval="variable" type="string">NEXT_ID</Parameter>
  <Parameter name="NextIdExt" direction="in" eval="variable" type="string">NEXT_IDEXT</Parameter>
   ...
  </Activity>
<!-- End user-specific loop body -->
<!-- Loop Activities : End -->
...
<!-- Loop Transitions : Start -->
<Transition FromActivity="...lead in activity..." ToActivity="InitializeLoop"/>
<Transition FromActivity="InitializeLoop" ToActivity="LoopPoint"/>
<Transition FromActivity="LoopPoint" ToActivity="NextRecord">
  <Rule>
    <Parameter direction="in" name="Iterator" eval="variable" type="recordlist">Iterator</Parameter>
    <Parameter name="result" type="boolean" direction="out" />
    <Condition format="bsh"><![CDATA[result = Iterator.hasNext();]]></Condition>
  </Rule>  
</Transition>
<!-- hasNext() is false, so Exit -->
<Transition FromActivity="LoopPoint" ToActivity="SetStatusToSuccess"/>
<!-- Start user-specific loop body -->
  <Transition FromActivity="NextRecord" ToActivity="...first activity in loop body..."/>
  ...
  <Transition FromActivity="...last activity in loop body..." ToActivity="LoopPoint"/>
<!-- End user-specific loop body -->
<!-- Loop Transitions : End -->
...