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 "ReadOnlyMessageIterator.java". Description:
010 * "Iterator though existing Stuctures in a message. "
011 *
012 * The Initial Developer of the Original Code is University Health Network. Copyright (C)
013 * 2005. 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 package ca.uhn.hl7v2.util;
028
029 import java.util.ArrayList;
030 import java.util.Iterator;
031 import java.util.List;
032 import java.util.NoSuchElementException;
033
034 import ca.uhn.hl7v2.HL7Exception;
035 import ca.uhn.hl7v2.model.Group;
036 import ca.uhn.hl7v2.model.Segment;
037 import ca.uhn.hl7v2.model.Structure;
038 import ca.uhn.hl7v2.parser.EncodingCharacters;
039 import ca.uhn.hl7v2.parser.PipeParser;
040
041 /**
042 * Iterator though existing Stuctures in a message. No new repetitions or optional
043 * structures are created during iteration (in contrast to MessageIterator).
044 *
045 * Note that some structures are created during parsing, so the iteration may include
046 * structures which were not present in the original encoded message. If these are
047 * not desired they can be skipped using a FilterIterator. In fact to obtain an
048 * iterator only over populated segments (not groups or empty segments) use the factory
049 * method in this class.
050 *
051 * @author <a href="mailto:bryan.tripp@uhn.on.ca">Bryan Tripp</a>
052 * @version $Revision: 1.1 $ updated on $Date: 2007-02-19 02:24:27 $ by $Author: jamesagnew $
053 */
054 public class ReadOnlyMessageIterator implements Iterator<Structure> {
055
056 private List<Structure> myRemaining; //remaining nodes in reverse order (i.e. last is next)
057
058 /**
059 * @param theRoot root of depth first iteration, which starts with the first child
060 */
061 public ReadOnlyMessageIterator(Group theRoot) {
062 myRemaining = new ArrayList<Structure>(40);
063 addChildren(theRoot);
064 }
065
066 /**
067 * @param theRoot root of depth first iteration, which starts with the first child
068 * @return an iterator that skips groups and empty segments, returning only populated
069 * segments
070 */
071 public static Iterator<Structure> createPopulatedSegmentIterator(Group theRoot) {
072 Iterator<Structure> allIterator = new ReadOnlyMessageIterator(theRoot);
073
074 FilterIterator.Predicate<Structure> segmentsOnly = new FilterIterator.Predicate<Structure>() {
075 public boolean evaluate(Structure obj) {
076 if (Segment.class.isAssignableFrom(obj.getClass())) {
077 return true;
078 } else {
079 return false;
080 }
081 }
082 };
083 FilterIterator<Structure> segmentIterator = new FilterIterator<Structure>(allIterator, segmentsOnly);
084
085 final EncodingCharacters ec = new EncodingCharacters('|', "^~\\&");
086 FilterIterator.Predicate<Structure> populatedOnly = new FilterIterator.Predicate<Structure>() {
087 public boolean evaluate(Structure obj) {
088 String encoded = PipeParser.encode((Segment) obj, ec);
089 if (encoded.length() > 3) {
090 return true;
091 } else {
092 return false;
093 }
094 }
095 };
096 return new FilterIterator<Structure>(segmentIterator, populatedOnly);
097 }
098
099 private void addChildren(Group theParent) {
100 String[] names = theParent.getNames();
101 for (int i = names.length - 1; i >= 0; i--) {
102 try {
103 Structure[] reps = theParent.getAll(names[i]);
104 for (int j = reps.length - 1; j >= 0; j--) {
105 myRemaining.add(reps[j]);
106 }
107 } catch (HL7Exception e) {
108 throw new Error("Internal error: an invalid child name was obtained from its parent.");
109 }
110 }
111 }
112
113 /**
114 * @see java.util.Iterator#hasNext()
115 */
116 public boolean hasNext() {
117 return !myRemaining.isEmpty();
118 }
119
120 /**
121 * @see java.util.Iterator#next()
122 */
123 public Structure next() {
124 if (!hasNext()) {
125 throw new NoSuchElementException("No more nodes in message");
126 }
127
128 Structure next = myRemaining.remove(myRemaining.size() - 1);
129
130 if (next instanceof Group) {
131 addChildren((Group) next);
132 }
133
134 return next;
135 }
136
137 /**
138 * Not supported.
139 */
140 public void remove() {
141 throw new UnsupportedOperationException("Can't remove a node from a message");
142 }
143
144 }