Coverage Report - ca.uhn.hl7v2.util.Hl7InputStreamReader
 
Classes in this File Line Coverage Branch Coverage Complexity
Hl7InputStreamReader
0%
0/37
0%
0/12
4.571
Hl7InputStreamReader$CommentFilterReader
0%
0/44
0%
0/34
4.571
 
 1  
 /*
 2  
  * Hl7InputStreamReader.java
 3  
  */
 4  
 
 5  
 package ca.uhn.hl7v2.util;
 6  
 
 7  
 import java.io.BufferedReader;
 8  
 import java.io.FileNotFoundException;
 9  
 import java.io.IOException;
 10  
 import java.io.InputStream;
 11  
 import java.io.InputStreamReader;
 12  
 import java.io.PushbackReader;
 13  
 import java.io.Reader;
 14  
 import java.util.ArrayList;
 15  
 import java.util.List;
 16  
 import java.util.regex.Matcher;
 17  
 import java.util.regex.Pattern;
 18  
 
 19  
 import org.slf4j.Logger;
 20  
 import org.slf4j.LoggerFactory;
 21  
 
 22  
 /**
 23  
  * Reads HL7 messages from an InputStream
 24  
  * 
 25  
  * @version $Revision: 1.1 $ updated on $Date: 2007-02-19 02:24:27 $ by $Author: jamesagnew $
 26  
  * @deprecated see {@link Hl7InputStreamMessageIterator} or
 27  
  *             {@link Hl7InputStreamMessageStringIterator}
 28  
  */
 29  0
 public class Hl7InputStreamReader {
 30  
 
 31  0
         private static final Logger ourLog = LoggerFactory.getLogger(Hl7InputStreamReader.class);
 32  
 
 33  
         /**
 34  
          * Reads HL7 messages from an InputStream and outputs an array of HL7 message strings
 35  
          * 
 36  
          * @version $Revision: 1.1 $ updated on $Date: 2007-02-19 02:24:27 $ by $Author: jamesagnew $
 37  
          */
 38  
         public static String[] read(InputStream theMsgInputStream) throws FileNotFoundException,
 39  
                         IOException {
 40  0
                 BufferedReader in = null;
 41  
                 try {
 42  0
                         in = new BufferedReader(new CommentFilterReader(
 43  
                                         new InputStreamReader(theMsgInputStream)));
 44  
 
 45  0
                         StringBuffer rawMsgBuffer = new StringBuffer();
 46  0
                         int c = 0;
 47  0
                         while ((c = in.read()) >= 0) {
 48  0
                                 rawMsgBuffer.append((char) c);
 49  
                         }
 50  
 
 51  0
                         String[] messages = getHL7Messages(rawMsgBuffer.toString());
 52  0
                         ourLog.info(messages.length + " messages sent.");
 53  0
                         return messages;
 54  
                 } finally {
 55  0
                         if (in != null)
 56  0
                                 in.close();
 57  
                 }
 58  
 
 59  
         }
 60  
 
 61  
         /**
 62  
          * Given a string that contains HL7 messages, and possibly other junk, returns an array of the
 63  
          * HL7 messages. An attempt is made to recognize segments even if there is other content between
 64  
          * segments, for example if a log file logs segments individually with timestamps between them.
 65  
          * 
 66  
          * @param theSource a string containing HL7 messages
 67  
          * @return the HL7 messages contained in theSource
 68  
          */
 69  
         private static String[] getHL7Messages(String theSource) {
 70  0
                 List<String> messages = new ArrayList<String>(20);
 71  0
                 Pattern startPattern = Pattern.compile("^MSH", Pattern.MULTILINE);
 72  0
                 Matcher startMatcher = startPattern.matcher(theSource);
 73  
 
 74  0
                 while (startMatcher.find()) {
 75  0
                         String messageExtent = getMessageExtent(theSource.substring(startMatcher.start()),
 76  
                                         startPattern);
 77  
 
 78  0
                         char fieldDelim = messageExtent.charAt(3);
 79  0
                         Pattern segmentPattern = Pattern.compile("^[A-Z]{3}\\" + fieldDelim + ".*$",
 80  
                                         Pattern.MULTILINE);
 81  0
                         Matcher segmentMatcher = segmentPattern.matcher(messageExtent);
 82  0
                         StringBuffer msg = new StringBuffer();
 83  0
                         while (segmentMatcher.find()) {
 84  0
                                 msg.append(segmentMatcher.group().trim());
 85  0
                                 msg.append('\r');
 86  
                         }
 87  0
                         messages.add(msg.toString());
 88  0
                 }
 89  0
                 return messages.toArray(new String[0]);
 90  
         }
 91  
 
 92  
         /**
 93  
          * Given a string that contains at least one HL7 message, returns the smallest string that
 94  
          * contains the first of these messages.
 95  
          */
 96  
         private static String getMessageExtent(String theSource, Pattern theStartPattern) {
 97  0
                 Matcher startMatcher = theStartPattern.matcher(theSource);
 98  0
                 if (!startMatcher.find()) {
 99  0
                         throw new IllegalArgumentException(theSource + "does not contain message start pattern"
 100  
                                         + theStartPattern.toString());
 101  
                 }
 102  
 
 103  0
                 int start = startMatcher.start();
 104  0
                 int end = theSource.length();
 105  0
                 if (startMatcher.find()) {
 106  0
                         end = startMatcher.start();
 107  
                 }
 108  
 
 109  0
                 return theSource.substring(start, end).trim();
 110  
         }
 111  
 
 112  
         /**
 113  
          * TODO: this code is copied from HAPI ... should make it part of HAPI public API instead
 114  
          * Removes C and C++ style comments from a reader stream. C style comments are distinguished
 115  
          * from URL protocol delimiters by the preceding colon in the latter.
 116  
          */
 117  0
         private static class CommentFilterReader extends PushbackReader {
 118  
 
 119  0
                 private final char[] startCPPComment = { '/', '*' };
 120  0
                 private final char[] endCPPComment = { '*', '/' };
 121  0
                 private final char[] startCComment = { '/', '/' };
 122  0
                 private final char[] endCComment = { '\n' };
 123  0
                 private final char[] protocolDelim = { ':', '/', '/' };
 124  
 
 125  
                 public CommentFilterReader(Reader in) {
 126  0
                         super(in, 5);
 127  0
                 }
 128  
 
 129  
                 /**
 130  
                  * Returns the next character, not including comments.
 131  
                  */
 132  
                 public int read() throws IOException {
 133  0
                         if (atSequence(protocolDelim)) {
 134  
                                 // proceed normally
 135  0
                         } else if (atSequence(startCPPComment)) {
 136  
                                 // skip() doesn't seem to work for some reason
 137  0
                                 while (!atSequence(endCPPComment))
 138  0
                                         super.read();
 139  0
                                 for (int i = 0; i < endCPPComment.length; i++)
 140  0
                                         super.read();
 141  0
                         } else if (atSequence(startCComment)) {
 142  0
                                 while (!atSequence(endCComment))
 143  0
                                         super.read();
 144  0
                                 for (int i = 0; i < endCComment.length; i++)
 145  0
                                         super.read();
 146  
                         }
 147  0
                         int ret = super.read();
 148  0
                         if (ret == 65535)
 149  0
                                 ret = -1;
 150  0
                         return ret;
 151  
                 }
 152  
 
 153  
                 public int read(char[] cbuf, int off, int len) throws IOException {
 154  0
                         int i = -1;
 155  0
                         boolean done = false;
 156  0
                         while (++i < len) {
 157  0
                                 int next = read();
 158  0
                                 if (next == 65535 || next == -1) { // Pushback causes -1 to convert to 65535
 159  0
                                         done = true;
 160  0
                                         break;
 161  
                                 }
 162  0
                                 cbuf[off + i] = (char) next;
 163  0
                         }
 164  0
                         if (i == 0 && done)
 165  0
                                 i = -1;
 166  0
                         return i;
 167  
                 }
 168  
 
 169  
                 /**
 170  
                  * Tests incoming data for match with char sequence, resets reader when done.
 171  
                  */
 172  
                 private boolean atSequence(char[] sequence) throws IOException {
 173  0
                         boolean result = true;
 174  0
                         int i = -1;
 175  0
                         int[] data = new int[sequence.length];
 176  0
                         while (++i < sequence.length && result == true) {
 177  0
                                 data[i] = super.read();
 178  0
                                 if ((char) data[i] != sequence[i])
 179  0
                                         result = false; // includes case where end of stream reached
 180  
                         }
 181  0
                         for (int j = i - 1; j >= 0; j--) {
 182  0
                                 this.unread(data[j]);
 183  
                         }
 184  0
                         return result;
 185  
                 }
 186  
         }
 187  
 
 188  
 }