001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.commons.collections;
018    
019    import java.lang.reflect.Array;
020    import java.lang.reflect.Method;
021    import java.util.ArrayList;
022    import java.util.Collection;
023    import java.util.Comparator;
024    import java.util.Dictionary;
025    import java.util.Enumeration;
026    import java.util.Iterator;
027    import java.util.List;
028    import java.util.ListIterator;
029    import java.util.Map;
030    
031    import org.apache.commons.collections.iterators.ArrayIterator;
032    import org.apache.commons.collections.iterators.ArrayListIterator;
033    import org.apache.commons.collections.iterators.CollatingIterator;
034    import org.apache.commons.collections.iterators.EmptyIterator;
035    import org.apache.commons.collections.iterators.EmptyListIterator;
036    import org.apache.commons.collections.iterators.EmptyMapIterator;
037    import org.apache.commons.collections.iterators.EmptyOrderedIterator;
038    import org.apache.commons.collections.iterators.EmptyOrderedMapIterator;
039    import org.apache.commons.collections.iterators.EnumerationIterator;
040    import org.apache.commons.collections.iterators.FilterIterator;
041    import org.apache.commons.collections.iterators.FilterListIterator;
042    import org.apache.commons.collections.iterators.IteratorChain;
043    import org.apache.commons.collections.iterators.IteratorEnumeration;
044    import org.apache.commons.collections.iterators.ListIteratorWrapper;
045    import org.apache.commons.collections.iterators.LoopingIterator;
046    import org.apache.commons.collections.iterators.LoopingListIterator;
047    import org.apache.commons.collections.iterators.ObjectArrayIterator;
048    import org.apache.commons.collections.iterators.ObjectArrayListIterator;
049    import org.apache.commons.collections.iterators.ObjectGraphIterator;
050    import org.apache.commons.collections.iterators.SingletonIterator;
051    import org.apache.commons.collections.iterators.SingletonListIterator;
052    import org.apache.commons.collections.iterators.TransformIterator;
053    import org.apache.commons.collections.iterators.UnmodifiableIterator;
054    import org.apache.commons.collections.iterators.UnmodifiableListIterator;
055    import org.apache.commons.collections.iterators.UnmodifiableMapIterator;
056    
057    /**
058     * Provides static utility methods and decorators for {@link Iterator} 
059     * instances. The implementations are provided in the iterators subpackage.
060     * <p>
061     * WARNING: Due to human error certain binary incompatabilities were introduced
062     * between Commons Collections 2.1 and 3.0. The class remained source and test
063     * compatible, so if you can recompile all your classes and dependencies
064     * everything is OK. Those methods which are binary incompatible are marked as
065     * such, together with alternate solutions that are binary compatible
066     * against versions 2.1.1 and 3.1.
067     *
068     * @since Commons Collections 2.1
069     * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
070     * 
071     * @author Stephen Colebourne
072     * @author Phil Steitz
073     */
074    public class IteratorUtils {
075        // validation is done in this class in certain cases because the
076        // public classes allow invalid states
077    
078        /**
079         * An iterator over no elements.
080         * <p>
081         * WARNING: This constant is binary incompatible with Commons Collections 2.1 and 2.1.1.
082         * Use <code>EmptyIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
083         */
084        public static final ResettableIterator EMPTY_ITERATOR = EmptyIterator.RESETTABLE_INSTANCE;
085        /**
086         * A list iterator over no elements.
087         * <p>
088         * WARNING: This constant is binary incompatible with Commons Collections 2.1 and 2.1.1.
089         * Use <code>EmptyListIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
090         */
091        public static final ResettableListIterator EMPTY_LIST_ITERATOR = EmptyListIterator.RESETTABLE_INSTANCE;
092        /**
093         * An ordered iterator over no elements.
094         */    
095        public static final OrderedIterator EMPTY_ORDERED_ITERATOR = EmptyOrderedIterator.INSTANCE;
096        /**
097         * A map iterator over no elements.
098         */    
099        public static final MapIterator EMPTY_MAP_ITERATOR = EmptyMapIterator.INSTANCE;
100        /**
101         * An ordered map iterator over no elements.
102         */    
103        public static final OrderedMapIterator EMPTY_ORDERED_MAP_ITERATOR = EmptyOrderedMapIterator.INSTANCE;
104    
105        /**
106         * IteratorUtils is not normally instantiated.
107         */
108        public IteratorUtils() {
109        }
110    
111        // Empty
112        //-----------------------------------------------------------------------
113        /**
114         * Gets an empty iterator.
115         * <p>
116         * This iterator is a valid iterator object that will iterate over
117         * nothing.
118         * <p>
119         * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
120         * Use <code>EmptyIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
121         *
122         * @return  an iterator over nothing
123         */
124        public static ResettableIterator emptyIterator() {
125            return EMPTY_ITERATOR;
126        }
127    
128        /**
129         * Gets an empty list iterator.
130         * <p>
131         * This iterator is a valid list iterator object that will iterate 
132         * over nothing.
133         * <p>
134         * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
135         * Use <code>EmptyListIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
136         *
137         * @return  a list iterator over nothing
138         */
139        public static ResettableListIterator emptyListIterator() {
140            return EMPTY_LIST_ITERATOR;
141        }
142    
143        /**
144         * Gets an empty ordered iterator.
145         * <p>
146         * This iterator is a valid iterator object that will iterate 
147         * over nothing.
148         *
149         * @return  an ordered iterator over nothing
150         */
151        public static OrderedIterator emptyOrderedIterator() {
152            return EMPTY_ORDERED_ITERATOR;
153        }
154    
155        /**
156         * Gets an empty map iterator.
157         * <p>
158         * This iterator is a valid map iterator object that will iterate 
159         * over nothing.
160         *
161         * @return  a map iterator over nothing
162         */
163        public static MapIterator emptyMapIterator() {
164            return EMPTY_MAP_ITERATOR;
165        }
166    
167        /**
168         * Gets an empty ordered map iterator.
169         * <p>
170         * This iterator is a valid map iterator object that will iterate 
171         * over nothing.
172         *
173         * @return  a map iterator over nothing
174         */
175        public static OrderedMapIterator emptyOrderedMapIterator() {
176            return EMPTY_ORDERED_MAP_ITERATOR;
177        }
178    
179        // Singleton
180        //-----------------------------------------------------------------------
181        /**
182         * Gets a singleton iterator.
183         * <p>
184         * This iterator is a valid iterator object that will iterate over
185         * the specified object.
186         * <p>
187         * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
188         * Use <code>new SingletonIterator(object)</code> for compatability.
189         *
190         * @param object  the single object over which to iterate
191         * @return  a singleton iterator over the object
192         */
193        public static ResettableIterator singletonIterator(Object object) {
194            return new SingletonIterator(object);
195        }
196    
197        /**
198         * Gets a singleton list iterator.
199         * <p>
200         * This iterator is a valid list iterator object that will iterate over
201         * the specified object.
202         *
203         * @param object  the single object over which to iterate
204         * @return  a singleton list iterator over the object
205         */
206        public static ListIterator singletonListIterator(Object object) {
207            return new SingletonListIterator(object);
208        }
209    
210        // Arrays
211        //-----------------------------------------------------------------------
212        /**
213         * Gets an iterator over an object array.
214         * <p>
215         * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
216         * Use <code>new ArrayIterator(array)</code> for compatability.
217         *
218         * @param array  the array over which to iterate
219         * @return  an iterator over the array
220         * @throws NullPointerException if array is null
221         */
222        public static ResettableIterator arrayIterator(Object[] array) {
223            return new ObjectArrayIterator(array);
224        }
225    
226        /**
227         * Gets an iterator over an object or primitive array.
228         * <p>
229         * This method will handle primitive arrays as well as object arrays.
230         * The primitives will be wrapped in the appropriate wrapper class.
231         *
232         * @param array  the array over which to iterate
233         * @return  an iterator over the array
234         * @throws IllegalArgumentException if the array is not an array
235         * @throws NullPointerException if array is null
236         */
237        public static ResettableIterator arrayIterator(Object array) {
238            return new ArrayIterator(array);
239        }
240    
241        /**
242         * Gets an iterator over the end part of an object array.
243         * <p>
244         * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
245         * Use <code>new ArrayIterator(array,start)</code> for compatability.
246         *
247         * @param array  the array over which to iterate
248         * @param start  the index to start iterating at
249         * @return an iterator over part of the array
250         * @throws IndexOutOfBoundsException if start is less than zero or greater
251         *  than the length of the array
252         * @throws NullPointerException if array is null
253         */
254        public static ResettableIterator arrayIterator(Object[] array, int start) {
255            return new ObjectArrayIterator(array, start);
256        }
257    
258        /**
259         * Gets an iterator over the end part of an object or primitive array.
260         * <p>
261         * This method will handle primitive arrays as well as object arrays.
262         * The primitives will be wrapped in the appropriate wrapper class.
263         *
264         * @param array  the array over which to iterate
265         * @param start  the index to start iterating at
266         * @return an iterator over part of the array
267         * @throws IllegalArgumentException if the array is not an array
268         * @throws IndexOutOfBoundsException if start is less than zero or greater
269         *  than the length of the array
270         * @throws NullPointerException if array is null
271         */
272        public static ResettableIterator arrayIterator(Object array, int start) {
273            return new ArrayIterator(array, start);
274        }
275    
276        /**
277         * Gets an iterator over part of an object array.
278         * <p>
279         * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
280         * Use <code>new ArrayIterator(array,start,end)</code> for compatability.
281         *
282         * @param array  the array over which to iterate
283         * @param start  the index to start iterating at
284         * @param end  the index to finish iterating at
285         * @return an iterator over part of the array
286         * @throws IndexOutOfBoundsException if array bounds are invalid
287         * @throws IllegalArgumentException if end is before start
288         * @throws NullPointerException if array is null
289         */
290        public static ResettableIterator arrayIterator(Object[] array, int start, int end) {
291            return new ObjectArrayIterator(array, start, end);
292        }
293    
294        /**
295         * Gets an iterator over part of an object or primitive array.
296         * <p>
297         * This method will handle primitive arrays as well as object arrays.
298         * The primitives will be wrapped in the appropriate wrapper class.
299         *
300         * @param array  the array over which to iterate
301         * @param start  the index to start iterating at
302         * @param end  the index to finish iterating at
303         * @return an iterator over part of the array
304         * @throws IllegalArgumentException if the array is not an array
305         * @throws IndexOutOfBoundsException if array bounds are invalid
306         * @throws IllegalArgumentException if end is before start
307         * @throws NullPointerException if array is null
308         */
309        public static ResettableIterator arrayIterator(Object array, int start, int end) {
310            return new ArrayIterator(array, start, end);
311        }
312    
313        //-----------------------------------------------------------------------
314        /**
315         * Gets a list iterator over an object array.
316         *
317         * @param array  the array over which to iterate
318         * @return  a list iterator over the array
319         * @throws NullPointerException if array is null
320         */
321        public static ResettableListIterator arrayListIterator(Object[] array) {
322            return new ObjectArrayListIterator(array);
323        }
324    
325        /**
326         * Gets a list iterator over an object or primitive array.
327         * <p>
328         * This method will handle primitive arrays as well as object arrays.
329         * The primitives will be wrapped in the appropriate wrapper class.
330         *
331         * @param array  the array over which to iterate
332         * @return  a list iterator over the array
333         * @throws IllegalArgumentException if the array is not an array
334         * @throws NullPointerException if array is null
335         */
336        public static ResettableListIterator arrayListIterator(Object array) {
337            return new ArrayListIterator(array);
338        }
339    
340        /**
341         * Gets a list iterator over the end part of an object array.
342         *
343         * @param array  the array over which to iterate
344         * @param start  the index to start iterating at
345         * @return a list iterator over part of the array
346         * @throws IndexOutOfBoundsException if start is less than zero
347         * @throws NullPointerException if array is null
348         */
349        public static ResettableListIterator arrayListIterator(Object[] array, int start) {
350            return new ObjectArrayListIterator(array, start);
351        }
352    
353        /**
354         * Gets a list iterator over the end part of an object or primitive array.
355         * <p>
356         * This method will handle primitive arrays as well as object arrays.
357         * The primitives will be wrapped in the appropriate wrapper class.
358         *
359         * @param array  the array over which to iterate
360         * @param start  the index to start iterating at
361         * @return a list iterator over part of the array
362         * @throws IllegalArgumentException if the array is not an array
363         * @throws IndexOutOfBoundsException if start is less than zero
364         * @throws NullPointerException if array is null
365         */
366        public static ResettableListIterator arrayListIterator(Object array, int start) {
367            return new ArrayListIterator(array, start);
368        }
369    
370        /**
371         * Gets a list iterator over part of an object array.
372         *
373         * @param array  the array over which to iterate
374         * @param start  the index to start iterating at
375         * @param end  the index to finish iterating at
376         * @return a list iterator over part of the array
377         * @throws IndexOutOfBoundsException if array bounds are invalid
378         * @throws IllegalArgumentException if end is before start
379         * @throws NullPointerException if array is null
380         */
381        public static ResettableListIterator arrayListIterator(Object[] array, int start, int end) {
382            return new ObjectArrayListIterator(array, start, end);
383        }
384        
385        /**
386         * Gets a list iterator over part of an object or primitive array.
387         * <p>
388         * This method will handle primitive arrays as well as object arrays.
389         * The primitives will be wrapped in the appropriate wrapper class.
390         *
391         * @param array  the array over which to iterate
392         * @param start  the index to start iterating at
393         * @param end  the index to finish iterating at
394         * @return a list iterator over part of the array
395         * @throws IllegalArgumentException if the array is not an array
396         * @throws IndexOutOfBoundsException if array bounds are invalid
397         * @throws IllegalArgumentException if end is before start
398         * @throws NullPointerException if array is null
399         */
400        public static ResettableListIterator arrayListIterator(Object array, int start, int end) {
401            return new ArrayListIterator(array, start, end);
402        }
403        
404        // Unmodifiable
405        //-----------------------------------------------------------------------
406        /**
407         * Gets an immutable version of an {@link Iterator}. The returned object
408         * will always throw an {@link UnsupportedOperationException} for
409         * the {@link Iterator#remove} method.
410         *
411         * @param iterator  the iterator to make immutable
412         * @return an immutable version of the iterator
413         */
414        public static Iterator unmodifiableIterator(Iterator iterator) {
415            return UnmodifiableIterator.decorate(iterator);
416        }
417        
418        /**
419         * Gets an immutable version of a {@link ListIterator}. The returned object
420         * will always throw an {@link UnsupportedOperationException} for
421         * the {@link Iterator#remove}, {@link ListIterator#add} and
422         * {@link ListIterator#set} methods.
423         *
424         * @param listIterator  the iterator to make immutable
425         * @return an immutable version of the iterator
426         */
427        public static ListIterator unmodifiableListIterator(ListIterator listIterator) {
428            return UnmodifiableListIterator.decorate(listIterator);
429        }
430    
431        /**
432         * Gets an immutable version of a {@link MapIterator}. The returned object
433         * will always throw an {@link UnsupportedOperationException} for
434         * the {@link Iterator#remove}, {@link MapIterator#setValue(Object)} methods.
435         *
436         * @param mapIterator  the iterator to make immutable
437         * @return an immutable version of the iterator
438         */
439        public static MapIterator unmodifiableMapIterator(MapIterator mapIterator) {
440            return UnmodifiableMapIterator.decorate(mapIterator);
441        }
442    
443        // Chained
444        //-----------------------------------------------------------------------
445        /**
446         * Gets an iterator that iterates through two {@link Iterator}s 
447         * one after another.
448         *
449         * @param iterator1  the first iterators to use, not null
450         * @param iterator2  the first iterators to use, not null
451         * @return a combination iterator over the iterators
452         * @throws NullPointerException if either iterator is null
453         */
454        public static Iterator chainedIterator(Iterator iterator1, Iterator iterator2) {
455            return new IteratorChain(iterator1, iterator2);
456        }
457    
458        /**
459         * Gets an iterator that iterates through an array of {@link Iterator}s 
460         * one after another.
461         *
462         * @param iterators  the iterators to use, not null or empty or contain nulls
463         * @return a combination iterator over the iterators
464         * @throws NullPointerException if iterators array is null or contains a null
465         */
466        public static Iterator chainedIterator(Iterator[] iterators) {
467            return new IteratorChain(iterators);
468        }
469    
470        /**
471         * Gets an iterator that iterates through a collections of {@link Iterator}s 
472         * one after another.
473         *
474         * @param iterators  the iterators to use, not null or empty or contain nulls
475         * @return a combination iterator over the iterators
476         * @throws NullPointerException if iterators collection is null or contains a null
477         * @throws ClassCastException if the iterators collection contains the wrong object type
478         */
479        public static Iterator chainedIterator(Collection iterators) {
480            return new IteratorChain(iterators);
481        }
482    
483        // Collated
484        //-----------------------------------------------------------------------
485        /**
486         * Gets an iterator that provides an ordered iteration over the elements
487         * contained in a collection of ordered {@link Iterator}s.
488         * <p>
489         * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
490         * the {@link Iterator#next()} method will return the lesser of 
491         * <code>A.next()</code> and <code>B.next()</code>.
492         * <p>
493         * The comparator is optional. If null is specified then natural order is used.
494         *
495         * @param comparator  the comparator to use, may be null for natural order
496         * @param iterator1  the first iterators to use, not null
497         * @param iterator2  the first iterators to use, not null
498         * @return a combination iterator over the iterators
499         * @throws NullPointerException if either iterator is null
500         */
501        public static Iterator collatedIterator(Comparator comparator, Iterator iterator1, Iterator iterator2) {
502            return new CollatingIterator(comparator, iterator1, iterator2);
503        }
504    
505        /**
506         * Gets an iterator that provides an ordered iteration over the elements
507         * contained in an array of {@link Iterator}s.
508         * <p>
509         * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
510         * the {@link Iterator#next()} method will return the lesser of 
511         * <code>A.next()</code> and <code>B.next()</code> and so on.
512         * <p>
513         * The comparator is optional. If null is specified then natural order is used.
514         *
515         * @param comparator  the comparator to use, may be null for natural order
516         * @param iterators  the iterators to use, not null or empty or contain nulls
517         * @return a combination iterator over the iterators
518         * @throws NullPointerException if iterators array is null or contains a null
519         */
520        public static Iterator collatedIterator(Comparator comparator, Iterator[] iterators) {
521            return new CollatingIterator(comparator, iterators);
522        }
523    
524        /**
525         * Gets an iterator that provides an ordered iteration over the elements
526         * contained in a collection of {@link Iterator}s.
527         * <p>
528         * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
529         * the {@link Iterator#next()} method will return the lesser of 
530         * <code>A.next()</code> and <code>B.next()</code> and so on.
531         * <p>
532         * The comparator is optional. If null is specified then natural order is used.
533         *
534         * @param comparator  the comparator to use, may be null for natural order
535         * @param iterators  the iterators to use, not null or empty or contain nulls
536         * @return a combination iterator over the iterators
537         * @throws NullPointerException if iterators collection is null or contains a null
538         * @throws ClassCastException if the iterators collection contains the wrong object type
539         */
540        public static Iterator collatedIterator(Comparator comparator, Collection iterators) {
541            return new CollatingIterator(comparator, iterators);
542        }
543        
544        // Object Graph
545        //-----------------------------------------------------------------------
546        /**
547         * Gets an iterator that operates over an object graph.
548         * <p>
549         * This iterator can extract multiple objects from a complex tree-like object graph.
550         * The iteration starts from a single root object.
551         * It uses a <code>Transformer</code> to extract the iterators and elements.
552         * Its main benefit is that no intermediate <code>List</code> is created.
553         * <p>
554         * For example, consider an object graph:
555         * <pre>
556         *                 |- Branch -- Leaf
557         *                 |         \- Leaf
558         *         |- Tree |         /- Leaf
559         *         |       |- Branch -- Leaf
560         *  Forest |                 \- Leaf
561         *         |       |- Branch -- Leaf
562         *         |       |         \- Leaf
563         *         |- Tree |         /- Leaf
564         *                 |- Branch -- Leaf
565         *                 |- Branch -- Leaf</pre>
566         * The following <code>Transformer</code>, used in this class, will extract all
567         * the Leaf objects without creating a combined intermediate list:
568         * <pre>
569         * public Object transform(Object input) {
570         *   if (input instanceof Forest) {
571         *     return ((Forest) input).treeIterator();
572         *   }
573         *   if (input instanceof Tree) {
574         *     return ((Tree) input).branchIterator();
575         *   }
576         *   if (input instanceof Branch) {
577         *     return ((Branch) input).leafIterator();
578         *   }
579         *   if (input instanceof Leaf) {
580         *     return input;
581         *   }
582         *   throw new ClassCastException();
583         * }</pre>
584         * <p>
585         * Internally, iteration starts from the root object. When next is called,
586         * the transformer is called to examine the object. The transformer will return
587         * either an iterator or an object. If the object is an Iterator, the next element
588         * from that iterator is obtained and the process repeats. If the element is an object
589         * it is returned.
590         * <p>
591         * Under many circumstances, linking Iterators together in this manner is
592         * more efficient (and convenient) than using nested for loops to extract a list.
593         * 
594         * @param root  the root object to start iterating from, null results in an empty iterator
595         * @param transformer  the transformer to use, see above, null uses no effect transformer
596         * @return a new object graph iterator
597         * @since Commons Collections 3.1
598         */
599        public static Iterator objectGraphIterator(Object root, Transformer transformer) {
600            return new ObjectGraphIterator(root, transformer);
601        }
602        
603        // Transformed
604        //-----------------------------------------------------------------------
605        /**
606         * Gets an iterator that transforms the elements of another iterator.
607         * <p>
608         * The transformation occurs during the next() method and the underlying
609         * iterator is unaffected by the transformation.
610         *
611         * @param iterator  the iterator to use, not null
612         * @param transform  the transform to use, not null
613         * @return a new transforming iterator
614         * @throws NullPointerException if either parameter is null
615         */
616        public static Iterator transformedIterator(Iterator iterator, Transformer transform) {
617            if (iterator == null) {
618                throw new NullPointerException("Iterator must not be null");
619            }
620            if (transform == null) {
621                throw new NullPointerException("Transformer must not be null");
622            }
623            return new TransformIterator(iterator, transform);
624        }
625        
626        // Filtered
627        //-----------------------------------------------------------------------
628        /**
629         * Gets an iterator that filters another iterator.
630         * <p>
631         * The returned iterator will only return objects that match the specified
632         * filtering predicate.
633         *
634         * @param iterator  the iterator to use, not null
635         * @param predicate  the predicate to use as a filter, not null
636         * @return a new filtered iterator
637         * @throws NullPointerException if either parameter is null
638         */
639        public static Iterator filteredIterator(Iterator iterator, Predicate predicate) {
640            if (iterator == null) {
641                throw new NullPointerException("Iterator must not be null");
642            }
643            if (predicate == null) {
644                throw new NullPointerException("Predicate must not be null");
645            }
646            return new FilterIterator(iterator, predicate);
647        }
648        
649        /**
650         * Gets a list iterator that filters another list iterator.
651         * <p>
652         * The returned iterator will only return objects that match the specified
653         * filtering predicate.
654         *
655         * @param listIterator  the list iterator to use, not null
656         * @param predicate  the predicate to use as a filter, not null
657         * @return a new filtered iterator
658         * @throws NullPointerException if either parameter is null
659         */
660        public static ListIterator filteredListIterator(ListIterator listIterator, Predicate predicate) {
661            if (listIterator == null) {
662                throw new NullPointerException("ListIterator must not be null");
663            }
664            if (predicate == null) {
665                throw new NullPointerException("Predicate must not be null");
666            }
667            return new FilterListIterator(listIterator, predicate);
668        }
669        
670        // Looping
671        //-----------------------------------------------------------------------
672        /**
673         * Gets an iterator that loops continuously over the supplied collection.
674         * <p>
675         * The iterator will only stop looping if the remove method is called
676         * enough times to empty the collection, or if the collection is empty
677         * to start with.
678         *
679         * @param coll  the collection to iterate over, not null
680         * @return a new looping iterator
681         * @throws NullPointerException if the collection is null
682         */
683        public static ResettableIterator loopingIterator(Collection coll) {
684            if (coll == null) {
685                throw new NullPointerException("Collection must not be null");
686            }
687            return new LoopingIterator(coll);
688        }
689        
690        /**
691         * Gets an iterator that loops continuously over the supplied list.
692         * <p>
693         * The iterator will only stop looping if the remove method is called
694         * enough times to empty the list, or if the list is empty to start with.
695         *
696         * @param list  the list to iterate over, not null
697         * @return a new looping iterator
698         * @throws NullPointerException if the list is null
699         * @since Commons Collections 3.2
700         */
701        public static ResettableListIterator loopingListIterator(List list) {
702            if (list == null) {
703                throw new NullPointerException("List must not be null");
704            }
705            return new LoopingListIterator(list);
706        }
707        
708        // Views
709        //-----------------------------------------------------------------------
710        /**
711         * Gets an iterator that provides an iterator view of the given enumeration.
712         *
713         * @param enumeration  the enumeration to use
714         * @return a new iterator
715         */
716        public static Iterator asIterator(Enumeration enumeration) {
717            if (enumeration == null) {
718                throw new NullPointerException("Enumeration must not be null");
719            }
720            return new EnumerationIterator(enumeration);
721        }
722    
723        /**
724         * Gets an iterator that provides an iterator view of the given enumeration 
725         * that will remove elements from the specified collection.
726         *
727         * @param enumeration  the enumeration to use
728         * @param removeCollection  the collection to remove elements from
729         * @return a new iterator
730         */
731        public static Iterator asIterator(Enumeration enumeration, Collection removeCollection) {
732            if (enumeration == null) {
733                throw new NullPointerException("Enumeration must not be null");
734            }
735            if (removeCollection == null) {
736                throw new NullPointerException("Collection must not be null");
737            }
738            return new EnumerationIterator(enumeration, removeCollection);
739        }
740        
741        /**
742         * Gets an enumeration that wraps an iterator.
743         *
744         * @param iterator  the iterator to use, not null
745         * @return a new enumeration
746         * @throws NullPointerException if iterator is null
747         */
748        public static Enumeration asEnumeration(Iterator iterator) {
749            if (iterator == null) {
750                throw new NullPointerException("Iterator must not be null");
751            }
752            return new IteratorEnumeration(iterator);
753        }
754        
755        /**
756         * Gets a list iterator based on a simple iterator.
757         * <p>
758         * As the wrapped Iterator is traversed, a LinkedList of its values is
759         * cached, permitting all required operations of ListIterator.
760         *
761         * @param iterator  the iterator to use, not null
762         * @return a new iterator
763         * @throws NullPointerException if iterator parameter is null
764         */
765        public static ListIterator toListIterator(Iterator iterator) {
766            if (iterator == null) {
767                throw new NullPointerException("Iterator must not be null");
768            }
769            return new ListIteratorWrapper(iterator);
770        }
771        
772        /**
773         * Gets an array based on an iterator.
774         * <p>
775         * As the wrapped Iterator is traversed, an ArrayList of its values is
776         * created. At the end, this is converted to an array.
777         *
778         * @param iterator  the iterator to use, not null
779         * @return an array of the iterator contents
780         * @throws NullPointerException if iterator parameter is null
781         */
782        public static Object[] toArray(Iterator iterator) {
783            if (iterator == null) {
784                throw new NullPointerException("Iterator must not be null");
785            }
786            List list = toList(iterator, 100);
787            return list.toArray();
788        }
789        
790        /**
791         * Gets an array based on an iterator.
792         * <p>
793         * As the wrapped Iterator is traversed, an ArrayList of its values is
794         * created. At the end, this is converted to an array.
795         *
796         * @param iterator  the iterator to use, not null
797         * @param arrayClass  the class of array to create
798         * @return an array of the iterator contents
799         * @throws NullPointerException if iterator parameter is null
800         * @throws NullPointerException if arrayClass is null
801         * @throws ClassCastException if the arrayClass is invalid
802         */
803        public static Object[] toArray(Iterator iterator, Class arrayClass) {
804            if (iterator == null) {
805                throw new NullPointerException("Iterator must not be null");
806            }
807            if (arrayClass == null) {
808                throw new NullPointerException("Array class must not be null");
809            }
810            List list = toList(iterator, 100);
811            return list.toArray((Object[]) Array.newInstance(arrayClass, list.size()));
812        }
813        
814        /**
815         * Gets a list based on an iterator.
816         * <p>
817         * As the wrapped Iterator is traversed, an ArrayList of its values is
818         * created. At the end, the list is returned.
819         *
820         * @param iterator  the iterator to use, not null
821         * @return a list of the iterator contents
822         * @throws NullPointerException if iterator parameter is null
823         */
824        public static List toList(Iterator iterator) {
825            return toList(iterator, 10);
826        }
827        
828        /**
829         * Gets a list based on an iterator.
830         * <p>
831         * As the wrapped Iterator is traversed, an ArrayList of its values is
832         * created. At the end, the list is returned.
833         *
834         * @param iterator  the iterator to use, not null
835         * @param estimatedSize  the initial size of the ArrayList
836         * @return a list of the iterator contents
837         * @throws NullPointerException if iterator parameter is null
838         * @throws IllegalArgumentException if the size is less than 1
839         */
840        public static List toList(Iterator iterator, int estimatedSize) {
841            if (iterator == null) {
842                throw new NullPointerException("Iterator must not be null");
843            }
844            if (estimatedSize < 1) {
845                throw new IllegalArgumentException("Estimated size must be greater than 0");
846            }
847            List list = new ArrayList(estimatedSize);
848            while (iterator.hasNext()) {
849                list.add(iterator.next());
850            }
851            return list;
852        }
853        
854        /** 
855         * Gets a suitable Iterator for the given object.
856         * <p>
857         * This method can handles objects as follows
858         * <ul>
859         * <li>null - empty iterator
860         * <li>Iterator - returned directly
861         * <li>Enumeration - wrapped
862         * <li>Collection - iterator from collection returned
863         * <li>Map - values iterator returned
864         * <li>Dictionary - values (elements) enumeration returned as iterator
865         * <li>array - iterator over array returned
866         * <li>object with iterator() public method accessed by reflection
867         * <li>object - singleton iterator
868         * </ul>
869         * 
870         * @param obj  the object to convert to an iterator
871         * @return a suitable iterator, never null
872         */
873        public static Iterator getIterator(Object obj) {
874            if (obj == null) {
875                return emptyIterator();
876                
877            } else if (obj instanceof Iterator) {
878                return (Iterator) obj;
879                
880            } else if (obj instanceof Collection) {
881                return ((Collection) obj).iterator();
882                
883            } else if (obj instanceof Object[]) {
884                return new ObjectArrayIterator((Object[]) obj);
885                
886            } else if (obj instanceof Enumeration) {
887                return new EnumerationIterator((Enumeration) obj);
888                
889            } else if (obj instanceof Map) {
890                return ((Map) obj).values().iterator();
891                
892            } else if (obj instanceof Dictionary) {
893                return new EnumerationIterator(((Dictionary) obj).elements());
894                
895            } else if (obj != null && obj.getClass().isArray()) {
896                return new ArrayIterator(obj);
897                
898            } else {
899                try {
900                    Method method = obj.getClass().getMethod("iterator", (Class[]) null);
901                    if (Iterator.class.isAssignableFrom(method.getReturnType())) {
902                        Iterator it = (Iterator) method.invoke(obj, (Object[]) null);
903                        if (it != null) {
904                            return it;
905                        }
906                    }
907                } catch (Exception ex) {
908                    // ignore
909                }
910                return singletonIterator(obj);
911            }
912        }
913    
914    }