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 }