001 /**
002 The 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.
004 You may obtain a copy of the License at http://www.mozilla.org/MPL/
005 Software distributed under the License is distributed on an "AS IS" basis,
006 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
007 specific language governing rights and limitations under the License.
008
009 The Original Code is "AbstractGroup.java". Description:
010 "A partial implementation of Group"
011
012 The Initial Developer of the Original Code is University Health Network. Copyright (C)
013 2001. All Rights Reserved.
014
015 Contributor(s): ______________________________________.
016
017 Alternatively, the contents of this file may be used under the terms of the
018 GNU General Public License (the "GPL"), in which case the provisions of the GPL are
019 applicable instead of those above. If you wish to allow use of your version of this
020 file only under the terms of the GPL and not to allow others to use your version
021 of this file under the MPL, indicate your decision by deleting the provisions above
022 and replace them with the notice and other provisions required by the GPL License.
023 If you do not delete the provisions above, a recipient may use your version of
024 this file under either the MPL or the GPL.
025
026 */
027
028 package ca.uhn.hl7v2.model;
029
030 import java.lang.reflect.Constructor;
031 import java.util.ArrayList;
032 import java.util.Collections;
033 import java.util.HashMap;
034 import java.util.HashSet;
035 import java.util.List;
036 import java.util.Map;
037 import java.util.Set;
038
039 import ca.uhn.hl7v2.HL7Exception;
040 import ca.uhn.hl7v2.VersionLogger;
041 import ca.uhn.hl7v2.parser.EncodingCharacters;
042 import ca.uhn.hl7v2.parser.ModelClassFactory;
043 import 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 */
054 public 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 }