package io.ifar.goodies;

import java.util.Iterator;

/**
 * Wraps Iterators, providing AutoCloseable and Iterable interfaces.
 *
 * Particularly intended for use with JDBI's ResultIterator; failing to exhaust
 * such an iterator will leak a database connection.
 */
public class AutoCloseableIterator<T> implements IterableIterator<T>, AutoCloseable {
    private final Iterator<T> wrapped;
    private final AutoCloseable closeHook;

    /**
     * Wraps a standard Iterator with no-op close behavior.
     */
    public AutoCloseableIterator(final Iterator<T> wrapped) {
        this(wrapped,null);
    }

    /**
     * Wraps Iterator and invokes provided closeHook when closed. Typical usage:
     *
     * <pre>
     * new AutoClosableIterator(myIterator, new AutoCloseable() {
     *     &#64;Override
     *     public void close() throws Exception {
     *         myIterator.close();
     *     }
     * });
     * </pre>
     *
     *
     * @param wrapped
     * @param closeHook
     */
    public AutoCloseableIterator(final Iterator<T> wrapped, AutoCloseable closeHook) {
        this.wrapped = wrapped;
        this.closeHook = closeHook;
    }

    @Override
    public void close() throws Exception {
        if (closeHook != null) {
            closeHook.close();
        }
    }

    @Override
    public boolean hasNext() {
        return wrapped.hasNext();
    }

    @Override
    public T next() {
        return wrapped.next();
    }

    @Override
    public void remove() {
        wrapped.remove();
    }

    @Override
    public Iterator<T> iterator() {
        return wrapped;
    }
}

@@ -19,16 +19,94 @@
 odies;%0A%0A
+import com.google.common.collect.ImmutableList;%0A%0Aimport java.util.Collection;%0A
 import j
@@ -507,16 +507,1984 @@
 eHook;%0A%0A
+    /**%0A     * Returns an AutoCloseableIterator that iterates over all the provided input iterators.%0A     *%0A     * If an Exception is thrown while closing an iterator, the other iterators are closed and the first Exception (only)%0A     * is rethrown.%0A     *%0A     * @see com.google.common.collect.Iterators#concat(java.util.Iterator%5B%5D)%0A     * @param inputs%0A     * @param %3CT%3E%0A     * @return%0A     */%0A    public static %3CT%3E AutoCloseableIterator%3CT%3E concat(final AutoCloseableIterator%3CT%3E... inputs) %7B%0A        return concat(ImmutableList.copyOf(inputs));%0A    %7D%0A%0A    /**%0A     * Returns an AutoCloseableIterator that iterates over all the provided input iterators.%0A     *%0A     * If an Exception is thrown while closing an iterator, the other iterators are closed and the first Exception (only)%0A     * is rethrown.%0A     *%0A     * @see com.google.common.collect.Iterators#concat(java.util.Iterator%5B%5D)%0A     * @param inputs%0A     * @param %3CT%3E%0A     * @return%0A     */%0A    public static %3CT%3E AutoCloseableIterator%3CT%3E concat(final Collection%3CAutoCloseableIterator%3CT%3E%3E inputs) %7B%0A        return new AutoCloseableIterator%3CT%3E(%0A                com.google.common.collect.Iterators.concat(inputs.iterator()),%0A                new AutoCloseable() %7B%0A                    @Override%0A                    public void close() throws Exception %7B%0A                        Exception firstException = null;%0A                        for (AutoCloseableIterator%3C? extends T%3E i : inputs) %7B%0A                            try %7B%0A                                i.close();%0A                            %7D catch (Exception e) %7B%0A                                if (firstException == null) %7B%0A                                    firstException = e;%0A                                %7D%0A                            %7D%0A                        %7D%0A                        if (firstException != null) %7B%0A                            throw firstException;%0A                        %7D%0A                    %7D%0A                %7D%0A        );%0A    %7D%0A%0A
     /**%0A

Add concat support to AutoCloseableIterator