This is an automated email from the ASF dual-hosted git repository.

egonzalez pushed a commit to branch main
in repository 
https://gitbox.apache.org/repos/asf/incubator-kie-kogito-runtimes.git


The following commit(s) were added to refs/heads/main by this push:
     new eaa39967e2 [incubator-kie-issues-1309] Multiinstance loop (#3554)
eaa39967e2 is described below

commit eaa39967e21386e581da6644f20171617f7cff3c
Author: Enrique <[email protected]>
AuthorDate: Mon Jul 29 12:13:01 2024 +0200

    [incubator-kie-issues-1309] Multiinstance loop (#3554)
---
 .../org/jbpm/bpmn2/xml/AbstractNodeHandler.java    |   9 +-
 .../compiler/canonical/ForEachNodeVisitor.java     |  12 +-
 .../canonical/node/ForEachNodeVisitorBuilder.java  |   3 +-
 .../process/instance/KogitoProcessContextImpl.java |   8 +
 .../core/WorkflowElementIdentifierFactory.java     |   2 +-
 .../ruleflow/core/factory/ForEachNodeFactory.java  |   7 +
 .../core/impl/MultiInstanceSpecification.java      |  10 ++
 .../org/jbpm/workflow/core/node/ForEachNode.java   |  11 +-
 .../instance/node/ForEachNodeInstance.java         |  40 ++---
 .../BPMN2-MultiInstanceLoopBoundaryTimer.bpmn2     |   2 +-
 ...tanceLoopCharacteristicsProcessSequential.bpmn2 |   3 +-
 ...haracteristicsProcessWithOutputAndScripts.bpmn2 |   4 +-
 ...PMN2-MultiInstanceLoopCharacteristicsTask.bpmn2 |   3 +-
 ...InstanceLoopCharacteristicsTaskSequential.bpmn2 |   2 +-
 ...cteristicsTaskWithOutputCmpCondSequential.bpmn2 |  11 +-
 .../BPMN2-EventSubprocessConditional.bpmn2         |   5 +
 .../subprocess/BPMN2-EventSubprocessMessage.bpmn2  |   6 +-
 .../src/test/java/org/jbpm/bpmn2/FlowTest.java     |  35 +++--
 .../java/org/jbpm/bpmn2/IntermediateEventTest.java | 175 +++++++++++++++++++--
 ...cteristicsTaskWithOutputCmpCondSequential.bpmn2 |  10 +-
 20 files changed, 290 insertions(+), 68 deletions(-)

diff --git 
a/jbpm/jbpm-bpmn2/src/main/java/org/jbpm/bpmn2/xml/AbstractNodeHandler.java 
b/jbpm/jbpm-bpmn2/src/main/java/org/jbpm/bpmn2/xml/AbstractNodeHandler.java
index e8429c2272..50eb0f0f9e 100755
--- a/jbpm/jbpm-bpmn2/src/main/java/org/jbpm/bpmn2/xml/AbstractNodeHandler.java
+++ b/jbpm/jbpm-bpmn2/src/main/java/org/jbpm/bpmn2/xml/AbstractNodeHandler.java
@@ -755,7 +755,13 @@ public abstract class AbstractNodeHandler extends 
BaseAbstractHandler implements
             }
         }
         // this is just an expression
-        
forEachNode.setCompletionConditionExpression(multiInstanceSpecification.getCompletionCondition());
+        ReturnValueEvaluator evaluator = null;
+        String completionConditionLang = 
multiInstanceSpecification.getCompletionConditionLang();
+        if ((completionConditionLang == null || 
completionConditionLang.isBlank() || 
completionConditionLang.toLowerCase().contains("mvel"))
+                && multiInstanceSpecification.getCompletionCondition() != 
null) {
+            evaluator = new 
MVELInterpretedReturnValueEvaluator(multiInstanceSpecification.getCompletionCondition());
+        }
+        forEachNode.setCompletionConditionExpression(evaluator);
         forEachNode.setMultiInstanceSpecification(multiInstanceSpecification);
 
         // This variable is used for adding items computed by each subcontext.
@@ -825,6 +831,7 @@ public abstract class AbstractNodeHandler extends 
BaseAbstractHandler implements
             String completion = completeCondition.getTextContent();
             if (completion != null && !completion.isEmpty()) {
                 multiInstanceSpecification.setCompletionCondition(completion);
+                
multiInstanceSpecification.setCompletionConditionLang(completeCondition.getAttribute("language"));
             }
         });
         return multiInstanceSpecification;
diff --git 
a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/ForEachNodeVisitor.java
 
b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/ForEachNodeVisitor.java
index 45e4ffdaa6..0a964980d8 100644
--- 
a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/ForEachNodeVisitor.java
+++ 
b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/ForEachNodeVisitor.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
+import org.jbpm.compiler.canonical.builtin.ReturnValueEvaluatorBuilderService;
 import org.jbpm.compiler.canonical.node.NodeVisitorBuilderService;
 import org.jbpm.process.core.context.variable.VariableScope;
 import org.jbpm.ruleflow.core.factory.ForEachNodeFactory;
@@ -45,8 +46,11 @@ import static 
org.jbpm.ruleflow.core.factory.ForEachNodeFactory.METHOD_SEQUENTIA
 
 public class ForEachNodeVisitor extends 
