001/** 002The contents of this file are subject to the Mozilla Public License Version 1.1 003(the "License"); you may not use this file except in compliance with the License. 004You may obtain a copy of the License at http://www.mozilla.org/MPL/ 005Software distributed under the License is distributed on an "AS IS" basis, 006WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the 007specific language governing rights and limitations under the License. 008 009The Original Code is "DefaultValidator.java". Description: 010"A default conformance validator." 011 012The Initial Developer of the Original Code is University Health Network. Copyright (C) 0132003. All Rights Reserved. 014 015Contributor(s): ______________________________________. 016 017Alternatively, the contents of this file may be used under the terms of the 018GNU General Public License (the �GPL�), in which case the provisions of the GPL are 019applicable instead of those above. If you wish to allow use of your version of this 020file only under the terms of the GPL and not to allow others to use your version 021of this file under the MPL, indicate your decision by deleting the provisions above 022and replace them with the notice and other provisions required by the GPL License. 023If you do not delete the provisions above, a recipient may use your version of 024this file under either the MPL or the GPL. 025 026 */ 027 028package ca.uhn.hl7v2.conf.check; 029 030import java.io.BufferedReader; 031import java.io.File; 032import java.io.FileReader; 033import java.io.IOException; 034import java.util.ArrayList; 035import java.util.List; 036 037import org.slf4j.Logger; 038import org.slf4j.LoggerFactory; 039 040import ca.uhn.hl7v2.DefaultHapiContext; 041import ca.uhn.hl7v2.HL7Exception; 042import ca.uhn.hl7v2.HapiContext; 043import ca.uhn.hl7v2.HapiContextSupport; 044import ca.uhn.hl7v2.conf.ProfileException; 045import ca.uhn.hl7v2.conf.parser.ProfileParser; 046import ca.uhn.hl7v2.conf.spec.RuntimeProfile; 047import ca.uhn.hl7v2.conf.spec.message.AbstractComponent; 048import ca.uhn.hl7v2.conf.spec.message.AbstractSegmentContainer; 049import ca.uhn.hl7v2.conf.spec.message.Component; 050import ca.uhn.hl7v2.conf.spec.message.Field; 051import ca.uhn.hl7v2.conf.spec.message.ProfileStructure; 052import ca.uhn.hl7v2.conf.spec.message.Seg; 053import ca.uhn.hl7v2.conf.spec.message.SegGroup; 054import ca.uhn.hl7v2.conf.spec.message.StaticDef; 055import ca.uhn.hl7v2.conf.spec.message.SubComponent; 056import ca.uhn.hl7v2.conf.store.CodeStore; 057import ca.uhn.hl7v2.conf.store.ProfileStoreFactory; 058import ca.uhn.hl7v2.model.Composite; 059import ca.uhn.hl7v2.model.DataTypeException; 060import ca.uhn.hl7v2.model.Group; 061import ca.uhn.hl7v2.model.Message; 062import ca.uhn.hl7v2.model.Primitive; 063import ca.uhn.hl7v2.model.Segment; 064import ca.uhn.hl7v2.model.Structure; 065import ca.uhn.hl7v2.model.Type; 066import ca.uhn.hl7v2.parser.EncodingCharacters; 067import ca.uhn.hl7v2.parser.GenericParser; 068import ca.uhn.hl7v2.parser.Parser; 069import ca.uhn.hl7v2.parser.PipeParser; 070import ca.uhn.hl7v2.util.Terser; 071 072/** 073 * A default conformance profile validator. 074 * 075 * Note: this class is currently NOT thread-safe! 076 * 077 * @author Bryan Tripp 078 */ 079public class DefaultValidator extends HapiContextSupport implements Validator { 080 081 private EncodingCharacters enc; // used to check for content in parts of a message 082 private static final Logger log = LoggerFactory.getLogger(DefaultValidator.class); 083 private boolean validateChildren = true; 084 private CodeStore codeStore; 085 086 /** Creates a new instance of DefaultValidator */ 087 public DefaultValidator() { 088 this(new DefaultHapiContext()); 089 } 090 091 public DefaultValidator(HapiContext context) { 092 super(context); 093 enc = new EncodingCharacters('|', null); // the | is assumed later -- don't change 094 } 095 096 /** 097 * If set to false (default is true), each testXX and validateXX method will only test the 098 * direct object it is responsible for, not its children. 099 */ 100 public void setValidateChildren(boolean validateChildren) { 101 this.validateChildren = validateChildren; 102 } 103 104 /** 105 * <p> 106 * Provides a code store to use to provide the code tables which will be used to validate coded 107 * value types. If a code store has not been set (which is the default), 108 * {@link ProfileStoreFactory} will be checked for an appropriate code store, and if none is 109 * found then coded values will not be validated. 110 * </p> 111 */ 112 public void setCodeStore(CodeStore theCodeStore) { 113 codeStore = theCodeStore; 114 } 115 116 /** 117 * @see Validator#validate 118 */ 119 public HL7Exception[] validate(Message message, StaticDef profile) throws ProfileException, 120 HL7Exception { 121 List<HL7Exception> exList = new ArrayList<HL7Exception>(); 122 Terser t = new Terser(message); 123 124 checkMessageType(t.get("/MSH-9-1"), profile, exList); 125 checkEventType(t.get("/MSH-9-2"), profile, exList); 126 checkMessageStructure(t.get("/MSH-9-3"), profile, exList); 127 128 exList.addAll(doTestGroup(message, profile, profile.getIdentifier(), 129 validateChildren)); 130 return exList.toArray(new HL7Exception[exList.size()]); 131 } 132 133 134 protected void checkEventType(String evType, StaticDef profile, List<HL7Exception> exList) throws HL7Exception { 135 if (!evType.equals(profile.getEventType()) 136 && !profile.getEventType().equalsIgnoreCase("ALL")) { 137 HL7Exception e = new ProfileNotFollowedException("Event type " + evType 138 + " doesn't match profile type of " + profile.getEventType()); 139 exList.add(e); 140 } 141 } 142 143 protected void checkMessageType(String msgType, StaticDef profile, List<HL7Exception> exList) throws HL7Exception { 144 if (!msgType.equals(profile.getMsgType())) { 145 HL7Exception e = new ProfileNotFollowedException("Message type " + msgType 146 + " doesn't match profile type of " + profile.getMsgType()); 147 exList.add(e); 148 } 149 } 150 151 protected void checkMessageStructure(String msgStruct, StaticDef profile, List<HL7Exception> exList) { 152 if (msgStruct == null || !msgStruct.equals(profile.getMsgStructID())) { 153 HL7Exception e = new ProfileNotFollowedException("Message structure " + msgStruct 154 + " doesn't match profile type of " + profile.getMsgStructID()); 155 exList.add(e); 156 } 157 } 158 159 /** 160 * Tests a group against a group section of a profile. 161 */ 162 public List<HL7Exception> testGroup(Group group, SegGroup profile, String profileID) 163 throws ProfileException { 164 return doTestGroup(group, profile, profileID, true); 165 } 166 167 protected List<HL7Exception> doTestGroup(Group group, AbstractSegmentContainer profile, 168 String profileID, boolean theValidateChildren) throws ProfileException { 169 List<HL7Exception> exList = new ArrayList<HL7Exception>(); 170 List<String> allowedStructures = new ArrayList<String>(); 171 172 for (ProfileStructure struct : profile) { 173 174 // only test a structure in detail if it isn't X 175 if (!struct.getUsage().equalsIgnoreCase("X")) { 176 allowedStructures.add(struct.getName()); 177 178 // see which instances have content 179 try { 180 List<Structure> instancesWithContent = new ArrayList<Structure>(); 181 for (Structure instance : group.getAll(struct.getName())) { 182 if (!instance.isEmpty()) 183 instancesWithContent.add(instance); 184 } 185 186 testCardinality(instancesWithContent.size(), struct.getMin(), 187 struct.getMax(), struct.getUsage(), struct.getName(), exList); 188 189 // test children on instances with content 190 if (theValidateChildren) { 191 for (Structure s : instancesWithContent) { 192 exList.addAll(testStructure(s, struct, profileID)); 193 } 194 } 195 196 } catch (HL7Exception he) { 197 exList.add(new ProfileNotHL7CompliantException(struct.getName() 198 + " not found in message")); 199 } 200 } 201 } 202 203 // complain about X structures that have content 204 checkForExtraStructures(group, allowedStructures, exList); 205 206 return exList; 207 } 208 209 /** 210 * Checks a group's children against a list of allowed structures for the group (ie those 211 * mentioned in the profile with usage other than X). Returns a list of exceptions representing 212 * structures that appear in the message but are not supposed to. 213 */ 214 protected void checkForExtraStructures(Group group, List<String> allowedStructures, List<HL7Exception> exList) 215 throws ProfileException { 216 for (String childName : group.getNames()) { 217 if (!allowedStructures.contains(childName)) { 218 try { 219 for (Structure rep : group.getAll(childName)) { 220 if (!rep.isEmpty()) { 221 HL7Exception e = new XElementPresentException("The structure " 222 + childName + " appears in the message but not in the profile"); 223 exList.add(e); 224 } 225 } 226 } catch (HL7Exception he) { 227 throw new ProfileException("Problem checking profile", he); 228 } 229 } 230 } 231 } 232 233 /** 234 * Checks cardinality and creates an appropriate exception if out of bounds. The usage code is 235 * needed because if min cardinality is > 0, the min # of reps is only required if the usage 236 * code is 'R' (see HL7 v2.5 section 2.12.6.4). 237 * 238 * @param reps the number of reps 239 * @param min the minimum number of reps 240 * @param max the maximum number of reps (-1 means *) 241 * @param usage the usage code 242 * @param name the name of the repeating structure (used in exception msg) 243 * @return null if cardinality OK, exception otherwise 244 */ 245 protected HL7Exception testCardinality(int reps, int min, int max, String usage, String name, List<HL7Exception> exList) { 246 HL7Exception e = null; 247 if (reps < min && usage.equalsIgnoreCase("R")) { 248 e = new ProfileNotFollowedException(name + " must have at least " + min 249 + " repetitions (has " + reps + ")"); 250 } else if (max > 0 && reps > max) { 251 e = new ProfileNotFollowedException(name + " must have no more than " + max 252 + " repetitions (has " + reps + ")"); 253 } 254 if (e != null) exList.add(e); 255 return e; 256 } 257 258 /** 259 * Tests a structure (segment or group) against the corresponding part of a profile. 260 */ 261 public List<HL7Exception> testStructure(Structure s, ProfileStructure profile, String profileID) 262 throws ProfileException { 263 List<HL7Exception> exList = new ArrayList<HL7Exception>(); 264 if (profile instanceof Seg) { 265 if (Segment.class.isAssignableFrom(s.getClass())) { 266 exList.addAll(doTestSegment((Segment) s, (Seg) profile, profileID, validateChildren)); 267 } else { 268 exList.add(new ProfileNotHL7CompliantException( 269 "Mismatch between a segment in the profile and the structure " 270 + s.getClass().getName() + " in the message")); 271 } 272 } else if (profile instanceof SegGroup) { 273 if (Group.class.isAssignableFrom(s.getClass())) { 274 exList.addAll(testGroup((Group) s, (SegGroup) profile, profileID)); 275 } else { 276 exList.add(new ProfileNotHL7CompliantException( 277 "Mismatch between a group in the profile and the structure " 278 + s.getClass().getName() + " in the message")); 279 } 280 } 281 return exList; 282 } 283 284 /** 285 * Tests a segment against a segment section of a profile. 286 */ 287 public List<HL7Exception> testSegment(ca.uhn.hl7v2.model.Segment segment, Seg profile, 288 String profileID) throws ProfileException { 289 return doTestSegment(segment, profile, profileID, true); 290 } 291 292 protected List<HL7Exception> doTestSegment(ca.uhn.hl7v2.model.Segment segment, Seg profile, 293 String profileID, boolean theValidateChildren) throws ProfileException { 294 List<HL7Exception> exList = new ArrayList<HL7Exception>(); 295 List<Integer> allowedFields = new ArrayList<Integer>(); 296 297 for (int i = 1; i <= profile.getFields(); i++) { 298 Field field = profile.getField(i); 299 300 // only test a field in detail if it isn't X 301 if (!field.getUsage().equalsIgnoreCase("X")) { 302 allowedFields.add(i); 303 304 // see which instances have content 305 try { 306 Type[] instances = segment.getField(i); 307 List<Type> instancesWithContent = new ArrayList<Type>(); 308 for (Type instance : instances) { 309 if (!instance.isEmpty()) 310 instancesWithContent.add(instance); 311 } 312 313 HL7Exception ce = testCardinality(instancesWithContent.size(), field.getMin(), 314 field.getMax(), field.getUsage(), field.getName(), exList); 315 if (ce != null) { 316 ce.setFieldPosition(i); 317 } 318 319 // test field instances with content 320 if (theValidateChildren) { 321 for (Type s : instancesWithContent) { 322 // escape field value when checking length 323 boolean escape = !(profile.getName().equalsIgnoreCase("MSH") && i < 3); 324 List<HL7Exception> childExceptions = doTestField(s, field, escape, 325 profileID, validateChildren); 326 for (HL7Exception ex : childExceptions) { 327 ex.setFieldPosition(i); 328 } 329 exList.addAll(childExceptions); 330 } 331 } 332 333 } catch (HL7Exception he) { 334 exList.add(new ProfileNotHL7CompliantException("Field " + i 335 + " not found in message")); 336 } 337 } 338 339 } 340 341 // complain about X fields with content 342 checkForExtraFields(segment, allowedFields, exList); 343 344 for (HL7Exception ex : exList) { 345 ex.setSegmentName(profile.getName()); 346 } 347 return exList; 348 } 349 350 /** 351 * Checks a segment against a list of allowed fields (ie those mentioned in the profile with 352 * usage other than X). Returns a list of exceptions representing field that appear but are not 353 * supposed to. 354 * 355 * @param allowedFields an array of Integers containing field #s of allowed fields 356 */ 357 protected void checkForExtraFields(Segment segment, List<Integer> allowedFields, List<HL7Exception> exList) 358 throws ProfileException { 359 for (int i = 1; i <= segment.numFields(); i++) { 360 if (!allowedFields.contains(i)) { 361 try { 362 Type[] reps = segment.getField(i); 363 for (Type rep : reps) { 364 if (!rep.isEmpty()) { 365 HL7Exception e = new XElementPresentException("Field " + i + " in " 366 + segment.getName() 367 + " appears in the message but not in the profile"); 368 exList.add(e); 369 } 370 } 371 } catch (HL7Exception he) { 372 throw new ProfileException("Problem testing against profile", he); 373 } 374 } 375 } 376 } 377 378 /** 379 * Tests a Type against the corresponding section of a profile. 380 * 381 * @param encoded optional encoded form of type (if you want to specify this -- if null, default 382 * pipe-encoded form is used to check length and constant val) 383 */ 384 public List<HL7Exception> testType(Type type, AbstractComponent<?> profile, String encoded, 385 String profileID) { 386 List<HL7Exception> exList = new ArrayList<HL7Exception>(); 387 if (encoded == null) 388 encoded = PipeParser.encode(type, this.enc); 389 390 testUsage(encoded, profile.getUsage(), profile.getName(), exList); 391 392 if (!profile.getUsage().equals("X")) { 393 checkDataType(profile.getDatatype(), type, exList); 394 checkLength(profile.getLength(), profile.getName(), encoded, exList); 395 checkConstantValue(profile.getConstantValue(), encoded, exList); 396 397 testTypeAgainstTable(type, profile, profileID, exList); 398 } 399 400 return exList; 401 } 402 403 protected void checkConstantValue(String value, String encoded, List<HL7Exception> exList) { 404 // check constant value 405 if (value != null && value.length() > 0) { 406 if (!encoded.equals(value)) 407 exList.add(new ProfileNotFollowedException("'" + encoded 408 + "' doesn't equal constant value of '" + value + "'")); 409 } 410 } 411 412 protected void checkLength(long length, String name, String encoded, List<HL7Exception> exList) { 413 // check length 414 if (encoded.length() > length) 415 exList.add(new ProfileNotFollowedException("The type " + name 416 + " has length " + encoded.length() + " which exceeds max of " 417 + length)); 418 } 419 420 protected void checkDataType(String dataType, Type type, List<HL7Exception> exList) { 421 // check datatype 422 String typeName = type.getName(); 423 if (!typeName.equals(dataType)) { 424 exList.add(new ProfileNotHL7CompliantException("HL7 datatype " + typeName 425 + " doesn't match profile datatype " + dataType)); 426 } 427 } 428 429 /** 430 * Tests whether the given type falls within a maximum length. 431 * 432 * @return null of OK, an HL7Exception otherwise 433 */ 434 public HL7Exception testLength(Type type, int maxLength) { 435 HL7Exception e = null; 436 String encoded = PipeParser.encode(type, this.enc); 437 if (encoded.length() > maxLength) { 438 e = new ProfileNotFollowedException("Length of " + encoded.length() 439 + " exceeds maximum of " + maxLength); 440 } 441 return e; 442 } 443 444 /** 445 * Tests an element against the corresponding usage code. The element is required in its encoded 446 * form. 447 * 448 * @param encoded the pipe-encoded message element 449 * @param usage the usage code (e.g. "CE") 450 * @param name the name of the element (for use in exception messages) 451 * @return null if there is no problem, an HL7Exception otherwise 452 */ 453 protected void testUsage(String encoded, String usage, String name, List<HL7Exception> exList) { 454 if (usage.equalsIgnoreCase("R")) { 455 if (encoded.length() == 0) 456 exList.add(new ProfileNotFollowedException("Required element " + name + " is missing")); 457 } else if (usage.equalsIgnoreCase("RE")) { 458 // can't test anything 459 } else if (usage.equalsIgnoreCase("O")) { 460 // can't test anything 461 } else if (usage.equalsIgnoreCase("C")) { 462 // can't test anything yet -- wait for condition syntax in v2.6 463 } else if (usage.equalsIgnoreCase("CE")) { 464 // can't test anything 465 } else if (usage.equalsIgnoreCase("X")) { 466 if (encoded.length() > 0) 467 exList.add(new XElementPresentException("Element \"" + name 468 + "\" is present but specified as not used (X)")); 469 } else if (usage.equalsIgnoreCase("B")) { 470 // can't test anything 471 } 472 } 473 474 /** 475 * Tests table values for ID, IS, and CE types. An empty list is returned for all other types or 476 * if the table name or number is missing. 477 */ 478 protected void testTypeAgainstTable(Type type, AbstractComponent<?> profile, 479 String profileID, List<HL7Exception> exList) { 480 if (profile.getTable() != null 481 && (type.getName().equals("IS") || type.getName().equals("ID"))) { 482 String codeSystem = String.format("HL7%1$4s", profile.getTable()).replace(" ", "0"); 483 String value = ((Primitive) type).getValue(); 484 addTableTestResult(profileID, codeSystem, value, exList); 485 } else if (type.getName().equals("CE")) { 486 String value = Terser.getPrimitive(type, 1, 1).getValue(); 487 String codeSystem = Terser.getPrimitive(type, 3, 1).getValue(); 488 addTableTestResult(profileID, codeSystem, value, exList); 489 490 value = Terser.getPrimitive(type, 4, 1).getValue(); 491 codeSystem = Terser.getPrimitive(type, 6, 1).getValue(); 492 addTableTestResult(profileID, codeSystem, value, exList); 493 } 494 } 495 496 protected void addTableTestResult(String profileID, String codeSystem, String value, List<HL7Exception> exList) { 497 if (codeSystem != null && value != null && validateChildren) { 498 testValueAgainstTable(profileID, codeSystem, value, exList); 499 } 500 } 501 502 protected void testValueAgainstTable(String profileID, String codeSystem, String value, List<HL7Exception> exList) { 503 CodeStore store = codeStore; 504 if (codeStore == null) { 505 store = getHapiContext().getCodeStoreRegistry().getCodeStore(profileID, codeSystem); 506 } 507 508 if (store == null) { 509 log.info( 510 "Not checking value {}: no code store was found for profile {} code system {}", 511 new Object[] { value, profileID, codeSystem }); 512 } else { 513 if (!store.knowsCodes(codeSystem)) { 514 log.warn("Not checking value {}: Don't have a table for code system {}", value, 515 codeSystem); 516 } else if (!store.isValidCode(codeSystem, value)) { 517 exList.add(new ProfileNotFollowedException("Code '" + value + "' not found in table " 518 + codeSystem + ", profile " + profileID)); 519 } 520 } 521 522 } 523 524 public List<HL7Exception> testField(Type type, Field profile, boolean escape, String profileID) 525 throws ProfileException, HL7Exception { 526 return doTestField(type, profile, escape, profileID, true); 527 } 528 529 protected List<HL7Exception> doTestField(Type type, Field profile, boolean escape, String profileID, 530 boolean theValidateChildren) throws ProfileException, HL7Exception { 531 List<HL7Exception> exList = new ArrayList<HL7Exception>(); 532 533 // account for MSH 1 & 2 which aren't escaped 534 String encoded = null; 535 if (!escape && Primitive.class.isAssignableFrom(type.getClass())) 536 encoded = ((Primitive) type).getValue(); 537 538 exList.addAll(testType(type, profile, encoded, profileID)); 539 540 // test children 541 if (theValidateChildren) { 542 if (profile.getComponents() > 0 && !profile.getUsage().equals("X")) { 543 if (Composite.class.isAssignableFrom(type.getClass())) { 544 Composite comp = (Composite) type; 545 for (int i = 1; i <= profile.getComponents(); i++) { 546 Component childProfile = profile.getComponent(i); 547 try { 548 Type child = comp.getComponent(i - 1); 549 exList.addAll(doTestComponent(child, childProfile, profileID, validateChildren)); 550 } catch (DataTypeException de) { 551 exList.add(new ProfileNotHL7CompliantException( 552 "More components in profile than allowed in message: " 553 + de.getMessage())); 554 } 555 } 556 checkExtraComponents(comp, profile.getComponents(), exList); 557 } else { 558 exList.add(new ProfileNotHL7CompliantException("A field has type primitive " 559 + type.getClass().getName() + " but the profile defines components")); 560 } 561 } 562 } 563 564 return exList; 565 } 566 567 public List<HL7Exception> testComponent(Type type, Component profile, String profileID) 568 throws ProfileException, HL7Exception { 569 return doTestComponent(type, profile, profileID, true); 570 } 571 572 protected List<HL7Exception> doTestComponent(Type type, Component profile, String profileID, 573 boolean theValidateChildren) throws ProfileException, HL7Exception { 574 List<HL7Exception> exList = new ArrayList<HL7Exception>(); 575 exList.addAll(testType(type, profile, null, profileID)); 576 577 // test children 578 if (profile.getSubComponents() > 0 && !profile.getUsage().equals("X") && (!type.isEmpty())) { 579 if (Composite.class.isAssignableFrom(type.getClass())) { 580 Composite comp = (Composite) type; 581 582 if (theValidateChildren) { 583 for (int i = 1; i <= profile.getSubComponents(); i++) { 584 SubComponent childProfile = profile.getSubComponent(i); 585 try { 586 Type child = comp.getComponent(i - 1); 587 exList.addAll(testType(child, childProfile, null, profileID)); 588 } catch (DataTypeException de) { 589 exList.add(new ProfileNotHL7CompliantException( 590 "More subcomponents in profile than allowed in message: " 591 + de.getMessage())); 592 } 593 } 594 } 595 596 checkExtraComponents(comp, profile.getSubComponents(), exList); 597 } else { 598 exList.add(new ProfileNotFollowedException("A component has primitive type " 599 + type.getClass().getName() + " but the profile defines subcomponents")); 600 } 601 } 602 603 return exList; 604 } 605 606 /** Tests for extra components (ie any not defined in the profile) */ 607 protected void checkExtraComponents(Composite comp, int numInProfile, List<HL7Exception> exList) 608 throws ProfileException { 609 StringBuilder extra = new StringBuilder(); 610 for (int i = numInProfile; i < comp.getComponents().length; i++) { 611 try { 612 String s = PipeParser.encode(comp.getComponent(i), enc); 613 if (s.length() > 0) { 614 extra.append(s).append(enc.getComponentSeparator()); 615 } 616 } catch (DataTypeException de) { 617 throw new ProfileException("Problem testing against profile", de); 618 } 619 } 620 621 if (extra.length() > 0) { 622 exList.add(new XElementPresentException( 623 "The following components are not defined in the profile: " + extra.toString())); 624 } 625 626 } 627 628 public static void main(String args[]) { 629 630 if (args.length != 2) { 631 System.out.println("Usage: DefaultValidator message_file profile_file"); 632 System.exit(1); 633 } 634 635 DefaultValidator val = new DefaultValidator(); 636 try { 637 String msgString = loadFile(args[0]); 638 Parser parser = new GenericParser(); 639 Message message = parser.parse(msgString); 640 641 String profileString = loadFile(args[1]); 642 ProfileParser profParser = new ProfileParser(true); 643 RuntimeProfile profile = profParser.parse(profileString); 644 645 HL7Exception[] exceptions = val.validate(message, profile.getMessage()); 646 647 System.out.println("Exceptions: "); 648 for (int i = 0; i < exceptions.length; i++) { 649 System.out.println((i + 1) + ". " + exceptions[i].getMessage()); 650 } 651 } catch (Exception e) { 652 e.printStackTrace(); 653 } 654 } 655 656 /** loads file at the given path */ 657 private static String loadFile(String path) throws IOException { 658 File file = new File(path); 659 // char[] cbuf = new char[(int) file.length()]; 660 BufferedReader in = new BufferedReader(new FileReader(file)); 661 StringBuffer buf = new StringBuffer(5000); 662 int c; 663 while ((c = in.read()) != -1) { 664 buf.append((char) c); 665 } 666 // in.read(cbuf, 0, (int) file.length()); 667 in.close(); 668 // return String.valueOf(cbuf); 669 return buf.toString(); 670 } 671 672}