/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.catalog.util;
import java.io.Closeable;
import java.io.IOException;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geotools.util.logging.Logging;
import org.opengis.filter.Filter;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterators;
import com.google.common.collect.UnmodifiableIterator;
import com.google.common.io.Closeables;
public class CloseableIteratorAdapter<T> implements CloseableIterator<T> {
private static final Logger LOGGER = Logging.getLogger(CloseableIteratorAdapter.class);
protected final Iterator<T> wrapped;
protected Closeable whatToClose;
public CloseableIteratorAdapter(Iterator<T> wrapped) {
this.wrapped = wrapped;
if (wrapped instanceof Closeable) {
this.whatToClose = (Closeable) wrapped;
} else {
this.whatToClose = null;
}
}
public CloseableIteratorAdapter(Iterator<T> filteredNotCloseable, Closeable closeMe) {
this.wrapped = filteredNotCloseable;
this.whatToClose = closeMe;
}
@Override
public boolean hasNext() {
boolean hasNext = wrapped.hasNext();
if (!hasNext) {
// auto close
close();
}
return hasNext;
}
@Override
public T next() {
return wrapped.next();
}
@Override
public void remove() {
wrapped.remove();
}
/**
* Closes the wrapped iterator if its an instance of {@code CloseableIterator}, does nothing
* otherwise; override if needed.
*
* @see java.io.Closeable#close()
*/
@Override
public void close() {
try {
Closeables.close(whatToClose, false);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
whatToClose = null;
}
}
@Override
protected void finalize() {
if (whatToClose != null) {
try {
close();
} finally {
LOGGER.warning("There is code not closing CloseableIterator!!! Auto closing at finalize().");
}
}
}
public static <T> CloseableIterator<T> filter(final Iterator<T> iterator, final Filter filter) {
Predicate<T> predicate = filterAdapter(filter);
return filter(iterator, predicate);
}
public static <T> CloseableIterator<T> filter(final Iterator<T> iterator, final Predicate<T> predicate) {
UnmodifiableIterator<T> filteredNotCloseable = Iterators.filter(iterator, predicate);
Closeable closeable = iterator instanceof Closeable ? (Closeable) iterator : null;
return new CloseableIteratorAdapter<T>(filteredNotCloseable, closeable);
}
public static <F, T> CloseableIterator<T> transform(Iterator<F> iterator,
Function<? super F, ? extends T> function) {
Iterator<T> transformedNotCloseable = Iterators.transform(iterator, function);
Closeable closeable = (Closeable) (iterator instanceof CloseableIterator ? iterator : null);
return new CloseableIteratorAdapter<T>(transformedNotCloseable, closeable);
}
public static <T> CloseableIterator<T> limit(final Iterator<T> iterator, int maxElements) {
Iterator<T> limitedNotCloseable = Iterators.limit(iterator, maxElements);
Closeable closeable = iterator instanceof Closeable ? (Closeable) iterator : null;
return new CloseableIteratorAdapter<T>(limitedNotCloseable, closeable);
}
public static void close(Iterator<?> iterator) {
if (iterator instanceof Closeable) {
try {
Closeables.close((Closeable) iterator, false);
} catch (IOException e) {
LOGGER.log(Level.FINE, "Ignoring exception on CloseableIteratorAdapter.close()", e);
}
}
}
public static <T> CloseableIterator<T> empty() {
Iterator<T> empty = Iterators.emptyIterator();
return new CloseableIteratorAdapter<T>(empty);
}
private static <T> com.google.common.base.Predicate<T> filterAdapter(
final Filter catalogPredicate) {
return new com.google.common.base.Predicate<T>() {
@Override
public boolean apply(T input) {
return catalogPredicate.evaluate(input);
}
};
}
}