This is an automated email from the ASF dual-hosted git repository.
pefernan pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie.git
The following commit(s) were added to refs/heads/main by this push:
new 5274e6c0311 Intermediate message correlation failure when used inside
a subprocess (#7130)
5274e6c0311 is described below
commit 5274e6c0311eaa13da542b438d9df5ff5c876df7
Author: Soniya Abraham <[email protected]>
AuthorDate: Wed Oct 14 19:46:15 2026 +0530
Intermediate message correlation failure when used inside a subprocess
(#7130)
* fix for intermediate message correlation failure
* Changes to check the message and process correlations
---
.../core/correlation/CorrelationInstance.java | 33 +++-
.../jbpm/process/core/event/EventTypeFilter.java | 2 +-
...eCatchEventMessageCorrelationInSubprocess.bpmn2 | 189 +++++++++++++++++++++
.../java/org/jbpm/bpmn2/IntermediateEventTest.java | 24 +++
4 files changed, 246 insertions(+), 2 deletions(-)
diff --git
a/kogito-jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/correlation/CorrelationInstance.java
b/kogito-jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/correlation/CorrelationInstance.java
index cd389bb2ba1..b253387e673 100644
---
a/kogito-jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/correlation/CorrelationInstance.java
+++
b/kogito-jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/correlation/CorrelationInstance.java
@@ -18,7 +18,9 @@
*/
package org.jbpm.process.core.correlation;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
public class CorrelationInstance {
@@ -84,9 +86,38 @@ public class CorrelationInstance {
return true;
}
+ public boolean matchesSubscription(CorrelationInstance subscription) {
+ if (subscription == null) {
+ return false;
+ }
+ if (!id.equals(subscription.id) || !name.equals(subscription.name)) {
+ return false;
+ }
+ if (properties.size() != subscription.properties.size()) {
+ return false;
+ }
+ for (Map.Entry<String, Object> entry : properties.entrySet()) {
+ Object messageVal = entry.getValue();
+ Object subscriptionVal =
subscription.properties.get(entry.getKey());
+ if (!correlationPropertyMatches(messageVal, subscriptionVal)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean correlationPropertyMatches(Object messageVal,
Object subscriptionVal) {
+ if (messageVal == null || subscriptionVal == null) {
+ return messageVal == subscriptionVal;
+ }
+ List<Object> messageList = messageVal instanceof Object[] ?
Arrays.asList((Object[]) messageVal) : List.of(messageVal);
+ List<Object> subscriptionList = subscriptionVal instanceof Object[] ?
Arrays.asList((Object[]) subscriptionVal) : List.of(subscriptionVal);
+ return messageList.stream().anyMatch(subscriptionList::contains);
+ }
+
@Override
public String toString() {
return "CorrelationInstance [id=" + id + ", name=" + name + ",
properties=" + properties + "]";
}
-}
\ No newline at end of file
+}
diff --git
a/kogito-jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/event/EventTypeFilter.java
b/kogito-jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/event/EventTypeFilter.java
index 6868325465f..5fa63ecc23e 100755
---
a/kogito-jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/event/EventTypeFilter.java
+++
b/kogito-jbpm/jbpm-flow/src/main/java/org/jbpm/process/core/event/EventTypeFilter.java
@@ -91,7 +91,7 @@ public class EventTypeFilter implements EventFilter,
Serializable {
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);
+ return messageCorrelation.matchesSubscription(processCorrelation);
}
return isAccepted(type, resolver);
diff --git
a/kogito-jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/intermediate/BPMN2-IntermediateCatchEventMessageCorrelationInSubprocess.bpmn2
b/kogito-jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/intermediate/BPMN2-IntermediateCatchEventMessageCorrelationInSubprocess.bpmn2
new file mode 100644
index 00000000000..fbdcdaa8c13
--- /dev/null
+++
b/kogito-jbpm/jbpm-tests/src/test/bpmn/org/jbpm/bpmn2/intermediate/BPMN2-IntermediateCatchEventMessageCorrelationInSubprocess.bpmn2
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+
+<!--
+ Regression test BPMN for:
+ "IntermediateCatchEvent with message correlation inside an embedded
subprocess fails
+ because the process-side correlation value is resolved as Object[]
instead of String"
+
+ Flow:
+ Start → ScriptTask (sets correlationKey = "testCorrelation") → SubProcess
+ └─ SubStart → IntermediateCatchEvent[Message-CorrelationMessage,
correlated] → SubEnd
+ → End
+
+ CorrelationSubscription binds correlationProperty "corrProp" to process
variable "correlationKey".
+ The incoming message must carry the same value in its "key" field.
+-->
+<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:dc="http://www.omg.org/spec/DD/20100524/DC"
+ xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
+ xmlns:tns="http://www.jboss.org/drools"
+ xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd
http://www.jboss.org/drools drools.xsd"
+ id="Definition"
+ expressionLanguage="http://www.mvel.org/2.0"
+ targetNamespace="http://www.jboss.org/drools"
+ typeLanguage="http://www.java.com/javaTypes">
+
+ <!-- item definitions — message type must be fully qualified for classloader
check in CorrelationManager -->
+ <bpmn2:itemDefinition id="_correlationKeyItem"
structureRef="java.lang.String"/>
+ <bpmn2:itemDefinition id="_msgPayloadItem"
structureRef="java.lang.String"/>
+ <bpmn2:itemDefinition id="_corrPropTypeItem"
structureRef="java.lang.String"/>
+
+ <!-- message carrying the correlation key as its payload -->
+ <bpmn2:message id="CorrelationMessage" itemRef="_msgPayloadItem"
name="CorrelationMessage"/>
+
+ <!-- correlation property: the message payload IS the correlation key —
return it as-is via MVEL -->
+ <bpmn2:correlationProperty id="corrProp" name="corrProp"
type="_corrPropTypeItem">
+ <bpmn2:correlationPropertyRetrievalExpression
messageRef="CorrelationMessage">
+ <!-- "this" in MVEL returns the root object itself, i.e. the String
payload -->
+ <bpmn2:messagePath evaluatesToTypeRef="_corrPropTypeItem"
language="java">this</bpmn2:messagePath>
+ </bpmn2:correlationPropertyRetrievalExpression>
+ </bpmn2:correlationProperty>
+
+ <!-- collaboration wrapping the correlation key -->
+ <bpmn2:collaboration id="_collaboration">
+ <bpmn2:participant id="_participant"
processRef="IntermediateCatchEventMessageCorrelationInSubprocess"/>
+ <bpmn2:correlationKey id="corrKey" name="corrProp">
+ <bpmn2:correlationPropertyRef>corrProp</bpmn2:correlationPropertyRef>
+ </bpmn2:correlationKey>
+ </bpmn2:collaboration>
+
+ <bpmn2:process
+ id="IntermediateCatchEventMessageCorrelationInSubprocess"
+ tns:packageName="org.jbpm.bpmn2.intermediate"
+ tns:version="1"
+ name="IntermediateCatchEventMessageCorrelationInSubprocess"
+ isExecutable="true"
+ processType="Private">
+
+ <!-- process variables -->
+ <bpmn2:property id="correlationKey" itemSubjectRef="_correlationKeyItem"
name="correlationKey"/>
+ <bpmn2:property id="receivedValue" itemSubjectRef="_msgPayloadItem"
name="receivedValue"/>
+
+ <!-- correlation subscription: the process-side value comes from
"correlationKey" variable -->
+ <bpmn2:correlationSubscription correlationKeyRef="corrKey">
+ <bpmn2:correlationPropertyBinding correlationPropertyRef="corrProp">
+ <bpmn2:dataPath evaluatesToTypeRef="_corrPropTypeItem"
language="java">correlationKey</bpmn2:dataPath>
+ </bpmn2:correlationPropertyBinding>
+ </bpmn2:correlationSubscription>
+
+ <!-- nodes -->
+ <bpmn2:startEvent id="StartEvent_1" name="Start">
+ <bpmn2:outgoing>SequenceFlow_1</bpmn2:outgoing>
+ </bpmn2:startEvent>
+
+ <!-- Script task sets the correlation variable before entering the
subprocess -->
+ <bpmn2:scriptTask id="ScriptTask_setCorrelation" name="Set Correlation"
scriptFormat="http://www.java.com/java">
+ <bpmn2:incoming>SequenceFlow_1</bpmn2:incoming>
+ <bpmn2:outgoing>SequenceFlow_2</bpmn2:outgoing>
+ <bpmn2:script>kcontext.setVariable("correlationKey",
"testCorrelation");</bpmn2:script>
+ </bpmn2:scriptTask>
+
+ <!-- Embedded subprocess containing the IntermediateCatchEvent -->
+ <bpmn2:subProcess id="SubProcess_1" name="Wait for correlated message">
+ <bpmn2:incoming>SequenceFlow_2</bpmn2:incoming>
+ <bpmn2:outgoing>SequenceFlow_3</bpmn2:outgoing>
+
+ <bpmn2:startEvent id="SubStart" name="SubStart">
+ <bpmn2:outgoing>SubFlow_1</bpmn2:outgoing>
+ </bpmn2:startEvent>
+
+ <bpmn2:intermediateCatchEvent id="CatchMsg" name="Catch Correlated
Message">
+ <bpmn2:incoming>SubFlow_1</bpmn2:incoming>
+ <bpmn2:outgoing>SubFlow_2</bpmn2:outgoing>
+ <bpmn2:dataOutput id="CatchMsg_output"
itemSubjectRef="_msgPayloadItem" name="event"/>
+ <bpmn2:dataOutputAssociation>
+ <bpmn2:sourceRef>CatchMsg_output</bpmn2:sourceRef>
+ <bpmn2:targetRef>receivedValue</bpmn2:targetRef>
+ </bpmn2:dataOutputAssociation>
+ <bpmn2:outputSet>
+ <bpmn2:dataOutputRefs>CatchMsg_output</bpmn2:dataOutputRefs>
+ </bpmn2:outputSet>
+ <bpmn2:messageEventDefinition messageRef="CorrelationMessage"/>
+ </bpmn2:intermediateCatchEvent>
+
+ <bpmn2:endEvent id="SubEnd" name="SubEnd">
+ <bpmn2:incoming>SubFlow_2</bpmn2:incoming>
+ </bpmn2:endEvent>
+
+ <bpmn2:sequenceFlow id="SubFlow_1" sourceRef="SubStart"
targetRef="CatchMsg"/>
+ <bpmn2:sequenceFlow id="SubFlow_2" sourceRef="CatchMsg"
targetRef="SubEnd"/>
+ </bpmn2:subProcess>
+
+ <bpmn2:endEvent id="EndEvent_1" name="End">
+ <bpmn2:incoming>SequenceFlow_3</bpmn2:incoming>
+ </bpmn2:endEvent>
+
+ <bpmn2:sequenceFlow id="SequenceFlow_1" sourceRef="StartEvent_1"
targetRef="ScriptTask_setCorrelation"/>
+ <bpmn2:sequenceFlow id="SequenceFlow_2"
sourceRef="ScriptTask_setCorrelation" targetRef="SubProcess_1"/>
+ <bpmn2:sequenceFlow id="SequenceFlow_3" sourceRef="SubProcess_1"
targetRef="EndEvent_1"/>
+
+ </bpmn2:process>
+
+ <bpmndi:BPMNDiagram id="BPMNDiagram_1">
+ <bpmndi:BPMNPlane id="BPMNPlane_1"
bpmnElement="IntermediateCatchEventMessageCorrelationInSubprocess">
+ <bpmndi:BPMNShape id="Shape_StartEvent_1" bpmnElement="StartEvent_1">
+ <dc:Bounds x="50" y="100" width="36" height="36"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Shape_ScriptTask_setCorrelation"
bpmnElement="ScriptTask_setCorrelation">
+ <dc:Bounds x="140" y="78" width="100" height="80"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Shape_SubProcess_1" bpmnElement="SubProcess_1"
isExpanded="true">
+ <dc:Bounds x="300" y="40" width="400" height="160"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Shape_SubStart" bpmnElement="SubStart">
+ <dc:Bounds x="330" y="102" width="36" height="36"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Shape_CatchMsg" bpmnElement="CatchMsg">
+ <dc:Bounds x="430" y="102" width="36" height="36"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Shape_SubEnd" bpmnElement="SubEnd">
+ <dc:Bounds x="600" y="102" width="36" height="36"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNShape id="Shape_EndEvent_1" bpmnElement="EndEvent_1">
+ <dc:Bounds x="760" y="100" width="36" height="36"/>
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNEdge id="Edge_SequenceFlow_1" bpmnElement="SequenceFlow_1">
+ <di:waypoint x="86" y="118"/>
+ <di:waypoint x="140" y="118"/>
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge id="Edge_SequenceFlow_2" bpmnElement="SequenceFlow_2">
+ <di:waypoint x="240" y="118"/>
+ <di:waypoint x="300" y="120"/>
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge id="Edge_SequenceFlow_3" bpmnElement="SequenceFlow_3">
+ <di:waypoint x="700" y="120"/>
+ <di:waypoint x="760" y="118"/>
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge id="Edge_SubFlow_1" bpmnElement="SubFlow_1">
+ <di:waypoint x="366" y="120"/>
+ <di:waypoint x="430" y="120"/>
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge id="Edge_SubFlow_2" bpmnElement="SubFlow_2">
+ <di:waypoint x="466" y="120"/>
+ <di:waypoint x="600" y="120"/>
+ </bpmndi:BPMNEdge>
+ </bpmndi:BPMNPlane>
+ </bpmndi:BPMNDiagram>
+
+</bpmn2:definitions>
\ No newline at end of file
diff --git
a/kogito-jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/IntermediateEventTest.java
b/kogito-jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/IntermediateEventTest.java
index d5a26665044..6a57dc9fb88 100755
---
a/kogito-jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/IntermediateEventTest.java
+++
b/kogito-jbpm/jbpm-tests/src/test/java/org/jbpm/bpmn2/IntermediateEventTest.java
@@ -2991,4 +2991,28 @@ public class IntermediateEventTest extends
JbpmBpmn2TestCase {
.isEqualTo(ProcessInstance.STATE_COMPLETED);
}
+ @Test
+ public void testIntermediateCatchEventMessageCorrelationInSubprocess() {
+ Application app = ProcessTestHelper.newApplication();
+
org.kie.kogito.process.Process<IntermediateCatchEventMessageCorrelationInSubprocessModel>
processDefinition =
+
IntermediateCatchEventMessageCorrelationInSubprocessProcess.newProcess(app);
+ IntermediateCatchEventMessageCorrelationInSubprocessModel model =
processDefinition.createModel();
+
org.kie.kogito.process.ProcessInstance<IntermediateCatchEventMessageCorrelationInSubprocessModel>
instance =
+ processDefinition.createInstance(model);
+ instance.start();
+ assertThat(instance.status()).isEqualTo(ProcessInstance.STATE_ACTIVE);
+
+ // Send a message with a WRONG correlation key — must be ignored.
+ instance.send(SignalFactory.of("Message-CorrelationMessage",
"wrongCorrelation"));
+ assertThat(instance.status())
+ .as("Process must remain ACTIVE after a non-matching
correlation key")
+ .isEqualTo(ProcessInstance.STATE_ACTIVE);
+
+ // Send the CORRECT correlation key — process must now complete.
+ instance.send(SignalFactory.of("Message-CorrelationMessage",
"testCorrelation"));
+ assertThat(instance.status())
+ .as("Process must complete after the matching correlation key")
+ .isEqualTo(ProcessInstance.STATE_COMPLETED);
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]