AbstractCompositeNodeVisitor<ForEachNode> {
 
-    public ForEachNodeVisitor(NodeVisitorBuilderService nodeVisitorService) {
+    private ReturnValueEvaluatorBuilderService 
returnValueEvaluatorBuilderService;
+
+    public ForEachNodeVisitor(NodeVisitorBuilderService nodeVisitorService, 
ReturnValueEvaluatorBuilderService returnValueEvaluatorBuilderService) {
         super(nodeVisitorService);
+        this.returnValueEvaluatorBuilderService = 
returnValueEvaluatorBuilderService;
     }
 
     @Override
@@ -115,6 +119,12 @@ public class ForEachNodeVisitor extends 
AbstractCompositeNodeVisitor<ForEachNode
             filterNodes.removeIf(n -> 
n.getId().equals(outgoingNode.getNodeId()));
         }
 
+        if (node.hasCompletionCondition()) {
+            String completionConditionDialect = 
node.getCompletionConditionExpression().dialect();
+            String completionConditionExpression = 
node.getCompletionConditionExpression().expression();
+            body.addStatement(getFactoryMethod(getNodeId(node), 
ForEachNodeFactory.METHOD_COMPLETE_CONDITION,
+                    returnValueEvaluatorBuilderService.build(node, 
completionConditionDialect, completionConditionExpression)));
+        }
         visitConnections(getNodeId(node), filterNodes.toArray(new 
Node[filterNodes.size()]), body);
 
         body.addStatement(getDoneMethod(getNodeId(node)));
diff --git 
a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/node/ForEachNodeVisitorBuilder.java
 
b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/node/ForEachNodeVisitorBuilder.java
index 0ddb803c05..1f450a5092 100644
--- 
a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/node/ForEachNodeVisitorBuilder.java
+++ 
b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/compiler/canonical/node/ForEachNodeVisitorBuilder.java
@@ -20,6 +20,7 @@ package org.jbpm.compiler.canonical.node;
 
 import org.jbpm.compiler.canonical.AbstractNodeVisitor;
 import org.jbpm.compiler.canonical.ForEachNodeVisitor;
+import org.jbpm.compiler.canonical.builtin.ReturnValueEvaluatorBuilderService;
 import org.jbpm.workflow.core.node.ForEachNode;
 import org.kie.api.definition.process.Node;
 
@@ -32,7 +33,7 @@ public class ForEachNodeVisitorBuilder implements 
NodeVisitorBuilder {
 
     @Override
     public AbstractNodeVisitor<? extends Node> 
visitor(NodeVisitorBuilderService nodeVisitorService, ClassLoader classLoader) {
-        return new ForEachNodeVisitor(nodeVisitorService);
+        return new ForEachNodeVisitor(nodeVisitorService, 
ReturnValueEvaluatorBuilderService.instance(classLoader));
     }
 
 }
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/KogitoProcessContextImpl.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/KogitoProcessContextImpl.java
index 5258ea7e2e..3411ce8975 100755
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/KogitoProcessContextImpl.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/KogitoProcessContextImpl.java
@@ -53,6 +53,14 @@ public class KogitoProcessContextImpl extends 
AbstractProcessContext implements
         return getVariable(variableId) != null;
     }
 
+    @Override
+    public Object getVariable(String variableId) {
+        if (contextData.containsKey(variableId)) {
+            return contextData.get(variableId);
+        }
+        return super.getVariable(variableId);
+    }
+
     @Override
     public KogitoProcessInstance getProcessInstance() {
         return (KogitoProcessInstance) super.getProcessInstance();
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/WorkflowElementIdentifierFactory.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/WorkflowElementIdentifierFactory.java
index 9c0e016f5f..434b4fdc83 100644
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/WorkflowElementIdentifierFactory.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/WorkflowElementIdentifierFactory.java
@@ -81,7 +81,7 @@ public class WorkflowElementIdentifierFactory implements 
WorkflowElementIdentifi
 
     @Override
     public String toSanitizeString() {
-        return toExternalFormat().replaceAll("-", "_");
+        return toExternalFormat().replaceAll("-", "_").replaceAll("\\.", "_");
     }
 
 }
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/ForEachNodeFactory.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/ForEachNodeFactory.java
index 501499530e..d32b223a42 100755
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/ForEachNodeFactory.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/factory/ForEachNodeFactory.java
@@ -21,6 +21,7 @@ package org.jbpm.ruleflow.core.factory;
 import org.jbpm.process.core.context.variable.Variable;
 import org.jbpm.process.core.datatype.DataType;
 import org.jbpm.process.instance.impl.Action;
+import org.jbpm.process.instance.impl.ReturnValueEvaluator;
 import org.jbpm.ruleflow.core.Metadata;
 import org.jbpm.ruleflow.core.RuleFlowNodeContainerFactory;
 import org.jbpm.workflow.core.NodeContainer;
@@ -38,6 +39,7 @@ public class ForEachNodeFactory<T extends 
RuleFlowNodeContainerFactory<T, ?>> ex
     public static final String METHOD_OUTPUT_VARIABLE = "outputVariable";
     public static final String METHOD_OUTPUT_TEMP = "tempVariable";
     public static final String METHOD_SEQUENTIAL = "sequential";
+    public static final String METHOD_COMPLETE_CONDITION = 
"completionCondition";
 
     public ForEachNodeFactory(T nodeContainerFactory, NodeContainer 
nodeContainer, WorkflowElementIdentifier id) {
         super(nodeContainerFactory, nodeContainer, new ForEachNode(id), id);
@@ -75,6 +77,11 @@ public class ForEachNodeFactory<T extends 
RuleFlowNodeContainerFactory<T, ?>> ex
         return this;
     }
 
