package de.invesdwin.util.collections.iterable; import java.util.NoSuchElementException; import javax.annotation.concurrent.NotThreadSafe; import de.invesdwin.util.error.FastNoSuchElementException; import de.invesdwin.util.error.Throwables; @NotThreadSafe public abstract class ACloseableIterator<E> implements ICloseableIterator<E> { private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(ACloseableIterator.class); private boolean closed; private Exception initStackTrace; private Exception nextStackTrace; public ACloseableIterator() { createInitStackTrace(); } protected void createInitStackTrace() { if (Throwables.isDebugStackTraceEnabled()) { initStackTrace = new Exception(); initStackTrace.fillInStackTrace(); } } protected void createNextStackTrace() { if (Throwables.isDebugStackTraceEnabled() && nextStackTrace == null) { initStackTrace = null; nextStackTrace = new Exception(); nextStackTrace.fillInStackTrace(); } } protected void createUnclosedFinalizeMessageLog() { String warning = "Finalizing unclosed iterator [" + getClass().getName() + "]"; if (Throwables.isDebugStackTraceEnabled()) { final Exception stackTrace; if (initStackTrace != null) { warning += " which was initialized but never used"; stackTrace = initStackTrace; } else { stackTrace = nextStackTrace; } if (stackTrace != null) { warning += " from stacktrace:\n" + Throwables.getFullStackTrace(stackTrace); } } LOGGER.warn(warning); } /** * http://www.informit.com/articles/article.aspx?p=1216151&seqNum=7 */ @Override protected void finalize() throws Throwable { if (!isClosed()) { createUnclosedFinalizeMessageLog(); close(); } super.finalize(); } @Override public final boolean hasNext() { if (isClosed()) { return false; } final boolean hasNext = innerHasNext(); if (!hasNext) { close(); } return hasNext; } protected abstract boolean innerHasNext(); @Override public final E next() { if (isClosed()) { throw new FastNoSuchElementException("ACloseableIterator: next blocked because already closed"); } createNextStackTrace(); final E next; try { next = innerNext(); } catch (final NoSuchElementException e) { close(); throw FastNoSuchElementException.maybeReplace(e, "ACloseableIterator: innerNext threw"); } if (next == null) { close(); throw new FastNoSuchElementException("ACloseableIterator: next is null"); } return next; } protected abstract E innerNext(); @Override public final void remove() { if (isClosed()) { throw new FastNoSuchElementException("ACloseableIterator: remove blocked because already closed"); } innerRemove(); } protected void innerRemove() { throw new UnsupportedOperationException(); } @Override public final void close() { if (!isClosed()) { closed = true; initStackTrace = null; nextStackTrace = null; innerClose(); } } public boolean isClosed() { return closed; } protected abstract void innerClose(); }