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 "AbstractGroup.java". Description: 010"A partial implementation of Group" 011 012The Initial Developer of the Original Code is University Health Network. Copyright (C) 0132001. 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.model; 029 030import java.lang.reflect.Constructor; 031import java.util.ArrayList; 032import java.util.Collections; 033import java.util.HashMap; 034import java.util.HashSet; 035import java.util.List; 036import java.util.Map; 037import java.util.Set; 038 039import ca.uhn.hl7v2.HL7Exception; 040import ca.uhn.hl7v2.VersionLogger; 041import ca.uhn.hl7v2.parser.EncodingCharacters; 042import ca.uhn.hl7v2.parser.ModelClassFactory; 043import ca.uhn.hl7v2.parser.PipeParser; 044 045/** 046 * A partial implementation of Group. Subclasses correspond to specific groups 047 * of segments (and/or other sub-groups) that are implicitly defined by message 048 * structures in the HL7 specification. A subclass should define it's group 049 * structure by putting repeated calls to the add(...) method in it's 050 * constructor. Each call to add(...) adds a specific component to the Group. 051 * 052 * @author Bryan Tripp (bryan_tripp@sourceforge.net) 053 */ 054public abstract class AbstractGroup extends AbstractStructure implements Group { 055 056 private static final long serialVersionUID = 1772720246448224363L; 057 058 private List<String> names; 059 private Map<String, List<Structure>> structures; 060 private Map<String, Boolean> required; 061 private Map<String, Boolean> repeating; 062 private Map<String, Class<? extends Structure>> classes; 063 // protected Message message; 064 private Set<String> nonStandardNames; 065 private final ModelClassFactory myFactory; 066 067 static { 068 VersionLogger.init(); 069 } 070 071 /** 072 * This constructor should be used by implementing classes that do not also 073 * implement Message. 074 * 075 * @param parent 076 * the group to which this Group belongs. 077 * @param factory 078 * the factory for classes of segments, groups, and datatypes 079 * under this group 080 */ 081 protected AbstractGroup(Group parent, ModelClassFactory factory) { 082 super(parent); 083 this.myFactory = factory; 084 init(); 085 } 086 087 private void init() { 088 names = new ArrayList<String>(); 089 structures = new HashMap<String, List<Structure>>(); 090 required = new HashMap<String, Boolean>(); 091 repeating = new HashMap<String, Boolean>(); 092 classes = new HashMap<String, Class<? extends Structure>>(); 093 } 094 095 /** 096 * Returns the named structure. If this Structure is repeating then the 097 * first repetition is returned. Creates the Structure if necessary. 098 * 099 * @throws HL7Exception 100 * if the named Structure is not part of this Group. 101 */ 102 public Structure get(String name) throws HL7Exception { 103 return get(name, 0); 104 } 105 106 protected <T extends Structure> T getTyped(String name, Class<T> type) { 107 try { 108 @SuppressWarnings("unchecked") T ret = (T)get(name); 109 return ret; 110 } catch(HL7Exception e) { 111 log.error("Unexpected error accessing data - this is probably a bug in the source code generator.", e); 112 throw new RuntimeException(e); 113 } 114 } 115 116 /** 117 * Returns a particular repetition of the named Structure. If the given 118 * repetition number is one greater than the existing number of repetitions 119 * then a new Structure is created. 120 * 121 * @throws HL7Exception 122 * if the named Structure is not part of this group, if the 123 * structure is not repeatable and the given rep is > 0, or if 124 * the given repetition number is more than one greater than the 125 * existing number of repetitions. 126 */ 127 public Structure get(String name, int rep) throws HL7Exception { 128 List<Structure> list = structures.get(name); 129 if (list == null) 130 throw new HL7Exception(name + " does not exist in the group " + this.getClass().getName(), HL7Exception.APPLICATION_INTERNAL_ERROR); 131 132 Structure ret; 133 if (rep < list.size()) { 134 // return existing Structure if it exists 135 ret = list.get(rep); 136 } else if (rep == list.size()) { 137 // verify that Structure is repeating ... 138 Boolean repeats = this.repeating.get(name); 139 if (!repeats.booleanValue() && list.size() > 0) 140 throw new HL7Exception("Can't create repetition #" + rep + " of Structure " + name + " - this Structure is non-repeating", HL7Exception.APPLICATION_INTERNAL_ERROR); 141 142 // create a new Structure, add it to the list, and return it 143 Class<? extends Structure> c = classes.get(name); // get class 144 ret = tryToInstantiateStructure(c, name); 145 list.add(ret); 146 } else { 147 throw new HL7Exception("Can't return repetition #" + rep + " of " + name + " - there are only " + list.size() + " repetitions.", 148 HL7Exception.APPLICATION_INTERNAL_ERROR); 149 } 150 return ret; 151 } 152 153 protected <T extends Structure> T getTyped(String name, int rep, Class<T> type) { 154 try { 155 @SuppressWarnings("unchecked") T ret = (T)get(name, rep); 156 return ret; 157 } catch(HL7Exception e) { 158 log.error("Unexpected error accessing data - this is probably a bug in the source code generator.", e); 159 throw new RuntimeException(e); 160 } 161 } 162 163 protected int getReps(String name) { 164 try { 165 return getAll(name).length; 166 } catch (HL7Exception e) { 167 String message = "Unexpected error accessing data - this is probably a bug in the source code generator."; 168 log.error(message, e); 169 throw new RuntimeException(message); 170 } 171 } 172 173 /** 174 * Expands the group definition to include a segment that is not defined by 175 * HL7 to be part of this group (eg an unregistered Z segment). The new 176 * segment is slotted at the end of the group. Thenceforward if such a 177 * segment is encountered it will be parsed into this location. If the 178 * segment name is unrecognized a GenericSegment is used. The segment is 179 * defined as repeating and not required. 180 */ 181 public String addNonstandardSegment(String name) throws HL7Exception { 182 String version = this.getMessage().getVersion(); 183 if (version == null) 184 throw new HL7Exception("Need message version to add segment by name; message.getVersion() returns null"); 185 Class<? extends Structure> c = myFactory.getSegmentClass(name, version); 186 if (c == null) 187 c = GenericSegment.class; 188 189 int index = this.getNames().length; 190 191 tryToInstantiateStructure(c, name); // may throw exception 192 193 String newName = insert(c, false, true, index, name); 194 if (this.nonStandardNames == null) { 195 this.nonStandardNames = new HashSet<String>(); 196 } 197 this.nonStandardNames.add(newName); 198 199 return newName; 200 } 201 202 public String addNonstandardSegment(String theName, int theIndex) throws HL7Exception { 203 if (this instanceof Message && theIndex == 0) { 204 throw new HL7Exception("Can not add nonstandard segment \"" + theName + "\" to start of message."); 205 } 206 207 String version = this.getMessage().getVersion(); 208 if (version == null) 209 throw new HL7Exception("Need message version to add segment by name; message.getVersion() returns null"); 210 Class<? extends Structure> c = myFactory.getSegmentClass(theName, version); 211 212 if (c == null) { 213 c = GenericSegment.class; 214 } 215 216 tryToInstantiateStructure(c, theName); // may throw exception 217 218 String newName = insert(c, false, true, theIndex, theName); 219 if (this.nonStandardNames == null) { 220 this.nonStandardNames = new HashSet<String>(); 221 } 222 this.nonStandardNames.add(newName); 223 224 return newName; 225 } 226 227 /** 228 * Returns a Set containing the names of all non-standard structures 229 * which have been added to this structure 230 */ 231 public Set<String> getNonStandardNames() { 232 if (nonStandardNames == null) { 233 return Collections.emptySet(); 234 } 235 return Collections.unmodifiableSet(nonStandardNames); 236 } 237 238 /** 239 * Returns an ordered array of the names of the Structures in this Group. 240 * These names can be used to iterate through the group using repeated calls 241 * to <code>get(name)</code>. 242 */ 243 public String[] getNames() { 244 String[] retVal = new String[this.names.size()]; 245 for (int i = 0; i < this.names.size(); i++) { 246 retVal[i] = this.names.get(i); 247 } 248 return retVal; 249 } 250 251 /** 252 * Adds a new Structure (group or segment) to this Group. A place for the 253 * Structure is added to the group but there are initially zero repetitions. 254 * This method should be used by the constructors of implementing classes to 255 * specify which Structures the Group contains - Structures should be added 256 * in the order in which they appear. Note that the class is supplied 257 * instead of an instance because we want there initially to be zero 258 * instances of each structure but we want the AbstractGroup code to be able 259 * to create instances as necessary to support get(...) calls. 260 * 261 * @return the actual name used to store this structure (may be appended 262 * with an integer if there are duplicates in the same Group). 263 */ 264 protected String add(Class<? extends Structure> c, boolean required, boolean repeating) throws HL7Exception { 265 String name = getName(c); 266 return insert(c, required, repeating, this.names.size(), name); 267 } 268 269 /** 270 * Adds a new Structure (group or segment) to this Group. A place for the 271 * Structure is added to the group but there are initially zero repetitions. 272 * This method should be used by the constructors of implementing classes to 273 * specify which Structures the Group contains - Structures should be added 274 * in the order in which they appear. Note that the class is supplied 275 * instead of an instance because we want there initially to be zero 276 * instances of each structure but we want the AbstractGroup code to be able 277 * to create instances as necessary to support get(...) calls. 278 * 279 * @return the actual name used to store this structure (may be appended 280 * with an integer if there are duplicates in the same Group). 281 */ 282 protected String add(Class<? extends Structure> c, boolean required, boolean repeating, int index) throws HL7Exception { 283 String name = getName(c); 284 return insert(c, required, repeating, index, name); 285 } 286 287 /** 288 * Returns true if the class name is already being used. 289 */ 290 private boolean nameExists(String name) { 291 return this.classes.get(name) != null; 292 } 293 294 /** 295 * Attempts to create an instance of the given class and return it as a 296 * Structure. 297 * 298 * @param c 299 * the Structure implementing class 300 * @param name 301 * an optional name of the structure (used by Generic structures; 302 * may be null) 303 */ 304 protected Structure tryToInstantiateStructure(Class<? extends Structure> c, String name) throws HL7Exception { 305 Structure s = null; 306 try { 307 Object o = null; 308 if (GenericSegment.class.isAssignableFrom(c)) { 309 String genericName = name; 310 if (genericName.length() > 3) { 311 genericName = genericName.substring(0, 3); 312 } 313 314 s = new GenericSegment(this, genericName); 315 } else if (GenericGroup.class.isAssignableFrom(c)) { 316 s = new GenericGroup(this, name, myFactory); 317 } else { 318 // first try to instantiate using constructor w/ Message args 319 // ... 320 try { 321 Class<?>[] argClasses = { Group.class, ModelClassFactory.class }; 322 Object[] argObjects = { this, myFactory }; 323 Constructor<?> con = c.getConstructor(argClasses); 324 o = con.newInstance(argObjects); 325 } catch (NoSuchMethodException nme) { 326 o = c.newInstance(); 327 } 328 if (!(o instanceof Structure)) 329 throw new HL7Exception("Class " + c.getName() + " does not implement " + "ca.on.uhn.hl7.message.Structure", HL7Exception.APPLICATION_INTERNAL_ERROR); 330 s = (Structure) o; 331 } 332 } catch (Exception e) { 333 if (e instanceof HL7Exception) { 334 throw (HL7Exception) e; 335 } else { 336 throw new HL7Exception("Can't instantiate class " + c.getName(), HL7Exception.APPLICATION_INTERNAL_ERROR, e); 337 } 338 } 339 return s; 340 } 341 342 /** 343 * Returns true if the named structure is a group 344 */ 345 public boolean isGroup(String name) throws HL7Exception { 346 Class<? extends Structure> clazz = classes.get(name); 347 if (clazz == null) 348 throw new HL7Exception("The structure " + name + " does not exist in the group " + this.getClass().getName(), HL7Exception.APPLICATION_INTERNAL_ERROR); 349 return Group.class.isAssignableFrom(clazz); 350 } 351 352 /** 353 * Returns true if the named structure is required. 354 */ 355 public boolean isRequired(String name) throws HL7Exception { 356 Object o = required.get(name); 357 if (o == null) 358 throw new HL7Exception("The structure " + name + " does not exist in the group " + this.getClass().getName(), HL7Exception.APPLICATION_INTERNAL_ERROR); 359 Boolean req = (Boolean) o; 360 return req.booleanValue(); 361 } 362 363 /** 364 * Returns true if the named structure is required. 365 */ 366 public boolean isRepeating(String name) throws HL7Exception { 367 Object o = repeating.get(name); 368 if (o == null) 369 throw new HL7Exception("The structure " + name + " does not exist in the group " + this.getClass().getName(), HL7Exception.APPLICATION_INTERNAL_ERROR); 370 Boolean rep = (Boolean) o; 371 return rep.booleanValue(); 372 } 373 374 /** 375 * Returns the number of existing repetitions of the named structure. 376 */ 377 public int currentReps(String name) throws HL7Exception { 378 List<Structure> list = structures.get(name); 379 if (list == null) 380 throw new HL7Exception("The structure " + name + " does not exist in the group " + this.getClass().getName(), HL7Exception.APPLICATION_INTERNAL_ERROR); 381 return list.size(); 382 } 383 384 /** 385 * Returns an array of Structure objects by name. For example, if the Group 386 * contains an MSH segment and "MSH" is supplied then this call would return 387 * a 1-element array containing the MSH segment. Multiple elements are 388 * returned when the segment or group repeats. The array may be empty if no 389 * repetitions have been accessed yet using the get(...) methods. 390 * 391 * @throws HL7Exception 392 * if the named Structure is not part of this Group. 393 */ 394 public Structure[] getAll(String name) throws HL7Exception { 395 List<Structure> list = structures.get(name); 396 if (list == null) { 397 throw new HL7Exception("The structure " + name + " does not exist in the group " + this.getClass().getName(), HL7Exception.APPLICATION_INTERNAL_ERROR); 398 } 399 return list.toArray(new Structure[list.size()]); 400 } 401 402 /** 403 * Returns a list containing all existing repetitions of the structure 404 * identified by name 405 * 406 * @throws HL7Exception 407 * if the named Structure is not part of this Group. 408 */ 409 @SuppressWarnings("unchecked") 410 protected <T extends Structure> List<T> getAllAsList(String name, Class<T> theType) throws HL7Exception { 411 Class<? extends Structure> clazz = classes.get(name); 412 413 if (!theType.equals(clazz)) { 414 throw new HL7Exception("Structure with name \"" + name + "\" has type " + clazz.getName() + " but should be " + theType); 415 } 416 List<T> retVal = new ArrayList<T>(); 417 for (Structure next : structures.get(name)) { 418 retVal.add((T) next); 419 } 420 return Collections.unmodifiableList(retVal); 421 } 422 423 /** 424 * Removes a repetition of a given Structure objects by name. For example, 425 * if the Group contains 10 repititions an OBX segment and "OBX" is supplied 426 * with an index of 2, then this call would remove the 3rd repetition. Note 427 * that in this case, the Set ID field in the OBX segments would also need 428 * to be renumbered manually. 429 * 430 * @return The removed structure 431 * @throws HL7Exception 432 * if the named Structure is not part of this Group. 433 */ 434 public Structure removeRepetition(String name, int index) throws HL7Exception { 435 List<Structure> list = structures.get(name); 436 if (list == null) { 437 throw new HL7Exception("The structure " + name + " does not exist in the group " + this.getClass().getName(), HL7Exception.APPLICATION_INTERNAL_ERROR); 438 } 439 if (list.size() == 0) { 440 throw new HL7Exception("Invalid index: " + index + ", structure " + name + " has no repetitions", HL7Exception.APPLICATION_INTERNAL_ERROR); 441 } 442 if (list.size() <= index) { 443 throw new HL7Exception("Invalid index: " + index + ", structure " + name + " must be between 0 and " + (list.size() - 1), HL7Exception.APPLICATION_INTERNAL_ERROR); 444 } 445 446 return list.remove(index); 447 } 448 449 /** 450 * Inserts a repetition of a given Structure into repetitions of that 451 * structure by name. For example, if the Group contains 10 repetitions an 452 * OBX segment and an OBX is supplied with an index of 2, then this call 453 * would insert the new repetition at index 2. (Note that in this example, the 454 * Set ID field in the OBX segments would also need to be renumbered 455 * manually). 456 * 457 * @throws HL7Exception 458 * if the named Structure is not part of this Group. 459 */ 460 protected void insertRepetition(String name, Structure structure, int index) throws HL7Exception { 461 if (structure == null) { 462 throw new NullPointerException("Structure may not be null"); 463 } 464 465 if (structure.getMessage() != this.getMessage()) { 466 throw new HL7Exception("Structure does not belong to this message", HL7Exception.APPLICATION_INTERNAL_ERROR); 467 } 468 469 List<Structure> list = structures.get(name); 470 471 if (list == null) { 472 throw new HL7Exception("The structure " + name + " does not exist in the group " + this.getClass().getName(), HL7Exception.APPLICATION_INTERNAL_ERROR); 473 } 474 if (list.size() < index) { 475 throw new HL7Exception("Invalid index: " + index + ", structure " + name + " must be between 0 and " + (list.size()), HL7Exception.APPLICATION_INTERNAL_ERROR); 476 } 477 478 list.add(index, structure); 479 } 480 481 /** 482 * Inserts a repetition of a given Structure into repetitions of that 483 * structure by name. For example, if the Group contains 10 repititions an 484 * OBX segment and an OBX is supplied with an index of 2, then this call 485 * would insert the new repetition at index 2. Note that in this case, the 486 * Set ID field in the OBX segments would also need to be renumbered 487 * manually. 488 * 489 * @return The removed structure 490 * @throws HL7Exception 491 * if the named Structure is not part of this Group. 492 */ 493 public Structure insertRepetition(String name, int index) throws HL7Exception { 494 if (name == null || name.length() == 0) { 495 throw new NullPointerException("Name may not be null/empty"); 496 } 497 498 Class<? extends Structure> structureClass = this.classes.get(name); 499 if (structureClass == null) { 500 throw new HL7Exception("Group " + this.getClass().getName() + " has no structure named " + name + ": Valid names: " + this.classes.keySet(), 501 HL7Exception.APPLICATION_INTERNAL_ERROR); 502 } 503 504 Structure rep = tryToInstantiateStructure(structureClass, name); 505 insertRepetition(name, rep, index); 506 507 return rep; 508 } 509 510 /** 511 * Given a child structure name, returns the child index (which is 1-indexed, meaning 512 * that the first child is at index 1 513 */ 514 public int getFieldNumForName(String name) throws HL7Exception { 515 int retVal = names.indexOf(name); 516 if (retVal == -1) { 517 throw new HL7Exception("Unknown name: " + name); 518 } 519 return retVal + 1; 520 } 521 522 /** 523 * Returns the Class of the Structure at the given name index. 524 */ 525 public Class<? extends Structure> getClass(String name) { 526 return classes.get(name); 527 } 528 529 /** 530 * Returns the class name (excluding package). 531 * 532 * @see Structure#getName() 533 */ 534 public String getName() { 535 return getName(this.getClass()); 536 } 537 538 // returns a name for a class of a Structure in this Message 539 private String getName(Class<? extends Structure> c) { 540 String fullName = c.getName(); 541 int dotLoc = fullName.lastIndexOf('.'); 542 String name = fullName.substring(dotLoc + 1, fullName.length()); 543 544 // remove message name prefix from group names for compatibility with 545 // getters ... 546 if (Group.class.isAssignableFrom(c) && !Message.class.isAssignableFrom(c)) { 547 String messageName = getMessage().getName(); 548 if (name.startsWith(messageName) && name.length() > messageName.length()) { 549 name = name.substring(messageName.length() + 1); 550 } 551 } 552 553 return name; 554 } 555 556 /** 557 * Inserts the given structure into this group, at the indicated index 558 * number. This method is used to support handling of unexpected segments 559 * (e.g. Z-segments). In contrast, specification of the group's normal 560 * children should be done at construction time, using the add(...) method. 561 */ 562 protected String insert(Class<? extends Structure> c, boolean required, boolean repeating, int index, String name) throws HL7Exception { 563 // tryToInstantiateStructure(c, name); //may throw exception 564 565 // see if there is already something by this name and make a new name if 566 // necessary ... 567 if (nameExists(name)) { 568 int version = 2; 569 String newName = name; 570 while (nameExists(newName)) { 571 newName = name + version++; 572 } 573 name = newName; 574 } 575 576 if (index > this.names.size()) { 577 throw new HL7Exception("Invalid index " + index + " - Should be <= " + this.names.size()); 578 } 579 580 this.names.add(index, name); 581 this.required.put(name, new Boolean(required)); 582 this.repeating.put(name, new Boolean(repeating)); 583 this.classes.put(name, c); 584 this.structures.put(name, new ArrayList<Structure>()); 585 586 return name; 587 } 588 589 /** 590 * Clears all data from this structure. 591 */ 592 public void clear() { 593 for (List<Structure> next : structures.values()) { 594 if (next != null) { 595 next.clear(); 596 } 597 } 598 } 599 600 /** 601 * Returns the {@link ModelClassFactory} associated with this structure 602 */ 603 public final ModelClassFactory getModelClassFactory() { 604 return myFactory; 605 } 606 607 /** 608 * <p> 609 * Appends a description of this group's structure and all children's structure 610 * to a string builder. 611 * </p> 612 * <p> 613 * Note that this method is intended only to be called by {@link AbstractMessage#printStructure()}. 614 * Please use caution if calling this method directly, as the method signature and/or behaviour may 615 * change in the future. 616 * </p> 617 */ 618 void appendStructureDescription(StringBuilder theStringBuilder, int theIndent, boolean theOptional, boolean theRepeating, boolean theAddStartName, boolean theAddEndName) throws HL7Exception { 619 String lineSeparator = System.getProperty("line.separator"); 620 621 if (theAddStartName) { 622 indent(theStringBuilder, theIndent); 623 theStringBuilder.append(getName()).append(" (start)").append(lineSeparator); 624 } 625 626 if (theOptional || theRepeating) { 627 indent(theStringBuilder, theIndent); 628 if (theOptional) { 629 theStringBuilder.append("["); 630 } 631 if (theRepeating) { 632 theStringBuilder.append("{"); 633 } 634 theStringBuilder.append(lineSeparator); 635 } 636 637 for (String nextName : getNames()) { 638 639 Class<? extends Structure> nextClass = classes.get(nextName); 640 641 boolean nextOptional = !isRequired(nextName); 642 boolean nextRepeating = isRepeating(nextName); 643 644 if (AbstractGroup.class.isAssignableFrom(nextClass)) { 645 646 Structure[] nextChildren = getAll(nextName); 647 for (int i = 0; i < nextChildren.length; i++) { 648 649 Structure structure = nextChildren[i]; 650 boolean addStartName = (i == 0); 651 boolean addEndName = (i == (nextChildren.length - 1)); 652 ((AbstractGroup)structure).appendStructureDescription(theStringBuilder, theIndent + 3, nextOptional, nextRepeating, addStartName, addEndName); 653 654 } 655 656 if (nextChildren.length == 0) { 657 Structure structure = tryToInstantiateStructure(nextClass, nextName); 658 ((AbstractGroup)structure).appendStructureDescription(theStringBuilder, theIndent + 3, nextOptional, nextRepeating, true, true); 659 } 660 661 } else if (Segment.class.isAssignableFrom(nextClass)) { 662 663 int currentIndent = theStringBuilder.length(); 664 665 StringBuilder structurePrefix = new StringBuilder(); 666 indent(structurePrefix, theIndent + 3); 667 if (nextOptional) { 668 structurePrefix.append("[ "); 669 } 670 if (nextRepeating) { 671 structurePrefix.append("{ "); 672 } 673 structurePrefix.append(nextName); 674 if (nextRepeating) { 675 structurePrefix.append(" }"); 676 } 677 if (nextOptional) { 678 structurePrefix.append(" ]"); 679 } 680 681 if (this.nonStandardNames != null && this.nonStandardNames.contains(nextName)) { 682 structurePrefix.append(" (non-standard)"); 683 } 684 structurePrefix.append(" - "); 685 686 currentIndent = theStringBuilder.length() - currentIndent; 687 List<Structure> nextStructureList = structures.get(nextName); 688 theStringBuilder.append(structurePrefix); 689 if (nextStructureList == null || nextStructureList.isEmpty()) { 690 theStringBuilder.append("Not populated"); 691 theStringBuilder.append(lineSeparator); 692 } else { 693 for (int i = 0; i < nextStructureList.size(); i++) { 694 if (i > 0) { 695 indent(theStringBuilder, currentIndent + structurePrefix.length()); 696 } 697 Segment nextSegment = (Segment)nextStructureList.get(i); 698 theStringBuilder.append(new PipeParser().doEncode(nextSegment, EncodingCharacters.getInstance(getMessage()))); 699 theStringBuilder.append(lineSeparator); 700 701 } 702 } 703 704 } 705 } 706 707 if (theOptional || theRepeating) { 708 indent(theStringBuilder, theIndent); 709 if (theRepeating) { 710 theStringBuilder.append("}"); 711 } 712 if (theOptional) { 713 theStringBuilder.append("]"); 714 } 715 theStringBuilder.append(lineSeparator); 716 } 717 718 if (theAddEndName) { 719 indent(theStringBuilder, theIndent); 720 theStringBuilder.append(getName()).append(" (end)").append(lineSeparator); 721 } 722 } 723 724 private void indent(StringBuilder theStringBuilder, int theIndent) { 725 for (int i = 0; i < theIndent; i++) { 726 theStringBuilder.append(' '); 727 } 728 } 729}