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/12/16 08:08:12 UTC

[1/8] camel git commit: CAMEL-10511: Updated MllpTcpClientProducer and MllpTcpServerConsumer to consume all available data on socket

Repository: camel
Updated Branches:
  refs/heads/camel-2.18.x 0ed067b1e -> ba8f3aa04
  refs/heads/master 911218438 -> 58e36d63b


http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/test/junit/rule/mllp/MllpServerResource.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/test/junit/rule/mllp/MllpServerResource.java b/components/camel-mllp/src/test/java/org/apache/camel/test/junit/rule/mllp/MllpServerResource.java
index fe1ad40..880761c 100644
--- a/components/camel-mllp/src/test/java/org/apache/camel/test/junit/rule/mllp/MllpServerResource.java
+++ b/components/camel-mllp/src/test/java/org/apache/camel/test/junit/rule/mllp/MllpServerResource.java
@@ -19,6 +19,7 @@ package org.apache.camel.test.junit.rule.mllp;
 import java.io.BufferedOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.net.BindException;
 import java.net.InetSocketAddress;
 import java.net.ServerSocket;
@@ -45,8 +46,6 @@ import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
  *
  * The server can be configured to simulate a large number
  * of error conditions.
- *
- * TODO:  This needs to be looked at - it may be orphaning threads
  */
 public class MllpServerResource extends ExternalResource {
     Logger log = LoggerFactory.getLogger(this.getClass());
@@ -59,6 +58,12 @@ public class MllpServerResource extends ExternalResource {
 
     boolean active = true;
 
+    int delayBeforeStartOfBlock;
+    int delayBeforeAcknowledgement;
+    int delayDuringAcknowledgement;
+    int delayAfterAcknowledgement;
+    int delayAfterEndOfBlock;
+
     int excludeStartOfBlockModulus;
     int excludeEndOfBlockModulus;
     int excludeEndOfDataModulus;
@@ -67,8 +72,11 @@ public class MllpServerResource extends ExternalResource {
 
     int sendOutOfBandDataModulus;
 
-    int disconnectBeforeAcknowledgementModulus;
-    int disconnectAfterAcknowledgementModulus;
+    int closeSocketBeforeAcknowledgementModulus;
+    int closeSocketAfterAcknowledgementModulus;
+
+    int resetSocketBeforeAcknowledgementModulus;
+    int resetSocketAfterAcknowledgementModulus;
 
     int sendApplicationRejectAcknowledgementModulus;
     int sendApplicationErrorAcknowledgementModulus;
@@ -76,6 +84,8 @@ public class MllpServerResource extends ExternalResource {
     Pattern sendApplicationRejectAcknowledgementPattern;
     Pattern sendApplicationErrorAcknowledgementPattern;
 
+    String acknowledgementString;
+
     ServerSocketThread serverSocketThread;
 
     public MllpServerResource() {
@@ -166,6 +176,46 @@ public class MllpServerResource extends ExternalResource {
         serverSocketThread.interrupt();
     }
 
+    public int getDelayBeforeStartOfBlock() {
+        return delayBeforeStartOfBlock;
+    }
+
+    public void setDelayBeforeStartOfBlock(int delayBeforeStartOfBlock) {
+        this.delayBeforeStartOfBlock = delayBeforeStartOfBlock;
+    }
+
+    public int getDelayBeforeAcknowledgement() {
+        return delayBeforeAcknowledgement;
+    }
+
+    public void setDelayBeforeAcknowledgement(int delayBeforeAcknowledgement) {
+        this.delayBeforeAcknowledgement = delayBeforeAcknowledgement;
+    }
+
+    public int getDelayDuringAcknowledgement() {
+        return delayDuringAcknowledgement;
+    }
+
+    public void setDelayDuringAcknowledgement(int delayDuringAcknowledgement) {
+        this.delayDuringAcknowledgement = delayDuringAcknowledgement;
+    }
+
+    public int getDelayAfterAcknowledgement() {
+        return delayAfterAcknowledgement;
+    }
+
+    public void setDelayAfterAcknowledgement(int delayAfterAcknowledgement) {
+        this.delayAfterAcknowledgement = delayAfterAcknowledgement;
+    }
+
+    public int getDelayAfterEndOfBlock() {
+        return delayAfterEndOfBlock;
+    }
+
+    public void setDelayAfterEndOfBlock(int delayAfterEndOfBlock) {
+        this.delayAfterEndOfBlock = delayAfterEndOfBlock;
+    }
+
     public boolean sendApplicationRejectAcknowledgement(String hl7Message) {
         return evaluatePatten(hl7Message, this.sendApplicationErrorAcknowledgementPattern);
     }
@@ -198,12 +248,20 @@ public class MllpServerResource extends ExternalResource {
         return evaluateModulus(messageCount, excludeEndOfDataModulus);
     }
 
-    public boolean disconnectBeforeAcknowledgement(int messageCount) {
-        return evaluateModulus(messageCount, disconnectBeforeAcknowledgementModulus);
+    public boolean closeSocketBeforeAcknowledgement(int messageCount) {
+        return evaluateModulus(messageCount, closeSocketBeforeAcknowledgementModulus);
     }
 
-    public boolean disconnectAfterAcknowledgement(int messageCount) {
-        return evaluateModulus(messageCount, disconnectAfterAcknowledgementModulus);
+    public boolean closeSocketAfterAcknowledgement(int messageCount) {
+        return evaluateModulus(messageCount, closeSocketAfterAcknowledgementModulus);
+    }
+
+    public boolean resetSocketBeforeAcknowledgement(int messageCount) {
+        return evaluateModulus(messageCount, resetSocketBeforeAcknowledgementModulus);
+    }
+
+    public boolean resetSocketAfterAcknowledgement(int messageCount) {
+        return evaluateModulus(messageCount, resetSocketAfterAcknowledgementModulus);
     }
 
     public boolean sendOutOfBandData(int messageCount) {
@@ -369,27 +427,51 @@ public class MllpServerResource extends ExternalResource {
         }
     }
 
-    public int getDisconnectBeforeAcknowledgementModulus() {
-        return disconnectBeforeAcknowledgementModulus;
+    public int getCloseSocketBeforeAcknowledgementModulus() {
+        return closeSocketBeforeAcknowledgementModulus;
+    }
+
+    public void setCloseSocketBeforeAcknowledgementModulus(int closeSocketBeforeAcknowledgementModulus) {
+        if (0 > closeSocketBeforeAcknowledgementModulus) {
+            this.closeSocketBeforeAcknowledgementModulus = 0;
+        } else {
+            this.closeSocketBeforeAcknowledgementModulus = closeSocketBeforeAcknowledgementModulus;
+        }
+    }
+
+    public int getCloseSocketAfterAcknowledgementModulus() {
+        return closeSocketAfterAcknowledgementModulus;
+    }
+
+    public void setCloseSocketAfterAcknowledgementModulus(int closeSocketAfterAcknowledgementModulus) {
+        if (0 > closeSocketAfterAcknowledgementModulus) {
+            this.closeSocketAfterAcknowledgementModulus = 0;
+        } else {
+            this.closeSocketAfterAcknowledgementModulus = closeSocketAfterAcknowledgementModulus;
+        }
+    }
+
+    public int getResetSocketBeforeAcknowledgementModulus() {
+        return resetSocketBeforeAcknowledgementModulus;
     }
 
-    public void setDisconnectBeforeAcknowledgementModulus(int disconnectBeforeAcknowledgementModulus) {
-        if (0 > disconnectBeforeAcknowledgementModulus) {
-            this.disconnectBeforeAcknowledgementModulus = 0;
+    public void setResetSocketBeforeAcknowledgementModulus(int resetSocketBeforeAcknowledgementModulus) {
+        if (0 > resetSocketBeforeAcknowledgementModulus) {
+            this.resetSocketBeforeAcknowledgementModulus = 0;
         } else {
-            this.disconnectBeforeAcknowledgementModulus = disconnectBeforeAcknowledgementModulus;
+            this.resetSocketBeforeAcknowledgementModulus = resetSocketBeforeAcknowledgementModulus;
         }
     }
 
-    public int getDisconnectAfterAcknowledgementModulus() {
-        return disconnectAfterAcknowledgementModulus;
+    public int getResetSocketAfterAcknowledgementModulus() {
+        return resetSocketAfterAcknowledgementModulus;
     }
 
-    public void setDisconnectAfterAcknowledgementModulus(int disconnectAfterAcknowledgementModulus) {
-        if (0 > disconnectAfterAcknowledgementModulus) {
-            this.disconnectAfterAcknowledgementModulus = 0;
+    public void setResetSocketAfterAcknowledgementModulus(int resetSocketAfterAcknowledgementModulus) {
+        if (0 > resetSocketAfterAcknowledgementModulus) {
+            this.resetSocketAfterAcknowledgementModulus = 0;
         } else {
-            this.disconnectAfterAcknowledgementModulus = disconnectAfterAcknowledgementModulus;
+            this.resetSocketAfterAcknowledgementModulus = resetSocketAfterAcknowledgementModulus;
         }
     }
 
@@ -433,6 +515,14 @@ public class MllpServerResource extends ExternalResource {
         this.sendApplicationErrorAcknowledgementPattern = sendApplicationErrorAcknowledgementPattern;
     }
 
+    public String getAcknowledgementString() {
+        return acknowledgementString;
+    }
+
+    public void setAcknowledgementString(String acknowledgementString) {
+        this.acknowledgementString = acknowledgementString;
+    }
+
     public ServerSocketThread getServerSocketThread() {
         return serverSocketThread;
     }
@@ -441,41 +531,95 @@ public class MllpServerResource extends ExternalResource {
         this.serverSocketThread = serverSocketThread;
     }
 
-    void closeConnection(Socket socket) {
-        if (null != socket) {
-            if (!socket.isClosed()) {
-                try {
-                    socket.shutdownInput();
-                } catch (Exception ex) {
-                    log.warn("Exception encountered shutting down the input stream on the client socket", ex);
-                }
-
-                try {
-                    socket.shutdownOutput();
-                } catch (Exception ex) {
-                    log.warn("Exception encountered shutting down the output stream on the client socket", ex);
-                }
+    public void closeClientConnections() {
+        if (serverSocketThread != null) {
+            serverSocketThread.closeClientConnections();
+        }
+    }
 
-                try {
-                    socket.close();
-                } catch (Exception ex) {
-                    log.warn("Exception encountered closing the client socket", ex);
-                }
-            }
+    public void resetClientConnections() {
+        if (serverSocketThread != null) {
+            serverSocketThread.resetClientConnections();
         }
     }
 
-    void resetConnection(Socket socket) {
-        if (null != socket && !socket.isClosed()) {
-            try {
-                socket.setSoLinger(true, 0);
-            } catch (SocketException socketEx) {
-                log.debug("SocketException encountered setting SO_LINGER to 0 on the socket to force a reset - ignoring", socketEx);
-            } finally {
-                closeConnection(socket);
+    /**
+     * Generates a HL7 Application Acknowledgement
+     *
+     * @param hl7Message          HL7 message that is being acknowledged
+     * @param acknowledgementCode AA, AE or AR
+     * @return a HL7 Application Acknowledgement
+     */
+    protected String generateAcknowledgement(String hl7Message, String acknowledgementCode) {
+        final String defaulNackMessage =
+                "MSH|^~\\&|||||||NACK||P|2.2" + SEGMENT_DELIMITER
+                        + "MSA|AR|" + SEGMENT_DELIMITER
+                        + MESSAGE_TERMINATOR;
+
+        if (hl7Message == null) {
+            log.error("Invalid HL7 message for parsing operation. Please check your inputs");
+            return defaulNackMessage;
+        }
+
+        if (!("AA".equals(acknowledgementCode) || "AE".equals(acknowledgementCode) || "AR".equals(acknowledgementCode))) {
+            throw new IllegalArgumentException("Acknowledgemnt Code must be AA, AE or AR: " + acknowledgementCode);
+        }
+
+        String messageControlId;
+
+        int endOfMshSegment = hl7Message.indexOf(SEGMENT_DELIMITER);
+        if (-1 != endOfMshSegment) {
+            String mshSegment = hl7Message.substring(0, endOfMshSegment);
+            char fieldSeparator = mshSegment.charAt(3);
+            String fieldSeparatorPattern = Pattern.quote("" + fieldSeparator);
+            String[] mshFields = mshSegment.split(fieldSeparatorPattern);
+            if (mshFields.length == 0) {
+                log.error("Failed to split MSH Segment into fields");
+            } else {
+                StringBuilder ackBuilder = new StringBuilder(mshSegment.length() + 25);
+                // Build the MSH Segment
+                ackBuilder
+                        .append(mshFields[0]).append(fieldSeparator)
+                        .append(mshFields[1]).append(fieldSeparator)
+                        .append(mshFields[4]).append(fieldSeparator)
+                        .append(mshFields[5]).append(fieldSeparator)
+                        .append(mshFields[2]).append(fieldSeparator)
+                        .append(mshFields[3]).append(fieldSeparator)
+                        .append(mshFields[6]).append(fieldSeparator)
+                        .append(mshFields[7]).append(fieldSeparator)
+                        .append("ACK")
+                        .append(mshFields[8].substring(3));
+                for (int i = 9; i < mshFields.length; ++i) {
+                    ackBuilder.append(fieldSeparator).append(mshFields[i]);
+                }
+                // Empty fields at the end are not preserved by String.split, so preserve them
+                int emptyFieldIndex = mshSegment.length() - 1;
+                if (fieldSeparator == mshSegment.charAt(mshSegment.length() - 1)) {
+                    ackBuilder.append(fieldSeparator);
+                    while (emptyFieldIndex >= 1 && mshSegment.charAt(emptyFieldIndex) == mshSegment.charAt(emptyFieldIndex - 1)) {
+                        ackBuilder.append(fieldSeparator);
+                        --emptyFieldIndex;
+                    }
+                }
+                ackBuilder.append(SEGMENT_DELIMITER);
+
+                // Build the MSA Segment
+                ackBuilder
+                        .append("MSA").append(fieldSeparator)
+                        .append(acknowledgementCode).append(fieldSeparator)
+                        .append(mshFields[9]).append(fieldSeparator)
+                        .append(SEGMENT_DELIMITER);
+
+                // Terminate the message
+                ackBuilder.append(MESSAGE_TERMINATOR);
+
+                return ackBuilder.toString();
             }
+        } else {
+            log.error("Failed to find the end of the  MSH Segment");
         }
 
+        return null;
     }
 
     /**
@@ -566,6 +710,22 @@ public class MllpServerResource extends ExternalResource {
             log.info("Opened TCP Listener on port {}", serverSocket.getLocalPort());
         }
 
+        void closeClientConnections() {
+            if (clientSocketThreads != null) {
+                for (ClientSocketThread clientSocketThread : clientSocketThreads) {
+                    clientSocketThread.closeConnection();
+                }
+            }
+        }
+
+        void resetClientConnections() {
+            if (clientSocketThreads != null) {
+                for (ClientSocketThread clientSocketThread : clientSocketThreads) {
+                    clientSocketThread.resetConnection();
+                }
+            }
+        }
+
         /**
          * Accept TCP connections and create ClientSocketThreads for them
          */
@@ -586,7 +746,16 @@ public class MllpServerResource extends ExternalResource {
                     if (null == clientSocket) {
                         continue;
                     } else if (!clientSocket.isClosed()) {
-                        resetConnection(clientSocket);
+                        try {
+                            clientSocket.setSoLinger(true, 0);
+                        } catch (SocketException soLingerEx) {
+                            log.warn("Ignoring SocketException encountered when setting SO_LINGER in preparation of resetting client Socket", soLingerEx);
+                        }
+                        try {
+                            clientSocket.close();
+                        } catch (IOException ioEx) {
+                            log.warn("Ignoring IOException encountered when resetting client Socket", ioEx);
+                        }
                         continue;
                     } else {
                         throw new MllpJUnitResourceException("Unexpected SocketException encountered accepting client connection", socketEx);
@@ -685,6 +854,10 @@ public class MllpServerResource extends ExternalResource {
             }
             super.interrupt();
         }
+
+        public void close() {
+
+        }
     }
 
     /**
@@ -711,6 +884,35 @@ public class MllpServerResource extends ExternalResource {
             this.clientSocket = clientSocket;
         }
 
+        void closeConnection() {
+            if (clientSocket != null && !clientSocket.isClosed()) {
+                try {
+                    clientSocket.close();
+                } catch (IOException ioEx) {
+                    log.warn("Ignoring IOException encountered when closing client Socket", ioEx);
+                } finally {
+                    clientSocket = null;
+                }
+            }
+        }
+
+        void resetConnection() {
+            if (clientSocket != null && !clientSocket.isClosed()) {
+                try {
+                    clientSocket.setSoLinger(true, 0);
+                } catch (SocketException socketEx) {
+                    log.warn("Ignoring SocketException encountered when setting SO_LINGER in preparation of resetting client Socket", socketEx);
+                }
+                try {
+                    clientSocket.close();
+                } catch (IOException ioEx) {
+                    log.warn("Ignoring IOException encountered when resetting client Socket", ioEx);
+                } finally {
+                    clientSocket = null;
+                }
+            }
+        }
+
         /**
          * Receives HL7 messages and replies with HL7 Acknowledgements.
          *
@@ -738,12 +940,30 @@ public class MllpServerResource extends ExternalResource {
                     } catch (Exception unexpectedEx) {
                         throw new MllpJUnitResourceException("Unexpected exception encounted getting input stream", unexpectedEx);
                     }
-                    String parsedHL7Message = getMessage(instream);
+                    String parsedHL7Message;
+                    try {
+                        parsedHL7Message = getMessage(instream);
+                    } catch (SocketTimeoutException timeoutEx) {
+                        log.info("Waiting for message from client");
+                        continue;
+                    }
 
                     if (null != parsedHL7Message && parsedHL7Message.length() > 0) {
                         ++messageCounter;
-                        if (disconnectBeforeAcknowledgement(messageCounter)) {
-                            log.warn("Disconnecting before sending acknowledgement");
+                        if (closeSocketBeforeAcknowledgement(messageCounter)) {
+                            log.warn("Closing socket before sending acknowledgement");
+                            clientSocket.shutdownInput();
+                            clientSocket.shutdownOutput();
+                            clientSocket.close();
+                            break;
+                        }
+                        if (resetSocketBeforeAcknowledgement(messageCounter)) {
+                            log.warn("Resetting socket before sending acknowledgement");
+                            try {
+                                clientSocket.setSoLinger(true, 0);
+                            } catch (IOException ioEx) {
+                                log.warn("Ignoring IOException encountered setting SO_LINGER when prepareing to reset socket", ioEx);
+                            }
                             clientSocket.shutdownInput();
                             clientSocket.shutdownOutput();
                             clientSocket.close();
@@ -752,39 +972,67 @@ public class MllpServerResource extends ExternalResource {
 
                         String acknowledgmentMessage;
 
-                        if (sendApplicationErrorAcknowledgement(messageCounter) || sendApplicationErrorAcknowledgement(parsedHL7Message)) {
-                            acknowledgmentMessage = generateAcknowledgementMessage(parsedHL7Message, "AE");
-                        } else if (sendApplicationRejectAcknowledgement(messageCounter) || sendApplicationRejectAcknowledgement(parsedHL7Message)) {
-                            acknowledgmentMessage = generateAcknowledgementMessage(parsedHL7Message, "AR");
+                        if (acknowledgementString == null) {
+                            if (sendApplicationErrorAcknowledgement(messageCounter) || sendApplicationErrorAcknowledgement(parsedHL7Message)) {
+                                acknowledgmentMessage = generateAcknowledgementMessage(parsedHL7Message, "AE");
+                            } else if (sendApplicationRejectAcknowledgement(messageCounter) || sendApplicationRejectAcknowledgement(parsedHL7Message)) {
+                                acknowledgmentMessage = generateAcknowledgementMessage(parsedHL7Message, "AR");
+                            } else {
+                                acknowledgmentMessage = generateAcknowledgementMessage(parsedHL7Message);
+                            }
                         } else {
-                            acknowledgmentMessage = generateAcknowledgementMessage(parsedHL7Message);
-
+                            acknowledgmentMessage = acknowledgementString;
                         }
+
                         BufferedOutputStream outstream = new BufferedOutputStream(clientSocket.getOutputStream());
 
                         if (sendOutOfBandData(messageCounter)) {
                             byte[] outOfBandDataBytes = "Out Of Band Hl7MessageGenerator".getBytes();
                             outstream.write(outOfBandDataBytes, 0, outOfBandDataBytes.length);
-
                         }
+
                         if (excludeStartOfBlock(messageCounter)) {
-                            log.warn("NOT sending bMLLP_ENVELOPE_START_OF_BLOCK");
+                            log.warn("NOT sending START_OF_BLOCK");
                         } else {
                             outstream.write(START_OF_BLOCK);
+                            if (delayBeforeStartOfBlock > 0) {
+                                uncheckedSleep(delayBeforeStartOfBlock);
+                                uncheckedFlush(outstream);
+                            }
                         }
 
                         if (excludeAcknowledgement(messageCounter)) {
                             log.info("NOT sending Acknowledgement body");
                         } else {
+                            if (delayBeforeAcknowledgement > 0) {
+                                uncheckedSleep(delayBeforeAcknowledgement);
+                            }
                             log.debug("Buffering Acknowledgement\n\t{}", acknowledgmentMessage.replace('\r', '\n'));
                             byte[] ackBytes = acknowledgmentMessage.getBytes();
-                            outstream.write(ackBytes, 0, ackBytes.length);
+                            if (delayDuringAcknowledgement > 0) {
+                                int firstHalf = ackBytes.length / 2;
+                                outstream.write(ackBytes, 0, firstHalf);
+                                uncheckedFlush(outstream);
+                                uncheckedSleep(delayDuringAcknowledgement);
+                                outstream.write(ackBytes, firstHalf, ackBytes.length - firstHalf);
+                                uncheckedFlush(outstream);
+                            } else {
+                                outstream.write(ackBytes, 0, ackBytes.length);
+                            }
+                            if (delayAfterAcknowledgement > 0) {
+                                uncheckedFlush(outstream);
+                                uncheckedSleep(delayAfterAcknowledgement);
+                            }
                         }
 
                         if (excludeEndOfBlock(messageCounter)) {
                             log.warn("NOT sending bMLLP_ENVELOPE_END_OF_BLOCK");
                         } else {
                             outstream.write(END_OF_BLOCK);
+                            if (delayAfterEndOfBlock > 0) {
+                                uncheckedFlush(outstream);
+                                uncheckedSleep(delayAfterEndOfBlock);
+                            }
                         }
 
                         if (excludeEndOfData(messageCounter)) {
@@ -794,9 +1042,9 @@ public class MllpServerResource extends ExternalResource {
                         }
 
                         log.debug("Writing Acknowledgement\n\t{}", acknowledgmentMessage.replace('\r', '\n'));
-                        outstream.flush();
+                        uncheckedFlush(outstream);
 
-                        if (disconnectAfterAcknowledgement(messageCounter)) {
+                        if (closeSocketAfterAcknowledgement(messageCounter)) {
                             log.info("Closing Client");
                             clientSocket.shutdownInput();
                             clientSocket.shutdownOutput();
@@ -806,16 +1054,18 @@ public class MllpServerResource extends ExternalResource {
                     }
                 }
             } catch (IOException e) {
-                String errorMessage = "Error whiling reading and writing to clientSocket";
+                String errorMessage = "Error while reading and writing from clientSocket";
                 log.error(errorMessage, e);
                 throw new MllpJUnitResourceException(errorMessage, e);
             } finally {
-                try {
-                    clientSocket.close();
-                } catch (IOException e) {
-                    String errorMessage = "Error whiling attempting to close to client Socket";
-                    log.error(errorMessage, e);
-                    throw new MllpJUnitResourceException(errorMessage, e);
+                if (clientSocket != null) {
+                    try {
+                        clientSocket.close();
+                    } catch (IOException e) {
+                        String errorMessage = "Error while attempting to close to client Socket";
+                        log.error(errorMessage, e);
+                        throw new MllpJUnitResourceException(errorMessage, e);
+                    }
                 }
             }
 
@@ -829,10 +1079,8 @@ public class MllpServerResource extends ExternalResource {
          * @return the MLLP payload
          * @throws IOException when the underlying Java Socket calls raise these exceptions
          */
-        // TODO:  Enhance this to detect non-HL7 data (i.e. look for MSH after START_OF_BLOCK)
         public String getMessage(InputStream anInputStream) throws IOException {
             try {
-                // TODO:  Enhance this to read a bunch of characters and log, rather than log them one at a time
                 boolean waitingForStartOfBlock = true;
                 while (waitingForStartOfBlock) {
                     int potentialStartCharacter = anInputStream.read();
@@ -847,14 +1095,16 @@ public class MllpServerResource extends ExternalResource {
                     }
                 }
             } catch (SocketException socketEx) {
-                if (clientSocket.isClosed()) {
-                    log.info("Client socket closed while waiting for MLLP_ENVELOPE_START_OF_BLOCK");
-                } else if (clientSocket.isConnected()) {
-                    log.info("SocketException encountered while waiting for MLLP_ENVELOPE_START_OF_BLOCK");
-                    resetConnection(clientSocket);
-                } else {
-                    log.error("Unable to read from socket stream when expected bMLLP_ENVELOPE_START_OF_BLOCK - resetting connection ", socketEx);
-                    resetConnection(clientSocket);
+                if (clientSocket != null) {
+                    if (clientSocket.isClosed()) {
+                        log.info("Client socket closed while waiting for MLLP_ENVELOPE_START_OF_BLOCK");
+                    } else if (clientSocket.isConnected()) {
+                        log.info("SocketException encountered while waiting for MLLP_ENVELOPE_START_OF_BLOCK");
+                        resetConnection();
+                    } else {
+                        log.error("Unable to read from socket stream when expected bMLLP_ENVELOPE_START_OF_BLOCK - resetting connection ", socketEx);
+                        resetConnection();
+                    }
                 }
                 return null;
             }
@@ -907,75 +1157,7 @@ public class MllpServerResource extends ExternalResource {
          * @return a HL7 Application Acknowledgement
          */
         private String generateAcknowledgementMessage(String hl7Message, String acknowledgementCode) {
-            final String defaulNackMessage =
-                    "MSH|^~\\&|||||||NACK||P|2.2" + SEGMENT_DELIMITER
-                            + "MSA|AR|" + SEGMENT_DELIMITER
-                            + MESSAGE_TERMINATOR;
-
-            if (hl7Message == null) {
-                log.error("Invalid HL7 message for parsing operation. Please check your inputs");
-                return defaulNackMessage;
-            }
-
-            if (!("AA".equals(acknowledgementCode) || "AE".equals(acknowledgementCode) || "AR".equals(acknowledgementCode))) {
-                throw new IllegalArgumentException("Acknowledgemnt Code must be AA, AE or AR: " + acknowledgementCode);
-            }
-
-            String messageControlId;
-
-            int endOfMshSegment = hl7Message.indexOf(SEGMENT_DELIMITER);
-            if (-1 != endOfMshSegment) {
-                String mshSegment = hl7Message.substring(0, endOfMshSegment);
-                char fieldSeparator = mshSegment.charAt(3);
-                String fieldSeparatorPattern = Pattern.quote("" + fieldSeparator);
-                String[] mshFields = mshSegment.split(fieldSeparatorPattern);
-                if (mshFields.length == 0) {
-                    log.error("Failed to split MSH Segment into fields");
-                } else {
-                    StringBuilder ackBuilder = new StringBuilder(mshSegment.length() + 25);
-                    // Build the MSH Segment
-                    ackBuilder
-                            .append(mshFields[0]).append(fieldSeparator)
-                            .append(mshFields[1]).append(fieldSeparator)
-                            .append(mshFields[4]).append(fieldSeparator)
-                            .append(mshFields[5]).append(fieldSeparator)
-                            .append(mshFields[2]).append(fieldSeparator)
-                            .append(mshFields[3]).append(fieldSeparator)
-                            .append(mshFields[6]).append(fieldSeparator)
-                            .append(mshFields[7]).append(fieldSeparator)
-                            .append("ACK")
-                            .append(mshFields[8].substring(3));
-                    for (int i = 9; i < mshFields.length; ++i) {
-                        ackBuilder.append(fieldSeparator).append(mshFields[i]);
-                    }
-                    // Empty fields at the end are not preserved by String.split, so preserve them
-                    int emptyFieldIndex = mshSegment.length() - 1;
-                    if (fieldSeparator == mshSegment.charAt(mshSegment.length() - 1)) {
-                        ackBuilder.append(fieldSeparator);
-                        while (emptyFieldIndex >= 1 && mshSegment.charAt(emptyFieldIndex) == mshSegment.charAt(emptyFieldIndex - 1)) {
-                            ackBuilder.append(fieldSeparator);
-                            --emptyFieldIndex;
-                        }
-                    }
-                    ackBuilder.append(SEGMENT_DELIMITER);
-
-                    // Build the MSA Segment
-                    ackBuilder
-                            .append("MSA").append(fieldSeparator)
-                            .append(acknowledgementCode).append(fieldSeparator)
-                            .append(mshFields[9]).append(fieldSeparator)
-                            .append(SEGMENT_DELIMITER);
-
-                    // Terminate the message
-                    ackBuilder.append(MESSAGE_TERMINATOR);
-
-                    return ackBuilder.toString();
-                }
-            } else {
-                log.error("Failed to find the end of the  MSH Segment");
-            }
-
-            return null;
+            return generateAcknowledgement(hl7Message, acknowledgementCode);
         }
 
         @Override
@@ -989,6 +1171,23 @@ public class MllpServerResource extends ExternalResource {
             }
             super.interrupt();
         }
+
+        private void uncheckedSleep(long milliseconds) {
+            try {
+                Thread.sleep(milliseconds);
+            } catch (InterruptedException e) {
+                log.warn("Sleep interrupted", e);
+            }
+
+        }
+
+        private void uncheckedFlush(OutputStream outputStream) {
+            try {
+                outputStream.flush();
+            } catch (IOException e) {
+                log.warn("Ignoring exception caught while flushing output stream", e);
+            }
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/test/util/PayloadBuilder.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/test/util/PayloadBuilder.java b/components/camel-mllp/src/test/java/org/apache/camel/test/util/PayloadBuilder.java
new file mode 100644
index 0000000..3959b43
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/test/util/PayloadBuilder.java
@@ -0,0 +1,211 @@
+/**
+ * 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.test.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class PayloadBuilder {
+    ByteArrayOutputStream builderStream = new ByteArrayOutputStream();
+
+    public PayloadBuilder() {
+    }
+
+    public PayloadBuilder(byte b) throws IOException {
+        this.append(b);
+    }
+
+    public PayloadBuilder(byte[] bytes) throws IOException {
+        this.append(bytes);
+    }
+
+    public PayloadBuilder(char... chars) throws IOException {
+        this.append(chars);
+    }
+
+    public PayloadBuilder(String... strings) throws IOException {
+        this.append(strings);
+    }
+
+    public PayloadBuilder append(byte b) throws IOException {
+        builderStream.write(b);
+
+        return this;
+    }
+
+    public PayloadBuilder append(byte[] bytes) throws IOException {
+        builderStream.write(bytes);
+
+        return this;
+    }
+
+    public PayloadBuilder append(char... chars) throws IOException {
+        if (chars != null) {
+            for (char c : chars) {
+                builderStream.write(c);
+            }
+        }
+
+        return this;
+    }
+
+    public PayloadBuilder append(String... strings) throws IOException {
+        if (strings != null) {
+            for (String s : strings) {
+                builderStream.write(s.getBytes());
+            }
+        }
+
+        return this;
+    }
+
+    public PayloadBuilder append(byte[] payload, int startPosition, int length) throws IOException {
+        builderStream.write(payload, startPosition, length);
+
+        return this;
+    }
+
+    public byte[] build() {
+        byte[] answer = builderStream.toByteArray();
+
+        builderStream.reset();
+
+        return answer;
+    }
+
+    public static byte[] build(byte b) {
+        try {
+            return new PayloadBuilder(b).build();
+        } catch (IOException e) {
+            throw new RuntimeException("PayloadBuilder.build(byte) failure", e);
+        }
+    }
+
+    public static byte[] build(byte b, byte... bytes) {
+        try {
+            return new PayloadBuilder(b).append(bytes).build();
+        } catch (IOException e) {
+            throw new RuntimeException("PayloadBuilder.build(byte) failure", e);
+        }
+    }
+
+    public static byte[] build(byte[] bytes) {
+        try {
+            return new PayloadBuilder(bytes).build();
+        } catch (IOException e) {
+            throw new RuntimeException("PayloadBuilder.build(byte[]) failure", e);
+        }
+    }
+
+    public static byte[] build(char c) {
+        try {
+            return new PayloadBuilder(c).build();
+        } catch (IOException e) {
+            throw new RuntimeException("PayloadBuilder.build(char...) failure", e);
+        }
+    }
+
+    public static byte[] build(char c, char... chars) {
+        try {
+            return new PayloadBuilder(c).append(chars).build();
+        } catch (IOException e) {
+            throw new RuntimeException("PayloadBuilder.build(char...) failure", e);
+        }
+    }
+
+    public static byte[] build(char[] chars) {
+        try {
+            return new PayloadBuilder(chars).build();
+        } catch (IOException e) {
+            throw new RuntimeException("PayloadBuilder.build(char...) failure", e);
+        }
+    }
+
+    public static byte[] build(String s) {
+        try {
+            return new PayloadBuilder(s).build();
+        } catch (IOException e) {
+            throw new RuntimeException("PayloadBuilder.build(String) failure", e);
+        }
+    }
+
+    public static byte[] build(String[] strings) {
+        try {
+            return new PayloadBuilder(strings).build();
+        } catch (IOException e) {
+            throw new RuntimeException("PayloadBuilder.build(String[]) failure", e);
+        }
+    }
+
+    public static byte[] build(char start, String s) {
+        try {
+            return new PayloadBuilder(start)
+                    .append(s)
+                    .build();
+        } catch (IOException e) {
+            throw new RuntimeException("PayloadBuilder.build(String) failure", e);
+        }
+    }
+
+    public static byte[] build(char start, String s, char... end) {
+        try {
+            return new PayloadBuilder(start)
+                    .append(s)
+                    .append(end)
+                    .build();
+        } catch (IOException e) {
+            throw new RuntimeException("PayloadBuilder.build(char, String, char...) failure", e);
+        }
+    }
+
+    public static byte[] build(char start, byte[] bytes, char... end) {
+        try {
+            return new PayloadBuilder(start)
+                    .append(bytes)
+                    .append(end).build();
+        } catch (IOException e) {
+            throw new RuntimeException("PayloadBuilder.build(char, byte[], char...) failure", e);
+        }
+    }
+
+    public static byte[] build(String s, char... end) {
+        try {
+            return new PayloadBuilder(s)
+                    .append(end).build();
+        } catch (IOException e) {
+            throw new RuntimeException("PayloadBuilder.build(String, char...) failure", e);
+        }
+    }
+
+    public static byte[] build(byte[] bytes, char... end) {
+        try {
+            return new PayloadBuilder(bytes)
+                    .append(end).build();
+        } catch (IOException e) {
+            throw new RuntimeException("PayloadBuilder.build(byte[], char...) failure", e);
+        }
+    }
+
+    public static byte[] build(byte[] bytes, String s) {
+        try {
+            return new PayloadBuilder(bytes)
+                    .append(s).build();
+        } catch (IOException e) {
+            throw new RuntimeException("PayloadBuilder.build(byte[], String) failure", e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/resources/log4j2.properties
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/resources/log4j2.properties b/components/camel-mllp/src/test/resources/log4j2.properties
index 8c321d2..e790099 100644
--- a/components/camel-mllp/src/test/resources/log4j2.properties
+++ b/components/camel-mllp/src/test/resources/log4j2.properties
@@ -19,14 +19,16 @@ appender.file.type = File
 appender.file.name = file
 appender.file.fileName = target/camel-mllp-test.log
 appender.file.layout.type = PatternLayout
-appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.file.layout.pattern = %d %X{camel.contextId} [%t] %-5p %-30.30c{1} - %m%n
+
 appender.out.type = Console
 appender.out.name = out
 appender.out.layout.type = PatternLayout
 appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
 rootLogger.level = INFO
 rootLogger.appenderRef.file.ref = file
 
-# loggers = mllp
-# logger.mllp.name = org.apache.camel.component.mllp
-# logger.mllp.level = DEBUG
+loggers = mllp
+logger.mllp.name = org.apache.camel.component.mllp
+# logger.mllp.level = TRACE


[4/8] camel git commit: CAMEL-10511: Updated MllpTcpClientProducer and MllpTcpServerConsumer to consume all available data on socket

Posted by da...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpUtil.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpUtil.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpUtil.java
deleted file mode 100644
index 20315e7..0000000
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpUtil.java
+++ /dev/null
@@ -1,390 +0,0 @@
-/**
- * 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.impl;
-
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.Socket;
-import java.net.SocketException;
-import java.net.SocketTimeoutException;
-
-import org.apache.camel.component.mllp.MllpComponent;
-import org.apache.camel.component.mllp.MllpException;
-import org.apache.camel.component.mllp.MllpFrameException;
-import org.apache.camel.component.mllp.MllpTimeoutException;
-import org.apache.camel.component.mllp.MllpWriteException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
-import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
-import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_STREAM;
-import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
-
-/**
- * Supplies methods to read and write messages in a MLLP Frame.
- * <p/>
- * Although the methods in the class are intended to handle HL7 v2 formatted messages, the methods do not
- * depend on that format - any byte[]can be written to the Socket.  Also, any byte[] can be read from the socket
- * provided it has the proper MLLP Enveloping - <START_OF_BLOCK>payload<END_OF_BLOCK><END_OF_DATA>>.
- * <p/>
- * NOTE: MLLP payloads are not logged unless the logging level is set to DEBUG or TRACE to avoid introducing PHI
- * into the log files.  Logging of PHI can be globally disabled by setting the org.apache.camel.mllp.logPHI system
- * property.  The property is evaluated using Boolean.parseBoolean.
- * <p/>
- */
-public final class MllpUtil {
-    private static final Logger LOG = LoggerFactory.getLogger(MllpUtil.class);
-
-    private MllpUtil() {
-    }
-
-    /**
-     * Open the MLLP frame by reading from the Socket until the begging of the frame is found.
-     * <p/>
-     * If any errors occur (including MLLP frame errors) while opening the frame, the socket will be closed and an
-     * Exception will be thrown.
-     *
-     * @param socket the Socket to read
-     * @throws SocketTimeoutException    thrown if a timeout occurs while looking for the beginning of the MLLP frame, but
-     *                                   nothing is yet available - this is NOT an error condition
-     * @throws MllpFrameException if the MLLP Frame is corrupted in some way
-     * @throws MllpException             for other unexpected error conditions
-     */
-    public static boolean openFrame(Socket socket, int receiveTimeout, int readTimeout) throws SocketTimeoutException, MllpFrameException, MllpException {
-        if (socket.isConnected() && !socket.isClosed()) {
-            InputStream socketInputStream = MllpUtil.getInputStream(socket);
-
-            int readByte = -1;
-            try {
-                socket.setSoTimeout(receiveTimeout);
-                readByte = socketInputStream.read();
-                switch (readByte) {
-                case START_OF_BLOCK:
-                    return true;
-                case END_OF_STREAM:
-                    resetConnection(socket);
-                    return false;
-                default:
-                    // Continue on and process the out-of-frame data
-                }
-            } catch (SocketTimeoutException normaTimeoutEx) {
-                // Just pass this on - the caller will wrap it in a MllpTimeoutException
-                throw normaTimeoutEx;
-            } catch (SocketException socketEx) {
-                if (socket.isClosed()) {
-                    LOG.debug("Socket closed while opening MLLP frame - ignoring exception", socketEx);
-                    return false;
-                } else {
-                    LOG.error("Unexpected Exception occurred opening MLLP frame - resetting the connection");
-                    MllpUtil.resetConnection(socket);
-                    throw new MllpException("Unexpected Exception occurred opening MLLP frame", socketEx);
-                }
-            } catch (IOException unexpectedException) {
-                LOG.error("Unexpected Exception occurred opening MLLP frame - resetting the connection");
-                MllpUtil.resetConnection(socket);
-                throw new MllpException("Unexpected Exception occurred opening MLLP frame", unexpectedException);
-            }
-
-            /*
-             From here on, we're in a bad frame state.  Read what's left in the socket, close the connection and
-             return the out-of-frame data.
-              */
-            ByteArrayOutputStream outOfFrameData = new ByteArrayOutputStream();
-            outOfFrameData.write(readByte);
-
-            try {
-                socket.setSoTimeout(readTimeout);
-                while (true) {
-                    readByte = socketInputStream.read();
-                    switch (readByte) {
-                    case END_OF_STREAM:
-                        if (isLogPHIEnabled(LOG)) {
-                            LOG.error("END_OF_STREAM read while looking for the beginning of the MLLP frame, and "
-                                            + "out-of-frame data had been read - resetting connection and eating out-of-frame data: {}",
-                                    outOfFrameData.toString().replace('\r', '\n'));
-                        } else {
-                            LOG.error("END_OF_STREAM read while looking for the beginning of the MLLP frame, and out-of-frame data had been read - resetting connection and eating out-of-frame data");
-                        }
-                        resetConnection(socket);
-
-                        throw new MllpFrameException("END_OF_STREAM read while looking for the beginning of the MLLP frame", outOfFrameData.toByteArray());
-                    case START_OF_BLOCK:
-                        if (isLogPHIEnabled(LOG)) {
-                            LOG.warn("The beginning of the MLLP frame was preceded by out-of-frame data - eating data: {}", outOfFrameData.toString().replace('\r', '\n'));
-                        } else {
-                            LOG.warn("The beginning of the MLLP frame was preceded by out-of-frame data - eating data");
-                        }
-
-                        throw new MllpFrameException("The beginning of the MLLP frame was preceded by out-of-frame data", outOfFrameData.toByteArray());
-                    default:
-                        // still reading out-of-frame data
-                        outOfFrameData.write(readByte);
-                        break;
-                    }
-                }
-            } catch (SocketTimeoutException timeoutEx) {
-                if (isLogPHIEnabled(LOG)) {
-                    LOG.error("Timeout looking for the beginning of the MLLP frame, and out-of-frame data had been read - resetting connection and eating out-of-frame data: {}",
-                            outOfFrameData.toString().replace('\r', '\n'));
-                } else {
-                    LOG.error("Timeout looking for the beginning of the MLLP frame, and out-of-frame data had been read - resetting connection and eating out-of-frame data");
-                }
-
-                resetConnection(socket);
-
-                throw new MllpFrameException("Timeout looking for the beginning of the MLLP frame, and out-of-frame data had been read", outOfFrameData.toByteArray());
-            } catch (IOException e) {
-                if (isLogPHIEnabled(LOG)) {
-                    LOG.error("Exception encountered looking for the beginning of the MLLP frame, and out-of-frame data had been read - resetting connection and eating out-of-frame data: {}",
-                            outOfFrameData.toString().replace('\r', '\n'));
-                } else {
-                    LOG.error("Exception encountered looking for the beginning of the MLLP frame, and out-of-frame data had been read - resetting connection and eating out-of-frame data");
-                }
-
-                resetConnection(socket);
-
-                throw new MllpFrameException("Exception encountered looking for the beginning of the MLLP frame, and out-of-frame data had been read", outOfFrameData.toByteArray());
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Close a MLLP frame by reading from the socket until the end of the frame is found.
-     * <p/>
-     * The method assumes the MLLP frame has already been opened and the first byte available
-     * will be the first byte of the framed message.
-     * <p/>
-     * The method consumes the END_OF_BLOCK and END_OF_DATA bytes from the stream before returning the payload
-     * <p/>
-     * If any errors occur (including MLLP frame errors) while opening the frame, the socket will be closed and an
-     * Exception will be thrown.
-     *
-     * @param socket the Socket to be read
-     * @return the payload of the MLLP-Enveloped message as a byte[]
-     * @throws MllpTimeoutException      thrown if a timeout occurs while closing the MLLP frame
-     * @throws MllpFrameException if the MLLP Frame is corrupted in some way
-     * @throws MllpException             for other unexpected error conditions
-     */
-    public static byte[] closeFrame(Socket socket, int receiveTimeout, int readTimeout) throws MllpTimeoutException, MllpFrameException, MllpException {
-        if (socket.isConnected() && !socket.isClosed()) {
-            InputStream socketInputStream = MllpUtil.getInputStream(socket);
-            // TODO:  Come up with an intelligent way to size this stream
-            ByteArrayOutputStream payload = new ByteArrayOutputStream(4096);
-            try {
-                socket.setSoTimeout(readTimeout);
-                while (true) {
-                    int readByte = socketInputStream.read();
-                    switch (readByte) {
-                    case END_OF_STREAM:
-                        if (isLogPHIEnabled(LOG)) {
-                            LOG.error("END_OF_STREAM read while looking for the end of the MLLP frame - resetting connection and eating data: {}", payload.toString().replace('\r', '\n'));
-                        } else {
-                            LOG.error("END_OF_STREAM read while looking for the end of the MLLP frame - resetting connection and eating data");
-                        }
-
-                        resetConnection(socket);
-
-                        throw new MllpFrameException("END_OF_STREAM read while looking for the end of the MLLP frame", payload.size() > 0 ? payload.toByteArray() : null);
-                    case START_OF_BLOCK:
-                        if (isLogPHIEnabled(LOG)) {
-                            LOG.error("A new MLLP frame was opened before the previous frame was closed - resetting connection and eating data: {}", payload.toString().replace('\r', '\n'));
-                        } else {
-                            LOG.error("A new MLLP frame was opened before the previous frame was closed - resetting connection and eating data");
-                        }
-
-                        resetConnection(socket);
-
-                        throw new MllpFrameException("A new MLLP frame was opened before the previous frame was closed", payload.size() > 0 ? payload.toByteArray() : null);
-                    case END_OF_BLOCK:
-                        if (END_OF_DATA != socketInputStream.read()) {
-                            if (isLogPHIEnabled(LOG)) {
-                                LOG.error("The MLLP frame was partially closed - END_OF_BLOCK was not followed by END_OF_DATA - resetting connection and eating data: {}",
-                                        payload.toString().replace('\r', '\n'));
-                            } else {
-                                LOG.error("The MLLP frame was partially closed - END_OF_BLOCK was not followed by END_OF_DATA - resetting connection and eating data");
-                            }
-
-                            resetConnection(socket);
-
-                            throw new MllpFrameException("The MLLP frame was partially closed - END_OF_BLOCK was not followed by END_OF_DATA",
-                                    payload.size() > 0 ? payload.toByteArray() : null);
-                        }
-                        socket.setSoTimeout(receiveTimeout);
-                        return payload.toByteArray();
-                    default:
-                        // log.trace( "Read Character: {}", (char)readByte );
-                        payload.write(readByte);
-                    }
-                }
-            } catch (SocketTimeoutException timeoutEx) {
-                if (0 < payload.size()) {
-                    if (isLogPHIEnabled(LOG)) {
-                        LOG.error("Timeout looking for the end of the MLLP frame - resetting connection and eating data: {}", payload.toString().replace('\r', '\n'));
-                    } else {
-                        LOG.error("Timeout looking for the end of the MLLP frame - resetting connection and eating data");
-                    }
-                } else {
-                    LOG.error("Timeout looking for the end of the MLLP frame - resetting connection");
-                }
-
-                resetConnection(socket);
-
-                throw new MllpFrameException("Timeout looking for the end of the MLLP frame", payload.size() > 0 ? payload.toByteArray() : null, timeoutEx);
-            } catch (IOException ioEx) {
-                if (0 < payload.size()) {
-                    if (isLogPHIEnabled(LOG)) {
-                        LOG.error("Exception encountered looking for the end of the MLLP frame - resetting connection and eating data: {}", payload.toString().replace('\r', '\n'));
-                    } else {
-                        LOG.error("Exception encountered looking for the end of the MLLP frame - resetting connection and eating data");
-                    }
-                } else {
-                    LOG.error("Exception encountered looking for the end of the MLLP frame - resetting connection");
-                }
-
-                resetConnection(socket);
-
-                throw new MllpFrameException("Exception encountered looking for the end of the MLLP frame", payload.size() > 0 ? payload.toByteArray() : null, ioEx);
-            }
-        }
-
-        try {
-            socket.setSoTimeout(receiveTimeout);
-        } catch (SocketException e) {
-            // Eat this exception
-        }
-        return null;
-    }
-
-    /**
-     * Write a MLLP-Framed payload to the Socket
-     *
-     * @param socket  the Socket to write the payload
-     * @param payload the MLLP payload
-     * @return true if write was successful; false otherwise
-     * @throws MllpWriteException if the write fails
-     * @throws MllpException      for other unexpected error conditions
-     */
-    public static void writeFramedPayload(Socket socket, byte[] payload) throws MllpException {
-        if (socket.isConnected() && !socket.isClosed()) {
-            OutputStream outputStream;
-            try {
-                outputStream = new BufferedOutputStream(socket.getOutputStream(), payload.length + 4);
-            } catch (IOException ioEx) {
-                LOG.error("Error Retrieving OutputStream from Socket - resetting connection");
-
-                resetConnection(socket);
-
-                throw new MllpException("Error Retrieving OutputStream from Socket", ioEx);
-            }
-
-            if (null != outputStream) {
-                try {
-                    outputStream.write(START_OF_BLOCK);
-                    outputStream.write(payload, 0, payload.length);
-                    outputStream.write(END_OF_BLOCK);
-                    outputStream.write(END_OF_DATA);
-                    outputStream.flush();
-                } catch (IOException ioEx) {
-                    LOG.error("Error writing MLLP payload - resetting connection");
-
-                    resetConnection(socket);
-
-                    throw new MllpWriteException("Error writing MLLP payload", payload, ioEx);
-                }
-            }
-        }
-    }
-
-    public static void closeConnection(Socket socket) {
-        if (null != socket) {
-            if (!socket.isClosed()) {
-                try {
-                    socket.shutdownInput();
-                } catch (Exception ex) {
-                    LOG.warn("Exception encountered shutting down the input stream on the client socket", ex);
-                }
-
-                try {
-                    socket.shutdownOutput();
-                } catch (Exception ex) {
-                    LOG.warn("Exception encountered shutting down the output stream on the client socket", ex);
-                }
-
-                try {
-                    socket.close();
-                } catch (Exception ex) {
-                    LOG.warn("Exception encountered closing the client socket", ex);
-                }
-            }
-        }
-    }
-
-    public static void resetConnection(Socket socket) {
-        if (null != socket  &&  !socket.isClosed()) {
-            try {
-                socket.setSoLinger(true, 0);
-            } catch (Exception ex) {
-                LOG.warn("Exception encountered setting SO_LINGER to 0 on the socket to force a reset", ex);
-            }
-
-            try {
-                socket.close();
-            } catch (Exception ex) {
-                LOG.warn("Exception encountered closing the client socket", ex);
-            }
-
-        }
-
-    }
-
-    /**
-     * Retrieve the InputStream from the Socket
-     * <p/>
-     * Private utility method that catches IOExceptions when retrieving the InputStream
-     *
-     * @param socket Socket to get the InputStream from
-     * @return the InputStream for the Socket
-     * @throws MllpException when unexpected conditions occur
-     */
-    private static InputStream getInputStream(Socket socket) throws MllpException {
-        InputStream socketInputStream = null;
-        try {
-            socketInputStream = socket.getInputStream();
-        } catch (IOException ioEx) {
-            throw new MllpException("Error Retrieving InputStream from Socket", ioEx);
-        }
-
-        return socketInputStream;
-    }
-
-    private static boolean isLogPHIEnabled(Logger targetLogger) {
-        if (targetLogger.isDebugEnabled()) {
-            if (Boolean.parseBoolean(System.getProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true"))) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java b/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java
index c7f4473..5c0013c 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java
@@ -143,6 +143,7 @@ public class Hl7AcknowledgementGenerator implements Processor {
         acknowledgement.write(SEGMENT_DELIMITER);
 
         // Terminate the message
+        acknowledgement.write(SEGMENT_DELIMITER);
         acknowledgement.write(MESSAGE_TERMINATOR);
 
         return acknowledgement.toByteArray();

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpAcknowledgementExceptionTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpAcknowledgementExceptionTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpAcknowledgementExceptionTest.java
deleted file mode 100644
index 439a3c9..0000000
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpAcknowledgementExceptionTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/**
- * 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 org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static org.junit.Assert.assertEquals;
-
-public class MllpAcknowledgementExceptionTest {
-    static final String HL7_MESSAGE = "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';
-
-    static final String HL7_ACKNOWLEDGEMENT = "MSH|^~\\&|^org^sys||APP_A|FAC_A|||ACK^A04^ADT_A04|||2.6" + '\r' + "MSA|AA|" + '\r' + '\n';
-
-    static final String EXCEPTION_MESSAGE_WITH_LOG_PHI_DISABLED = MllpAcknowledgementDeliveryException.EXCEPTION_MESSAGE;
-    static final String EXCEPTION_MESSAGE_WITH_LOG_PHI_ENABLED =
-            String.format("%s:\n\tHL7 Message: %s\n\tHL7 Acknowledgement: %s",
-                    MllpAcknowledgementDeliveryException.EXCEPTION_MESSAGE,
-                    new String(HL7_MESSAGE).replaceAll("\r", "<CR>").replaceAll("\n", "<LF>"),
-                    new String(HL7_ACKNOWLEDGEMENT).replaceAll("\r", "<CR>").replaceAll("\n", "<LF>")
-            );
-
-    Exception exception;
-
-    Logger log = LoggerFactory.getLogger(this.getClass());
-
-    @Before
-    public void setUp() throws Exception {
-        exception = new MllpAcknowledgementDeliveryException(HL7_MESSAGE.getBytes(), HL7_ACKNOWLEDGEMENT.getBytes());
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        System.clearProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY);
-    }
-
-
-    @Test
-    public void testLogPhiDefault() throws Exception {
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(EXCEPTION_MESSAGE_WITH_LOG_PHI_ENABLED, exceptionMessage);
-    }
-
-    @Test
-    public void testLogPhiDisabled() throws Exception {
-        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "false");
-
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(EXCEPTION_MESSAGE_WITH_LOG_PHI_DISABLED, exceptionMessage);
-    }
-
-    @Test
-    public void testLogPhiEnabled() throws Exception {
-        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
-
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(EXCEPTION_MESSAGE_WITH_LOG_PHI_ENABLED, exceptionMessage);
-    }
-
-    @Test
-    public void testNullMessage() throws Exception {
-        final String expectedMessage =
-                String.format("%s:\n\tHL7 Message: null\n\tHL7 Acknowledgement: %s",
-                        MllpAcknowledgementDeliveryException.EXCEPTION_MESSAGE,
-                        new String(HL7_ACKNOWLEDGEMENT).replaceAll("\r", "<CR>").replaceAll("\n", "<LF>")
-                );
-
-        exception = new MllpAcknowledgementDeliveryException(null, HL7_ACKNOWLEDGEMENT.getBytes());
-
-        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(expectedMessage, exceptionMessage);
-    }
-
-    @Test
-    public void testNullAcknowledgement() throws Exception {
-        final String expectedMessage =
-                String.format("%s:\n\tHL7 Message: %s\n\tHL7 Acknowledgement: null",
-                        MllpAcknowledgementDeliveryException.EXCEPTION_MESSAGE,
-                        new String(HL7_MESSAGE).replaceAll("\r", "<CR>").replaceAll("\n", "<LF>")
-                );
-
-        exception = new MllpAcknowledgementDeliveryException(HL7_MESSAGE.getBytes(), null);
-
-        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(expectedMessage, exceptionMessage);
-    }
-
-    @Test
-    public void testToString() throws Exception {
-        final String expectedString =
-                "org.apache.camel.component.mllp.MllpAcknowledgementDeliveryException: "
-                        + "{hl7Message="
-                        +      "MSH|^~\\&|APP_A|FAC_A|^org^sys||||ADT^A04^ADT_A04|||2.6<CR>"
-                        +      "PID|1||1100832^^^^PI||TEST^FIG||98765432|U||R|435 MAIN STREET^^LONGMONT^CO^80503||123-456-7890|||S<CR><CR><LF>"
-                        + ", hl7Acknowledgement="
-                        +      "MSH|^~\\&|^org^sys||APP_A|FAC_A|||ACK^A04^ADT_A04|||2.6<CR>MSA|AA|<CR><LF>"
-                        + "}";
-
-        assertEquals(expectedString, exception.toString());
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpExceptionTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpExceptionTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpExceptionTest.java
new file mode 100644
index 0000000..0c6940b
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpExceptionTest.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 org.junit.After;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class MllpExceptionTest {
+    static final String EXCEPTION_MESSAGE = "Test Frame Exception";
+
+    static final String HL7_MESSAGE =
+            "MSH|^~\\&|APP_A|FAC_A|^org^sys||20161206193919||ADT^A04|00001||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';
+
+    static final String HL7_ACK =
+            "MSH|^~\\&|APP_A|FAC_A|^org^sys||20161206193919||ACK^A04|00002||2.6" + '\r'
+                    + "MSA|AA|00001" + '\r'
+                    + '\r' + '\n';
+
+    @After
+    public void tearDown() throws Exception {
+        System.clearProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY);
+    }
+
+    @Test
+    public void testLogPhiDefault() throws Exception {
+        assertEquals(expectedMessage(HL7_MESSAGE, HL7_ACK), createException(HL7_MESSAGE, HL7_ACK).getMessage());
+    }
+
+    @Test
+    public void testLogPhiDisabled() throws Exception {
+        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "false");
+
+        assertEquals(EXCEPTION_MESSAGE, createException(HL7_MESSAGE, HL7_ACK).getMessage());
+    }
+
+    @Test
+    public void testLogPhiEnabled() throws Exception {
+        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
+
+        assertEquals(expectedMessage(HL7_MESSAGE, HL7_ACK), createException(HL7_MESSAGE, HL7_ACK).getMessage());
+    }
+
+    @Test
+    public void testNullHl7Message() throws Exception {
+        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
+
+        assertEquals(expectedMessage(null, HL7_ACK), createException(null, HL7_ACK).getMessage());
+    }
+
+    @Test
+    public void testNullHl7Acknowledgement() throws Exception {
+        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
+
+        assertEquals(expectedMessage(HL7_MESSAGE, null), createException(HL7_MESSAGE, null).getMessage());
+    }
+
+    @Test
+    public void testNullHl7Payloads() throws Exception {
+        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
+
+        assertEquals(expectedMessage(null, null), createException(null, null).getMessage());
+    }
+
+
+    // Utility methods
+    private Exception createException(String hl7Message, String hl7Acknowledgment) {
+        byte[] hl7MessageBytes = null;
+        byte[] hl7AcknowledgementBytes = null;
+
+        if (hl7Message != null) {
+            hl7MessageBytes = hl7Message.getBytes();
+        }
+
+        if (hl7Acknowledgment != null) {
+            hl7AcknowledgementBytes = hl7Acknowledgment.getBytes();
+        }
+        return new MllpException(EXCEPTION_MESSAGE, hl7MessageBytes, hl7AcknowledgementBytes);
+    }
+
+    private String expectedMessage(String hl7Message, String hl7Acknowledgment) {
+        final String exceptionMessageFormat = EXCEPTION_MESSAGE + " \n\t{hl7Message= %s} \n\t{hl7Acknowledgement= %s}";
+
+        String formattedHl7Message = null;
+        String formattedHl7Acknowledgement = null;
+
+        if (hl7Message != null) {
+            formattedHl7Message = hl7Message.replaceAll("\r", "<CR>").replaceAll("\n", "<LF>");
+        }
+
+        if (hl7Acknowledgment != null) {
+            formattedHl7Acknowledgement = hl7Acknowledgment.replaceAll("\r", "<CR>").replaceAll("\n", "<LF>");
+        }
+
+        return String.format(exceptionMessageFormat, formattedHl7Message, formattedHl7Acknowledgement);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpFrameExceptionTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpFrameExceptionTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpFrameExceptionTest.java
deleted file mode 100644
index ca713dc..0000000
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpFrameExceptionTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * 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 org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class MllpFrameExceptionTest {
-    static final String EXCEPTION_MESSAGE = "Test Frame Exception";
-
-    static final String HL7_MESSAGE =
-            "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';
-
-    static final String EXCEPTION_MESSAGE_WITH_LOG_PHI_DISABLED = EXCEPTION_MESSAGE;
-    static final String EXCEPTION_MESSAGE_WITH_LOG_PHI_ENABLED =
-            String.format(String.format("%s:\n\tMLLP Payload: %s",
-                    EXCEPTION_MESSAGE,
-                    new String(HL7_MESSAGE).replaceAll("\r", "<CR>").replaceAll("\n", "<LF>"))
-            );
-
-    Exception exception;
-
-    @Before
-    public void setUp() throws Exception {
-        exception = new MllpFrameException(EXCEPTION_MESSAGE, HL7_MESSAGE.getBytes());
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        System.clearProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY);
-    }
-
-    @Test
-    public void testLogPhiDefault() throws Exception {
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(EXCEPTION_MESSAGE_WITH_LOG_PHI_ENABLED, exceptionMessage);
-    }
-
-    @Test
-    public void testLogPhiDisabled() throws Exception {
-        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "false");
-
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(EXCEPTION_MESSAGE_WITH_LOG_PHI_DISABLED, exceptionMessage);
-    }
-
-    @Test
-    public void testLogPhiEnabled() throws Exception {
-        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
-
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(EXCEPTION_MESSAGE_WITH_LOG_PHI_ENABLED, exceptionMessage);
-    }
-
-    @Test
-    public void testNullPayload() throws Exception {
-        final String expectedMessage = String.format("%s:\n\tMLLP Payload: null", EXCEPTION_MESSAGE);
-
-        exception = new MllpFrameException(EXCEPTION_MESSAGE, null);
-
-        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(expectedMessage, exceptionMessage);
-    }
-    @Test
-    public void testToString() throws Exception {
-        final String expectedString =
-                "org.apache.camel.component.mllp.MllpFrameException: "
-                        + "{mllpPayload="
-                        +      "MSH|^~\\&|APP_A|FAC_A|^org^sys||||ADT^A04^ADT_A04|||2.6<CR>"
-                        +      "PID|1||1100832^^^^PI||TEST^FIG||98765432|U||R|435 MAIN STREET^^LONGMONT^CO^80503||123-456-7890|||S<CR><CR><LF>"
-                        + "}";
-
-        assertEquals(expectedString, exception.toString());
-    }
-
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpProducerConsumerLoopbackTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpProducerConsumerLoopbackTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpProducerConsumerLoopbackTest.java
index 116e67c..e090a50 100644
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpProducerConsumerLoopbackTest.java
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpProducerConsumerLoopbackTest.java
@@ -64,19 +64,16 @@ public class MllpProducerConsumerLoopbackTest extends CamelTestSupport {
     @Override
     protected RouteBuilder[] createRouteBuilders() throws Exception {
         RouteBuilder[] builders = new RouteBuilder[2];
-        final int groupInterval = 1000;
-        final boolean groupActiveOnly = false;
 
         builders[0] = new RouteBuilder() {
             String routeId = "mllp-receiver";
 
             public void configure() {
-                fromF("mllp://%s:%d?autoAck=true", mllpHost, mllpPort)
+                fromF("mllp://%s:%d?autoAck=true&readTimeout=1000", mllpHost, mllpPort)
                         .convertBodyTo(String.class)
                         .to(acknowledged)
                         .process(new PassthroughProcessor("after send to result"))
-                        .log(LoggingLevel.DEBUG, routeId, "Receiving: ${body}")
-                        .toF("log://%s?level=INFO&groupInterval=%d&groupActiveOnly=%b", routeId, groupInterval, groupActiveOnly);
+                        .log(LoggingLevel.INFO, routeId, "Receiving: ${body}");
             }
         };
 
@@ -85,10 +82,9 @@ public class MllpProducerConsumerLoopbackTest extends CamelTestSupport {
 
             public void configure() {
                 from(source.getDefaultEndpoint()).routeId(routeId)
-                        .log(LoggingLevel.DEBUG, routeId, "Sending: ${body}")
-                        .toF("mllp://%s:%d", mllpHost, mllpPort)
-                        .setBody(header(MllpConstants.MLLP_ACKNOWLEDGEMENT))
-                        .toF("log://%s?level=INFO&groupInterval=%d&groupActiveOnly=%b", routeId, groupInterval, groupActiveOnly);
+                        .log(LoggingLevel.INFO, routeId, "Sending: ${body}")
+                        .toF("mllp://%s:%d?readTimeout=5000", mllpHost, mllpPort)
+                        .setBody(header(MllpConstants.MLLP_ACKNOWLEDGEMENT));
             }
         };
 
@@ -107,7 +103,7 @@ public class MllpProducerConsumerLoopbackTest extends CamelTestSupport {
     }
 
     @Test
-    public void testLoopbackMultipleMessages() throws Exception {
+    public void testLoopbackWithMultipleMessages() throws Exception {
         int messageCount = 1000;
         acknowledged.expectedMessageCount(messageCount);
 

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientConsumerBlueprintTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientConsumerBlueprintTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientConsumerBlueprintTest.java
deleted file mode 100644
index e4ca285..0000000
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientConsumerBlueprintTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * 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 org.apache.camel.EndpointInject;
-import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.test.blueprint.CamelBlueprintTestSupport;
-import org.junit.Ignore;
-
-@Ignore(value = "Not Yet Implemented")
-// TODO: Implement this
-public class MllpTcpClientConsumerBlueprintTest extends CamelBlueprintTestSupport {
-    @EndpointInject(uri = "mock://target")
-    MockEndpoint target;
-
-    @Override
-    protected String getBlueprintDescriptor() {
-        return "OSGI-INF/blueprint/mllp-tcp-client-consumer.xml";
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerAcknowledgementTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerAcknowledgementTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerAcknowledgementTest.java
index 125df76..f6df61c 100644
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerAcknowledgementTest.java
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerAcknowledgementTest.java
@@ -28,12 +28,46 @@ import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.test.AvailablePortFinder;
 import org.apache.camel.test.junit.rule.mllp.MllpServerResource;
 import org.apache.camel.test.junit4.CamelTestSupport;
+
 import org.junit.Rule;
 import org.junit.Test;
 
-import static org.apache.camel.test.mllp.Hl7MessageGenerator.generateMessage;
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 
 public class MllpTcpClientProducerAcknowledgementTest extends CamelTestSupport {
+    static final String TEST_MESSAGE =
+        "MSH|^~\\&|ADT|EPIC|JCAPS|CC|20161206193919|RISTECH|ADT^A08|00001|D|2.3^^|||||||" + '\r'
+            + "EVN|A08|20150107161440||REG_UPDATE_SEND_VISIT_MESSAGES_ON_PATIENT_CHANGES|RISTECH^RADIOLOGY^TECHNOLOGIST^^^^^^UCLA^^^^^RRMC||" + '\r'
+            + "PID|1|2100355^^^MRN^MRN|2100355^^^MRN^MRN||MDCLS9^MC9||19700109|F||U|111 HOVER STREET^^LOS ANGELES^CA^90032^USA^P^^LOS ANGELE|LOS ANGELE|"
+                + "(310)725-6952^P^PH^^^310^7256952||ENGLISH|U||60000013647|565-33-2222|||U||||||||N||" + '\r'
+            + "PD1|||UCLA HEALTH SYSTEM^^10|10002116^ADAMS^JOHN^D^^^^^EPIC^^^^PROVID||||||||||||||" + '\r'
+            + "NK1|1|DOE^MC9^^|OTH|^^^^^USA|(310)888-9999^^^^^310^8889999|(310)999-2222^^^^^310^9992222|Emergency Contact 1|||||||||||||||||||||||||||" + '\r'
+            + "PV1|1|OUTPATIENT|RR CT^^^1000^^^^^^^DEPID|EL|||017511^TOBIAS^JONATHAN^^^^^^EPIC^^^^PROVID|017511^TOBIAS^JONATHAN^^^^^^EPIC^^^^PROVID||||||"
+                + "CLR|||||60000013647|SELF|||||||||||||||||||||HOV_CONF|^^^1000^^^^^^^||20150107161438||||||||||" + '\r'
+            + "PV2||||||||20150107161438||||CT BRAIN W WO CONTRAST||||||||||N|||||||||||||||||||||||||||" + '\r'
+            + "ZPV||||||||||||20150107161438|||||||||" + '\r'
+            + "AL1|1||33361^NO KNOWN ALLERGIES^^NOTCOMPUTRITION^NO KNOWN ALLERGIES^EXTELG||||||" + '\r'
+            + "DG1|1|DX|784.0^Headache^DX|Headache||VISIT" + '\r'
+            + "GT1|1|1000235129|MDCLS9^MC9^^||111 HOVER STREET^^LOS ANGELES^CA^90032^USA^^^LOS ANGELE|(310)725-6952^^^^^310^7256952||19700109|F|P/F|SLF|"
+                + "565-33-2222|||||^^^^^USA|||UNKNOWN|||||||||||||||||||||||||||||" + '\r'
+            + "UB2||||||||" + '\r'
+            + '\n';
+
+    static final String EXPECTED_AA =
+        "MSH|^~\\&|JCAPS|CC|ADT|EPIC|20161206193919|RISTECH|ACK^A08|00001|D|2.3^^|||||||" + '\r'
+            + "MSA|AA|00001|" + '\r'
+            + '\n';
+
+    static final String EXPECTED_AR =
+        "MSH|^~\\&|JCAPS|CC|ADT|EPIC|20161206193919|RISTECH|ACK^A08|00001|D|2.3^^|||||||" + '\r'
+            + "MSA|AR|00001|" + '\r'
+            + '\n';
+
+    static final String EXPECTED_AE =
+        "MSH|^~\\&|JCAPS|CC|ADT|EPIC|20161206193919|RISTECH|ACK^A08|00001|D|2.3^^|||||||" + '\r'
+            + "MSA|AE|00001|" + '\r'
+            + '\n';
 
     @Rule
     public MllpServerResource mllpServer = new MllpServerResource("localhost", AvailablePortFinder.getNextAvailable());
@@ -41,15 +75,18 @@ public class MllpTcpClientProducerAcknowledgementTest extends CamelTestSupport {
     @EndpointInject(uri = "direct://source")
     ProducerTemplate source;
 
-    @EndpointInject(uri = "mock://complete")
-    MockEndpoint complete;
+    @EndpointInject(uri = "mock://failed")
+    MockEndpoint failed;
 
     @EndpointInject(uri = "mock://aa-ack")
-    MockEndpoint accept;
+    MockEndpoint aa;
     @EndpointInject(uri = "mock://ae-nack")
-    MockEndpoint error;
+    MockEndpoint ae;
     @EndpointInject(uri = "mock://ar-nack")
-    MockEndpoint reject;
+    MockEndpoint ar;
+
+    @EndpointInject(uri = "mock://invalid-ack")
+    MockEndpoint invalid;
 
     @Override
     protected CamelContext createCamelContext() throws Exception {
@@ -61,7 +98,6 @@ public class MllpTcpClientProducerAcknowledgementTest extends CamelTestSupport {
         return context;
     }
 
-
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
@@ -70,66 +106,181 @@ public class MllpTcpClientProducerAcknowledgementTest extends CamelTestSupport {
             public void configure() {
                 onException(MllpApplicationRejectAcknowledgementException.class)
                         .handled(true)
-                        .to(reject)
+                        .to(ar)
                         .log(LoggingLevel.ERROR, routeId, "AR Acknowledgement");
 
                 onException(MllpApplicationErrorAcknowledgementException.class)
                         .handled(true)
-                        .to(error)
+                        .to(ae)
                         .log(LoggingLevel.ERROR, routeId, "AE Acknowledgement");
 
+                onException(MllpInvalidAcknowledgementException.class)
+                        .handled(true)
+                        .to(invalid)
+                        .log(LoggingLevel.ERROR, routeId, "Invalid Acknowledgement");
+
                 onCompletion()
-                        .onCompleteOnly()
-                        .to(complete)
-                        .log(LoggingLevel.DEBUG, routeId, "AA Acknowledgement");
+                        .onFailureOnly()
+                        .to(failed)
+                        .log(LoggingLevel.DEBUG, routeId, "Exchange failed");
 
                 from(source.getDefaultEndpoint()).routeId(routeId)
                         .log(LoggingLevel.INFO, routeId, "Sending Message")
                         .toF("mllp://%s:%d", mllpServer.getListenHost(), mllpServer.getListenPort())
                         .log(LoggingLevel.INFO, routeId, "Received Acknowledgement")
-                        .to(accept);
+                        .to(aa);
             }
         };
     }
 
     @Test
     public void testApplicationAcceptAcknowledgement() throws Exception {
-        complete.setExpectedMessageCount(1);
-        accept.setExpectedMessageCount(1);
-        reject.setExpectedMessageCount(0);
-        error.setExpectedMessageCount(0);
+        aa.expectedBodiesReceived(TEST_MESSAGE);
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE, "AA");
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT, EXPECTED_AA.getBytes());
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, EXPECTED_AA);
+
+        failed.expectedMessageCount(0);
+        failed.setAssertPeriod(1000);
+
+        ae.expectedMessageCount(0);
+        ar.expectedMessageCount(0);
+        invalid.expectedMessageCount(0);
 
-        source.sendBody(generateMessage());
+        source.sendBody(TEST_MESSAGE);
 
         assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
     }
 
     @Test
     public void testApplicationRejectAcknowledgement() throws Exception {
-        complete.setExpectedMessageCount(1);
-        accept.setExpectedMessageCount(0);
-        reject.setExpectedMessageCount(1);
-        error.setExpectedMessageCount(0);
+        ar.expectedBodiesReceived(TEST_MESSAGE);
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE, "AR");
+        ar.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT, EXPECTED_AR.getBytes());
+        ar.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, EXPECTED_AR);
+
+        failed.expectedMessageCount(0);
+        failed.setAssertPeriod(1000);
+
+        aa.expectedMessageCount(0);
+        ae.expectedMessageCount(0);
+        invalid.expectedMessageCount(0);
 
         mllpServer.setSendApplicationRejectAcknowledgementModulus(1);
 
-        source.sendBody(generateMessage());
+        source.sendBody(TEST_MESSAGE);
 
         assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
     }
 
     @Test
     public void testApplicationErrorAcknowledgement() throws Exception {
-        complete.setExpectedMessageCount(1);
-        accept.setExpectedMessageCount(0);
-        reject.setExpectedMessageCount(0);
-        error.setExpectedMessageCount(1);
+        ae.expectedBodiesReceived(TEST_MESSAGE);
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE, "AE");
+        ae.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT, EXPECTED_AE.getBytes());
+        ae.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, EXPECTED_AE);
+
+        failed.expectedMessageCount(0);
+        failed.setAssertPeriod(1000);
+
+        aa.expectedMessageCount(0);
+        ar.expectedMessageCount(0);
+        invalid.expectedMessageCount(0);
 
         mllpServer.setSendApplicationErrorAcknowledgementModulus(1);
 
-        source.sendBody(generateMessage());
+        source.sendBody(TEST_MESSAGE);
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testEmptyAcknowledgement() throws Exception {
+        aa.expectedBodiesReceived(TEST_MESSAGE);
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE, "");
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT, "".getBytes());
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, "");
+
+        failed.expectedMessageCount(0);
+        failed.setAssertPeriod(1000);
+
+        ar.expectedMessageCount(0);
+        ae.expectedMessageCount(0);
+        invalid.expectedMessageCount(0);
+
+        mllpServer.setExcludeAcknowledgementModulus(1);
+
+        source.sendBody(TEST_MESSAGE);
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testInvalidAcknowledgement() throws Exception {
+        final String badAcknowledgement = "A VERY BAD ACKNOWLEDGEMENT";
+
+        aa.expectedBodiesReceived(TEST_MESSAGE);
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE, "");
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, badAcknowledgement.getBytes());
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, badAcknowledgement);
+
+        failed.expectedMessageCount(0);
+        failed.setAssertPeriod(1000);
+
+        ar.expectedMessageCount(0);
+        ae.expectedMessageCount(0);
+        invalid.expectedMessageCount(0);
+
+        mllpServer.setAcknowledgementString(badAcknowledgement);
+
+        source.sendBody(TEST_MESSAGE);
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testInvalidAcknowledgementContainingEmbeddedStartOfBlock() throws Exception {
+        final String badAcknowledgement = EXPECTED_AA.replaceFirst("RISTECH", "RISTECH" + START_OF_BLOCK);
+
+        aa.expectedBodiesReceived(TEST_MESSAGE);
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE, "AA");
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, badAcknowledgement.getBytes());
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, badAcknowledgement);
+
+        failed.expectedMessageCount(0);
+        failed.setAssertPeriod(1000);
+
+        ar.expectedMessageCount(0);
+        ae.expectedMessageCount(0);
+        invalid.expectedMessageCount(0);
+
+        mllpServer.setAcknowledgementString(badAcknowledgement);
+
+        source.sendBody(TEST_MESSAGE);
 
         assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
     }
 
+    @Test
+    public void testInvalidAcknowledgementContainingEmbeddedEndOfBlock() throws Exception {
+        final String badAcknowledgement = EXPECTED_AA.replaceFirst("RISTECH", "RISTECH" + END_OF_BLOCK);
+
+        aa.expectedBodiesReceived(TEST_MESSAGE);
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE, "AA");
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, badAcknowledgement.getBytes());
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, badAcknowledgement);
+
+        failed.expectedMessageCount(0);
+        failed.setAssertPeriod(1000);
+
+        ar.expectedMessageCount(0);
+        ae.expectedMessageCount(0);
+        invalid.expectedMessageCount(0);
+
+        mllpServer.setAcknowledgementString(badAcknowledgement);
+
+        source.sendBody(TEST_MESSAGE);
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerAcknowledgementValidationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerAcknowledgementValidationTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerAcknowledgementValidationTest.java
new file mode 100644
index 0000000..1ff641c
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerAcknowledgementValidationTest.java
@@ -0,0 +1,283 @@
+/**
+ * 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.ProducerTemplate;
+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.MllpServerResource;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+
+public class MllpTcpClientProducerAcknowledgementValidationTest extends CamelTestSupport {
+    static final String TEST_MESSAGE =
+        "MSH|^~\\&|ADT|EPIC|JCAPS|CC|20161206193919|RISTECH|ADT^A08|00001|D|2.3^^|||||||" + '\r'
+            + "EVN|A08|20150107161440||REG_UPDATE_SEND_VISIT_MESSAGES_ON_PATIENT_CHANGES|RISTECH^RADIOLOGY^TECHNOLOGIST^^^^^^UCLA^^^^^RRMC||" + '\r'
+            + "PID|1|2100355^^^MRN^MRN|2100355^^^MRN^MRN||MDCLS9^MC9||19700109|F||U|111 HOVER STREET^^LOS ANGELES^CA^90032^USA^P^^LOS ANGELE|LOS ANGELE|"
+                + "(310)725-6952^P^PH^^^310^7256952||ENGLISH|U||60000013647|565-33-2222|||U||||||||N||" + '\r'
+            + "PD1|||UCLA HEALTH SYSTEM^^10|10002116^ADAMS^JOHN^D^^^^^EPIC^^^^PROVID||||||||||||||" + '\r'
+            + "NK1|1|DOE^MC9^^|OTH|^^^^^USA|(310)888-9999^^^^^310^8889999|(310)999-2222^^^^^310^9992222|Emergency Contact 1|||||||||||||||||||||||||||" + '\r'
+            + "PV1|1|OUTPATIENT|RR CT^^^1000^^^^^^^DEPID|EL|||017511^TOBIAS^JONATHAN^^^^^^EPIC^^^^PROVID|017511^TOBIAS^JONATHAN^^^^^^EPIC^^^^PROVID||||||"
+                + "CLR|||||60000013647|SELF|||||||||||||||||||||HOV_CONF|^^^1000^^^^^^^||20150107161438||||||||||" + '\r'
+            + "PV2||||||||20150107161438||||CT BRAIN W WO CONTRAST||||||||||N|||||||||||||||||||||||||||" + '\r'
+            + "ZPV||||||||||||20150107161438|||||||||" + '\r'
+            + "AL1|1||33361^NO KNOWN ALLERGIES^^NOTCOMPUTRITION^NO KNOWN ALLERGIES^EXTELG||||||" + '\r'
+            + "DG1|1|DX|784.0^Headache^DX|Headache||VISIT" + '\r'
+            + "GT1|1|1000235129|MDCLS9^MC9^^||111 HOVER STREET^^LOS ANGELES^CA^90032^USA^^^LOS ANGELE|(310)725-6952^^^^^310^7256952||19700109|F|P/F|SLF|"
+                + "565-33-2222|||||^^^^^USA|||UNKNOWN|||||||||||||||||||||||||||||" + '\r'
+            + "UB2||||||||" + '\r'
+            + '\n';
+
+    static final String EXPECTED_AA =
+        "MSH|^~\\&|JCAPS|CC|ADT|EPIC|20161206193919|RISTECH|ACK^A08|00001|D|2.3^^|||||||" + '\r'
+            + "MSA|AA|00001|" + '\r'
+            + '\n';
+
+    static final String EXPECTED_AR =
+        "MSH|^~\\&|JCAPS|CC|ADT|EPIC|20161206193919|RISTECH|ACK^A08|00001|D|2.3^^|||||||" + '\r'
+            + "MSA|AR|00001|" + '\r'
+            + '\n';
+
+    static final String EXPECTED_AE =
+        "MSH|^~\\&|JCAPS|CC|ADT|EPIC|20161206193919|RISTECH|ACK^A08|00001|D|2.3^^|||||||" + '\r'
+            + "MSA|AE|00001|" + '\r'
+            + '\n';
+
+    @Rule
+    public MllpServerResource mllpServer = new MllpServerResource("localhost", AvailablePortFinder.getNextAvailable());
+
+    @EndpointInject(uri = "direct://source")
+    ProducerTemplate source;
+
+    @EndpointInject(uri = "mock://failed")
+    MockEndpoint failed;
+
+    @EndpointInject(uri = "mock://aa-ack")
+    MockEndpoint aa;
+    @EndpointInject(uri = "mock://ae-nack")
+    MockEndpoint ae;
+    @EndpointInject(uri = "mock://ar-nack")
+    MockEndpoint ar;
+
+    @EndpointInject(uri = "mock://invalid-ack")
+    MockEndpoint invalid;
+
+    @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() throws Exception {
+        return new RouteBuilder() {
+            String routeId = "mllp-sender";
+
+            public void configure() {
+                onException(MllpApplicationRejectAcknowledgementException.class)
+                        .handled(true)
+                        .to(ar)
+                        .log(LoggingLevel.ERROR, routeId, "AR Acknowledgement");
+
+                onException(MllpApplicationErrorAcknowledgementException.class)
+                        .handled(true)
+                        .to(ae)
+                        .log(LoggingLevel.ERROR, routeId, "AE Acknowledgement");
+
+                onException(MllpInvalidAcknowledgementException.class)
+                        .handled(true)
+                        .to(invalid)
+                        .log(LoggingLevel.ERROR, routeId, "Invalid Acknowledgement");
+
+                onCompletion()
+                        .onFailureOnly()
+                        .to(failed)
+                        .log(LoggingLevel.DEBUG, routeId, "Exchange failed");
+
+                from(source.getDefaultEndpoint()).routeId(routeId)
+                        .log(LoggingLevel.INFO, routeId, "Sending Message")
+                        .toF("mllp://%s:%d?validatePayload=true", mllpServer.getListenHost(), mllpServer.getListenPort())
+                        .log(LoggingLevel.INFO, routeId, "Received Acknowledgement")
+                        .to(aa);
+            }
+        };
+    }
+
+    @Test
+    public void testApplicationAcceptAcknowledgement() throws Exception {
+        aa.expectedBodiesReceived(TEST_MESSAGE);
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE, "AA");
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT, EXPECTED_AA.getBytes());
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, EXPECTED_AA);
+
+        failed.expectedMessageCount(0);
+        failed.setAssertPeriod(1000);
+
+        ae.expectedMessageCount(0);
+        ar.expectedMessageCount(0);
+        invalid.expectedMessageCount(0);
+
+        source.sendBody(TEST_MESSAGE);
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testApplicationRejectAcknowledgement() throws Exception {
+        ar.expectedBodiesReceived(TEST_MESSAGE);
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE, "AR");
+        ar.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT, EXPECTED_AR.getBytes());
+        ar.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, EXPECTED_AR);
+
+        failed.expectedMessageCount(0);
+        failed.setAssertPeriod(1000);
+
+        aa.expectedMessageCount(0);
+        ae.expectedMessageCount(0);
+        invalid.expectedMessageCount(0);
+
+        mllpServer.setSendApplicationRejectAcknowledgementModulus(1);
+
+        source.sendBody(TEST_MESSAGE);
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testApplicationErrorAcknowledgement() throws Exception {
+        ae.expectedBodiesReceived(TEST_MESSAGE);
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE, "AE");
+        ae.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT, EXPECTED_AE.getBytes());
+        ae.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, EXPECTED_AE);
+
+        failed.expectedMessageCount(0);
+        failed.setAssertPeriod(1000);
+
+        aa.expectedMessageCount(0);
+        ar.expectedMessageCount(0);
+        invalid.expectedMessageCount(0);
+
+        mllpServer.setSendApplicationErrorAcknowledgementModulus(1);
+
+        source.sendBody(TEST_MESSAGE);
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testEmptyAcknowledgement() throws Exception {
+        invalid.expectedBodiesReceived(TEST_MESSAGE);
+        invalid.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT, "".getBytes());
+        invalid.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, "");
+
+        failed.expectedMessageCount(0);
+        failed.setAssertPeriod(1000);
+
+        aa.expectedMessageCount(0);
+        ae.expectedMessageCount(0);
+        ar.expectedMessageCount(0);
+
+        mllpServer.setExcludeAcknowledgementModulus(1);
+
+        source.sendBody(TEST_MESSAGE);
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testInvalidAcknowledgement() throws Exception {
+        final String badAcknowledgement = "A VERY BAD ACKNOWLEDGEMENT";
+
+        invalid.expectedBodiesReceived(TEST_MESSAGE);
+        invalid.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, badAcknowledgement.getBytes());
+        invalid.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, badAcknowledgement);
+
+        failed.expectedMessageCount(0);
+        failed.setAssertPeriod(1000);
+
+        aa.expectedMessageCount(0);
+        ae.expectedMessageCount(0);
+        ar.expectedMessageCount(0);
+
+        mllpServer.setAcknowledgementString(badAcknowledgement);
+
+        source.sendBody(TEST_MESSAGE);
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testInvalidAcknowledgementContainingEmbeddedStartOfBlock() throws Exception {
+        final String badAcknowledgement = EXPECTED_AA.replaceFirst("RISTECH", "RISTECH" + START_OF_BLOCK);
+
+        invalid.expectedBodiesReceived(TEST_MESSAGE);
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE, "AA");
+        invalid.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, badAcknowledgement.getBytes());
+        invalid.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, badAcknowledgement);
+
+        failed.expectedMessageCount(0);
+        failed.setAssertPeriod(1000);
+
+        aa.expectedMessageCount(0);
+        ae.expectedMessageCount(0);
+        ar.expectedMessageCount(0);
+
+        mllpServer.setAcknowledgementString(badAcknowledgement);
+
+        source.sendBody(TEST_MESSAGE);
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testInvalidAcknowledgementContainingEmbeddedEndOfBlock() throws Exception {
+        final String badAcknowledgement = EXPECTED_AA.replaceFirst("RISTECH", "RISTECH" + END_OF_BLOCK);
+
+        invalid.expectedBodiesReceived(TEST_MESSAGE);
+        aa.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE, "AA");
+        invalid.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, badAcknowledgement.getBytes());
+        invalid.expectedHeaderReceived(MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING, badAcknowledgement);
+
+        failed.expectedMessageCount(0);
+        failed.setAssertPeriod(1000);
+
+        aa.expectedMessageCount(0);
+        ae.expectedMessageCount(0);
+        ar.expectedMessageCount(0);
+
+        mllpServer.setAcknowledgementString(badAcknowledgement);
+
+        source.sendBody(TEST_MESSAGE);
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerBlueprintTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerBlueprintTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerBlueprintTest.java
index 9b10a14..6d308bf 100644
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerBlueprintTest.java
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerBlueprintTest.java
@@ -41,10 +41,10 @@ public class MllpTcpClientProducerBlueprintTest extends CamelBlueprintTestSuppor
 
     final String sourceUri = "direct://source";
     final String mockAcknowledgedUri = "mock://acknowledged";
-    final String mockTimeoutUri = "mock://timeout-ex";
+    final String mockTimeoutUri = "mock://timeoutError-ex";
     final String mockAeExUri = "mock://ae-ack";
     final String mockArExUri = "mock://ar-ack";
-    final String mockFrameExUri = "mock://frame-ex";
+    final String mockFrameExUri = "mock://frameError-ex";
 
     @EndpointInject(uri = sourceUri)
     ProducerTemplate source;
@@ -101,11 +101,11 @@ public class MllpTcpClientProducerBlueprintTest extends CamelBlueprintTestSuppor
     @Test()
     public void testSendMultipleMessages() throws Exception {
         int messageCount = 500;
-        acknowledged.setExpectedMessageCount(messageCount);
-        timeout.setExpectedMessageCount(0);
-        frame.setExpectedMessageCount(0);
-        ae.setExpectedMessageCount(0);
-        ar.setExpectedMessageCount(0);
+        acknowledged.expectedMessageCount(messageCount);
+        timeout.expectedMessageCount(0);
+        frame.expectedMessageCount(0);
+        ae.expectedMessageCount(0);
+        ar.expectedMessageCount(0);
 
         // Uncomment one of these lines to see the NACKs handled
         // mllpServer.setSendApplicationRejectAcknowledgementModulus(10);

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerConnectionErrorTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerConnectionErrorTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerConnectionErrorTest.java
new file mode 100644
index 0000000..897b74b
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerConnectionErrorTest.java
@@ -0,0 +1,165 @@
+/**
+ * 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.ProducerTemplate;
+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.MllpServerResource;
+import org.apache.camel.test.junit4.CamelTestSupport;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.apache.camel.test.mllp.Hl7MessageGenerator.generateMessage;
+
+public class MllpTcpClientProducerConnectionErrorTest extends CamelTestSupport {
+    @Rule
+    public MllpServerResource mllpServer = new MllpServerResource("localhost", AvailablePortFinder.getNextAvailable());
+
+    @EndpointInject(uri = "direct://source")
+    ProducerTemplate source;
+
+    @EndpointInject(uri = "mock://complete")
+    MockEndpoint complete;
+
+    @EndpointInject(uri = "mock://write-ex")
+    MockEndpoint writeEx;
+
+    @EndpointInject(uri = "mock://receive-ex")
+    MockEndpoint receiveEx;
+
+    @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() throws Exception {
+        return new RouteBuilder() {
+            String routeId = "mllp-sender";
+
+            public void configure() {
+                onException(MllpWriteException.class)
+                        .handled(true)
+                        .to(writeEx)
+                        .log(LoggingLevel.ERROR, routeId, "Write Error")
+                        .stop();
+
+                onException(MllpReceiveAcknowledgementException.class)
+                        .handled(true)
+                        .to(receiveEx)
+                        .log(LoggingLevel.ERROR, routeId, "Receive Error")
+                        .stop();
+
+                from(source.getDefaultEndpoint()).routeId(routeId)
+                        .log(LoggingLevel.INFO, routeId, "Sending Message")
+                        .toF("mllp://%s:%d", mllpServer.getListenHost(), mllpServer.getListenPort())
+                        .log(LoggingLevel.INFO, routeId, "Received Acknowledgement")
+                        .to(complete);
+            }
+        };
+    }
+
+    @Test
+    public void testConnectionClosedBeforeSendingHL7Message() throws Exception {
+        complete.expectedMessageCount(1);
+        writeEx.expectedMessageCount(0);
+        receiveEx.expectedMessageCount(1);
+
+        NotifyBuilder done = new NotifyBuilder(context).whenCompleted(2).create();
+
+        // Need to send one message to get the connection established
+        source.sendBody(generateMessage());
+
+        mllpServer.closeClientConnections();
+        source.sendBody(generateMessage());
+
+        assertTrue("Should have completed an exchange", done.matches(5, TimeUnit.SECONDS));
+
+        assertMockEndpointsSatisfied(5, TimeUnit.SECONDS);
+    }
+
+    @Test()
+    public void testConnectionResetBeforeSendingHL7Message() throws Exception {
+        complete.expectedMessageCount(1);
+        writeEx.expectedMessageCount(1);
+        receiveEx.expectedMessageCount(0);
+
+        NotifyBuilder done = new NotifyBuilder(context).whenCompleted(2).create();
+
+        // Need to send one message to get the connection established
+        source.sendBody(generateMessage());
+
+        mllpServer.resetClientConnections();
+
+        source.sendBody(generateMessage());
+
+        assertTrue("Should have completed an exchange", done.matches(5, TimeUnit.SECONDS));
+
+        assertMockEndpointsSatisfied(5, TimeUnit.SECONDS);
+    }
+
+    @Test()
+    public void testConnectionClosedBeforeReadingAcknowledgement() throws Exception {
+        complete.expectedMessageCount(0);
+        writeEx.expectedMessageCount(0);
+        receiveEx.expectedMessageCount(1);
+
+        mllpServer.setCloseSocketBeforeAcknowledgementModulus(1);
+
+        NotifyBuilder done = new NotifyBuilder(context).whenCompleted(1).create();
+
+        source.sendBody(generateMessage());
+
+        assertTrue("Should have completed an exchange", done.matches(5, TimeUnit.SECONDS));
+
+        assertMockEndpointsSatisfied(5, TimeUnit.SECONDS);
+    }
+
+    @Test()
+    public void testConnectionResetBeforeReadingAcknowledgement() throws Exception {
+        complete.expectedMessageCount(0);
+        writeEx.expectedMessageCount(0);
+        receiveEx.expectedMessageCount(1);
+
+        mllpServer.setResetSocketBeforeAcknowledgementModulus(1);
+
+        NotifyBuilder done = new NotifyBuilder(context).whenCompleted(1).create();
+
+        source.sendBody(generateMessage());
+
+        assertTrue("Should have completed an exchange", done.matches(5, TimeUnit.SECONDS));
+
+        assertMockEndpointsSatisfied(5, TimeUnit.SECONDS);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerTest.java
index 6edc48c..0a98daa 100644
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerTest.java
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpClientProducerTest.java
@@ -29,6 +29,7 @@ import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.test.AvailablePortFinder;
 import org.apache.camel.test.junit.rule.mllp.MllpServerResource;
 import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 
@@ -44,16 +45,8 @@ public class MllpTcpClientProducerTest extends CamelTestSupport {
     @EndpointInject(uri = "mock://acknowledged")
     MockEndpoint acknowledged;
 
-    @EndpointInject(uri = "mock://timeout-ex")
-    MockEndpoint timeout;
-
-    @EndpointInject(uri = "mock://frame-ex")
-    MockEndpoint frame;
-
-    @Override
-    public String isMockEndpoints() {
-        return "log://netty-mllp-sender-throughput*";
-    }
+    @EndpointInject(uri = "mock://timeout-error")
+    MockEndpoint timeoutError;
 
     @Override
     protected CamelContext createCamelContext() throws Exception {
@@ -75,34 +68,26 @@ public class MllpTcpClientProducerTest extends CamelTestSupport {
             public void configure() throws Exception {
                 errorHandler(
                         defaultErrorHandler().allowRedeliveryWhileStopping(false));
-                onException(MllpFrameException.class)
-                        .handled(true)
-                        .logHandled(false)
-                        .to(frame);
-                onException(MllpTimeoutException.class)
+
+                onException(MllpAcknowledgementTimeoutException.class)
                         .handled(true)
                         .logHandled(false)
-                        .to(timeout);
-                onCompletion()
-                        .onFailureOnly().log(LoggingLevel.ERROR, "Processing Failed");
+                        .to(timeoutError);
+
                 from(source.getDefaultEndpoint())
                         .routeId("mllp-sender-test-route")
                         .log(LoggingLevel.INFO, "Sending Message: $simple{header[CamelHL7MessageControl]}")
                         .toF("mllp://%s:%d?connectTimeout=%d&receiveTimeout=%d",
                                 mllpServer.getListenHost(), mllpServer.getListenPort(), connectTimeout, responseTimeout)
                         .to(acknowledged);
-                from("direct://handle-timeout")
-                        .log(LoggingLevel.ERROR, "Response Timeout")
-                        .rollback();
             }
         };
     }
 
     @Test
     public void testSendSingleMessage() throws Exception {
-        acknowledged.setExpectedMessageCount(1);
-        timeout.setExpectedMessageCount(0);
-        frame.setExpectedMessageCount(0);
+        acknowledged.expectedMessageCount(1);
+        timeoutError.expectedMessageCount(0);
 
         source.sendBody(generateMessage());
 
@@ -113,9 +98,8 @@ public class MllpTcpClientProducerTest extends CamelTestSupport {
     @Test
     public void testSendMultipleMessages() throws Exception {
         int messageCount = 5;
-        acknowledged.setExpectedMessageCount(messageCount);
-        timeout.setExpectedMessageCount(0);
-        frame.setExpectedMessageCount(0);
+        acknowledged.expectedMessageCount(messageCount);
+        timeoutError.expectedMessageCount(0);
 
         NotifyBuilder[] complete = new NotifyBuilder[messageCount];
         for (int i = 0; i < messageCount; ++i) {
@@ -134,9 +118,8 @@ public class MllpTcpClientProducerTest extends CamelTestSupport {
     @Test
     public void testNoResponseOnFirstMessage() throws Exception {
         int sendMessageCount = 5;
-        acknowledged.setExpectedMessageCount(sendMessageCount - 1);
-        timeout.expectedMessageCount(1);
-        frame.setExpectedMessageCount(0);
+        acknowledged.expectedMessageCount(sendMessageCount - 1);
+        timeoutError.expectedMessageCount(1);
 
         NotifyBuilder[] complete = new NotifyBuilder[sendMessageCount];
         for (int i = 0; i < sendMessageCount; ++i) {
@@ -161,9 +144,8 @@ public class MllpTcpClientProducerTest extends CamelTestSupport {
     @Test
     public void testNoResponseOnNthMessage() throws Exception {
         int sendMessageCount = 3;
-        acknowledged.setExpectedMessageCount(sendMessageCount - 1);
-        timeout.expectedMessageCount(1);
-        frame.setExpectedMessageCount(0);
+        acknowledged.expectedMessageCount(sendMessageCount - 1);
+        timeoutError.expectedMessageCount(1);
 
         NotifyBuilder[] complete = new NotifyBuilder[sendMessageCount];
         for (int i = 0; i < sendMessageCount; ++i) {
@@ -183,7 +165,8 @@ public class MllpTcpClientProducerTest extends CamelTestSupport {
     @Test
     public void testMissingEndOfDataByte() throws Exception {
         int sendMessageCount = 3;
-        acknowledged.setExpectedMessageCount(sendMessageCount - 1);
+        acknowledged.expectedMessageCount(sendMessageCount - 1);
+        timeoutError.expectedMessageCount(1);
 
         NotifyBuilder[] complete = new NotifyBuilder[sendMessageCount];
         for (int i = 0; i < sendMessageCount; ++i) {
@@ -203,7 +186,8 @@ public class MllpTcpClientProducerTest extends CamelTestSupport {
     @Test
     public void testMissingEndOfBlockByte() throws Exception {
         int sendMessageCount = 3;
-        acknowledged.setExpectedMessageCount(sendMessageCount - 1);
+        acknowledged.expectedMessageCount(sendMessageCount - 1);
+        timeoutError.expectedMessageCount(1);
 
         NotifyBuilder[] complete = new NotifyBuilder[sendMessageCount];
         for (int i = 0; i < sendMessageCount; ++i) {
@@ -221,19 +205,25 @@ public class MllpTcpClientProducerTest extends CamelTestSupport {
     }
 
     @Test
-    public void testApplicationAcceptAcknowledgement() throws Exception {
-        int sendMessageCount = 5;
-        acknowledged.setExpectedMessageCount(sendMessageCount);
+    public void testAcknowledgementReceiveTimeout() throws Exception {
+        acknowledged.expectedMessageCount(0);
+        timeoutError.expectedMessageCount(1);
 
-        NotifyBuilder[] complete = new NotifyBuilder[sendMessageCount];
-        for (int i = 0; i < sendMessageCount; ++i) {
-            complete[i] = new NotifyBuilder(context).whenDone(i + 1).create();
-        }
+        mllpServer.disableResponse(1);
 
-        for (int i = 0; i < sendMessageCount; ++i) {
-            source.sendBody(generateMessage(i + 1));
-            assertTrue("Messege " + i + " not completed", complete[i].matches(1, TimeUnit.SECONDS));
-        }
+        source.sendBody(generateMessage());
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testAcknowledgementReadTimeout() throws Exception {
+        acknowledged.expectedMessageCount(0);
+        timeoutError.expectedMessageCount(1);
+
+        mllpServer.setDelayDuringAcknowledgement(15000);
+
+        source.sendBody(generateMessage());
 
         assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/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
index e2971dd..557d462 100644
--- 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
@@ -101,7 +101,8 @@ public class MllpTcpServerConsumerAcknowledgementTest extends CamelTestSupport {
 
         final String expectedAcknowledgement =
                 "MSH|^~\\&|^org^sys||APP_A|FAC_A|||ACK^A04^ADT_A04|||2.6" + '\r'
-                        + "MSA|AA|" + '\r' + '\n';
+                        + "MSA|AA|" + '\r'
+                        + '\r' + '\n';
 
         result.expectedBodiesReceived(testMessage);
         result.expectedHeaderReceived(MLLP_SENDING_APPLICATION, "APP_A");
@@ -141,7 +142,7 @@ public class MllpTcpServerConsumerAcknowledgementTest extends CamelTestSupport {
 
         final String expectedAcknowledgement =
                 "MSH|^~\\&|^org^sys||APP_A|FAC_A|||ACK^A04^ADT_A04|||2.6" + '\r'
-                        + "MSA|AA|"
+                        + "MSA|AA|" + '\r'
                         + '\r' + '\n';
 
         result.expectedBodiesReceived(testMessage);

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerConnectionTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerConnectionTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerConnectionTest.java
index ce89b40..239a178 100644
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerConnectionTest.java
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerConnectionTest.java
@@ -30,6 +30,9 @@ import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Rule;
 import org.junit.Test;
 
+import static org.apache.camel.component.mllp.MllpTcpServerConsumer.SOCKET_STARTUP_TEST_READ_TIMEOUT;
+import static org.apache.camel.component.mllp.MllpTcpServerConsumer.SOCKET_STARTUP_TEST_WAIT;
+
 public class MllpTcpServerConsumerConnectionTest extends CamelTestSupport {
     static final int RECEIVE_TIMEOUT = 500;
 
@@ -83,11 +86,12 @@ public class MllpTcpServerConsumerConnectionTest extends CamelTestSupport {
      * @throws Exception
      */
     @Test
-    public void testConnectWithoutData() throws Exception {
+    public void testConnectThenCloseWithoutData() throws Exception {
         int connectionCount = 10;
         long connectionMillis = 200;
 
         result.setExpectedCount(0);
+        result.setAssertPeriod(SOCKET_STARTUP_TEST_WAIT + SOCKET_STARTUP_TEST_READ_TIMEOUT);
 
         addTestRoute(-1);
 
@@ -97,6 +101,35 @@ public class MllpTcpServerConsumerConnectionTest extends CamelTestSupport {
             mllpClient.close();
         }
 
+        // Connect one more time and allow a client thread to start
+        mllpClient.connect();
+        Thread.sleep(SOCKET_STARTUP_TEST_WAIT + SOCKET_STARTUP_TEST_READ_TIMEOUT + 1000);
+        mllpClient.close();
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testConnectThenResetWithoutData() throws Exception {
+        int connectionCount = 10;
+        long connectionMillis = 200;
+
+        result.setExpectedCount(0);
+        result.setAssertPeriod(SOCKET_STARTUP_TEST_WAIT + SOCKET_STARTUP_TEST_READ_TIMEOUT);
+
+        addTestRoute(-1);
+
+        for (int i = 1; i <= connectionCount; ++i) {
+            mllpClient.connect();
+            Thread.sleep(connectionMillis);
+            mllpClient.reset();
+        }
+
+        // Connect one more time and allow a client thread to start
+        mllpClient.connect();
+        Thread.sleep(SOCKET_STARTUP_TEST_WAIT + SOCKET_STARTUP_TEST_READ_TIMEOUT + 1000);
+        mllpClient.reset();
+
         assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
     }
 


[3/8] camel git commit: CAMEL-10511: Updated MllpTcpClientProducer and MllpTcpServerConsumer to consume all available data on socket

Posted by da...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerMessageValidationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerMessageValidationTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerMessageValidationTest.java
new file mode 100644
index 0000000..5c431e6
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerMessageValidationTest.java
@@ -0,0 +1,317 @@
+/**
+ * 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 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.junit.rule.mllp.MllpJUnitResourceTimeoutException;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+import static org.apache.camel.test.mllp.Hl7MessageGenerator.generateMessage;
+
+public class MllpTcpServerConsumerMessageValidationTest extends CamelTestSupport {
+    @Rule
+    public MllpClientResource mllpClient = new MllpClientResource();
+
+    @EndpointInject(uri = "mock://result")
+    MockEndpoint result;
+
+    @EndpointInject(uri = "mock://timeout-ex")
+    MockEndpoint timeout;
+
+    @EndpointInject(uri = "mock://invalid-ex")
+    MockEndpoint invalid;
+
+    @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";
+
+                onException(MllpTimeoutException.class)
+                        .to(timeout);
+
+                onException(MllpInvalidMessageException.class)
+                        .to(invalid);
+
+                fromF("mllp://%s:%d?validatePayload=true&autoAck=true&connectTimeout=%d&receiveTimeout=%d",
+                        mllpClient.getMllpHost(), mllpClient.getMllpPort(), connectTimeout, responseTimeout)
+                        .routeId(routeId)
+                        .log(LoggingLevel.INFO, routeId, "Test route received message")
+                        .to(result);
+
+            }
+        };
+    }
+
+    @Test
+    public void testReceiveSingleMessage() throws Exception {
+        result.expectedMessageCount(1);
+        result.setAssertPeriod(1000);
+        timeout.expectedMessageCount(0);
+        invalid.expectedMessageCount(0);
+
+        mllpClient.connect();
+
+        mllpClient.sendMessageAndWaitForAcknowledgement(generateMessage(), 10000);
+
+        assertMockEndpointsSatisfied(10, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testReceiveSingleMessageWithDelayAfterConnection() throws Exception {
+        result.expectedMinimumMessageCount(1);
+        result.setAssertPeriod(1000);
+        timeout.expectedMessageCount(0);
+        invalid.expectedMessageCount(0);
+
+        mllpClient.connect();
+
+        Thread.sleep(5000);
+        mllpClient.sendMessageAndWaitForAcknowledgement(generateMessage(), 10000);
+
+        assertMockEndpointsSatisfied(10, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testReceiveMultipleMessages() throws Exception {
+        int sendMessageCount = 5;
+        result.expectedMinimumMessageCount(5);
+        result.setAssertPeriod(1000);
+        timeout.expectedMessageCount(0);
+        invalid.expectedMessageCount(0);
+
+        mllpClient.connect();
+
+        for (int i = 1; i <= sendMessageCount; ++i) {
+            mllpClient.sendMessageAndWaitForAcknowledgement(generateMessage(i));
+        }
+
+        assertMockEndpointsSatisfied(10, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testOpenMllpEnvelopeWithReset() throws Exception {
+        result.expectedMessageCount(4);
+        result.setAssertPeriod(1000);
+        timeout.expectedMessageCount(1);
+        invalid.expectedMessageCount(0);
+
+        NotifyBuilder notify1 = new NotifyBuilder(context).whenDone(2).create();
+        NotifyBuilder notify2 = new NotifyBuilder(context).whenDone(5).create();
+
+        mllpClient.connect();
+        mllpClient.setSoTimeout(10000);
+
+        log.info("Sending TEST_MESSAGE_1");
+        String acknowledgement1 = mllpClient.sendMessageAndWaitForAcknowledgement(generateMessage(1));
+
+        log.info("Sending TEST_MESSAGE_2");
+        String acknowledgement2 = mllpClient.sendMessageAndWaitForAcknowledgement(generateMessage(2));
+
+        assertTrue("First two normal exchanges did not complete", notify1.matches(10, TimeUnit.SECONDS));
+
+        log.info("Sending TEST_MESSAGE_3");
+        mllpClient.setSendEndOfBlock(false);
+        mllpClient.setSendEndOfData(false);
+        // Acknowledgement won't come here
+        try {
+            mllpClient.sendMessageAndWaitForAcknowledgement(generateMessage(3));
+        } catch (MllpJUnitResourceException resourceEx) {
+            log.info("Expected exception reading response");
+        }
+        mllpClient.disconnect();
+        Thread.sleep(1000);
+        mllpClient.connect();
+
+        log.info("Sending TEST_MESSAGE_4");
+        mllpClient.setSendEndOfBlock(true);
+        mllpClient.setSendEndOfData(true);
+        String acknowledgement4 = mllpClient.sendMessageAndWaitForAcknowledgement(generateMessage(4));
+
+        log.info("Sending TEST_MESSAGE_5");
+        String acknowledgement5 = mllpClient.sendMessageAndWaitForAcknowledgement(generateMessage(5));
+
+        assertTrue("Remaining exchanges did not complete", notify2.matches(10, TimeUnit.SECONDS));
+
+        assertMockEndpointsSatisfied(10, TimeUnit.SECONDS);
+
+        assertTrue("Should be acknowledgment for message 1", acknowledgement1.contains("MSA|AA|00001"));
+        assertTrue("Should be acknowledgment for message 2", acknowledgement2.contains("MSA|AA|00002"));
+        // assertTrue("Should be acknowledgment for message 3", acknowledgement3.contains("MSA|AA|00003"));
+        assertTrue("Should be acknowledgment for message 4", acknowledgement4.contains("MSA|AA|00004"));
+        assertTrue("Should be acknowledgment for message 5", acknowledgement5.contains("MSA|AA|00005"));
+    }
+
+    @Test
+    public void testMessageReadTimeout() throws Exception {
+        result.expectedMessageCount(0);
+        result.setAssertPeriod(1000);
+        timeout.expectedMessageCount(1);
+        invalid.expectedMessageCount(0);
+
+        NotifyBuilder notify = new NotifyBuilder(context).whenDone(1).create();
+
+        mllpClient.setSendEndOfBlock(false);
+        mllpClient.setSendEndOfData(false);
+
+        mllpClient.sendFramedData(generateMessage());
+
+        assertTrue("One exchange should have completed", notify.matches(15, TimeUnit.SECONDS));
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testInvalidMessage() throws Exception {
+        result.expectedMessageCount(0);
+        result.setAssertPeriod(1000);
+        timeout.expectedMessageCount(0);
+        invalid.expectedMessageCount(1);
+
+        mllpClient.sendFramedData("INVALID PAYLOAD");
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testNthInvalidMessage() throws Exception {
+        int messageCount = 10;
+
+        result.expectedMessageCount(messageCount - 1);
+        result.setAssertPeriod(1000);
+        timeout.expectedMessageCount(0);
+        invalid.expectedMessageCount(1);
+
+        for (int i = 0; i < messageCount; ++i) {
+            if (i == messageCount / 2) {
+                try {
+                    mllpClient.sendMessageAndWaitForAcknowledgement("INVALID PAYLOAD");
+                    fail("An acknowledgement should not be received for an invalid HL7 message");
+                } catch (MllpJUnitResourceTimeoutException timeoutEx) {
+                    // expected - eat this
+                }
+            } else {
+                mllpClient.sendMessageAndWaitForAcknowledgement(generateMessage(i + 1));
+            }
+        }
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testMessageContainingEmbeddedStartOfBlock() throws Exception {
+        result.expectedMessageCount(0);
+        result.setAssertPeriod(1000);
+        timeout.expectedMessageCount(0);
+        invalid.expectedMessageCount(1);
+
+        mllpClient.sendMessageAndWaitForAcknowledgement(generateMessage().replaceFirst("EVN", "EVN" + START_OF_BLOCK));
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testNthMessageContainingEmbeddedStartOfBlock() throws Exception {
+        int messageCount = 10;
+
+        result.expectedMessageCount(messageCount - 1);
+        result.setAssertPeriod(1000);
+        timeout.expectedMessageCount(0);
+        invalid.expectedMessageCount(1);
+
+        for (int i = 0; i < messageCount; ++i) {
+            String message = (i == (messageCount/2))
+                    ? generateMessage(i + 1).replaceFirst("EVN", "EVN" + START_OF_BLOCK)
+                    : generateMessage(i + 1);
+
+            log.debug("Sending message {}", MllpComponent.covertToPrintFriendlyString(message));
+
+            mllpClient.sendMessageAndWaitForAcknowledgement(message);
+        }
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testMessageContainingEmbeddedEndOfBlock() throws Exception {
+        result.expectedMessageCount(0);
+        result.setAssertPeriod(1000);
+        timeout.expectedMessageCount(0);
+        invalid.expectedMessageCount(1);
+
+        mllpClient.sendMessageAndWaitForAcknowledgement(generateMessage().replaceFirst("EVN", "EVN" + END_OF_BLOCK));
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testInvalidMessageContainingEmbeddedEndOfBlock() throws Exception {
+        int messageCount = 10;
+
+        result.expectedMessageCount(messageCount - 1);
+        result.setAssertPeriod(1000);
+        timeout.expectedMessageCount(0);
+        invalid.expectedMessageCount(1);
+
+        for (int i = 0; i < messageCount; ++i) {
+            String message = (i == (messageCount/2))
+                    ? generateMessage(i + 1).replaceFirst("EVN", "EVN" + END_OF_BLOCK)
+                    : generateMessage(i + 1);
+
+            log.debug("Sending message {}", MllpComponent.covertToPrintFriendlyString(message));
+
+            mllpClient.sendMessageAndWaitForAcknowledgement(message);
+        }
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java
index eb6a463..6d05883 100644
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java
@@ -30,10 +30,15 @@ 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.junit.rule.mllp.MllpJUnitResourceTimeoutException;
 import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Rule;
 import org.junit.Test;
 
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 import static org.apache.camel.test.mllp.Hl7MessageGenerator.generateMessage;
 
 public class MllpTcpServerConsumerTest extends CamelTestSupport {
@@ -43,6 +48,9 @@ public class MllpTcpServerConsumerTest extends CamelTestSupport {
     @EndpointInject(uri = "mock://result")
     MockEndpoint result;
 
+    @EndpointInject(uri = "mock://timeout-ex")
+    MockEndpoint timeout;
+
     @Override
     protected CamelContext createCamelContext() throws Exception {
         DefaultCamelContext context = (DefaultCamelContext) super.createCamelContext();
@@ -67,9 +75,8 @@ public class MllpTcpServerConsumerTest extends CamelTestSupport {
             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");
+                onException(MllpTimeoutException.class)
+                        .to(timeout);
 
                 fromF("mllp://%s:%d?autoAck=true&connectTimeout=%d&receiveTimeout=%d",
                         mllpClient.getMllpHost(), mllpClient.getMllpPort(), connectTimeout, responseTimeout)
@@ -84,6 +91,7 @@ public class MllpTcpServerConsumerTest extends CamelTestSupport {
     @Test
     public void testReceiveSingleMessage() throws Exception {
         result.expectedMessageCount(1);
+        timeout.expectedMessageCount(0);
 
         mllpClient.connect();
 
@@ -95,6 +103,7 @@ public class MllpTcpServerConsumerTest extends CamelTestSupport {
     @Test
     public void testReceiveSingleMessageWithDelayAfterConnection() throws Exception {
         result.expectedMinimumMessageCount(1);
+        timeout.expectedMessageCount(0);
 
         mllpClient.connect();
 
@@ -108,6 +117,7 @@ public class MllpTcpServerConsumerTest extends CamelTestSupport {
     public void testReceiveMultipleMessages() throws Exception {
         int sendMessageCount = 5;
         result.expectedMinimumMessageCount(5);
+        timeout.expectedMessageCount(0);
 
         mllpClient.connect();
 
@@ -121,6 +131,7 @@ public class MllpTcpServerConsumerTest extends CamelTestSupport {
     @Test
     public void testOpenMllpEnvelopeWithReset() throws Exception {
         result.expectedMessageCount(4);
+        timeout.expectedMessageCount(1);
         NotifyBuilder notify1 = new NotifyBuilder(context).whenDone(2).create();
         NotifyBuilder notify2 = new NotifyBuilder(context).whenDone(5).create();
 
@@ -167,5 +178,114 @@ public class MllpTcpServerConsumerTest extends CamelTestSupport {
         assertTrue("Should be acknowledgment for message 5", acknowledgement5.contains("MSA|AA|00005"));
     }
 
+    @Test
+    public void testMessageReadTimeout() throws Exception {
+        result.expectedMessageCount(0);
+        timeout.expectedMessageCount(1);
+
+        NotifyBuilder notify = new NotifyBuilder(context).whenDone(1).create();
+
+        mllpClient.setSendEndOfBlock(false);
+        mllpClient.setSendEndOfData(false);
+
+        mllpClient.sendFramedData(generateMessage());
+
+        assertTrue("One exchange should have completed", notify.matches(15, TimeUnit.SECONDS));
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testInvalidMessage() throws Exception {
+        result.expectedMessageCount(1);
+        timeout.expectedMessageCount(0);
+
+        mllpClient.sendFramedData("INVALID PAYLOAD");
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testNthInvalidMessage() throws Exception {
+        int messageCount = 10;
+
+        result.expectedMessageCount(messageCount);
+        timeout.expectedMessageCount(0);
+
+        for (int i = 0; i < messageCount; ++i) {
+            if (i == messageCount / 2) {
+                try {
+                    mllpClient.sendMessageAndWaitForAcknowledgement("INVALID PAYLOAD");
+                    fail("An acknowledgement should not be received for an invalid HL7 message");
+                } catch (MllpJUnitResourceTimeoutException timeoutEx) {
+                    // expected - eat this
+                }
+            } else {
+                mllpClient.sendMessageAndWaitForAcknowledgement(generateMessage(i + 1));
+            }
+        }
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testMessageContainingEmbeddedStartOfBlock() throws Exception {
+        result.expectedMessageCount(1);
+        timeout.expectedMessageCount(0);
+
+        mllpClient.sendMessageAndWaitForAcknowledgement(generateMessage().replaceFirst("EVN", "EVN" + START_OF_BLOCK));
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testNthMessageContainingEmbeddedStartOfBlock() throws Exception {
+        int messageCount = 10;
+
+        result.expectedMessageCount(messageCount);
+        timeout.expectedMessageCount(0);
+
+        for (int i = 0; i < messageCount; ++i) {
+            String message = (i == (messageCount/2))
+                    ? generateMessage(i + 1).replaceFirst("EVN", "EVN" + START_OF_BLOCK)
+                    : generateMessage(i + 1);
+
+            log.debug("Sending message {}", MllpComponent.covertToPrintFriendlyString(message));
+
+            mllpClient.sendMessageAndWaitForAcknowledgement(message);
+        }
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testMessageContainingEmbeddedEndOfBlock() throws Exception {
+        result.expectedMessageCount(1);
+        timeout.expectedMessageCount(0);
+
+        mllpClient.sendMessageAndWaitForAcknowledgement(generateMessage().replaceFirst("EVN", "EVN" + END_OF_BLOCK));
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testInvalidMessageContainingEmbeddedEndOfBlock() throws Exception {
+        int messageCount = 10;
+
+        result.expectedMessageCount(messageCount);
+        timeout.expectedMessageCount(0);
+
+        for (int i = 0; i < messageCount; ++i) {
+            String message = (i == (messageCount/2))
+                    ? generateMessage(i + 1).replaceFirst("EVN", "EVN" + END_OF_BLOCK)
+                    : generateMessage(i + 1);
+
+            log.debug("Sending message {}", MllpComponent.covertToPrintFriendlyString(message));
+
+            mllpClient.sendMessageAndWaitForAcknowledgement(message);
+        }
+
+        assertMockEndpointsSatisfied(15, TimeUnit.SECONDS);
+    }
 }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerProducerBlueprintTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerProducerBlueprintTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerProducerBlueprintTest.java
deleted file mode 100644
index dc796a5..0000000
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerProducerBlueprintTest.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/**
- * 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 org.apache.camel.EndpointInject;
-import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.test.blueprint.CamelBlueprintTestSupport;
-import org.junit.Ignore;
-
-@Ignore(value = "Not Yet Implemented")
-// TODO: Implement this
-public class MllpTcpServerProducerBlueprintTest extends CamelBlueprintTestSupport {
-    @EndpointInject(uri = "mock://target")
-    MockEndpoint target;
-
-    @Override
-    protected String getBlueprintDescriptor() {
-        return "OSGI-INF/blueprint/mllp-tcp-server-producer.xml";
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTimeoutExceptionTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTimeoutExceptionTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTimeoutExceptionTest.java
deleted file mode 100644
index da4ceb7..0000000
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTimeoutExceptionTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * 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 org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class MllpTimeoutExceptionTest {
-    static final String EXCEPTION_MESSAGE = "Test Timeoute Exception";
-
-    static final String HL7_MESSAGE =
-            "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';
-
-    static final String EXCEPTION_MESSAGE_WITH_LOG_PHI_DISABLED = EXCEPTION_MESSAGE;
-    static final String EXCEPTION_MESSAGE_WITH_LOG_PHI_ENABLED =
-            String.format(String.format("%s:\n\tHL7 Message: %s",
-                    EXCEPTION_MESSAGE,
-                    new String(HL7_MESSAGE).replaceAll("\r", "<CR>").replaceAll("\n", "<LF>"))
-            );
-
-    Exception exception;
-
-    @Before
-    public void setUp() throws Exception {
-        exception = new MllpTimeoutException(EXCEPTION_MESSAGE, HL7_MESSAGE.getBytes());
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        System.clearProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY);
-    }
-
-    @Test
-    public void testLogPhiDefault() throws Exception {
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(EXCEPTION_MESSAGE_WITH_LOG_PHI_ENABLED, exceptionMessage);
-    }
-
-    @Test
-    public void testLogPhiDisabled() throws Exception {
-        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "false");
-
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(EXCEPTION_MESSAGE_WITH_LOG_PHI_DISABLED, exceptionMessage);
-    }
-
-    @Test
-    public void testLogPhiEnabled() throws Exception {
-        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
-
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(EXCEPTION_MESSAGE_WITH_LOG_PHI_ENABLED, exceptionMessage);
-    }
-
-    @Test
-    public void testNullPayload() throws Exception {
-        final String expectedMessage = String.format("%s:\n\tHL7 Message: null", EXCEPTION_MESSAGE);
-
-        exception = new MllpTimeoutException(EXCEPTION_MESSAGE, null);
-
-        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(expectedMessage, exceptionMessage);
-    }
-
-    @Test
-    public void testToString() throws Exception {
-        final String expectedString =
-                "org.apache.camel.component.mllp.MllpTimeoutException: "
-                        + "{hl7Message="
-                        +      "MSH|^~\\&|APP_A|FAC_A|^org^sys||||ADT^A04^ADT_A04|||2.6<CR>"
-                        +      "PID|1||1100832^^^^PI||TEST^FIG||98765432|U||R|435 MAIN STREET^^LONGMONT^CO^80503||123-456-7890|||S<CR><CR><LF>"
-                        + "}";
-
-        assertEquals(expectedString, exception.toString());
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpWriteExceptionTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpWriteExceptionTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpWriteExceptionTest.java
deleted file mode 100644
index daf7fe9..0000000
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpWriteExceptionTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * 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 org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-public class MllpWriteExceptionTest {
-    static final String EXCEPTION_MESSAGE = "Test Write Exception";
-
-    static final String HL7_MESSAGE =
-            "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';
-
-    static final String EXCEPTION_MESSAGE_WITH_LOG_PHI_DISABLED = EXCEPTION_MESSAGE;
-    static final String EXCEPTION_MESSAGE_WITH_LOG_PHI_ENABLED =
-            String.format(String.format("%s:\n\tMLLP Payload: %s",
-                    EXCEPTION_MESSAGE,
-                    new String(HL7_MESSAGE).replaceAll("\r", "<CR>").replaceAll("\n", "<LF>"))
-            );
-
-    Exception exception;
-
-    @Before
-    public void setUp() throws Exception {
-        exception = new MllpWriteException(EXCEPTION_MESSAGE, HL7_MESSAGE.getBytes());
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        System.clearProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY);
-    }
-
-    @Test
-    public void testLogPhiDefault() throws Exception {
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(EXCEPTION_MESSAGE_WITH_LOG_PHI_ENABLED, exceptionMessage);
-    }
-
-    @Test
-    public void testLogPhiDisabled() throws Exception {
-        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "false");
-
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(EXCEPTION_MESSAGE_WITH_LOG_PHI_DISABLED, exceptionMessage);
-    }
-
-    @Test
-    public void testLogPhiEnabled() throws Exception {
-        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
-
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(EXCEPTION_MESSAGE_WITH_LOG_PHI_ENABLED, exceptionMessage);
-    }
-
-    @Test
-    public void testNullPayload() throws Exception {
-        final String expectedMessage = String.format("%s:\n\tMLLP Payload: null", EXCEPTION_MESSAGE);
-
-        exception = new MllpWriteException(EXCEPTION_MESSAGE, null);
-
-        System.setProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
-        String exceptionMessage = exception.getMessage();
-
-        assertEquals(expectedMessage, exceptionMessage);
-    }
-
-    @Test
-    public void testToString() throws Exception {
-        final String expectedString =
-                "org.apache.camel.component.mllp.MllpWriteException: "
-                        + "{mllpPayload="
-                        +      "MSH|^~\\&|APP_A|FAC_A|^org^sys||||ADT^A04^ADT_A04|||2.6<CR>"
-                        +      "PID|1||1100832^^^^PI||TEST^FIG||98765432|U||R|435 MAIN STREET^^LONGMONT^CO^80503||123-456-7890|||S<CR><CR><LF>"
-                        + "}";
-
-        assertEquals(expectedString, exception.toString());
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/Hl7UtilTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/Hl7UtilTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/Hl7UtilTest.java
new file mode 100644
index 0000000..e7d443c
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/Hl7UtilTest.java
@@ -0,0 +1,126 @@
+/**
+ * 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.impl;
+
+import java.io.ByteArrayOutputStream;
+
+import org.junit.Test;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class Hl7UtilTest {
+    static final String TEST_MESSAGE =
+        "MSH|^~\\&|ADT|EPIC|JCAPS|CC|20161206193919|RISTECH|ADT^A08|00001|D|2.3^^|||||||" + '\r'
+            + "EVN|A08|20150107161440||REG_UPDATE_SEND_VISIT_MESSAGES_ON_PATIENT_CHANGES|RISTECH^RADIOLOGY^TECHNOLOGIST^^^^^^UCLA^^^^^RRMC||" + '\r'
+            + "PID|1|2100355^^^MRN^MRN|2100355^^^MRN^MRN||MDCLS9^MC9||19700109|F||U|111 HOVER STREET^^LOS ANGELES^CA^90032^USA^P^^LOS ANGELE|"
+                + "LOS ANGELE|(310)725-6952^P^PH^^^310^7256952||ENGLISH|U||60000013647|565-33-2222|||U||||||||N||" + '\r'
+            + "PD1|||UCLA HEALTH SYSTEM^^10|10002116^ADAMS^JOHN^D^^^^^EPIC^^^^PROVID||||||||||||||" + '\r'
+            + "NK1|1|DOE^MC9^^|OTH|^^^^^USA|(310)888-9999^^^^^310^8889999|(310)999-2222^^^^^310^9992222|Emergency Contact 1|||||||||||||||||||||||||||" + '\r'
+            + "PV1|1|OUTPATIENT|RR CT^^^1000^^^^^^^DEPID|EL|||017511^TOBIAS^JONATHAN^^^^^^EPIC^^^^PROVID|017511^TOBIAS^JONATHAN^^^^^^EPIC^^^^PROVID||||||"
+                + "CLR|||||60000013647|SELF|||||||||||||||||||||HOV_CONF|^^^1000^^^^^^^||20150107161438||||||||||" + '\r'
+            + "PV2||||||||20150107161438||||CT BRAIN W WO CONTRAST||||||||||N|||||||||||||||||||||||||||" + '\r'
+            + "ZPV||||||||||||20150107161438|||||||||" + '\r'
+            + "AL1|1||33361^NO KNOWN ALLERGIES^^NOTCOMPUTRITION^NO KNOWN ALLERGIES^EXTELG||||||" + '\r'
+            + "DG1|1|DX|784.0^Headache^DX|Headache||VISIT" + '\r'
+            + "GT1|1|1000235129|MDCLS9^MC9^^||111 HOVER STREET^^LOS ANGELES^CA^90032^USA^^^LOS ANGELE|(310)725-6952^^^^^310^7256952||19700109|F|P/F|SLF|"
+                + "565-33-2222|||||^^^^^USA|||UNKNOWN|||||||||||||||||||||||||||||" + '\r'
+            + "UB2||||||||" + '\r'
+            + '\n';
+
+    @Test
+    public void testGenerateInvalidPayloadExceptionMessage() throws Exception {
+        String message = Hl7Util.generateInvalidPayloadExceptionMessage(TEST_MESSAGE.getBytes());
+
+        assertNull("Valid payload should result in a null message", message);
+    }
+
+    @Test
+    public void testGenerateInvalidPayloadExceptionMessageWithLengthLargerThanArraySize() throws Exception {
+        byte[] payload = TEST_MESSAGE.getBytes();
+        String message = Hl7Util.generateInvalidPayloadExceptionMessage(payload, payload.length * 2);
+
+        assertNull("Valid payload should result in a null message", message);
+    }
+
+    @Test
+    public void testGenerateInvalidPayloadExceptionMessageWithLengthSmallerThanArraySize() throws Exception {
+        byte[] payload = TEST_MESSAGE.getBytes();
+        String message = Hl7Util.generateInvalidPayloadExceptionMessage(payload, 10);
+
+        assertEquals("The HL7 payload terminating bytes [0x7c, 0x41] are incorrect - expected [0xd, 0xa]  {ASCII [<CR>, <LF>]}", message);
+    }
+
+    @Test
+    public void testGenerateInvalidPayloadExceptionMessageWithNullPayload() throws Exception {
+        assertEquals("HL7 payload is null", Hl7Util.generateInvalidPayloadExceptionMessage(null));
+    }
+
+    @Test
+    public void testGenerateInvalidPayloadExceptionMessageWithInvalidStartingSegment() throws Exception {
+        byte[] invalidStartingSegment = "MSA|AA|00001|\r".getBytes();
+        byte[] basePayload = TEST_MESSAGE.getBytes();
+
+        ByteArrayOutputStream payloadStream = new ByteArrayOutputStream(invalidStartingSegment.length + basePayload.length);
+        payloadStream.write(invalidStartingSegment);
+        payloadStream.write(basePayload.length);
+
+        assertEquals("The first segment of the HL7 payload {MSA} is not an MSH segment", Hl7Util.generateInvalidPayloadExceptionMessage(payloadStream.toByteArray()));
+    }
+
+    @Test
+    public void testGenerateInvalidPayloadExceptionMessageWithEmptyPayload() throws Exception {
+        byte[] payload = new byte[0];
+
+        assertEquals("HL7 payload is empty", Hl7Util.generateInvalidPayloadExceptionMessage(payload));
+        assertEquals("HL7 payload is empty", Hl7Util.generateInvalidPayloadExceptionMessage(payload, payload.length));
+    }
+
+    @Test
+    public void testGenerateInvalidPayloadExceptionMessageWithEmbeddedStartOfBlock() throws Exception {
+        byte[] basePayload = TEST_MESSAGE.getBytes();
+
+        ByteArrayOutputStream payloadStream = new ByteArrayOutputStream(basePayload.length + 1);
+
+        int embeddedStartOfBlockIndex = basePayload.length / 2;
+        payloadStream.write(basePayload, 0, embeddedStartOfBlockIndex);
+        payloadStream.write(START_OF_BLOCK);
+        payloadStream.write(basePayload, embeddedStartOfBlockIndex, basePayload.length - embeddedStartOfBlockIndex);
+
+        String expected = "HL7 payload contains an embedded START_OF_BLOCK {0xb, ASCII <VT>} at index " + embeddedStartOfBlockIndex;
+
+        assertEquals(expected, Hl7Util.generateInvalidPayloadExceptionMessage(payloadStream.toByteArray()));
+    }
+
+    @Test
+    public void testGenerateInvalidPayloadExceptionMessageWithEmbeddedEndOfBlock() throws Exception {
+        byte[] basePayload = TEST_MESSAGE.getBytes();
+
+        ByteArrayOutputStream payloadStream = new ByteArrayOutputStream(basePayload.length + 1);
+
+        int embeddedEndOfBlockIndex = basePayload.length / 2;
+        payloadStream.write(basePayload, 0, embeddedEndOfBlockIndex);
+        payloadStream.write(END_OF_BLOCK);
+        payloadStream.write(basePayload, embeddedEndOfBlockIndex, basePayload.length - embeddedEndOfBlockIndex);
+
+        String expected = "HL7 payload contains an embedded END_OF_BLOCK {0x1c, ASCII <FS>} at index " + embeddedEndOfBlockIndex;
+
+        assertEquals(expected, Hl7Util.generateInvalidPayloadExceptionMessage(payloadStream.toByteArray()));
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketAcknowledgementWriterTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketAcknowledgementWriterTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketAcknowledgementWriterTest.java
new file mode 100644
index 0000000..41fa6e5
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketAcknowledgementWriterTest.java
@@ -0,0 +1,125 @@
+/**
+ * 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.impl;
+
+import org.apache.camel.component.mllp.MllpAcknowledgementDeliveryException;
+import org.apache.camel.test.util.PayloadBuilder;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class MllpBufferedSocketAcknowledgementWriterTest extends MllpSocketWriterTestSupport {
+    MllpSocketWriter mllpSocketWriter;
+
+    @Before
+    public void setUp() throws Exception {
+        mllpSocketWriter = new MllpBufferedSocketWriter(fakeSocket, true);
+    }
+
+    @Test
+    public void testWriteAcknowledgement() throws Exception {
+        byte[] expected = PayloadBuilder.build(START_OF_BLOCK, TEST_ACKNOWLEDGEMENT, END_OF_BLOCK, END_OF_DATA);
+
+        mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), TEST_ACKNOWLEDGEMENT.getBytes());
+
+        assertArrayEquals(expected, fakeSocket.payload());
+    }
+
+    @Test
+    public void testWriteNullAcknowledgement() throws Exception {
+        byte[] acknowledgement = null;
+
+        byte[] expected = PayloadBuilder.build(START_OF_BLOCK, END_OF_BLOCK, END_OF_DATA);
+
+        mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), acknowledgement);
+
+        assertArrayEquals(expected, fakeSocket.payload());
+    }
+
+    @Test
+    public void testWriteEmptyAcknowledgement() throws Exception {
+        byte[] acknowledgement = new byte[0];
+
+        byte[] expected = PayloadBuilder.build(START_OF_BLOCK, END_OF_BLOCK, END_OF_DATA);
+
+        mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), acknowledgement);
+
+        assertArrayEquals(expected, fakeSocket.payload());
+    }
+
+    @Test(expected = MllpAcknowledgementDeliveryException.class)
+    public void testGetOutputStreamFailure() throws Exception {
+        fakeSocket.fakeSocketOutputStream = null;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), TEST_ACKNOWLEDGEMENT.getBytes());
+        } catch (MllpAcknowledgementDeliveryException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpAcknowledgementDeliveryException.class)
+    public void testWriteToUnconnectedSocket() throws Exception {
+        fakeSocket.connected = false;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), TEST_ACKNOWLEDGEMENT.getBytes());
+        } catch (MllpAcknowledgementDeliveryException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpAcknowledgementDeliveryException.class)
+    public void testWriteToClosedSocket() throws Exception {
+        fakeSocket.closed = true;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), TEST_ACKNOWLEDGEMENT.getBytes());
+        } catch (MllpAcknowledgementDeliveryException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpAcknowledgementDeliveryException.class)
+    public void testWriteAcknowledgementFailure() throws Exception {
+        fakeSocket.fakeSocketOutputStream.failOnWriteArray = true;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), TEST_ACKNOWLEDGEMENT.getBytes());
+        } catch (MllpAcknowledgementDeliveryException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    private void verifyException(MllpAcknowledgementDeliveryException expectedEx) throws Exception {
+        assertNotNull(expectedEx.getMessage());
+        assertArrayEquals(TEST_MESSAGE.getBytes(), expectedEx.getHl7Message());
+        assertArrayEquals(TEST_ACKNOWLEDGEMENT.getBytes(), expectedEx.getHl7Acknowledgement());
+        assertArrayEquals(TEST_ACKNOWLEDGEMENT.getBytes(), expectedEx.getMllpPayload());
+    }
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketMessageWriterTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketMessageWriterTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketMessageWriterTest.java
new file mode 100644
index 0000000..1f2c7bf
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketMessageWriterTest.java
@@ -0,0 +1,126 @@
+/**
+ * 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.impl;
+
+import org.apache.camel.component.mllp.MllpWriteException;
+import org.apache.camel.test.util.PayloadBuilder;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class MllpBufferedSocketMessageWriterTest extends MllpSocketWriterTestSupport {
+    MllpSocketWriter mllpSocketWriter;
+
+    @Before
+    public void setUp() throws Exception {
+        mllpSocketWriter = new MllpBufferedSocketWriter(fakeSocket, false);
+    }
+
+    @Test
+    public void testWriteMessage() throws Exception {
+        byte[] expected = PayloadBuilder.build(START_OF_BLOCK, TEST_MESSAGE, END_OF_BLOCK, END_OF_DATA);
+
+        mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), null);
+
+        assertArrayEquals(expected, fakeSocket.payload());
+    }
+
+    @Test
+    public void testWriteNullMessage() throws Exception {
+        byte[] message = null;
+
+        byte[] expected = PayloadBuilder.build(START_OF_BLOCK, END_OF_BLOCK, END_OF_DATA);
+
+        mllpSocketWriter.writeEnvelopedPayload(message, null);
+
+        assertArrayEquals(expected, fakeSocket.payload());
+    }
+
+    @Test
+    public void testWriteEmptyMessage() throws Exception {
+        byte[] message = new byte[0];
+
+        byte[] expected = PayloadBuilder.build(START_OF_BLOCK, END_OF_BLOCK, END_OF_DATA);
+
+        mllpSocketWriter.writeEnvelopedPayload(message, null);
+
+        assertArrayEquals(expected, fakeSocket.payload());
+    }
+
+    @Test(expected = MllpWriteException.class)
+    public void testGetOutputStreamFailure() throws Exception {
+        fakeSocket.fakeSocketOutputStream = null;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), null);
+        } catch (MllpWriteException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpWriteException.class)
+    public void testWriteToUnconnectedSocket() throws Exception {
+        fakeSocket.connected = false;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), null);
+        } catch (MllpWriteException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpWriteException.class)
+    public void testWriteToClosedSocket() throws Exception {
+        fakeSocket.closed = true;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), null);
+        } catch (MllpWriteException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpWriteException.class)
+    public void testWriteFailure() throws Exception {
+        fakeSocket.fakeSocketOutputStream.failOnWriteArray = true;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), null);
+        } catch (MllpWriteException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+
+    private void verifyException(MllpWriteException expectedEx) throws Exception {
+        assertNotNull(expectedEx.getMessage());
+        assertArrayEquals(TEST_MESSAGE.getBytes(), expectedEx.getHl7Message());
+        assertNull(expectedEx.getHl7Acknowledgement());
+        assertArrayEquals(TEST_MESSAGE.getBytes(), expectedEx.getMllpPayload());
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketAcknowledgementReaderTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketAcknowledgementReaderTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketAcknowledgementReaderTest.java
new file mode 100644
index 0000000..fa3b687
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketAcknowledgementReaderTest.java
@@ -0,0 +1,533 @@
+/**
+ * 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.impl;
+
+
+import java.io.IOException;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+
+import org.apache.camel.component.mllp.MllpAcknowledgementException;
+import org.apache.camel.component.mllp.MllpAcknowledgementTimeoutException;
+import org.apache.camel.component.mllp.MllpReceiveAcknowledgementException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.SEGMENT_DELIMITER;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+
+public class MllpSocketAcknowledgementReaderTest extends MllpSocketReaderTestSupport {
+    MllpSocketReader mllpSocketReader;
+
+    @Before
+    public void setUp() throws Exception {
+        mllpSocketReader = new MllpSocketReader(fakeSocket, 5000, 1000, true);
+    }
+
+    @Test
+    public void testReadMessage() throws Exception {
+        byte[] expected = TEST_ACKNOWLEDGEMENT.getBytes();
+
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, expected, END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testReadMessageWithSeparateEnvelopingAndMessagePackets() throws Exception {
+        byte[] expected = TEST_MESSAGE.getBytes();
+
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, TEST_MESSAGE.getBytes(), END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testReadMessageWithMultipleMessagePackets() throws Exception {
+        byte[] expected = TEST_MESSAGE.getBytes();
+
+        fakeSocket.fakeSocketInputStream
+                .addPacket(START_PACKET)
+                .addPackets(TEST_MESSAGE, SEGMENT_DELIMITER)
+                .addPacket(END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testReadEmptyMessage() throws Exception {
+        byte[] expected = new byte[0];
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testReadEmptyMessageWithSeparateEnvelopingPackets() throws Exception {
+        byte[] expected = new byte[0];
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test()
+    public void testGetInputStreamFailure() throws Exception {
+        fakeSocket.fakeSocketInputStream = null;
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpReceiveAcknowledgementException.class);
+        } catch (MllpReceiveAcknowledgementException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause(), instanceOf(IOException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testEndOfStreamOnInitialRead() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPackets(EMPTY_PACKET, TEST_MESSAGE);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpReceiveAcknowledgementException.class);
+        } catch (MllpReceiveAcknowledgementException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNull(expectedEx.getCause());
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testTimeoutOnInitialRead() throws Exception {
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpAcknowledgementTimeoutException.class);
+        } catch (MllpAcknowledgementTimeoutException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketTimeoutException.class));
+            assertSocketOpen();
+        }
+    }
+
+    @Test
+    public void testTimeoutOnInitialReadWithStartOfBlock() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPacket(START_OF_BLOCK);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpAcknowledgementTimeoutException.class);
+        } catch (MllpAcknowledgementTimeoutException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketTimeoutException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testSocketExceptionOnInitialRead() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPacket(EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpReceiveAcknowledgementException.class);
+        } catch (MllpReceiveAcknowledgementException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testIOExceptionOnInitialRead() throws Exception {
+        fakeSocket.fakeSocketInputStream.useSocketExceptionOnNullPacket = false;
+        fakeSocket.fakeSocketInputStream.addPacket(EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpReceiveAcknowledgementException.class);
+        } catch (MllpReceiveAcknowledgementException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(IOException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testEndOfStreamOnFirstAdditionalRead() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, EMPTY_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpReceiveAcknowledgementException.class);
+        } catch (MllpReceiveAcknowledgementException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNull(expectedEx.getCause());
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testEndOfStreamOnFirstAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, TEST_ACKNOWLEDGEMENT.getBytes()).addPacket(EMPTY_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpReceiveAcknowledgementException.class);
+        } catch (MllpReceiveAcknowledgementException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNull(expectedEx.getCause());
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testTimeoutOnFirstAdditionalRead() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpAcknowledgementTimeoutException.class);
+        } catch (MllpAcknowledgementTimeoutException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketTimeoutException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testTimeoutOnFirstAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, TEST_ACKNOWLEDGEMENT.getBytes());
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpAcknowledgementTimeoutException.class);
+        } catch (MllpAcknowledgementTimeoutException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketTimeoutException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testSocketExceptionOnFirstAdditionalRead() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpReceiveAcknowledgementException.class);
+        } catch (MllpReceiveAcknowledgementException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testSocketExceptionOnFirstAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, TEST_ACKNOWLEDGEMENT.getBytes()).addPacket(EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpReceiveAcknowledgementException.class);
+        } catch (MllpReceiveAcknowledgementException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testIOExceptionOnFirstAdditionalRead() throws Exception {
+        fakeSocket.fakeSocketInputStream.useSocketExceptionOnNullPacket = false;
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpReceiveAcknowledgementException.class);
+        } catch (MllpReceiveAcknowledgementException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(IOException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testIOExceptionOnFirstAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.useSocketExceptionOnNullPacket = false;
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, TEST_ACKNOWLEDGEMENT.getBytes()).addPacket(EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpReceiveAcknowledgementException.class);
+        } catch (MllpReceiveAcknowledgementException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(IOException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testEndOfStreamOnSecondAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, TEST_ACKNOWLEDGEMENT.getBytes(), EMPTY_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpReceiveAcknowledgementException.class);
+        } catch (MllpReceiveAcknowledgementException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNull(expectedEx.getCause());
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testTimeoutOnSecondAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, TEST_ACKNOWLEDGEMENT.getBytes());
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpAcknowledgementTimeoutException.class);
+        } catch (MllpAcknowledgementTimeoutException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketTimeoutException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testSocketExceptionOnSecondAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, TEST_ACKNOWLEDGEMENT.getBytes(), EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpReceiveAcknowledgementException.class);
+        } catch (MllpReceiveAcknowledgementException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testIOExceptionOnSecondAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.useSocketExceptionOnNullPacket = false;
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, TEST_ACKNOWLEDGEMENT.getBytes(), EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+            expectedExceptionFailure(MllpReceiveAcknowledgementException.class);
+        } catch (MllpReceiveAcknowledgementException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(IOException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testLeadingOutOfBandBytes() throws Exception {
+        byte[] expected = TEST_ACKNOWLEDGEMENT.getBytes();
+
+        fakeSocket.fakeSocketInputStream.addPacket("Junk".getBytes(), START_PACKET, expected, END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+        assertArrayEquals(expected, actual);
+    }
+
+    @Test
+    public void testLeadingOutOfBandBytesWithEmptyMessage() throws Exception {
+        byte[] expected = new byte[0];
+        fakeSocket.fakeSocketInputStream.addPacket("Junk".getBytes(), START_PACKET, END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testLeadingOutOfBandBytesWithEmptyMessageWithSeparateEnvelopingPackets() throws Exception {
+        byte[] expected = new byte[0];
+        fakeSocket.fakeSocketInputStream.addPackets("Junk".getBytes(), START_PACKET, END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testLeadingOutOfBandBytesSeparateEnvelopingAndMessagePackets() throws Exception {
+        byte[] expected = TEST_ACKNOWLEDGEMENT.getBytes();
+
+        fakeSocket.fakeSocketInputStream.addPackets("Junk".getBytes(), START_PACKET, expected, END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testLeadingOutOfBandBytesWithMultipleMessagePackets() throws Exception {
+        byte[] expected = TEST_ACKNOWLEDGEMENT.getBytes();
+
+        fakeSocket.fakeSocketInputStream
+                .addPacket("Junk")
+                .addPacket(START_PACKET)
+                .addPackets(TEST_ACKNOWLEDGEMENT, SEGMENT_DELIMITER)
+                .addPacket(END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testTrailingOutOfBandBytes() throws Exception {
+        byte[] expected = TEST_ACKNOWLEDGEMENT.getBytes();
+
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, expected, END_PACKET, "Junk".getBytes());
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+        assertArrayEquals(expected, actual);
+    }
+
+    @Test
+    public void testTrailingOutOfBandBytesWithEmptyMessage() throws Exception {
+        byte[] expected = new byte[0];
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, END_PACKET, "Junk".getBytes());
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testTrailingOutOfBandBytesWithEmptyMessageWithSeparateEnvelopingPackets() throws Exception {
+        byte[] expected = new byte[0];
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, END_PACKET, "Junk".getBytes());
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testTrailingOutOfBandBytesSeparateEnvelopingAndMessagePackets() throws Exception {
+        byte[] expected = TEST_ACKNOWLEDGEMENT.getBytes();
+
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, expected, END_PACKET, "Junk".getBytes());
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testTrailingOutOfBandBytesWithMultipleMessagePackets() throws Exception {
+        byte[] expected = TEST_ACKNOWLEDGEMENT.getBytes();
+
+        fakeSocket.fakeSocketInputStream
+                .addPacket(START_PACKET)
+                .addPackets(TEST_ACKNOWLEDGEMENT, SEGMENT_DELIMITER)
+                .addPacket(END_PACKET)
+                .addPacket("Junk");
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload(TEST_MESSAGE.getBytes());
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    private void assertEmptyExpectedException(MllpAcknowledgementException expectedEx) {
+        assertNotNull(expectedEx);
+        assertNotNull(expectedEx.getMessage());
+        assertArrayEquals(TEST_MESSAGE.getBytes(), expectedEx.getHl7Message());
+        assertNull(expectedEx.getHl7Acknowledgement());
+        assertArrayEquals(TEST_MESSAGE.getBytes(), expectedEx.getMllpPayload());
+    }
+
+    private void assertExpectedException(MllpAcknowledgementException expectedEx) {
+        assertNotNull(expectedEx);
+        assertNotNull(expectedEx.getMessage());
+        assertArrayEquals(TEST_MESSAGE.getBytes(), expectedEx.getHl7Message());
+        assertArrayEquals(TEST_ACKNOWLEDGEMENT.getBytes(), expectedEx.getHl7Acknowledgement());
+        assertArrayEquals(TEST_ACKNOWLEDGEMENT.getBytes(), expectedEx.getMllpPayload());
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketAcknowledgementWriterTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketAcknowledgementWriterTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketAcknowledgementWriterTest.java
new file mode 100644
index 0000000..9c218a7
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketAcknowledgementWriterTest.java
@@ -0,0 +1,150 @@
+/**
+ * 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.impl;
+
+import org.apache.camel.component.mllp.MllpAcknowledgementDeliveryException;
+import org.apache.camel.test.util.PayloadBuilder;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+import static org.apache.camel.component.mllp.impl.MllpSocketWriter.PAYLOAD_TERMINATOR;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class MllpSocketAcknowledgementWriterTest extends MllpSocketWriterTestSupport {
+    MllpSocketWriter mllpSocketWriter;
+
+    @Before
+    public void setUp() throws Exception {
+        mllpSocketWriter = new MllpSocketWriter(fakeSocket, true);
+    }
+
+    @Test
+    public void testWriteAcknowledgement() throws Exception {
+        byte[] expected = PayloadBuilder.build(START_OF_BLOCK, TEST_ACKNOWLEDGEMENT, END_OF_BLOCK, END_OF_DATA);
+
+        mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), TEST_ACKNOWLEDGEMENT.getBytes());
+
+        assertArrayEquals(expected, fakeSocket.payload());
+    }
+
+    @Test
+    public void testWriteNullAcknowledgement() throws Exception {
+        byte[] acknowledgement = null;
+
+        byte[] expected = PayloadBuilder.build(START_OF_BLOCK, END_OF_BLOCK, END_OF_DATA);
+
+        mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), acknowledgement);
+
+        assertArrayEquals(expected, fakeSocket.payload());
+    }
+
+    @Test
+    public void testWriteEmptyAcknowledgement() throws Exception {
+        byte[] acknowledgement = new byte[0];
+
+        byte[] expected = PayloadBuilder.build(START_OF_BLOCK, END_OF_BLOCK, END_OF_DATA);
+
+        mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), acknowledgement);
+
+        assertArrayEquals(expected, fakeSocket.payload());
+    }
+
+    @Test(expected = MllpAcknowledgementDeliveryException.class)
+    public void testGetOutputStreamFailure() throws Exception {
+        fakeSocket.fakeSocketOutputStream = null;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), TEST_ACKNOWLEDGEMENT.getBytes());
+        } catch (MllpAcknowledgementDeliveryException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpAcknowledgementDeliveryException.class)
+    public void testWriteToUnconnectedSocket() throws Exception {
+        fakeSocket.connected = false;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), TEST_ACKNOWLEDGEMENT.getBytes());
+        } catch (MllpAcknowledgementDeliveryException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpAcknowledgementDeliveryException.class)
+    public void testWriteToClosedSocket() throws Exception {
+        fakeSocket.closed = true;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), TEST_ACKNOWLEDGEMENT.getBytes());
+        } catch (MllpAcknowledgementDeliveryException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpAcknowledgementDeliveryException.class)
+    public void testWriteStartOfBlockFailure() throws Exception {
+        fakeSocket.fakeSocketOutputStream.writeFailOn = new Byte((byte) START_OF_BLOCK);
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), TEST_ACKNOWLEDGEMENT.getBytes());
+        } catch (MllpAcknowledgementDeliveryException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpAcknowledgementDeliveryException.class)
+    public void testWriteAcknowledgementFailure() throws Exception {
+        fakeSocket.fakeSocketOutputStream.writeArrayFailOn = TEST_ACKNOWLEDGEMENT.getBytes();
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), TEST_ACKNOWLEDGEMENT.getBytes());
+        } catch (MllpAcknowledgementDeliveryException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpAcknowledgementDeliveryException.class)
+    public void testWriteEndOfMessageFailure() throws Exception {
+        fakeSocket.fakeSocketOutputStream.writeArrayFailOn = PAYLOAD_TERMINATOR;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), TEST_ACKNOWLEDGEMENT.getBytes());
+        } catch (MllpAcknowledgementDeliveryException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    private void verifyException(MllpAcknowledgementDeliveryException expectedEx) throws Exception {
+        assertNotNull(expectedEx.getMessage());
+        assertArrayEquals(TEST_MESSAGE.getBytes(), expectedEx.getHl7Message());
+        assertArrayEquals(TEST_ACKNOWLEDGEMENT.getBytes(), expectedEx.getHl7Acknowledgement());
+        assertArrayEquals(TEST_ACKNOWLEDGEMENT.getBytes(), expectedEx.getMllpPayload());
+    }
+
+
+}
\ No newline at end of file


[5/8] camel git commit: CAMEL-10511: Updated MllpTcpClientProducer and MllpTcpServerConsumer to consume all available data on socket

Posted by da...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/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 05b8cbe..0ec8564 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
@@ -15,7 +15,6 @@
  * limitations under the License.
  */
 package org.apache.camel.component.mllp;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.BindException;
@@ -29,18 +28,31 @@ import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 
+
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
 import org.apache.camel.Message;
 import org.apache.camel.Processor;
-import org.apache.camel.component.mllp.impl.AcknowledgmentSynchronizationAdapter;
-import org.apache.camel.component.mllp.impl.MllpUtil;
+import org.apache.camel.component.mllp.impl.Hl7Util;
+import org.apache.camel.component.mllp.impl.MllpBufferedSocketWriter;
+import org.apache.camel.component.mllp.impl.MllpSocketReader;
+import org.apache.camel.component.mllp.impl.MllpSocketUtil;
+import org.apache.camel.component.mllp.impl.MllpSocketWriter;
+import org.apache.camel.converter.IOConverter;
 import org.apache.camel.impl.DefaultConsumer;
+import org.apache.camel.processor.mllp.Hl7AcknowledgementGenerationException;
 import org.apache.camel.processor.mllp.Hl7AcknowledgementGenerator;
 import org.apache.camel.util.IOHelper;
+import org.slf4j.MDC;
 
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_ACKNOWLEDGEMENT;
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_ACKNOWLEDGEMENT_EXCEPTION;
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING;
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE;
 import static org.apache.camel.component.mllp.MllpConstants.MLLP_AUTO_ACKNOWLEDGE;
 import static org.apache.camel.component.mllp.MllpConstants.MLLP_CHARSET;
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_CLOSE_CONNECTION_AFTER_SEND;
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_CLOSE_CONNECTION_BEFORE_SEND;
 import static org.apache.camel.component.mllp.MllpConstants.MLLP_EVENT_TYPE;
 import static org.apache.camel.component.mllp.MllpConstants.MLLP_LOCAL_ADDRESS;
 import static org.apache.camel.component.mllp.MllpConstants.MLLP_MESSAGE_CONTROL;
@@ -49,6 +61,8 @@ import static org.apache.camel.component.mllp.MllpConstants.MLLP_PROCESSING_ID;
 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_REMOTE_ADDRESS;
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_RESET_CONNECTION_AFTER_SEND;
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_RESET_CONNECTION_BEFORE_SEND;
 import static org.apache.camel.component.mllp.MllpConstants.MLLP_SECURITY;
 import static org.apache.camel.component.mllp.MllpConstants.MLLP_SENDING_APPLICATION;
 import static org.apache.camel.component.mllp.MllpConstants.MLLP_SENDING_FACILITY;
@@ -56,16 +70,19 @@ import static org.apache.camel.component.mllp.MllpConstants.MLLP_TIMESTAMP;
 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.component.mllp.MllpEndpoint.SEGMENT_DELIMITER;
-import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 
 /**
  * The MLLP consumer.
  */
 public class MllpTcpServerConsumer extends DefaultConsumer {
+    public static final int SOCKET_STARTUP_TEST_WAIT = 100;
+    public static final int SOCKET_STARTUP_TEST_READ_TIMEOUT = 250;
     ServerSocketThread serverSocketThread;
 
     List<ClientSocketThread> clientThreads = new LinkedList<>();
 
+    Hl7AcknowledgementGenerator acknowledgementGenerator = new Hl7AcknowledgementGenerator();
+
     private final MllpEndpoint endpoint;
 
     public MllpTcpServerConsumer(MllpEndpoint endpoint, Processor processor) {
@@ -191,11 +208,10 @@ public class MllpTcpServerConsumer extends DefaultConsumer {
          * short.
          */
         public void run() {
-            log.debug("Starting acceptor thread");
+            MDC.put("camel.contextId", endpoint.getCamelContext().getName());
 
             try {
                 while (!isInterrupted()  &&  null != serverSocket && serverSocket.isBound()  &&  !serverSocket.isClosed()) {
-                    // TODO: Need to check maxConnections and figure out what to do when exceeded
                     Socket socket = null;
                     try {
                         socket = serverSocket.accept();
@@ -229,16 +245,15 @@ public class MllpTcpServerConsumer extends DefaultConsumer {
                     /* Wait a bit and then check and see if the socket is really there - it could be a load balancer
                      pinging the port
                       */
-                        Thread.sleep(100);
                         if (socket.isConnected() && !socket.isClosed()) {
-                            log.debug("Socket appears to be there - check for available data");
+                            log.debug("Socket appears to be there - checking for available data in {} milliseconds", SOCKET_STARTUP_TEST_WAIT);
+                            Thread.sleep(SOCKET_STARTUP_TEST_WAIT);
+
                             InputStream inputStream;
                             try {
                                 inputStream = socket.getInputStream();
                             } catch (IOException ioEx) {
-                                // Bad Socket -
-                                log.warn("Failed to retrieve the InputStream for socket after the initial connection was accepted");
-                                MllpUtil.resetConnection(socket);
+                                MllpSocketUtil.reset(socket, log, "Failed to retrieve the InputStream for socket after the initial connection was accepted");
                                 continue;
                             }
 
@@ -251,13 +266,12 @@ public class MllpTcpServerConsumer extends DefaultConsumer {
                             }
 
                             // The easy check failed - so trigger a blocking read
-                            socket.setSoTimeout(100);
+                            MllpSocketUtil.setSoTimeout(socket, SOCKET_STARTUP_TEST_READ_TIMEOUT, log, "Preparing to check for available data on component startup");
                             try {
                                 int tmpByte = inputStream.read();
-                                socket.setSoTimeout(endpoint.receiveTimeout);
                                 if (-1 == tmpByte) {
-                                    log.debug("Socket.read() returned END_OF_STREAM - resetting connection");
-                                    MllpUtil.resetConnection(socket);
+                                    log.debug("Check for available data failed - Socket.read() returned END_OF_STREAM");
+                                    MllpSocketUtil.close(socket, null, null);
                                 } else {
                                     ClientSocketThread clientThread = new ClientSocketThread(socket, tmpByte);
                                     clientThreads.add(clientThread);
@@ -265,10 +279,20 @@ public class MllpTcpServerConsumer extends DefaultConsumer {
                                 }
                             } catch (SocketTimeoutException timeoutEx) {
                                 // No data, but the socket is there
-                                log.debug("No Data - but the socket is there.  Starting ClientSocketThread");
+                                String logMessageFormat =
+                                    "Check for available data failed - Socket.read() timed-out after {} milliseconds."
+                                        + "  No Data - but the socket is there.  Starting ClientSocketThread";
+                                log.debug(logMessageFormat, SOCKET_STARTUP_TEST_READ_TIMEOUT);
                                 ClientSocketThread clientThread = new ClientSocketThread(socket, null);
                                 clientThreads.add(clientThread);
                                 clientThread.start();
+                            } catch (IOException ioEx) {
+                                log.debug("Ignoring IOException encountered when attempting to read a byte - connection was reset");
+                                try {
+                                    socket.close();
+                                } catch (IOException closeEx) {
+                                    log.debug("Ignoring IOException encountered when attempting to close the connection after the connection reset was detected", closeEx);
+                                }
                             }
                         }
                     } catch (SocketTimeoutException timeoutEx) {
@@ -320,10 +344,12 @@ public class MllpTcpServerConsumer extends DefaultConsumer {
     }
 
     /**
-     * Nested Class read the Socket
+     * Nested Class reads the Socket
      */
     class ClientSocketThread extends Thread {
-        Socket clientSocket;
+        final Socket clientSocket;
+        final MllpSocketReader mllpSocketReader;
+        final MllpSocketWriter mllpSocketWriter;
 
         Integer initialByte;
 
@@ -343,8 +369,14 @@ public class MllpTcpServerConsumer extends DefaultConsumer {
             this.clientSocket.setSoLinger(false, -1);
 
             // Initial Read Timeout
-            this.clientSocket.setSoTimeout(endpoint.receiveTimeout);
+            MllpSocketUtil.setSoTimeout(clientSocket, endpoint.receiveTimeout, log, "Constructing ClientSocketThread");
 
+            mllpSocketReader = new MllpSocketReader(this.clientSocket, endpoint.receiveTimeout, endpoint.readTimeout, false);
+            if (endpoint.bufferWrites) {
+                mllpSocketWriter = new MllpBufferedSocketWriter(this.clientSocket, true);
+            } else {
+                mllpSocketWriter = new MllpSocketWriter(this.clientSocket, true);
+            }
         }
 
         /**
@@ -375,78 +407,238 @@ public class MllpTcpServerConsumer extends DefaultConsumer {
         @Override
         public void run() {
             int receiveTimeoutCounter = 0;
+            MDC.put("camel.contextId", endpoint.getCamelContext().getName());
 
             while (!isInterrupted()  &&  null != clientSocket  &&  clientSocket.isConnected()  &&  !clientSocket.isClosed()) {
                 byte[] hl7MessageBytes = null;
-                // Send the message on for processing and wait for the response
-                log.debug("Reading data ....");
+
+                log.debug("Checking for data ....");
                 try {
-                    if (null != initialByte && START_OF_BLOCK == initialByte) {
-                        hl7MessageBytes = MllpUtil.closeFrame(clientSocket, endpoint.receiveTimeout, endpoint.readTimeout);
-                    } else {
-                        try {
-                            if (!MllpUtil.openFrame(clientSocket, endpoint.receiveTimeout, endpoint.readTimeout)) {
-                                receiveTimeoutCounter = 0;
-                                continue;
-                            } else {
-                                receiveTimeoutCounter = 0;
-                            }
-                        } catch (SocketTimeoutException timeoutEx) {
-                            // When thrown by openFrame, it indicates that no data was available - but no error
-                            if (endpoint.maxReceiveTimeouts > 0 && ++receiveTimeoutCounter >= endpoint.maxReceiveTimeouts) {
-                                // TODO:  Enhance logging??
-                                log.warn("Idle Client - resetting connection");
-                                MllpUtil.resetConnection(clientSocket);
-                            }
-                            continue;
+                    hl7MessageBytes = mllpSocketReader.readEnvelopedPayload(initialByte);
+                    if (hl7MessageBytes == null) {
+                        // No data received - check for max timeouts
+                        if (endpoint.maxReceiveTimeouts > 0 && ++receiveTimeoutCounter >= endpoint.maxReceiveTimeouts) {
+                            String reasonMessage = String.format("Idle Client after %d receive timeouts [%d-milliseconds] - resetting connection", receiveTimeoutCounter, endpoint.receiveTimeout);
+                            MllpSocketUtil.reset(clientSocket, log, reasonMessage);
                         }
-                        hl7MessageBytes = MllpUtil.closeFrame(clientSocket, endpoint.receiveTimeout, endpoint.readTimeout);
+                        continue;
                     }
                 } catch (MllpException mllpEx) {
                     Exchange exchange = endpoint.createExchange(ExchangePattern.InOut);
                     exchange.setException(mllpEx);
-                    return;
+                    log.warn("Exception encountered reading payload - sending exception to route", mllpEx);
+                    try {
+                        getProcessor().process(exchange);
+                    } catch (Exception e) {
+                        log.error("Exception encountered processing exchange with exception encounter reading payload", e);
+                    }
+                    continue;
                 } finally {
                     initialByte = null;
                 }
 
-                if (null == hl7MessageBytes) {
+                // Send the message on for processing and wait for the response
+                log.debug("Populating the exchange with received message");
+                Exchange exchange = endpoint.createExchange(ExchangePattern.InOut);
+                try {
+                    createUoW(exchange);
+                    Message message = exchange.getIn();
+                    message.setBody(hl7MessageBytes, byte[].class);
+
+                    message.setHeader(MLLP_LOCAL_ADDRESS, clientSocket.getLocalAddress().toString());
+                    message.setHeader(MLLP_REMOTE_ADDRESS, clientSocket.getRemoteSocketAddress());
+                    message.setHeader(MLLP_AUTO_ACKNOWLEDGE, endpoint.autoAck);
+
+                    if (endpoint.validatePayload) {
+                        String exceptionMessage = Hl7Util.generateInvalidPayloadExceptionMessage(hl7MessageBytes);
+                        if (exceptionMessage != null) {
+                            exchange.setException(new MllpInvalidMessageException(exceptionMessage, hl7MessageBytes));
+                        }
+                    }
+                    populateHl7DataHeaders(exchange, message, hl7MessageBytes);
+
+                    log.debug("Calling processor");
+                    try {
+                        getProcessor().process(exchange);
+                        sendAcknowledgement(hl7MessageBytes, exchange);
+                    } catch (RuntimeException runtimeEx) {
+                        throw runtimeEx;
+                    } catch (Exception ex) {
+                        log.error("Unexpected exception processing exchange", ex);
+                    }
+                } catch (Exception uowEx) {
+                    // TODO:  Handle this correctly
+                    exchange.setException(uowEx);
+                    log.warn("Exception encountered creating Unit of Work - sending exception to route", uowEx);
+                    try {
+                        getProcessor().process(exchange);
+                    } catch (Exception e) {
+                        log.error("Exception encountered processing exchange with exception encountered createing Unit of Work", e);
+                    }
                     continue;
+                } finally {
+                    if (exchange != null) {
+                        doneUoW(exchange);
+                    }
                 }
 
-                log.debug("Populating the exchange with received message");
-                Exchange exchange = endpoint.createExchange(ExchangePattern.InOut);
-                Message message = exchange.getIn();
-                message.setBody(hl7MessageBytes, byte[].class);
 
-                message.setHeader(MLLP_LOCAL_ADDRESS, clientSocket.getLocalAddress().toString());
-                message.setHeader(MLLP_REMOTE_ADDRESS, clientSocket.getRemoteSocketAddress());
-                message.setHeader(MLLP_AUTO_ACKNOWLEDGE, endpoint.autoAck);
+            }
 
-                populateHl7DataHeaders(exchange, message, hl7MessageBytes);
+            log.debug("ClientSocketThread exiting");
+        }
 
-                exchange.addOnCompletion(new AcknowledgmentSynchronizationAdapter(clientSocket, hl7MessageBytes));
+        private void sendAcknowledgement(byte[] originalHl7MessageBytes, Exchange exchange) {
+            log.info("sendAcknowledgement");
+
+            // Check BEFORE_SEND Properties
+            if (exchange.getProperty(MLLP_RESET_CONNECTION_BEFORE_SEND, boolean.class)) {
+                String reasonMessage = String.format("Exchange property %s is %b", MLLP_RESET_CONNECTION_BEFORE_SEND,  exchange.getProperty(MLLP_RESET_CONNECTION_BEFORE_SEND, boolean.class));
+                MllpSocketUtil.reset(clientSocket, log, reasonMessage);
+                return;
+            } else if (exchange.getProperty(MLLP_CLOSE_CONNECTION_BEFORE_SEND, boolean.class)) {
+                String reasonMessage = String.format("Exchange property %s is %b", MLLP_CLOSE_CONNECTION_BEFORE_SEND,  exchange.getProperty(MLLP_CLOSE_CONNECTION_BEFORE_SEND, boolean.class));
+                MllpSocketUtil.close(clientSocket, log, reasonMessage);
+                return;
+            }
+
+            // Find the acknowledgement body
+            // TODO:  Enhance this to say whether or not the acknowledgment is missing or just of an un-convertible type
+            byte[] acknowledgementMessageBytes = exchange.getProperty(MLLP_ACKNOWLEDGEMENT, byte[].class);
+            String acknowledgementMessageType = null;
+            if (null == acknowledgementMessageBytes) {
+                boolean autoAck = exchange.getProperty(MLLP_AUTO_ACKNOWLEDGE, true, boolean.class);
+                if (!autoAck) {
+                    exchange.setException(new MllpInvalidAcknowledgementException("Automatic Acknowledgement is disabled and the "
+                            + MLLP_ACKNOWLEDGEMENT + " exchange property is null or cannot be converted to byte[]", originalHl7MessageBytes, acknowledgementMessageBytes));
+                    return;
+                }
 
-                log.debug("Calling processor");
+                String acknowledgmentTypeProperty = exchange.getProperty(MLLP_ACKNOWLEDGEMENT_TYPE, String.class);
                 try {
-                    getProcessor().process(exchange);
-                } catch (RuntimeException runtimeEx) {
-                    throw runtimeEx;
-                } catch (Exception ex) {
-                    log.error("Unexpected exception processing exchange", ex);
-                    throw new RuntimeException("Unexpected exception processing exchange", ex);
+                    if (null == acknowledgmentTypeProperty) {
+                        if (null == exchange.getException()) {
+                            acknowledgementMessageType = "AA";
+                            acknowledgementMessageBytes = acknowledgementGenerator.generateApplicationAcceptAcknowledgementMessage(originalHl7MessageBytes);
+                        } else {
+                            acknowledgementMessageType = "AE";
+                            acknowledgementMessageBytes = acknowledgementGenerator.generateApplicationErrorAcknowledgementMessage(originalHl7MessageBytes);
+                        }
+                    } else {
+                        switch (acknowledgmentTypeProperty) {
+                        case "AA":
+                            acknowledgementMessageType = "AA";
+                            acknowledgementMessageBytes = acknowledgementGenerator.generateApplicationAcceptAcknowledgementMessage(originalHl7MessageBytes);
+                            break;
+                        case "AE":
+                            acknowledgementMessageType = "AE";
+                            acknowledgementMessageBytes = acknowledgementGenerator.generateApplicationErrorAcknowledgementMessage(originalHl7MessageBytes);
+                            break;
+                        case "AR":
+                            acknowledgementMessageType = "AR";
+                            acknowledgementMessageBytes = acknowledgementGenerator.generateApplicationRejectAcknowledgementMessage(originalHl7MessageBytes);
+                            break;
+                        default:
+                            exchange.setException(new Hl7AcknowledgementGenerationException("Unsupported acknowledgment type: " + acknowledgmentTypeProperty));
+                            return;
+                        }
+                    }
+                } catch (Hl7AcknowledgementGenerationException ackGenerationException) {
+                    exchange.setProperty(MLLP_ACKNOWLEDGEMENT_EXCEPTION, ackGenerationException);
+                    exchange.setException(ackGenerationException);
                 }
+            } else {
+                final byte bM = 77;
+                final byte bS = 83;
+                final byte bA = 65;
+                final byte bE = 69;
+                final byte bR = 82;
+
+                final byte fieldSeparator = originalHl7MessageBytes[3];
+                // Acknowledgment is specified in exchange property - determine the acknowledgement type
+                for (int i = 0; i < originalHl7MessageBytes.length; ++i) {
+                    if (SEGMENT_DELIMITER == i) {
+                        if (i + 7 < originalHl7MessageBytes.length // Make sure we don't run off the end of the message
+                                && bM == originalHl7MessageBytes[i + 1] && bS == originalHl7MessageBytes[i + 2]
+                                && bA == originalHl7MessageBytes[i + 3] && fieldSeparator == originalHl7MessageBytes[i + 4]) {
+                            if (fieldSeparator != originalHl7MessageBytes[i + 7]) {
+                                log.warn("MSA-1 is longer than 2-bytes - ignoring trailing bytes");
+                            }
+                            // Found MSA - pull acknowledgement bytes
+                            byte[] acknowledgmentTypeBytes = new byte[2];
+                            acknowledgmentTypeBytes[0] = originalHl7MessageBytes[i + 5];
+                            acknowledgmentTypeBytes[1] = originalHl7MessageBytes[i + 6];
+                            try {
+                                acknowledgementMessageType = IOConverter.toString(acknowledgmentTypeBytes, exchange);
+                            } catch (IOException ioEx) {
+                                throw new RuntimeException("Failed to convert acknowledgement message to string", ioEx);
+                            }
 
+                            // Verify it's a valid acknowledgement code
+                            if (bA != acknowledgmentTypeBytes[0]) {
+                                switch (acknowledgementMessageBytes[1]) {
+                                case bA:
+                                case bR:
+                                case bE:
+                                    break;
+                                default:
+                                    log.warn("Invalid acknowledgement type [" + acknowledgementMessageType + "] found in message - should be AA, AE or AR");
+                                }
+                            }
+
+                            // if the MLLP_ACKNOWLEDGEMENT_TYPE property is set on the exchange, make sure it matches
+                            String acknowledgementTypeProperty = exchange.getProperty(MLLP_ACKNOWLEDGEMENT_TYPE, String.class);
+                            if (null != acknowledgementTypeProperty && !acknowledgementTypeProperty.equals(acknowledgementMessageType)) {
+                                log.warn("Acknowledgement type found in message [" + acknowledgementMessageType + "] does not match "
+                                        + MLLP_ACKNOWLEDGEMENT_TYPE + " exchange property value [" + acknowledgementTypeProperty + "] - using value found in message");
+                            }
+                        }
+                    }
+                }
             }
 
-            log.debug("ClientSocketThread exiting");
+            Message message;
+            if (exchange.hasOut()) {
+                message = exchange.getOut();
+            } else {
+                message = exchange.getIn();
+            }
+            message.setHeader(MLLP_ACKNOWLEDGEMENT, acknowledgementMessageBytes);
+            // TODO:  Use the charset of the exchange
+            message.setHeader(MLLP_ACKNOWLEDGEMENT_STRING, new String(acknowledgementMessageBytes));
+            message.setHeader(MLLP_ACKNOWLEDGEMENT_TYPE, acknowledgementMessageType);
+
+            // Send the acknowledgement
+            log.debug("Sending Acknowledgement: {}", MllpComponent.covertBytesToPrintFriendlyString(acknowledgementMessageBytes));
+            try {
+                mllpSocketWriter.writeEnvelopedPayload(originalHl7MessageBytes, acknowledgementMessageBytes);
+            } catch (MllpException mllpEx) {
+                log.error("MLLP Acknowledgement failure: {}", mllpEx);
+                MllpAcknowledgementDeliveryException deliveryException = new MllpAcknowledgementDeliveryException(originalHl7MessageBytes, acknowledgementMessageBytes, mllpEx);
+                exchange.setProperty(MLLP_ACKNOWLEDGEMENT_EXCEPTION, deliveryException);
+                exchange.setException(deliveryException);
+            }
+
+            // Check AFTER_SEND Properties
+            if (exchange.getProperty(MLLP_RESET_CONNECTION_AFTER_SEND, boolean.class)) {
+                String reasonMessage = String.format("Exchange property %s is %b", MLLP_RESET_CONNECTION_AFTER_SEND,  exchange.getProperty(MLLP_RESET_CONNECTION_AFTER_SEND, boolean.class));
+                MllpSocketUtil.reset(clientSocket, log, reasonMessage);
+                return;
+            } else if (exchange.getProperty(MLLP_CLOSE_CONNECTION_AFTER_SEND, boolean.class)) {
+                String reasonMessage = String.format("Exchange property %s is %b", MLLP_CLOSE_CONNECTION_AFTER_SEND,  exchange.getProperty(MLLP_CLOSE_CONNECTION_AFTER_SEND, boolean.class));
+                MllpSocketUtil.reset(clientSocket, log, reasonMessage);
+            }
         }
 
         private void populateHl7DataHeaders(Exchange exchange, Message message, byte[] hl7MessageBytes) {
+            if (hl7MessageBytes == null ||  hl7MessageBytes.length < 8) {
+                // Not enough data to populate anything - just return
+                return;
+            }
             // Find the end of the MSH and indexes of the fields in the MSH to populate message headers
             final byte fieldSeparator = hl7MessageBytes[3];
             int endOfMSH = -1;
-            List<Integer> fieldSeparatorIndexes = new ArrayList<>(10);  // We need at least 10 fields to create the acknowledgment
+            List<Integer> fieldSeparatorIndexes = new ArrayList<>(10);  // We should have at least 10 fields
 
             for (int i = 0; i < hl7MessageBytes.length; ++i) {
                 if (fieldSeparator == hl7MessageBytes[i]) {
@@ -541,11 +733,7 @@ public class MllpTcpServerConsumer extends DefaultConsumer {
         @Override
         public void interrupt() {
             if (null != clientSocket  &&  clientSocket.isConnected()  && !clientSocket.isClosed()) {
-                try {
-                    clientSocket.close();
-                } catch (IOException ex) {
-                    log.warn("Exception encoutered closing client Socket in interrupt", ex);
-                }
+                MllpSocketUtil.close(clientSocket, log, this.getClass().getSimpleName() + " interrupted");
             }
             super.interrupt();
         }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTimeoutException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTimeoutException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTimeoutException.java
index 7c2014a..b1e4906 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTimeoutException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTimeoutException.java
@@ -17,43 +17,45 @@
 package org.apache.camel.component.mllp;
 
 /**
- * Raised when a MLLP Producer or Consumer encounter a timeout reading a message
+ * Raised when a MLLP Producer or Consumer encounter a timeout reading a message or an acknowledgment
  */
 public class MllpTimeoutException extends MllpException {
-    private final byte[] hl7Message;
+    static final String EXCEPTION_MESSAGE = "Timeout receiving HL7 Message";
 
-    public MllpTimeoutException(String message, byte[] hl7Message) {
-        super(message);
-        this.hl7Message = hl7Message;
+    public MllpTimeoutException(byte[] partialHl7Message) {
+        super(EXCEPTION_MESSAGE, partialHl7Message);
     }
 
-    public MllpTimeoutException(String message, byte[] hl7Message, Throwable cause) {
-        super(message, cause);
-        this.hl7Message = hl7Message;
+    public MllpTimeoutException(String message, byte[] partialHl7Message) {
+        super(message, partialHl7Message);
     }
 
-    public byte[] getHl7Message() {
-        return hl7Message;
+    public MllpTimeoutException(byte[] partialHl7Message, Throwable cause) {
+        super(EXCEPTION_MESSAGE, partialHl7Message, cause);
     }
 
-    @Override
-    public String getMessage() {
-        if (isLogPhi()) {
-            return String.format("%s:\n\tHL7 Message: %s", super.getMessage(), covertBytesToPrintFriendlyString(hl7Message));
-        } else {
-            return super.getMessage();
-        }
+    public MllpTimeoutException(String message, byte[] partialHl7Message, Throwable cause) {
+        super(message, partialHl7Message, cause);
     }
 
-    @Override
-    public String toString() {
-        StringBuilder stringBuilder = new StringBuilder(this.getClass().getName());
+    protected MllpTimeoutException(String message, byte[] hl7Message, byte[] partialHl7Acknowledgement) {
+        super(message, hl7Message, partialHl7Acknowledgement);
+    }
 
-        stringBuilder.append(": {hl7Message=")
-                .append(covertBytesToPrintFriendlyString(hl7Message))
-                .append("}");
+    protected MllpTimeoutException(String message, byte[] hl7Message, byte[] partialHl7Acknowledgement, Throwable cause) {
+        super(message, hl7Message, partialHl7Acknowledgement, cause);
+    }
 
-        return stringBuilder.toString();
+    /**
+     * Get the HL7 message payload associated with this exception, if any.
+     *
+     * @return If the timeout occurred while attempting to receive an HL7 Message, this will be null.  If the timeout
+     * occurred while attempting to receive an HL7 Acknowledgement, this will be the HL7 Message.  If the timeout occurred
+     * while attempting to complete the read of an HL7 message (i.e. part of the message has already been read), this
+     * will be the partial acknowledgement payload that was read before the timeout.
+     */
+    public byte[] getHl7Message() {
+        return super.getHl7Message();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpWriteException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpWriteException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpWriteException.java
index dd5bf42..2661d7c 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpWriteException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpWriteException.java
@@ -20,40 +20,19 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer or consumer encounter an error transmitting data
  */
 public class MllpWriteException extends MllpException {
-    private final byte[] mllpPayload;
-
-    public MllpWriteException(String message, byte[] mllpPayload) {
-        super(message);
-        this.mllpPayload = mllpPayload;
-    }
-
-    public MllpWriteException(String message, byte[] mllpPayload, Throwable cause) {
-        super(message, cause);
-        this.mllpPayload = mllpPayload;
+    public MllpWriteException(String message, byte[] hl7Message) {
+        super(message, hl7Message);
     }
 
-    public byte[] getMllpPayload() {
-        return mllpPayload;
+    public MllpWriteException(String message, byte[] hl7Message, byte[] hl7Acknowledgement) {
+        super(message, hl7Message, hl7Acknowledgement);
     }
 
-    @Override
-    public String getMessage() {
-        if (isLogPhi()) {
-            return String.format("%s:\n\tMLLP Payload: %s", super.getMessage(), covertBytesToPrintFriendlyString(mllpPayload));
-        } else {
-            return super.getMessage();
-        }
+    public MllpWriteException(String message, byte[] hl7Message, Throwable cause) {
+        super(message, hl7Message, cause);
     }
 
-    @Override
-    public String toString() {
-        StringBuilder stringBuilder = new StringBuilder(this.getClass().getName());
-
-        stringBuilder.append(": {mllpPayload=")
-                .append(covertBytesToPrintFriendlyString(mllpPayload))
-                .append("}");
-
-        return stringBuilder.toString();
+    public MllpWriteException(String message, byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
+        super(message, hl7Message, hl7Acknowledgement, cause);
     }
-
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/AcknowledgmentSynchronizationAdapter.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/AcknowledgmentSynchronizationAdapter.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/AcknowledgmentSynchronizationAdapter.java
deleted file mode 100644
index c7916d4..0000000
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/AcknowledgmentSynchronizationAdapter.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/**
- * 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.impl;
-
-import java.io.IOException;
-import java.net.Socket;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.Message;
-import org.apache.camel.Route;
-import org.apache.camel.component.mllp.MllpAcknowledgementDeliveryException;
-import org.apache.camel.component.mllp.MllpException;
-import org.apache.camel.component.mllp.MllpInvalidAcknowledgementException;
-import org.apache.camel.converter.IOConverter;
-import org.apache.camel.processor.mllp.Hl7AcknowledgementGenerationException;
-import org.apache.camel.processor.mllp.Hl7AcknowledgementGenerator;
-import org.apache.camel.support.SynchronizationAdapter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static org.apache.camel.component.mllp.MllpConstants.MLLP_ACKNOWLEDGEMENT;
-import static org.apache.camel.component.mllp.MllpConstants.MLLP_ACKNOWLEDGEMENT_EXCEPTION;
-import static org.apache.camel.component.mllp.MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE;
-import static org.apache.camel.component.mllp.MllpConstants.MLLP_AUTO_ACKNOWLEDGE;
-import static org.apache.camel.component.mllp.MllpConstants.MLLP_CLOSE_CONNECTION_AFTER_SEND;
-import static org.apache.camel.component.mllp.MllpConstants.MLLP_CLOSE_CONNECTION_BEFORE_SEND;
-import static org.apache.camel.component.mllp.MllpConstants.MLLP_RESET_CONNECTION_AFTER_SEND;
-import static org.apache.camel.component.mllp.MllpConstants.MLLP_RESET_CONNECTION_BEFORE_SEND;
-import static org.apache.camel.component.mllp.MllpEndpoint.SEGMENT_DELIMITER;
-
-public class AcknowledgmentSynchronizationAdapter extends SynchronizationAdapter {
-    Logger log = LoggerFactory.getLogger(this.getClass());
-    final byte[] originalHl7MessageBytes;
-    Hl7AcknowledgementGenerator acknowledgementGenerator = new Hl7AcknowledgementGenerator();
-    private Socket clientSocket;
-
-    public AcknowledgmentSynchronizationAdapter(Socket clientSocket, byte[] hl7MessageBytes) {
-        this.clientSocket = clientSocket;
-        this.originalHl7MessageBytes = hl7MessageBytes;
-    }
-
-    @Override
-    public int getOrder() {
-        return HIGHEST;
-    }
-
-    @Override
-    public void onAfterRoute(Route route, Exchange exchange) {
-        log.info("onAfterRoute");
-
-        // Check BEFORE_SEND Properties
-        if (exchange.getProperty(MLLP_RESET_CONNECTION_BEFORE_SEND, boolean.class)) {
-            MllpUtil.resetConnection(clientSocket);
-            return;
-        } else if (exchange.getProperty(MLLP_CLOSE_CONNECTION_BEFORE_SEND, boolean.class)) {
-            MllpUtil.closeConnection(clientSocket);
-            return;
-        }
-
-        // Find the acknowledgement body
-        // TODO:  Enhance this to say whether or not the acknowledgment is missing or just of an unconvertible type
-        byte[] acknowledgementMessageBytes = exchange.getProperty(MLLP_ACKNOWLEDGEMENT, byte[].class);
-        String acknowledgementMessageType = null;
-        if (null == acknowledgementMessageBytes) {
-            boolean autoAck = exchange.getProperty(MLLP_AUTO_ACKNOWLEDGE, true, boolean.class);
-            if (!autoAck) {
-                exchange.setException(new MllpInvalidAcknowledgementException("Automatic Acknowledgement is disabled and the "
-                        + MLLP_ACKNOWLEDGEMENT + " exchange property is null or cannot be converted to byte[]", originalHl7MessageBytes, acknowledgementMessageBytes));
-                return;
-            }
-
-            String acknowledgmentTypeProperty = exchange.getProperty(MLLP_ACKNOWLEDGEMENT_TYPE, String.class);
-            try {
-                if (null == acknowledgmentTypeProperty) {
-                    if (null == exchange.getException()) {
-                        acknowledgementMessageType = "AA";
-                        acknowledgementMessageBytes = acknowledgementGenerator.generateApplicationAcceptAcknowledgementMessage(originalHl7MessageBytes);
-                    } else {
-                        acknowledgementMessageType = "AE";
-                        acknowledgementMessageBytes = acknowledgementGenerator.generateApplicationErrorAcknowledgementMessage(originalHl7MessageBytes);
-                    }
-                } else {
-                    switch (acknowledgmentTypeProperty) {
-                    case "AA":
-                        acknowledgementMessageType = "AA";
-                        acknowledgementMessageBytes = acknowledgementGenerator.generateApplicationAcceptAcknowledgementMessage(originalHl7MessageBytes);
-                        break;
-                    case "AE":
-                        acknowledgementMessageType = "AE";
-                        acknowledgementMessageBytes = acknowledgementGenerator.generateApplicationErrorAcknowledgementMessage(originalHl7MessageBytes);
-                        break;
-                    case "AR":
-                        acknowledgementMessageType = "AR";
-                        acknowledgementMessageBytes = acknowledgementGenerator.generateApplicationRejectAcknowledgementMessage(originalHl7MessageBytes);
-                        break;
-                    default:
-                        exchange.setException(new Hl7AcknowledgementGenerationException("Unsupported acknowledgment type: " + acknowledgmentTypeProperty));
-                        return;
-                    }
-                }
-            } catch (Hl7AcknowledgementGenerationException ackGenerationException) {
-                exchange.setProperty(MLLP_ACKNOWLEDGEMENT_EXCEPTION, ackGenerationException);
-                exchange.setException(ackGenerationException);
-            }
-        } else {
-            final byte bM = 77;
-            final byte bS = 83;
-            final byte bA = 65;
-            final byte bE = 69;
-            final byte bR = 82;
-
-            final byte fieldSeparator = originalHl7MessageBytes[3];
-            // Acknowledgment is specified in exchange property - determine the acknowledgement type
-            for (int i = 0; i < originalHl7MessageBytes.length; ++i) {
-                if (SEGMENT_DELIMITER == i) {
-                    if (i + 7 < originalHl7MessageBytes.length // Make sure we don't run off the end of the message
-                            && bM == originalHl7MessageBytes[i + 1] && bS == originalHl7MessageBytes[i + 2]
-                            && bA == originalHl7MessageBytes[i + 3] && fieldSeparator == originalHl7MessageBytes[i + 4]) {
-                        if (fieldSeparator != originalHl7MessageBytes[i + 7]) {
-                            log.warn("MSA-1 is longer than 2-bytes - ignoring trailing bytes");
-                        }
-                        // Found MSA - pull acknowledgement bytes
-                        byte[] acknowledgmentTypeBytes = new byte[2];
-                        acknowledgmentTypeBytes[0] = originalHl7MessageBytes[i + 5];
-                        acknowledgmentTypeBytes[1] = originalHl7MessageBytes[i + 6];
-                        try {
-                            acknowledgementMessageType = IOConverter.toString(acknowledgmentTypeBytes, exchange);
-                        } catch (IOException ioEx) {
-                            throw new RuntimeException("Failed to convert acknowledgement message to string", ioEx);
-                        }
-
-                        // Verify it's a valid acknowledgement code
-                        if (bA != acknowledgmentTypeBytes[0]) {
-                            switch (acknowledgementMessageBytes[1]) {
-                            case bA:
-                            case bR:
-                            case bE:
-                                break;
-                            default:
-                                log.warn("Invalid acknowledgement type [" + acknowledgementMessageType + "] found in message - should be AA, AE or AR");
-                            }
-                        }
-
-                        // if the MLLP_ACKNOWLEDGEMENT_TYPE property is set on the exchange, make sure it matches
-                        String acknowledgementTypeProperty = exchange.getProperty(MLLP_ACKNOWLEDGEMENT_TYPE, String.class);
-                        if (null != acknowledgementTypeProperty && !acknowledgementTypeProperty.equals(acknowledgementMessageType)) {
-                            log.warn("Acknowledgement type found in message [" + acknowledgementMessageType + "] does not match "
-                                    + MLLP_ACKNOWLEDGEMENT_TYPE + " exchange property value [" + acknowledgementTypeProperty + "] - using value found in message");
-                        }
-                    }
-                }
-            }
-        }
-
-        Message message;
-        if (exchange.hasOut()) {
-            message = exchange.getOut();
-        } else {
-            message = exchange.getIn();
-        }
-        message.setHeader(MLLP_ACKNOWLEDGEMENT, acknowledgementMessageBytes);
-        message.setHeader(MLLP_ACKNOWLEDGEMENT_TYPE, acknowledgementMessageType);
-
-        // Send the acknowledgement
-        log.debug("Sending Acknowledgement");
-        try {
-            MllpUtil.writeFramedPayload(clientSocket, acknowledgementMessageBytes);
-        } catch (MllpException mllpEx) {
-            log.error("MLLP Acknowledgement failure: {}", mllpEx);
-            MllpAcknowledgementDeliveryException deliveryException = new MllpAcknowledgementDeliveryException(originalHl7MessageBytes, acknowledgementMessageBytes, mllpEx);
-            exchange.setProperty(MLLP_ACKNOWLEDGEMENT_EXCEPTION, deliveryException);
-            exchange.setException(deliveryException);
-        }
-
-        // Check AFTER_SEND Properties
-        if (exchange.getProperty(MLLP_RESET_CONNECTION_AFTER_SEND, boolean.class)) {
-            MllpUtil.resetConnection(clientSocket);
-            return;
-        } else if (exchange.getProperty(MLLP_CLOSE_CONNECTION_AFTER_SEND, boolean.class)) {
-            MllpUtil.closeConnection(clientSocket);
-        }
-
-        super.onAfterRoute(route, exchange);
-    }
-
-    @Override
-    public void onComplete(Exchange exchange) {
-        log.info("onComplete");
-        super.onComplete(exchange);
-
-    }
-
-    @Override
-    public void onFailure(Exchange exchange) {
-        log.warn("onFailure");
-        super.onFailure(exchange);
-    }
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/Hl7Util.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/Hl7Util.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/Hl7Util.java
new file mode 100644
index 0000000..0c762cb
--- /dev/null
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/Hl7Util.java
@@ -0,0 +1,90 @@
+/**
+ * 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.impl;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.MESSAGE_TERMINATOR;
+import static org.apache.camel.component.mllp.MllpEndpoint.SEGMENT_DELIMITER;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+
+public final class Hl7Util {
+    static final Logger LOG = LoggerFactory.getLogger(Hl7Util.class);
+
+    private Hl7Util() {
+    }
+
+    public static String generateInvalidPayloadExceptionMessage(final byte[] hl7Bytes) {
+        if (hl7Bytes == null) {
+            return "HL7 payload is null";
+        }
+
+        return generateInvalidPayloadExceptionMessage(hl7Bytes, hl7Bytes.length);
+    }
+
+    /**
+     * Verifies that the HL7 payload array
+     * <p>
+     * The MLLP protocol does not allow embedded START_OF_BLOCK or END_OF_BLOCK characters.  The END_OF_DATA character
+     * is allowed (and expected) because it is also the segment delimiter for an HL7 message
+     *
+     * @param hl7Bytes the HL7 payload to validate
+     * @return If the payload is invalid, an error message suitable for inclusion in an exception is returned.  If
+     * the payload is valid, null is returned;
+     */
+    public static String generateInvalidPayloadExceptionMessage(final byte[] hl7Bytes, final int length) {
+        if (hl7Bytes == null) {
+            return "HL7 payload is null";
+        }
+
+        if (hl7Bytes.length <= 0) {
+            return "HL7 payload is empty";
+        }
+
+        if (length > hl7Bytes.length) {
+            LOG.warn("The length specified for the HL7 payload array <{}> is greater than the actual length of the array <{}> - only validating {} bytes", length, hl7Bytes.length, length);
+        }
+
+        if (hl7Bytes.length < 3 || hl7Bytes[0] != 'M' || hl7Bytes[1] != 'S' || hl7Bytes[2] != 'H') {
+            return String.format("The first segment of the HL7 payload {%s} is not an MSH segment", new String(hl7Bytes, 0, Math.min(3, hl7Bytes.length)));
+        }
+
+        int validationLength = Math.min(length, hl7Bytes.length);
+
+        if (hl7Bytes[validationLength - 2] != SEGMENT_DELIMITER || hl7Bytes[validationLength - 1] != MESSAGE_TERMINATOR) {
+            String format = "The HL7 payload terminating bytes [%#x, %#x] are incorrect - expected [%#x, %#x]  {ASCII [<CR>, <LF>]}";
+            return String.format(format, hl7Bytes[validationLength - 2], hl7Bytes[validationLength - 1], (byte) SEGMENT_DELIMITER, (byte) MESSAGE_TERMINATOR);
+        }
+
+        for (int i = 0; i < validationLength; ++i) {
+            switch (hl7Bytes[i]) {
+            case START_OF_BLOCK:
+                return String.format("HL7 payload contains an embedded START_OF_BLOCK {%#x, ASCII <VT>} at index %d", hl7Bytes[i], i);
+            case END_OF_BLOCK:
+                return String.format("HL7 payload contains an embedded END_OF_BLOCK {%#x, ASCII <FS>} at index %d", hl7Bytes[i], i);
+            default:
+                // continue on
+            }
+        }
+
+        return null;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketWriter.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketWriter.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketWriter.java
new file mode 100644
index 0000000..46db872
--- /dev/null
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketWriter.java
@@ -0,0 +1,123 @@
+/**
+ * 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.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.SocketException;
+
+import org.apache.camel.component.mllp.MllpAcknowledgementDeliveryException;
+import org.apache.camel.component.mllp.MllpException;
+import org.apache.camel.component.mllp.MllpWriteException;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+
+public class MllpBufferedSocketWriter extends MllpSocketWriter {
+    static final int DEFAULT_SO_SNDBUF = 65535;
+
+    ByteArrayOutputStream outputBuffer;
+
+    public MllpBufferedSocketWriter(Socket socket, boolean acknowledgementWriter) {
+        super(socket, acknowledgementWriter);
+        try {
+            outputBuffer = new ByteArrayOutputStream(socket.getSendBufferSize());
+        } catch (SocketException socketEx) {
+            log.warn(String.format("Ignoring exception encountered retrieving SO_SNDBUF from the socket - using default size of %d bytes", DEFAULT_SO_SNDBUF), socketEx);
+            outputBuffer = new ByteArrayOutputStream(DEFAULT_SO_SNDBUF);
+        }
+    }
+
+    @Override
+    public void writeEnvelopedPayload(byte[] hl7MessageBytes, byte[] hl7AcknowledgementBytes) throws MllpException {
+        if (socket == null) {
+            final String errorMessage = "Socket is null";
+            if (isAcknowledgementWriter()) {
+                throw new MllpAcknowledgementDeliveryException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            } else {
+                throw new MllpWriteException(errorMessage, hl7MessageBytes);
+            }
+        } else if (!socket.isConnected()) {
+            final String errorMessage = "Socket is not connected";
+            if (isAcknowledgementWriter()) {
+                throw new MllpAcknowledgementDeliveryException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            } else {
+                throw new MllpWriteException(errorMessage, hl7MessageBytes);
+            }
+        } else if (socket.isClosed()) {
+            final String errorMessage = "Socket is closed";
+            if (isAcknowledgementWriter()) {
+                throw new MllpAcknowledgementDeliveryException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            } else {
+                throw new MllpWriteException(errorMessage, hl7MessageBytes);
+            }
+        }
+
+        OutputStream socketOutputStream = null;
+        try {
+            socketOutputStream = socket.getOutputStream();
+        } catch (IOException e) {
+            final String errorMessage = "Failed to retrieve the OutputStream from the Socket";
+            if (isAcknowledgementWriter()) {
+                throw new MllpAcknowledgementDeliveryException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            } else {
+                throw new MllpWriteException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            }
+        }
+
+        outputBuffer.write(START_OF_BLOCK);
+
+        if (isAcknowledgementWriter()) {
+            if (hl7AcknowledgementBytes == null) {
+                log.warn("HL7 Acknowledgement payload is null - sending empty MLLP payload");
+            } else if (hl7AcknowledgementBytes.length <= 0) {
+                log.warn("HL7 Acknowledgement payload is empty - sending empty MLLP payload");
+            } else {
+                outputBuffer.write(hl7AcknowledgementBytes, 0, hl7AcknowledgementBytes.length);
+            }
+        } else {
+            if (hl7MessageBytes == null) {
+                log.warn("HL7 Message payload is null - sending empty MLLP payload");
+            } else if (hl7MessageBytes.length <= 0) {
+                log.warn("HL7 Message payload is empty - sending empty MLLP payload");
+            } else {
+                outputBuffer.write(hl7MessageBytes, 0, hl7MessageBytes.length);
+            }
+        }
+
+        outputBuffer.write(END_OF_BLOCK);
+        outputBuffer.write(END_OF_DATA);
+
+        try {
+            outputBuffer.writeTo(socketOutputStream);
+            socketOutputStream.flush();
+        } catch (IOException e) {
+            final String errorMessage = "Failed to write the MLLP payload to the Socket's OutputStream";
+            if (isAcknowledgementWriter()) {
+                throw new MllpAcknowledgementDeliveryException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            } else {
+                throw new MllpWriteException(errorMessage, hl7MessageBytes);
+            }
+        } finally {
+            outputBuffer.reset();
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketReader.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketReader.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketReader.java
new file mode 100644
index 0000000..7d10cce
--- /dev/null
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketReader.java
@@ -0,0 +1,290 @@
+/**
+ * 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.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+
+import org.apache.camel.component.mllp.MllpAcknowledgementTimeoutException;
+import org.apache.camel.component.mllp.MllpComponent;
+import org.apache.camel.component.mllp.MllpException;
+import org.apache.camel.component.mllp.MllpReceiveAcknowledgementException;
+import org.apache.camel.component.mllp.MllpReceiveException;
+import org.apache.camel.component.mllp.MllpTimeoutException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+
+public class MllpSocketReader {
+    final Socket socket;
+    final int receiveTimeout;
+    final int readTimeout;
+    final boolean acknowledgementReader;
+    Logger log = LoggerFactory.getLogger(this.getClass());
+    byte[] receiveBuffer;
+    ByteArrayOutputStream readAdditionalStream;
+
+    public MllpSocketReader(Socket socket, int receiveTimeout, int readTimeout, boolean acknowledgementReader) {
+        this.socket = socket;
+        this.receiveTimeout = receiveTimeout;
+        this.readTimeout = readTimeout;
+        this.acknowledgementReader = acknowledgementReader;
+        try {
+            receiveBuffer = new byte[socket.getReceiveBufferSize()];
+        } catch (SocketException socketEx) {
+            throw new IllegalStateException("Cannot retrieve the value of SO_RCVBUF from the Socket", socketEx);
+        }
+    }
+
+
+    public byte[] readEnvelopedPayload() throws MllpException {
+        return readEnvelopedPayload(null, null);
+    }
+
+    public byte[] readEnvelopedPayload(byte[] hl7MessageBytes) throws MllpException {
+        return readEnvelopedPayload(null, hl7MessageBytes);
+    }
+
+    public byte[] readEnvelopedPayload(Integer initialByte) throws MllpException {
+        return readEnvelopedPayload(initialByte, null);
+    }
+
+    protected byte[] readEnvelopedPayload(Integer initialByte, byte[] hl7MessageBytes) throws MllpException {
+        byte[] answer = null;
+
+        MllpSocketUtil.setSoTimeout(socket, receiveTimeout, log, "Preparing to receive payload");
+
+        InputStream socketInputStream = null;
+        try {
+            socketInputStream = socket.getInputStream();
+        } catch (IOException ioEx) {
+            final String errorMessage = "Failed to retrieve the InputStream from the Socket";
+            resetConnection(errorMessage);
+            throw isAcknowledgementReader()
+                    ? new MllpReceiveAcknowledgementException(errorMessage, hl7MessageBytes, ioEx)
+                    : new MllpReceiveException(errorMessage, ioEx);
+        }
+
+        // Read the acknowledgment - hopefully in one shot
+        int readCount;
+        int startPosition = (initialByte != null && initialByte == START_OF_BLOCK) ? 0 : -1;
+        do { // Read from the socket until the beginning of a MLLP payload is found or a timeout occurs
+            try {
+                readCount = socketInputStream.read(receiveBuffer);
+                if (readCount == -1) {
+                    String errorMessage = "END_OF_STREAM encountered while attempting to receive payload - was Socket closed?";
+                    resetConnection(errorMessage);
+                    throw isAcknowledgementReader()
+                            ? new MllpReceiveAcknowledgementException(errorMessage, hl7MessageBytes)
+                            : new MllpReceiveException(errorMessage);
+                } else if (log.isTraceEnabled()) {
+                    log.trace("Received bytes: {}", MllpComponent.covertBytesToPrintFriendlyString(receiveBuffer, 0, readCount));
+                }
+            } catch (SocketTimeoutException timeoutEx) {
+                if (isAcknowledgementReader()) {
+                    throw new MllpAcknowledgementTimeoutException(hl7MessageBytes, timeoutEx);
+                } else {
+                    if (initialByte != null && initialByte == START_OF_BLOCK) {
+                        answer = new byte[1];
+                        answer[0] = initialByte.byteValue();
+                        throw new MllpTimeoutException(answer, timeoutEx);
+                    }
+
+                    return null;
+                }
+            } catch (IOException ioEx) {
+                String errorMessage = "Error receiving payload";
+                log.error(errorMessage, ioEx);
+                resetConnection(errorMessage);
+                throw isAcknowledgementReader()
+                        ? new MllpReceiveAcknowledgementException(errorMessage, hl7MessageBytes, ioEx)
+                        : new MllpReceiveException(errorMessage, ioEx);
+            }
+
+            if (readCount > 0) {  // If some data was read, make sure we found the beginning of the message
+                if (initialByte != null && initialByte == START_OF_BLOCK) {
+                    startPosition = 0;
+                } else {
+                    int startOfBlock = MllpSocketUtil.findStartOfBlock(receiveBuffer, readCount);
+                    startPosition = (startOfBlock == -1) ? -1 : startOfBlock + 1;
+                }
+                if (startPosition > 1) {
+                    // Some out-of-band data was received - log it
+                    final String format = "Ignoring {} out-of-band bytes received before the beginning of the payload";
+                    int length = readCount - startPosition - 1;
+                    if (MllpComponent.isLogPhi()) {
+                        log.warn(format + ": {}", length, MllpComponent.covertBytesToPrintFriendlyString(receiveBuffer, 0, length));
+                    } else {
+                        log.warn(format, length);
+                    }
+                }
+            }
+        } while (startPosition == -1);
+
+        // Check to see if the payload is complete
+        int endPosition = MllpSocketUtil.findEndOfMessage(receiveBuffer, readCount);
+
+        if (endPosition != -1) {
+            // We have a complete payload - build the result without delimiters
+            if (endPosition < readCount - 3) {
+                // Some out-of-band data was received - log it
+                final String format = "Ignoring {} out-of-band bytes received after the end of the payload";
+                int length = readCount - endPosition - 2;
+                if (MllpComponent.isLogPhi()) {
+                    log.warn(format + ": {}", length, MllpComponent.covertBytesToPrintFriendlyString(receiveBuffer, endPosition + 1, length));
+                } else {
+                    log.warn(format, length);
+                }
+            }
+
+            // Build the answer
+            int length = endPosition - startPosition;
+            answer = new byte[length];
+            System.arraycopy(receiveBuffer, startPosition, answer, 0, length);
+        } else {
+            // The payload is incomplete - read it all before returning
+
+            // Write the data already received to the overflow stream, without the beginning delimiters
+            getReadAdditionalStream().reset();
+            readAdditionalStream.write(receiveBuffer, startPosition, readCount - startPosition);
+
+            // We've already received some data, so switch to the read timeout
+            MllpSocketUtil.setSoTimeout(socket, readTimeout, log, "Preparing to continue reading payload");
+
+            // Now the current data is in the overflow stream, continue reading until the end of the payload is found or a timeout occurs
+            endPosition = -1;
+            do { // Read from the socket until the end of the MLLP payload is found or a timeout occurs
+                try {
+                    readCount = socketInputStream.read(receiveBuffer);
+                    if (readCount == -1) {
+                        String errorMessage = "END_OF_STREAM encountered while attempting to read the end of the payload - Socket was closed or reset";
+                        resetConnection(errorMessage);
+                        byte[] partialPayload = (readAdditionalStream.size() > 0) ? readAdditionalStream.toByteArray() : null;
+                        throw isAcknowledgementReader()
+                                ? new MllpReceiveAcknowledgementException(errorMessage, hl7MessageBytes, partialPayload)
+                                : new MllpReceiveException(errorMessage, partialPayload);
+                    } else if (log.isTraceEnabled()) {
+                        log.trace("Read additional bytes: {}", MllpComponent.covertBytesToPrintFriendlyString(receiveBuffer, 0, readCount));
+                    }
+                } catch (SocketTimeoutException timeoutEx) {
+                    String errorMessage = "Timeout reading the end of the payload";
+                    resetConnection(errorMessage);
+                    byte[] partialPayload = (readAdditionalStream.size() > 0) ? readAdditionalStream.toByteArray() : null;
+                    throw isAcknowledgementReader()
+                            ? new MllpAcknowledgementTimeoutException(errorMessage, hl7MessageBytes, partialPayload, timeoutEx)
+                            : new MllpTimeoutException(errorMessage, partialPayload, timeoutEx);
+                } catch (IOException ioEx) {
+                    String errorMessage = "Error reading  the end of the payload";
+                    resetConnection(errorMessage);
+                    log.error(errorMessage);
+                    byte[] partialPayload = (readAdditionalStream.size() > 0) ? readAdditionalStream.toByteArray() : null;
+                    throw isAcknowledgementReader()
+                            ? new MllpReceiveAcknowledgementException(errorMessage, hl7MessageBytes, partialPayload, ioEx)
+                            : new MllpReceiveException(errorMessage, partialPayload, ioEx);
+                }
+                if (readCount > 0) {  // If some data was read, make sure we found the end of the message
+                    endPosition = MllpSocketUtil.findEndOfMessage(receiveBuffer, readCount);
+                    if (endPosition != -1) {
+                        if (endPosition < readCount - 2) {
+                            final String format = "Ignoring {} out-of-band bytes after the end of the payload";
+                            int length = readCount - endPosition - 2;
+                            if (MllpComponent.isLogPhi()) {
+                                log.warn(format + ": {}", length, MllpComponent.covertBytesToPrintFriendlyString(receiveBuffer, endPosition + 2, length));
+                            } else {
+                                log.warn(format, length);
+                            }
+                        }
+                        readAdditionalStream.write(receiveBuffer, 0, endPosition);
+                    } else {
+                        readAdditionalStream.write(receiveBuffer, 0, readCount);
+                    }
+                }
+            } while (endPosition == -1);
+
+            // All available data has been read - return the data
+            answer = readAdditionalStream.toByteArray();
+        }
+
+        // Check to see if there is any more data available
+        int availableCount;
+        do {
+            try {
+                availableCount = socketInputStream.available();
+            } catch (IOException ioEx) {
+                log.warn("Ignoring IOException encountered while checking for additional available trailing bytes", ioEx);
+                break;
+            }
+            if (availableCount > 0) { // if data is available, eat it
+                try {
+                    readCount = socketInputStream.read(receiveBuffer);
+                    final String format = "Ignoring {} out-of-band bytes trailing after the end of the payload";
+                    if (MllpComponent.isLogPhi()) {
+                        log.warn(format + ": {}", readCount, MllpComponent.covertBytesToPrintFriendlyString(receiveBuffer, 0, readCount));
+                    } else {
+                        log.warn(format, readCount);
+                    }
+                } catch (IOException ioEx) {
+                    log.warn(String.format("Ignoring IOException encountered while attempting to read %d bytes of trailing data", availableCount), ioEx);
+                    break;
+                }
+            }
+        } while (availableCount != 0);
+
+        return answer;
+    }
+
+    public void closeConnection(String reasonMessage) {
+        MllpSocketUtil.close(socket, log, reasonMessage);
+    }
+
+    public void resetConnection(String reasonMessage) {
+        MllpSocketUtil.reset(socket, log, reasonMessage);
+    }
+
+    public Socket getSocket() {
+        return socket;
+    }
+
+    public int getReceiveTimeout() {
+        return receiveTimeout;
+    }
+
+    public int getReadTimeout() {
+        return readTimeout;
+    }
+
+    public byte[] getReceiveBuffer() {
+        return receiveBuffer;
+    }
+
+    public boolean isAcknowledgementReader() {
+        return acknowledgementReader;
+    }
+
+    public ByteArrayOutputStream getReadAdditionalStream() {
+        if (readAdditionalStream == null) {
+            readAdditionalStream = new ByteArrayOutputStream(receiveBuffer.length);
+        }
+
+        return readAdditionalStream;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketUtil.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketUtil.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketUtil.java
new file mode 100644
index 0000000..fab33a8
--- /dev/null
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketUtil.java
@@ -0,0 +1,230 @@
+/**
+ * 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.impl;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+
+public final class MllpSocketUtil {
+    private static final Logger LOG = LoggerFactory.getLogger(MllpSocketUtil.class);
+
+    private MllpSocketUtil() {
+    }
+
+    public static void setSoTimeout(Socket socket, int timeout, Logger logger, String reasonMessage) {
+        if (logger != null && logger.isDebugEnabled()) {
+            final String format = "Setting SO_TIMEOUT to {} for connection {}";
+            if (reasonMessage != null && !reasonMessage.isEmpty()) {
+                logger.debug(format + "  Reason: {}", timeout, getAddressString(socket), reasonMessage);
+            } else {
+                logger.debug(format, timeout, getAddressString(socket));
+            }
+        }
+        try {
+            socket.setSoTimeout(timeout);
+        } catch (SocketException socketEx) {
+            if (logger != null) {
+                final String format = "Ignoring SocketException encountered setting SO_TIMEOUT to %d for connection %s.";
+                if (reasonMessage != null && !reasonMessage.isEmpty()) {
+                    logger.warn(String.format(format + "  Reason: %s", timeout, getAddressString(socket), reasonMessage), socketEx);
+                } else {
+                    logger.warn(String.format(format, timeout, getAddressString(socket)), socketEx);
+                }
+            }
+        }
+    }
+
+    public static void close(Socket socket, Logger logger, String reasonMessage) {
+        if (socket != null && socket.isConnected() && !socket.isClosed()) {
+            final String format = "Closing connection {}";
+
+            String address = getAddressString(socket);
+
+            if (logger != null) {
+                if (reasonMessage != null && !reasonMessage.isEmpty()) {
+                    logger.warn(format + ".  Reason: {}", address, reasonMessage);
+                } else {
+                    logger.warn(format, address);
+                }
+            }
+
+            if (!socket.isInputShutdown()) {
+                try {
+                    socket.shutdownInput();
+                } catch (Exception ex) {
+                    String logMessage = String.format("Ignoring Exception encountered shutting down the input stream on the client socket %s", address);
+                    if (logger != null) {
+                        logger.warn(logMessage, ex);
+                    } else {
+                        LOG.warn(logMessage, ex);
+                    }
+                }
+            }
+
+            if (!socket.isOutputShutdown()) {
+                try {
+                    socket.shutdownOutput();
+                } catch (Exception ex) {
+                    String logMessage = String.format("Ignoring Exception encountered shutting down the output stream on the client socket %s", address);
+                    if (logger != null) {
+                        logger.warn(logMessage, ex);
+                    } else {
+                        LOG.warn(logMessage, ex);
+                    }
+                }
+            }
+
+            try {
+                socket.close();
+            } catch (IOException ioEx) {
+                String logMessage = String.format("Ignoring IOException encountered while closing connection %s", address);
+                if (logger != null) {
+                    logger.warn(logMessage, ioEx);
+                } else {
+                    LOG.warn(logMessage, ioEx);
+                }
+            }
+        }
+    }
+
+    public static void reset(Socket socket, Logger logger, String reasonMessage) {
+        if (socket != null && socket.isConnected() && !socket.isClosed()) {
+            final String format = "Resetting connection {}";
+
+            String address = getAddressString(socket);
+
+            if (logger != null) {
+                if (reasonMessage != null && !reasonMessage.isEmpty()) {
+                    logger.warn(format + ".  Reason: {}", address, reasonMessage);
+                } else {
+                    logger.warn(format, address);
+                }
+            }
+
+            try {
+                socket.setSoLinger(true, 0);
+            } catch (SocketException socketEx) {
+                String logMessage = String.format("Ignoring SocketException encountered setting SO_LINGER in preparation for resetting connection %s", address);
+                if (logger != null) {
+                    logger.warn(logMessage, socketEx);
+                } else {
+                    LOG.warn(logMessage, socketEx);
+                }
+            }
+
+            try {
+                socket.close();
+            } catch (IOException ioEx) {
+                String logMessage = String.format("Ignoring IOException encountered while resetting connection %s", address);
+                if (logger != null) {
+                    logger.warn(logMessage, ioEx);
+                } else {
+                    LOG.warn(logMessage, ioEx);
+                }
+            }
+        }
+    }
+
+    public static String getAddressString(Socket socket) {
+        String localAddressString = "null";
+        String remoteAddressString = "null";
+
+        if (socket != null) {
+            SocketAddress localSocketAddress = socket.getLocalSocketAddress();
+            if (localSocketAddress != null) {
+                localAddressString = localSocketAddress.toString();
+            }
+
+            SocketAddress remoteSocketAddress = socket.getRemoteSocketAddress();
+            if (remoteSocketAddress != null) {
+                remoteAddressString = remoteSocketAddress.toString();
+            }
+        }
+
+        return String.format("%s -> %s", localAddressString, remoteAddressString);
+    }
+
+    public static int findStartOfBlock(byte[] payload) {
+        if (payload != null) {
+            return findStartOfBlock(payload, payload.length);
+        }
+
+        return -1;
+    }
+
+    /**
+     * Find the beginning of the HL7 Payload
+     * <p>
+     * Searches the payload from the beginning, looking for the START_OF_BLOCK character.
+     *
+     * @param payload the payload to check
+     * @param length  the current valid length of the receive buffer
+     * @return the index of the START_OF_BLOCK, or -1 if not found
+     */
+    public static int findStartOfBlock(byte[] payload, int length) {
+        if (payload != null && length >= 0) {
+            for (int i = 0; i < Math.min(length, payload.length); ++i) {
+                if (payload[i] == START_OF_BLOCK) {
+                    return i;
+                }
+            }
+        }
+
+        return -1;
+    }
+
+    public static int findEndOfMessage(byte[] payload) {
+        if (payload != null) {
+            return findEndOfMessage(payload, payload.length);
+        }
+
+        return -1;
+    }
+
+    /**
+     * Find the end of the HL7 Payload
+     * <p>
+     * Searches the payload from the end, looking for the [END_OF_BLOCK, END_OF_DATA] characters.
+     *
+     * @param payload the payload to check
+     * @param length  the current valid length of the receive buffer
+     * @return the index of the END_OF_BLOCK character that terminates the message, or -1 if not found
+     */
+    public static int findEndOfMessage(byte[] payload, int length) {
+        if (payload != null && length >= 0) {
+            for (int i = Math.min(length, payload.length) - 1; i > 0; --i) {
+                if (payload[i] == END_OF_DATA) {
+                    if (i > 0 && payload[i - 1] == END_OF_BLOCK) {
+                        return i - 1;
+                    }
+                }
+            }
+        }
+
+        return -1;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketWriter.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketWriter.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketWriter.java
new file mode 100644
index 0000000..bd9515c
--- /dev/null
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketWriter.java
@@ -0,0 +1,143 @@
+/**
+ * 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.impl;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+
+import org.apache.camel.component.mllp.MllpAcknowledgementDeliveryException;
+import org.apache.camel.component.mllp.MllpException;
+import org.apache.camel.component.mllp.MllpWriteException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+
+public class MllpSocketWriter {
+    static final byte[] PAYLOAD_TERMINATOR;
+
+    static {
+        PAYLOAD_TERMINATOR = new byte[2];
+        PAYLOAD_TERMINATOR[0] = END_OF_BLOCK;
+        PAYLOAD_TERMINATOR[1] = END_OF_DATA;
+    }
+
+    final Socket socket;
+    final boolean acknowledgementWriter;
+
+    Logger log = LoggerFactory.getLogger(this.getClass());
+
+    public MllpSocketWriter(Socket socket, boolean acknowledgementWriter) {
+        this.socket = socket;
+        this.acknowledgementWriter = acknowledgementWriter;
+    }
+
+    public void writeEnvelopedPayload(byte[] hl7MessageBytes, byte[] hl7AcknowledgementBytes) throws MllpException {
+        if (socket == null) {
+            final String errorMessage = "Socket is null";
+            if (isAcknowledgementWriter()) {
+                throw new MllpAcknowledgementDeliveryException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            } else {
+                throw new MllpWriteException(errorMessage, hl7MessageBytes);
+            }
+        } else if (!socket.isConnected()) {
+            final String errorMessage = "Socket is not connected";
+            if (isAcknowledgementWriter()) {
+                throw new MllpAcknowledgementDeliveryException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            } else {
+                throw new MllpWriteException(errorMessage, hl7MessageBytes);
+            }
+        } else if (socket.isClosed()) {
+            final String errorMessage = "Socket is closed";
+            if (isAcknowledgementWriter()) {
+                throw new MllpAcknowledgementDeliveryException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            } else {
+                throw new MllpWriteException(errorMessage, hl7MessageBytes);
+            }
+        }
+
+        OutputStream socketOutputStream = null;
+        try {
+            socketOutputStream = socket.getOutputStream();
+        } catch (IOException e) {
+            final String errorMessage = "Failed to retrieve the OutputStream from the Socket";
+            if (isAcknowledgementWriter()) {
+                throw new MllpAcknowledgementDeliveryException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            } else {
+                throw new MllpWriteException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            }
+        }
+
+        try {
+            socketOutputStream.write(START_OF_BLOCK);
+        } catch (IOException e) {
+            final String errorMessage = "Failed to write the START_OF_BLOCK to the Socket's OutputStream";
+            if (isAcknowledgementWriter()) {
+                throw new MllpAcknowledgementDeliveryException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            } else {
+                throw new MllpWriteException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            }
+        }
+
+        if (isAcknowledgementWriter()) {
+            if (hl7AcknowledgementBytes == null) {
+                log.warn("HL7 Acknowledgement payload is null - sending empty MLLP payload");
+            } else if (hl7AcknowledgementBytes.length <= 0) {
+                log.warn("HL7 Acknowledgement payload is empty - sending empty MLLP payload");
+            } else {
+                try {
+                    socketOutputStream.write(hl7AcknowledgementBytes);
+                } catch (IOException ioEx) {
+                    throw new MllpAcknowledgementDeliveryException("Failed to write the HL7 Acknowledgement payload to the Socket's OutputStream", hl7MessageBytes, hl7AcknowledgementBytes, ioEx);
+                }
+            }
+        } else {
+            if (hl7MessageBytes == null) {
+                log.warn("HL7 Message payload is null - sending empty MLLP payload");
+            } else if (hl7MessageBytes.length <= 0) {
+                log.warn("HL7 Message payload is empty - sending empty MLLP payload");
+            } else {
+                try {
+                    socketOutputStream.write(hl7MessageBytes);
+                } catch (IOException ioEx) {
+                    throw new MllpWriteException("Failed to write the HL7 Message payload to the Socket's OutputStream", hl7MessageBytes, hl7AcknowledgementBytes, ioEx);
+                }
+            }
+        }
+
+        try {
+            socketOutputStream.write(PAYLOAD_TERMINATOR);
+            socketOutputStream.flush();
+        } catch (IOException e) {
+            final String errorMessage = "Failed to write the END_OF_BLOCK and END_OF_DATA to the Socket's OutputStream";
+            if (isAcknowledgementWriter()) {
+                throw new MllpAcknowledgementDeliveryException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            } else {
+                throw new MllpWriteException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
+            }
+        }
+
+    }
+
+    public boolean isAcknowledgementWriter() {
+        return acknowledgementWriter;
+    }
+}


[8/8] camel git commit: CAMEL-10511: Polished and fixed CS

Posted by da...@apache.org.
CAMEL-10511: Polished and fixed CS


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

Branch: refs/heads/camel-2.18.x
Commit: ba8f3aa04457929c81df1bfca21fb0393c9acf81
Parents: e6d58b6
Author: Claus Ibsen <da...@apache.org>
Authored: Fri Dec 16 09:02:52 2016 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Fri Dec 16 09:05:50 2016 +0100

----------------------------------------------------------------------
 .../mllp/MllpAcknowledgementDeliveryException.java          | 1 +
 .../component/mllp/MllpAcknowledgementTimeoutException.java | 1 +
 .../mllp/MllpApplicationErrorAcknowledgementException.java  | 1 +
 .../mllp/MllpApplicationRejectAcknowledgementException.java | 1 +
 .../mllp/MllpCommitErrorAcknowledgementException.java       | 1 +
 .../mllp/MllpCommitRejectAcknowledgementException.java      | 1 +
 .../java/org/apache/camel/component/mllp/MllpComponent.java | 2 +-
 .../java/org/apache/camel/component/mllp/MllpException.java | 1 -
 .../org/apache/camel/component/mllp/MllpFrameException.java | 2 ++
 .../component/mllp/MllpInvalidAcknowledgementException.java | 1 +
 .../camel/component/mllp/MllpInvalidMessageException.java   | 1 +
 .../mllp/MllpNegativeAcknowledgementException.java          | 1 +
 .../component/mllp/MllpReceiveAcknowledgementException.java | 3 +--
 .../apache/camel/component/mllp/MllpReceiveException.java   | 1 +
 .../apache/camel/component/mllp/MllpTcpClientProducer.java  | 2 +-
 .../apache/camel/component/mllp/MllpTcpServerConsumer.java  | 2 +-
 .../java/org/apache/camel/component/mllp/impl/Hl7Util.java  | 1 +
 .../camel/component/mllp/impl/MllpBufferedSocketWriter.java | 1 +
 .../apache/camel/component/mllp/impl/MllpSocketReader.java  | 2 +-
 .../apache/camel/component/mllp/impl/MllpSocketUtil.java    | 1 +
 .../apache/camel/component/mllp/impl/MllpSocketWriter.java  | 1 +
 .../mllp/Hl7AcknowledgementGenerationException.java         | 2 +-
 .../camel/processor/mllp/Hl7AcknowledgementGenerator.java   | 3 +--
 .../mllp/MllpTcpServerConsumerMessageValidationTest.java    | 9 ++++-----
 .../camel/component/mllp/MllpTcpServerConsumerTest.java     | 6 ++----
 25 files changed, 29 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java
index c6fc878..19bc353 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Consumer cannot deliver the MLLP Acknowledgement
  */
 public class MllpAcknowledgementDeliveryException extends MllpAcknowledgementException {
+
     static final String EXCEPTION_MESSAGE = "HL7 Acknowledgment Delivery Failed";
 
     public MllpAcknowledgementDeliveryException(byte[] hl7Message, byte[] hl7Acknowledgement) {

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimeoutException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimeoutException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimeoutException.java
index 8cb2822..50510c9 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimeoutException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimeoutException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer does not receive a HL7 acknowledgement within the configured timespan
  */
 public class MllpAcknowledgementTimeoutException extends MllpAcknowledgementException {
+
     static final String EXCEPTION_MESSAGE = "Timeout receiving HL7 Acknowledgement";
 
     public MllpAcknowledgementTimeoutException(byte[] hl7Message) {

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java
index c8db47a..afcbdc5 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer receives a HL7 Application Error Acknowledgement
  */
 public class MllpApplicationErrorAcknowledgementException extends MllpNegativeAcknowledgementException {
+
     static final String EXCEPTION_MESSAGE = "HL7 Application Error Acknowledgment Received";
 
     public MllpApplicationErrorAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java
index 00dd3e4..ca0deb6 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer receives a HL7 Application Reject Acknowledgement
  */
 public class MllpApplicationRejectAcknowledgementException extends MllpNegativeAcknowledgementException {
+
     static final String EXCEPTION_MESSAGE = "HL7 Application Reject Acknowledgment Received";
 
     public MllpApplicationRejectAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java
index bec34d9..05591de 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer receives a HL7 Commit Error Acknowledgement
  */
 public class MllpCommitErrorAcknowledgementException extends MllpNegativeAcknowledgementException {
+
     static final String EXCEPTION_MESSAGE = "HL7 Commit Error Acknowledgment Received";
 
     public MllpCommitErrorAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java
index f98ee5e..b21d213 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer receives a HL7 Commit Reject Acknowledgement
  */
 public class MllpCommitRejectAcknowledgementException extends MllpNegativeAcknowledgementException {
+
     static final String EXCEPTION_MESSAGE = "HL7 Commit Reject Acknowledgment Received";
 
     public MllpCommitRejectAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java
index f3e22b1..504a6cf 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java
@@ -23,13 +23,13 @@ import org.apache.camel.Endpoint;
 import org.apache.camel.impl.UriEndpointComponent;
 
 import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
-import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 
 /**
  * Represents the component that manages {@link MllpEndpoint}.
  */
 public class MllpComponent extends UriEndpointComponent {
+
     public static final String MLLP_LOG_PHI_PROPERTY = "org.apache.camel.component.mllp.logPHI";
 
     public MllpComponent() {

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java
index 0d2c1ce..ffa908f 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java
@@ -59,7 +59,6 @@ public class MllpException extends Exception {
         this.hl7Acknowledgement = (hl7Acknowledgement != null && hl7Acknowledgement.length > 0) ? hl7Acknowledgement : null;
     }
 
-
     /**
      * Get the HL7 message payload associated with this exception, if any.
      *

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java
index 7b7a3c4..7ae2dd1 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java
@@ -21,7 +21,9 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer or consumer encounters a corrupt MLLP Frame while attempting
  * to readEnvelopedPayload or writeEnvelopedMessage a MLLP payload.
  */
+@Deprecated
 public class MllpFrameException extends MllpException {
+
     public MllpFrameException(String message, byte[] hl7Message) {
         super(message, hl7Message);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidAcknowledgementException.java
index 67d5316..2543bec 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidAcknowledgementException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer receives a HL7 Acknowledgement for which the HL7 Acknowledgement type cannot be determined.
  */
 public class MllpInvalidAcknowledgementException extends MllpAcknowledgementException {
+
     public MllpInvalidAcknowledgementException(String message, byte[] hl7Message, byte[] hl7Acknowledgement) {
         super(message, hl7Message, hl7Acknowledgement);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidMessageException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidMessageException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidMessageException.java
index 9cde29a..847a4de 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidMessageException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidMessageException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Consumer receives an invalid HL7 Message.
  */
 public class MllpInvalidMessageException extends MllpException {
+
     public MllpInvalidMessageException(String message, byte[] hl7Message) {
         super(message, hl7Message);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpNegativeAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpNegativeAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpNegativeAcknowledgementException.java
index 6b8a4f8..b57aebe 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpNegativeAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpNegativeAcknowledgementException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Abstract base for all MLLP Negative Acknowledgements
  */
 public abstract class MllpNegativeAcknowledgementException extends MllpAcknowledgementException {
+
     public MllpNegativeAcknowledgementException(String message, byte[] hl7Message, byte[] hl7Acknowledgement) {
         super(message, hl7Message, hl7Acknowledgement);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveAcknowledgementException.java
index 2268137..75b486f 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveAcknowledgementException.java
@@ -26,7 +26,6 @@ public class MllpReceiveAcknowledgementException extends MllpAcknowledgementExce
         super(EXCEPTION_MESSAGE, hl7Message);
     }
 
-
     public MllpReceiveAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {
         super(EXCEPTION_MESSAGE, hl7Message, hl7Acknowledgement);
     }
@@ -35,7 +34,6 @@ public class MllpReceiveAcknowledgementException extends MllpAcknowledgementExce
         super(EXCEPTION_MESSAGE, hl7Message, cause);
     }
 
-
     public MllpReceiveAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
         super(EXCEPTION_MESSAGE, hl7Message, hl7Acknowledgement, cause);
     }
@@ -51,6 +49,7 @@ public class MllpReceiveAcknowledgementException extends MllpAcknowledgementExce
     public MllpReceiveAcknowledgementException(String message, byte[] hl7Message, Throwable cause) {
         super(message, hl7Message, cause);
     }
+
     public MllpReceiveAcknowledgementException(String message, byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
         super(message, hl7Message, hl7Acknowledgement, cause);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveException.java
index c755d02..bf8826b 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Consumer cannot deliver the MLLP Acknowledgement
  */
 public class MllpReceiveException extends MllpException {
+
     public MllpReceiveException(String message) {
         super(message);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
index 69176bc..e1827cb 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
@@ -237,7 +237,7 @@ public class MllpTcpClientProducer extends DefaultProducer {
     /**
      * Validate the TCP Connection
      *
-     * @return null if the connection is valid, otherwise the Exception encounted checking the connection
+     * @return null if the connection is valid, otherwise the Exception encountered checking the connection
      */
     void checkConnection() throws IOException {
         if (null == socket || socket.isClosed() || !socket.isConnected()) {

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/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 0ec8564..b1be22b 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
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 package org.apache.camel.component.mllp;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.BindException;
@@ -28,7 +29,6 @@ import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 
-
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
 import org.apache.camel.Message;

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/Hl7Util.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/Hl7Util.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/Hl7Util.java
index 0c762cb..f4a8f9b 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/Hl7Util.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/Hl7Util.java
@@ -25,6 +25,7 @@ import static org.apache.camel.component.mllp.MllpEndpoint.SEGMENT_DELIMITER;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 
 public final class Hl7Util {
+
     static final Logger LOG = LoggerFactory.getLogger(Hl7Util.class);
 
     private Hl7Util() {

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketWriter.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketWriter.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketWriter.java
index 46db872..6f52543 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketWriter.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketWriter.java
@@ -31,6 +31,7 @@ import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 
 public class MllpBufferedSocketWriter extends MllpSocketWriter {
+
     static final int DEFAULT_SO_SNDBUF = 65535;
 
     ByteArrayOutputStream outputBuffer;

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketReader.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketReader.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketReader.java
index 7d10cce..d0c78e0 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketReader.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketReader.java
@@ -35,6 +35,7 @@ import org.slf4j.LoggerFactory;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 
 public class MllpSocketReader {
+
     final Socket socket;
     final int receiveTimeout;
     final int readTimeout;
@@ -55,7 +56,6 @@ public class MllpSocketReader {
         }
     }
 
-
     public byte[] readEnvelopedPayload() throws MllpException {
         return readEnvelopedPayload(null, null);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketUtil.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketUtil.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketUtil.java
index fab33a8..d6a05d7 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketUtil.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketUtil.java
@@ -29,6 +29,7 @@ import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 
 public final class MllpSocketUtil {
+
     private static final Logger LOG = LoggerFactory.getLogger(MllpSocketUtil.class);
 
     private MllpSocketUtil() {

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketWriter.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketWriter.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketWriter.java
index bd9515c..3f9310d 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketWriter.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketWriter.java
@@ -32,6 +32,7 @@ import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 
 public class MllpSocketWriter {
+
     static final byte[] PAYLOAD_TERMINATOR;
 
     static {

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerationException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerationException.java b/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerationException.java
index c27c7f9..2d429c5 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerationException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerationException.java
@@ -17,6 +17,7 @@
 package org.apache.camel.processor.mllp;
 
 public class Hl7AcknowledgementGenerationException extends Exception {
+
     private final byte[] hl7Message;
 
     public Hl7AcknowledgementGenerationException(String message) {
@@ -34,7 +35,6 @@ public class Hl7AcknowledgementGenerationException extends Exception {
         this.hl7Message = hl7Message;
     }
 
-
     public byte[] getHl7Message() {
         return hl7Message;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java b/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java
index 5c0013c..ddc1927 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java
@@ -41,10 +41,9 @@ public class Hl7AcknowledgementGenerator implements Processor {
             + "MSA|AR|" + SEGMENT_DELIMITER
             + MESSAGE_TERMINATOR;
 
-
     @Override
     public void process(Exchange exchange) throws Exception {
-        Message message = null;
+        Message message;
         if (exchange.hasOut()) {
             message = exchange.getOut();
         } else {

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerMessageValidationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerMessageValidationTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerMessageValidationTest.java
index 5c431e6..ba8ca8b 100644
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerMessageValidationTest.java
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerMessageValidationTest.java
@@ -16,6 +16,8 @@
  */
 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;
@@ -28,12 +30,9 @@ import org.apache.camel.test.junit.rule.mllp.MllpClientResource;
 import org.apache.camel.test.junit.rule.mllp.MllpJUnitResourceException;
 import org.apache.camel.test.junit.rule.mllp.MllpJUnitResourceTimeoutException;
 import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 
-import java.util.concurrent.TimeUnit;
-
 import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 import static org.apache.camel.test.mllp.Hl7MessageGenerator.generateMessage;
@@ -268,7 +267,7 @@ public class MllpTcpServerConsumerMessageValidationTest extends CamelTestSupport
         invalid.expectedMessageCount(1);
 
         for (int i = 0; i < messageCount; ++i) {
-            String message = (i == (messageCount/2))
+            String message = (i == (messageCount / 2))
                     ? generateMessage(i + 1).replaceFirst("EVN", "EVN" + START_OF_BLOCK)
                     : generateMessage(i + 1);
 
@@ -302,7 +301,7 @@ public class MllpTcpServerConsumerMessageValidationTest extends CamelTestSupport
         invalid.expectedMessageCount(1);
 
         for (int i = 0; i < messageCount; ++i) {
-            String message = (i == (messageCount/2))
+            String message = (i == (messageCount / 2))
                     ? generateMessage(i + 1).replaceFirst("EVN", "EVN" + END_OF_BLOCK)
                     : generateMessage(i + 1);
 

http://git-wip-us.apache.org/repos/asf/camel/blob/ba8f3aa0/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java
index 6d05883..9984359 100644
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java
@@ -35,8 +35,6 @@ import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Rule;
 import org.junit.Test;
 
-import java.util.concurrent.TimeUnit;
-
 import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 import static org.apache.camel.test.mllp.Hl7MessageGenerator.generateMessage;
@@ -246,7 +244,7 @@ public class MllpTcpServerConsumerTest extends CamelTestSupport {
         timeout.expectedMessageCount(0);
 
         for (int i = 0; i < messageCount; ++i) {
-            String message = (i == (messageCount/2))
+            String message = (i == (messageCount / 2))
                     ? generateMessage(i + 1).replaceFirst("EVN", "EVN" + START_OF_BLOCK)
                     : generateMessage(i + 1);
 
@@ -276,7 +274,7 @@ public class MllpTcpServerConsumerTest extends CamelTestSupport {
         timeout.expectedMessageCount(0);
 
         for (int i = 0; i < messageCount; ++i) {
-            String message = (i == (messageCount/2))
+            String message = (i == (messageCount / 2))
                     ? generateMessage(i + 1).replaceFirst("EVN", "EVN" + END_OF_BLOCK)
                     : generateMessage(i + 1);
 


[2/8] camel git commit: CAMEL-10511: Updated MllpTcpClientProducer and MllpTcpServerConsumer to consume all available data on socket

Posted by da...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketMessageReaderTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketMessageReaderTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketMessageReaderTest.java
new file mode 100644
index 0000000..9ecdcb0
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketMessageReaderTest.java
@@ -0,0 +1,527 @@
+/**
+ * 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.impl;
+
+import java.io.IOException;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+
+import org.apache.camel.component.mllp.MllpException;
+import org.apache.camel.component.mllp.MllpReceiveException;
+import org.apache.camel.component.mllp.MllpTimeoutException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.SEGMENT_DELIMITER;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+
+public class MllpSocketMessageReaderTest extends MllpSocketReaderTestSupport {
+    MllpSocketReader mllpSocketReader;
+
+    @Before
+    public void setUp() throws Exception {
+        assertSocketOpen();
+        mllpSocketReader = new MllpSocketReader(fakeSocket, 5000, 1000, false);
+    }
+
+    @Test
+    public void testReadMessage() throws Exception {
+        byte[] expected = TEST_MESSAGE.getBytes();
+
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, expected, END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testReadMessageWithSeparateEnvelopingAndMessagePackets() throws Exception {
+        byte[] expected = TEST_MESSAGE.getBytes();
+
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, TEST_MESSAGE.getBytes(), END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testReadMessageWithMultipleMessagePackets() throws Exception {
+        byte[] expected = TEST_MESSAGE.getBytes();
+
+        fakeSocket.fakeSocketInputStream
+                .addPacket(START_PACKET)
+                .addPackets(TEST_MESSAGE, SEGMENT_DELIMITER)
+                .addPacket(END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testReadEmptyMessage() throws Exception {
+        byte[] expected = new byte[0];
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testReadEmptyMessageWithSeparateEnvelopingPackets() throws Exception {
+        byte[] expected = new byte[0];
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test()
+    public void testGetInputStreamFailure() throws Exception {
+        fakeSocket.fakeSocketInputStream = null;
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpReceiveException.class);
+        } catch (MllpReceiveException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause(), instanceOf(IOException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testEndOfStreamOnInitialRead() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPackets(EMPTY_PACKET, TEST_MESSAGE);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpReceiveException.class);
+        } catch (MllpReceiveException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNull(expectedEx.getCause());
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testTimeoutOnInitialRead() throws Exception {
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(null, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testTimeoutOnInitialReadWithStartOfBlock() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPacket(START_OF_BLOCK);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpTimeoutException.class);
+        } catch (MllpTimeoutException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketTimeoutException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testSocketExceptionOnInitialRead() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPacket(EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpReceiveException.class);
+        } catch (MllpReceiveException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testIOExceptionOnInitialRead() throws Exception {
+        fakeSocket.fakeSocketInputStream.useSocketExceptionOnNullPacket = false;
+        fakeSocket.fakeSocketInputStream.addPacket(EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpReceiveException.class);
+        } catch (MllpReceiveException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(IOException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testEndOfStreamOnFirstAdditionalRead() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, EMPTY_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpReceiveException.class);
+        } catch (MllpReceiveException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNull(expectedEx.getCause());
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testEndOfStreamOnFirstAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, TEST_MESSAGE.getBytes()).addPacket(EMPTY_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpReceiveException.class);
+        } catch (MllpReceiveException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNull(expectedEx.getCause());
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testTimeoutOnFirstAdditionalRead() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpTimeoutException.class);
+        } catch (MllpTimeoutException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketTimeoutException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testTimeoutOnFirstAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, TEST_MESSAGE.getBytes());
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpTimeoutException.class);
+        } catch (MllpTimeoutException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketTimeoutException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testSocketExceptionOnFirstAdditionalRead() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpReceiveException.class);
+        } catch (MllpReceiveException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testSocketExceptionOnFirstAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, TEST_MESSAGE.getBytes()).addPacket(EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpReceiveException.class);
+        } catch (MllpReceiveException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testIOExceptionOnFirstAdditionalRead() throws Exception {
+        fakeSocket.fakeSocketInputStream.useSocketExceptionOnNullPacket = false;
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpReceiveException.class);
+        } catch (MllpReceiveException expectedEx) {
+            assertEmptyExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(IOException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testIOExceptionOnFirstAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.useSocketExceptionOnNullPacket = false;
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, TEST_MESSAGE.getBytes()).addPacket(EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpReceiveException.class);
+        } catch (MllpReceiveException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(IOException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testEndOfStreamOnSecondAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, TEST_MESSAGE.getBytes(), EMPTY_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpReceiveException.class);
+        } catch (MllpReceiveException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNull(expectedEx.getCause());
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testTimeoutOnSecondAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, TEST_MESSAGE.getBytes());
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpTimeoutException.class);
+        } catch (MllpTimeoutException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketTimeoutException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testSocketExceptionOnSecondAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, TEST_MESSAGE.getBytes(), EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpReceiveException.class);
+        } catch (MllpReceiveException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(SocketException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testIOExceptionOnSecondAdditionalReadWithPartialPayload() throws Exception {
+        fakeSocket.fakeSocketInputStream.useSocketExceptionOnNullPacket = false;
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, TEST_MESSAGE.getBytes(), EXCEPTION_PACKET);
+
+        try {
+            mllpSocketReader.readEnvelopedPayload();
+
+            expectedExceptionFailure(MllpReceiveException.class);
+        } catch (MllpReceiveException expectedEx) {
+            assertExpectedException(expectedEx);
+            assertNotNull(expectedEx.getCause());
+            assertThat(expectedEx.getCause().getClass(), sameInstance(IOException.class));
+            assertSocketReset();
+        }
+    }
+
+    @Test
+    public void testLeadingOutOfBandBytes() throws Exception {
+        byte[] expected = TEST_MESSAGE.getBytes();
+
+        fakeSocket.fakeSocketInputStream.addPacket("Junk".getBytes(), START_PACKET, expected, END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+    }
+
+    @Test
+    public void testLeadingOutOfBandBytesWithEmptyMessage() throws Exception {
+        byte[] expected = new byte[0];
+        fakeSocket.fakeSocketInputStream.addPacket("Junk".getBytes(), START_PACKET, END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testLeadingOutOfBandBytesWithEmptyMessageWithSeparateEnvelopingPackets() throws Exception {
+        byte[] expected = new byte[0];
+        fakeSocket.fakeSocketInputStream.addPackets("Junk".getBytes(), START_PACKET, END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testLeadingOutOfBandBytesSeparateEnvelopingAndMessagePackets() throws Exception {
+        byte[] expected = TEST_MESSAGE.getBytes();
+
+        fakeSocket.fakeSocketInputStream.addPackets("Junk".getBytes(), START_PACKET, TEST_MESSAGE.getBytes(), END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testLeadingOutOfBandBytesWithMultipleMessagePackets() throws Exception {
+        byte[] expected = TEST_MESSAGE.getBytes();
+
+        fakeSocket.fakeSocketInputStream
+                .addPacket("Junk")
+                .addPacket(START_PACKET)
+                .addPackets(TEST_MESSAGE, SEGMENT_DELIMITER)
+                .addPacket(END_PACKET);
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testTrailingOutOfBandBytes() throws Exception {
+        byte[] expected = TEST_MESSAGE.getBytes();
+
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, expected, END_PACKET, "Junk".getBytes());
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+    }
+
+    @Test
+    public void testTrailingOutOfBandBytesWithEmptyMessage() throws Exception {
+        byte[] expected = new byte[0];
+        fakeSocket.fakeSocketInputStream.addPacket(START_PACKET, END_PACKET, "Junk".getBytes());
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testTrailingOutOfBandBytesWithEmptyMessageWithSeparateEnvelopingPackets() throws Exception {
+        byte[] expected = new byte[0];
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, END_PACKET, "Junk".getBytes());
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testTrailingOutOfBandBytesSeparateEnvelopingAndMessagePackets() throws Exception {
+        byte[] expected = TEST_MESSAGE.getBytes();
+
+        fakeSocket.fakeSocketInputStream.addPackets(START_PACKET, TEST_MESSAGE.getBytes(), END_PACKET, "Junk".getBytes());
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    @Test
+    public void testTrailingOutOfBandBytesWithMultipleMessagePackets() throws Exception {
+        byte[] expected = TEST_MESSAGE.getBytes();
+
+        fakeSocket.fakeSocketInputStream
+                .addPacket(START_PACKET)
+                .addPackets(TEST_MESSAGE, SEGMENT_DELIMITER)
+                .addPacket(END_PACKET)
+                .addPacket("Junk");
+
+        byte[] actual = mllpSocketReader.readEnvelopedPayload();
+
+        assertArrayEquals(expected, actual);
+        assertSocketOpen();
+    }
+
+    private void assertEmptyExpectedException(MllpException expectedEx) {
+        assertNotNull(expectedEx);
+        assertNotNull(expectedEx.getMessage());
+        assertNull(expectedEx.getHl7Message());
+        assertNull(expectedEx.getHl7Acknowledgement());
+        assertNull(expectedEx.getMllpPayload());
+    }
+
+    private void assertExpectedException(MllpException expectedEx) {
+        assertNotNull(expectedEx);
+        assertNotNull(expectedEx.getMessage());
+        assertArrayEquals(TEST_MESSAGE.getBytes(), expectedEx.getHl7Message());
+        assertNull(expectedEx.getHl7Acknowledgement());
+        assertArrayEquals(TEST_MESSAGE.getBytes(), expectedEx.getMllpPayload());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketMessageWriterTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketMessageWriterTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketMessageWriterTest.java
new file mode 100644
index 0000000..8e02bf9
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketMessageWriterTest.java
@@ -0,0 +1,150 @@
+/**
+ * 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.impl;
+
+import org.apache.camel.component.mllp.MllpWriteException;
+import org.apache.camel.test.util.PayloadBuilder;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+import static org.apache.camel.component.mllp.impl.MllpSocketWriter.PAYLOAD_TERMINATOR;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class MllpSocketMessageWriterTest extends MllpSocketWriterTestSupport {
+    MllpSocketWriter mllpSocketWriter;
+
+    @Before
+    public void setUp() throws Exception {
+        mllpSocketWriter = new MllpSocketWriter(fakeSocket, false);
+    }
+
+    @Test
+    public void testWriteMessage() throws Exception {
+        byte[] expected = PayloadBuilder.build(START_OF_BLOCK, TEST_MESSAGE, END_OF_BLOCK, END_OF_DATA);
+
+        mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), null);
+
+        assertArrayEquals(expected, fakeSocket.payload());
+    }
+
+    @Test
+    public void testWriteNullMessage() throws Exception {
+        byte[] message = null;
+
+        byte[] expected = PayloadBuilder.build(START_OF_BLOCK, END_OF_BLOCK, END_OF_DATA);
+
+        mllpSocketWriter.writeEnvelopedPayload(message, null);
+
+        assertArrayEquals(expected, fakeSocket.payload());
+    }
+
+    @Test
+    public void testWriteEmptyMessage() throws Exception {
+        byte[] message = new byte[0];
+
+        byte[] expected = PayloadBuilder.build(START_OF_BLOCK, END_OF_BLOCK, END_OF_DATA);
+
+        mllpSocketWriter.writeEnvelopedPayload(message, null);
+
+        assertArrayEquals(expected, fakeSocket.payload());
+    }
+
+    @Test(expected = MllpWriteException.class)
+    public void testGetOutputStreamFailure() throws Exception {
+        fakeSocket.fakeSocketOutputStream = null;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), null);
+        } catch (MllpWriteException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpWriteException.class)
+    public void testWriteToUnconnectedSocket() throws Exception {
+        fakeSocket.connected = false;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), null);
+        } catch (MllpWriteException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpWriteException.class)
+    public void testWriteToClosedSocket() throws Exception {
+        fakeSocket.closed = true;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), null);
+        } catch (MllpWriteException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpWriteException.class)
+    public void testWriteStartOfBlockFailure() throws Exception {
+        fakeSocket.fakeSocketOutputStream.writeFailOn = new Byte((byte) START_OF_BLOCK);
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), null);
+        } catch (MllpWriteException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpWriteException.class)
+    public void testWriteMessageFailure() throws Exception {
+        fakeSocket.fakeSocketOutputStream.writeArrayFailOn = TEST_MESSAGE.getBytes();
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), null);
+        } catch (MllpWriteException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    @Test(expected = MllpWriteException.class)
+    public void testWriteEndOfMessageFailure() throws Exception {
+        fakeSocket.fakeSocketOutputStream.writeArrayFailOn = PAYLOAD_TERMINATOR;
+
+        try {
+            mllpSocketWriter.writeEnvelopedPayload(TEST_MESSAGE.getBytes(), null);
+        } catch (MllpWriteException expectedEx) {
+            verifyException(expectedEx);
+            throw expectedEx;
+        }
+    }
+
+    private void verifyException(MllpWriteException expectedEx) throws Exception {
+        assertNotNull(expectedEx.getMessage());
+        assertArrayEquals(TEST_MESSAGE.getBytes(), expectedEx.getHl7Message());
+        assertNull(expectedEx.getHl7Acknowledgement());
+        assertArrayEquals(TEST_MESSAGE.getBytes(), expectedEx.getMllpPayload());
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketReaderTestSupport.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketReaderTestSupport.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketReaderTestSupport.java
new file mode 100644
index 0000000..11a4cfe
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketReaderTestSupport.java
@@ -0,0 +1,342 @@
+/**
+ * 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.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.StringTokenizer;
+
+import org.apache.camel.test.util.PayloadBuilder;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public abstract class MllpSocketReaderTestSupport {
+    static final String TEST_MESSAGE =
+        "MSH|^~\\&|ADT|EPIC|JCAPS|CC|20161206193919|RISTECH|ADT^A08|00001|D|2.3^^|||||||" + '\r'
+            + "EVN|A08|20150107161440||REG_UPDATE_SEND_VISIT_MESSAGES_ON_PATIENT_CHANGES|RISTECH^RADIOLOGY^TECHNOLOGIST^^^^^^UCLA^^^^^RRMC||" + '\r'
+            + "PID|1|2100355^^^MRN^MRN|2100355^^^MRN^MRN||MDCLS9^MC9||19700109|F||U|111 HOVER STREET^^LOS ANGELES^CA^90032^USA^P^^LOS ANGELE|LOS ANGELE|"
+                + "(310)725-6952^P^PH^^^310^7256952||ENGLISH|U||60000013647|565-33-2222|||U||||||||N||" + '\r'
+            + "PD1|||UCLA HEALTH SYSTEM^^10|10002116^ADAMS^JOHN^D^^^^^EPIC^^^^PROVID||||||||||||||" + '\r'
+            + "NK1|1|DOE^MC9^^|OTH|^^^^^USA|(310)888-9999^^^^^310^8889999|(310)999-2222^^^^^310^9992222|Emergency Contact 1|||||||||||||||||||||||||||" + '\r'
+            + "PV1|1|OUTPATIENT|RR CT^^^1000^^^^^^^DEPID|EL|||017511^TOBIAS^JONATHAN^^^^^^EPIC^^^^PROVID|017511^TOBIAS^JONATHAN^^^^^^EPIC^^^^PROVID||||||"
+                + "CLR|||||60000013647|SELF|||||||||||||||||||||HOV_CONF|^^^1000^^^^^^^||20150107161438||||||||||" + '\r'
+            + "PV2||||||||20150107161438||||CT BRAIN W WO CONTRAST||||||||||N|||||||||||||||||||||||||||" + '\r'
+            + "ZPV||||||||||||20150107161438|||||||||" + '\r'
+            + "AL1|1||33361^NO KNOWN ALLERGIES^^NOTCOMPUTRITION^NO KNOWN ALLERGIES^EXTELG||||||" + '\r'
+            + "DG1|1|DX|784.0^Headache^DX|Headache||VISIT" + '\r'
+            + "GT1|1|1000235129|MDCLS9^MC9^^||111 HOVER STREET^^LOS ANGELES^CA^90032^USA^^^LOS ANGELE|(310)725-6952^^^^^310^7256952||19700109|F|P/F|SLF|"
+                + "565-33-2222|||||^^^^^USA|||UNKNOWN|||||||||||||||||||||||||||||" + '\r'
+            + "UB2||||||||" + '\r'
+            + '\n';
+
+    static final String TEST_ACKNOWLEDGEMENT =
+        "MSH|^~\\&|JCAPS|CC|ADT|EPIC|20161206193919|RISTECH|ACK^A08|00001|D|2.3^^|||||||" + '\r'
+            + "MSA|AA|00001|" + '\r'
+            + '\n';
+
+    static final byte[] EXCEPTION_PACKET = null;
+    static final byte[] EMPTY_PACKET = new byte[0];
+    static final byte[] START_PACKET = PayloadBuilder.build(START_OF_BLOCK);
+    static final byte[] END_PACKET = PayloadBuilder.build(END_OF_BLOCK, END_OF_DATA);
+
+    FakeSocket fakeSocket = new FakeSocket();
+
+    void assertSocketOpen() throws Exception {
+        assertTrue("socket should have been connected", fakeSocket.connected);
+        assertFalse("shutdownInput() should not have been called", fakeSocket.inputShutdown);
+        assertFalse("shutdownOutput() should not have been called", fakeSocket.outputShutdown);
+        assertFalse("close() should not have been called", fakeSocket.closed);
+        assertNotNull("socket should have an input stream", fakeSocket.fakeSocketInputStream);
+    }
+
+    void assertSocketClosed() throws Exception {
+        assertTrue("socket should have been connected", fakeSocket.connected);
+        assertTrue("shutdownInput() should have been called", fakeSocket.inputShutdown);
+        assertTrue("shutdownOutput() should have been called", fakeSocket.outputShutdown);
+        assertTrue("close() should have been called", fakeSocket.closed);
+        assertFalse("SO_LINGER should not be enabled", fakeSocket.linger);
+    }
+
+    void assertSocketReset() throws Exception {
+        assertTrue("socket should have been connected", fakeSocket.connected);
+        assertTrue("close() should have been called", fakeSocket.closed);
+        assertTrue("SO_LINGER should be enabled", fakeSocket.linger);
+        assertEquals("SO_LINGER timeout should be 0", 0, fakeSocket.lingerTimeout);
+    }
+
+    <E extends Exception> void expectedExceptionFailure(Class<E> expected) throws Exception {
+        fail("Expected exception " + expected.getName() + " was not thrown");
+    }
+
+    class FakeSocket extends Socket {
+        boolean connected = true;
+        boolean inputShutdown;
+        boolean outputShutdown;
+        boolean closed;
+        int receiveBufferSize = 1024;
+        int sendBufferSize = 1024;
+        int timeout = 1000;
+        boolean linger;
+        int lingerTimeout = 1024;
+        FakeSocketInputStream fakeSocketInputStream = new FakeSocketInputStream();
+
+        FakeSocket() {
+        }
+
+        @Override
+        public boolean isConnected() {
+            return connected;
+        }
+
+        @Override
+        public boolean isInputShutdown() {
+            return inputShutdown;
+        }
+
+        @Override
+        public boolean isOutputShutdown() {
+            return outputShutdown;
+        }
+
+        @Override
+        public boolean isClosed() {
+            return closed;
+        }
+
+        @Override
+        public void shutdownInput() throws IOException {
+            inputShutdown = true;
+        }
+
+        @Override
+        public void shutdownOutput() throws IOException {
+            outputShutdown = true;
+        }
+
+        @Override
+        public synchronized void close() throws IOException {
+            closed = true;
+        }
+
+        @Override
+        public int getSoLinger() throws SocketException {
+            if (linger) {
+                return lingerTimeout;
+            }
+
+            return -1;
+        }
+
+        @Override
+        public void setSoLinger(boolean on, int linger) throws SocketException {
+            this.linger = on;
+            this.lingerTimeout = linger;
+        }
+
+        @Override
+        public synchronized int getReceiveBufferSize() throws SocketException {
+            return receiveBufferSize;
+        }
+
+        @Override
+        public synchronized void setReceiveBufferSize(int size) throws SocketException {
+            this.receiveBufferSize = size;
+        }
+
+        @Override
+        public synchronized int getSendBufferSize() throws SocketException {
+            return sendBufferSize;
+        }
+
+        @Override
+        public synchronized void setSendBufferSize(int size) throws SocketException {
+            this.sendBufferSize = size;
+        }
+
+        @Override
+        public synchronized int getSoTimeout() throws SocketException {
+            return timeout;
+        }
+
+        @Override
+        public synchronized void setSoTimeout(int timeout) throws SocketException {
+            this.timeout = timeout;
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            if (fakeSocketInputStream == null) {
+                throw new IOException("Faking getInputStream failure");
+            }
+            return fakeSocketInputStream;
+        }
+
+    }
+
+    class FakeSocketInputStream extends InputStream {
+        boolean useSocketExceptionOnNullPacket = true;
+        private Queue<ByteArrayInputStream> packetQueue = new LinkedList<>();
+
+        FakeSocketInputStream() {
+        }
+
+        @Override
+        public int read() throws IOException {
+            if (packetQueue.size() > 0) {
+                if (packetQueue.peek() == null) {
+                    if (useSocketExceptionOnNullPacket) {
+                        throw new SocketException("Faking Socket read() failure - simulating reset");
+                    } else {
+                        throw new IOException("Faking Socket read() failure");
+                    }
+                }
+                int answer = packetQueue.element().read();
+                if (answer == -1 || packetQueue.element().available() == 0) {
+                    packetQueue.remove();
+                }
+                return answer;
+            }
+
+            throw new SocketTimeoutException("Faking Socket read() Timeout");
+        }
+
+        @Override
+        public int read(byte[] buffer) throws IOException {
+            if (packetQueue.size() > 0) {
+                if (packetQueue.peek() == null) {
+                    if (useSocketExceptionOnNullPacket) {
+                        throw new SocketException("Faking Socket read(byte[]) failure - simulating reset");
+                    } else {
+                        throw new IOException("Faking Socket read(byte[]) failure");
+                    }
+                }
+                int answer = packetQueue.element().read(buffer);
+                if (answer == -1 || packetQueue.element().available() == 0) {
+                    packetQueue.remove();
+                }
+                return answer;
+            }
+
+            throw new SocketTimeoutException("Faking Socket read(byte[]) Timeout");
+        }
+
+        @Override
+        public int read(byte[] buffer, int offset, int length) throws IOException {
+            if (packetQueue.size() > 0) {
+                if (packetQueue.peek() == null) {
+                    if (useSocketExceptionOnNullPacket) {
+                        throw new SocketException("Faking Socket read(byte[], int, int) failure - simulating reset");
+                    } else {
+                        throw new IOException("Faking Socket read(byte[], int, int) failure");
+                    }
+                }
+                int answer = packetQueue.element().read(buffer, offset, length);
+                if (answer == -1 || packetQueue.element().available() == 0) {
+                    packetQueue.remove();
+                }
+
+                return answer;
+            }
+
+            throw new SocketTimeoutException("Faking Socket read(byte[], int, int) Timeout");
+        }
+
+        @Override
+        public int available() throws IOException {
+            if (packetQueue.size() > 0) {
+                return packetQueue.element().available();
+            }
+
+            return 0;
+        }
+
+        public FakeSocketInputStream addPacket(char... packet) {
+            this.packetQueue.add(new ByteArrayInputStream(PayloadBuilder.build(packet)));
+
+            return this;
+        }
+
+        public FakeSocketInputStream addPacket(byte[] bytes) throws IOException {
+            if (bytes != null) {
+                this.packetQueue.add(new ByteArrayInputStream(bytes));
+            } else {
+                this.packetQueue.add(null);
+            }
+
+            return this;
+        }
+
+        public FakeSocketInputStream addPacket(byte[] bytes, byte[]... byteArrays) throws IOException {
+            PayloadBuilder builder = new PayloadBuilder(bytes);
+            for (byte[] additionalBytes : byteArrays) {
+                builder.append(additionalBytes);
+            }
+            this.packetQueue.add(new ByteArrayInputStream(builder.build()));
+
+            return this;
+        }
+
+        public FakeSocketInputStream addPacket(String... strings) throws IOException {
+            this.packetQueue.add(new ByteArrayInputStream(PayloadBuilder.build(strings)));
+
+            return this;
+        }
+
+        public FakeSocketInputStream addPackets(String message, char delimiter) throws IOException {
+            StringTokenizer tokenizer = new StringTokenizer(message, String.valueOf(delimiter), true);
+            while (tokenizer.hasMoreTokens()) {
+                addPacket(tokenizer.nextToken());
+            }
+
+            return this;
+        }
+
+        public FakeSocketInputStream addPackets(char... packets) {
+            for (char c : packets) {
+                addPacket(c);
+            }
+
+            return this;
+        }
+
+        public FakeSocketInputStream addPackets(byte[]... packets) throws IOException {
+            for (byte[] packet : packets) {
+                addPacket(packet);
+            }
+
+            return this;
+        }
+
+        public FakeSocketInputStream addPackets(byte[] bytes, String s) throws IOException {
+            return addPacket(bytes).addPacket(s);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketUtilExceptionHandlingTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketUtilExceptionHandlingTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketUtilExceptionHandlingTest.java
new file mode 100644
index 0000000..543b028
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketUtilExceptionHandlingTest.java
@@ -0,0 +1,133 @@
+/**
+ * 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.impl;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.net.SocketException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.Assert.assertTrue;
+
+public class MllpSocketUtilExceptionHandlingTest {
+    Logger logger = LoggerFactory.getLogger(this.getClass());
+    Socket socket;
+
+    @Before
+    public void setUp() throws Exception {
+        socket = new FakeSocket();
+    }
+
+    @Test
+    public void testClose() throws Exception {
+        MllpSocketUtil.close(socket, null, null);
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+    @Test
+    public void testCloseWithLogger() throws Exception {
+        MllpSocketUtil.close(socket, logger, null);
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+    @Test
+    public void testCloseWithLoggerAndReason() throws Exception {
+        MllpSocketUtil.close(socket, logger, "Testing " + this.getClass().getSimpleName() + ".close(...)");
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+
+    @Test
+    public void testReset() throws Exception {
+        MllpSocketUtil.reset(socket, null, null);
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+    @Test
+    public void testResetWithLogger() throws Exception {
+        MllpSocketUtil.reset(socket, logger, null);
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+    @Test
+    public void testResetWithLoggerAndReason() throws Exception {
+        MllpSocketUtil.reset(socket, logger, "Testing " + this.getClass().getSimpleName() + ".reset(...)");
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+
+    // Utility Methods
+
+    class FakeSocket extends Socket {
+        boolean connected = true;
+        boolean closed;
+
+        FakeSocket() {
+        }
+
+        @Override
+        public boolean isInputShutdown() {
+            return false;
+        }
+
+        @Override
+        public boolean isOutputShutdown() {
+            return false;
+        }
+
+        @Override
+        public void setSoLinger(boolean on, int linger) throws SocketException {
+            throw new SocketException("Faking a setSoLinger failure");
+        }
+
+        @Override
+        public void shutdownInput() throws IOException {
+            throw new IOException("Faking a shutdownInput failure");
+        }
+
+        @Override
+        public void shutdownOutput() throws IOException {
+            throw new IOException("Faking a shutdownOutput failure");
+        }
+
+        @Override
+        public boolean isConnected() {
+            return connected;
+        }
+
+        @Override
+        public boolean isClosed() {
+            return closed;
+        }
+
+        @Override
+        public synchronized void close() throws IOException {
+            closed = true;
+            throw new IOException("Faking a close failure");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketUtilFindXxxOfBlockTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketUtilFindXxxOfBlockTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketUtilFindXxxOfBlockTest.java
new file mode 100644
index 0000000..31704a5
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketUtilFindXxxOfBlockTest.java
@@ -0,0 +1,241 @@
+/**
+ * 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.impl;
+
+import org.apache.camel.test.util.PayloadBuilder;
+import org.junit.Test;
+
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+import static org.junit.Assert.assertEquals;
+
+public class MllpSocketUtilFindXxxOfBlockTest {
+    static final String HL7_PAYLOAD_STRING =
+            "MSH|^~\\&|JCAPS|CC|ADT|EPIC|20161206193919|RISTECH|ACK^A08|00001|D|2.3^^|||||||" + '\r'
+                    + "MSA|AA|00001|" + '\r'
+                    + '\n';
+
+    @Test
+    public void testFindStartOfBlockWithDummyPayload() throws Exception {
+        byte[] payload = PayloadBuilder.build(START_OF_BLOCK, "Dummy non-hl7 payload", END_OF_BLOCK, END_OF_DATA);
+
+        int actual = MllpSocketUtil.findStartOfBlock(payload);
+
+        assertEquals(0, actual);
+    }
+
+    @Test
+    public void testFindStartOfBlockWithHl7Payload() throws Exception {
+        byte[] payload = PayloadBuilder.build(START_OF_BLOCK, HL7_PAYLOAD_STRING, END_OF_BLOCK, END_OF_DATA);
+
+        int actual = MllpSocketUtil.findStartOfBlock(payload);
+
+        assertEquals(0, actual);
+    }
+
+    @Test
+    public void testFindStartOfBlockWithNullPayload() throws Exception {
+        int actual = MllpSocketUtil.findStartOfBlock(null, 12345);
+
+        assertEquals(-1, actual);
+    }
+
+    @Test
+    public void testFindStartOfBlockWithOnlyStartOfBlock() throws Exception {
+        byte[] payload = PayloadBuilder.build(START_OF_BLOCK);
+
+        int actual = MllpSocketUtil.findStartOfBlock(payload);
+
+        assertEquals(0, actual);
+    }
+
+    @Test
+    public void testFindStartOfBlockWithStartOfBlockAfterLength() throws Exception {
+        byte[] payload = PayloadBuilder.build(HL7_PAYLOAD_STRING, END_OF_BLOCK, END_OF_DATA, START_OF_BLOCK);
+
+        int actual = MllpSocketUtil.findStartOfBlock(payload, payload.length - 1);
+
+        assertEquals(-1, actual);
+    }
+
+    @Test
+    public void testFindStartOfBlockWithMissingStartOfBlock() throws Exception {
+        byte[] payload = PayloadBuilder.build(HL7_PAYLOAD_STRING, END_OF_BLOCK, END_OF_DATA);
+
+        int actual = MllpSocketUtil.findStartOfBlock(payload);
+
+        assertEquals(-1, actual);
+    }
+
+    @Test
+    public void testFindStartOfBlockWithLengthLargerThanArraySize() throws Exception {
+        byte[] payload = PayloadBuilder.build(START_OF_BLOCK, HL7_PAYLOAD_STRING, END_OF_BLOCK, END_OF_DATA);
+
+        int actual = MllpSocketUtil.findStartOfBlock(payload, payload.length + 1);
+
+        assertEquals(0, actual);
+    }
+
+    @Test
+    public void testFindStartOfBlockWithLengthSmallerThanArraySize() throws Exception {
+        byte[] payload = PayloadBuilder.build(START_OF_BLOCK, HL7_PAYLOAD_STRING, END_OF_BLOCK, END_OF_DATA);
+
+        int actual = MllpSocketUtil.findStartOfBlock(payload, payload.length - 2);
+
+        assertEquals(0, actual);
+    }
+
+    @Test
+    public void testFindEndOfMessageWithDummyPayload() throws Exception {
+        final byte[] dummyPayload = "Dummy non-hl7 payload".getBytes();
+        byte[] payload = PayloadBuilder.build(dummyPayload, END_OF_BLOCK, END_OF_DATA);
+
+        int expected = dummyPayload.length;
+        int actual = MllpSocketUtil.findEndOfMessage(payload);
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testFindEndOfMessageWithDummyPayloadAndStartOfBlock() throws Exception {
+        final byte[] dummyPayload = "Dummy non-hl7 payload".getBytes();
+        byte[] payload = PayloadBuilder.build(START_OF_BLOCK, dummyPayload, END_OF_BLOCK, END_OF_DATA);
+
+        int expected = dummyPayload.length + 1;
+        int actual = MllpSocketUtil.findEndOfMessage(payload);
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testFindEndOfMessageWithHl7Payload() throws Exception {
+        byte[] payload = PayloadBuilder.build(HL7_PAYLOAD_STRING, END_OF_BLOCK, END_OF_DATA);
+
+        int expected = HL7_PAYLOAD_STRING.length();
+        int actual = MllpSocketUtil.findEndOfMessage(payload);
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testFindEndOfMessageWithHl7PayloadAndStartOfBlock() throws Exception {
+        byte[] payload = PayloadBuilder.build(START_OF_BLOCK, HL7_PAYLOAD_STRING, END_OF_BLOCK, END_OF_DATA);
+
+        int expected = HL7_PAYLOAD_STRING.length() + 1;
+        int actual = MllpSocketUtil.findEndOfMessage(payload);
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testFindEndOfMessageWithNullPayload() throws Exception {
+        assertEquals(-1, MllpSocketUtil.findEndOfMessage(null, 12345));
+    }
+
+    @Test
+    public void testFindEndOfMessagekWithOnlyEndOfBlock() throws Exception {
+        byte[] payload = PayloadBuilder.build(END_OF_BLOCK);
+
+        int actual = MllpSocketUtil.findEndOfMessage(payload);
+
+        assertEquals(-1, actual);
+    }
+
+    @Test
+    public void testFindEndOfMessagekWithOnlyEndOfData() throws Exception {
+        byte[] payload = PayloadBuilder.build(END_OF_DATA);
+
+        int actual = MllpSocketUtil.findEndOfMessage(payload);
+
+        assertEquals(-1, actual);
+    }
+
+    @Test
+    public void testFindEndOfMessagekWithOnlyEndOfBlockAndEndOfData() throws Exception {
+        byte[] payload = PayloadBuilder.build(END_OF_BLOCK, END_OF_DATA);
+
+        int actual = MllpSocketUtil.findEndOfMessage(payload);
+
+        assertEquals(0, actual);
+    }
+
+    @Test
+    public void testFindEndOfMessageWithEndOfBlockAfterLength() throws Exception {
+        byte[] payload = PayloadBuilder.build(HL7_PAYLOAD_STRING, END_OF_BLOCK, END_OF_DATA);
+
+        int actual = MllpSocketUtil.findEndOfMessage(payload, payload.length - 2);
+
+        assertEquals(-1, actual);
+    }
+
+    @Test
+    public void testFindEndOfMessageWithMissingEndOfBlock() throws Exception {
+        byte[] payload = PayloadBuilder.build(HL7_PAYLOAD_STRING, END_OF_DATA);
+
+        int actual = MllpSocketUtil.findEndOfMessage(payload);
+
+        assertEquals(-1, actual);
+    }
+
+    @Test
+    public void testFindEndOfMessageWithEndOfBlockButMissingEndOfData() throws Exception {
+        byte[] payload = PayloadBuilder.build(HL7_PAYLOAD_STRING, END_OF_BLOCK);
+
+        int actual = MllpSocketUtil.findEndOfMessage(payload);
+
+        assertEquals(-1, actual);
+    }
+
+    @Test
+    public void testFindEndOfMessageWithStartOfBlockButMissingEndOfBlock() throws Exception {
+        byte[] payload = PayloadBuilder.build(START_OF_BLOCK, HL7_PAYLOAD_STRING, END_OF_DATA);
+
+        int actual = MllpSocketUtil.findEndOfMessage(payload);
+
+        assertEquals(-1, actual);
+    }
+
+    @Test
+    public void testFindEndOfMessageWithStartOfBlockAndEndOfBlockButMissingEndOfData() throws Exception {
+        byte[] payload = PayloadBuilder.build(START_OF_BLOCK, HL7_PAYLOAD_STRING, END_OF_BLOCK);
+
+        int actual = MllpSocketUtil.findEndOfMessage(payload);
+
+        assertEquals(-1, actual);
+    }
+
+    @Test
+    public void testFindEndOfMessageWithLengthLargerThanArraySize() throws Exception {
+        byte[] payload = PayloadBuilder.build(START_OF_BLOCK, HL7_PAYLOAD_STRING, END_OF_BLOCK, END_OF_DATA);
+
+        int expected = HL7_PAYLOAD_STRING.length() + 1;
+        int actual = MllpSocketUtil.findEndOfMessage(payload, payload.length + 1);
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testFindEndOfMessageWithLengthSmallerThanArraySize() throws Exception {
+        byte[] payload = PayloadBuilder.build(START_OF_BLOCK, HL7_PAYLOAD_STRING, END_OF_BLOCK, END_OF_DATA);
+
+        int actual = MllpSocketUtil.findEndOfMessage(payload, payload.length - 1);
+
+        assertEquals(-1, actual);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketUtilSocketTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketUtilSocketTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketUtilSocketTest.java
new file mode 100644
index 0000000..9f7007c
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketUtilSocketTest.java
@@ -0,0 +1,288 @@
+/**
+ * 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.impl;
+
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class MllpSocketUtilSocketTest {
+    Logger logger = LoggerFactory.getLogger(this.getClass());
+    ServerSocket serverSocket;
+    Socket socket;
+
+    @Before
+    public void setUp() throws Exception {
+        serverSocket = new ServerSocket(0);
+        socket = new Socket();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (socket != null) {
+            socket.close();
+        }
+        serverSocket.close();
+    }
+
+    @Test
+    public void testSetSoTimeout() throws Exception {
+        final int expected = 1000;
+
+        connect();
+
+        MllpSocketUtil.setSoTimeout(socket, expected, null, null);
+
+        assertEquals(expected, socket.getSoTimeout());
+    }
+
+    @Test
+    public void testSetSoTimeoutWithLogger() throws Exception {
+        final int expected = 1000;
+
+        connect();
+
+        MllpSocketUtil.setSoTimeout(socket, expected, logger, null);
+
+        assertEquals(expected, socket.getSoTimeout());
+    }
+
+    @Test
+    public void testSetSoTimeoutWithLoggerAndReason() throws Exception {
+        final int expected = 1000;
+
+        connect();
+
+        MllpSocketUtil.setSoTimeout(socket, expected, logger, "Testing setSoTimeout");
+
+        assertEquals(expected, socket.getSoTimeout());
+    }
+
+    @Test
+    public void testSetSoTimeoutWithUnconnectedSocket() throws Exception {
+        int expected = 1000;
+
+        MllpSocketUtil.setSoTimeout(socket, expected, logger, "Testing setSoTimeout with unconnected Socket");
+
+        assertEquals(expected, socket.getSoTimeout());
+    }
+
+    @Test
+    public void testSetSoTimeoutWithClosedSocket() throws Exception {
+        int expected = 1000;
+
+        connect();
+        close();
+
+        MllpSocketUtil.setSoTimeout(socket, expected, logger, "Testing setSoTimeout with closed Socket");
+
+        // We can't get the SO_TIMEOUT from a closed socket (Socket.getSoTimeout() will throw a SocketException
+        // assertEquals(expected, socket.getSoTimeout());
+    }
+
+    @Test
+    public void testSetSoTimeoutWithResetSocket() throws Exception {
+        int expected = 1000;
+
+        connect();
+        close();
+
+        MllpSocketUtil.close(socket, null, null);
+
+        MllpSocketUtil.setSoTimeout(socket, expected, logger, "Testing setSoTimeout with reset Socket");
+
+        // We can't get the SO_TIMEOUT from a closed socket (Socket.getSoTimeout() will throw a SocketException
+        // assertEquals(expected, socket.getSoTimeout());
+    }
+
+    @Test
+    public void testClose() throws Exception {
+        connect();
+
+        MllpSocketUtil.close(socket, null, null);
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+    @Test
+    public void testCloseWithLogger() throws Exception {
+        connect();
+
+        MllpSocketUtil.close(socket, logger, null);
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+    @Test
+    public void testCloseWithLoggerAndReason() throws Exception {
+        connect();
+
+        MllpSocketUtil.close(socket, logger, "Testing close");
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+    @Test
+    public void testCloseWithUnconnectedSocket() throws Exception {
+        MllpSocketUtil.close(socket, logger, "Testing close with unconnected Socket");
+
+        assertFalse("Socket should NOT closed because it was never connected", socket.isClosed());
+    }
+
+    @Test
+    public void testCloseWithClosedSocket() throws Exception {
+        connect();
+        close();
+
+        MllpSocketUtil.close(socket, logger, "Testing close with closed Socket");
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+    @Test
+    public void testCloseWithResetSocket() throws Exception {
+        connect();
+        reset();
+
+        MllpSocketUtil.close(socket, logger, "Testing close with reset Socket");
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+    @Test
+    public void testReset() throws Exception {
+        connect();
+
+        MllpSocketUtil.reset(socket, null, null);
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+    @Test
+    public void testResetWithLogger() throws Exception {
+        connect();
+
+        MllpSocketUtil.reset(socket, logger, null);
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+    @Test
+    public void testResetWithLoggerAndReason() throws Exception {
+        connect();
+
+        MllpSocketUtil.reset(socket, logger, "Testing reset");
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+    @Test
+    public void testResetWithUnconnectedSocket() throws Exception {
+        MllpSocketUtil.reset(socket, logger, "Testing reset with unconnected Socket");
+
+        assertFalse("Socket should NOT closed because it was never connected", socket.isClosed());
+    }
+
+    @Test
+    public void testResetWithClosedSocket() throws Exception {
+        connect();
+        close();
+
+        MllpSocketUtil.reset(socket, logger, "Testing reset with closed Socket");
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+    @Test
+    public void testResetWithResetSocket() throws Exception {
+        connect();
+        reset();
+
+        MllpSocketUtil.reset(socket, logger, "Testing reset with reset Socket");
+
+        assertTrue("Socket should be closed", socket.isClosed());
+    }
+
+    @Test
+    public void testGetAddressString() throws Exception {
+        connect();
+
+        String address = MllpSocketUtil.getAddressString(socket);
+
+        assertNotNull("Should have an address string", address);
+    }
+
+    @Test
+    public void testGetAddressStringWithUnconnectedSocket() throws Exception {
+        String address = MllpSocketUtil.getAddressString(socket);
+
+        assertNotNull("Should have an address string", address);
+    }
+
+    @Test
+    public void testGetAddressStringWithClosedSocket() throws Exception {
+        connect();
+        close();
+
+        String address = MllpSocketUtil.getAddressString(socket);
+
+        assertNotNull("Should have an address string", address);
+    }
+
+    // Utility Methods
+
+    private void connect() throws Exception {
+        if (socket != null) {
+            socket = new Socket(serverSocket.getInetAddress().getHostAddress(), serverSocket.getLocalPort());
+        } else {
+            socket.connect(serverSocket.getLocalSocketAddress());
+        }
+
+        assertTrue("Socket should be open", socket.isConnected() && !socket.isClosed());
+    }
+
+    private void close() throws Exception {
+        if (socket != null) {
+            if (socket.isConnected() && !socket.isClosed()) {
+                socket.close();
+            }
+
+            assertTrue("Socket should have been connected and closed", socket.isConnected() && socket.isClosed());
+        }
+    }
+
+    private void reset() throws Exception {
+        if (socket != null) {
+            if (socket.isConnected() && !socket.isClosed()) {
+                socket.setSoLinger(true, 0);
+                socket.close();
+            }
+
+            assertTrue("Socket should have been connected and closed", socket.isConnected() && socket.isClosed());
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketWriterTestSupport.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketWriterTestSupport.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketWriterTestSupport.java
new file mode 100644
index 0000000..a819771
--- /dev/null
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/impl/MllpSocketWriterTestSupport.java
@@ -0,0 +1,132 @@
+/**
+ * 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.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+
+public abstract class MllpSocketWriterTestSupport {
+    static final String TEST_MESSAGE =
+        "MSH|^~\\&|ADT|EPIC|JCAPS|CC|20161206193919|RISTECH|ADT^A08|00001|D|2.3^^|||||||" + '\r'
+            + "EVN|A08|20150107161440||REG_UPDATE_SEND_VISIT_MESSAGES_ON_PATIENT_CHANGES|RISTECH^RADIOLOGY^TECHNOLOGIST^^^^^^UCLA^^^^^RRMC||" + '\r'
+            + "PID|1|2100355^^^MRN^MRN|2100355^^^MRN^MRN||MDCLS9^MC9||19700109|F||U|111 HOVER STREET^^LOS ANGELES^CA^90032^USA^P^^LOS ANGELE|LOS ANGELE|"
+                + "(310)725-6952^P^PH^^^310^7256952||ENGLISH|U||60000013647|565-33-2222|||U||||||||N||" + '\r'
+            + "PD1|||UCLA HEALTH SYSTEM^^10|10002116^ADAMS^JOHN^D^^^^^EPIC^^^^PROVID||||||||||||||" + '\r'
+            + "NK1|1|DOE^MC9^^|OTH|^^^^^USA|(310)888-9999^^^^^310^8889999|(310)999-2222^^^^^310^9992222|Emergency Contact 1|||||||||||||||||||||||||||" + '\r'
+            + "PV1|1|OUTPATIENT|RR CT^^^1000^^^^^^^DEPID|EL|||017511^TOBIAS^JONATHAN^^^^^^EPIC^^^^PROVID|017511^TOBIAS^JONATHAN^^^^^^EPIC^^^^PROVID||||||"
+                + "CLR|||||60000013647|SELF|||||||||||||||||||||HOV_CONF|^^^1000^^^^^^^||20150107161438||||||||||" + '\r'
+            + "PV2||||||||20150107161438||||CT BRAIN W WO CONTRAST||||||||||N|||||||||||||||||||||||||||" + '\r'
+            + "ZPV||||||||||||20150107161438|||||||||" + '\r'
+            + "AL1|1||33361^NO KNOWN ALLERGIES^^NOTCOMPUTRITION^NO KNOWN ALLERGIES^EXTELG||||||" + '\r'
+            + "DG1|1|DX|784.0^Headache^DX|Headache||VISIT" + '\r'
+            + "GT1|1|1000235129|MDCLS9^MC9^^||111 HOVER STREET^^LOS ANGELES^CA^90032^USA^^^LOS ANGELE|(310)725-6952^^^^^310^7256952||19700109|F|P/F|SLF|"
+                + "565-33-2222|||||^^^^^USA|||UNKNOWN|||||||||||||||||||||||||||||" + '\r'
+            + "UB2||||||||" + '\r'
+            + '\n';
+
+    static final String TEST_ACKNOWLEDGEMENT =
+        "MSH|^~\\&|JCAPS|CC|ADT|EPIC|20161206193919|RISTECH|ACK^A08|00001|D|2.3^^|||||||" + '\r'
+            + "MSA|AA|00001|" + '\r'
+            + '\n';
+
+    FakeSocket fakeSocket = new FakeSocket();
+
+    class FakeSocket extends Socket {
+        boolean connected = true;
+        boolean closed;
+
+        FakeSocketOutputStream fakeSocketOutputStream = new FakeSocketOutputStream();
+
+        FakeSocket() {
+        }
+
+        @Override
+        public boolean isConnected() {
+            return connected;
+        }
+
+        @Override
+        public boolean isClosed() {
+            return closed;
+        }
+
+        @Override
+        public OutputStream getOutputStream() throws IOException {
+            if (fakeSocketOutputStream == null) {
+                return super.getOutputStream();
+            }
+            return fakeSocketOutputStream;
+        }
+
+        byte[] payload() {
+            if (fakeSocketOutputStream != null) {
+                return fakeSocketOutputStream.fakeOutputStream.toByteArray();
+            }
+
+            return null;
+        }
+    }
+
+    class FakeSocketOutputStream extends OutputStream {
+        ByteArrayOutputStream fakeOutputStream = new ByteArrayOutputStream();
+
+        boolean failOnWrite;
+        boolean failOnWriteArray;
+
+        Byte writeFailOn;
+        byte[] writeArrayFailOn;
+
+        FakeSocketOutputStream() {
+        }
+
+        @Override
+        public void write(int b) throws IOException {
+            if (failOnWrite) {
+                throw new IOException("Faking write failure");
+            } else if (writeFailOn != null && writeFailOn == b) {
+                throw new IOException("Faking write failure");
+            }
+
+            fakeOutputStream.write(b);
+        }
+
+        @Override
+        public void write(byte[] array, int off, int len) throws IOException {
+            if (failOnWriteArray) {
+                throw new IOException("Faking write array failure");
+            }
+
+            if (writeArrayFailOn != null) {
+                if (writeArrayFailOn == array) {
+                    throw new IOException("Faking write array failure");
+                }
+                for (int i = 0; i < Math.min(len, writeArrayFailOn.length); ++i) {
+                    if (array[off + i] != writeArrayFailOn[i]) {
+                        super.write(array, off, len);
+                        return;
+                    }
+                }
+                throw new IOException("Faking write array failure");
+            } else {
+                super.write(array, off, len);
+            }
+        }
+    }
+
+}
\ No newline at end of file


[7/8] camel git commit: CAMEL-10511: Polished and fixed CS

Posted by da...@apache.org.
CAMEL-10511: Polished and fixed CS


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

Branch: refs/heads/master
Commit: 58e36d63b0148e4e5931d5a0619312eb969edc80
Parents: 91121843
Author: Claus Ibsen <da...@apache.org>
Authored: Fri Dec 16 09:02:52 2016 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Fri Dec 16 09:04:53 2016 +0100

----------------------------------------------------------------------
 .../mllp/MllpAcknowledgementDeliveryException.java          | 1 +
 .../component/mllp/MllpAcknowledgementTimeoutException.java | 1 +
 .../mllp/MllpApplicationErrorAcknowledgementException.java  | 1 +
 .../mllp/MllpApplicationRejectAcknowledgementException.java | 1 +
 .../mllp/MllpCommitErrorAcknowledgementException.java       | 1 +
 .../mllp/MllpCommitRejectAcknowledgementException.java      | 1 +
 .../java/org/apache/camel/component/mllp/MllpComponent.java | 2 +-
 .../java/org/apache/camel/component/mllp/MllpException.java | 1 -
 .../org/apache/camel/component/mllp/MllpFrameException.java | 2 ++
 .../component/mllp/MllpInvalidAcknowledgementException.java | 1 +
 .../camel/component/mllp/MllpInvalidMessageException.java   | 1 +
 .../mllp/MllpNegativeAcknowledgementException.java          | 1 +
 .../component/mllp/MllpReceiveAcknowledgementException.java | 3 +--
 .../apache/camel/component/mllp/MllpReceiveException.java   | 1 +
 .../apache/camel/component/mllp/MllpTcpClientProducer.java  | 2 +-
 .../apache/camel/component/mllp/MllpTcpServerConsumer.java  | 2 +-
 .../java/org/apache/camel/component/mllp/impl/Hl7Util.java  | 1 +
 .../camel/component/mllp/impl/MllpBufferedSocketWriter.java | 1 +
 .../apache/camel/component/mllp/impl/MllpSocketReader.java  | 2 +-
 .../apache/camel/component/mllp/impl/MllpSocketUtil.java    | 1 +
 .../apache/camel/component/mllp/impl/MllpSocketWriter.java  | 1 +
 .../mllp/Hl7AcknowledgementGenerationException.java         | 2 +-
 .../camel/processor/mllp/Hl7AcknowledgementGenerator.java   | 3 +--
 .../mllp/MllpTcpServerConsumerMessageValidationTest.java    | 9 ++++-----
 .../camel/component/mllp/MllpTcpServerConsumerTest.java     | 8 ++++----
 25 files changed, 31 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java
index c6fc878..19bc353 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Consumer cannot deliver the MLLP Acknowledgement
  */
 public class MllpAcknowledgementDeliveryException extends MllpAcknowledgementException {
+
     static final String EXCEPTION_MESSAGE = "HL7 Acknowledgment Delivery Failed";
 
     public MllpAcknowledgementDeliveryException(byte[] hl7Message, byte[] hl7Acknowledgement) {

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimeoutException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimeoutException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimeoutException.java
index 8cb2822..50510c9 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimeoutException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimeoutException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer does not receive a HL7 acknowledgement within the configured timespan
  */
 public class MllpAcknowledgementTimeoutException extends MllpAcknowledgementException {
+
     static final String EXCEPTION_MESSAGE = "Timeout receiving HL7 Acknowledgement";
 
     public MllpAcknowledgementTimeoutException(byte[] hl7Message) {

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java
index c8db47a..afcbdc5 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer receives a HL7 Application Error Acknowledgement
  */
 public class MllpApplicationErrorAcknowledgementException extends MllpNegativeAcknowledgementException {
+
     static final String EXCEPTION_MESSAGE = "HL7 Application Error Acknowledgment Received";
 
     public MllpApplicationErrorAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java
index 00dd3e4..ca0deb6 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer receives a HL7 Application Reject Acknowledgement
  */
 public class MllpApplicationRejectAcknowledgementException extends MllpNegativeAcknowledgementException {
+
     static final String EXCEPTION_MESSAGE = "HL7 Application Reject Acknowledgment Received";
 
     public MllpApplicationRejectAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java
index bec34d9..05591de 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer receives a HL7 Commit Error Acknowledgement
  */
 public class MllpCommitErrorAcknowledgementException extends MllpNegativeAcknowledgementException {
+
     static final String EXCEPTION_MESSAGE = "HL7 Commit Error Acknowledgment Received";
 
     public MllpCommitErrorAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java
index f98ee5e..b21d213 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer receives a HL7 Commit Reject Acknowledgement
  */
 public class MllpCommitRejectAcknowledgementException extends MllpNegativeAcknowledgementException {
+
     static final String EXCEPTION_MESSAGE = "HL7 Commit Reject Acknowledgment Received";
 
     public MllpCommitRejectAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java
index f3e22b1..504a6cf 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java
@@ -23,13 +23,13 @@ import org.apache.camel.Endpoint;
 import org.apache.camel.impl.UriEndpointComponent;
 
 import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
-import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 
 /**
  * Represents the component that manages {@link MllpEndpoint}.
  */
 public class MllpComponent extends UriEndpointComponent {
+
     public static final String MLLP_LOG_PHI_PROPERTY = "org.apache.camel.component.mllp.logPHI";
 
     public MllpComponent() {

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java
index 0d2c1ce..ffa908f 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java
@@ -59,7 +59,6 @@ public class MllpException extends Exception {
         this.hl7Acknowledgement = (hl7Acknowledgement != null && hl7Acknowledgement.length > 0) ? hl7Acknowledgement : null;
     }
 
-
     /**
      * Get the HL7 message payload associated with this exception, if any.
      *

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java
index 7b7a3c4..7ae2dd1 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java
@@ -21,7 +21,9 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer or consumer encounters a corrupt MLLP Frame while attempting
  * to readEnvelopedPayload or writeEnvelopedMessage a MLLP payload.
  */
+@Deprecated
 public class MllpFrameException extends MllpException {
+
     public MllpFrameException(String message, byte[] hl7Message) {
         super(message, hl7Message);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidAcknowledgementException.java
index 67d5316..2543bec 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidAcknowledgementException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Producer receives a HL7 Acknowledgement for which the HL7 Acknowledgement type cannot be determined.
  */
 public class MllpInvalidAcknowledgementException extends MllpAcknowledgementException {
+
     public MllpInvalidAcknowledgementException(String message, byte[] hl7Message, byte[] hl7Acknowledgement) {
         super(message, hl7Message, hl7Acknowledgement);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidMessageException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidMessageException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidMessageException.java
index 9cde29a..847a4de 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidMessageException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidMessageException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Consumer receives an invalid HL7 Message.
  */
 public class MllpInvalidMessageException extends MllpException {
+
     public MllpInvalidMessageException(String message, byte[] hl7Message) {
         super(message, hl7Message);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpNegativeAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpNegativeAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpNegativeAcknowledgementException.java
index 6b8a4f8..b57aebe 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpNegativeAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpNegativeAcknowledgementException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Abstract base for all MLLP Negative Acknowledgements
  */
 public abstract class MllpNegativeAcknowledgementException extends MllpAcknowledgementException {
+
     public MllpNegativeAcknowledgementException(String message, byte[] hl7Message, byte[] hl7Acknowledgement) {
         super(message, hl7Message, hl7Acknowledgement);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveAcknowledgementException.java
index 2268137..75b486f 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveAcknowledgementException.java
@@ -26,7 +26,6 @@ public class MllpReceiveAcknowledgementException extends MllpAcknowledgementExce
         super(EXCEPTION_MESSAGE, hl7Message);
     }
 
-
     public MllpReceiveAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {
         super(EXCEPTION_MESSAGE, hl7Message, hl7Acknowledgement);
     }
@@ -35,7 +34,6 @@ public class MllpReceiveAcknowledgementException extends MllpAcknowledgementExce
         super(EXCEPTION_MESSAGE, hl7Message, cause);
     }
 
-
     public MllpReceiveAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
         super(EXCEPTION_MESSAGE, hl7Message, hl7Acknowledgement, cause);
     }
@@ -51,6 +49,7 @@ public class MllpReceiveAcknowledgementException extends MllpAcknowledgementExce
     public MllpReceiveAcknowledgementException(String message, byte[] hl7Message, Throwable cause) {
         super(message, hl7Message, cause);
     }
+
     public MllpReceiveAcknowledgementException(String message, byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
         super(message, hl7Message, hl7Acknowledgement, cause);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveException.java
index c755d02..bf8826b 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveException.java
@@ -20,6 +20,7 @@ package org.apache.camel.component.mllp;
  * Raised when a MLLP Consumer cannot deliver the MLLP Acknowledgement
  */
 public class MllpReceiveException extends MllpException {
+
     public MllpReceiveException(String message) {
         super(message);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
index 69176bc..e1827cb 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
@@ -237,7 +237,7 @@ public class MllpTcpClientProducer extends DefaultProducer {
     /**
      * Validate the TCP Connection
      *
-     * @return null if the connection is valid, otherwise the Exception encounted checking the connection
+     * @return null if the connection is valid, otherwise the Exception encountered checking the connection
      */
     void checkConnection() throws IOException {
         if (null == socket || socket.isClosed() || !socket.isConnected()) {

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/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 0ec8564..b1be22b 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
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 package org.apache.camel.component.mllp;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.BindException;
@@ -28,7 +29,6 @@ import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 
-
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
 import org.apache.camel.Message;

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/Hl7Util.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/Hl7Util.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/Hl7Util.java
index 0c762cb..f4a8f9b 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/Hl7Util.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/Hl7Util.java
@@ -25,6 +25,7 @@ import static org.apache.camel.component.mllp.MllpEndpoint.SEGMENT_DELIMITER;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 
 public final class Hl7Util {
+
     static final Logger LOG = LoggerFactory.getLogger(Hl7Util.class);
 
     private Hl7Util() {

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketWriter.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketWriter.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketWriter.java
index 46db872..6f52543 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketWriter.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpBufferedSocketWriter.java
@@ -31,6 +31,7 @@ import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 
 public class MllpBufferedSocketWriter extends MllpSocketWriter {
+
     static final int DEFAULT_SO_SNDBUF = 65535;
 
     ByteArrayOutputStream outputBuffer;

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketReader.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketReader.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketReader.java
index 7d10cce..d0c78e0 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketReader.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketReader.java
@@ -35,6 +35,7 @@ import org.slf4j.LoggerFactory;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 
 public class MllpSocketReader {
+
     final Socket socket;
     final int receiveTimeout;
     final int readTimeout;
@@ -55,7 +56,6 @@ public class MllpSocketReader {
         }
     }
 
-
     public byte[] readEnvelopedPayload() throws MllpException {
         return readEnvelopedPayload(null, null);
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketUtil.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketUtil.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketUtil.java
index fab33a8..d6a05d7 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketUtil.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketUtil.java
@@ -29,6 +29,7 @@ import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 
 public final class MllpSocketUtil {
+
     private static final Logger LOG = LoggerFactory.getLogger(MllpSocketUtil.class);
 
     private MllpSocketUtil() {

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketWriter.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketWriter.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketWriter.java
index bd9515c..3f9310d 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketWriter.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/impl/MllpSocketWriter.java
@@ -32,6 +32,7 @@ import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 
 public class MllpSocketWriter {
+
     static final byte[] PAYLOAD_TERMINATOR;
 
     static {

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerationException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerationException.java b/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerationException.java
index c27c7f9..2d429c5 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerationException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerationException.java
@@ -17,6 +17,7 @@
 package org.apache.camel.processor.mllp;
 
 public class Hl7AcknowledgementGenerationException extends Exception {
+
     private final byte[] hl7Message;
 
     public Hl7AcknowledgementGenerationException(String message) {
@@ -34,7 +35,6 @@ public class Hl7AcknowledgementGenerationException extends Exception {
         this.hl7Message = hl7Message;
     }
 
-
     public byte[] getHl7Message() {
         return hl7Message;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java b/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java
index 5c0013c..ddc1927 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/processor/mllp/Hl7AcknowledgementGenerator.java
@@ -41,10 +41,9 @@ public class Hl7AcknowledgementGenerator implements Processor {
             + "MSA|AR|" + SEGMENT_DELIMITER
             + MESSAGE_TERMINATOR;
 
-
     @Override
     public void process(Exchange exchange) throws Exception {
-        Message message = null;
+        Message message;
         if (exchange.hasOut()) {
             message = exchange.getOut();
         } else {

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerMessageValidationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerMessageValidationTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerMessageValidationTest.java
index 5c431e6..ba8ca8b 100644
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerMessageValidationTest.java
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerMessageValidationTest.java
@@ -16,6 +16,8 @@
  */
 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;
@@ -28,12 +30,9 @@ import org.apache.camel.test.junit.rule.mllp.MllpClientResource;
 import org.apache.camel.test.junit.rule.mllp.MllpJUnitResourceException;
 import org.apache.camel.test.junit.rule.mllp.MllpJUnitResourceTimeoutException;
 import org.apache.camel.test.junit4.CamelTestSupport;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 
-import java.util.concurrent.TimeUnit;
-
 import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 import static org.apache.camel.test.mllp.Hl7MessageGenerator.generateMessage;
@@ -268,7 +267,7 @@ public class MllpTcpServerConsumerMessageValidationTest extends CamelTestSupport
         invalid.expectedMessageCount(1);
 
         for (int i = 0; i < messageCount; ++i) {
-            String message = (i == (messageCount/2))
+            String message = (i == (messageCount / 2))
                     ? generateMessage(i + 1).replaceFirst("EVN", "EVN" + START_OF_BLOCK)
                     : generateMessage(i + 1);
 
@@ -302,7 +301,7 @@ public class MllpTcpServerConsumerMessageValidationTest extends CamelTestSupport
         invalid.expectedMessageCount(1);
 
         for (int i = 0; i < messageCount; ++i) {
-            String message = (i == (messageCount/2))
+            String message = (i == (messageCount / 2))
                     ? generateMessage(i + 1).replaceFirst("EVN", "EVN" + END_OF_BLOCK)
                     : generateMessage(i + 1);
 

http://git-wip-us.apache.org/repos/asf/camel/blob/58e36d63/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java
index 4060626..2ac159e 100644
--- a/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java
+++ b/components/camel-mllp/src/test/java/org/apache/camel/component/mllp/MllpTcpServerConsumerTest.java
@@ -16,6 +16,8 @@
  */
 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;
@@ -31,8 +33,6 @@ import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Rule;
 import org.junit.Test;
 
-import java.util.concurrent.TimeUnit;
-
 import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
 import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
 import static org.apache.camel.test.mllp.Hl7MessageGenerator.generateMessage;
@@ -242,7 +242,7 @@ public class MllpTcpServerConsumerTest extends CamelTestSupport {
         timeout.expectedMessageCount(0);
 
         for (int i = 0; i < messageCount; ++i) {
-            String message = (i == (messageCount/2))
+            String message = (i == (messageCount / 2))
                     ? generateMessage(i + 1).replaceFirst("EVN", "EVN" + START_OF_BLOCK)
                     : generateMessage(i + 1);
 
@@ -272,7 +272,7 @@ public class MllpTcpServerConsumerTest extends CamelTestSupport {
         timeout.expectedMessageCount(0);
 
         for (int i = 0; i < messageCount; ++i) {
-            String message = (i == (messageCount/2))
+            String message = (i == (messageCount / 2))
                     ? generateMessage(i + 1).replaceFirst("EVN", "EVN" + END_OF_BLOCK)
                     : generateMessage(i + 1);
 


[6/8] camel git commit: CAMEL-10511: Updated MllpTcpClientProducer and MllpTcpServerConsumer to consume all available data on socket

Posted by da...@apache.org.
CAMEL-10511:  Updated MllpTcpClientProducer and MllpTcpServerConsumer to consume all available data on socket


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

Branch: refs/heads/camel-2.18.x
Commit: e6d58b67ccfdf024854234cfd9a1a02cde149772
Parents: 0ed067b
Author: Quinn Stevenson <qu...@pronoia-solutions.com>
Authored: Tue Dec 6 12:23:03 2016 -0700
Committer: Claus Ibsen <da...@apache.org>
Committed: Fri Dec 16 08:58:13 2016 +0100

----------------------------------------------------------------------
 .../MllpAcknowledgementDeliveryException.java   |   8 +
 .../mllp/MllpAcknowledgementException.java      |  42 +-
 .../MllpAcknowledgementTimeoutException.java    |  69 +++
 .../MllpAcknowledgementTimoutException.java     |  30 --
 ...pplicationErrorAcknowledgementException.java |   7 +-
 ...plicationRejectAcknowledgementException.java |   7 +-
 ...MllpCommitErrorAcknowledgementException.java |   7 +-
 ...llpCommitRejectAcknowledgementException.java |   7 +-
 .../camel/component/mllp/MllpComponent.java     |  38 ++
 .../camel/component/mllp/MllpConstants.java     |   1 +
 .../camel/component/mllp/MllpEndpoint.java      |  40 ++
 .../camel/component/mllp/MllpException.java     |  81 ++-
 .../component/mllp/MllpFrameException.java      |  39 +-
 .../mllp/MllpInvalidMessageException.java       |  30 ++
 .../MllpNegativeAcknowledgementException.java   |  32 ++
 .../MllpReceiveAcknowledgementException.java    |  57 ++
 .../component/mllp/MllpReceiveException.java    |  46 ++
 .../component/mllp/MllpTcpClientProducer.java   | 208 ++++----
 .../component/mllp/MllpTcpServerConsumer.java   | 318 ++++++++---
 .../component/mllp/MllpTimeoutException.java    |  50 +-
 .../component/mllp/MllpWriteException.java      |  37 +-
 .../AcknowledgmentSynchronizationAdapter.java   | 212 --------
 .../camel/component/mllp/impl/Hl7Util.java      |  90 ++++
 .../mllp/impl/MllpBufferedSocketWriter.java     | 123 +++++
 .../component/mllp/impl/MllpSocketReader.java   | 290 ++++++++++
 .../component/mllp/impl/MllpSocketUtil.java     | 230 ++++++++
 .../component/mllp/impl/MllpSocketWriter.java   | 143 +++++
 .../camel/component/mllp/impl/MllpUtil.java     | 390 --------------
 .../mllp/Hl7AcknowledgementGenerator.java       |   1 +
 .../mllp/MllpAcknowledgementExceptionTest.java  | 127 -----
 .../camel/component/mllp/MllpExceptionTest.java | 114 ++++
 .../component/mllp/MllpFrameExceptionTest.java  | 101 ----
 .../mllp/MllpProducerConsumerLoopbackTest.java  |  16 +-
 .../MllpTcpClientConsumerBlueprintTest.java     |  36 --
 ...llpTcpClientProducerAcknowledgementTest.java | 207 ++++++-
 ...ntProducerAcknowledgementValidationTest.java | 283 ++++++++++
 .../MllpTcpClientProducerBlueprintTest.java     |  14 +-
 ...llpTcpClientProducerConnectionErrorTest.java | 165 ++++++
 .../mllp/MllpTcpClientProducerTest.java         |  82 ++-
 ...llpTcpServerConsumerAcknowledgementTest.java |   5 +-
 .../MllpTcpServerConsumerConnectionTest.java    |  35 +-
 ...pTcpServerConsumerMessageValidationTest.java | 317 +++++++++++
 .../mllp/MllpTcpServerConsumerTest.java         | 126 ++++-
 .../MllpTcpServerProducerBlueprintTest.java     |  35 --
 .../mllp/MllpTimeoutExceptionTest.java          | 101 ----
 .../component/mllp/MllpWriteExceptionTest.java  | 101 ----
 .../camel/component/mllp/impl/Hl7UtilTest.java  | 126 +++++
 ...BufferedSocketAcknowledgementWriterTest.java | 125 +++++
 .../MllpBufferedSocketMessageWriterTest.java    | 126 +++++
 .../MllpSocketAcknowledgementReaderTest.java    | 533 +++++++++++++++++++
 .../MllpSocketAcknowledgementWriterTest.java    | 150 ++++++
 .../mllp/impl/MllpSocketMessageReaderTest.java  | 527 ++++++++++++++++++
 .../mllp/impl/MllpSocketMessageWriterTest.java  | 150 ++++++
 .../mllp/impl/MllpSocketReaderTestSupport.java  | 342 ++++++++++++
 .../MllpSocketUtilExceptionHandlingTest.java    | 133 +++++
 .../impl/MllpSocketUtilFindXxxOfBlockTest.java  | 241 +++++++++
 .../mllp/impl/MllpSocketUtilSocketTest.java     | 288 ++++++++++
 .../mllp/impl/MllpSocketWriterTestSupport.java  | 132 +++++
 .../junit/rule/mllp/MllpServerResource.java     | 497 +++++++++++------
 .../apache/camel/test/util/PayloadBuilder.java  | 211 ++++++++
 .../src/test/resources/log4j2.properties        |  10 +-
 61 files changed, 6422 insertions(+), 1667 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java
index 4ac46c9..c6fc878 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementDeliveryException.java
@@ -29,4 +29,12 @@ public class MllpAcknowledgementDeliveryException extends MllpAcknowledgementExc
     public MllpAcknowledgementDeliveryException(byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
         super(EXCEPTION_MESSAGE, hl7Message, hl7Acknowledgement, cause);
     }
+
+    public MllpAcknowledgementDeliveryException(String message, byte[] hl7Message, byte[] hl7Acknowledgement) {
+        super(message, hl7Message, hl7Acknowledgement);
+    }
+
+    public MllpAcknowledgementDeliveryException(String message, byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
+        super(message, hl7Message, hl7Acknowledgement, cause);
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementException.java
index 992d506..296430b 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementException.java
@@ -20,49 +20,25 @@ package org.apache.camel.component.mllp;
  * Base class for HL7 Application Acknowledgement Exceptions
  */
 public abstract class MllpAcknowledgementException extends MllpException {
-    private final byte[] hl7Message;
-    private final byte[] hl7Acknowledgement;
 
-    public MllpAcknowledgementException(String message, byte[] hl7Message, byte[] hl7Acknowledgement) {
+    public MllpAcknowledgementException(String message) {
         super(message);
-        this.hl7Message = hl7Message;
-        this.hl7Acknowledgement = hl7Acknowledgement;
     }
 
-    public MllpAcknowledgementException(String message, byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
-        super(message, cause);
-        this.hl7Message = hl7Message;
-        this.hl7Acknowledgement = hl7Acknowledgement;
+    public MllpAcknowledgementException(String message, byte[] hl7Message) {
+        super(message, hl7Message);
     }
 
-    public byte[] getHl7Message() {
-        return hl7Message;
+    public MllpAcknowledgementException(String message, byte[] hl7Message, byte[] hl7Acknowledgement) {
+        super(message, hl7Message, hl7Acknowledgement);
     }
 
-    public byte[] getHl7Acknowledgement() {
-        return hl7Acknowledgement;
+    public MllpAcknowledgementException(String message, byte[] hl7Message, Throwable cause) {
+        super(message, hl7Message, cause);
     }
 
-    @Override
-    public String getMessage() {
-        if (isLogPhi()) {
-            return String.format("%s:\n\tHL7 Message: %s\n\tHL7 Acknowledgement: %s",
-                    super.getMessage(), covertBytesToPrintFriendlyString(hl7Message), covertBytesToPrintFriendlyString(hl7Acknowledgement));
-        } else {
-            return super.getMessage();
-        }
+    public MllpAcknowledgementException(String message, byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
+        super(message, hl7Message, hl7Acknowledgement, cause);
     }
 
-    @Override
-    public String toString() {
-        StringBuilder stringBuilder = new StringBuilder(this.getClass().getName());
-
-        stringBuilder.append(": {hl7Message=")
-                .append(covertBytesToPrintFriendlyString(hl7Message))
-                .append(", hl7Acknowledgement=")
-                .append(covertBytesToPrintFriendlyString(hl7Acknowledgement))
-                .append("}");
-
-        return stringBuilder.toString();
-    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimeoutException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimeoutException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimeoutException.java
new file mode 100644
index 0000000..8cb2822
--- /dev/null
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimeoutException.java
@@ -0,0 +1,69 @@
+/**
+ * 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;
+
+/**
+ * Raised when a MLLP Producer does not receive a HL7 acknowledgement within the configured timespan
+ */
+public class MllpAcknowledgementTimeoutException extends MllpAcknowledgementException {
+    static final String EXCEPTION_MESSAGE = "Timeout receiving HL7 Acknowledgement";
+
+    public MllpAcknowledgementTimeoutException(byte[] hl7Message) {
+        super(EXCEPTION_MESSAGE, hl7Message);
+    }
+
+    public MllpAcknowledgementTimeoutException(byte[] hl7Message, byte[] partialHl7Acknowledgement) {
+        super(EXCEPTION_MESSAGE, hl7Message, partialHl7Acknowledgement);
+    }
+
+    public MllpAcknowledgementTimeoutException(byte[] hl7Message, Throwable cause) {
+        super(EXCEPTION_MESSAGE, hl7Message, cause);
+    }
+
+    public MllpAcknowledgementTimeoutException(byte[] hl7Message, byte[] partialHl7Acknowledgement, Throwable cause) {
+        super(EXCEPTION_MESSAGE, hl7Message, partialHl7Acknowledgement, cause);
+    }
+
+    public MllpAcknowledgementTimeoutException(String message, byte[] hl7Message) {
+        super(message, hl7Message);
+    }
+
+    public MllpAcknowledgementTimeoutException(String message, byte[] hl7Message, byte[] partialHl7Acknowledgement) {
+        super(message, hl7Message, partialHl7Acknowledgement);
+    }
+
+    public MllpAcknowledgementTimeoutException(String message, byte[] hl7Message, Throwable cause) {
+        super(message, hl7Message, cause);
+    }
+
+    public MllpAcknowledgementTimeoutException(String message, byte[] hl7Message, byte[] partialHl7Acknowledgement, Throwable cause) {
+        super(message, hl7Message, partialHl7Acknowledgement, cause);
+    }
+
+    /**
+     * Get the HL7 acknowledgement payload associated with this exception, if any.
+     *
+     * @return If the timeout occurred while attempting to receive an HL7 Message, this will be null.  If the timeout
+     * occurred while attempting to receive an HL7 Acknowledgement, this will be the HL7 Message.  If the timeout occurred
+     * while attempting to complete the read of an HL7 message (i.e. part of the message has already been read), this
+     * will be the partial acknowledgement payload that was read before the timeout.
+     */
+    public byte[] getHl7Acknowledgement() {
+        return super.getHl7Acknowledgement();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimoutException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimoutException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimoutException.java
deleted file mode 100644
index a1cf147..0000000
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpAcknowledgementTimoutException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * 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;
-
-/**
- * Raised when a MLLP Producer does not receive a HL7 acknowledgement within the configured timespan
- */
-public class MllpAcknowledgementTimoutException extends MllpTimeoutException {
-    public MllpAcknowledgementTimoutException(String message, byte[] hl7Message) {
-        super(message, hl7Message);
-    }
-
-    public MllpAcknowledgementTimoutException(String message, byte[] hl7Message, Throwable cause) {
-        super(message, hl7Message, cause);
-    }
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java
index 5b6fed1..c8db47a 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationErrorAcknowledgementException.java
@@ -19,7 +19,7 @@ package org.apache.camel.component.mllp;
 /**
  * Raised when a MLLP Producer receives a HL7 Application Error Acknowledgement
  */
-public class MllpApplicationErrorAcknowledgementException extends MllpAcknowledgementException {
+public class MllpApplicationErrorAcknowledgementException extends MllpNegativeAcknowledgementException {
     static final String EXCEPTION_MESSAGE = "HL7 Application Error Acknowledgment Received";
 
     public MllpApplicationErrorAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {
@@ -29,4 +29,9 @@ public class MllpApplicationErrorAcknowledgementException extends MllpAcknowledg
     public MllpApplicationErrorAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
         super(EXCEPTION_MESSAGE, hl7Message, hl7Acknowledgement, cause);
     }
+
+    @Override
+    public String getAcknowledgmentType() {
+        return "AE";
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java
index 76cbf2c..00dd3e4 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpApplicationRejectAcknowledgementException.java
@@ -19,7 +19,7 @@ package org.apache.camel.component.mllp;
 /**
  * Raised when a MLLP Producer receives a HL7 Application Reject Acknowledgement
  */
-public class MllpApplicationRejectAcknowledgementException extends MllpAcknowledgementException {
+public class MllpApplicationRejectAcknowledgementException extends MllpNegativeAcknowledgementException {
     static final String EXCEPTION_MESSAGE = "HL7 Application Reject Acknowledgment Received";
 
     public MllpApplicationRejectAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {
@@ -29,4 +29,9 @@ public class MllpApplicationRejectAcknowledgementException extends MllpAcknowled
     public MllpApplicationRejectAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
         super(EXCEPTION_MESSAGE, hl7Message, hl7Acknowledgement, cause);
     }
+
+    @Override
+    public String getAcknowledgmentType() {
+        return "AR";
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java
index aef1a27..bec34d9 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitErrorAcknowledgementException.java
@@ -19,7 +19,7 @@ package org.apache.camel.component.mllp;
 /**
  * Raised when a MLLP Producer receives a HL7 Commit Error Acknowledgement
  */
-public class MllpCommitErrorAcknowledgementException extends MllpAcknowledgementException {
+public class MllpCommitErrorAcknowledgementException extends MllpNegativeAcknowledgementException {
     static final String EXCEPTION_MESSAGE = "HL7 Commit Error Acknowledgment Received";
 
     public MllpCommitErrorAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {
@@ -29,4 +29,9 @@ public class MllpCommitErrorAcknowledgementException extends MllpAcknowledgement
     public MllpCommitErrorAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
         super(EXCEPTION_MESSAGE, hl7Message, hl7Acknowledgement, cause);
     }
+
+    @Override
+    public String getAcknowledgmentType() {
+        return "CE";
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java
index 3907694..f98ee5e 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpCommitRejectAcknowledgementException.java
@@ -19,7 +19,7 @@ package org.apache.camel.component.mllp;
 /**
  * Raised when a MLLP Producer receives a HL7 Commit Reject Acknowledgement
  */
-public class MllpCommitRejectAcknowledgementException extends MllpAcknowledgementException {
+public class MllpCommitRejectAcknowledgementException extends MllpNegativeAcknowledgementException {
     static final String EXCEPTION_MESSAGE = "HL7 Commit Reject Acknowledgment Received";
 
     public MllpCommitRejectAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {
@@ -29,4 +29,9 @@ public class MllpCommitRejectAcknowledgementException extends MllpAcknowledgemen
     public MllpCommitRejectAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
         super(EXCEPTION_MESSAGE, hl7Message, hl7Acknowledgement, cause);
     }
+
+    @Override
+    public String getAcknowledgmentType() {
+        return "CR";
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java
index b23a421..f3e22b1 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpComponent.java
@@ -22,6 +22,10 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.Endpoint;
 import org.apache.camel.impl.UriEndpointComponent;
 
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_BLOCK;
+import static org.apache.camel.component.mllp.MllpEndpoint.END_OF_DATA;
+import static org.apache.camel.component.mllp.MllpEndpoint.START_OF_BLOCK;
+
 /**
  * Represents the component that manages {@link MllpEndpoint}.
  */
@@ -64,4 +68,38 @@ public class MllpComponent extends UriEndpointComponent {
         return endpoint;
     }
 
+    public static boolean isLogPhi() {
+        String logPhiProperty = System.getProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
+        return Boolean.valueOf(logPhiProperty);
+    }
+
+    public static String covertToPrintFriendlyString(String hl7Message) {
+        if (hl7Message == null) {
+            return "null";
+        } else if (hl7Message.isEmpty()) {
+            return "empty";
+        }
+
+        return hl7Message.replaceAll("" + START_OF_BLOCK, "<VT>").replaceAll("" + END_OF_BLOCK, "<FS>").replaceAll("\r", "<CR>").replaceAll("\n", "<LF>");
+    }
+
+    public static String covertBytesToPrintFriendlyString(byte[] hl7Bytes) {
+        if (hl7Bytes == null) {
+            return "null";
+        } else if (hl7Bytes.length == 0) {
+            return "";
+        }
+
+        return covertBytesToPrintFriendlyString(hl7Bytes, 0, hl7Bytes.length);
+    }
+
+    public static String covertBytesToPrintFriendlyString(byte[] hl7Bytes, int startPosition, int length) {
+        if (null == hl7Bytes) {
+            return "null";
+        } else if (hl7Bytes.length == 0) {
+            return "";
+        }
+        return covertToPrintFriendlyString(new String(hl7Bytes, startPosition, length));
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpConstants.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpConstants.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpConstants.java
index 8275a0e..4e14da0 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpConstants.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpConstants.java
@@ -21,6 +21,7 @@ public final class MllpConstants {
     public static final String MLLP_REMOTE_ADDRESS = "CamelMllpRemoteAddress";
 
     public static final String MLLP_ACKNOWLEDGEMENT = "CamelMllpAcknowledgement";
+    public static final String MLLP_ACKNOWLEDGEMENT_STRING = "CamelMllpAcknowledgementString";
     public static final String MLLP_ACKNOWLEDGEMENT_TYPE = "CamelMllpAcknowledgementType";
 
     public static final String MLLP_ACKNOWLEDGEMENT_EXCEPTION = "CamelMllpAcknowledgementException";

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpEndpoint.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpEndpoint.java
index ae2e01f..3732254 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpEndpoint.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpEndpoint.java
@@ -100,6 +100,12 @@ public class MllpEndpoint extends DefaultEndpoint {
     @UriParam(defaultValue = "true")
     boolean hl7Headers = true;
 
+    @UriParam(defaultValue = "true")
+    boolean bufferWrites = true;
+
+    @UriParam(defaultValue = "false")
+    boolean validatePayload;
+
     @UriParam(label = "codec")
     String charsetName;
 
@@ -391,4 +397,38 @@ public class MllpEndpoint extends DefaultEndpoint {
     public void setHl7Headers(boolean hl7Headers) {
         this.hl7Headers = hl7Headers;
     }
+
+    public boolean isValidatePayload() {
+        return validatePayload;
+    }
+
+    /**
+     * Enable/Disable the validation of HL7 Payloads
+     *
+     * If enabled, HL7 Payloads received from external systems will be validated (see Hl7Util.generateInvalidPayloadExceptionMessage for details on the validation).
+     * If and invalid payload is detected, a MllpInvalidMessageException (for consumers) or a MllpInvalidAcknowledgementException will be thrown.
+     *
+     * @param validatePayload enabled if true, otherwise disabled
+     */
+    public void setValidatePayload(boolean validatePayload) {
+        this.validatePayload = validatePayload;
+    }
+
+    public boolean isBufferWrites() {
+        return bufferWrites;
+    }
+
+    /**
+     * Enable/Disable the validation of HL7 Payloads
+     *
+     * If enabled, MLLP Payloads are buffered and written to the external system in a single write(byte[]) operation.
+     * If disabled, the MLLP payload will not be buffered, and three write operations will be used.  The first operation
+     * will write the MLLP start-of-block character {0x0b (ASCII VT)}, the second operation will write the HL7 payload, and the
+     * third operation will writh the MLLP end-of-block character and the MLLP end-of-data character {[0x1c, 0x0d] (ASCII [FS, CR])}.
+     *
+     * @param bufferWrites enabled if true, otherwise disabled
+     */
+    public void setBufferWrites(boolean bufferWrites) {
+        this.bufferWrites = bufferWrites;
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java
index f0d5e84..0d2c1ce 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpException.java
@@ -20,25 +20,88 @@ package org.apache.camel.component.mllp;
  * Base class for all MLLP Exceptions, and also used as a generic MLLP exception
  */
 public class MllpException extends Exception {
+    private final byte[] hl7Message;
+    private final byte[] hl7Acknowledgement;
+
     public MllpException(String message) {
         super(message);
+        this.hl7Message = null;
+        this.hl7Acknowledgement = null;
+    }
+
+    public MllpException(String message, byte[] hl7Message) {
+        super(message);
+        this.hl7Message = (hl7Message != null && hl7Message.length > 0) ? hl7Message : null;
+        this.hl7Acknowledgement = null;
+    }
+
+    public MllpException(String message, byte[] hl7Message, byte[] hl7Acknowledgement) {
+        super(message);
+        this.hl7Message = (hl7Message != null && hl7Message.length > 0) ? hl7Message : null;
+        this.hl7Acknowledgement = (hl7Acknowledgement != null && hl7Acknowledgement.length > 0) ? hl7Acknowledgement : null;
     }
 
     public MllpException(String message, Throwable cause) {
         super(message, cause);
+        this.hl7Message = null;
+        this.hl7Acknowledgement = null;
     }
 
-    public boolean isLogPhi() {
-        String logPhiProperty = System.getProperty(MllpComponent.MLLP_LOG_PHI_PROPERTY, "true");
-        return Boolean.valueOf(logPhiProperty);
+    public MllpException(String message, byte[] hl7Message, Throwable cause) {
+        super(message, cause);
+        this.hl7Message = (hl7Message != null && hl7Message.length > 0) ? hl7Message : null;
+        this.hl7Acknowledgement = null;
     }
 
-    protected String covertBytesToPrintFriendlyString(byte[] hl7Bytes) {
-        if (null == hl7Bytes) {
-            return "null";
-        } else if (hl7Bytes.length == 0) {
-            return "";
+    public MllpException(String message, byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
+        super(message, cause);
+        this.hl7Message = (hl7Message != null && hl7Message.length > 0) ? hl7Message : null;
+        this.hl7Acknowledgement = (hl7Acknowledgement != null && hl7Acknowledgement.length > 0) ? hl7Acknowledgement : null;
+    }
+
+
+    /**
+     * Get the HL7 message payload associated with this exception, if any.
+     *
+     * @return HL7 message payload
+     */
+    public byte[] getHl7Message() {
+        return hl7Message;
+    }
+
+    /**
+     * Get the HL7 acknowledgement payload associated with this exception, if any.
+     *
+     * @return HL7 acknowledgement payload
+     */
+    public byte[] getHl7Acknowledgement() {
+        return hl7Acknowledgement;
+    }
+
+    /**
+     * Override the base version of this method, and include the HL7 Message and Acknowledgement, if any
+     *
+     * @return the detail message of this MLLP Exception
+     */
+    @Override
+    public String getMessage() {
+        if (MllpComponent.isLogPhi()) {
+            return String.format("%s \n\t{hl7Message= %s} \n\t{hl7Acknowledgement= %s}",
+                    super.getMessage(), MllpComponent.covertBytesToPrintFriendlyString(hl7Message), MllpComponent.covertBytesToPrintFriendlyString(hl7Acknowledgement));
+        } else {
+            return super.getMessage();
         }
-        return new String(hl7Bytes).replaceAll("\r", "<CR>").replaceAll("\n", "<LF>");
     }
+
+    /**
+     * Return the MLLP Payload that is most likely the cause of the Exception
+     *
+     * If the HL7 Acknowledgement is present, return it.  Otherwise, return the HL7 Message.
+     *
+     * @return the MLLP Payload with the framing error
+     */
+    public byte[] getMllpPayload() {
+        return (hl7Acknowledgement != null  &&  hl7Acknowledgement.length > 0) ? hl7Acknowledgement : hl7Message;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java
index 43b1281..7b7a3c4 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpFrameException.java
@@ -17,44 +17,25 @@
 package org.apache.camel.component.mllp;
 
 /**
+ * @deprecated - replaced by more specific exceptions.  MllpTimeoutException, MllpInvalidMessageException and MllpInvalidAcknowledgementException
  * Raised when a MLLP Producer or consumer encounters a corrupt MLLP Frame while attempting
- * to read or write a MLLP payload.
+ * to readEnvelopedPayload or writeEnvelopedMessage a MLLP payload.
  */
 public class MllpFrameException extends MllpException {
-    private final byte[] mllpPayload;
-
-    public MllpFrameException(String message, byte[] mllpPayload) {
-        super(message);
-        this.mllpPayload = mllpPayload;
-    }
-
-    public MllpFrameException(String message, byte[] mllpPayload, Throwable cause) {
-        super(message, cause);
-        this.mllpPayload = mllpPayload;
+    public MllpFrameException(String message, byte[] hl7Message) {
+        super(message, hl7Message);
     }
 
-    public byte[] getMllpPayload() {
-        return mllpPayload;
+    public MllpFrameException(String message, byte[] hl7Message, byte[] hl7Acknowledgement) {
+        super(message, hl7Message, hl7Acknowledgement);
     }
 
-    @Override
-    public String getMessage() {
-        if (isLogPhi()) {
-            return String.format("%s:\n\tMLLP Payload: %s", super.getMessage(), covertBytesToPrintFriendlyString(mllpPayload));
-        } else {
-            return super.getMessage();
-        }
+    public MllpFrameException(String message, byte[] hl7Message, Throwable cause) {
+        super(message, hl7Message, cause);
     }
 
-    @Override
-    public String toString() {
-        StringBuilder stringBuilder = new StringBuilder(this.getClass().getName());
-
-        stringBuilder.append(": {mllpPayload=")
-                .append(covertBytesToPrintFriendlyString(mllpPayload))
-                .append("}");
-
-        return stringBuilder.toString();
+    public MllpFrameException(String message, byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
+        super(message, hl7Message, hl7Acknowledgement, cause);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidMessageException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidMessageException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidMessageException.java
new file mode 100644
index 0000000..9cde29a
--- /dev/null
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpInvalidMessageException.java
@@ -0,0 +1,30 @@
+/**
+ * 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;
+
+/**
+ * Raised when a MLLP Consumer receives an invalid HL7 Message.
+ */
+public class MllpInvalidMessageException extends MllpException {
+    public MllpInvalidMessageException(String message, byte[] hl7Message) {
+        super(message, hl7Message);
+    }
+
+    public MllpInvalidMessageException(String message, byte[] hl7Message, Throwable cause) {
+        super(message, hl7Message, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpNegativeAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpNegativeAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpNegativeAcknowledgementException.java
new file mode 100644
index 0000000..6b8a4f8
--- /dev/null
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpNegativeAcknowledgementException.java
@@ -0,0 +1,32 @@
+/**
+ * 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;
+
+/**
+ * Abstract base for all MLLP Negative Acknowledgements
+ */
+public abstract class MllpNegativeAcknowledgementException extends MllpAcknowledgementException {
+    public MllpNegativeAcknowledgementException(String message, byte[] hl7Message, byte[] hl7Acknowledgement) {
+        super(message, hl7Message, hl7Acknowledgement);
+    }
+
+    public MllpNegativeAcknowledgementException(String message, byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
+        super(message, hl7Message, hl7Acknowledgement, cause);
+    }
+
+    public abstract String getAcknowledgmentType();
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveAcknowledgementException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveAcknowledgementException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveAcknowledgementException.java
new file mode 100644
index 0000000..2268137
--- /dev/null
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveAcknowledgementException.java
@@ -0,0 +1,57 @@
+/**
+ * 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;
+
+/**
+ * Raised when a MLLP Consumer cannot deliver the MLLP Acknowledgement
+ */
+public class MllpReceiveAcknowledgementException extends MllpAcknowledgementException {
+    static final String EXCEPTION_MESSAGE = "HL7 Acknowledgment Receipt Failed";
+
+    public MllpReceiveAcknowledgementException(byte[] hl7Message) {
+        super(EXCEPTION_MESSAGE, hl7Message);
+    }
+
+
+    public MllpReceiveAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement) {
+        super(EXCEPTION_MESSAGE, hl7Message, hl7Acknowledgement);
+    }
+
+    public MllpReceiveAcknowledgementException(byte[] hl7Message, Throwable cause) {
+        super(EXCEPTION_MESSAGE, hl7Message, cause);
+    }
+
+
+    public MllpReceiveAcknowledgementException(byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
+        super(EXCEPTION_MESSAGE, hl7Message, hl7Acknowledgement, cause);
+    }
+
+    public MllpReceiveAcknowledgementException(String message, byte[] hl7Message) {
+        super(message, hl7Message);
+    }
+
+    public MllpReceiveAcknowledgementException(String message, byte[] hl7Message, byte[] hl7Acknowledgement) {
+        super(message, hl7Message, hl7Acknowledgement);
+    }
+
+    public MllpReceiveAcknowledgementException(String message, byte[] hl7Message, Throwable cause) {
+        super(message, hl7Message, cause);
+    }
+    public MllpReceiveAcknowledgementException(String message, byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
+        super(message, hl7Message, hl7Acknowledgement, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveException.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveException.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveException.java
new file mode 100644
index 0000000..c755d02
--- /dev/null
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpReceiveException.java
@@ -0,0 +1,46 @@
+/**
+ * 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;
+
+/**
+ * Raised when a MLLP Consumer cannot deliver the MLLP Acknowledgement
+ */
+public class MllpReceiveException extends MllpException {
+    public MllpReceiveException(String message) {
+        super(message);
+    }
+
+    public MllpReceiveException(String message, byte[] hl7Message) {
+        super(message, hl7Message);
+    }
+
+    public MllpReceiveException(String message, byte[] hl7Message, byte[] hl7Acknowledgement) {
+        super(message, hl7Message, hl7Acknowledgement);
+    }
+
+    public MllpReceiveException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public MllpReceiveException(String message, byte[] hl7Message, Throwable cause) {
+        super(message, hl7Message, cause);
+    }
+
+    public MllpReceiveException(String message, byte[] hl7Message, byte[] hl7Acknowledgement, Throwable cause) {
+        super(message, hl7Message, hl7Acknowledgement, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/e6d58b67/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
----------------------------------------------------------------------
diff --git a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
index 5793aea..69176bc 100644
--- a/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
+++ b/components/camel-mllp/src/main/java/org/apache/camel/component/mllp/MllpTcpClientProducer.java
@@ -20,14 +20,19 @@ import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.net.Socket;
 import java.net.SocketException;
-import java.net.SocketTimeoutException;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
-import org.apache.camel.component.mllp.impl.MllpUtil;
+import org.apache.camel.component.mllp.impl.Hl7Util;
+import org.apache.camel.component.mllp.impl.MllpBufferedSocketWriter;
+import org.apache.camel.component.mllp.impl.MllpSocketReader;
+import org.apache.camel.component.mllp.impl.MllpSocketUtil;
+import org.apache.camel.component.mllp.impl.MllpSocketWriter;
 import org.apache.camel.impl.DefaultProducer;
+import org.apache.camel.util.IOHelper;
 
 import static org.apache.camel.component.mllp.MllpConstants.MLLP_ACKNOWLEDGEMENT;
+import static org.apache.camel.component.mllp.MllpConstants.MLLP_ACKNOWLEDGEMENT_STRING;
 import static org.apache.camel.component.mllp.MllpConstants.MLLP_ACKNOWLEDGEMENT_TYPE;
 import static org.apache.camel.component.mllp.MllpConstants.MLLP_CLOSE_CONNECTION_AFTER_SEND;
 import static org.apache.camel.component.mllp.MllpConstants.MLLP_CLOSE_CONNECTION_BEFORE_SEND;
@@ -45,6 +50,9 @@ public class MllpTcpClientProducer extends DefaultProducer {
 
     Socket socket;
 
+    MllpSocketReader mllpSocketReader;
+    MllpSocketWriter mllpSocketWriter;
+
     public MllpTcpClientProducer(MllpEndpoint endpoint) throws SocketException {
         super(endpoint);
         log.trace("MllpTcpClientProducer(endpoint)");
@@ -63,7 +71,7 @@ public class MllpTcpClientProducer extends DefaultProducer {
     protected void doStop() throws Exception {
         log.trace("doStop()");
 
-        MllpUtil.closeConnection(socket);
+        MllpSocketUtil.close(socket, log, "Stopping component");
 
         super.doStop();
     }
@@ -74,15 +82,18 @@ public class MllpTcpClientProducer extends DefaultProducer {
 
         // Check BEFORE_SEND Properties
         if (exchange.getProperty(MLLP_RESET_CONNECTION_BEFORE_SEND, boolean.class)) {
-            MllpUtil.resetConnection(socket);
+            MllpSocketUtil.reset(socket, log, "Exchange property " + MLLP_RESET_CONNECTION_BEFORE_SEND + " = " + exchange.getProperty(MLLP_RESET_CONNECTION_BEFORE_SEND, boolean.class));
             return;
         } else if (exchange.getProperty(MLLP_CLOSE_CONNECTION_BEFORE_SEND, boolean.class)) {
-            MllpUtil.closeConnection(socket);
+            MllpSocketUtil.close(socket, log, "Exchange property " + MLLP_CLOSE_CONNECTION_BEFORE_SEND + " = " + exchange.getProperty(MLLP_CLOSE_CONNECTION_BEFORE_SEND, boolean.class));
+            return;
         }
 
-        Exception connectionException = checkConnection();
-        if (null != connectionException) {
-            exchange.setException(connectionException);
+        // Establish a connection if needed
+        try {
+            checkConnection();
+        } catch (IOException ioEx) {
+            exchange.setException(ioEx);
             return;
         }
 
@@ -93,95 +104,118 @@ public class MllpTcpClientProducer extends DefaultProducer {
             message = exchange.getIn();
         }
 
+        message.setHeader(MLLP_LOCAL_ADDRESS, socket.getLocalAddress().toString());
+        message.setHeader(MLLP_REMOTE_ADDRESS, socket.getRemoteSocketAddress().toString());
+
+        // Send the message to the external system
         byte[] hl7MessageBytes = message.getMandatoryBody(byte[].class);
+        byte[] acknowledgementBytes = null;
 
-        log.debug("Sending message to external system");
         try {
-            MllpUtil.writeFramedPayload(socket, hl7MessageBytes);
+            log.debug("Sending message to external system");
+            mllpSocketWriter.writeEnvelopedPayload(hl7MessageBytes, null);
+            log.debug("Reading acknowledgement from external system");
+            acknowledgementBytes = mllpSocketReader.readEnvelopedPayload(hl7MessageBytes);
+        } catch (MllpWriteException writeEx) {
+            MllpSocketUtil.reset(socket, log, writeEx.getMessage());
+            exchange.setException(writeEx);
+            return;
+        } catch (MllpReceiveException ackReceiveEx) {
+            MllpSocketUtil.reset(socket, log, ackReceiveEx.getMessage());
+            exchange.setException(ackReceiveEx);
+            return;
         } catch (MllpException mllpEx) {
+            Throwable mllpExCause = mllpEx.getCause();
+            if (mllpExCause != null && mllpExCause instanceof IOException) {
+                MllpSocketUtil.reset(socket, log, mllpEx.getMessage());
+            }
             exchange.setException(mllpEx);
             return;
         }
 
-        log.debug("Reading acknowledgement from external system");
-        byte[] acknowledgementBytes = null;
-        try {
-            if (MllpUtil.openFrame(socket, endpoint.receiveTimeout, endpoint.readTimeout)) {
-                acknowledgementBytes = MllpUtil.closeFrame(socket, endpoint.receiveTimeout, endpoint.readTimeout);
+        log.debug("Populating message headers with the acknowledgement from the external system");
+        message.setHeader(MLLP_ACKNOWLEDGEMENT, acknowledgementBytes);
+        message.setHeader(MLLP_ACKNOWLEDGEMENT_STRING, new String(acknowledgementBytes, IOHelper.getCharsetName(exchange, true)));
+
+        if (endpoint.validatePayload) {
+            String exceptionMessage = Hl7Util.generateInvalidPayloadExceptionMessage(acknowledgementBytes);
+            if (exceptionMessage != null) {
+                exchange.setException(new MllpInvalidAcknowledgementException(exceptionMessage, hl7MessageBytes, acknowledgementBytes));
+                return;
             }
-        } catch (SocketTimeoutException timeoutEx) {
-            exchange.setException(new MllpAcknowledgementTimoutException("Acknowledgement timout", hl7MessageBytes, timeoutEx));
-            return;
+        }
+
+        log.debug("Processing the acknowledgement from the external system");
+        try {
+            String acknowledgementType = processAcknowledgment(hl7MessageBytes, acknowledgementBytes);
+            message.setHeader(MLLP_ACKNOWLEDGEMENT_TYPE, acknowledgementType);
         } catch (MllpException mllpEx) {
             exchange.setException(mllpEx);
             return;
         }
 
-        if (null != acknowledgementBytes) {
-            log.debug("Populating the exchange with the acknowledgement from the external system");
-            message.setHeader(MLLP_ACKNOWLEDGEMENT, acknowledgementBytes);
+        // Check AFTER_SEND Properties
+        if (exchange.getProperty(MLLP_RESET_CONNECTION_AFTER_SEND, boolean.class)) {
+            MllpSocketUtil.reset(socket, log, "Exchange property " + MLLP_RESET_CONNECTION_AFTER_SEND + " = " + exchange.getProperty(MLLP_RESET_CONNECTION_AFTER_SEND, boolean.class));
+        } else if (exchange.getProperty(MLLP_CLOSE_CONNECTION_AFTER_SEND, boolean.class)) {
+            MllpSocketUtil.close(socket, log, "Exchange property " + MLLP_CLOSE_CONNECTION_AFTER_SEND + " = " + exchange.getProperty(MLLP_CLOSE_CONNECTION_AFTER_SEND, boolean.class));
+        }
+    }
 
-            message.setHeader(MLLP_LOCAL_ADDRESS, socket.getLocalAddress().toString());
-            message.setHeader(MLLP_REMOTE_ADDRESS, socket.getRemoteSocketAddress());
+    private String processAcknowledgment(byte[] hl7MessageBytes, byte[] hl7AcknowledgementBytes) throws MllpException {
+        String acknowledgementType = "";
 
-            // Now, extract the acknowledgement type and check for a NACK
-            byte fieldDelim = acknowledgementBytes[3];
+        if (hl7AcknowledgementBytes != null && hl7AcknowledgementBytes.length > 3) {
+            // Extract the acknowledgement type and check for a NACK
+            byte fieldDelim = hl7AcknowledgementBytes[3];
             // First, find the beginning of the MSA segment - should be the second segment
             int msaStartIndex = -1;
-            for (int i = 0; i < acknowledgementBytes.length; ++i) {
-                if (SEGMENT_DELIMITER == acknowledgementBytes[i]) {
+            for (int i = 0; i < hl7AcknowledgementBytes.length; ++i) {
+                if (SEGMENT_DELIMITER == hl7AcknowledgementBytes[i]) {
                     final byte bM = 77;
                     final byte bS = 83;
                     final byte bC = 67;
                     final byte bA = 65;
                     final byte bE = 69;
                     final byte bR = 82;
-                        /* We've found the start of a new segment - make sure peeking ahead
-                           won't run off the end of the array - we need at least 7 more bytes
-                         */
-                    if (acknowledgementBytes.length > i + 7) {
+                    /* We've found the start of a new segment - make sure peeking ahead
+                       won't run off the end of the array - we need at least 7 more bytes
+                     */
+                    if (hl7AcknowledgementBytes.length > i + 7) {
                         // We can safely peek ahead
-                        if (bM == acknowledgementBytes[i + 1] && bS == acknowledgementBytes[i + 2] && bA == acknowledgementBytes[i + 3] && fieldDelim == acknowledgementBytes[i + 4]) {
+                        if (bM == hl7AcknowledgementBytes[i + 1] && bS == hl7AcknowledgementBytes[i + 2] && bA == hl7AcknowledgementBytes[i + 3] && fieldDelim == hl7AcknowledgementBytes[i + 4]) {
                             // Found the beginning of the MSA - the next two bytes should be our acknowledgement code
                             msaStartIndex = i + 1;
-                            if (bA != acknowledgementBytes[i + 5] && bC != acknowledgementBytes[i + 5]) {
-                                exchange.setException(new MllpInvalidAcknowledgementException(new String(acknowledgementBytes, i + 5, 2), hl7MessageBytes, acknowledgementBytes));
+                            if (bA != hl7AcknowledgementBytes[i + 5] && bC != hl7AcknowledgementBytes[i + 5]) {
+                                String errorMessage = "Unsupported acknowledgement type: " + new String(hl7AcknowledgementBytes, i + 5, 2);
+                                throw new MllpInvalidAcknowledgementException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
                             } else {
-                                String acknowledgemenTypeString;
-                                switch (acknowledgementBytes[i + 6]) {
+                                switch (hl7AcknowledgementBytes[i + 6]) {
                                 case bA:
-                                    // We have an AA or CA- make sure that's the end of the field
-                                    if (fieldDelim != acknowledgementBytes[i + 7]) {
-                                        exchange.setException(new MllpInvalidAcknowledgementException(new String(acknowledgementBytes, i + 5, 3), hl7MessageBytes, acknowledgementBytes));
-                                    }
-                                    if (bA == acknowledgementBytes[i + 5]) {
-                                        message.setHeader(MLLP_ACKNOWLEDGEMENT_TYPE, "AA");
+                                    // We have an AA or CA
+                                    if (bA == hl7AcknowledgementBytes[i + 5]) {
+                                        acknowledgementType = "AA";
                                     } else {
-                                        message.setHeader(MLLP_ACKNOWLEDGEMENT_TYPE, "CA");
+                                        acknowledgementType = "CA";
                                     }
                                     break;
                                 case bE:
                                     // We have an AE or CE
-                                    if (bA == acknowledgementBytes[i + 5]) {
-                                        message.setHeader(MLLP_ACKNOWLEDGEMENT_TYPE, "AE");
-                                        exchange.setException(new MllpApplicationErrorAcknowledgementException(hl7MessageBytes, acknowledgementBytes));
+                                    if (bA == hl7AcknowledgementBytes[i + 5]) {
+                                        throw new MllpApplicationErrorAcknowledgementException(hl7MessageBytes, hl7AcknowledgementBytes);
                                     } else {
-                                        message.setHeader(MLLP_ACKNOWLEDGEMENT_TYPE, "CE");
-                                        exchange.setException(new MllpCommitErrorAcknowledgementException(hl7MessageBytes, acknowledgementBytes));
+                                        throw new MllpCommitErrorAcknowledgementException(hl7MessageBytes, hl7AcknowledgementBytes);
                                     }
-                                    break;
                                 case bR:
                                     // We have an AR or CR
-                                    if (bA == acknowledgementBytes[i + 5]) {
-                                        message.setHeader(MLLP_ACKNOWLEDGEMENT_TYPE, "AR");
-                                        exchange.setException(new MllpApplicationRejectAcknowledgementException(hl7MessageBytes, acknowledgementBytes));
+                                    if (bA == hl7AcknowledgementBytes[i + 5]) {
+                                        throw new MllpApplicationRejectAcknowledgementException(hl7MessageBytes, hl7AcknowledgementBytes);
                                     } else {
-                                        message.setHeader(MLLP_ACKNOWLEDGEMENT_TYPE, "CR");
-                                        exchange.setException(new MllpCommitRejectAcknowledgementException(hl7MessageBytes, acknowledgementBytes));
+                                        throw new MllpCommitRejectAcknowledgementException(hl7MessageBytes, hl7AcknowledgementBytes);
                                     }
-                                    break;
                                 default:
-                                    exchange.setException(new MllpInvalidAcknowledgementException(new String(acknowledgementBytes, i + 5, 2), hl7MessageBytes, acknowledgementBytes));
+                                    String errorMessage = "Unsupported acknowledgement type: " + new String(hl7AcknowledgementBytes, i + 5, 2);
+                                    throw new MllpInvalidAcknowledgementException(errorMessage, hl7MessageBytes, hl7AcknowledgementBytes);
                                 }
                             }
 
@@ -191,18 +225,13 @@ public class MllpTcpClientProducer extends DefaultProducer {
                 }
 
             }
-            if (-1 == msaStartIndex) {
+            if (-1 == msaStartIndex  &&  endpoint.validatePayload) {
                 // Didn't find an MSA
-                exchange.setException(new MllpInvalidAcknowledgementException("MSA Not found in acknowledgement", hl7MessageBytes, acknowledgementBytes));
+                throw new MllpInvalidAcknowledgementException("MSA Not found in acknowledgement", hl7MessageBytes, hl7AcknowledgementBytes);
             }
         }
-        // Check AFTER_SEND Properties
-        if (exchange.getProperty(MLLP_RESET_CONNECTION_AFTER_SEND, boolean.class)) {
-            MllpUtil.resetConnection(socket);
-            return;
-        } else if (exchange.getProperty(MLLP_CLOSE_CONNECTION_AFTER_SEND, boolean.class)) {
-            MllpUtil.closeConnection(socket);
-        }
+
+        return acknowledgementType;
     }
 
     /**
@@ -210,28 +239,24 @@ public class MllpTcpClientProducer extends DefaultProducer {
      *
      * @return null if the connection is valid, otherwise the Exception encounted checking the connection
      */
-    Exception checkConnection() {
+    void checkConnection() throws IOException {
         if (null == socket || socket.isClosed() || !socket.isConnected()) {
             socket = new Socket();
 
-            try {
-                socket.setKeepAlive(endpoint.keepAlive);
-                socket.setTcpNoDelay(endpoint.tcpNoDelay);
-                if (null != endpoint.receiveBufferSize) {
-                    socket.setReceiveBufferSize(endpoint.receiveBufferSize);
-                }
-                if (null != endpoint.sendBufferSize) {
-                    socket.setSendBufferSize(endpoint.sendBufferSize);
-                }
-                socket.setReuseAddress(endpoint.reuseAddress);
-                socket.setSoLinger(false, -1);
-
-                // Read Timeout
-                socket.setSoTimeout(endpoint.receiveTimeout);
-            } catch (SocketException e) {
-                return e;
+            socket.setKeepAlive(endpoint.keepAlive);
+            socket.setTcpNoDelay(endpoint.tcpNoDelay);
+            if (null != endpoint.receiveBufferSize) {
+                socket.setReceiveBufferSize(endpoint.receiveBufferSize);
+            } else {
+                endpoint.receiveBufferSize = socket.getReceiveBufferSize();
             }
-
+            if (null != endpoint.sendBufferSize) {
+                socket.setSendBufferSize(endpoint.sendBufferSize);
+            } else {
+                endpoint.sendBufferSize = socket.getSendBufferSize();
+            }
+            socket.setReuseAddress(endpoint.reuseAddress);
+            socket.setSoLinger(false, -1);
 
             InetSocketAddress socketAddress;
             if (null == endpoint.getHostname()) {
@@ -239,17 +264,18 @@ public class MllpTcpClientProducer extends DefaultProducer {
             } else {
                 socketAddress = new InetSocketAddress(endpoint.getHostname(), endpoint.getPort());
             }
+
             log.debug("Connecting to socket on {}", socketAddress);
-            try {
-                socket.connect(socketAddress, endpoint.connectTimeout);
-            } catch (SocketTimeoutException e) {
-                return e;
-            } catch (IOException e) {
-                return e;
+            socket.connect(socketAddress, endpoint.connectTimeout);
+
+            log.debug("Creating MllpSocketReader and MllpSocketWriter");
+            mllpSocketReader = new MllpSocketReader(socket, endpoint.receiveTimeout, endpoint.readTimeout, true);
+            if (endpoint.bufferWrites) {
+                mllpSocketWriter = new MllpBufferedSocketWriter(socket, false);
+            } else {
+                mllpSocketWriter = new MllpSocketWriter(socket, false);
             }
         }
-
-        return null;
     }
 
 }