1 /**
2 * The contents of this file are subject to the Mozilla Public License Version 1.1
3 * (the "License"); you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at http://www.mozilla.org/MPL/
5 * Software distributed under the License is distributed on an "AS IS" basis,
6 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
7 * specific language governing rights and limitations under the License.
8 *
9 * The Original Code is "ReadOnlyMessageIterator.java". Description:
10 * "Iterator though existing Stuctures in a message. "
11 *
12 * The Initial Developer of the Original Code is University Health Network. Copyright (C)
13 * 2005. All Rights Reserved.
14 *
15 * Contributor(s): ______________________________________.
16 *
17 * Alternatively, the contents of this file may be used under the terms of the
18 * GNU General Public License (the "GPL"), in which case the provisions of the GPL are
19 * applicable instead of those above. If you wish to allow use of your version of this
20 * file only under the terms of the GPL and not to allow others to use your version
21 * of this file under the MPL, indicate your decision by deleting the provisions above
22 * and replace them with the notice and other provisions required by the GPL License.
23 * If you do not delete the provisions above, a recipient may use your version of
24 * this file under either the MPL or the GPL.
25 *
26 */
27 package ca.uhn.hl7v2.util;
28
29 import java.util.ArrayList;
30 import java.util.Iterator;
31 import java.util.List;
32 import java.util.NoSuchElementException;
33
34 import ca.uhn.hl7v2.HL7Exception;
35 import ca.uhn.hl7v2.model.Group;
36 import ca.uhn.hl7v2.model.Segment;
37 import ca.uhn.hl7v2.model.Structure;
38
39 /**
40 * Iterator though existing Stuctures in a message. No new repetitions or optional
41 * structures are created during iteration (in contrast to MessageIterator).
42 *
43 * Note that some structures are created during parsing, so the iteration may include
44 * structures which were not present in the original encoded message. If these are
45 * not desired they can be skipped using a FilterIterator. In fact to obtain an
46 * iterator only over populated segments (not groups or empty segments) use the factory
47 * method in this class.
48 *
49 * @author <a href="mailto:bryan.tripp@uhn.on.ca">Bryan Tripp</a>
50 * @version $Revision: 1.1 $ updated on $Date: 2007-02-19 02:24:27 $ by $Author: jamesagnew $
51 */
52 public class ReadOnlyMessageIterator implements Iterator<Structure> {
53
54 private final List<Structure> myRemaining; //remaining nodes in reverse order (i.e. last is next)
55
56 /**
57 * @param theRoot root of depth first iteration, which starts with the first child
58 */
59 public ReadOnlyMessageIterator(Group theRoot) {
60 myRemaining = new ArrayList<>(40);
61 addChildren(theRoot);
62 }
63
64 /**
65 * @param theRoot root of depth first iteration, which starts with the first child
66 * @return an iterator that skips groups and empty segments, returning only populated
67 * segments
68 */
69 public static Iterator<Structure> createPopulatedSegmentIterator(Group theRoot) {
70 return createPopulatedStructureIterator(theRoot, Segment.class);
71 }
72
73 /**
74 * @param theRoot root of depth first iteration, which starts with the first child
75 * @param c structure class to look for
76 * @return an iterator that skips all structures that do not match the parameter
77 */
78 public static Iterator<Structure> createPopulatedStructureIterator(Group theRoot, Class<? extends Structure> c) {
79 return createPopulatedStructureIterator(theRoot, new StructurePredicate(c));
80 }
81
82 /**
83 * @param theRoot root of depth first iteration, which starts with the first child
84 * @param structureName structure name to look for
85 * @return an iterator that skips all structures that do not match the parameter
86 */
87 public static Iterator<Structure> createPopulatedStructureIterator(Group theRoot, String structureName) {
88 return createPopulatedStructureIterator(theRoot, new StructureNamePredicate(structureName));
89 }
90
91 /**
92 * @param theRoot root of depth first iteration, which starts with the first child
93 * @param structureFilter filter class
94 * @return iterator that skips all structures that the filter does not accept
95 */
96 public static Iterator<Structure> createPopulatedStructureIterator(Group theRoot, FilterIterator.Predicate<Structure> structureFilter) {
97 Iterator<Structure> allIterator = new ReadOnlyMessageIterator(theRoot);
98 Iterator<Structure> structureIterator = new FilterIterator<>(allIterator, structureFilter);
99
100 FilterIterator.Predicate<Structure> populatedOnly = obj -> {
101 try {
102 return !obj.isEmpty();
103 } catch (HL7Exception e) {
104 return false; // no exception expected
105 }
106 };
107 return new FilterIterator<>(structureIterator, populatedOnly);
108 }
109
110 private void addChildren(Group theParent) {
111 String[] names = theParent.getNames();
112 for (int i = names.length - 1; i >= 0; i--) {
113 try {
114 Structure[] reps = theParent.getAll(names[i]);
115 for (int j = reps.length - 1; j >= 0; j--) {
116 myRemaining.add(reps[j]);
117 }
118 } catch (HL7Exception e) {
119 throw new Error("Internal error: an invalid child name was obtained from its parent.");
120 }
121 }
122 }
123
124 /**
125 * @see java.util.Iterator#hasNext()
126 */
127 public boolean hasNext() {
128 return !myRemaining.isEmpty();
129 }
130
131 /**
132 * @see java.util.Iterator#next()
133 */
134 public Structure next() {
135 if (!hasNext()) {
136 throw new NoSuchElementException("No more nodes in message");
137 }
138
139 Structure next = myRemaining.remove(myRemaining.size() - 1);
140
141 if (next instanceof Group) {
142 addChildren((Group) next);
143 }
144
145 return next;
146 }
147
148 /**
149 * Not supported.
150 */
151 public void remove() {
152 throw new UnsupportedOperationException("Can't remove a node from a message");
153 }
154
155 }