Merge branch 'TINKERPOP-2412' into 3.4-dev
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 2f5b903..a1d822d 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -30,6 +30,7 @@
 * Improved initialization time of Java Driver if the default serializer is replaced.
 * Deprecated `withGraph()` in favor of `withEmbedded()` on `AnonymousTraversalSource`.
 * Fixed bug in Javascript `Translator` that wasn't handling child traversals well.
+* Implemented `AutoCloseable` on `MultiIterator`.
 * Fixed an iterator leak in `HasContainer`.
 * Avoid creating unnecessary detached objects in JVM
 * Added `Traversal.getTraverserSetSupplier()` to allow providers to supply their own `TraverserSet` instances.
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/iterator/MultiIterator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/iterator/MultiIterator.java
index 20c0946..1f1d4e9 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/iterator/MultiIterator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/iterator/MultiIterator.java
@@ -19,6 +19,7 @@
 package org.apache.tinkerpop.gremlin.util.iterator;
 
 import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
+import org.apache.tinkerpop.gremlin.structure.util.CloseableIterator;
 
 import java.io.Serializable;
 import java.util.ArrayList;
@@ -28,7 +29,7 @@
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class MultiIterator<T> implements Iterator<T>, Serializable {
+public final class MultiIterator<T> implements Iterator<T>, Serializable, AutoCloseable {
 
     private final List<Iterator<T>> iterators = new ArrayList<>();
     private int current = 0;
@@ -85,4 +86,14 @@
         this.current = 0;
     }
 
+    /**
+     * Close the underlying iterators if auto-closeable. Note that when Exception is thrown from any iterator
+     * in the for loop on closing, remaining iterators possibly left unclosed.
+     */
+    @Override
+    public void close() {
+        for (Iterator<T> iterator : this.iterators) {
+            CloseableIterator.closeIterator(iterator);
+        }
+    }
 }
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/iterator/MultiIteratorTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/iterator/MultiIteratorTest.java
index a52d124..4b97299 100644
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/iterator/MultiIteratorTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/iterator/MultiIteratorTest.java
@@ -20,7 +20,6 @@
 
 import org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException;
 import org.junit.Test;
-
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -29,6 +28,7 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
@@ -112,4 +112,47 @@
 
         assertFalse(itty.hasNext());
     }
+
+    @Test
+    public void shouldCloseIterators() {
+
+        final MultiIterator<String> itty = new MultiIterator<>();
+        final DummyAutoCloseableIterator<String> inner1 = new DummyAutoCloseableIterator<>();
+        final DummyAutoCloseableIterator<String> inner2 = new DummyAutoCloseableIterator<>();
+        itty.addIterator(inner1);
+        itty.addIterator(inner2);
+
+        itty.close();
+
+        assertTrue(inner1.isClosed());
+        assertTrue(inner2.isClosed());
+    }
+
+    // Dummy iterator to verify that its close method is called in the test.
+    private static class DummyAutoCloseableIterator<T> implements Iterator<T>, AutoCloseable {
+        private boolean closed;
+
+        public DummyAutoCloseableIterator() {
+            closed = false;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return false;
+        }
+
+        @Override
+        public T next() {
+            return null;
+        }
+
+        @Override
+        public void close() throws Exception {
+            closed = true;
+        }
+
+        public boolean isClosed() {
+            return closed;
+        }
+    }
 }