+    public ForEachNodeFactory<T> completionCondition(ReturnValueEvaluator 
completionConditionExpression) {
+        
getForEachNode().setCompletionConditionExpression(completionConditionExpression);
+        return this;
+    }
+
     public ForEachNodeFactory<T> completionAction(Action completionAction) {
         getForEachNode().setCompletionAction(completionAction);
         return this;
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/core/impl/MultiInstanceSpecification.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/core/impl/MultiInstanceSpecification.java
index 45f1616821..b5fae80fca 100644
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/core/impl/MultiInstanceSpecification.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/core/impl/MultiInstanceSpecification.java
@@ -31,6 +31,8 @@ public class MultiInstanceSpecification implements 
Serializable {
     private String completionCondition;
     private boolean isSequential = false;
 
+    private String completionConditionLang;
+
     public boolean hasMultiInstanceInput() {
         return loopDataInputRef != null;
     }
@@ -67,6 +69,14 @@ public class MultiInstanceSpecification implements 
Serializable {
         return loopDataInputRef;
     }
 
+    public void setCompletionConditionLang(String completionConditionLang) {
+        this.completionConditionLang = completionConditionLang;
+    }
+
+    public String getCompletionConditionLang() {
+        return completionConditionLang;
+    }
+
     public void setCompletionCondition(String completionCondition) {
         this.completionCondition = completionCondition;
     }
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/core/node/ForEachNode.java 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/core/node/ForEachNode.java
index a53a6aff11..2bacf60430 100755
--- a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/core/node/ForEachNode.java
+++ b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/core/node/ForEachNode.java
@@ -27,6 +27,7 @@ import org.jbpm.process.core.context.variable.Variable;
 import org.jbpm.process.core.context.variable.VariableScope;
 import org.jbpm.process.core.datatype.DataType;
 import org.jbpm.process.instance.impl.Action;
+import org.jbpm.process.instance.impl.ReturnValueEvaluator;
 import org.jbpm.ruleflow.core.WorkflowElementIdentifierFactory;
 import org.jbpm.workflow.core.Node;
 import org.jbpm.workflow.core.impl.ConnectionImpl;
@@ -51,7 +52,7 @@ public class ForEachNode extends CompositeContextNode {
     private String outputVariableName;
     private String collectionExpression;
     private String outputCollectionExpression;
-    private String completionConditionExpression;
+    private ReturnValueEvaluator completionConditionExpression;
 
     private Action finishAction;
     private boolean waitForCompletion = true;
@@ -345,12 +346,12 @@ public class ForEachNode extends CompositeContextNode {
         return ctx;
     }
 
-    public String getCompletionConditionExpression() {
+    public ReturnValueEvaluator getCompletionConditionExpression() {
         return completionConditionExpression;
     }
 
     public void setCompletionConditionExpression(
-            String completionConditionExpression) {
+            ReturnValueEvaluator completionConditionExpression) {
         this.completionConditionExpression = completionConditionExpression;
     }
 
@@ -361,4 +362,8 @@ public class ForEachNode extends CompositeContextNode {
     public void setSequential(boolean sequential) {
         this.getMultiInstanceSpecification().setSequential(sequential);
     }
+
+    public boolean hasCompletionCondition() {
+        return completionConditionExpression != null;
+    }
 }
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/ForEachNodeInstance.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/ForEachNodeInstance.java
index 0b5df806ff..453c700fbb 100755
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/ForEachNodeInstance.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/ForEachNodeInstance.java
@@ -31,8 +31,10 @@ import org.jbpm.process.core.ContextContainer;
 import org.jbpm.process.core.context.variable.VariableScope;
 import org.jbpm.process.instance.ContextInstance;
 import org.jbpm.process.instance.ContextableInstance;
+import org.jbpm.process.instance.KogitoProcessContextImpl;
 import org.jbpm.process.instance.context.variable.VariableScopeInstance;
 import org.jbpm.process.instance.impl.Action;
+import org.jbpm.process.instance.impl.ReturnValueEvaluator;
 import org.jbpm.ruleflow.core.Metadata;
 import org.jbpm.util.ContextFactory;
 import org.jbpm.workflow.core.Node;
@@ -239,22 +241,18 @@ public class ForEachNodeInstance extends 
CompositeContextNodeInstance {
 
             Map<String, Object> tempVariables = new HashMap<>();
             if (getForEachNode().getOutputVariableName() != null) {
+                Object outputVariable = 
from.getVariable(getForEachNode().getOutputVariableName());
 
                 Collection<Object> outputCollection = (Collection<Object>) 
this.getVariable(TEMP_OUTPUT_VAR);
                 if (outputCollection == null) {
                     outputCollection = new ArrayList<>();
-
-                }
-                Object outputVariable = 
from.getVariable(getForEachNode().getOutputVariableName());
-                if (outputVariable != null) {
-                    outputCollection.add(outputVariable);
                 }
 
+                outputCollection.add(outputVariable);
+
                 setVariable(TEMP_OUTPUT_VAR, outputCollection);
-                if (getForEachNode().getOutputVariableName() != null) {
-                    //  add temp collection under actual output name for 
completion condition evaluation
-                    
tempVariables.put(getForEachNode().getOutputVariableName(), outputVariable);
-                }
+                tempVariables.put(getForEachNode().getOutputVariableName(), 
outputVariable);
+
                 String outputCollectionName = 
getForEachNode().getOutputCollectionExpression();
                 if (outputCollectionName != null) {
                     tempVariables.put(outputCollectionName, outputCollection);
@@ -262,7 +260,7 @@ public class ForEachNodeInstance extends 
CompositeContextNodeInstance {
 
             }
 
-            boolean isCompletionConditionMet = 
evaluateCompletionCondition(getForEachNode().getCompletionConditionExpression(),
 tempVariables);
+            boolean isCompletionConditionMet = 
getForEachNode().hasCompletionCondition() && 
evaluateCompletionCondition(getForEachNode().getCompletionConditionExpression(),
 tempVariables);
             if (isSequential() && !isCompletionConditionMet && 
!areNodeInstancesCompleted()) {
                 getFirstCompositeNodeInstance()
                         .ifPresent(nodeInstance -> {
@@ -319,21 +317,13 @@ public class ForEachNodeInstance extends 
CompositeContextNodeInstance {
             return getNodeInstanceContainer().getNodeInstances().size() == 1;
         }
 
-        private boolean evaluateCompletionCondition(String expression, 
Map<String, Object> tempVariables) {
-            if (expression == null || expression.isEmpty()) {
-                return false;
-            } else {
-                try {
-                    Object result = 
MVELProcessHelper.evaluator().eval(expression,
-                            new ForEachNodeInstanceResolverFactory(this, 
tempVariables));
-                    if (!(result instanceof Boolean)) {
-                        throw new IllegalArgumentException("Completion 
condition expression must return boolean values: " +
-                                result + " for expression " + expression);
-                    }
-                    return ((Boolean) result).booleanValue();
-                } catch (Exception t) {
-                    throw new IllegalArgumentException("Could not evaluate 
completion condition  " + expression, t);
-                }
+        private boolean evaluateCompletionCondition(ReturnValueEvaluator 
completeConditionEvaluator, Map<String, Object> tempVariables) {
+            try {
+                KogitoProcessContextImpl context = (KogitoProcessContextImpl) 
ContextFactory.fromNode(this);
+                context.setContextData(tempVariables);
+                return (Boolean) completeConditionEvaluator.evaluate(context);
+            } catch (Exception t) {
+                throw new IllegalArgumentException("Could not evaluate 
completion condition  " + completeConditionEvaluator, t);
             }
         }
 
diff --git 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopBoundaryTimer.bpmn2 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopBoundaryTimer.bpmn2
similarity index 99%
rename from 
jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopBoundaryTimer.bpmn2
rename to 
jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopBoundaryTimer.bpmn2
index 6e64db3370..979afdd569 100755
--- 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopBoundaryTimer.bpmn2
+++ 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopBoundaryTimer.bpmn2
@@ -36,7 +36,7 @@
   <itemDefinition id="_sub_multiInstanceItemType" />
 
   <process processType="Private" isExecutable="true" 
id="MultiInstanceLoopBoundaryTimer" 
-    name="BoundaryTimerMultipleInstances" 
tns:packageName="org.jbpm.bpmn2.intermediate" tns:version="1.0" >
+    name="BoundaryTimerMultipleInstances" 
tns:packageName="org.jbpm.bpmn2.loop" tns:version="1.0" >
 
     <!-- process variables -->
     <property id="actorNameList" itemSubjectRef="_actorNameListItem"/>
diff --git 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsProcessSequential.bpmn2
 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsProcessSequential.bpmn2
similarity index 97%
rename from 
jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsProcessSequential.bpmn2
rename to 
jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsProcessSequential.bpmn2
index 6247abfc0b..0e274b0f33 100644
--- 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsProcessSequential.bpmn2
+++ 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsProcessSequential.bpmn2
@@ -34,7 +34,8 @@
 
   <itemDefinition id="_2_multiInstanceItemType" structureRef="String" />
 
-  <process processType="Private" isExecutable="true" 
id="MultiInstanceLoopCharacteristicsProcess" 
name="MultiInstanceLoopCharacteristics SubProcess" >
+  <process processType="Private" isExecutable="true" 
id="MultiInstanceLoopCharacteristicsProcessSequential" 
+    tns:packageName="org.jbpm.bpmn2.loop" 
name="MultiInstanceLoopCharacteristics SubProcess" >
 
     <!-- process variables -->
     <property id="list" itemSubjectRef="_listItem"/>
diff --git 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsProcessWithOutputAndScripts.bpmn2
 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsProcessWithOutputAndScripts.bpmn2
similarity index 98%
rename from 
jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsProcessWithOutputAndScripts.bpmn2
rename to 
jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsProcessWithOutputAndScripts.bpmn2
index 187d0f8d1a..c3b954cc95 100755
--- 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsProcessWithOutputAndScripts.bpmn2
+++ 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsProcessWithOutputAndScripts.bpmn2
@@ -23,7 +23,7 @@
   <itemDefinition id="_listItemOut" structureRef="java.util.List"/>
   <itemDefinition id="_2_multiInstanceItemType" structureRef="String" />
   <itemDefinition id="_2_multiInstanceItemOutType" structureRef="String" />
-  <process id="MultiInstanceLoopCharacteristicsProcessWithOutputAndScripts" 
tns:packageName="org.jbpm.bpmn2.flow" name="Multiple instances sub-process" 
isExecutable="true" processType="Private">
+  <process id="MultiInstanceLoopCharacteristicsProcessWithOutputAndScripts" 
tns:packageName="org.jbpm.bpmn2.loop" name="Multiple instances sub-process" 
isExecutable="true" processType="Private">
     <property id="list" itemSubjectRef="_listItem"/>
     <property id="listOut" itemSubjectRef="_listItemOut"/>
     <property id="scriptList" itemSubjectRef="_listItem"/>
@@ -77,7 +77,7 @@
         <script>
           System.out.println( &quot;start item:&quot; + item ); item = item + 
&quot; changed&quot;;
           System.out.println(&quot;update item to:&quot; + item);
-          context.setVariable(&quot;itemOut&quot;, item);
+          kcontext.setVariable(&quot;itemOut&quot;, item);
 </script>
       </scriptTask>
       <sequenceFlow id="_2-2-4-_2-2-3" sourceRef="_2-2-4" targetRef="_2-2-3"/>
diff --git 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsTask.bpmn2
 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsTask.bpmn2
similarity index 96%
rename from 
jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsTask.bpmn2
rename to 
jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsTask.bpmn2
index e0d7802b44..75d89de2c4 100755
--- 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsTask.bpmn2
+++ 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsTask.bpmn2
@@ -34,7 +34,8 @@
 
   <itemDefinition id="_2_multiInstanceItemType" structureRef="String" />
 
-  <process processType="Private" isExecutable="true" 
id="MultiInstanceLoopCharacteristicsTask" 
name="MultiInstanceLoopCharacteristics SubProcess" >
+  <process processType="Private" isExecutable="true" 
id="MultiInstanceLoopCharacteristicsTask" 
+    tns:packageName="org.jbpm.bpmn2.loop" 
name="MultiInstanceLoopCharacteristics SubProcess" >
 
     <!-- process variables -->
     <property id="list" itemSubjectRef="_listItem"/>
diff --git 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsTaskSequential.bpmn2
 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsTaskSequential.bpmn2
similarity index 96%
rename from 
jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsTaskSequential.bpmn2
rename to 
jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsTaskSequential.bpmn2
index c18ad7c802..5a61046d04 100644
--- 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsTaskSequential.bpmn2
+++ 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsTaskSequential.bpmn2
@@ -34,7 +34,7 @@
 
   <itemDefinition id="_2_multiInstanceItemType" structureRef="String" />
 
-  <process processType="Private" isExecutable="true" 
id="MultiInstanceLoopCharacteristicsTask" 
name="MultiInstanceLoopCharacteristics SubProcess" >
+  <process processType="Private" isExecutable="true" 
id="MultiInstanceLoopCharacteristicsTaskSequential" 
tns:packageName="org.jbpm.bpmn2.loop" name="MultiInstanceLoopCharacteristics 
SubProcess" >
 
     <!-- process variables -->
     <property id="list" itemSubjectRef="_listItem"/>
diff --git 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential.bpmn2
 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential.bpmn2
similarity index 90%
copy from 
jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential.bpmn2
copy to 
jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential.bpmn2
index 15a95166b0..0b8a32113a 100644
--- 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential.bpmn2
+++ 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential.bpmn2
@@ -35,7 +35,7 @@
   <itemDefinition id="_2_multiInstanceItemType" structureRef="String" />
   <itemDefinition id="_2_multiInstanceItemOutType" structureRef="String" />
 
-  <process processType="Private" isExecutable="true" 
id="MultiInstanceLoopCharacteristicsTask" 
name="MultiInstanceLoopCharacteristics SubProcess" >
+  <process processType="Private" isExecutable="true" 
id="MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential" 
tns:packageName="org.jbpm.bpmn2.loop" name="MultiInstanceLoopCharacteristics 
SubProcess" >
 
     <!-- process variables -->
     <property id="list" itemSubjectRef="_listItem"/>
@@ -53,6 +53,7 @@
         <dataInput id="_2_input" name="MultiInstanceInput" />
         <dataInput id="_2_item" name="Item" />
         <dataOutput id="_2_listOutOutput" name="listOut"/>
+        <dataOutput id="_2_itemOut" name="itemOut"/>
         <inputSet>
           <dataInputRefs>_2_item</dataInputRefs>
         </inputSet>
@@ -68,6 +69,14 @@
         <sourceRef>list</sourceRef>
         <targetRef>_2_input</targetRef>
       </dataInputAssociation>
+      <dataOutputAssociation>
+        <sourceRef>_2_listOutOutput</sourceRef>
+        <targetRef>listOut</targetRef>
+      </dataOutputAssociation>
+      <dataOutputAssociation>
+        <sourceRef>_2_itemOut</sourceRef>
+        <targetRef>itemOut</targetRef>
+      </dataOutputAssociation>
       <potentialOwner>
         <resourceAssignmentExpression>
           <formalExpression>john</formalExpression>
diff --git 
a/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/subprocess/BPMN2-EventSubprocessConditional.bpmn2
 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/subprocess/BPMN2-EventSubprocessConditional.bpmn2
index 9b309e6518..b99c255f61 100755
--- 
a/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/subprocess/BPMN2-EventSubprocessConditional.bpmn2
+++ 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/subprocess/BPMN2-EventSubprocessConditional.bpmn2
@@ -32,6 +32,11 @@
     <bpmn2:userTask id="UserTask_1" name="User Task 1">
       <bpmn2:incoming>SequenceFlow_2</bpmn2:incoming>
       <bpmn2:outgoing>SequenceFlow_1</bpmn2:outgoing>
+      <bpmn2:potentialOwner id="_1aVcYLe_EDyttMyrW6hRzg">
+        <bpmn2:resourceAssignmentExpression id="_1aVcYbe_EDyttMyrW6hRzg">
+          <bpmn2:formalExpression>john</bpmn2:formalExpression>
+        </bpmn2:resourceAssignmentExpression>
+      </bpmn2:potentialOwner>
     </bpmn2:userTask>
     <bpmn2:sequenceFlow id="SequenceFlow_2" tns:priority="1" name="" 
sourceRef="StartEvent_1" targetRef="UserTask_1"/>
     <bpmn2:subProcess id="SubProcess_1" name="Sub Process 1" 
triggeredByEvent="true" >
diff --git 
a/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/subprocess/BPMN2-EventSubprocessMessage.bpmn2
 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/subprocess/BPMN2-EventSubprocessMessage.bpmn2
index 82df93c8a4..e3b4980dd0 100755
--- 
a/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/subprocess/BPMN2-EventSubprocessMessage.bpmn2
+++ 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/subprocess/BPMN2-EventSubprocessMessage.bpmn2
@@ -31,7 +31,11 @@
     </bpmn2:endEvent>
     <bpmn2:userTask id="UserTask_1" name="User Task 1">
       <bpmn2:incoming>SequenceFlow_2</bpmn2:incoming>
-      <bpmn2:outgoing>SequenceFlow_1</bpmn2:outgoing>
+      <bpmn2:outgoing>SequenceFlow_1</bpmn2:outgoing>      
<bpmn2:potentialOwner id="_1aVcYLe_EDyttMyrW6hRzg">
+      <bpmn2:resourceAssignmentExpression id="_1aVcYbe_EDyttMyrW6hRzg">
+          <bpmn2:formalExpression>john</bpmn2:formalExpression>
+        </bpmn2:resourceAssignmentExpression>
+      </bpmn2:potentialOwner>
     </bpmn2:userTask>
     <bpmn2:sequenceFlow id="SequenceFlow_2" tns:priority="1" name="" 
sourceRef="StartEvent_1" targetRef="UserTask_1"/>
     <bpmn2:subProcess id="SubProcess_1" name="Sub Process 1" 
triggeredByEvent="true" >
diff --git a/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/FlowTest.java 
b/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/FlowTest.java
index 3e9e883feb..aaa0fe5a16 100755
--- a/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/FlowTest.java
+++ b/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/FlowTest.java
@@ -21,6 +21,7 @@ package org.jbpm.bpmn2;
 import java.io.ByteArrayInputStream;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -28,6 +29,8 @@ import java.util.Map;
 
 import javax.xml.parsers.DocumentBuilderFactory;
 
+import org.jbpm.bpmn2.loop.MultiInstanceLoopCharacteristicsTaskModel;
+import org.jbpm.bpmn2.loop.MultiInstanceLoopCharacteristicsTaskProcess;
 import org.jbpm.bpmn2.objects.TestWorkItemHandler;
 import org.jbpm.process.core.context.variable.VariableScope;
 import org.jbpm.process.instance.InternalProcessRuntime;
@@ -35,6 +38,7 @@ import 
org.jbpm.process.instance.context.variable.VariableScopeInstance;
 import org.jbpm.process.instance.impl.demo.SystemOutWorkItemHandler;
 import org.jbpm.process.instance.impl.humantask.InternalHumanTaskWorkItem;
 import org.jbpm.test.util.NodeLeftCountDownProcessEventListener;
+import org.jbpm.test.utils.ProcessTestHelper;
 import org.jbpm.workflow.instance.impl.NodeInstanceImpl;
 import org.jbpm.workflow.instance.impl.WorkflowProcessInstanceImpl;
 import org.jbpm.workflow.instance.node.CompositeContextNodeInstance;
@@ -53,6 +57,7 @@ import org.kie.api.runtime.Context;
 import org.kie.api.runtime.KieSession;
 import org.kie.api.runtime.process.NodeInstance;
 import org.kie.internal.command.RegistryContext;
+import org.kie.kogito.Application;
 import org.kie.kogito.internal.process.event.DefaultKogitoProcessEventListener;
 import org.kie.kogito.internal.process.runtime.KogitoProcessInstance;
 import org.kie.kogito.internal.process.runtime.KogitoProcessRuntime;
@@ -1241,17 +1246,25 @@ public class FlowTest extends JbpmBpmn2TestCase {
 
     @Test
     public void testMultiInstanceLoopCharacteristicsTask() throws Exception {
-        kruntime = 
createKogitoProcessRuntime("BPMN2-MultiInstanceLoopCharacteristicsTask.bpmn2");
-        kruntime.getKogitoWorkItemManager().registerWorkItemHandler("Human 
Task",
-                new SystemOutWorkItemHandler());
-        Map<String, Object> params = new HashMap<>();
-        List<String> myList = new ArrayList<>();
-        myList.add("First Item");
-        myList.add("Second Item");
-        params.put("list", myList);
-        KogitoProcessInstance processInstance = kruntime.startProcess(
-                "MultiInstanceLoopCharacteristicsTask", params);
-        assertProcessInstanceCompleted(processInstance);
+        Application app = ProcessTestHelper.newApplication();
+        TestWorkItemHandler handler = new TestWorkItemHandler();
+        ProcessTestHelper.registerHandler(app, "Human Task", handler);
+
+        
org.kie.kogito.process.Process<MultiInstanceLoopCharacteristicsTaskModel> 
definition = MultiInstanceLoopCharacteristicsTaskProcess.newProcess(app);
+        MultiInstanceLoopCharacteristicsTaskModel model = 
definition.createModel();
+        model.setList(new ArrayList<>(List.of("First Item", "Second Item")));
+
+        
org.kie.kogito.process.ProcessInstance<MultiInstanceLoopCharacteristicsTaskModel>
 instance = definition.createInstance(model);
+        instance.start();
+
+        List<KogitoWorkItem> workItems = handler.getWorkItems();
+        assertThat(workItems).isNotNull().hasSize(2);
+        assertThat(workItems.get(0).getParameter("Item")).isEqualTo("First 
Item");
+        assertThat(workItems.get(1).getParameter("Item")).isEqualTo("Second 
Item");
+        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
 
     }
 
diff --git 
a/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/IntermediateEventTest.java 
b/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/IntermediateEventTest.java
index b5e1687195..1d24ef1aa4 100755
--- a/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/IntermediateEventTest.java
+++ b/jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/IntermediateEventTest.java
@@ -64,10 +64,22 @@ import 
org.jbpm.bpmn2.intermediate.IntermediateThrowEventMessageModel;
 import org.jbpm.bpmn2.intermediate.IntermediateThrowEventMessageProcess;
 import 
org.jbpm.bpmn2.intermediate.IntermediateThrowEventMessageWithTransformationModel;
 import 
org.jbpm.bpmn2.intermediate.IntermediateThrowEventMessageWithTransformationProcess;
-import org.jbpm.bpmn2.intermediate.IntermediateThrowEventSignalModel;
-import org.jbpm.bpmn2.intermediate.IntermediateThrowEventSignalProcess;
+import org.jbpm.bpmn2.loop.MultiInstanceLoopBoundaryTimerModel;
+import org.jbpm.bpmn2.loop.MultiInstanceLoopBoundaryTimerProcess;
+import 
org.jbpm.bpmn2.loop.MultiInstanceLoopCharacteristicsProcessSequentialModel;
+import 
org.jbpm.bpmn2.loop.MultiInstanceLoopCharacteristicsProcessSequentialProcess;
+import 
org.jbpm.bpmn2.loop.MultiInstanceLoopCharacteristicsProcessWithOutputAndScriptsModel;
+import 
org.jbpm.bpmn2.loop.MultiInstanceLoopCharacteristicsProcessWithOutputAndScriptsProcess;
+import org.jbpm.bpmn2.loop.MultiInstanceLoopCharacteristicsTaskModel;
+import org.jbpm.bpmn2.loop.MultiInstanceLoopCharacteristicsTaskProcess;
+import org.jbpm.bpmn2.loop.MultiInstanceLoopCharacteristicsTaskSequentialModel;
+import 
org.jbpm.bpmn2.loop.MultiInstanceLoopCharacteristicsTaskSequentialProcess;
+import 
org.jbpm.bpmn2.loop.MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequentialModel;
+import 
org.jbpm.bpmn2.loop.MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequentialProcess;
 import org.jbpm.bpmn2.objects.Person;
 import org.jbpm.bpmn2.objects.TestWorkItemHandler;
+import org.jbpm.bpmn2.start.IntermediateThrowEventSignalModel;
+import org.jbpm.bpmn2.start.IntermediateThrowEventSignalProcess;
 import org.jbpm.bpmn2.subprocess.EventSubprocessConditionalModel;
 import org.jbpm.bpmn2.subprocess.EventSubprocessConditionalProcess;
 import org.jbpm.bpmn2.subprocess.EventSubprocessMessageModel;
@@ -768,7 +780,7 @@ public class IntermediateEventTest extends 
JbpmBpmn2TestCase {
 
         KogitoWorkItem workItem = workItemHandler.getWorkItem();
         assertThat(workItem).isNotNull();
-        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+        ProcessTestHelper.completeWorkItem(instance, Collections.emptyMap(), 
"john");
 
         
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
 
@@ -890,13 +902,15 @@ public class IntermediateEventTest extends 
JbpmBpmn2TestCase {
         KogitoWorkItem workItem = workItemHandler.getWorkItem();
         assertThat(workItem).isNotNull();
 
-        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+        ProcessTestHelper.completeWorkItem(instance, Collections.emptyMap(), 
"john");
 
         
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
 
         
assertThat(trackerListener.tracked()).anyMatch(ProcessTestHelper.triggered("start"))
-                .anyMatch(ProcessTestHelper.triggered("User Task 
1")).anyMatch(ProcessTestHelper.triggered("end"))
-                .anyMatch(ProcessTestHelper.left("Sub Process 
1")).anyMatch(ProcessTestHelper.left("start-sub"))
+                .anyMatch(ProcessTestHelper.triggered("User Task 1"))
+                .anyMatch(ProcessTestHelper.triggered("end"))
+                .anyMatch(ProcessTestHelper.left("Sub Process 1"))
+                .anyMatch(ProcessTestHelper.left("start-sub"))
                 .anyMatch(ProcessTestHelper.triggered("Script Task 1"))
                 .anyMatch(ProcessTestHelper.triggered("end-sub"));
 
@@ -1924,26 +1938,155 @@ public class IntermediateEventTest extends 
JbpmBpmn2TestCase {
     }
 
     @Test
-    public void testTimerMultipleInstances() throws Exception {
+    public void testMultiInstanceLoopBoundaryTimer() throws Exception {
+        Application app = ProcessTestHelper.newApplication();
         NodeLeftCountDownProcessEventListener countDownListener = new 
NodeLeftCountDownProcessEventListener("timer", 3);
-        kruntime = 
createKogitoProcessRuntime("BPMN2-MultiInstanceLoopBoundaryTimer.bpmn2");
-        kruntime.getProcessEventManager().addEventListener(countDownListener);
+        ProcessTestHelper.registerProcessEventListener(app, countDownListener);
         TestWorkItemHandler handler = new TestWorkItemHandler();
+        ProcessTestHelper.registerHandler(app, "Human Task", handler);
 
-        kruntime.getKogitoWorkItemManager().registerWorkItemHandler("Human 
Task", handler);
-        KogitoProcessInstance processInstance = 
kruntime.startProcess("MultiInstanceLoopBoundaryTimer");
-        assertProcessInstanceActive(processInstance);
+        org.kie.kogito.process.Process<MultiInstanceLoopBoundaryTimerModel> 
definition = MultiInstanceLoopBoundaryTimerProcess.newProcess(app);
+        
org.kie.kogito.process.ProcessInstance<MultiInstanceLoopBoundaryTimerModel> 
instance = definition.createInstance(definition.createModel());
+        instance.start();
+
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_ACTIVE);
 
         countDownListener.waitTillCompleted();
 
         List<KogitoWorkItem> workItems = handler.getWorkItems();
         assertThat(workItems).isNotNull().hasSize(3);
 
-        for (KogitoWorkItem wi : workItems) {
-            
kruntime.getKogitoWorkItemManager().completeWorkItem(wi.getStringId(), null);
-        }
+        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+        ProcessTestHelper.completeWorkItem(instance, "mary", 
Collections.emptyMap());
+        ProcessTestHelper.completeWorkItem(instance, "krisv", 
Collections.emptyMap());
 
-        assertProcessInstanceFinished(processInstance, kruntime);
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
+    }
+
+    @Test
+    public void testMultiInstanceLoopCharacteristicsProcessSequential() throws 
Exception {
+        Application app = ProcessTestHelper.newApplication();
+        TestWorkItemHandler handler = new TestWorkItemHandler();
+        ProcessTestHelper.registerHandler(app, "Human Task", handler);
+
+        
org.kie.kogito.process.Process<MultiInstanceLoopCharacteristicsProcessSequentialModel>
 definition = 
MultiInstanceLoopCharacteristicsProcessSequentialProcess.newProcess(app);
+        MultiInstanceLoopCharacteristicsProcessSequentialModel model = 
definition.createModel();
+        model.setList(List.of(1, 2, 3));
+        
org.kie.kogito.process.ProcessInstance<MultiInstanceLoopCharacteristicsProcessSequentialModel>
 instance = definition.createInstance(model);
+        instance.start();
+
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_ACTIVE);
+
+        assertThat(handler.getWorkItems()).isNotNull().hasSize(1);
+        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+
+        assertThat(handler.getWorkItems()).isNotNull().hasSize(1);
+        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+
+        assertThat(handler.getWorkItems()).isNotNull().hasSize(1);
+        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
+    }
+
+    @Test
+    public void 
testMultiInstanceLoopCharacteristicsProcessWithOutputAndScripts() throws 
Exception {
+        Application app = ProcessTestHelper.newApplication();
+        TestWorkItemHandler handler = new TestWorkItemHandler();
+        ProcessTestHelper.registerHandler(app, "Human Task", handler);
+
+        
org.kie.kogito.process.Process<MultiInstanceLoopCharacteristicsProcessWithOutputAndScriptsModel>
 definition =
+                
MultiInstanceLoopCharacteristicsProcessWithOutputAndScriptsProcess.newProcess(app);
+        MultiInstanceLoopCharacteristicsProcessWithOutputAndScriptsModel model 
= definition.createModel();
+        model.setList(new ArrayList<>(List.of("1", "2", "3")));
+        model.setScriptList(new ArrayList<String>());
+        
org.kie.kogito.process.ProcessInstance<MultiInstanceLoopCharacteristicsProcessWithOutputAndScriptsModel>
 instance = definition.createInstance(model);
+        instance.start();
+
+        assertThat(instance.variables().getListOut()).containsExactly("1 
changed", "2 changed", "3 changed");
+
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
+    }
+
+    @Test
+    public void testMultiInstanceLoopCharacteristicsTask() throws Exception {
+        Application app = ProcessTestHelper.newApplication();
+        TestWorkItemHandler handler = new TestWorkItemHandler();
+        ProcessTestHelper.registerHandler(app, "Human Task", handler);
+
+        
org.kie.kogito.process.Process<MultiInstanceLoopCharacteristicsTaskModel> 
definition = MultiInstanceLoopCharacteristicsTaskProcess.newProcess(app);
+        MultiInstanceLoopCharacteristicsTaskModel model = 
definition.createModel();
+        model.setList(new ArrayList<>(List.of("1", "2", "3")));
+
+        
org.kie.kogito.process.ProcessInstance<MultiInstanceLoopCharacteristicsTaskModel>
 instance = definition.createInstance(model);
+        instance.start();
+
+        List<KogitoWorkItem> workItems = handler.getWorkItems();
+        assertThat(workItems).isNotNull().hasSize(3);
+        assertThat(workItems.get(0).getParameter("Item")).isEqualTo("1");
+        assertThat(workItems.get(1).getParameter("Item")).isEqualTo("2");
+        assertThat(workItems.get(2).getParameter("Item")).isEqualTo("3");
+        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
+    }
+
+    @Test
+    public void testMultiInstanceLoopCharacteristicsTaskSequential() throws 
Exception {
+        Application app = ProcessTestHelper.newApplication();
+        TestWorkItemHandler handler = new TestWorkItemHandler();
+        ProcessTestHelper.registerHandler(app, "Human Task", handler);
+
+        
org.kie.kogito.process.Process<MultiInstanceLoopCharacteristicsTaskSequentialModel>
 definition = 
MultiInstanceLoopCharacteristicsTaskSequentialProcess.newProcess(app);
+        MultiInstanceLoopCharacteristicsTaskSequentialModel model = 
definition.createModel();
+        model.setList(new ArrayList<>(List.of("1", "2", "3")));
+
+        
org.kie.kogito.process.ProcessInstance<MultiInstanceLoopCharacteristicsTaskSequentialModel>
 instance = definition.createInstance(model);
+        instance.start();
+
+        List<KogitoWorkItem> workItems = null;
+        workItems = handler.getWorkItems();
+        assertThat(workItems).isNotNull().hasSize(1);
+        assertThat(workItems.get(0).getParameter("Item")).isEqualTo("1");
+        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+
+        workItems = handler.getWorkItems();
+        assertThat(workItems).isNotNull().hasSize(1);
+        assertThat(workItems.get(0).getParameter("Item")).isEqualTo("2");
+        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+
+        workItems = handler.getWorkItems();
+        assertThat(workItems).isNotNull().hasSize(1);
+        assertThat(workItems.get(0).getParameter("Item")).isEqualTo("3");
+        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
+    }
+
+    @Test
+    public void 
testMultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential() throws 
Exception {
+        Application app = ProcessTestHelper.newApplication();
+        TestWorkItemHandler handler = new TestWorkItemHandler();
+        ProcessTestHelper.registerHandler(app, "Human Task", handler);
+
+        
org.kie.kogito.process.Process<MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequentialModel>
 definition =
+                
MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequentialProcess.newProcess(app);
+        MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequentialModel 
model = definition.createModel();
+        model.setList(new ArrayList<>(List.of("1", "2", "3")));
+        model.setListOut(new ArrayList());
+
+        
org.kie.kogito.process.ProcessInstance<MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequentialModel>
 instance = definition.createInstance(model);
+        instance.start();
+
+        List<KogitoWorkItem> workItems = null;
+        workItems = handler.getWorkItems();
+        assertThat(workItems).isNotNull().hasSize(1);
+        assertThat(workItems.get(0).getParameter("Item")).isEqualTo("1");
+        ProcessTestHelper.completeWorkItem(instance, "john", 
Collections.emptyMap());
+
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
+        assertThat(instance.variables().getListOut()).hasSize(1);
     }
 
     @Test
diff --git 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential.bpmn2
 
b/jbpm/jbpm-tools/jbpm-tools-maven-plugin/src/test/resources/unit/project/src/main/bpmn/BPMN2-MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential.bpmn2
similarity index 91%
rename from 
jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential.bpmn2
rename to 
jbpm/jbpm-tools/jbpm-tools-maven-plugin/src/test/resources/unit/project/src/main/bpmn/BPMN2-MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential.bpmn2
index 15a95166b0..bce624ffd8 100644
--- 
a/jbpm/jbpm-tests/src/test/resources/BPMN2-MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential.bpmn2
+++ 
b/jbpm/jbpm-tools/jbpm-tools-maven-plugin/src/test/resources/unit/project/src/main/bpmn/BPMN2-MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential.bpmn2
@@ -35,7 +35,7 @@
   <itemDefinition id="_2_multiInstanceItemType" structureRef="String" />
   <itemDefinition id="_2_multiInstanceItemOutType" structureRef="String" />
 
-  <process processType="Private" isExecutable="true" 
id="MultiInstanceLoopCharacteristicsTask" 
name="MultiInstanceLoopCharacteristics SubProcess" >
+  <process processType="Private" isExecutable="true" 
id="MultiInstanceLoopCharacteristicsTaskWithOutputCmpCondSequential" 
tns:packageName="org.jbpm.bpmn2.loop" name="MultiInstanceLoopCharacteristics 
SubProcess" >
 
     <!-- process variables -->
     <property id="list" itemSubjectRef="_listItem"/>
@@ -68,6 +68,14 @@
         <sourceRef>list</sourceRef>
         <targetRef>_2_input</targetRef>
       </dataInputAssociation>
+      <dataOutputAssociation>
+        <sourceRef>_2_listOutOutput</sourceRef>
+        <targetRef>listOut</targetRef>
+      </dataOutputAssociation>
+      <dataOutputAssociation>
+        <sourceRef>_2_itemOut</sourceRef>
+        <targetRef>itemOut</targetRef>
+      </dataOutputAssociation>
       <potentialOwner>
         <resourceAssignmentExpression>
           <formalExpression>john</formalExpression>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to