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

porcelli 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 8358246fe5 [incubator-kie-issues-1555] Multiple sub process instances 
cancelled by the same timer. (#3745)
8358246fe5 is described below

commit 8358246fe5c64609b7254c2591b2622894d97e5b
Author: Enrique <[email protected]>
AuthorDate: Fri Nov 1 16:40:01 2024 +0100

    [incubator-kie-issues-1555] Multiple sub process instances cancelled by the 
same timer. (#3745)
    
    * [incubator-kie-issues-1555] Multiple sub process instances cancelled by 
the same timer.
    
    * fix tests
    
    * fix Composite rest
---
 .../util/DefaultCountDownProcessEventListener.java |  14 ++
 .../jbpm/process/core/event/EventTypeFilter.java   | 112 ++++++++--
 .../impl/actions/AbstractNodeInstanceAction.java   |   4 +-
 .../jbpm/ruleflow/core/RuleFlowProcessFactory.java |   7 +-
 .../instance/impl/WorkflowProcessInstanceImpl.java | 197 +++++++++++++----
 .../instance/node/BoundaryEventNodeInstance.java   |   2 +-
 .../instance/node/CompositeNodeInstance.java       |  15 +-
 .../instance/node/StateBasedNodeInstance.java      |   7 +-
 .../workflow/instance/node/TimerNodeInstance.java  |   3 +-
 ...-MultiInstanceLoopSubprocessBoundaryTimer.bpmn2 | 245 +++++++++++++++++++++
 .../java/org/jbpm/bpmn2/IntermediateEventTest.java |  34 ++-
 11 files changed, 566 insertions(+), 74 deletions(-)

diff --git 
a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/test/util/DefaultCountDownProcessEventListener.java
 
b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/test/util/DefaultCountDownProcessEventListener.java
index b00a151e44..777a972eac 100644
--- 
a/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/test/util/DefaultCountDownProcessEventListener.java
+++ 
b/jbpm/jbpm-flow-builder/src/main/java/org/jbpm/test/util/DefaultCountDownProcessEventListener.java
@@ -43,6 +43,20 @@ public class DefaultCountDownProcessEventListener extends 
DefaultKogitoProcessEv
         return waitTillCompleted(10000);
     }
 
+    public boolean await() {
+        try {
+            latch.await();
+            return true;
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            logger.error("Interrputed thread while waiting for all triggers", 
e);
+            return false;
+        } catch (Exception e) {
+            logger.error("Error during waiting state", e);
+            return false;
+        }
+    }
+
     public boolean waitTillCompleted(long timeOut) {
         try {
             return latch.await(timeOut, TimeUnit.MILLISECONDS);
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/event/EventTypeFilter.java 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/event/EventTypeFilter.java
index 01ee3388e2..6868325465 100755
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/event/EventTypeFilter.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/event/EventTypeFilter.java
@@ -19,10 +19,19 @@
 package org.jbpm.process.core.event;
 
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.function.Function;
+import java.util.regex.Matcher;
 
 import org.jbpm.process.core.correlation.CorrelationInstance;
 import org.jbpm.process.core.correlation.CorrelationManager;
+import org.jbpm.util.PatternConstants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -55,37 +64,106 @@ public class EventTypeFilter implements EventFilter, 
Serializable {
         this.type = type;
     }
 
+    public void setMessageRef(String messageRef) {
+        this.messageRef = messageRef;
+    }
+
     public String toString() {
         return "Event filter: [" + this.type + "]";
     }
 
     @Override
     public boolean acceptsEvent(String type, Object event, Function<String, 
Object> resolver) {
-        logger.debug("This event is subscribed to a message type {} with 
payload {}", type, event);
+        if (this.type == null) {
+            return false;
+        }
+
         if (resolver == null) {
-            return this.type != null && this.type.equals(type);
+            return this.type.equals(type);
         }
 
-        if (this.type != null && this.type.equals(type)) {
-            if (correlationManager != null && 
correlationManager.isSubscribe(messageRef)) {
-                if (event == null) {
-                    logger.debug("This event is subscribed to a message ref 
{}", type);
-                    return false;
-                }
-                CorrelationInstance messageCorrelation = 
correlationManager.computeCorrelationInstance(messageRef, event);
-                CorrelationInstance processCorrelation = 
correlationManager.computeSubscription(messageRef, resolver);
-                logger.debug("The event type {} is correlated, computing 
correlations. Message correlation is {}; process correlation is: {} ", type, 
messageCorrelation, processCorrelation);
-                return messageCorrelation.equals(processCorrelation);
+        if (this.type.equals(type) && correlationManager != null && 
correlationManager.isSubscribe(messageRef)) {
+            logger.debug("This event is subscribed to a message type {} with 
payload {}", type, event);
+            if (event == null) {
+                logger.debug("Cannot compute subscription for messageref {} 
and type {}", messageRef, type);
+                return false;
             }
-            return true;
+            CorrelationInstance messageCorrelation = 
correlationManager.computeCorrelationInstance(messageRef, event);
+            CorrelationInstance processCorrelation = 
correlationManager.computeSubscription(messageRef, resolver);
+            logger.debug("The event type {} is correlated, computing 
correlations. Message correlation is {}; process correlation is: {} ", type, 
messageCorrelation, processCorrelation);
+            return messageCorrelation.equals(processCorrelation);
         }
 
-        String resolvedType = (String) resolver.apply(this.type);
-        return resolvedType != null && resolvedType.equals(type);
+        return isAccepted(type, resolver);
 
     }
 
-    public void setMessageRef(String messageRef) {
-        this.messageRef = messageRef;
+    public boolean isAccepted(String type, Function<String, Object> resolver) {
+        return resolveVariable(this.type, resolver).contains(type);
     }
+
+    private List<String> resolveVariable(String varExpression, 
Function<String, Object> resolver) {
+        if (varExpression == null) {
+            return Collections.emptyList();
+        }
+        Map<String, Object[]> replacements = new HashMap<>();
+        Matcher matcher = 
PatternConstants.PARAMETER_MATCHER.matcher(varExpression);
+        while (matcher.find()) {
+            String paramName = matcher.group(1);
+            Object value = resolver.apply(paramName);
+            if (value == null) {
+                logger.warn("expression {} in dynamic signal {} not resolved", 
paramName, varExpression);
+                continue;
+            } else if (value instanceof Object[]) {
+                replacements.put(paramName, (Object[]) value);
+            } else {
+                replacements.put(paramName, new Object[] { value });
+            }
+        }
+        List<String> acceptedTypes = new ArrayList<>();
+        List<Map<String, String>> data = 
generateCombinations(replacements.keySet(), replacements);
+        for (Map<String, String> combination : data) {
+            String tmp = varExpression;
+            for (Map.Entry<String, String> replacement : 
combination.entrySet()) {
+                tmp = tmp.replace("#{" + replacement.getKey() + "}", 
replacement.getValue());
+            }
+            acceptedTypes.add(tmp);
+        }
+        if (acceptedTypes.isEmpty()) {
+            acceptedTypes.add(varExpression);
+        }
+        return acceptedTypes;
+    }
+
+    private List<Map<String, String>> generateCombinations(Set<String> keys, 
Map<String, Object[]> data) {
+        List<Map<String, String>> combinations = new ArrayList<>();
+        for (String key : keys) {
+            Set<String> remaining = new HashSet<>(keys);
+            remaining.remove(key);
+            List<Map<String, String>> subCombinations = 
generateCombinations(remaining, data);
+            if (subCombinations.isEmpty()) {
+                for (Object value : data.get(key)) {
+                    Map<String, String> combination = new HashMap<>();
+                    combination.put(key, value.toString());
+                    if (!combinations.contains(combination)) {
+                        combinations.add(combination);
+                    }
+                }
+            } else {
+                for (Map<String, String> subCombination : subCombinations) {
+                    for (Object value : data.get(key)) {
+                        Map<String, String> combination = new HashMap<>();
+                        combination.putAll(subCombination);
+                        combination.put(key, value.toString());
+                        if (!combinations.contains(combination)) {
+                            combinations.add(combination);
+                        }
+                    }
+                }
+            }
+        }
+
+        return combinations;
+    }
+
 }
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/impl/actions/AbstractNodeInstanceAction.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/impl/actions/AbstractNodeInstanceAction.java
index 569a3faceb..aa1d5756e7 100644
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/impl/actions/AbstractNodeInstanceAction.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/process/instance/impl/actions/AbstractNodeInstanceAction.java
@@ -24,7 +24,7 @@ import java.util.Collection;
 import org.jbpm.process.instance.impl.Action;
 import org.jbpm.workflow.instance.node.CompositeNodeInstance;
 import org.kie.api.runtime.process.NodeInstance;
-import org.kie.api.runtime.process.WorkflowProcessInstance;
+import org.kie.api.runtime.process.NodeInstanceContainer;
 import org.kie.kogito.internal.process.runtime.KogitoProcessContext;
 
 public abstract class AbstractNodeInstanceAction implements Action, 
Serializable {
@@ -39,7 +39,7 @@ public abstract class AbstractNodeInstanceAction implements 
Action, Serializable
 
     @Override
     public void execute(KogitoProcessContext context) throws Exception {
-        WorkflowProcessInstance pi = 
context.getNodeInstance().getProcessInstance();
+        NodeInstanceContainer pi = 
context.getNodeInstance().getNodeInstanceContainer();
         NodeInstance nodeInstance = findNodeByUniqueId(pi.getNodeInstances(), 
attachedToNodeId);
         if (nodeInstance != null) {
             execute(nodeInstance);
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/RuleFlowProcessFactory.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/RuleFlowProcessFactory.java
index ea9a67f0a9..2234646210 100755
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/RuleFlowProcessFactory.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/ruleflow/core/RuleFlowProcessFactory.java
@@ -42,6 +42,7 @@ import org.jbpm.process.instance.impl.Action;
 import org.jbpm.process.instance.impl.ReturnValueEvaluator;
 import org.jbpm.process.instance.impl.actions.CancelNodeInstanceAction;
 import org.jbpm.process.instance.impl.actions.SignalProcessInstanceAction;
+import org.jbpm.process.instance.impl.util.VariableUtil;
 import org.jbpm.ruleflow.core.validation.RuleFlowProcessValidator;
 import org.jbpm.workflow.core.DroolsAction;
 import org.jbpm.workflow.core.WorkflowModelValidator;
@@ -412,8 +413,10 @@ public class RuleFlowProcessFactory extends 
RuleFlowNodeContainerFactory<RuleFlo
 
     protected DroolsAction timerAction(String type) {
         DroolsAction signal = new DroolsAction();
-
-        Action action = kcontext -> 
kcontext.getProcessInstance().signalEvent(type, 
kcontext.getNodeInstance().getStringId());
+        Action action = kcontext -> {
+            String eventType = VariableUtil.resolveVariable(type, 
kcontext.getNodeInstance());
+            kcontext.getProcessInstance().signalEvent(eventType, 
kcontext.getNodeInstance().getStringId());
+        };
         signal.wire(action);
 
         return signal;
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/WorkflowProcessInstanceImpl.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/WorkflowProcessInstanceImpl.java
index 25a0cd0467..48a7276e26 100755
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/WorkflowProcessInstanceImpl.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/impl/WorkflowProcessInstanceImpl.java
@@ -34,11 +34,13 @@ import java.util.UUID;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Function;
 import java.util.function.Predicate;
+import java.util.function.Supplier;
 import java.util.regex.Matcher;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import org.drools.core.common.InternalKnowledgeRuntime;
+import org.drools.mvel.MVELSafeHelper;
 import org.drools.mvel.util.MVELEvaluator;
 import org.jbpm.process.core.ContextContainer;
 import org.jbpm.process.core.ContextResolver;
@@ -57,16 +59,19 @@ import org.jbpm.workflow.core.DroolsAction;
 import org.jbpm.workflow.core.Node;
 import org.jbpm.workflow.core.impl.NodeImpl;
 import org.jbpm.workflow.core.node.BoundaryEventNode;
+import org.jbpm.workflow.core.node.CompositeContextNode;
 import org.jbpm.workflow.core.node.CompositeNode;
 import org.jbpm.workflow.core.node.DynamicNode;
 import org.jbpm.workflow.core.node.EventNode;
 import org.jbpm.workflow.core.node.EventNodeInterface;
 import org.jbpm.workflow.core.node.EventSubProcessNode;
+import org.jbpm.workflow.core.node.ForEachNode;
 import org.jbpm.workflow.core.node.MilestoneNode;
 import org.jbpm.workflow.core.node.StartNode;
 import org.jbpm.workflow.core.node.StateNode;
 import org.jbpm.workflow.instance.NodeInstance;
 import org.jbpm.workflow.instance.WorkflowProcessInstance;
+import org.jbpm.workflow.instance.node.CompositeContextNodeInstance;
 import org.jbpm.workflow.instance.node.CompositeNodeInstance;
 import org.jbpm.workflow.instance.node.EndNodeInstance;
 import org.jbpm.workflow.instance.node.EventBasedNodeInstanceInterface;
@@ -74,6 +79,7 @@ import org.jbpm.workflow.instance.node.EventNodeInstance;
 import org.jbpm.workflow.instance.node.EventNodeInstanceInterface;
 import org.jbpm.workflow.instance.node.EventSubProcessNodeInstance;
 import org.jbpm.workflow.instance.node.FaultNodeInstance;
+import org.jbpm.workflow.instance.node.ForEachNodeInstance;
 import org.jbpm.workflow.instance.node.StateBasedNodeInstance;
 import org.jbpm.workflow.instance.node.WorkItemNodeInstance;
 import org.kie.api.definition.process.NodeContainer;
@@ -99,6 +105,7 @@ import org.kie.kogito.process.flexible.ItemDescription;
 import org.kie.kogito.process.flexible.Milestone;
 import org.kie.kogito.timer.TimerInstance;
 import org.mvel2.integration.VariableResolverFactory;
+import org.mvel2.integration.impl.ImmutableDefaultFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -291,12 +298,12 @@ public abstract class WorkflowProcessInstanceImpl extends 
ProcessInstanceImpl im
         return result;
     }
 
-    public List<NodeInstance> getNodeInstances(WorkflowElementIdentifier 
nodeId, final List<NodeInstance> currentView) {
+    public List<org.kie.api.runtime.process.NodeInstance> 
getNodeInstances(WorkflowElementIdentifier nodeId, final 
List<org.kie.api.runtime.process.NodeInstance> currentView) {
         if (nodeId == null) {
             return Collections.emptyList();
         }
-        List<NodeInstance> result = new ArrayList<>();
-        for (final NodeInstance nodeInstance : currentView) {
+        List<org.kie.api.runtime.process.NodeInstance> result = new 
ArrayList<>();
+        for (org.kie.api.runtime.process.NodeInstance nodeInstance : 
currentView) {
             if (nodeId.equals(nodeInstance.getNodeId())) {
                 result.add(nodeInstance);
             }
@@ -677,8 +684,6 @@ public abstract class WorkflowProcessInstanceImpl extends 
ProcessInstanceImpl im
                 return;
             }
 
-            List<NodeInstance> currentView = new 
ArrayList<>(this.nodeInstances);
-
             try {
                 this.activatingNodeIds = new ArrayList<>();
                 List<KogitoEventListener> listeners = eventListeners.get(type);
@@ -693,32 +698,8 @@ public abstract class WorkflowProcessInstanceImpl extends 
ProcessInstanceImpl im
                         listener.signalEvent(type, event);
                     }
                 }
-                for (org.kie.api.definition.process.Node node : 
getWorkflowProcess().getNodes()) {
-                    if (node instanceof EventNodeInterface && 
((EventNodeInterface) node).acceptsEvent(type, event, getResolver(node, 
currentView))) {
-                        if (node instanceof BoundaryEventNode 
boundaryEventNode) {
-                            WorkflowElementIdentifier id = 
WorkflowElementIdentifierFactory.fromExternalFormat(boundaryEventNode.getAttachedToNodeId());
-                            if (!getNodeInstances(id, currentView).isEmpty()) {
-                                EventNodeInstance eventNodeInstance = 
(EventNodeInstance) getNodeInstance(node);
-                                eventNodeInstance.signalEvent(type, event, 
getResolver(node, currentView));
-                            } else if (type.startsWith("Error-") || 
type.startsWith("Compensation-") || type.startsWith("implicit:compensation")) {
-                                EventNodeInstance eventNodeInstance = 
(EventNodeInstance) getNodeInstance(node);
-                                eventNodeInstance.signalEvent(type, event, 
getResolver(node, currentView));
-                            }
-                        } else {
-                            if (node instanceof EventSubProcessNode && 
(resolveVariables(((EventSubProcessNode) node).getEvents()).contains(type))) {
-                                EventSubProcessNodeInstance eventNodeInstance 
= (EventSubProcessNodeInstance) getNodeInstance(node);
-                                eventNodeInstance.signalEvent(type, event);
-                            } else {
-                                List<NodeInstance> nodeInstances = 
getNodeInstances(node.getId(), currentView);
-                                if (nodeInstances != null && 
!nodeInstances.isEmpty()) {
-                                    for (NodeInstance nodeInstance : 
nodeInstances) {
-                                        ((EventNodeInstanceInterface) 
nodeInstance).signalEvent(type, event, getResolver(node, currentView));
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
+
+                signal(this, (node) -> this.getNodeInstance(node), () -> 
this.getWorkflowProcess().getNodes(), type, event);
 
                 if (((org.jbpm.workflow.core.WorkflowProcess) 
getWorkflowProcess()).isDynamic()) {
                     for (org.kie.api.definition.process.Node node : 
getWorkflowProcess().getNodes()) {
@@ -749,28 +730,168 @@ public abstract class WorkflowProcessInstanceImpl 
extends ProcessInstanceImpl im
         }
     }
 
-    private Function<String, Object> 
getResolver(org.kie.api.definition.process.Node node, List<NodeInstance> 
currentView) {
+    private void signal(org.kie.api.runtime.process.NodeInstanceContainer 
container, Function<org.kie.api.definition.process.Node, 
org.kie.api.runtime.process.NodeInstance> nodeInstanceSupplier,
+            Supplier<org.kie.api.definition.process.Node[]> resolveNodes, 
String type, Object event) {
+
+        List<org.kie.api.runtime.process.NodeInstance> currentView = 
container.getNodeInstances().stream().map(NodeInstance.class::cast).collect(Collectors.toList());
+        for (org.kie.api.definition.process.Node node : resolveNodes.get()) {
+            if (node instanceof EventNodeInterface && ((EventNodeInterface) 
node).acceptsEvent(type, event, getEventFilterResolver(container, node, 
currentView))) {
+                if (node instanceof BoundaryEventNode boundaryEventNode) {
+                    WorkflowElementIdentifier id = 
WorkflowElementIdentifierFactory.fromExternalFormat(boundaryEventNode.getAttachedToNodeId());
+                    if (!getNodeInstances(id, currentView).isEmpty()) {
+                        EventNodeInstance eventNodeInstance = 
(EventNodeInstance) nodeInstanceSupplier.apply(node);
+                        eventNodeInstance.signalEvent(type, event, 
getEventFilterResolver(container, node, currentView));
+                    } else if (type.startsWith("Error-") || 
type.startsWith("Compensation-") || type.startsWith("implicit:compensation")) {
+                        EventNodeInstance eventNodeInstance = 
(EventNodeInstance) nodeInstanceSupplier.apply(node);
+                        eventNodeInstance.signalEvent(type, event, 
getEventFilterResolver(container, node, currentView));
+                    }
+                } else {
+                    if (node instanceof EventSubProcessNode && 
(resolveVariables(((EventSubProcessNode) node).getEvents()).contains(type))) {
+                        EventSubProcessNodeInstance eventNodeInstance = 
(EventSubProcessNodeInstance) getNodeInstance(node);
+                        eventNodeInstance.signalEvent(type, event);
+                    } else {
+                        List<org.kie.api.runtime.process.NodeInstance> 
nodeInstances = getNodeInstances(node.getId(), currentView);
+                        if (nodeInstances != null && !nodeInstances.isEmpty()) 
{
+                            for (org.kie.api.runtime.process.NodeInstance 
nodeInstance : nodeInstances) {
+                                ((EventNodeInstanceInterface) 
nodeInstance).signalEvent(type, event, getEventFilterResolver(container, node, 
currentView));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public Function<String, Object> 
getEventFilterResolver(org.kie.api.runtime.process.NodeInstanceContainer 
container, org.kie.api.definition.process.Node node,
+            List<org.kie.api.runtime.process.NodeInstance> currentView) {
         if (node instanceof DynamicNode) {
             // special handling for dynamic node to allow to resolve variables 
from individual node instances of the dynamic node
             // instead of just relying on process instance's variables
-            return e -> {
-                List<NodeInstance> nodeInstances = 
getNodeInstances(node.getId(), currentView);
+            return (varExpresion) -> {
+                List<org.kie.api.runtime.process.NodeInstance> nodeInstances = 
getNodeInstances(node.getId(), currentView);
                 if (nodeInstances != null && !nodeInstances.isEmpty()) {
                     StringBuilder st = new StringBuilder();
-                    for (NodeInstance ni : nodeInstances) {
-                        Object result = resolveVariable(e, new 
NodeInstanceResolverFactory(ni));
+                    for (org.kie.api.runtime.process.NodeInstance ni : 
nodeInstances) {
+                        Object result = 
resolveExpressionVariable(varExpresion, new 
NodeInstanceResolverFactory((NodeInstance) ni));
                         st.append(result).append("###");
                     }
                     return st.toString();
                 } else {
-                    return resolveVariable(e);
+                    NodeInstanceImpl instance = (NodeInstanceImpl) 
getNodeInstance(node.getId().toExternalFormat(), true);
+                    if (instance != null) {
+                        return instance.getVariable(varExpresion);
+                    }
+                    return null;
+                }
+            };
+        } else if (node instanceof BoundaryEventNode) {
+            return (varExpresion) -> {
+                Function<String, Object> getScopedVariable;
+                if (container instanceof CompositeContextNodeInstance) {
+                    getScopedVariable = (name) -> getVariable(name, 
((CompositeContextNodeInstance) 
container).getContextInstances(VariableScope.VARIABLE_SCOPE));
+                } else if (container instanceof WorkflowProcessInstanceImpl) {
+                    getScopedVariable = (name) -> 
((WorkflowProcessInstanceImpl) container).getVariable(name);
+                } else {
+                    getScopedVariable = null;
+                }
+                Object value = getScopedVariable.apply(varExpresion);
+                if (value != null) {
+                    return value;
                 }
+                VariableResolverFactory resolverFactory = new 
ImmutableDefaultFactory() {
+                    @Override
+                    public boolean isResolveable(String varName) {
+                        return getScopedVariable.apply(varName) != null;
+                    }
+
+                    @Override
+                    public org.mvel2.integration.VariableResolver 
getVariableResolver(String varName) {
+                        return new 
org.mvel2.integration.impl.SimpleValueResolver(getScopedVariable.apply(varName));
+                    }
+                };
+                return resolveExpressionVariable(varExpresion, 
resolverFactory).orElse(null);
+            };
+        } else if (node instanceof ForEachNode) {
+            return (varExpression) -> {
+                try {
+                    // for each can have multiple outcomes 1 per item of the 
list so it should be computed like that
+                    ForEachNodeInstance forEachNodeInstance = 
(ForEachNodeInstance) getNodeInstanceByNodeId(node.getId(), true);
+                    if (forEachNodeInstance == null) {
+                        return new Object[0];
+                    }
+                    List<CompositeContextNodeInstance> data = 
forEachNodeInstance.getNodeInstances().stream().filter(e -> e instanceof 
CompositeContextNodeInstance)
+                            .map(e -> (CompositeContextNodeInstance) 
e).collect(Collectors.toList());
+                    List<Object> outcome = new ArrayList<>();
+                    for (CompositeContextNodeInstance nodeInstance : data) {
+                        Object resolvedValue = 
resolveExpressionVariable(varExpression, new 
NodeInstanceResolverFactory(nodeInstance)).orElse(null);
+                        if (resolvedValue != null) {
+                            outcome.add(resolvedValue);
+                        }
+                    }
+                    return outcome.toArray();
+                } catch (Throwable t) {
+                    return new Object[0];
+                }
+            };
+        } else if (node instanceof EventSubProcessNode || node instanceof 
StateNode) {
+            return (varName) -> {
+                return resolveExpressionVariable(varName, new 
ProcessInstanceResolverFactory(this)).orElse(null);
+            };
+        } else if (node instanceof CompositeContextNode) {
+            return (varExpression) -> {
+                List<org.kie.api.runtime.process.NodeInstance> nodeInstances = 
getNodeInstances(node.getId(), currentView);
+                List<Object> outcome = new ArrayList<>();
+                if (nodeInstances != null && !nodeInstances.isEmpty()) {
+                    for (org.kie.api.runtime.process.NodeInstance nodeInstance 
: nodeInstances) {
+                        Object resolvedValue = 
resolveExpressionVariable(varExpression, new 
NodeInstanceResolverFactory((NodeInstance) nodeInstance)).orElse(null);
+                        if (resolvedValue != null) {
+                            outcome.add(resolvedValue);
+                        }
+                    }
+                }
+                return outcome.toArray();
             };
         } else {
-            return this::resolveVariable;
+            return (varName) -> {
+                return resolveExpressionVariable(varName, new 
ProcessInstanceResolverFactory(this)).orElse(null);
+            };
+        }
+    }
+
+    public Object getVariable(String name, List<ContextInstance> 
variableScopeInstances) {
+        if (variableScopeInstances != null) {
+            for (ContextInstance contextInstance : variableScopeInstances) {
+                Object value = ((VariableScopeInstance) 
contextInstance).getVariable(name);
+                if (value != null) {
+                    return value;
+                }
+            }
+        }
+        return null;
+    }
+
+    private Optional<Object> resolveExpressionVariable(String paramName, 
VariableResolverFactory factory) {
+        try {
+            // just in case is not an expression
+            if (factory.isResolveable(paramName)) {
+                return 
Optional.of(factory.getVariableResolver(paramName).getValue());
+            }
+            return 
Optional.ofNullable(MVELSafeHelper.getEvaluator().eval(paramName, factory));
+        } catch (Throwable t) {
+            logger.error("Could not find variable scope for variable {}", 
paramName);
+            return Optional.empty();
         }
     }
 
+    public NodeInstance getNodeInstanceByNodeId(WorkflowElementIdentifier 
nodeId, boolean recursive) {
+        for (NodeInstance nodeInstance : getNodeInstances(recursive)) {
+            if (nodeInstance.getNodeId().equals(nodeId)) {
+                return nodeInstance;
+            }
+        }
+        return null;
+    }
+
     protected List<String> resolveVariables(List<String> events) {
         return 
events.stream().map(this::resolveVariable).map(Object::toString).collect(Collectors.toList());
     }
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/BoundaryEventNodeInstance.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/BoundaryEventNodeInstance.java
index e4fbc35959..40e911c01b 100755
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/BoundaryEventNodeInstance.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/BoundaryEventNodeInstance.java
@@ -74,7 +74,7 @@ public class BoundaryEventNodeInstance extends 
EventNodeInstance {
                 if (attachedTo.equals(nodeUniqueId) && !isActivating) {
                     // in case this is timer event make sure it corresponds to 
the proper node instance
                     if (type.startsWith("Timer-")) {
-                        if (nInstance.getStringId().equals(event)) {
+                        if (nInstance.getId().equals(event)) {
                             return true;
                         }
                     } else {
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/CompositeNodeInstance.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/CompositeNodeInstance.java
index ea9a677462..c926ba21a3 100755
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/CompositeNodeInstance.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/CompositeNodeInstance.java
@@ -41,6 +41,7 @@ import org.jbpm.workflow.instance.WorkflowProcessInstance;
 import org.jbpm.workflow.instance.impl.NodeInstanceFactory;
 import org.jbpm.workflow.instance.impl.NodeInstanceFactoryRegistry;
 import org.jbpm.workflow.instance.impl.NodeInstanceImpl;
+import org.jbpm.workflow.instance.impl.WorkflowProcessInstanceImpl;
 import org.kie.api.definition.process.Connection;
 import org.kie.api.definition.process.NodeContainer;
 import org.kie.api.definition.process.WorkflowElementIdentifier;
@@ -305,19 +306,19 @@ public class CompositeNodeInstance extends 
StateBasedNodeInstance implements Nod
 
     @Override
     public void signalEvent(String type, Object event, Function<String, 
Object> varResolver) {
-        List<NodeInstance> currentView = new ArrayList<>(this.nodeInstances);
+        List<org.kie.api.runtime.process.NodeInstance> currentView = new 
ArrayList<>(this.nodeInstances);
         super.signalEvent(type, event);
 
         for (org.kie.api.definition.process.Node node : 
getCompositeNode().internalGetNodes()) {
             if (node instanceof EventNodeInterface
-                    && ((EventNodeInterface) node).acceptsEvent(type, event, 
varName -> this.getVariable(varName))) {
+                    && ((EventNodeInterface) node).acceptsEvent(type, event, 
((WorkflowProcessInstanceImpl) 
this.getProcessInstance()).getEventFilterResolver(this, node, currentView))) {
                 if (node instanceof EventNode && ((EventNode) node).getFrom() 
== null || node instanceof EventSubProcessNode) {
                     EventNodeInstanceInterface eventNodeInstance = 
(EventNodeInstanceInterface) getNodeInstance(node);
                     eventNodeInstance.signalEvent(type, event, varResolver);
                 } else {
-                    List<NodeInstance> nodeInstances = 
getNodeInstances(node.getId(), currentView);
+                    List<org.kie.api.runtime.process.NodeInstance> 
nodeInstances = getNodeInstances(node.getId(), currentView);
                     if (nodeInstances != null && !nodeInstances.isEmpty()) {
-                        for (NodeInstance nodeInstance : nodeInstances) {
+                        for (org.kie.api.runtime.process.NodeInstance 
nodeInstance : nodeInstances) {
                             ((EventNodeInstanceInterface) 
nodeInstance).signalEvent(type, event, varResolver);
                         }
                     }
@@ -354,9 +355,9 @@ public class CompositeNodeInstance extends 
StateBasedNodeInstance implements Nod
         return result;
     }
 
-    public List<NodeInstance> getNodeInstances(WorkflowElementIdentifier 
nodeId, List<NodeInstance> currentView) {
-        List<NodeInstance> result = new ArrayList<>();
-        for (final NodeInstance nodeInstance : currentView) {
+    public List<org.kie.api.runtime.process.NodeInstance> 
getNodeInstances(WorkflowElementIdentifier nodeId, 
List<org.kie.api.runtime.process.NodeInstance> currentView) {
+        List<org.kie.api.runtime.process.NodeInstance> result = new 
ArrayList<>();
+        for (org.kie.api.runtime.process.NodeInstance nodeInstance : 
currentView) {
             if (nodeInstance.getNodeId().equals(nodeId)) {
                 result.add(nodeInstance);
             }
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/StateBasedNodeInstance.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/StateBasedNodeInstance.java
index 6b69126d81..2b0517718c 100755
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/StateBasedNodeInstance.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/StateBasedNodeInstance.java
@@ -24,7 +24,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Optional;
 
 import org.drools.core.common.InternalAgenda;
 import org.drools.core.common.ReteEvaluator;
@@ -100,11 +99,11 @@ public abstract class StateBasedNodeInstance extends 
ExtendedNodeInstanceImpl im
                                 .generateId()
                                 .timerId(Long.toString(timer.getId()))
                                 .expirationTime(createTimerInstance(timer))
-                                
.processInstanceId(getProcessInstance().getStringId())
+                                
.rootProcessId(getProcessInstance().getRootProcessId())
                                 
.rootProcessInstanceId(getProcessInstance().getRootProcessInstanceId())
                                 .processId(getProcessInstance().getProcessId())
-                                
.rootProcessId(getProcessInstance().getRootProcessId())
-                                
.nodeInstanceId(Optional.ofNullable(from).map(KogitoNodeInstance::getStringId).orElse(null))
+                                
.processInstanceId(getProcessInstance().getStringId())
+                                .nodeInstanceId(this.getId())
                                 .build();
                 String jobId = 
jobService.scheduleProcessInstanceJob(jobDescription);
                 timerInstances.add(jobId);
diff --git 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/TimerNodeInstance.java
 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/TimerNodeInstance.java
index 054ef0ef8d..452e978528 100755
--- 
a/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/TimerNodeInstance.java
+++ 
b/jbpm/jbpm-flow/src/main/java/org/jbpm/workflow/instance/node/TimerNodeInstance.java
@@ -23,7 +23,6 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Optional;
 import java.util.Set;
 import java.util.UUID;
 
@@ -91,7 +90,7 @@ public class TimerNodeInstance extends StateBasedNodeInstance 
implements EventLi
                                     
.rootProcessInstanceId(getProcessInstance().getRootProcessInstanceId())
                                     
.processId(getProcessInstance().getProcessId())
                                     
.rootProcessId(getProcessInstance().getRootProcessId())
-                                    
.nodeInstanceId(Optional.ofNullable(from).map(KogitoNodeInstance::getStringId).orElse(null))
+                                    .nodeInstanceId(this.getId())
                                     .build();
                     JobsService jobService = processRuntime.getJobsService();
                     String jobId = 
jobService.scheduleProcessInstanceJob(jobDescription);
diff --git 
a/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopSubprocessBoundaryTimer.bpmn2
 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopSubprocessBoundaryTimer.bpmn2
new file mode 100644
index 0000000000..5afcff04cb
--- /dev/null
+++ 
b/jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/loop/BPMN2-MultiInstanceLoopSubprocessBoundaryTimer.bpmn2
@@ -0,0 +1,245 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL"; 
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"; 
xmlns:bpsim="http://www.bpsim.org/schemas/1.0"; 
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"; 
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"; 
xmlns:drools="http://www.jboss.org/drools"; id="_Nw1jAGpCED2xyqiTIWNwhw" 
xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd 
http://www. [...]
+  <bpmn2:itemDefinition id="_mi_inputItem" 
structureRef="java.util.List&lt;String&gt;"/>
+  <bpmn2:itemDefinition 
id="_EEFE61C3-C4A3-48D3-9971-D499F41E88CC_multiInstanceItemType_item" 
structureRef="String"/>
+  <bpmn2:itemDefinition 
id="__DEF3687C-875E-4F22-B764-AB6C5626902D_SkippableInputXItem" 
structureRef="Object"/>
+  <bpmn2:itemDefinition 
id="__DEF3687C-875E-4F22-B764-AB6C5626902D_PriorityInputXItem" 
structureRef="Object"/>
+  <bpmn2:itemDefinition 
id="__DEF3687C-875E-4F22-B764-AB6C5626902D_CommentInputXItem" 
structureRef="Object"/>
+  <bpmn2:itemDefinition 
id="__DEF3687C-875E-4F22-B764-AB6C5626902D_DescriptionInputXItem" 
structureRef="Object"/>
+  <bpmn2:itemDefinition 
id="__DEF3687C-875E-4F22-B764-AB6C5626902D_CreatedByInputXItem" 
structureRef="Object"/>
+  <bpmn2:itemDefinition 
id="__DEF3687C-875E-4F22-B764-AB6C5626902D_TaskNameInputXItem" 
structureRef="Object"/>
+  <bpmn2:itemDefinition 
id="__DEF3687C-875E-4F22-B764-AB6C5626902D_GroupIdInputXItem" 
structureRef="Object"/>
+  <bpmn2:itemDefinition 
id="__DEF3687C-875E-4F22-B764-AB6C5626902D_ContentInputXItem" 
structureRef="Object"/>
+  <bpmn2:itemDefinition 
id="__DEF3687C-875E-4F22-B764-AB6C5626902D_NotStartedReassignInputXItem" 
structureRef="Object"/>
+  <bpmn2:itemDefinition 
id="__DEF3687C-875E-4F22-B764-AB6C5626902D_NotCompletedReassignInputXItem" 
structureRef="Object"/>
+  <bpmn2:itemDefinition 
id="__DEF3687C-875E-4F22-B764-AB6C5626902D_NotStartedNotifyInputXItem" 
structureRef="Object"/>
+  <bpmn2:itemDefinition 
id="__DEF3687C-875E-4F22-B764-AB6C5626902D_NotCompletedNotifyInputXItem" 
structureRef="Object"/>
+  <bpmn2:collaboration id="_83BEC677-1889-4FEA-852C-73E9749D1542" 
name="Default Collaboration">
+    <bpmn2:participant id="_642BE7C4-3C99-4329-B03B-BB5923F62430" name="Pool 
Participant" processRef="Sample"/>
+  </bpmn2:collaboration>
+  <bpmn2:process id="MultiInstanceLoopSubprocessBoundaryTimer" 
drools:packageName="org.jbpm.bpmn2.loop" drools:version="1.0" 
drools:adHoc="false" name="Sample" isExecutable="true" processType="Public">
+    <bpmn2:property id="mi_input" itemSubjectRef="_mi_inputItem" 
name="mi_input"/>
+    <bpmn2:sequenceFlow id="_E51B394B-06A3-4AF6-BC86-157D9039A0FB" 
sourceRef="_EEFE61C3-C4A3-48D3-9971-D499F41E88CC" 
targetRef="_92C1C8CF-C2F9-4616-9EEF-0C052BBB7409"/>
+    <bpmn2:sequenceFlow id="_D296A998-04B5-4CB2-9CFE-1D19C729D5B8" 
sourceRef="_F5F71D13-6758-4EF0-A513-BBC57C836BB2" 
targetRef="_EEFE61C3-C4A3-48D3-9971-D499F41E88CC">
+      <bpmn2:extensionElements>
+        <drools:metaData name="isAutoConnection.target">
+          <drools:metaValue><![CDATA[true]]></drools:metaValue>
+        </drools:metaData>
+      </bpmn2:extensionElements>
+    </bpmn2:sequenceFlow>
+    <bpmn2:endEvent id="_92C1C8CF-C2F9-4616-9EEF-0C052BBB7409">
+      <bpmn2:incoming>_E51B394B-06A3-4AF6-BC86-157D9039A0FB</bpmn2:incoming>
+    </bpmn2:endEvent>
+    <bpmn2:startEvent id="_F5F71D13-6758-4EF0-A513-BBC57C836BB2">
+      <bpmn2:outgoing>_D296A998-04B5-4CB2-9CFE-1D19C729D5B8</bpmn2:outgoing>
+    </bpmn2:startEvent>
+    <bpmn2:subProcess id="_EEFE61C3-C4A3-48D3-9971-D499F41E88CC" 
name="Multiple Instance Sub-process">
+      <bpmn2:extensionElements>
+        <drools:metaData name="elementname">
+          <drools:metaValue><![CDATA[Multiple Instance 
Sub-process]]></drools:metaValue>
+        </drools:metaData>
+      </bpmn2:extensionElements>
+      <bpmn2:incoming>_D296A998-04B5-4CB2-9CFE-1D19C729D5B8</bpmn2:incoming>
+      <bpmn2:outgoing>_E51B394B-06A3-4AF6-BC86-157D9039A0FB</bpmn2:outgoing>
+      <bpmn2:ioSpecification>
+        <bpmn2:dataInput 
id="_EEFE61C3-C4A3-48D3-9971-D499F41E88CC_IN_COLLECTIONInputX" 
itemSubjectRef="_mi_inputItem" name="IN_COLLECTION"/>
+        <bpmn2:dataInput id="_EEFE61C3-C4A3-48D3-9971-D499F41E88CC_itemInputX" 
itemSubjectRef="_EEFE61C3-C4A3-48D3-9971-D499F41E88CC_multiInstanceItemType_item"
 name="item"/>
+        <bpmn2:inputSet>
+          
<bpmn2:dataInputRefs>_EEFE61C3-C4A3-48D3-9971-D499F41E88CC_IN_COLLECTIONInputX</bpmn2:dataInputRefs>
+          
<bpmn2:dataInputRefs>_EEFE61C3-C4A3-48D3-9971-D499F41E88CC_itemInputX</bpmn2:dataInputRefs>
+        </bpmn2:inputSet>
+        <bpmn2:outputSet/>
+      </bpmn2:ioSpecification>
+      <bpmn2:dataInputAssociation>
+        <bpmn2:sourceRef>mi_input</bpmn2:sourceRef>
+        
<bpmn2:targetRef>_EEFE61C3-C4A3-48D3-9971-D499F41E88CC_IN_COLLECTIONInputX</bpmn2:targetRef>
+      </bpmn2:dataInputAssociation>
+      <bpmn2:multiInstanceLoopCharacteristics>
+        
<bpmn2:loopDataInputRef>_EEFE61C3-C4A3-48D3-9971-D499F41E88CC_IN_COLLECTIONInputX</bpmn2:loopDataInputRef>
+        <bpmn2:inputDataItem id="item" 
itemSubjectRef="_EEFE61C3-C4A3-48D3-9971-D499F41E88CC_multiInstanceItemType_item"
 name="item"/>
+      </bpmn2:multiInstanceLoopCharacteristics>
+      <bpmn2:sequenceFlow id="_DB8BA8C1-DE12-479A-AF7D-7A562718926C" 
sourceRef="_DFF45CF9-1DB5-4822-B9B8-0F8C1A2EA873" 
targetRef="_469041DB-5440-428A-BE21-0D888F71826F"/>
+      <bpmn2:sequenceFlow id="_DFAE59C0-EE21-4991-AF31-BEBFD37BEB98" 
sourceRef="_D8F28EF9-54FF-4DB7-B175-4785487029B6" 
targetRef="_DFF45CF9-1DB5-4822-B9B8-0F8C1A2EA873">
+        <bpmn2:extensionElements>
+          <drools:metaData name="isAutoConnection.target">
+            <drools:metaValue><![CDATA[true]]></drools:metaValue>
+          </drools:metaData>
+        </bpmn2:extensionElements>
+      </bpmn2:sequenceFlow>
+      <bpmn2:sequenceFlow id="_A75E00C6-6FBD-48DE-9750-462DC521483A" 
sourceRef="_DEF3687C-875E-4F22-B764-AB6C5626902D" 
targetRef="_469041DB-5440-428A-BE21-0D888F71826F"/>
+      <bpmn2:sequenceFlow id="_72B473CD-9F5C-461D-AC1B-DCEE85A38365" 
sourceRef="_8B2BC1B3-43C5-40B7-9447-885984A9BCDA" 
targetRef="_DEF3687C-875E-4F22-B764-AB6C5626902D">
+        <bpmn2:extensionElements>
+          <drools:metaData name="isAutoConnection.target">
+            <drools:metaValue><![CDATA[true]]></drools:metaValue>
+          </drools:metaData>
+        </bpmn2:extensionElements>
+      </bpmn2:sequenceFlow>
+      <bpmn2:sequenceFlow id="_CA5FFA7C-D186-4CCB-BC1C-134145DD3C0A" 
sourceRef="_469041DB-5440-428A-BE21-0D888F71826F" 
targetRef="_74AF4474-AADE-4EB1-BA73-6E1FD285480D"/>
+      <bpmn2:sequenceFlow id="_2FC3736F-E7E6-446C-87B5-5B018FF20372" 
sourceRef="_0E50FC70-D02D-4509-A286-72A1F6239EFD" 
targetRef="_8B2BC1B3-43C5-40B7-9447-885984A9BCDA">
+        <bpmn2:extensionElements>
+          <drools:metaData name="isAutoConnection.target">
+            <drools:metaValue><![CDATA[true]]></drools:metaValue>
+          </drools:metaData>
+        </bpmn2:extensionElements>
+      </bpmn2:sequenceFlow>
+      <bpmn2:exclusiveGateway id="_469041DB-5440-428A-BE21-0D888F71826F" 
gatewayDirection="Converging">
+        <bpmn2:incoming>_A75E00C6-6FBD-48DE-9750-462DC521483A</bpmn2:incoming>
+        <bpmn2:incoming>_DB8BA8C1-DE12-479A-AF7D-7A562718926C</bpmn2:incoming>
+        <bpmn2:outgoing>_CA5FFA7C-D186-4CCB-BC1C-134145DD3C0A</bpmn2:outgoing>
+      </bpmn2:exclusiveGateway>
+      <bpmn2:scriptTask id="_DFF45CF9-1DB5-4822-B9B8-0F8C1A2EA873" 
name="Script2" scriptFormat="http://www.java.com/java";>
+        <bpmn2:extensionElements>
+          <drools:metaData name="elementname">
+            <drools:metaValue><![CDATA[Script2]]></drools:metaValue>
+          </drools:metaData>
+        </bpmn2:extensionElements>
+        <bpmn2:incoming>_DFAE59C0-EE21-4991-AF31-BEBFD37BEB98</bpmn2:incoming>
+        <bpmn2:outgoing>_DB8BA8C1-DE12-479A-AF7D-7A562718926C</bpmn2:outgoing>
+        <bpmn2:script>System.out.println("Script Timer Task!");</bpmn2:script>
+      </bpmn2:scriptTask>
+      <bpmn2:userTask id="_DEF3687C-875E-4F22-B764-AB6C5626902D" name="Task">
+        <bpmn2:extensionElements>
+          <drools:metaData name="elementname">
+            <drools:metaValue><![CDATA[Task #{item}]]></drools:metaValue>
+          </drools:metaData>
+        </bpmn2:extensionElements>
+        <bpmn2:incoming>_72B473CD-9F5C-461D-AC1B-DCEE85A38365</bpmn2:incoming>
+        <bpmn2:outgoing>_A75E00C6-6FBD-48DE-9750-462DC521483A</bpmn2:outgoing>
+        <bpmn2:ioSpecification>
+          <bpmn2:dataInput 
id="_DEF3687C-875E-4F22-B764-AB6C5626902D_TaskNameInputX" drools:dtype="Object" 
itemSubjectRef="__DEF3687C-875E-4F22-B764-AB6C5626902D_TaskNameInputXItem" 
name="TaskName"/>
+          <bpmn2:dataInput 
id="_DEF3687C-875E-4F22-B764-AB6C5626902D_SkippableInputX" 
drools:dtype="Object" 
itemSubjectRef="__DEF3687C-875E-4F22-B764-AB6C5626902D_SkippableInputXItem" 
name="Skippable"/>
+          <bpmn2:inputSet>
+            
<bpmn2:dataInputRefs>_DEF3687C-875E-4F22-B764-AB6C5626902D_TaskNameInputX</bpmn2:dataInputRefs>
+            
<bpmn2:dataInputRefs>_DEF3687C-875E-4F22-B764-AB6C5626902D_SkippableInputX</bpmn2:dataInputRefs>
+          </bpmn2:inputSet>
+        </bpmn2:ioSpecification>
+        <bpmn2:dataInputAssociation>
+          
<bpmn2:targetRef>_DEF3687C-875E-4F22-B764-AB6C5626902D_TaskNameInputX</bpmn2:targetRef>
+          <bpmn2:assignment>
+            <bpmn2:from 
xsi:type="bpmn2:tFormalExpression"><![CDATA[Task]]></bpmn2:from>
+            <bpmn2:to 
xsi:type="bpmn2:tFormalExpression"><![CDATA[_DEF3687C-875E-4F22-B764-AB6C5626902D_TaskNameInputX]]></bpmn2:to>
+          </bpmn2:assignment>
+        </bpmn2:dataInputAssociation>
+        <bpmn2:dataInputAssociation>
+          
<bpmn2:targetRef>_DEF3687C-875E-4F22-B764-AB6C5626902D_SkippableInputX</bpmn2:targetRef>
+          <bpmn2:assignment>
+            <bpmn2:from 
xsi:type="bpmn2:tFormalExpression"><![CDATA[false]]></bpmn2:from>
+            <bpmn2:to 
xsi:type="bpmn2:tFormalExpression"><![CDATA[_DEF3687C-875E-4F22-B764-AB6C5626902D_SkippableInputX]]></bpmn2:to>
+          </bpmn2:assignment>
+        </bpmn2:dataInputAssociation>
+        <bpmn2:potentialOwner id="_Nw5NYGpCED2xyqiTIWNwhw">
+          <bpmn2:resourceAssignmentExpression id="_Nw5NYWpCED2xyqiTIWNwhw">
+            <bpmn2:formalExpression>admin</bpmn2:formalExpression>
+          </bpmn2:resourceAssignmentExpression>
+        </bpmn2:potentialOwner>
+      </bpmn2:userTask>
+      <bpmn2:scriptTask id="_8B2BC1B3-43C5-40B7-9447-885984A9BCDA" 
name="Script1" scriptFormat="http://www.java.com/java";>
+        <bpmn2:extensionElements>
+          <drools:metaData name="elementname">
+            <drools:metaValue><![CDATA[Script1]]></drools:metaValue>
+          </drools:metaData>
+        </bpmn2:extensionElements>
+        <bpmn2:incoming>_2FC3736F-E7E6-446C-87B5-5B018FF20372</bpmn2:incoming>
+        <bpmn2:outgoing>_72B473CD-9F5C-461D-AC1B-DCEE85A38365</bpmn2:outgoing>
+        <bpmn2:script>System.out.println("Script Task: " + 
item);</bpmn2:script>
+      </bpmn2:scriptTask>
+      <bpmn2:endEvent id="_74AF4474-AADE-4EB1-BA73-6E1FD285480D">
+        <bpmn2:incoming>_CA5FFA7C-D186-4CCB-BC1C-134145DD3C0A</bpmn2:incoming>
+      </bpmn2:endEvent>
+      <bpmn2:startEvent id="_0E50FC70-D02D-4509-A286-72A1F6239EFD">
+        <bpmn2:outgoing>_2FC3736F-E7E6-446C-87B5-5B018FF20372</bpmn2:outgoing>
+      </bpmn2:startEvent>
+      <bpmn2:boundaryEvent id="_D8F28EF9-54FF-4DB7-B175-4785487029B6" 
drools:dockerinfo="65.27659574468085^74|" drools:boundaryca="true" 
attachedToRef="_DEF3687C-875E-4F22-B764-AB6C5626902D">
+        <bpmn2:outgoing>_DFAE59C0-EE21-4991-AF31-BEBFD37BEB98</bpmn2:outgoing>
+        <bpmn2:timerEventDefinition>
+          <bpmn2:timeDuration 
xsi:type="bpmn2:tFormalExpression">#{item}</bpmn2:timeDuration>
+        </bpmn2:timerEventDefinition>
+      </bpmn2:boundaryEvent>
+    </bpmn2:subProcess>
+  </bpmn2:process>
+  <bpmndi:BPMNDiagram>
+    <bpmndi:BPMNPlane bpmnElement="Sample">
+      <bpmndi:BPMNShape id="shape__EEFE61C3-C4A3-48D3-9971-D499F41E88CC" 
bpmnElement="_EEFE61C3-C4A3-48D3-9971-D499F41E88CC">
+        <dc:Bounds height="412" width="817" x="259" y="281"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="shape__0E50FC70-D02D-4509-A286-72A1F6239EFD" 
bpmnElement="_0E50FC70-D02D-4509-A286-72A1F6239EFD">
+        <dc:Bounds height="56" width="56" x="308" y="378"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="shape__74AF4474-AADE-4EB1-BA73-6E1FD285480D" 
bpmnElement="_74AF4474-AADE-4EB1-BA73-6E1FD285480D">
+        <dc:Bounds height="56" width="56" x="976" y="378"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="shape__8B2BC1B3-43C5-40B7-9447-885984A9BCDA" 
bpmnElement="_8B2BC1B3-43C5-40B7-9447-885984A9BCDA">
+        <dc:Bounds height="102" width="154" x="405" y="355"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="shape__DEF3687C-875E-4F22-B764-AB6C5626902D" 
bpmnElement="_DEF3687C-875E-4F22-B764-AB6C5626902D">
+        <dc:Bounds height="102" width="154" x="612" y="355"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="shape__DFF45CF9-1DB5-4822-B9B8-0F8C1A2EA873" 
bpmnElement="_DFF45CF9-1DB5-4822-B9B8-0F8C1A2EA873">
+        <dc:Bounds height="102" width="154" x="628" y="529"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="shape__469041DB-5440-428A-BE21-0D888F71826F" 
bpmnElement="_469041DB-5440-428A-BE21-0D888F71826F">
+        <dc:Bounds height="56" width="56" x="851" y="378"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="shape__D8F28EF9-54FF-4DB7-B175-4785487029B6" 
bpmnElement="_D8F28EF9-54FF-4DB7-B175-4785487029B6">
+        <dc:Bounds height="56" width="56" x="677.2765957446809" y="429"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge 
id="edge_shape__0E50FC70-D02D-4509-A286-72A1F6239EFD_to_shape__8B2BC1B3-43C5-40B7-9447-885984A9BCDA"
 bpmnElement="_2FC3736F-E7E6-446C-87B5-5B018FF20372">
+        <di:waypoint x="336" y="406"/>
+        <di:waypoint x="405" y="406"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge 
id="edge_shape__469041DB-5440-428A-BE21-0D888F71826F_to_shape__74AF4474-AADE-4EB1-BA73-6E1FD285480D"
 bpmnElement="_CA5FFA7C-D186-4CCB-BC1C-134145DD3C0A">
+        <di:waypoint x="879" y="406"/>
+        <di:waypoint x="1004" y="406"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge 
id="edge_shape__8B2BC1B3-43C5-40B7-9447-885984A9BCDA_to_shape__DEF3687C-875E-4F22-B764-AB6C5626902D"
 bpmnElement="_72B473CD-9F5C-461D-AC1B-DCEE85A38365">
+        <di:waypoint x="482" y="406"/>
+        <di:waypoint x="612" y="406"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge 
id="edge_shape__DEF3687C-875E-4F22-B764-AB6C5626902D_to_shape__469041DB-5440-428A-BE21-0D888F71826F"
 bpmnElement="_A75E00C6-6FBD-48DE-9750-462DC521483A">
+        <di:waypoint x="689" y="406"/>
+        <di:waypoint x="879" y="406"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge 
id="edge_shape__D8F28EF9-54FF-4DB7-B175-4785487029B6_to_shape__DFF45CF9-1DB5-4822-B9B8-0F8C1A2EA873"
 bpmnElement="_DFAE59C0-EE21-4991-AF31-BEBFD37BEB98">
+        <di:waypoint x="705.2765957446809" y="457"/>
+        <di:waypoint x="705" y="529"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge 
id="edge_shape__DFF45CF9-1DB5-4822-B9B8-0F8C1A2EA873_to_shape__469041DB-5440-428A-BE21-0D888F71826F"
 bpmnElement="_DB8BA8C1-DE12-479A-AF7D-7A562718926C">
+        <di:waypoint x="705" y="580"/>
+        <di:waypoint x="879" y="579.0208415906989"/>
+        <di:waypoint x="879" y="406"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNShape id="shape__F5F71D13-6758-4EF0-A513-BBC57C836BB2" 
bpmnElement="_F5F71D13-6758-4EF0-A513-BBC57C836BB2">
+        <dc:Bounds height="56" width="56" x="118" y="459"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNShape id="shape__92C1C8CF-C2F9-4616-9EEF-0C052BBB7409" 
bpmnElement="_92C1C8CF-C2F9-4616-9EEF-0C052BBB7409">
+        <dc:Bounds height="56" width="56" x="1161" y="459"/>
+      </bpmndi:BPMNShape>
+      <bpmndi:BPMNEdge 
id="edge_shape__F5F71D13-6758-4EF0-A513-BBC57C836BB2_to_shape__EEFE61C3-C4A3-48D3-9971-D499F41E88CC"
 bpmnElement="_D296A998-04B5-4CB2-9CFE-1D19C729D5B8">
+        <di:waypoint x="146" y="487"/>
+        <di:waypoint x="259" y="487"/>
+      </bpmndi:BPMNEdge>
+      <bpmndi:BPMNEdge 
id="edge_shape__EEFE61C3-C4A3-48D3-9971-D499F41E88CC_to_shape__92C1C8CF-C2F9-4616-9EEF-0C052BBB7409"
 bpmnElement="_E51B394B-06A3-4AF6-BC86-157D9039A0FB">
+        <di:waypoint x="667.5" y="487"/>
+        <di:waypoint x="1189" y="487"/>
+      </bpmndi:BPMNEdge>
+    </bpmndi:BPMNPlane>
+  </bpmndi:BPMNDiagram>
+  <bpmn2:relationship type="BPSimData">
+    <bpmn2:extensionElements>
+      <bpsim:BPSimData>
+        <bpsim:Scenario id="default" name="Simulationscenario">
+          <bpsim:ScenarioParameters/>
+          <bpsim:ElementParameters 
elementRef="_F5F71D13-6758-4EF0-A513-BBC57C836BB2">
+            <bpsim:TimeParameters>
+              <bpsim:ProcessingTime>
+                <bpsim:NormalDistribution mean="0" standardDeviation="0"/>
+              </bpsim:ProcessingTime>
+            </bpsim:TimeParameters>
+          </bpsim:ElementParameters>
+        </bpsim:Scenario>
+      </bpsim:BPSimData>
+    </bpmn2:extensionElements>
+    <bpmn2:source>_Nw1jAGpCED2xyqiTIWNwhw</bpmn2:source>
+    <bpmn2:target>_Nw1jAGpCED2xyqiTIWNwhw</bpmn2:target>
+  </bpmn2:relationship>
+</bpmn2:definitions>
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 9d2ec7cc3b..bace416905 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
@@ -111,6 +111,8 @@ 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.loop.MultiInstanceLoopSubprocessBoundaryTimerModel;
+import org.jbpm.bpmn2.loop.MultiInstanceLoopSubprocessBoundaryTimerProcess;
 import org.jbpm.bpmn2.objects.Person;
 import org.jbpm.bpmn2.objects.TestUserTaskWorkItemHandler;
 import org.jbpm.bpmn2.objects.TestWorkItemHandler;
@@ -144,6 +146,7 @@ import org.jbpm.test.utils.ProcessTestHelper;
 import org.jbpm.test.utils.ProcessTestHelper.CompletionKogitoEventListener;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
 import org.kie.api.command.ExecutableCommand;
 import org.kie.api.event.process.ProcessCompletedEvent;
 import org.kie.api.event.process.ProcessNodeLeftEvent;
@@ -481,6 +484,7 @@ public class IntermediateEventTest extends 
JbpmBpmn2TestCase {
     }
 
     @Test
+    @Timeout(10000L)
     public void testEventBasedSplit2() {
         ProcessCompletedCountDownProcessEventListener countDownListener = new 
ProcessCompletedCountDownProcessEventListener(1);
         Application app = ProcessTestHelper.newApplication();
@@ -511,7 +515,7 @@ public class IntermediateEventTest extends 
JbpmBpmn2TestCase {
         instance = processDefinition.createInstance(model);
         instance.start();
         
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_ACTIVE);
-        countDownListener.waitTillCompleted();
+        countDownListener.await();
         
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
     }
 
@@ -2037,6 +2041,34 @@ public class IntermediateEventTest extends 
JbpmBpmn2TestCase {
         
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
     }
 
+    @Test
+    @Timeout(10000L)
+    public void testMultiInstanceLoopSubprocessBoundaryTimer() throws 
Exception {
+        Application app = ProcessTestHelper.newApplication();
+        NodeLeftCountDownProcessEventListener countDownListener = new 
NodeLeftCountDownProcessEventListener("Script2", 1);
+        ProcessTestHelper.registerProcessEventListener(app, countDownListener);
+        TestUserTaskWorkItemHandler handler = new 
TestUserTaskWorkItemHandler();
+        ProcessTestHelper.registerHandler(app, "Human Task", handler);
+
+        
org.kie.kogito.process.Process<MultiInstanceLoopSubprocessBoundaryTimerModel> 
definition = MultiInstanceLoopSubprocessBoundaryTimerProcess.newProcess(app);
+        MultiInstanceLoopSubprocessBoundaryTimerModel model = 
definition.createModel();
+        model.setMi_input(List.of("PT1S", "PT2S", "PT3S"));
+        
org.kie.kogito.process.ProcessInstance<MultiInstanceLoopSubprocessBoundaryTimerModel>
 instance = definition.createInstance(model);
+        instance.start();
+
+        countDownListener.reset(1);
+        assertThat(countDownListener.await()).isTrue();
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_ACTIVE);
+
+        countDownListener.reset(1);
+        assertThat(countDownListener.await()).isTrue();
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_ACTIVE);
+
+        countDownListener.reset(1);
+        assertThat(countDownListener.await()).isTrue();
+        
assertThat(instance.status()).isEqualTo(org.kie.kogito.process.ProcessInstance.STATE_COMPLETED);
+    }
+
     @Test
     public void testMultiInstanceLoopCharacteristicsProcessSequential() throws 
Exception {
         Application app = ProcessTestHelper.newApplication();


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

Reply via email to