This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new c92e25590855 CAMEL-25125: camel-mllp - ACK generation uses the MSH-2
component separator, not '^' (#27034)
c92e25590855 is described below
commit c92e255908550b015639388f934d0e07932db048
Author: allthingssecurity <[email protected]>
AuthorDate: Tue Sep 29 17:25:53 2026 +0530
CAMEL-25125: camel-mllp - ACK generation uses the MSH-2 component
separator, not '^' (#27034)
* CAMEL-25125: camel-mllp - ACK generation uses the MSH-2 component
separator, not '^'
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
.../camel/component/mllp/internal/Hl7Util.java | 12 ++---
...knowledgementWithoutBridgeErrorHandlerTest.java | 19 ++++++++
.../camel/component/mllp/internal/Hl7UtilTest.java | 57 ++++++++++++++++++++++
3 files changed, 82 insertions(+), 6 deletions(-)
diff --git
a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/internal/Hl7Util.java
b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/internal/Hl7Util.java
index 3d3a308a8767..5e5c8a3c0c4a 100644
---
a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/internal/Hl7Util.java
+++
b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/internal/Hl7Util.java
@@ -305,9 +305,9 @@ public final class Hl7Util {
if (-1 == msh92start) {
LOG.warn("Didn't find component separator for MSH-9.2 - sending
ACK in MSH-9");
} else {
- final String msh9Content =
convertToPrintFriendlyString(hl7MessageBytes, fieldSeparatorIndexes.get(7) + 1,
- fieldSeparatorIndexes.get(8));
- final int[] componentIndexesInMsh9 = caretPositionsIn(msh9Content);
+ // the component separators of MSH-9, from the one that starts
MSH-9.2 (MSH-2 may define another one than '^')
+ final int[] componentIndexesInMsh9
+ = componentSeparatorIndexes(hl7MessageBytes, msh92start,
fieldSeparatorIndexes.get(8), componentSeparator);
final int componentDiff =
componentIndexesInMsh9[componentIndexesInMsh9.length - 1] -
componentIndexesInMsh9[0];
if (componentIndexesInMsh9.length == 2) { //MSH-9.3 is an optional
field since 2.3.1, required since 2.5; this is a non-breaking change by just
checking the number of the components in the field MSH-9
@@ -486,9 +486,9 @@ public final class Hl7Util {
return String.valueOf(c);
}
- private int[] caretPositionsIn(String data) {
- return IntStream.range(0, data.length())
- .filter(i -> data.charAt(i) == '^')
+ private static int[] componentSeparatorIndexes(byte[] hl7MessageBytes, int
start, int end, byte componentSeparator) {
+ return IntStream.range(start, end)
+ .filter(i -> hl7MessageBytes[i] == componentSeparator)
.toArray();
}
diff --git
a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerAutoAcknowledgementWithoutBridgeErrorHandlerTest.java
b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerAutoAcknowledgementWithoutBridgeErrorHandlerTest.java
index 81d950e9dc60..a1a94f122c32 100644
---
a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerAutoAcknowledgementWithoutBridgeErrorHandlerTest.java
+++
b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerAutoAcknowledgementWithoutBridgeErrorHandlerTest.java
@@ -17,6 +17,7 @@
package org.apache.camel.component.mllp;
import org.apache.camel.Exchange;
+import org.apache.camel.component.mock.MockEndpoint;
import org.junit.jupiter.api.Test;
import static org.apache.camel.test.junit6.TestSupport.assertIsInstanceOf;
@@ -58,6 +59,24 @@ public class
MllpTcpServerConsumerAutoAcknowledgementWithoutBridgeErrorHandlerTe
assertThat(acknowledgement,
endsWith("||ACK^A04^ACK|||2.6\rMSA|AA|\r"));
}
+ @Test
+ public void testReceiveMessageWithOtherComponentSeparator() throws
Exception {
+ // MSH-2 defines the separators, and the component separator does not
have to be '^'
+ final String testMessage =
TEST_MESSAGE.replace("MSH|^~\\&|APP_A|FAC_A|^org^sys||||ADT^A04^ADT_A04|",
+ "MSH|$~\\&|APP_A|FAC_A|$org$sys||||ADT$A04$ADT_A04|");
+
+ result.expectedBodiesReceived(testMessage);
+ complete.expectedBodiesReceived(testMessage);
+
complete.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE, "AA");
+
+ mllpClient.connect();
+ String acknowledgement =
mllpClient.sendMessageAndWaitForAcknowledgement(testMessage);
+
+ MockEndpoint.assertIsSatisfied(context);
+ assertThat(acknowledgement,
startsWith("MSH|$~\\&|$org$sys||APP_A|FAC_A|"));
+ assertThat(acknowledgement,
endsWith("||ACK$A04$ACK|||2.6\rMSA|AA|\r"));
+ }
+
public void testAcknowledgementDeliveryFailure() throws Exception {
result.expectedBodiesReceived(TEST_MESSAGE);
diff --git
a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/internal/Hl7UtilTest.java
b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/internal/Hl7UtilTest.java
index 82b1cba72ba8..ca733f0dbeaa 100644
---
a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/internal/Hl7UtilTest.java
+++
b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/internal/Hl7UtilTest.java
@@ -110,6 +110,12 @@ public class Hl7UtilTest {
+
MllpProtocolConstants.END_OF_BLOCK
+
MllpProtocolConstants.END_OF_DATA;
+ static final String MSH_SEGMENT_BEFORE_MSH9_OTHER_SEPARATOR
+ = "MSH|$~\\&|REQUESTING|ICE|INHOUSE|RTH00|20250912193919||";
+
+ static final String EXPECTED_ACKNOWLEDGEMENT_PAYLOAD_START_OTHER_SEPARATOR
+ = MllpProtocolConstants.START_OF_BLOCK +
"MSH|$~\\&|INHOUSE|RTH00|REQUESTING|ICE|";
+
static final byte[] TEST_MESSAGE_BYTES = TEST_MESSAGE.getBytes();
private final Hl7Util hl7util = new Hl7Util(5120, LOG_PHI_TRUE);
@@ -775,4 +781,55 @@ public class Hl7UtilTest {
assertThat(actual, endsWith("||ACK^T01^ACK" +
EXPECTED_ACKNOWLEDGEMENT_PAYLOAD_END_MSH));
}
+ @Test
+ public void
testGenerateAcknowledgementPayloadWithOtherComponentSeparator() throws
Exception {
+ final MllpSocketBuffer mllpSocketBuffer = new MllpSocketBuffer(new
MllpEndpointStub());
+ final String testMessage = MSH_SEGMENT_BEFORE_MSH9_OTHER_SEPARATOR +
"MDM$T01" + MSH_SEGMENT_AFTER_MSH9;
+ hl7util.generateAcknowledgementPayload(mllpSocketBuffer,
testMessage.getBytes(), "AA");
+
+ final String actual = mllpSocketBuffer.toString();
+
+ assertThat(actual,
startsWith(EXPECTED_ACKNOWLEDGEMENT_PAYLOAD_START_OTHER_SEPARATOR));
+ assertThat(actual, endsWith("||ACK$T01" +
EXPECTED_ACKNOWLEDGEMENT_PAYLOAD_END_MSH));
+ }
+
+ @Test
+ public void
testGenerateAcknowledgementPayloadWithOtherComponentSeparatorAndMsh93() throws
Exception {
+ final MllpSocketBuffer mllpSocketBuffer = new MllpSocketBuffer(new
MllpEndpointStub());
+ final String testMessage = MSH_SEGMENT_BEFORE_MSH9_OTHER_SEPARATOR +
"MDM$T01$MDM_T01" + MSH_SEGMENT_AFTER_MSH9;
+ hl7util.generateAcknowledgementPayload(mllpSocketBuffer,
testMessage.getBytes(), "AA");
+
+ final String actual = mllpSocketBuffer.toString();
+
+ assertThat(actual,
startsWith(EXPECTED_ACKNOWLEDGEMENT_PAYLOAD_START_OTHER_SEPARATOR));
+ assertThat(actual, endsWith("||ACK$T01$ACK" +
EXPECTED_ACKNOWLEDGEMENT_PAYLOAD_END_MSH));
+ }
+
+ @Test
+ public void
testGenerateAcknowledgementPayloadWithOtherComponentSeparatorAndCaretInMsh93()
throws Exception {
+ final MllpSocketBuffer mllpSocketBuffer = new MllpSocketBuffer(new
MllpEndpointStub());
+ // '^' is not a separator here, so MSH-9 has three components
+ final String testMessage = MSH_SEGMENT_BEFORE_MSH9_OTHER_SEPARATOR +
"MDM$T01$MDM^T01" + MSH_SEGMENT_AFTER_MSH9;
+ hl7util.generateAcknowledgementPayload(mllpSocketBuffer,
testMessage.getBytes(), "AA");
+
+ final String actual = mllpSocketBuffer.toString();
+
+ assertThat(actual,
startsWith(EXPECTED_ACKNOWLEDGEMENT_PAYLOAD_START_OTHER_SEPARATOR));
+ assertThat(actual, endsWith("||ACK$T01$ACK" +
EXPECTED_ACKNOWLEDGEMENT_PAYLOAD_END_MSH));
+ }
+
+ @Test
+ public void
testGenerateAcknowledgementPayloadWithMsh93AndSmallLogPhiMaxBytes() throws
Exception {
+ // logPhiMaxBytes only limits what is logged, it must not change the
acknowledgement
+ final Hl7Util local = new Hl7Util(3, LOG_PHI_TRUE);
+ final MllpSocketBuffer mllpSocketBuffer = new MllpSocketBuffer(new
MllpEndpointStub());
+ final String testMessage = MSH_SEGMENT_BEFORE_MSH9 + "MDM^T01^MDM_T01"
+ MSH_SEGMENT_AFTER_MSH9;
+ local.generateAcknowledgementPayload(mllpSocketBuffer,
testMessage.getBytes(), "AA");
+
+ final String actual = mllpSocketBuffer.toString();
+
+ assertThat(actual, startsWith(EXPECTED_ACKNOWLEDGEMENT_PAYLOAD_START));
+ assertThat(actual, endsWith("||ACK^T01^ACK" +
EXPECTED_ACKNOWLEDGEMENT_PAYLOAD_END_MSH));
+ }
+
}