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 // check msg type, event type, msg struct ID 125 String msgType = t.get("/MSH-9-1"); 126 if (!msgType.equals(profile.getMsgType())) { 127 HL7Exception e = new ProfileNotFollowedException("Message type " + msgType 128 + " doesn't match profile type of " + profile.getMsgType()); 129 exList.add(e); 130 } 131 132 String evType = t.get("/MSH-9-2"); 133 if (!evType.equals(profile.getEventType()) 134 && !profile.getEventType().equalsIgnoreCase("ALL")) { 135 HL7Exception e = new ProfileNotFollowedException("Event type " + evType 136 + " doesn't match profile type of " + profile.getEventType()); 137 exList.add(e); 138 } 139 140 String msgStruct = t.get("/MSH-9-3"); 141 if (msgStruct == null || !msgStruct.equals(profile.getMsgStructID())) { 142 HL7Exception e = new ProfileNotFollowedException("Message structure " + msgStruct 143 + " doesn't match profile type of " + profile.getMsgStructID()); 144 exList.add(e); 145 } 146 147 exList.addAll(doTestGroup(message, profile, profile.getIdentifier(), 148 validateChildren)); 149 return exList.toArray(new HL7Exception[exList.size()]); 150 } 151 152 /** 153 * Tests a group against a group section of a profile. 154 */ 155 public List<HL7Exception> testGroup(Group group, SegGroup profile, String profileID) 156 throws ProfileException { 157 return doTestGroup(group, profile, profileID, true); 158 } 159 160 private List<HL7Exception> doTestGroup(Group group, AbstractSegmentContainer profile, 161 String profileID, boolean theValidateChildren) throws ProfileException { 162 List<HL7Exception> exList = new ArrayList<HL7Exception>(); 163 List<String> allowedStructures = new ArrayList<String>(); 164 165 for (ProfileStructure struct : profile) { 166 167 // only test a structure in detail if it isn't X 168 if (!struct.getUsage().equalsIgnoreCase("X")) { 169 allowedStructures.add(struct.getName()); 170 171 // see which instances have content 172 try { 173 List<Structure> instancesWithContent = new ArrayList<Structure>(); 174 for (Structure instance : group.getAll(struct.getName())) { 175 if (!instance.isEmpty()) 176 instancesWithContent.add(instance); 177 } 178 179 HL7Exception ce = testCardinality(instancesWithContent.size(), struct.getMin(), 180 struct.getMax(), struct.getUsage(), struct.getName()); 181 if (ce != null) 182 exList.add(ce); 183 184 // test children on instances with content 185 if (theValidateChildren) { 186 for (Structure s : instancesWithContent) { 187 List<HL7Exception> childExceptions = testStructure(s, struct, profileID); 188 exList.addAll(childExceptions); 189 } 190 } 191 192 } catch (HL7Exception he) { 193 exList.add(new ProfileNotHL7CompliantException(struct.getName() 194 + " not found in message")); 195 } 196 } 197 } 198 199 // complain about X structures that have content 200 exList.addAll(checkForExtraStructures(group, allowedStructures)); 201 202 return exList; 203 } 204 205 /** 206 * Checks a group's children against a list of allowed structures for the group (ie those 207 * mentioned in the profile with usage other than X). Returns a list of exceptions representing 208 * structures that appear in the message but are not supposed to. 209 */ 210 private List<HL7Exception> checkForExtraStructures(Group group, List<String> allowedStructures) 211 throws ProfileException { 212 List<HL7Exception> exList = new ArrayList<HL7Exception>(); 213 for (String childName : group.getNames()) { 214 if (!allowedStructures.contains(childName)) { 215 try { 216 for (Structure rep : group.getAll(childName)) { 217 if (!rep.isEmpty()) { 218 HL7Exception e = new XElementPresentException("The structure " 219 + childName + " appears in the message but not in the profile"); 220 exList.add(e); 221 } 222 } 223 } catch (HL7Exception he) { 224 throw new ProfileException("Problem checking profile", he); 225 } 226 } 227 } 228 return exList; 229 } 230 231 /** 232 * Checks cardinality and creates an appropriate exception if out of bounds. The usage code is 233 * needed because if min cardinality is > 0, the min # of reps is only required if the usage 234 * code is 'R' (see HL7 v2.5 section 2.12.6.4). 235 * 236 * @param reps the number of reps 237 * @param min the minimum number of reps 238 * @param max the maximum number of reps (-1 means *) 239 * @param usage the usage code 240 * @param name the name of the repeating structure (used in exception msg) 241 * @return null if cardinality OK, exception otherwise 242 */ 243 protected HL7Exception testCardinality(int reps, int min, int max, String usage, String name) { 244 HL7Exception e = null; 245 if (reps < min && usage.equalsIgnoreCase("R")) { 246 e = new ProfileNotFollowedException(name + " must have at least " + min 247 + " repetitions (has " + reps + ")"); 248 } else if (max > 0 && reps > max) { 249 e = new ProfileNotFollowedException(name + " must have no more than " + max 250 + " repetitions (has " + reps + ")"); 251 } 252 return e; 253 } 254 255 /** 256 * Tests a structure (segment or group) against the corresponding part of a profile. 257 */ 258 public List<HL7Exception> testStructure(Structure s, ProfileStructure profile, String profileID) 259 throws ProfileException { 260 List<HL7Exception> exList = new ArrayList<HL7Exception>(); 261 if (profile instanceof Seg) { 262 if (Segment.class.isAssignableFrom(s.getClass())) { 263 exList.addAll(doTestSegment((Segment) s, (Seg) profile, profileID, validateChildren)); 264 } else { 265 exList.add(new ProfileNotHL7CompliantException( 266 "Mismatch between a segment in the profile and the structure " 267 + s.getClass().getName() + " in the message")); 268 } 269 } else if (profile instanceof SegGroup) { 270 if (Group.class.isAssignableFrom(s.getClass())) { 271 exList.addAll(testGroup((Group) s, (SegGroup) profile, profileID)); 272 } else { 273 exList.add(new ProfileNotHL7CompliantException( 274 "Mismatch between a group in the profile and the structure " 275 + s.getClass().getName() + " in the message")); 276 } 277 } 278 return exList; 279 } 280 281 /** 282 * Tests a segment against a segment section of a profile. 283 */ 284 public List<HL7Exception> testSegment(ca.uhn.hl7v2.model.Segment segment, Seg profile, 285 String profileID) throws ProfileException { 286 return doTestSegment(segment, profile, profileID, true); 287 } 288 289 private List<HL7Exception> doTestSegment(ca.uhn.hl7v2.model.Segment segment, Seg profile, 290 String profileID, boolean theValidateChildren) throws ProfileException { 291 List<HL7Exception> exList = new ArrayList<HL7Exception>(); 292 List<Integer> allowedFields = new ArrayList<Integer>(); 293 294 for (int i = 1; i <= profile.getFields(); i++) { 295 Field field = profile.getField(i); 296 297 // only test a field in detail if it isn't X 298 if (!field.getUsage().equalsIgnoreCase("X")) { 299 allowedFields.add(i); 300 301 // see which instances have content 302 try { 303 Type[] instances = segment.getField(i); 304 List<Type> instancesWithContent = new ArrayList<Type>(); 305 for (Type instance : instances) { 306 if (!instance.isEmpty()) 307 instancesWithContent.add(instance); 308 } 309 310 HL7Exception ce = testCardinality(instancesWithContent.size(), field.getMin(), 311 field.getMax(), field.getUsage(), field.getName()); 312 if (ce != null) { 313 ce.setFieldPosition(i); 314 exList.add(ce); 315 } 316 317 // test field instances with content 318 if (theValidateChildren) { 319 for (Type s : instancesWithContent) { 320 boolean escape = true; // escape field value when checking length 321 if (profile.getName().equalsIgnoreCase("MSH") && i < 3) { 322 escape = false; 323 } 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 exList.addAll(checkForExtraFields(segment, allowedFields)); 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 private List<HL7Exception> checkForExtraFields(Segment segment, List<Integer> allowedFields) 358 throws ProfileException { 359 ArrayList<HL7Exception> exList = new ArrayList<HL7Exception>(); 360 for (int i = 1; i <= segment.numFields(); i++) { 361 if (!allowedFields.contains(new Integer(i))) { 362 try { 363 Type[] reps = segment.getField(i); 364 for (Type rep : reps) { 365 if (!rep.isEmpty()) { 366 HL7Exception e = new XElementPresentException("Field " + i + " in " 367 + segment.getName() 368 + " appears in the message but not in the profile"); 369 exList.add(e); 370 } 371 } 372 } catch (HL7Exception he) { 373 throw new ProfileException("Problem testing against profile", he); 374 } 375 } 376 } 377 return exList; 378 } 379 380 /** 381 * Tests a Type against the corresponding section of a profile. 382 * 383 * @param encoded optional encoded form of type (if you want to specify this -- if null, default 384 * pipe-encoded form is used to check length and constant val) 385 */ 386 public List<HL7Exception> testType(Type type, AbstractComponent<?> profile, String encoded, 387 String profileID) { 388 ArrayList<HL7Exception> exList = new ArrayList<HL7Exception>(); 389 if (encoded == null) 390 encoded = PipeParser.encode(type, this.enc); 391 392 HL7Exception ue = testUsage(encoded, profile.getUsage(), profile.getName()); 393 if (ue != null) 394 exList.add(ue); 395 396 if (!profile.getUsage().equals("X")) { 397 // check datatype 398 String typeName = type.getName(); 399 if (!typeName.equals(profile.getDatatype())) { 400 exList.add(new ProfileNotHL7CompliantException("HL7 datatype " + typeName 401 + " doesn't match profile datatype " + profile.getDatatype())); 402 } 403 404 // check length 405 if (encoded.length() > profile.getLength()) 406 exList.add(new ProfileNotFollowedException("The type " + profile.getName() 407 + " has length " + encoded.length() + " which exceeds max of " 408 + profile.getLength())); 409 410 // check constant value 411 if (profile.getConstantValue() != null && profile.getConstantValue().length() > 0) { 412 if (!encoded.equals(profile.getConstantValue())) 413 exList.add(new ProfileNotFollowedException("'" + encoded 414 + "' doesn't equal constant value of '" + profile.getConstantValue() 415 + "'")); 416 } 417 418 exList.addAll(testTypeAgainstTable(type, profile, profileID)); 419 } 420 421 return exList; 422 } 423 424 /** 425 * Tests whether the given type falls within a maximum length. 426 * 427 * @return null of OK, an HL7Exception otherwise 428 */ 429 public HL7Exception testLength(Type type, int maxLength) { 430 HL7Exception e = null; 431 String encoded = PipeParser.encode(type, this.enc); 432 if (encoded.length() > maxLength) { 433 e = new ProfileNotFollowedException("Length of " + encoded.length() 434 + " exceeds maximum of " + maxLength); 435 } 436 return e; 437 } 438 439 /** 440 * Tests an element against the corresponding usage code. The element is required in its encoded 441 * form. 442 * 443 * @param encoded the pipe-encoded message element 444 * @param usage the usage code (e.g. "CE") 445 * @param name the name of the element (for use in exception messages) 446 * @return null if there is no problem, an HL7Exception otherwise 447 */ 448 private HL7Exception testUsage(String encoded, String usage, String name) { 449 HL7Exception e = null; 450 if (usage.equalsIgnoreCase("R")) { 451 if (encoded.length() == 0) 452 e = new ProfileNotFollowedException("Required element " + name + " is missing"); 453 } else if (usage.equalsIgnoreCase("RE")) { 454 // can't test anything 455 } else if (usage.equalsIgnoreCase("O")) { 456 // can't test anything 457 } else if (usage.equalsIgnoreCase("C")) { 458 // can't test anything yet -- wait for condition syntax in v2.6 459 } else if (usage.equalsIgnoreCase("CE")) { 460 // can't test anything 461 } else if (usage.equalsIgnoreCase("X")) { 462 if (encoded.length() > 0) 463 e = new XElementPresentException("Element \"" + name 464 + "\" is present but specified as not used (X)"); 465 } else if (usage.equalsIgnoreCase("B")) { 466 // can't test anything 467 } 468 return e; 469 } 470 471 /** 472 * Tests table values for ID, IS, and CE types. An empty list is returned for all other types or 473 * if the table name or number is missing. 474 */ 475 private List<HL7Exception> testTypeAgainstTable(Type type, AbstractComponent<?> profile, 476 String profileID) { 477 ArrayList<HL7Exception> exList = new ArrayList<HL7Exception>(); 478 if (profile.getTable() != null 479 && (type.getName().equals("IS") || type.getName().equals("ID"))) { 480 String codeSystem = makeTableName(profile.getTable()); 481 String value = ((Primitive) type).getValue(); 482 addTableTestResult(exList, profileID, codeSystem, value); 483 } else if (type.getName().equals("CE")) { 484 String value = Terser.getPrimitive(type, 1, 1).getValue(); 485 String codeSystem = Terser.getPrimitive(type, 3, 1).getValue(); 486 addTableTestResult(exList, profileID, codeSystem, value); 487 488 value = Terser.getPrimitive(type, 4, 1).getValue(); 489 codeSystem = Terser.getPrimitive(type, 6, 1).getValue(); 490 addTableTestResult(exList, profileID, codeSystem, value); 491 } 492 return exList; 493 } 494 495 private void addTableTestResult(List<HL7Exception> exList, String profileID, 496 String codeSystem, String value) { 497 if (codeSystem != null && value != null) { 498 HL7Exception e = testValueAgainstTable(profileID, codeSystem, value); 499 if (e != null) 500 exList.add(e); 501 } 502 } 503 504 private HL7Exception testValueAgainstTable(String profileID, String codeSystem, String value) { 505 HL7Exception ret = null; 506 if (!validateChildren) { 507 return ret; 508 } 509 510 CodeStore store = codeStore; 511 if (codeStore == null) { 512 store = getHapiContext().getCodeStoreRegistry().getCodeStore(profileID, codeSystem); 513 } 514 515 if (store == null) { 516 log.warn( 517 "Not checking value {}: no code store was found for profile {} code system {}", 518 new Object[] { value, profileID, codeSystem }); 519 } else { 520 if (!store.knowsCodes(codeSystem)) { 521 log.warn("Not checking value {}: Don't have a table for code system {}", value, 522 codeSystem); 523 } else if (!store.isValidCode(codeSystem, value)) { 524 ret = new ProfileNotFollowedException("Code '" + value + "' not found in table " 525 + codeSystem + ", profile " + profileID); 526 } 527 } 528 return ret; 529 } 530 531 private String makeTableName(String hl7Table) { 532 return String.format("HL7%1$4s", hl7Table).replace(" ", "0"); 533 } 534 535 public List<HL7Exception> testField(Type type, Field profile, boolean escape, String profileID) 536 throws ProfileException { 537 return doTestField(type, profile, escape, profileID, true); 538 } 539 540 private List<HL7Exception> doTestField(Type type, Field profile, boolean escape, String profileID, 541 boolean theValidateChildren) throws ProfileException { 542 List<HL7Exception> exList = new ArrayList<HL7Exception>(); 543 544 // account for MSH 1 & 2 which aren't escaped 545 String encoded = null; 546 if (!escape && Primitive.class.isAssignableFrom(type.getClass())) 547 encoded = ((Primitive) type).getValue(); 548 549 exList.addAll(testType(type, profile, encoded, profileID)); 550 551 // test children 552 if (theValidateChildren) { 553 if (profile.getComponents() > 0 && !profile.getUsage().equals("X")) { 554 if (Composite.class.isAssignableFrom(type.getClass())) { 555 Composite comp = (Composite) type; 556 for (int i = 1; i <= profile.getComponents(); i++) { 557 Component childProfile = profile.getComponent(i); 558 try { 559 Type child = comp.getComponent(i - 1); 560 exList.addAll(doTestComponent(child, childProfile, profileID, validateChildren)); 561 } catch (DataTypeException de) { 562 exList.add(new ProfileNotHL7CompliantException( 563 "More components in profile than allowed in message: " 564 + de.getMessage())); 565 } 566 } 567 exList.addAll(checkExtraComponents(comp, profile.getComponents())); 568 } else { 569 exList.add(new ProfileNotHL7CompliantException("A field has type primitive " 570 + type.getClass().getName() + " but the profile defines components")); 571 } 572 } 573 } 574 575 return exList; 576 } 577 578 public List<HL7Exception> testComponent(Type type, Component profile, String profileID) 579 throws ProfileException { 580 return doTestComponent(type, profile, profileID, true); 581 } 582 583 private List<HL7Exception> doTestComponent(Type type, Component profile, String profileID, 584 boolean theValidateChildren) throws ProfileException { 585 List<HL7Exception> exList = new ArrayList<HL7Exception>(); 586 exList.addAll(testType(type, profile, null, profileID)); 587 588 // test children 589 if (profile.getSubComponents() > 0 && !profile.getUsage().equals("X") && (!type.isEmpty())) { 590 if (Composite.class.isAssignableFrom(type.getClass())) { 591 Composite comp = (Composite) type; 592 593 if (theValidateChildren) { 594 for (int i = 1; i <= profile.getSubComponents(); i++) { 595 SubComponent childProfile = profile.getSubComponent(i); 596 try { 597 Type child = comp.getComponent(i - 1); 598 exList.addAll(testType(child, childProfile, null, profileID)); 599 } catch (DataTypeException de) { 600 exList.add(new ProfileNotHL7CompliantException( 601 "More subcomponents in profile than allowed in message: " 602 + de.getMessage())); 603 } 604 } 605 } 606 607 exList.addAll(checkExtraComponents(comp, profile.getSubComponents())); 608 } else { 609 exList.add(new ProfileNotFollowedException("A component has primitive type " 610 + type.getClass().getName() + " but the profile defines subcomponents")); 611 } 612 } 613 614 return exList; 615 } 616 617 /** Tests for extra components (ie any not defined in the profile) */ 618 private List<HL7Exception> checkExtraComponents(Composite comp, int numInProfile) 619 throws ProfileException { 620 List<HL7Exception> exList = new ArrayList<HL7Exception>(); 621 622 StringBuffer extra = new StringBuffer(); 623 for (int i = numInProfile; i < comp.getComponents().length; i++) { 624 try { 625 String s = PipeParser.encode(comp.getComponent(i), enc); 626 if (s.length() > 0) { 627 extra.append(s).append(enc.getComponentSeparator()); 628 } 629 } catch (DataTypeException de) { 630 throw new ProfileException("Problem testing against profile", de); 631 } 632 } 633 634 if (extra.toString().length() > 0) { 635 exList.add(new XElementPresentException( 636 "The following components are not defined in the profile: " + extra.toString())); 637 } 638 639 return exList; 640 } 641 642 public static void main(String args[]) { 643 644 if (args.length != 2) { 645 System.out.println("Usage: DefaultValidator message_file profile_file"); 646 System.exit(1); 647 } 648 649 DefaultValidator val = new DefaultValidator(); 650 try { 651 String msgString = loadFile(args[0]); 652 Parser parser = new GenericParser(); 653 Message message = parser.parse(msgString); 654 655 String profileString = loadFile(args[1]); 656 ProfileParser profParser = new ProfileParser(true); 657 RuntimeProfile profile = profParser.parse(profileString); 658 659 HL7Exception[] exceptions = val.validate(message, profile.getMessage()); 660 661 System.out.println("Exceptions: "); 662 for (int i = 0; i < exceptions.length; i++) { 663 System.out.println((i + 1) + ". " + exceptions[i].getMessage()); 664 } 665 } catch (Exception e) { 666 e.printStackTrace(); 667 } 668 } 669 670 /** loads file at the given path */ 671 private static String loadFile(String path) throws IOException { 672 File file = new File(path); 673 // char[] cbuf = new char[(int) file.length()]; 674 BufferedReader in = new BufferedReader(new FileReader(file)); 675 StringBuffer buf = new StringBuffer(5000); 676 int c; 677 while ((c = in.read()) != -1) { 678 buf.append((char) c); 679 } 680 // in.read(cbuf, 0, (int) file.length()); 681 in.close(); 682 // return String.valueOf(cbuf); 683 return buf.toString(); 684 } 685 686}