001: package com.bostechcorp.cbesb.custom.protocol;
002:
003: import java.net.SocketTimeoutException;
004: import java.text.SimpleDateFormat;
005: import java.util.Date;
006: import java.util.Vector;
007:
008: import com.bostechcorp.cbesb.runtime.ccsl.lib.DumpNormalizedMessage;
009: import com.bostechcorp.cbesb.runtime.ccsl.lib.ITcpipContext;
010:
011: public class MllpAckNakHandler extends MllpHandler {
012: protected char fieldSep;
013: protected String[] mshFields;
014:
015: public String getDescription() {
016: return "TCPIP MLLP ACK/NAK protocol handler";
017: }
018:
019: public void init(ITcpipContext ctx) {
020: super .init(ctx);
021: ctx.setIsAsyncSend(true);
022: }
023:
024: /*
025: * This handles received data in consumer mode.
026: * Create an exchange and send an ACK if the MSH is valid
027: */
028: public int gotReceiveData(byte[] bytes) throws Exception {
029: int bytesConsumed = receiveStateMachine(bytes);
030: if (gotInMessage) {
031: // pre-parse the message and make sure that we at least have a valid MSH segment
032: String messageString = new String(inMessage);
033: byte[] messageBytes = messageString.getBytes("ISO8859-1");
034: logger.debug("got inbound message ("
035: + inMessage.length()
036: + " bytes)\n"
037: + DumpNormalizedMessage
038: .dumpBytesAsHex(messageBytes));
039: if (hl7PreParse(messageString)) {
040: // send a message exchange into the container.
041: context.createInbound(messageBytes);
042:
043: // construct an ACK message
044: String ackString = makeAck();
045: byte[] ackBytes = ackString.getBytes("ISO8859-1");
046: logger.debug("sending acknowledgement ("
047: + ackString.length()
048: + " bytes)\n"
049: + DumpNormalizedMessage
050: .dumpBytesAsHex(ackBytes));
051: sendMessage(ackBytes);
052: } else
053: logger.debug("not valid HL7");
054:
055: // reset the input state
056: inMessage = new StringBuffer();
057: inputState = INPUT_WANT_0B;
058: gotInMessage = false;
059: context.setSocketTimeout(0);
060: }
061: return bytesConsumed;
062: }
063:
064: /*
065: * Send a message. Get the ack and resend if timeout or not "MSA|AA"
066: */
067: public void processInOnlyBytes(byte[] bytes) throws Exception {
068: int retries;
069: for (retries = 0; retries < 5; retries++) {
070: try {
071: byte[] receivedBytes;
072: try {
073: receivedBytes = super .processInOutBytes(bytes);
074: } catch (SocketTimeoutException toe) {
075: logger.error("Exception in ConfigFactory(): "
076: + toe.getMessage());
077: if (logger.isDebugEnabled()) {
078: logger.debug("Exception in ConfigFactory():",
079: toe);
080: }
081: continue;
082: }
083: String receivedString = new String(receivedBytes,
084: "ISO8859-1");
085: int crPosition = receivedString.indexOf((char) 13);
086: if (crPosition > 0) {
087: String fieldSep = receivedString.substring(3, 4);
088: String goodAck = "MSA" + fieldSep + "AA";
089: if (receivedString.substring(crPosition + 1,
090: crPosition + 1 + goodAck.length()).equals(
091: goodAck)) {
092: logger.debug("got good ack\n"
093: + DumpNormalizedMessage
094: .dumpBytesAsHex(receivedBytes));
095: break;
096: }
097: }
098: } catch (SocketTimeoutException e) {
099: logger.error("ACKNACK send got: " + e.getMessage());
100: if (logger.isDebugEnabled()) {
101: logger.debug("ACKNACK send got:", e);
102: }
103: }
104: }
105: if (retries == 5) {
106: throw new Exception("no ACK received");
107: }
108: }
109:
110: /*
111: * in-out exchanges are not valid for this handler. We simply demote it to
112: * in-only and return a canned success message.
113: */
114: public byte[] processInOutBytes(byte[] bytes) throws Exception {
115: byte[] successBytes = "MllpAckNakHandler sent message successfully"
116: .getBytes("ISO8859-1");
117: processInOnlyBytes(bytes);
118: return successBytes;
119: }
120:
121: /*
122: * Verify that the message begins with 'MSH' and contains a carriage return.
123: * Split the MSH segment into an array on the field separator
124: */
125: protected boolean hl7PreParse(String messageString) {
126: boolean isValid = false;
127: int firstCr = messageString.indexOf(13);
128: if (firstCr > 2 && messageString.startsWith("MSH")) {
129: fieldSep = messageString.charAt(3);
130: mshFields = splitFields(
131: messageString.substring(0, firstCr), fieldSep);
132: // we need at least 12 fields
133: if (mshFields.length >= 12)
134: isValid = true;
135: }
136: return isValid;
137: }
138:
139: protected String makeAck() {
140: SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
141: long timeNow = System.currentTimeMillis();
142: String timeStamp = sdf.format(new Date(timeNow));
143: String eventString;
144: if (mshFields[8].length() > 4)
145: eventString = mshFields[8].substring(3);
146: else
147: eventString = "";
148: String ack = "MSH" + fieldSep + mshFields[1]
149: + fieldSep
150: + // encoding characters
151: mshFields[4]
152: + fieldSep
153: + // flip the sender and receiver
154: mshFields[5] + fieldSep + mshFields[2] + fieldSep
155: + mshFields[3] + fieldSep + timeStamp + fieldSep
156: + // current date & time
157: "" + fieldSep
158: + // not used
159: "ACK"
160: + // message type
161: eventString + fieldSep + timeNow + fieldSep
162: + // control number, use current time
163: mshFields[10] + fieldSep
164: + // processing (T/P)
165: mshFields[11] + (char) 13 + "MSA" + fieldSep + "AA"
166: + fieldSep + mshFields[9] + fieldSep + // original control number
167: (char) 13;
168: return ack;
169: }
170:
171: protected String[] splitFields(String mes, char sep) {
172: Vector<String> fields = new Vector<String>();
173: int startPosition = 0;
174: int sepPosition;
175: while ((sepPosition = mes.indexOf(sep, startPosition)) >= 0) {
176: fields.add(mes.substring(startPosition, sepPosition));
177: startPosition = sepPosition + 1;
178: }
179: if (startPosition < mes.length())
180: fields.add(mes.substring(startPosition));
181: return fields.toArray(new String[0]);
182: }
183: }
|