KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > collections > iterators > IteratorChain


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.commons.collections.iterators;
17
18 import java.util.ArrayList JavaDoc;
19 import java.util.Collection JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.List JavaDoc;
22
23 import org.apache.commons.collections.list.UnmodifiableList;
24
25 /**
26  * An IteratorChain is an Iterator that wraps a number of Iterators.
27  * <p>
28  * This class makes multiple iterators look like one to the caller
29  * When any method from the Iterator interface is called, the IteratorChain
30  * will delegate to a single underlying Iterator. The IteratorChain will
31  * invoke the Iterators in sequence until all Iterators are exhausted.
32  * <p>
33  * Under many circumstances, linking Iterators together in this manner is
34  * more efficient (and convenient) than reading out the contents of each
35  * Iterator into a List and creating a new Iterator.
36  * <p>
37  * Calling a method that adds new Iterator<i>after a method in the Iterator
38  * interface has been called</i> will result in an UnsupportedOperationException.
39  * Subclasses should <i>take care</i> to not alter the underlying List of Iterators.
40  * <p>
41  * NOTE: As from version 3.0, the IteratorChain may contain no
42  * iterators. In this case the class will function as an empty iterator.
43  *
44  * @since Commons Collections 2.1
45  * @version $Revision: 1.13 $ $Date: 2004/05/26 21:58:02 $
46  *
47  * @author Morgan Delagrange
48  * @author Stephen Colebourne
49  */

