You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2016/04/14 07:43:26 UTC

[3/5] camel git commit: CAMEL-9876 - fix IndexOutOfBounds exception when MSH-18 isn't in message

CAMEL-9876 - fix IndexOutOfBounds exception when MSH-18 isn't in message


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/57f9f49c
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/57f9f49c
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/57f9f49c

Branch: refs/heads/camel-2.17.x
Commit: 57f9f49c2292aeecf0c38c7005a1ffea9d91bd8f
Parents: f043e47
Author: Quinn Stevenson <qu...@pronoia-solutions.com>
Authored: Wed Apr 13 11:40:22 2016 -0600
Committer: Claus Ibsen <da...@apache.org>
Committed: Thu Apr 14 07:42:47 2016 +0200

----------------------------------------------------------------------
 .../component/mllp/MllpTcpServerConsumer.java   | 113 ++++++++++--------
 ...llpTcpServerConsumerAcknowledgementTest.java | 114 +++++++++++++++++++
 2 files changed, 181 insertions(+), 46 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/57f9f49c/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpServerConsumer.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpServerConsumer.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpServerConsumer.java
index 95a2d22..c025f80 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpServerConsumer.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpServerConsumer.java
@@ -543,7 +543,6 @@ public class MllpTcpServerConsumer extends DefaultConsumer {
         private void populateHl7DataHeaders(Exchange exchange, Message message, byte[] hl7MessageBytes) {
             // Find the end of the MSH and indexes of the fields in the MSH to populate message headers
             final byte fieldSeparator = hl7MessageBytes[3];
-            final byte componentSeparator = hl7MessageBytes[4];
             int endOfMSH = -1;
             List<Integer> fieldSeparatorIndexes = new ArrayList<>(10);  // We need at least 10 fields to create the acknowledgment
 
@@ -551,11 +550,16 @@ public class MllpTcpServerConsumer extends DefaultConsumer {
                 if (fieldSeparator == hl7MessageBytes[i]) {
                     fieldSeparatorIndexes.add(i);
                 } else if (SEGMENT_DELIMITER == hl7MessageBytes[i]) {
+                    // If the MSH Segment doesn't have a trailing field separator, add one so the field can be extracted into a header
+                    if (fieldSeparator != hl7MessageBytes[i - 1]) {
+                        fieldSeparatorIndexes.add(i);
+                    }
                     endOfMSH = i;
                     break;
                 }
             }
 
+            String messageBodyForDebugging = new String(hl7MessageBytes);
             if (-1 == endOfMSH) {
                 // TODO:  May want to throw some sort of an Exception here
                 log.error("Population of message headers failed - unable to find the end of the MSH segment");
@@ -563,54 +567,71 @@ public class MllpTcpServerConsumer extends DefaultConsumer {
                 log.debug("Populating the message headers");
                 Charset charset = Charset.forName(IOHelper.getCharsetName(exchange));
 
-                // MSH-3
-                message.setHeader(MLLP_SENDING_APPLICATION, new String(hl7MessageBytes, fieldSeparatorIndexes.get(1) + 1,
-                        fieldSeparatorIndexes.get(2) - fieldSeparatorIndexes.get(1) - 1, charset));
-                // MSH-4
-                message.setHeader(MLLP_SENDING_FACILITY, new String(hl7MessageBytes, fieldSeparatorIndexes.get(2) + 1,
-                        fieldSeparatorIndexes.get(3) - fieldSeparatorIndexes.get(2) - 1, charset));
-                // MSH-5
-                message.setHeader(MLLP_RECEIVING_APPLICATION, new String(hl7MessageBytes, fieldSeparatorIndexes.get(3) + 1,
-                        fieldSeparatorIndexes.get(4) - fieldSeparatorIndexes.get(3) - 1,
-                        charset));
-                // MSH-6
-                message.setHeader(MLLP_RECEIVING_FACILITY, new String(hl7MessageBytes, fieldSeparatorIndexes.get(4) + 1,
-                        fieldSeparatorIndexes.get(5) - fieldSeparatorIndexes.get(4) - 1,
-                        charset));
-                // MSH-7
-                message.setHeader(MLLP_TIMESTAMP, new String(hl7MessageBytes, fieldSeparatorIndexes.get(5) + 1,
-                        fieldSeparatorIndexes.get(6) - fieldSeparatorIndexes.get(5) - 1, charset));
-                // MSH-8
-                message.setHeader(MLLP_SECURITY, new String(hl7MessageBytes, fieldSeparatorIndexes.get(6) + 1,
-                        fieldSeparatorIndexes.get(7) - fieldSeparatorIndexes.get(6) - 1, charset));
-                // MSH-9
-                message.setHeader(MLLP_MESSAGE_TYPE, new String(hl7MessageBytes, fieldSeparatorIndexes.get(7) + 1,
-                        fieldSeparatorIndexes.get(8) - fieldSeparatorIndexes.get(7) - 1, charset));
-                // MSH-10
-                message.setHeader(MLLP_MESSAGE_CONTROL, new String(hl7MessageBytes, fieldSeparatorIndexes.get(8) + 1,
-                        fieldSeparatorIndexes.get(9) - fieldSeparatorIndexes.get(8) - 1, charset));
-                // MSH-11
-                message.setHeader(MLLP_PROCESSING_ID, new String(hl7MessageBytes, fieldSeparatorIndexes.get(9) + 1,
-                        fieldSeparatorIndexes.get(10) - fieldSeparatorIndexes.get(9) - 1, charset));
-                // MSH-12
-                message.setHeader(MLLP_VERSION_ID, new String(hl7MessageBytes, fieldSeparatorIndexes.get(10) + 1,
-                        fieldSeparatorIndexes.get(11) - fieldSeparatorIndexes.get(10) - 1, charset));
-                // MSH-18
-                message.setHeader(MLLP_CHARSET, new String(hl7MessageBytes, fieldSeparatorIndexes.get(16) + 1,
-                        fieldSeparatorIndexes.get(17) - fieldSeparatorIndexes.get(16) - 1, charset));
-
-                for (int i = fieldSeparatorIndexes.get(7) + 1; i < fieldSeparatorIndexes.get(8); ++i) {
-                    if (componentSeparator == hl7MessageBytes[i]) {
-                        // MSH-9.1
-                        message.setHeader(MLLP_EVENT_TYPE, new String(hl7MessageBytes, fieldSeparatorIndexes.get(7) + 1,
-                                i - fieldSeparatorIndexes.get(7) - 1, charset));
-                        // MSH-9.2
-                        message.setHeader(MLLP_TRIGGER_EVENT, new String(hl7MessageBytes, i + 1,
-                                fieldSeparatorIndexes.get(8) - i - 1, charset));
-                        break;
+                for (int i = 2; i < fieldSeparatorIndexes.size(); ++i) {
+                    int startingFieldSeparatorIndex = fieldSeparatorIndexes.get(i - 1);
+                    int endingFieldSeparatorIndex = fieldSeparatorIndexes.get(i);
+
+                    // Only populate the header if there's data in the HL7 field
+                    if (endingFieldSeparatorIndex - startingFieldSeparatorIndex > 1) {
+                        String headerName = null;
+                        switch (i) {
+                        case 2: // MSH-3
+                            headerName = MLLP_SENDING_APPLICATION;
+                            break;
+                        case 3: // MSH-4
+                            headerName = MLLP_SENDING_FACILITY;
+                            break;
+                        case 4: // MSH-5
+                            headerName = MLLP_RECEIVING_APPLICATION;
+                            break;
+                        case 5: // MSH-6
+                            headerName = MLLP_RECEIVING_FACILITY;
+                            break;
+                        case 6: // MSH-7
+                            headerName = MLLP_TIMESTAMP;
+                            break;
+                        case 7: // MSH-8
+                            headerName = MLLP_SECURITY;
+                            break;
+                        case 8: // MSH-9
+                            headerName = MLLP_MESSAGE_TYPE;
+                            break;
+                        case 9: // MSH-10
+                            headerName = MLLP_MESSAGE_CONTROL;
+                            break;
+                        case 10: // MSH-11
+                            headerName = MLLP_PROCESSING_ID;
+                            break;
+                        case 11: // MSH-12
+                            headerName = MLLP_VERSION_ID;
+                            break;
+                        case 17: // MSH-18
+                            headerName = MLLP_CHARSET;
+                            break;
+                        default:
+                            // Not processing this field
+                            continue;
+                        }
+
+                        String headerValue = new String(hl7MessageBytes, startingFieldSeparatorIndex + 1,
+                                endingFieldSeparatorIndex - startingFieldSeparatorIndex - 1,
+                                charset);
+                        message.setHeader(headerName, headerValue);
+
+                        // For MSH-9, set a couple more headers
+                        if (i == 8) {
+                            // final byte componentSeparator = hl7MessageBytes[4];
+                            String componentSeparator = new String(hl7MessageBytes, 4, 1, charset);
+                            String[] components = headerValue.split(String.format("\\Q%s\\E", componentSeparator), 3);
+                            message.setHeader(MLLP_EVENT_TYPE, components[0]);
+                            if (2 <= components.length) {
+                                message.setHeader(MLLP_TRIGGER_EVENT, components[1]);
+                            }
+                        }
                     }
                 }
             }
+
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/camel/blob/57f9f49c/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerAcknowledgementTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerAcknowledgementTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerAcknowledgementTest.java
new file mode 100644
index 0000000..33ce3c8
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerAcknowledgementTest.java
@@ -0,0 +1,114 @@
+/**
+ * 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.
+ */
+package org.apache.camel.component.mllp;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.LoggingLevel;
+import org.apache.camel.builder.NotifyBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.test.AvailablePortFinder;
+import org.apache.camel.test.junit.rule.mllp.MllpClientResource;
+import org.apache.camel.test.junit.rule.mllp.MllpJUnitResourceException;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_EVENT_TYPE;
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_RECEIVING_APPLICATION;
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_RECEIVING_FACILITY;
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_SENDING_APPLICATION;
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_SENDING_FACILITY;
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_TRIGGER_EVENT;
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_VERSION_ID;
+import static org.apache.camel.test.mllp.Hl7MessageGenerator.generateMessage;
+
+public class MllpTcpServerConsumerAcknowledgementTest extends CamelTestSupport {
+    @Rule
+    public MllpClientResource mllpClient = new MllpClientResource();
+
+    @EndpointInject(uri = "mock://result")
+    MockEndpoint result;
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        DefaultCamelContext context = (DefaultCamelContext) super.createCamelContext();
+
+        context.setUseMDCLogging(true);
+        context.setName(this.getClass().getSimpleName());
+
+        return context;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+
+        mllpClient.setMllpHost("localhost");
+        mllpClient.setMllpPort(AvailablePortFinder.getNextAvailable());
+
+        return new RouteBuilder() {
+            int connectTimeout = 500;
+            int responseTimeout = 5000;
+
+            @Override
+            public void configure() throws Exception {
+                String routeId = "mllp-test-receiver-route";
+
+                onCompletion()
+                        .toF("log:%s?level=INFO&showAll=true", routeId)
+                        .log(LoggingLevel.INFO, routeId, "Test route complete");
+
+                fromF("mllp://%s:%d?autoAck=true&connectTimeout=%d&receiveTimeout=%d",
+                        mllpClient.getMllpHost(), mllpClient.getMllpPort(), connectTimeout, responseTimeout)
+                        .routeId(routeId)
+                        .to(result);
+
+            }
+        };
+    }
+
+    @Test
+    public void testReceiveSingleMessage() throws Exception {
+        final String testMessage = "MSH|^~\\&|APP_A|FAC_A|^org^sys||||ADT^A04^ADT_A04|||2.6" + '\r'
+                + "PID|1||1100832^^^^PI||TEST^FIG||98765432|U||R|435 MAIN STREET^^LONGMONT^CO^80503||123-456-7890|||S" + '\r'
+                + '\r' + '\n';
+
+        final String expectedAcknowledgement = "MSH|^~\\&|^org^sys||APP_A|FAC_A|||ACK^A04^ADT_A04|||2.6" + '\r' + "MSA|AA|" + '\r' + '\n';
+
+        result.expectedMessageCount(1);
+        result.expectedHeaderReceived(MLLP_SENDING_APPLICATION, "APP_A");
+        result.expectedHeaderReceived(MLLP_SENDING_FACILITY, "FAC_A");
+        result.expectedHeaderReceived(MLLP_RECEIVING_APPLICATION, "^org^sys");
+        result.expectedHeaderReceived(MLLP_EVENT_TYPE, "ADT");
+        result.expectedHeaderReceived(MLLP_TRIGGER_EVENT, "A04");
+        result.expectedHeaderReceived(MLLP_VERSION_ID, "2.6");
+
+        mllpClient.connect();
+
+        String acknowledgement = mllpClient.sendMessageAndWaitForAcknowledgement(testMessage, 10000);
+
+        assertEquals("Unexpected Acknowledgement", expectedAcknowledgement, acknowledgement);
+
+        assertMockEndpointsSatisfied(10, TimeUnit.SECONDS);
+    }
+
+}
+