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 {
055    
056        private List 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(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 createPopulatedSegmentIterator(Group theRoot) {
072            Iterator allIterator = new ReadOnlyMessageIterator(theRoot);
073            
074            FilterIterator.Predicate segmentsOnly = new FilterIterator.Predicate() {
075                public boolean evaluate(Object obj) {
076                    if (Segment.class.isAssignableFrom(obj.getClass())) {
077                        return true;
078                    } else {
079                        return false;
080                    }
081                }
082            };
083            FilterIterator segmentIterator = new FilterIterator(allIterator, segmentsOnly);
084            
085            final EncodingCharacters ec = new EncodingCharacters('|', "^~\\&");
086            FilterIterator.Predicate populatedOnly = new FilterIterator.Predicate() {
087                public boolean evaluate(Object 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(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 Object next() {
124            if (!hasNext()) {
125                throw new NoSuchElementException("No more nodes in message");
126            }
127            
128            Structure next = (Structure) 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    }