50 public class IteratorChain implements Iterator JavaDoc {
51
52     /** The chain of iterators */
53     protected final List JavaDoc iteratorChain = new ArrayList JavaDoc();
54     /** The index of the current iterator */
55     protected int currentIteratorIndex = 0;
56     /** The current iterator */
57     protected Iterator JavaDoc currentIterator = null;
58     /**
59      * The "last used" Iterator is the Iterator upon which
60      * next() or hasNext() was most recently called
61      * used for the remove() operation only
62      */

63     protected Iterator JavaDoc lastUsedIterator = null;
64     /**
65      * ComparatorChain is "locked" after the first time
66      * compare(Object,Object) is called
67      */

68     protected boolean isLocked = false;
69
70     //-----------------------------------------------------------------------
71
/**
72      * Construct an IteratorChain with no Iterators.
73      * <p>
74      * You will normally use {@link #addIterator(Iterator)} to add
75      * some iterators after using this constructor.
76      */

77     public IteratorChain() {
78         super();
79     }
80
81     /**
82      * Construct an IteratorChain with a single Iterator.
83      *
84      * @param iterator first Iterator in the IteratorChain
85      * @throws NullPointerException if the iterator is null
86      */

87     public IteratorChain(Iterator JavaDoc iterator) {
88         super();
89         addIterator(iterator);
90     }
91
92     /**
93      * Constructs a new <code>IteratorChain</code> over the two
94      * given iterators.
95      *
96      * @param a the first child iterator
97      * @param b the second child iterator
98      * @throws NullPointerException if either iterator is null
99      */

100     public IteratorChain(Iterator JavaDoc a, Iterator JavaDoc b) {
101         super();
102         addIterator(a);
103         addIterator(b);
104     }
105
106     /**
107      * Constructs a new <code>IteratorChain</code> over the array
108      * of iterators.
109      *
110      * @param iterators the array of iterators
111      * @throws NullPointerException if iterators array is or contains null
112      */

113     public IteratorChain(Iterator JavaDoc[] iterators) {
114         super();
115         for (int i = 0; i < iterators.length; i++) {
116             addIterator(iterators[i]);
117         }
118     }
119
120     /**
121      * Constructs a new <code>IteratorChain</code> over the collection
122      * of iterators.
123      *
124      * @param iterators the collection of iterators
125      * @throws NullPointerException if iterators collection is or contains null
126      * @throws ClassCastException if iterators collection doesn't contain an iterator
127      */

128     public IteratorChain(Collection JavaDoc iterators) {
129         super();
130         for (Iterator JavaDoc it = iterators.iterator(); it.hasNext();) {
131             Iterator JavaDoc item = (Iterator JavaDoc) it.next();
132             addIterator(item);
133         }
134     }
135     
136     //-----------------------------------------------------------------------
137
/**
138      * Add an Iterator to the end of the chain
139      *
140      * @param iterator Iterator to add
141      * @throws IllegalStateException if I've already started iterating
142      * @throws NullPointerException if the iterator is null
143      */

144     public void addIterator(Iterator JavaDoc iterator) {
145         checkLocked();
146         if (iterator == null) {
147             throw new NullPointerException JavaDoc("Iterator must not be null");
148         }
149         iteratorChain.add(iterator);
150     }
151
152     /**
153      * Set the Iterator at the given index
154      *
155      * @param index index of the Iterator to replace
156      * @param iterator Iterator to place at the given index
157      * @throws IndexOutOfBoundsException if index &lt; 0 or index &gt; size()
158      * @throws IllegalStateException if I've already started iterating
159      * @throws NullPointerException if the iterator is null
160      */

161     public void setIterator(int index, Iterator JavaDoc iterator) throws IndexOutOfBoundsException JavaDoc {
162         checkLocked();
163         if (iterator == null) {
164             throw new NullPointerException JavaDoc("Iterator must not be null");
165         }
166         iteratorChain.set(index, iterator);
167     }
168
169     /**
170      * Get the list of Iterators (unmodifiable)
171      *
172      * @return the unmodifiable list of iterators added
173      */

174     public List JavaDoc getIterators() {
175         return UnmodifiableList.decorate(iteratorChain);
176     }
177
178     /**
179      * Number of Iterators in the current IteratorChain.
180      *
181      * @return Iterator count
182      */

183     public int size() {
184         return iteratorChain.size();
185     }
186
187     /**
188      * Determine if modifications can still be made to the IteratorChain.
189      * IteratorChains cannot be modified once they have executed a method
190      * from the Iterator interface.
191      *
192      * @return true if IteratorChain cannot be modified, false if it can
193      */

194     public boolean isLocked() {
195         return isLocked;
196     }
197
198     /**
199      * Checks whether the iterator chain is now locked and in use.
200      */

201     private void checkLocked() {
202         if (isLocked == true) {
203             throw new UnsupportedOperationException JavaDoc("IteratorChain cannot be changed after the first use of a method from the Iterator interface");
204         }
205     }
206
207     /**
208      * Lock the chain so no more iterators can be added.
209      * This must be called from all Iterator interface methods.
210      */

211     private void lockChain() {
212         if (isLocked == false) {
213             isLocked = true;
214         }
215     }
216
217     /**
218      * Updates the current iterator field to ensure that the current Iterator
219      * is not exhausted
220      */

221     protected void updateCurrentIterator() {
222         if (currentIterator == null) {
223             if (iteratorChain.isEmpty()) {
224                 currentIterator = EmptyIterator.INSTANCE;
225             } else {
226                 currentIterator = (Iterator JavaDoc) iteratorChain.get(0);
227             }
228             // set last used iterator here, in case the user calls remove
229
// before calling hasNext() or next() (although they shouldn't)
230
lastUsedIterator = currentIterator;
231         }
232
233         while (currentIterator.hasNext() == false && currentIteratorIndex < iteratorChain.size() - 1) {
234             currentIteratorIndex++;
235             currentIterator = (Iterator JavaDoc) iteratorChain.get(currentIteratorIndex);
236         }
237     }
238
239     //-----------------------------------------------------------------------
240
/**
241      * Return true if any Iterator in the IteratorChain has a remaining element.
242      *
243      * @return true if elements remain
244      */

245     public boolean hasNext() {
246         lockChain();
247         updateCurrentIterator();
248         lastUsedIterator = currentIterator;
249
250         return currentIterator.hasNext();
251     }
252
253     /**
254      * Returns the next Object of the current Iterator
255      *
256      * @return Object from the current Iterator
257      * @throws java.util.NoSuchElementException if all the Iterators are exhausted
258      */

259     public Object JavaDoc next() {
260         lockChain();
261         updateCurrentIterator();
262         lastUsedIterator = currentIterator;
263
264         return currentIterator.next();
265     }
266
267     /**
268      * Removes from the underlying collection the last element
269      * returned by the Iterator. As with next() and hasNext(),
270      * this method calls remove() on the underlying Iterator.
271      * Therefore, this method may throw an
272      * UnsupportedOperationException if the underlying
273      * Iterator does not support this method.
274      *
275      * @throws UnsupportedOperationException
276      * if the remove operator is not supported by the underlying Iterator
277      * @throws IllegalStateException
278      * if the next method has not yet been called, or the remove method has
279      * already been called after the last call to the next method.
280      */

281     public void remove() {
282         lockChain();
283         updateCurrentIterator();
284
285         lastUsedIterator.remove();
286     }
287
288 }
289
Popular Tags