package mil.nga.giat.geowave.core.store.util; import java.util.Iterator; import java.util.LinkedList; /** * This class is used internally within the ingest process of GeoWave to convert * each entry into a set of mutations and iterate through them (maintaining a * queue of mutations internally in the case where a single entry converts to * multiple mutations). It is generalized to wrap any iterator with a converter * to a list of a different type. * * @param <InputType> * The type of the input iterator * @param <ConvertedType> * The type of the new converted iterator */ public class IteratorWrapper<InputType, ConvertedType> implements Iterator<ConvertedType> { public static interface Converter<InputType, ConvertedType> { public Iterator<ConvertedType> convert( InputType entry ); } public static interface Callback<InputType, ConvertedType> { public void notifyIterationComplete( InputType entry ); } final private Iterator<InputType> inputIterator; final private Converter<InputType, ConvertedType> converter; private Iterator<ConvertedType> conversionQueue = new LinkedList<ConvertedType>().iterator(); private final Callback<InputType, ConvertedType> conversionCallback; private InputType lastInput; public IteratorWrapper( final Iterator<InputType> inputIterator, final Converter<InputType, ConvertedType> converter ) { this( inputIterator, converter, null); } public IteratorWrapper( final Iterator<InputType> inputIterator, final Converter<InputType, ConvertedType> converter, final Callback<InputType, ConvertedType> conversionCallback ) { this.inputIterator = inputIterator; this.converter = converter; this.conversionCallback = conversionCallback; } @Override public synchronized boolean hasNext() { if (conversionQueue.hasNext()) { return true; } return inputIterator.hasNext(); } @Override public synchronized ConvertedType next() { while (!conversionQueue.hasNext() && inputIterator.hasNext()) { // fill conversion queue with converted objects from the next input final InputType input = inputIterator.next(); final Iterator<ConvertedType> conversions = converter.convert(input); lastInput = input; conversionQueue = conversions; } final ConvertedType retVal = conversionQueue.next(); if (!conversionQueue.hasNext() && (conversionCallback != null)) { // if the queue is empty, then notify that the last input had been // converted and iterated on notifyIterationComplete(); } return retVal; } private synchronized void notifyIterationComplete() { if (lastInput != null) { if (conversionCallback != null) { conversionCallback.notifyIterationComplete(lastInput); } lastInput = null; } } @Override public synchronized void remove() { conversionQueue.remove(); inputIterator.remove(); } }