|
|||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
IteratorChain.java | 0% | 0% | 0% | 0% |
|
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.drools.util; | |
17 | ||
18 | import java.util.ArrayList; | |
19 | import java.util.Collection; | |
20 | import java.util.Collections; | |
21 | import java.util.Iterator; | |
22 | import java.util.List; | |
23 | ||
24 | /** | |
25 | * An IteratorChain is an Iterator that wraps a number of Iterators. | |
26 | * <p> | |
27 | * This class makes multiple iterators look like one to the caller When any | |
28 | * method from the Iterator interface is called, the IteratorChain will delegate | |
29 | * to a single underlying Iterator. The IteratorChain will invoke the Iterators | |
30 | * in sequence until all Iterators are exhausted. | |
31 | * <p> | |
32 | * Under many circumstances, linking Iterators together in this manner is more | |
33 | * efficient (and convenient) than reading out the contents of each Iterator | |
34 | * into a List and creating a new Iterator. | |
35 | * <p> | |
36 | * Calling a method that adds new Iterator <i>after a method in the Iterator | |
37 | * interface has been called </i> will result in an | |
38 | * UnsupportedOperationException. Subclasses should <i>take care </i> to not | |
39 | * alter the underlying List of Iterators. | |
40 | * <p> | |
41 | * NOTE: As from version 3.0, the IteratorChain may contain no iterators. In | |
42 | * this case the class will function as an empty iterator. | |
43 | * | |
44 | * @since Commons Collections 2.1 | |
45 | * @version $Revision: 1.4 $ $Date: 2004/12/06 01:30:38 $ | |
46 | * | |
47 | * @author Morgan Delagrange | |
48 | * @author Stephen Colebourne | |
49 | */ | |
50 | public class IteratorChain | |
51 | implements | |
52 | Iterator | |
53 | { | |
54 | ||
55 | /** The chain of iterators */ | |
56 | protected final List iteratorChain = new ArrayList( ); | |
57 | /** The index of the current iterator */ | |
58 | protected int currentIteratorIndex = 0; | |
59 | /** The current iterator */ | |
60 | protected Iterator currentIterator = null; | |
61 | /** | |
62 | * The "last used" Iterator is the Iterator upon which next() or hasNext() | |
63 | * was most recently called used for the remove() operation only | |
64 | */ | |
65 | protected Iterator lastUsedIterator = null; | |
66 | /** | |
67 | * ComparatorChain is "locked" after the first time compare(Object,Object) | |
68 | * is called | |
69 | */ | |
70 | protected boolean isLocked = false; | |
71 | ||
72 | // ----------------------------------------------------------------------- | |
73 | /** | |
74 | * Construct an IteratorChain with no Iterators. | |
75 | * <p> | |
76 | * You will normally use {@link #addIterator(Iterator)}to add some | |
77 | * iterators after using this constructor. | |
78 | */ | |
79 | 0 | public IteratorChain() |
80 | { | |
81 | 0 | super( ); |
82 | } | |
83 | ||
84 | /** | |
85 | * Construct an IteratorChain with a single Iterator. | |
86 | * | |
87 | * @param iterator | |
88 | * first Iterator in the IteratorChain | |
89 | * @throws NullPointerException | |
90 | * if the iterator is null | |
91 | */ | |
92 | 0 | public IteratorChain(Iterator iterator) |
93 | { | |
94 | 0 | super( ); |
95 | 0 | addIterator( iterator ); |
96 | } | |
97 | ||
98 | /** | |
99 | * Constructs a new <code>IteratorChain</code> over the two given | |
100 | * iterators. | |
101 | * | |
102 | * @param a | |
103 | * the first child iterator | |
104 | * @param b | |
105 | * the second child iterator | |
106 | * @throws NullPointerException | |
107 | * if either iterator is null | |
108 | */ | |
109 | 0 | public IteratorChain(Iterator a, |
110 | Iterator b) | |
111 | { | |
112 | 0 | super( ); |
113 | 0 | addIterator( a ); |
114 | 0 | addIterator( b ); |
115 | } | |
116 | ||
117 | /** | |
118 | * Constructs a new <code>IteratorChain</code> over the array of | |
119 | * iterators. | |
120 | * | |
121 | * @param iterators | |
122 | * the array of iterators | |
123 | * @throws NullPointerException | |
124 | * if iterators array is or contains null | |
125 | */ | |
126 | 0 | public IteratorChain(Iterator[] iterators) |
127 | { | |
128 | 0 | super( ); |
129 | 0 | for ( int i = 0; i < iterators.length; i++ ) |
130 | { | |
131 | 0 | addIterator( iterators[i] ); |
132 | } | |
133 | } | |
134 | ||
135 | /** | |
136 | * Constructs a new <code>IteratorChain</code> over the collection of | |
137 | * iterators. | |
138 | * | |
139 | * @param iterators | |
140 | * the collection of iterators | |
141 | * @throws NullPointerException | |
142 | * if iterators collection is or contains null | |
143 | * @throws ClassCastException | |
144 | * if iterators collection doesn't contain an iterator | |
145 | */ | |
146 | 0 | public IteratorChain(Collection iterators) |
147 | { | |
148 | 0 | super( ); |
149 | 0 | for ( Iterator it = iterators.iterator( ); it.hasNext( ); ) |
150 | { | |
151 | 0 | Iterator item = (Iterator) it.next( ); |
152 | 0 | addIterator( item ); |
153 | } | |
154 | } | |
155 | ||
156 | // ----------------------------------------------------------------------- | |
157 | /** | |
158 | * Add an Iterator to the end of the chain | |
159 | * | |
160 | * @param iterator | |
161 | * Iterator to add | |
162 | * @throws IllegalStateException | |
163 | * if I've already started iterating | |
164 | * @throws NullPointerException | |
165 | * if the iterator is null | |
166 | */ | |
167 | 0 | public void addIterator(Iterator iterator) |
168 | { | |
169 | 0 | checkLocked( ); |
170 | 0 | if ( iterator == null ) |
171 | { | |
172 | 0 | throw new NullPointerException( "Iterator must not be null" ); |
173 | } | |
174 | 0 | iteratorChain.add( iterator ); |
175 | } | |
176 | ||
177 | /** | |
178 | * Set the Iterator at the given index | |
179 | * | |
180 | * @param index | |
181 | * index of the Iterator to replace | |
182 | * @param iterator | |
183 | * Iterator to place at the given index | |
184 | * @throws IndexOutOfBoundsException | |
185 | * if index < 0 or index > size() | |
186 | * @throws IllegalStateException | |
187 | * if I've already started iterating | |
188 | * @throws NullPointerException | |
189 | * if the iterator is null | |
190 | */ | |
191 | 0 | public void setIterator(int index, |
192 | Iterator iterator) throws IndexOutOfBoundsException | |
193 | { | |
194 | 0 | checkLocked( ); |
195 | 0 | if ( iterator == null ) |
196 | { | |
197 | 0 | throw new NullPointerException( "Iterator must not be null" ); |
198 | } | |
199 | 0 | iteratorChain.set( index, |
200 | iterator ); | |
201 | } | |
202 | ||
203 | /** | |
204 | * Get the list of Iterators (unmodifiable) | |
205 | * | |
206 | * @return the unmodifiable list of iterators added | |
207 | */ | |
208 | 0 | public List getIterators() |
209 | { | |
210 | 0 | return Collections.unmodifiableList( iteratorChain ); |
211 | } | |
212 | ||
213 | /** | |
214 | * Number of Iterators in the current IteratorChain. | |
215 | * | |
216 | * @return Iterator count | |
217 | */ | |
218 | 0 | public int size() |
219 | { | |
220 | 0 | return iteratorChain.size( ); |
221 | } | |
222 | ||
223 | /** | |
224 | * Determine if modifications can still be made to the IteratorChain. | |
225 | * IteratorChains cannot be modified once they have executed a method from | |
226 | * the Iterator interface. | |
227 | * | |
228 | * @return true if IteratorChain cannot be modified, false if it can | |
229 | */ | |
230 | 0 | public boolean isLocked() |
231 | { | |
232 | 0 | return isLocked; |
233 | } | |
234 | ||
235 | /** | |
236 | * Checks whether the iterator chain is now locked and in use. | |
237 | */ | |
238 | 0 | private void checkLocked() |
239 | { | |
240 | 0 | if ( isLocked == true ) |
241 | { | |
242 | 0 | throw new UnsupportedOperationException( "IteratorChain cannot be changed after the first use of a method from the Iterator interface" ); |
243 | } | |
244 | } | |
245 | ||
246 | /** | |
247 | * Lock the chain so no more iterators can be added. This must be called | |
248 | * from all Iterator interface methods. | |
249 | */ | |
250 | 0 | private void lockChain() |
251 | { | |
252 | 0 | if ( isLocked == false ) |
253 | { | |
254 | 0 | isLocked = true; |
255 | } | |
256 | } | |
257 | ||
258 | /** | |
259 | * Updates the current iterator field to ensure that the current Iterator is | |
260 | * not exhausted | |
261 | */ | |
262 | 0 | protected void updateCurrentIterator() |
263 | { | |
264 | 0 | if ( currentIterator == null ) |
265 | { | |
266 | 0 | if ( iteratorChain.isEmpty( ) ) |
267 | { | |
268 | 0 | currentIterator = Collections.EMPTY_LIST.iterator( ); |
269 | } | |
270 | else | |
271 | { | |
272 | 0 | currentIterator = (Iterator) iteratorChain.get( 0 ); |
273 | } | |
274 | // set last used iterator here, in case the user calls remove | |
275 | // before calling hasNext() or next() (although they shouldn't) | |
276 | 0 | lastUsedIterator = currentIterator; |
277 | } | |
278 | ||
279 | 0 | while ( currentIterator.hasNext( ) == false && currentIteratorIndex < iteratorChain.size( ) - 1 ) |
280 | { | |
281 | 0 | currentIteratorIndex++; |
282 | 0 | currentIterator = (Iterator) iteratorChain.get( currentIteratorIndex ); |
283 | } | |
284 | } | |
285 | ||
286 | // ----------------------------------------------------------------------- | |
287 | /** | |
288 | * Return true if any Iterator in the IteratorChain has a remaining element. | |
289 | * | |
290 | * @return true if elements remain | |
291 | */ | |
292 | 0 | public boolean hasNext() |
293 | { | |
294 | 0 | lockChain( ); |
295 | 0 | updateCurrentIterator( ); |
296 | 0 | lastUsedIterator = currentIterator; |
297 | ||
298 | 0 | return currentIterator.hasNext( ); |
299 | } | |
300 | ||
301 | /** | |
302 | * Returns the next Object of the current Iterator | |
303 | * | |
304 | * @return Object from the current Iterator | |
305 | * @throws java.util.NoSuchElementException | |
306 | * if all the Iterators are exhausted | |
307 | */ | |
308 | 0 | public Object next() |
309 | { | |
310 | 0 | lockChain( ); |
311 | 0 | updateCurrentIterator( ); |
312 | 0 | lastUsedIterator = currentIterator; |
313 | ||
314 | 0 | return currentIterator.next( ); |
315 | } | |
316 | ||
317 | /** | |
318 | * Removes from the underlying collection the last element returned by the | |
319 | * Iterator. As with next() and hasNext(), this method calls remove() on the | |
320 | * underlying Iterator. Therefore, this method may throw an | |
321 | * UnsupportedOperationException if the underlying Iterator does not support | |
322 | * this method. | |
323 | * | |
324 | * @throws UnsupportedOperationException | |
325 | * if the remove operator is not supported by the underlying | |
326 | * Iterator | |
327 | * @throws IllegalStateException | |
328 | * if the next method has not yet been called, or the remove | |
329 | * method has already been called after the last call to the | |
330 | * next method. | |
331 | */ | |
332 | 0 | public void remove() |
333 | { | |
334 | 0 | lockChain( ); |
335 | 0 | updateCurrentIterator( ); |
336 | ||
337 | 0 | lastUsedIterator.remove( ); |
338 | } | |
339 | ||
340 | } |
|