001/*
002 * #%L
003 * Netarchivesuite - common
004 * %%
005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library,
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023
024package dk.netarkivet.common.utils;
025
026import java.util.Iterator;
027import java.util.NoSuchElementException;
028
029/**
030 * An iterator that filters out and converts items from another iterator. Java 1.5 type: FilterIterator<T>,<S>> <S>
031 * filter(<T> o);
032 *
033 * @param <T> Type of Iterator
034 * @param <S> Type of objects returned by the iterator.
035 */
036public abstract class FilterIterator<T, S> implements Iterator<S> {
037
038    private S objectcache;
039
040    private final Iterator<T> iter;
041
042    /**
043     * Create a new iterator based on an old one. The old one must not contain any null entries.
044     *
045     * @param i An iterator
046     */
047    public FilterIterator(Iterator<T> i) {
048        iter = i;
049    }
050
051    /**
052     * Returns the object corresponding to the given object, or null if that object is to be skipped.
053     *
054     * @param o An object in the source iterator domain
055     * @return An object in this iterators domain, or null
056     */
057    protected abstract S filter(T o);
058
059    /**
060     * Returns <tt>true</tt> if the iteration has more elements. (In other words, returns <tt>true</tt> if <tt>next</tt>
061     * would return an element rather than throwing an exception.)
062     *
063     * @return <tt>true</tt> if the iterator has more elements.
064     */
065    public boolean hasNext() {
066        while (iter.hasNext() && objectcache == null) {
067            objectcache = filter(iter.next());
068        }
069        return objectcache != null;
070    }
071
072    /**
073     * Returns the next element in the iteration. Calling this method repeatedly until the {@link #hasNext()} method
074     * returns false will return each element in the underlying collection exactly once.
075     *
076     * @return the next element in the iteration.
077     * @throws NoSuchElementException iteration has no more elements.
078     */
079    public S next() {
080        if (hasNext()) {
081            S o = objectcache;
082            objectcache = null;
083            return o;
084        }
085
086        throw new NoSuchElementException("No more accepted elements");
087    }
088
089    /**
090     * Removes from the underlying collection the last element returned by the iterator (optional operation). This
091     * method can be called only once per call to <tt>next</tt>. The behavior of an iterator is unspecified if the
092     * underlying collection is modified while the iteration is in progress in any way other than by calling this
093     * method.
094     *
095     * @throws UnsupportedOperationException if the <tt>remove</tt> operation is not supported by this Iterator.
096     * @throws IllegalStateException if the <tt>next</tt> method has not yet been called, or the <tt>remove</tt> method
097     * has already been called after the last call to the <tt>next</tt> method.
098     */
099    public void remove() {
100        throw new UnsupportedOperationException("Cannot remove from this iterator");
101    }
102
103}