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/15 19:20:30 UTC
[1/6] camel git commit: CAMEL-10511: Updated MllpTcpClientProducer
and MllpTcpServerConsumer to consume all available data on socket
Repository: camel
Updated Branches:
refs/heads/master c03b2cd06 -> 911218438
http://git-wip-us.apache.org/repos/asf/camel/blob/91121843/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 1ee2d6e..4191468 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 evaluatePattern(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/91121843/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/91121843/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
[5/6] 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/91121843/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 e3a4593..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,17 +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;
@@ -48,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;
@@ -55,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) {
@@ -190,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();
@@ -228,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;
}
@@ -250,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);
@@ -264,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) {
@@ -319,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;
@@ -342,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);
+ }
}
/**
@@ -374,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]) {
@@ -540,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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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;
+ }
+}
[3/6] 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/91121843/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/91121843/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 c77c35f..4060626 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,8 +16,6 @@
*/
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,10 +26,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 {
@@ -41,6 +44,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();
@@ -65,9 +71,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)
@@ -82,6 +87,7 @@ public class MllpTcpServerConsumerTest extends CamelTestSupport {
@Test
public void testReceiveSingleMessage() throws Exception {
result.expectedMessageCount(1);
+ timeout.expectedMessageCount(0);
mllpClient.connect();
@@ -93,6 +99,7 @@ public class MllpTcpServerConsumerTest extends CamelTestSupport {
@Test
public void testReceiveSingleMessageWithDelayAfterConnection() throws Exception {
result.expectedMinimumMessageCount(1);
+ timeout.expectedMessageCount(0);
mllpClient.connect();
@@ -106,6 +113,7 @@ public class MllpTcpServerConsumerTest extends CamelTestSupport {
public void testReceiveMultipleMessages() throws Exception {
int sendMessageCount = 5;
result.expectedMinimumMessageCount(5);
+ timeout.expectedMessageCount(0);
mllpClient.connect();
@@ -119,6 +127,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();
@@ -165,5 +174,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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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
[6/6] 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/91121843
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/91121843
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/91121843
Branch: refs/heads/master
Commit: 91121843801aed6411b7c91da3b1e502e2d35009
Parents: c03b2cd
Author: Quinn Stevenson <qu...@pronoia-solutions.com>
Authored: Tue Dec 6 12:23:03 2016 -0700
Committer: Claus Ibsen <da...@apache.org>
Committed: Thu Dec 15 20:20:20 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 | 319 ++++++++---
.../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 | 128 ++++-
.../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, 6423 insertions(+), 1669 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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;
}
}
[4/6] 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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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);
}
[2/6] 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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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/91121843/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