/** * The contents of this file are subject to the license and copyright * detailed in the LICENSE file at the root of the source * tree and available online at * * https://github.com/keeps/roda */ package org.roda.core.common.iterables; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.function.Function; import org.apache.commons.io.IOUtils; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Iterators; import com.google.common.collect.UnmodifiableIterator; public final class CloseableIterables { private CloseableIterables() { } public static <T> CloseableIterable<T> concat(List<CloseableIterable<T>> list) { checkNotNull(list); return new CloseableIterable<T>() { @Override public void close() throws IOException { closeAll(list); } @Override public Iterator<T> iterator() { return Iterators.concat(iterators(list)); } }; } public static <A, B> CloseableIterable<B> concat(final CloseableIterable<A> list, final Function<A, CloseableIterable<B>> listFunction) { CloseableIterable<CloseableIterable<B>> iterable = new CloseableIterable<CloseableIterable<B>>() { @Override public void close() throws IOException { list.close(); } @Override public Iterator<CloseableIterable<B>> iterator() { final Iterator<A> iterator = list.iterator(); return new Iterator<CloseableIterable<B>>() { @Override public boolean hasNext() { return iterator.hasNext(); } @Override public CloseableIterable<B> next() { A next = iterator.next(); return listFunction.apply(next); } }; } }; return concat(iterable); } public static <T> CloseableIterable<T> concat(CloseableIterable<CloseableIterable<T>> list) { final Iterator<CloseableIterable<T>> main = list.iterator(); return new CloseableIterable<T>() { CloseableIterable<T> current = null; @Override public void close() throws IOException { if (current != null) { current.close(); } list.close(); } @Override public Iterator<T> iterator() { return new Iterator<T>() { Iterator<T> currentIt = null; @Override public boolean hasNext() { boolean hasNext = false; if (current != null) { if (currentIt.hasNext()) { hasNext = true; } else { IOUtils.closeQuietly(current); hasNext = fastForward(); } } else { hasNext = fastForward(); } return hasNext; } private boolean fastForward() { boolean hasNext = false; while (main.hasNext()) { current = main.next(); currentIt = current.iterator(); if (currentIt.hasNext()) { hasNext = true; break; } else { IOUtils.closeQuietly(current); } } return hasNext; } @Override public T next() { return hasNext() ? currentIt.next() : null; } }; } }; } /** * Returns an iterator over the iterators of the given iterables. */ private static <T> UnmodifiableIterator<Iterator<? extends T>> iterators( Iterable<? extends Iterable<? extends T>> iterables) { final Iterator<? extends Iterable<? extends T>> iterableIterator = iterables.iterator(); return new UnmodifiableIterator<Iterator<? extends T>>() { @Override public boolean hasNext() { return iterableIterator.hasNext(); } @Override public Iterator<? extends T> next() { return iterableIterator.next().iterator(); } }; } private static <T> void checkNotNull(List<CloseableIterable<T>> list) { if (list == null) { throw new NullPointerException(); } else { for (CloseableIterable<T> it : list) { if (it == null) { throw new NullPointerException(); } } } } protected static <T> void closeAll(List<CloseableIterable<T>> list) { for (CloseableIterable<T> it : list) { IOUtils.closeQuietly(it); } } @SuppressWarnings("unchecked") public static <T> CloseableIterable<T> concat(CloseableIterable<T>... iterables) { return concat(Arrays.asList(iterables)); } public static <T> int size(CloseableIterable<T> iterable) { int size = Iterables.size(iterable); IOUtils.closeQuietly(iterable); return size; } public static <T> CloseableIterable<T> filter(final CloseableIterable<T> unfiltered, Predicate<? super T> predicate) { return new CloseableIterable<T>() { @Override public void close() throws IOException { unfiltered.close(); } @Override public Iterator<T> iterator() { return Iterators.filter(unfiltered.iterator(), predicate); } }; } public static <T> boolean isEmpty(CloseableIterable<T> it) { boolean empty = Iterables.isEmpty(it); IOUtils.closeQuietly(it); return empty; } public static <T> CloseableIterable<T> fromList(final List<T> list) { return new CloseableIterable<T>() { @Override public void close() throws IOException { // do nothing } @Override public Iterator<T> iterator() { return list.iterator(); } }; } public static <T> CloseableIterable<T> empty() { return new CloseableIterable<T>() { @Override public void close() throws IOException { // nothing to do } @Override public Iterator<T> iterator() { return Collections.emptyIterator(); } }; } }