Coverage Report - ca.uhn.hl7v2.util.ParseTester
 
Classes in this File Line Coverage Branch Coverage Complexity
ParseTester
0%
0/79
0%
0/38
4.25
ParseTester$CommentFilterReader
0%
0/35
0%
0/32
4.25
 
 1  
 package ca.uhn.hl7v2.util;
 2  
 
 3  
 import ca.uhn.hl7v2.parser.*;
 4  
 import ca.uhn.hl7v2.HL7Exception;
 5  
 import ca.uhn.hl7v2.model.Message;
 6  
 import java.io.*;
 7  
 import java.util.ArrayList;
 8  
 import java.util.Arrays;
 9  
 import java.util.List;
 10  
 
 11  
 /**
 12  
  * Tests correctness of message parsing by testing equivalence of re-encoded
 13  
  * form with original.
 14  
  * @author Bryan Tripp
 15  
  * @deprecated
 16  
  */
 17  
 public class ParseTester {
 18  
     
 19  0
     private static GenericParser parser = new GenericParser();
 20  
     private BufferedReader source;
 21  
     private String context;
 22  
     
 23  
     /** Creates a new instance of ParseTester */
 24  0
     public ParseTester() {
 25  0
     }
 26  
     
 27  
     /**
 28  
      * Checks whether the given message parses correctly with a GenericParser.
 29  
      * Failure indicates that the parsed and re-encoded message is semantically
 30  
      * different than the original, or that the message could not be parsed.  This 
 31  
      * may stem from an error in the parser, or from an error in the message.  This 
 32  
      * may also arise from unexpected message components (e.g. Z-segments) although 
 33  
      * in future HAPI versions these will be parsed as well.
 34  
      * @param message an XML or ER7 encoded message string
 35  
      * @return null if it parses correctly, an HL7Exception otherwise
 36  
      */
 37  
     public static HL7Exception parsesCorrectly(String context, String message) {
 38  0
         HL7Exception problem = null;
 39  
         try {
 40  0
             Message m = parser.parse(message);
 41  0
             String encoding = parser.getEncoding(message);
 42  0
             String result = parser.encode(m, encoding);
 43  0
             if (!EncodedMessageComparator.equivalent(message, result)) {
 44  0
                 problem = new HL7Exception(context + ": Original differs semantically from parsed/encoded message.\r\n-----Original:------------\r\n" 
 45  
                     + message + " \r\n------ Parsed/Encoded: ----------\r\n" + result + " \r\n-----Original Standardized: ---------\r\n"
 46  
                     + EncodedMessageComparator.standardize(message) + " \r\n---------------------\r\n");
 47  
             }            
 48  0
         } catch (Exception e) {
 49  0
             problem = new HL7Exception(context + ": " + e.getMessage() + " in message: \r\n-------------\r\n" + message + "\r\n-------------");;
 50  0
         }
 51  0
         return problem; 
 52  
     }
 53  
     
 54  
     /**
 55  
      * Sets the source of message data (messages must be delimited by blank lines)
 56  
      */
 57  
     public void setSource(Reader source) {
 58  0
         this.source = new BufferedReader(new CommentFilterReader(source));
 59  0
     }
 60  
     
 61  
     /**
 62  
      * Sets a description of the context of the messages (e.g. file name) that can be 
 63  
      * reported within error messages.  
 64  
      */
 65  
     public void setContext(String description) {
 66  0
         this.context = description;
 67  0
     }
 68  
     
 69  
     /**
 70  
      * Sets the source reader to point to the given file, and tests
 71  
      * all the messages therein (if a directory, processes all contained
 72  
      * files recursively).
 73  
      */
 74  
     public HL7Exception[] testAll(File source) throws IOException {
 75  0
         List<HL7Exception> list = new ArrayList<HL7Exception>();
 76  0
         System.out.println("Testing " + source.getPath());
 77  0
         if (source.isDirectory()) {
 78  0
             File[] contents = source.listFiles();
 79  0
             for (int i = 0; i < contents.length; i++) {
 80  0
                 HL7Exception[] exceptions = testAll(contents[i]);
 81  0
                 list.addAll(Arrays.asList(exceptions));
 82  
             }
 83  0
         } else if (source.isFile()) {          
 84  0
             FileReader in = new FileReader(source);
 85  0
             setSource(in);
 86  0
             setContext(source.getAbsolutePath());
 87  0
             HL7Exception[] exceptions = testAll();
 88  0
             list.addAll(Arrays.asList(exceptions));
 89  0
         } else {
 90  0
             System.out.println("Warning: " + source.getPath() + " is not a normal file");
 91  
         }
 92  0
         return list.toArray(new HL7Exception[0]);
 93  
     }
 94  
     
 95  
     /**
 96  
      * Tests all remaining messages available from the currrent source.
 97  
      */
 98  
     public HL7Exception[] testAll() throws IOException {
 99  0
             List<HL7Exception> list = new ArrayList<HL7Exception>();
 100  
 
 101  0
         String message = null;
 102  0
         while ((message = getNextMessage()).length() > 0) {
 103  0
             HL7Exception e = parsesCorrectly(this.context, message);
 104  0
             if (e != null) list.add(e);
 105  0
         }
 106  
         
 107  0
         return list.toArray(new HL7Exception[0]);
 108  
     }
 109  
     
 110  
     /**
 111  
      * Retrieves the next message (setSource() must be called first).  The next message
 112  
      * is interpreted as everything up to the next blank line, not including
 113  
      * C or C++ style comments (or blank lines themselves).  An empty string
 114  
      * indicates that there are no more messages.
 115  
      */
 116  
     public String getNextMessage() throws IOException {
 117  0
         if (this.source == null) throw new IOException("Message source is null -- call setSource() first");
 118  
         
 119  0
         StringBuffer message = new StringBuffer();
 120  0
         boolean started = false; //got at least one non-blank line
 121  0
         boolean finished = false; //got a blank line after started, or end of stream
 122  0
         while (!finished) {
 123  0
             String line = this.source.readLine();
 124  0
             if (line == null || (started && line.trim().length() == 0)) {
 125  0
                 finished = true;
 126  
             } else {
 127  0
                 if (line.trim().length() > 0) {
 128  0
                     started = true;
 129  0
                     message.append(line);
 130  0
                     message.append("\r");
 131  
                 }
 132  
             }
 133  0
         }
 134  0
         if (message.toString().trim().length() == 0) {
 135  0
             return "";
 136  
         } else {
 137  0
             return message.toString(); // can't trim by default (will omit final end-segment)
 138  
         }
 139  
     }
 140  
     
 141  
     /**
 142  
      * Command line tool for testing messages in files.
 143  
      */
 144  
     public static void main(String args[]) {
 145  0
         if (args.length != 1
 146  
         || args[0].equalsIgnoreCase("-?")
 147  
         || args[0].equalsIgnoreCase("-h")
 148  
         || args[0].equalsIgnoreCase("-help")) {
 149  0
             System.out.println("USAGE:");
 150  0
             System.out.println("  ParseTester <source>");
 151  0
             System.out.println();
 152  0
             System.out.println("  <source> must be either a file containing HL7 messages or a directory containing such files");
 153  0
             System.out.println();
 154  0
             System.out.println("Notes:");
 155  0
             System.out.println(" - Messages can be XML or ER7 encoded. ");
 156  0
             System.out.println(" - If there are multiple messages in a file they must be delimited by blank lines");
 157  0
             System.out.println(" - C and C++ style comments are skipped");
 158  
             
 159  
         } else {
 160  
             try {                
 161  0
                 System.out.println("Testing ... ");
 162  0
                 File source = new File(args[0]);
 163  0
                 ParseTester tester = new ParseTester();
 164  0
                 HL7Exception[] exceptions = tester.testAll(source);
 165  0
                 if (exceptions.length > 0) System.out.println("Parsing problems with tested messages: ");
 166  0
                 for (int i = 0; i < exceptions.length; i++) {
 167  0
                     System.out.println("PROBLEM #" + (i+1));
 168  0
                     System.out.println(exceptions[i].getMessage());
 169  
                 }
 170  0
             } catch (IOException e) {
 171  0
                 System.out.println("Testing failed to complete because of a problem reading source file(s) ... \r\n");
 172  0
                 e.printStackTrace();
 173  0
             }
 174  
         }
 175  0
     }
 176  
     
 177  
     /**
 178  
      * Removes C and C++ style comments from a reader stream.  C style comments are
 179  
      * distinguished from URL protocol delimiters by the preceding colon in the
 180  
      * latter.
 181  
      */
 182  
     public static class CommentFilterReader extends PushbackReader {
 183  
         
 184  0
         private final char[] startCPPComment = {'/', '*'};
 185  0
         private final char[] endCPPComment = {'*', '/'};
 186  0
         private final char[] startCComment = {'/', '/'};
 187  0
         private final char[] endCComment = {'\n'};
 188  0
         private final char[] protocolDelim = {':', '/', '/'};
 189  
         
 190  
         public CommentFilterReader(Reader in) {
 191  0
             super(in, 5);
 192  0
         }
 193  
         
 194  
         /**
 195  
          * Returns the next character, not including comments.
 196  
          */
 197  
         public int read() throws IOException {
 198  0
             if (atSequence(protocolDelim)) {
 199  
                 //proceed normally
 200  0
             } else if (atSequence(startCPPComment)) {
 201  
                 //skip() doesn't seem to work for some reason
 202  0
                 while (!atSequence(endCPPComment)) super.read();
 203  0
                 for (int i = 0; i < endCPPComment.length; i++) super.read();
 204  0
             } else if (atSequence(startCComment)) {
 205  0
                 while (!atSequence(endCComment)) super.read();
 206  0
                 for (int i = 0; i < endCComment.length; i++) super.read();
 207  
             }
 208  0
             return super.read();            
 209  
         }
 210  
                 
 211  
         public int read(char[] cbuf, int off, int len) throws IOException {
 212  0
             int i = -1;
 213  0
             boolean done = false;
 214  0
             while (++i < len) {
 215  0
                 int next = read();
 216  0
                 if (next == 65535 || next == -1) { //Pushback causes -1 to convert to 65535
 217  0
                     done = true;
 218  0
                     break;  
 219  
                 }
 220  0
                 cbuf[off + i] = (char) next;
 221  0
             }
 222  0
             if (i == 0 && done) i = -1; 
 223  0
             return i; 
 224  
         }            
 225  
         
 226  
         /**
 227  
          * Tests incoming data for match with char sequence, resets reader when done.
 228  
          */
 229  
         private boolean atSequence(char[] sequence) throws IOException {
 230  0
             boolean result = true;
 231  0
             int i = -1;
 232  0
             int[] data = new int[sequence.length];
 233  0
             while (++i < sequence.length && result == true) {
 234  0
                 data[i] = super.read();
 235  0
                 if ((char) data[i] != sequence[i]) result = false; //includes case where end of stream reached
 236  
             }
 237  0
             for (int j = i-1; j >= 0; j--) {
 238  0
                 this.unread(data[j]);
 239  
             }
 240  0
             return result;
 241  
         }        
 242  
     }
 243  
 }