You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commonsrdf.apache.org by st...@apache.org on 2016/10/06 23:46:30 UTC

[1/3] incubator-commonsrdf git commit: test with try-with-resource to close rdf4j connections

Repository: incubator-commonsrdf
Updated Branches:
  refs/heads/rdf4j 95cda336c -> 90e3e5006


test with try-with-resource to close rdf4j connections


Project: http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/commit/365b5f2f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/tree/365b5f2f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/diff/365b5f2f

Branch: refs/heads/rdf4j
Commit: 365b5f2f2319772b6f638f92df81e0358a16c482
Parents: 95cda33
Author: Stian Soiland-Reyes <st...@apache.org>
Authored: Fri Oct 7 00:16:13 2016 +0100
Committer: Stian Soiland-Reyes <st...@apache.org>
Committed: Fri Oct 7 00:16:13 2016 +0100

----------------------------------------------------------------------
 .../commons/rdf/api/AbstractGraphTest.java      | 101 ++++++++++++-------
 1 file changed, 64 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/365b5f2f/api/src/test/java/org/apache/commons/rdf/api/AbstractGraphTest.java
----------------------------------------------------------------------
diff --git a/api/src/test/java/org/apache/commons/rdf/api/AbstractGraphTest.java b/api/src/test/java/org/apache/commons/rdf/api/AbstractGraphTest.java
index cb78c05..d7b3fbc 100644
--- a/api/src/test/java/org/apache/commons/rdf/api/AbstractGraphTest.java
+++ b/api/src/test/java/org/apache/commons/rdf/api/AbstractGraphTest.java
@@ -43,7 +43,10 @@ import org.junit.Test;
  * in <code>Test</code> and provide {@link #createFactory()} which minimally
  * must support {@link RDFTermFactory#createGraph()} and
  * {@link RDFTermFactory#createIRI(String)}, but ideally support all operations.
- *
+ * <p>
+ * This test uses try-with-resources blocks for calls to {@link Graph#stream()}
+ * and {@link Graph#iterate()}.
+ * 
  * @see Graph
  * @see RDFTermFactory
  */
@@ -147,21 +150,33 @@ public abstract class AbstractGraphTest {
         }
 
         // aborted iteration
-        Iterator<Triple> it = graph.iterate().iterator();
-
+        Iterable<Triple> iterate = graph.iterate();
+		Iterator<Triple> it = iterate.iterator();
+        
         assertTrue(it.hasNext());
         it.next();
+        closeIterable(iterate);
+        
 
         // second iteration - should start from fresh and
         // get the same count
         long count = 0;
         Iterable<Triple> iterable = graph.iterate();
-        for (Triple t : iterable) {
+        for (@SuppressWarnings("unused") Triple t : iterable) {
             count++;
         }
         assertEquals(graph.size(), count);
     }
 
+    /**
+     * Special triple closing for RDF4J.
+     */
+	private void closeIterable(Iterable<Triple> iterate) throws Exception {
+        if (iterate instanceof AutoCloseable) {
+        	((AutoCloseable) iterate).close();
+        }
+	}
+
     @Test
     public void iterateFilter() throws Exception {
         List<RDFTerm> friends = new ArrayList<>();
@@ -174,9 +189,11 @@ public abstract class AbstractGraphTest {
         assertEquals(bob, friends.get(0));
 
         // .. can we iterate over zero hits?
-        for (Triple unexpected : graph.iterate(bob, knows, alice)) {
+        Iterable<Triple> iterate = graph.iterate(bob, knows, alice);
+		for (Triple unexpected : iterate) {
         	fail("Unexpected triple " + unexpected);
         }
+        //closeIterable(iterate);
     }
 
     @Test
@@ -277,15 +294,21 @@ public abstract class AbstractGraphTest {
     @Test
     public void getTriplesQuery() throws Exception {
 
-        long aliceCount = graph.stream(alice, null, null).count();
-        assertTrue(aliceCount > 0);
-        Assume.assumeNotNull(aliceName);
-        assertEquals(3, aliceCount);
+        try (Stream<? extends Triple> stream = graph.stream(alice, null, null)) {
+			long aliceCount = stream.count();
+			assertTrue(aliceCount > 0);
+			Assume.assumeNotNull(aliceName);
+			assertEquals(3, aliceCount);
+        }
 
         Assume.assumeNotNull(bnode1, bnode2, bobName, companyName, secretClubName);
-        assertEquals(4, graph.stream(null, name, null).count());
+        try (Stream<? extends Triple> stream = graph.stream(null, name, null)) {
+        	assertEquals(4, stream.count());
+        }
         Assume.assumeNotNull(bnode1);
-        assertEquals(3, graph.stream(null, member, null).count());
+        try (Stream<? extends Triple> stream = graph.stream(null, member, null)) {
+        	assertEquals(3, stream.count());
+        }
     }
 
     @Test
@@ -313,8 +336,10 @@ public abstract class AbstractGraphTest {
             
             // look up BlankNodes by name
             IRI name = factory.createIRI("http://xmlns.com/foaf/0.1/name");
-            g3.stream(null, name, null).parallel().forEach( t ->
-                whoIsWho.put( t.getObject().ntriplesString(), t.getSubject()));
+            try (Stream<? extends Triple> stream = g3.stream(null, name, null)) {
+            	stream.parallel().forEach( t ->
+                	whoIsWho.put( t.getObject().ntriplesString(), t.getSubject()));
+			}
                         
             assertEquals(4, whoIsWho.size());
             // and contains 4 unique values
@@ -477,29 +502,31 @@ public abstract class AbstractGraphTest {
     public void whyJavaStreamsMightNotTakeOverFromSparql() throws Exception {
         Assume.assumeNotNull(bnode1, bnode2, secretClubName);
         // Find a secret organizations
-        assertEquals(
-                "\"The Secret Club\"",
-                graph.stream(null, knows, null)
-                        // Find One-way "knows"
-                        .filter(t -> !graph.contains(
-                                (BlankNodeOrIRI) t.getObject(), knows,
-                                t.getSubject()))
-                        .map(knowsTriple -> graph
-                                // and those they know, what are they member of?
-                                .stream(
-                                        (BlankNodeOrIRI) knowsTriple
-                                                .getObject(), member, null)
-                                        // keep those which first-guy is a member of
-                                .filter(memberTriple -> graph.contains(
-                                        knowsTriple.getSubject(), member,
-                                        // First hit is good enough
-                                        memberTriple.getObject())).findFirst()
-                                .get().getObject())
-                                // then look up the name of that org
-                        .map(org -> graph
-                                .stream((BlankNodeOrIRI) org, name, null)
-                                .findFirst().get().getObject().ntriplesString())
-                        .findFirst().get());
-
+		try (Stream<? extends Triple> stream = graph.stream(null, knows, null)) {
+			assertEquals("\"The Secret Club\"",
+					// Find One-way "knows"
+				stream.filter(t -> !graph.contains((BlankNodeOrIRI) t.getObject(), knows, t.getSubject()))
+					.map(knowsTriple -> {
+						try (Stream<? extends Triple> memberOf = graph
+								// and those they know, what are they
+								// member of?
+								.stream((BlankNodeOrIRI) knowsTriple.getObject(), member, null)) {
+							return memberOf
+									// keep those which first-guy is a
+									// member of
+									.filter(memberTriple -> graph.contains(knowsTriple.getSubject(), member,
+											// First hit is good enough
+											memberTriple.getObject()))
+									.findFirst().get().getObject();
+						}
+					})
+					// then look up the name of that org
+					.map(org -> {
+						try (Stream<? extends Triple> orgName = graph.stream((BlankNodeOrIRI) org, name,
+								null)) {
+							return orgName.findFirst().get().getObject().ntriplesString();
+						}
+					}).findFirst().get());
+		}
     }
 }


[2/3] incubator-commonsrdf git commit: Added ClosableIterable for rdf4j .iterate

Posted by st...@apache.org.
Added ClosableIterable for rdf4j .iterate


Project: http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/commit/a47ad362
Tree: http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/tree/a47ad362
Diff: http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/diff/a47ad362

Branch: refs/heads/rdf4j
Commit: a47ad3623d178ea4957ce95d3b905d0415cd4b16
Parents: 365b5f2
Author: Stian Soiland-Reyes <st...@apache.org>
Authored: Fri Oct 7 00:16:53 2016 +0100
Committer: Stian Soiland-Reyes <st...@apache.org>
Committed: Fri Oct 7 00:16:53 2016 +0100

----------------------------------------------------------------------
 .../commons/rdf/rdf4j/ClosableIterable.java     | 22 +++++++++
 .../apache/commons/rdf/rdf4j/RDF4JGraph.java    | 49 ++++++++++++++++++-
 .../commons/rdf/rdf4j/impl/ModelGraphImpl.java  | 26 ++++++++++
 .../rdf/rdf4j/impl/RepositoryGraphImpl.java     | 51 ++++++++++++++++++++
 .../commons/rdf/rdf4j/NativeStoreGraphTest.java | 10 ++--
 5 files changed, 152 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/a47ad362/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/ClosableIterable.java
----------------------------------------------------------------------
diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/ClosableIterable.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/ClosableIterable.java
new file mode 100644
index 0000000..2cca6c6
--- /dev/null
+++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/ClosableIterable.java
@@ -0,0 +1,22 @@
+package org.apache.commons.rdf.rdf4j;
+
+/**
+ * An {@link Iterable} which should be {@link #close()}d after use.
+ * <p>
+ * A good pattern to use this iterator is with an outer try-with-resources
+ * block: 
+ * <code>
+ * for (ClosableIterable&lt;Triple&gt; triples : graph.iterate()) {
+ *     for (Triple t : triples) {
+ *       return t; // OK to terminate for-loop early
+ *     }
+ * }
+ * </code> 
+ * The above will ensure that underlying resources are closed even if
+ * the iteration does not exhaust all triples.
+ *
+ * @param <T>
+ */
+public interface ClosableIterable<T> extends Iterable<T>, AutoCloseable {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/a47ad362/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java
----------------------------------------------------------------------
diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java
index 93886a4..8030723 100644
--- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java
+++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java
@@ -17,6 +17,7 @@
  */
 package org.apache.commons.rdf.rdf4j;
 
+import java.util.ConcurrentModificationException;
 import java.util.Set;
 import java.util.stream.Stream;
 
@@ -97,7 +98,7 @@ public interface RDF4JGraph extends Graph, RDF4JGraphLike<Triple> {
 	 * This can generally achieved using a try-with-resources block, e.g.:
 	 * <pre>
 	 * int subjects;
-	 * try (Stream&lt;RDF4JTriple&gt; s : graph.stream()) {
+	 * try (Stream&lt;RDF4JTriple&gt; s : graph.stream(s,p,o)) {
 	 *   subjects = s.map(RDF4JTriple::getSubject).distinct().count()
 	 * }
 	 * </pre>
@@ -105,4 +106,50 @@ public interface RDF4JGraph extends Graph, RDF4JGraphLike<Triple> {
 	@Override
 	Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, IRI predicate, RDFTerm object);
 	
+	
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 * Note that the iterable <strong>must be closed</strong> with
+	 * {@link ClosableIterable#close()}. 
+	 * call 
+	 * <p>
+	 * This can generally achieved using a try-with-resources block, e.g.:
+	 * <pre>
+	 * int subjects;
+	 * try (ClosableIterable&lt;Triple&gt; s : graph.iterate()) {
+     *   for (Triple t : triples) {
+     *       return t; // OK to terminate for-loop early
+     *   }
+	 * }
+	 * </pre>
+	 * If you don't use a try-with-resources block, the iterator will 
+	 * attempt to close the ClosableIterable 
+	 * when reaching the end of the iteration.
+	 */	
+	@Override
+	ClosableIterable<Triple> iterate() throws ConcurrentModificationException, IllegalStateException;
+
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 * Note that the iterable <strong>must be closed</strong> with
+	 * {@link ClosableIterable#close()}. 
+	 * call 
+	 * <p>
+	 * This can generally achieved using a try-with-resources block, e.g.:
+	 * <pre>
+	 * int subjects;
+	 * try (ClosableIterable&lt;Triple&gt; s : graph.iterate(s,p,o)) {
+     *   for (Triple t : triples) {
+     *       return t; // OK to terminate for-loop early
+     *   }
+	 * }
+	 * </pre>
+	 * If you don't use a try-with-resources block, the iterator will 
+	 * attempt to close the ClosableIterable 
+	 * when reaching the end of the iteration.
+	 */	
+	@Override
+	Iterable<Triple> iterate(BlankNodeOrIRI subject, IRI predicate, RDFTerm object);
 }

http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/a47ad362/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java
----------------------------------------------------------------------
diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java
index e207007..17aeccb 100644
--- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java
+++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java
@@ -18,13 +18,17 @@
 package org.apache.commons.rdf.rdf4j.impl;
 
 import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Stream;
 
 import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.IRI;
 import org.apache.commons.rdf.api.RDFTerm;
 import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.ClosableIterable;
 import org.apache.commons.rdf.rdf4j.RDF4JBlankNodeOrIRI;
 import org.apache.commons.rdf.rdf4j.RDF4JGraph;
 import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
@@ -128,5 +132,27 @@ final class ModelGraphImpl implements RDF4JGraph {
 		return Collections.emptySet();
 		// TODO: Should we support contextMask like in RepositoryGraphImpl?
 	}
+
+	@Override
+	public ClosableIterable<Triple> iterate(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+		return new ClosableIterable<Triple>() {		
+			@SuppressWarnings("unchecked")
+			@Override
+			public Iterator<Triple> iterator() {
+				// double-cast to fight Java generics..
+				Stream<? extends Triple> s = stream(subject, predicate, object);
+				return (Iterator<Triple>) s.iterator();
+			}
+			@Override
+			public void close() throws Exception {
+				// no-op as Model don't have transaction
+			}
+		};
+	}
+	
+	@Override
+	public ClosableIterable<Triple> iterate() throws ConcurrentModificationException, IllegalStateException {
+		return iterate(null, null, null);
+	}
 	
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/a47ad362/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java
----------------------------------------------------------------------
diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java
index b6b44d9..ce0add1 100644
--- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java
+++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java
@@ -18,7 +18,9 @@
 package org.apache.commons.rdf.rdf4j.impl;
 
 import java.util.Collections;
+import java.util.ConcurrentModificationException;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Stream;
@@ -28,6 +30,7 @@ import org.apache.commons.rdf.api.Graph;
 import org.apache.commons.rdf.api.IRI;
 import org.apache.commons.rdf.api.RDFTerm;
 import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.ClosableIterable;
 import org.apache.commons.rdf.rdf4j.RDF4JBlankNodeOrIRI;
 import org.apache.commons.rdf.rdf4j.RDF4JGraph;
 import org.apache.commons.rdf.rdf4j.RDF4JTriple;
@@ -41,6 +44,40 @@ import org.eclipse.rdf4j.repository.RepositoryResult;
 
 class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements Graph, RDF4JGraph {
 
+	private final class TripleIteration implements ClosableIterable<Triple> {
+		private RepositoryConnection conn;
+		private RepositoryResult<Statement> results;
+		private TripleIteration(Resource subj, org.eclipse.rdf4j.model.IRI pred, Value obj) {
+			conn = getRepositoryConnection();
+			results = conn.getStatements(subj, pred, obj, contextMask);
+		}
+		
+		@Override
+		public Iterator<Triple> iterator() {
+			return new Iterator<Triple>(){
+				@Override
+				public boolean hasNext() {
+					boolean hasNext = results.hasNext();
+					if (! hasNext) {
+						close();
+					}
+					return hasNext;
+				}
+				@Override
+				public Triple next() {					
+					Statement statement = results.next();
+					return rdf4jTermFactory.asTriple(statement);
+				}
+			};
+		}
+
+		@Override
+		public void close() {
+			results.close();
+			conn.close();
+		}
+	}
+
 	private final Resource[] contextMask;
 
 	RepositoryGraphImpl(Repository repository, boolean handleInitAndShutdown, boolean includeInferred, Resource... contextMask) {
@@ -128,6 +165,20 @@ class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements
 			conn.commit();
 		}
 	}
+	
+	@Override
+	public ClosableIterable<Triple> iterate() throws ConcurrentModificationException, IllegalStateException {
+		return iterate(null, null, null);
+	}
+	
+	@Override
+	public ClosableIterable<Triple> iterate(BlankNodeOrIRI subject, IRI predicate, RDFTerm object)
+			throws ConcurrentModificationException, IllegalStateException {
+		Resource subj = (Resource) rdf4jTermFactory.asValue(subject);
+		org.eclipse.rdf4j.model.IRI pred = (org.eclipse.rdf4j.model.IRI) rdf4jTermFactory.asValue(predicate);
+		Value obj = rdf4jTermFactory.asValue(object);
+		return new TripleIteration(subj, pred, obj);
+	}
 
 	@Override
 	public Stream<RDF4JTriple> stream() {

http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/a47ad362/rdf4j/src/test/java/org/apache/commons/rdf/rdf4j/NativeStoreGraphTest.java
----------------------------------------------------------------------
diff --git a/rdf4j/src/test/java/org/apache/commons/rdf/rdf4j/NativeStoreGraphTest.java b/rdf4j/src/test/java/org/apache/commons/rdf/rdf4j/NativeStoreGraphTest.java
index 392d63d..aed763b 100644
--- a/rdf4j/src/test/java/org/apache/commons/rdf/rdf4j/NativeStoreGraphTest.java
+++ b/rdf4j/src/test/java/org/apache/commons/rdf/rdf4j/NativeStoreGraphTest.java
@@ -19,6 +19,8 @@ package org.apache.commons.rdf.rdf4j;
 
 import java.io.IOException;
 import java.io.UncheckedIOException;
+import java.util.Collections;
+import java.util.Set;
 
 import org.apache.commons.rdf.api.AbstractGraphTest;
 import org.apache.commons.rdf.api.BlankNodeOrIRI;
@@ -39,10 +41,6 @@ import org.junit.rules.TemporaryFolder;
 /**
  * Test a graph within a file-based RDF4J {@link SailRepository}.
  * <p>
- * Note that for efficiency reasons this test uses a shared repository for all
- * tests, but uses a different BlankNode context for each 
- * {@link NativeStoreFactory#createGraph()}.
- * <p>
  * TIP: If the {@link #shutdownAndDelete()} take about 20 seconds
  * this is a hint that a {@link RepositoryConnection} or 
  * {@link RepositoryResult} was not closed correctly.
@@ -56,7 +54,9 @@ public class NativeStoreGraphTest extends AbstractGraphTest {
 
 		@Override
 		public RDF4JGraph createGraph() {
-			return rdf4jFactory.asRDFTermGraph(getRepository());
+			// We re-use the repository connection, but use a different context every time
+			Set<RDF4JBlankNode> context = Collections.singleton(rdf4jFactory.createBlankNode());
+			return rdf4jFactory.asRDFTermGraph(getRepository(), context);
 		}
 
 		// Delegate methods 


[3/3] incubator-commonsrdf git commit: Split out ConvertedStatements iterable

Posted by st...@apache.org.
Split out ConvertedStatements iterable


Project: http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/commit/90e3e500
Tree: http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/tree/90e3e500
Diff: http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/diff/90e3e500

Branch: refs/heads/rdf4j
Commit: 90e3e50067112a947a0e5147940bb04854e93d96
Parents: a47ad36
Author: Stian Soiland-Reyes <st...@apache.org>
Authored: Fri Oct 7 00:36:36 2016 +0100
Committer: Stian Soiland-Reyes <st...@apache.org>
Committed: Fri Oct 7 00:43:50 2016 +0100

----------------------------------------------------------------------
 .../apache/commons/rdf/rdf4j/RDF4JDataset.java  | 47 +++++++++++++
 .../apache/commons/rdf/rdf4j/RDF4JGraph.java    |  4 +-
 .../rdf/rdf4j/impl/ConvertedStatements.java     | 71 ++++++++++++++++++++
 .../rdf/rdf4j/impl/RepositoryDatasetImpl.java   | 19 ++++++
 .../rdf/rdf4j/impl/RepositoryGraphImpl.java     | 41 ++---------
 5 files changed, 142 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/90e3e500/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JDataset.java
----------------------------------------------------------------------
diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JDataset.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JDataset.java
index d1aea4c..8ed5d4d 100644
--- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JDataset.java
+++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JDataset.java
@@ -25,6 +25,7 @@ import org.apache.commons.rdf.api.Dataset;
 import org.apache.commons.rdf.api.IRI;
 import org.apache.commons.rdf.api.Quad;
 import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.Triple;
 import org.eclipse.rdf4j.repository.RepositoryConnection;
 
 
@@ -88,4 +89,50 @@ public interface RDF4JDataset extends Dataset, RDF4JGraphLike<Quad> {
 	@Override
 	Stream<BlankNodeOrIRI> getGraphNames();
 	
+
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 * Note that the iterable <strong>must be closed</strong> with
+	 * {@link ClosableIterable#close()}. 
+	 * call 
+	 * <p>
+	 * This can generally achieved using a try-with-resources block, e.g.:
+	 * <pre>
+	 * try (ClosableIterable&lt;Quad&gt; s : graph.iterate()) {
+     *   for (Quad q : quads) {
+     *       return q; // OK to terminate for-loop early
+     *   }
+	 * }
+	 * </pre>
+	 * If you don't use a try-with-resources block, the iterator will 
+	 * attempt to close the ClosableIterable 
+	 * when reaching the end of the iteration.
+	 */	
+	@Override
+	ClosableIterable<Quad> iterate();
+	
+
+	/**
+	 * {@inheritDoc}
+	 * <p>
+	 * Note that the iterable <strong>must be closed</strong> with
+	 * {@link ClosableIterable#close()}. 
+	 * call 
+	 * <p>
+	 * This can generally achieved using a try-with-resources block, e.g.:
+	 * <pre>
+	 * try (ClosableIterable&lt;Quad&gt; s : graph.iterate(g,s,p,o)) {
+     *   for (Quad q : quads) {
+     *       return q; // OK to terminate for-loop early
+     *   }
+	 * }
+	 * </pre>
+	 * If you don't use a try-with-resources block, the iterator will 
+	 * attempt to close the ClosableIterable 
+	 * when reaching the end of the iteration.
+	 */	
+	@Override
+	ClosableIterable<Quad> iterate(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object);	
+	
 }

http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/90e3e500/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java
----------------------------------------------------------------------
diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java
index 8030723..c19e14a 100644
--- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java
+++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java
@@ -116,7 +116,6 @@ public interface RDF4JGraph extends Graph, RDF4JGraphLike<Triple> {
 	 * <p>
 	 * This can generally achieved using a try-with-resources block, e.g.:
 	 * <pre>
-	 * int subjects;
 	 * try (ClosableIterable&lt;Triple&gt; s : graph.iterate()) {
      *   for (Triple t : triples) {
      *       return t; // OK to terminate for-loop early
@@ -139,7 +138,6 @@ public interface RDF4JGraph extends Graph, RDF4JGraphLike<Triple> {
 	 * <p>
 	 * This can generally achieved using a try-with-resources block, e.g.:
 	 * <pre>
-	 * int subjects;
 	 * try (ClosableIterable&lt;Triple&gt; s : graph.iterate(s,p,o)) {
      *   for (Triple t : triples) {
      *       return t; // OK to terminate for-loop early
@@ -151,5 +149,5 @@ public interface RDF4JGraph extends Graph, RDF4JGraphLike<Triple> {
 	 * when reaching the end of the iteration.
 	 */	
 	@Override
-	Iterable<Triple> iterate(BlankNodeOrIRI subject, IRI predicate, RDFTerm object);
+	ClosableIterable<Triple> iterate(BlankNodeOrIRI subject, IRI predicate, RDFTerm object);
 }

http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/90e3e500/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ConvertedStatements.java
----------------------------------------------------------------------
diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ConvertedStatements.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ConvertedStatements.java
new file mode 100644
index 0000000..4c8478a
--- /dev/null
+++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ConvertedStatements.java
@@ -0,0 +1,71 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.rdf.rdf4j.impl;
+
+import java.util.Iterator;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import org.apache.commons.rdf.rdf4j.ClosableIterable;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+final class ConvertedStatements<T> implements ClosableIterable<T> {
+	
+	private RepositoryConnection conn;
+	private RepositoryResult<Statement> results;
+	private Function<Statement, T> statementAdapter;
+
+	ConvertedStatements(Supplier<RepositoryConnection> repositoryConnector, Function<Statement, T> statementAdapter,
+			Resource subj, org.eclipse.rdf4j.model.IRI pred, Value obj, Resource... contexts) {
+		this.statementAdapter = statementAdapter;
+		this.conn = repositoryConnector.get();
+		this.results = conn.getStatements(subj, pred, obj, contexts);
+	}
+
+	@Override
+	public Iterator<T> iterator() {
+		return new ConvertedIterator();
+	}
+
+	@Override
+	public void close() {
+		results.close();
+		conn.close();
+	}
+
+	private final class ConvertedIterator implements Iterator<T> {
+		@Override
+		public boolean hasNext() {
+			boolean hasNext = results.hasNext();
+			if (!hasNext) {
+				close();
+			}
+			return hasNext;
+		}
+
+		@Override
+		public T next() {
+			return statementAdapter.apply(results.next());
+		}
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/90e3e500/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java
----------------------------------------------------------------------
diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java
index eca52fe..2efef42 100644
--- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java
+++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java
@@ -17,6 +17,7 @@
  */
 package org.apache.commons.rdf.rdf4j.impl;
 
+import java.util.ConcurrentModificationException;
 import java.util.Optional;
 import java.util.stream.Stream;
 
@@ -26,6 +27,7 @@ import org.apache.commons.rdf.api.Graph;
 import org.apache.commons.rdf.api.IRI;
 import org.apache.commons.rdf.api.Quad;
 import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.rdf4j.ClosableIterable;
 import org.apache.commons.rdf.rdf4j.RDF4JDataset;
 import org.apache.commons.rdf.rdf4j.RDF4JQuad;
 import org.eclipse.rdf4j.common.iteration.Iterations;
@@ -170,6 +172,23 @@ class RepositoryDatasetImpl extends AbstractRepositoryGraphLike<Quad> implements
 
 	}
 
+
+	@Override
+	public ClosableIterable<Quad> iterate() throws ConcurrentModificationException, IllegalStateException {
+		return iterate(null, null, null, null);
+	}
+	
+	@Override
+	public ClosableIterable<Quad> iterate(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object)
+			throws ConcurrentModificationException, IllegalStateException {
+		Resource[] contexts = asContexts(graphName);
+		Resource subj = (Resource) rdf4jTermFactory.asValue(subject);
+		org.eclipse.rdf4j.model.IRI pred = (org.eclipse.rdf4j.model.IRI) rdf4jTermFactory.asValue(predicate);
+		Value obj = rdf4jTermFactory.asValue(object);
+		return new ConvertedStatements<Quad>(this::getRepositoryConnection, 
+				rdf4jTermFactory::asQuad, subj, pred, obj, contexts);
+	}	
+	
 	@Override
 	protected RDF4JQuad asTripleLike(Statement s) {
 		return rdf4jTermFactory.asQuad(s);

http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/90e3e500/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java
----------------------------------------------------------------------
diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java
index ce0add1..03fede3 100644
--- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java
+++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java
@@ -20,9 +20,9 @@ package org.apache.commons.rdf.rdf4j.impl;
 import java.util.Collections;
 import java.util.ConcurrentModificationException;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Objects;
 import java.util.Set;
+import java.util.function.Function;
 import java.util.stream.Stream;
 
 import org.apache.commons.rdf.api.BlankNodeOrIRI;
@@ -43,41 +43,7 @@ import org.eclipse.rdf4j.repository.RepositoryConnection;
 import org.eclipse.rdf4j.repository.RepositoryResult;
 
 class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements Graph, RDF4JGraph {
-
-	private final class TripleIteration implements ClosableIterable<Triple> {
-		private RepositoryConnection conn;
-		private RepositoryResult<Statement> results;
-		private TripleIteration(Resource subj, org.eclipse.rdf4j.model.IRI pred, Value obj) {
-			conn = getRepositoryConnection();
-			results = conn.getStatements(subj, pred, obj, contextMask);
-		}
-		
-		@Override
-		public Iterator<Triple> iterator() {
-			return new Iterator<Triple>(){
-				@Override
-				public boolean hasNext() {
-					boolean hasNext = results.hasNext();
-					if (! hasNext) {
-						close();
-					}
-					return hasNext;
-				}
-				@Override
-				public Triple next() {					
-					Statement statement = results.next();
-					return rdf4jTermFactory.asTriple(statement);
-				}
-			};
-		}
-
-		@Override
-		public void close() {
-			results.close();
-			conn.close();
-		}
-	}
-
+	
 	private final Resource[] contextMask;
 
 	RepositoryGraphImpl(Repository repository, boolean handleInitAndShutdown, boolean includeInferred, Resource... contextMask) {
@@ -177,7 +143,8 @@ class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements
 		Resource subj = (Resource) rdf4jTermFactory.asValue(subject);
 		org.eclipse.rdf4j.model.IRI pred = (org.eclipse.rdf4j.model.IRI) rdf4jTermFactory.asValue(predicate);
 		Value obj = rdf4jTermFactory.asValue(object);
-		return new TripleIteration(subj, pred, obj);
+		return new ConvertedStatements<Triple>(this::getRepositoryConnection, rdf4jTermFactory::asTriple, 
+				subj, pred, obj, contextMask);
 	}
 
 	@Override