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<String>"/>
+ <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]