You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commonsrdf.apache.org by stain <gi...@git.apache.org> on 2016/09/28 13:59:41 UTC
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
GitHub user stain opened a pull request:
https://github.com/apache/incubator-commonsrdf/pull/24
COMMONSRDF-35 Add rdf4j integration
This adds the `rdf4j` module, adding integrations for [Eclipse RDF4J](http://rdf4j.org/) - formerly known as Sesame.
You can merge this pull request into a Git repository by running:
$ git pull https://github.com/apache/incubator-commonsrdf rdf4j
Alternatively you can review and apply these changes as the patch at:
https://github.com/apache/incubator-commonsrdf/pull/24.patch
To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:
This closes #24
----
commit dadfaeca2a3c9a4722f5b481eb2792196392e6ac
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T15:50:44Z
Rdf4jRDFTermFactory
commit 36db3bcc78a1cabbc5ee50b1b519aa133eb93194
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T18:49:22Z
sesame Triple/Graph support
commit 12a6a39dda7c0aed7ce5216b577494d7418e6840
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T19:08:31Z
Sesame: Avoid anonymous classes
commit 1fb7e72f500abe8363e3b5c6dfda4965aca84a7a
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T21:26:57Z
rdf4j tests
commit e4a43bcfa999025e7bd13358ce3ec704450692a2
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T21:43:33Z
Added RDFTermImplementation
commit 57b7b568426122d8c43b783a07b78ad09b2c1f36
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T21:46:30Z
Trying Sesame's MemoryStore transactions..
commit fbdeb5250ffe353721daaec16e1413a7cb5c6b3f
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T22:01:24Z
rdf4j .equals
commit fcb04d6c8ea1dc163bd843fa9f9a41caf008e540
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T22:03:15Z
Correct @language in literal.ntriplesString()
commit 774be3d3bf8e2f46e821048dd6652b30682705ed
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T22:14:51Z
Correct Literal.ntriplesString() datatype
commit b58505747f8627153c812d6fbff5fa197a21c41d
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T22:15:09Z
rdf4j tests
commit c3ee194a4f380660d2c878226ae5f51527e7f69c
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T22:27:05Z
Escape BlankNode labels - if needed
commit 78310991d4a13869e456a73250f306b22a424b72
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T22:33:02Z
No need for Simple just for Types.XSD_STRING
commit 38126b3b0dd8adca8770383ffc6f34cb4c4ffced
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T22:34:36Z
README
commit d55717a73f8604c5f39e5b74a369179ad33c9457
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T22:44:31Z
Expose GraphImpl etc for .asModel() calls
commit 71b5893f1772f37f3ad980e98935c1ce088bc578
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T23:03:15Z
Added RDF4J interfaces
to expose asValue(), asModel(), asStatement()
commit 730a9cd0cc129bfb069ce8b5cbc72245c519e642
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T23:04:14Z
RDF4JTermFactory
commit 5e7dfc681d83a823df270c69cacf915d181a6403
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T23:14:49Z
Reorganizing
commit d1386378336ab2cf50823207514e9d3c50a9b3b2
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T23:15:09Z
javadocs
commit 764cb813bbd8f2294e25bb745e583fd02783c9a3
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T23:35:59Z
javadocs
commit 978af59126faf07ef610a59f9f16d14bd150409c
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T23:38:37Z
organized method order
commit ed2271366fbf8ccd8980ffd855d8510727036a55
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-05-03T23:40:22Z
static RDFTermImpl
commit 575d2afde1ed479aa8e3b84c4b64ea38ee7aff56
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-06-02T16:32:42Z
Merge branch 'quad' into rdf4j
commit 12051e9c6e9be4fa15a84562cf04052084d779d7
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-06-02T16:39:47Z
Upgrade to rdf4j 2.0M2
commit b0c67ac9aaf4bf490799fbfa8df7e4ef73c5acd4
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-06-02T16:42:39Z
getTriples() -> stream
commit 9534c3938537c4a4039d2c300251c2df054d6969
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-06-02T16:42:42Z
Ensure consistent rdf4j versions
commit 6fd4ce5d9c39143967aeec9babdf2f4e11c3c679
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-06-02T16:45:01Z
Include rdf4j <module>
commit a82949f6105f8b322dcd9c46278dd477c30f0e52
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-06-02T17:03:42Z
commons-rdf-parent 0.3.0
commit 2cde4c93d584059d0e1d1da91b136e3062809cb2
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-06-02T17:04:02Z
static classes, pass UUID salt
commit ed0213ddc6ae5990052a1f0a7f0824dcb66b32b6
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-06-02T17:09:27Z
GraphImpl also static class
commit 16ff4466cd5e01ec1d59dce55294a28d908e314c
Author: Stian Soiland-Reyes <st...@apache.org>
Date: 2016-06-02T17:43:46Z
Exctracted rdf4j implementation classes
----
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81337539
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRepositoryGraphLike.java ---
@@ -0,0 +1,80 @@
+/**
+ * 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.Optional;
+
+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.TripleLike;
+import org.apache.commons.rdf.rdf4j.RDF4JGraphLike;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+
+public abstract class AbstractRepositoryGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
+ implements RDF4JGraphLike<T> {
+
+ protected Repository repository;
+ protected boolean includeInferred;
+ protected boolean shouldWeShutdown = false;
+ protected RDF4JTermFactory rdf4jTermFactory;
+
+ public AbstractRepositoryGraphLike(Repository repository) {
+ this(repository, false);
+ }
+
+ public AbstractRepositoryGraphLike(Repository repository, boolean includeInferred) {
+ this.repository = repository;
+ this.includeInferred = includeInferred;
+ if (!repository.isInitialized()) {
+ repository.initialize();
+ shouldWeShutdown = true;
+ }
+ rdf4jTermFactory = new RDF4JTermFactory(repository.getValueFactory());
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (shouldWeShutdown) {
--- End diff --
Perhaps this can only be done given a `handleInitAndShutdown` boolean constructor parameter.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81259774
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java ---
@@ -0,0 +1,134 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+public final class ModelGraphImpl implements RDF4JGraph {
+
+ private Model model;
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ public ModelGraphImpl(Model model) {
+ this.model = model;
+ this.rdf4jTermFactory = new RDF4JTermFactory();
+ }
+
+ public ModelGraphImpl(Model model, RDF4JTermFactory rdf4jTermFactory) {
+ this.model = model;
+ this.rdf4jTermFactory = rdf4jTermFactory;
+ }
+
+ @Override
+ public void add(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.add(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void add(Triple triple) {
+ model.add(rdf4jTermFactory.asStatement(triple));
+ }
+
+ public Optional<Model> asModel() {
+ return Optional.of(model);
+ }
+
+ @Override
+ public Optional<Repository> asRepository() {
+ return Optional.empty();
+ }
+
+ @Override
+ public void clear() {
+ model.clear();
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.contains(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public boolean contains(Triple triple) {
+ return model.contains(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.remove(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void remove(Triple triple) {
+ model.remove(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public long size() {
+ int size = model.size();
+ if (size < Integer.MAX_VALUE) {
+ return size;
+ } else {
+ // TODO: Check if this can really happen with RDF4J models
+ // Collection.size() can't help us, we'll have to count
+ return model.parallelStream().count();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream() {
+ return model.parallelStream().map(rdf4jTermFactory::asTriple);
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.filter(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object)).parallelStream()
+ .map(rdf4jTermFactory::asTriple);
+ }
+
+ @Override
+ public Optional<Resource[]> getContextFilter() {
+ // ModelGraph always do the unionGraph
+ return Optional.empty();
+ // TODO: Should we support contextFilter like in RepositoryGraphImpl?
--- End diff --
To be consistent, the mask/filter should be implemented the same for both the Model and Repository versions. Model supports the same methods for context selection as Repository so it shouldn't be difficult to implement them both.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81256212
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/BlankNodeImpl.java ---
@@ -0,0 +1,93 @@
+/**
+ * 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.nio.charset.StandardCharsets;
+import java.util.UUID;
+
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNode;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.rio.turtle.TurtleUtil;
+
+public final class BlankNodeImpl extends AbstractRDFTerm<BNode>
+ implements RDF4JBlankNode {
+
+ private transient int hashCode = 0;
+ private long saltUUIDleast;
+ private long saltUUIDmost;
+
+ public BlankNodeImpl(BNode bNode, UUID salt) {
+ super(bNode);
+ // Space-efficient storage of salt UUID
+ saltUUIDmost = salt.getMostSignificantBits();
+ saltUUIDleast = salt.getLeastSignificantBits();
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ // NOTE: Do NOT use Bnode.equals() as it has a more generous
+ // equality based only on the value.getID();
+ if (obj instanceof BlankNode) {
+ BlankNode blankNode = (BlankNode) obj;
+ return uniqueReference().equals(blankNode.uniqueReference());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ if (hashCode != 0) {
+ return hashCode;
+ }
+ return hashCode = uniqueReference().hashCode();
+ }
+
+ private boolean isValidBlankNodeLabel(String id) {
+ // FIXME: Replace with a regular expression?
--- End diff --
Directly using the regex from the N-Triples specification would be simpler than this version.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81665489
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/BlankNodeImpl.java ---
@@ -0,0 +1,93 @@
+/**
+ * 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.nio.charset.StandardCharsets;
+import java.util.UUID;
+
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNode;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.rio.turtle.TurtleUtil;
+
+public final class BlankNodeImpl extends AbstractRDFTerm<BNode>
+ implements RDF4JBlankNode {
+
+ private transient int hashCode = 0;
+ private long saltUUIDleast;
+ private long saltUUIDmost;
+
+ public BlankNodeImpl(BNode bNode, UUID salt) {
+ super(bNode);
+ // Space-efficient storage of salt UUID
+ saltUUIDmost = salt.getMostSignificantBits();
+ saltUUIDleast = salt.getLeastSignificantBits();
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ // NOTE: Do NOT use Bnode.equals() as it has a more generous
+ // equality based only on the value.getID();
+ if (obj instanceof BlankNode) {
+ BlankNode blankNode = (BlankNode) obj;
+ return uniqueReference().equals(blankNode.uniqueReference());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ if (hashCode != 0) {
+ return hashCode;
+ }
+ return hashCode = uniqueReference().hashCode();
+ }
+
+ private boolean isValidBlankNodeLabel(String id) {
+ // FIXME: Replace with a regular expression?
+ if (id.isEmpty()) {
+ return false;
+ }
+ if (! TurtleUtil.isBLANK_NODE_LABEL_StartChar(id.codePointAt(0))) {
--- End diff --
All of the Rio parser modules other than the main package in the rio-api module are effectively implementations, even though their package names don't indicate as much. Accessing RDFParser and RDFWriter implementations is best done indirectly using ServiceLoader, via the "Rio.getParser..." methods. However, actually putting those packages down on paper as officially not part of the public API is a task that I brought up before the initial RDF4J releases but was postponed. Hence, classes like TurtleUtil are still presumed to be fair game for reuse at this point.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81322552
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java ---
@@ -0,0 +1,66 @@
+/**
+ * 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;
+
+import java.util.Optional;
+
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+
+/**
+ * Marker interface for RDF4J implementations of Graph.
+ *
+ * @see ModelGraphImpl
+ * @see RepositoryGraphImpl
+ */
+public interface RDF4JGraph extends Graph, RDF4JGraphLike<Triple> {
+
+ /**
+ * Return a copy of the context filter, if present.
+ * <p>
+ * If {@link Optional#isPresent()}, the filter determines which
+ * <em>contexts</em> in the corresponding RDF4J {@link Model} or
+ * {@link Repository} that this graph reflect. Modifications to the graph
+ * (e.g. {@link #add(Triple)} will be performed for all the specified
+ * contexts, while retrieval (e.g. {@link #contains(Triple)}) will succeed
+ * if the triple is in at least one of the specified contexts.
+ * <p>
+ * The context filter array may contain <code>null</code>, indicating the
+ * default context (the <em>default graph</em> in RDF datasets).
+ * <p>
+ * If the context filter is {@link Optional#empty()}, then this is a
+ * <em>union graph</em> which triples reflecting statements in any contexts.
+ * Triples added to the graph will be added in the default context
+ * <code>null</code>.
+ * <p>
+ * The filter array is a copy, and thus any modifications are not reflected
+ * in the RDF4JGraph.
+ *
+ * @return The context filter as an array of {@link Resource}s, or
+ * {@link Optional#empty()} indicating the union graph (any
+ * context).
+ */
+ public Optional<Resource[]> getContextFilter();
--- End diff --
Problem with `getContexts()` is that it sounds like a query (what contexts does this graph incidentally cover) rather than a selection (what contexts does it select/add to).
On that note `contextFilter` does not make sense for insertion either.. :). Let's try `getContextMask()` then.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81251222
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/BlankNodeImpl.java ---
@@ -0,0 +1,93 @@
+/**
+ * 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.nio.charset.StandardCharsets;
+import java.util.UUID;
+
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNode;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.rio.turtle.TurtleUtil;
+
+public final class BlankNodeImpl extends AbstractRDFTerm<BNode>
+ implements RDF4JBlankNode {
+
+ private transient int hashCode = 0;
+ private long saltUUIDleast;
+ private long saltUUIDmost;
+
+ public BlankNodeImpl(BNode bNode, UUID salt) {
+ super(bNode);
+ // Space-efficient storage of salt UUID
+ saltUUIDmost = salt.getMostSignificantBits();
+ saltUUIDleast = salt.getLeastSignificantBits();
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ // NOTE: Do NOT use Bnode.equals() as it has a more generous
+ // equality based only on the value.getID();
+ if (obj instanceof BlankNode) {
+ BlankNode blankNode = (BlankNode) obj;
+ return uniqueReference().equals(blankNode.uniqueReference());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ if (hashCode != 0) {
+ return hashCode;
+ }
+ return hashCode = uniqueReference().hashCode();
+ }
+
+ private boolean isValidBlankNodeLabel(String id) {
+ // FIXME: Replace with a regular expression?
+ if (id.isEmpty()) {
+ return false;
+ }
+ if (! TurtleUtil.isBLANK_NODE_LABEL_StartChar(id.codePointAt(0))) {
--- End diff --
Not sure if we have put TurtleUtil on the public API (giving partial explanation for the function name you are calling here). I have made backwards incompatible changes to it in the past assuming it wasn't part of the official public API. It is reused in other internal RDF4J modules, which is why it is technically "public", but any updates are synchronised across RDF4J versions which wouldn't necessarily be simple to do here.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81591997
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java ---
@@ -0,0 +1,192 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JQuad;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryDatasetImpl extends AbstractRepositoryGraphLike<Quad> implements RDF4JDataset, Dataset {
+
+ public RepositoryDatasetImpl(Repository repository, boolean includeInferred) {
+ super(repository, includeInferred);
+ }
+
+ public RepositoryDatasetImpl(Repository repository) {
+ super(repository);
+ }
+
+
+ @Override
+ public void add(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred);
+ }
+ }
+
+ @Override
+ public void remove(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear();
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ if (includeInferred) {
+ // We'll need to count them all
+ return stream().count();
+ }
+ // else: Ask directly
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.size();
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ Resource context = (Resource) rdf4jTermFactory.asValue(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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, context);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contexts);
+ }
+ }
+
+ private Resource[] asContexts(Optional<BlankNodeOrIRI> graphName) {
+ Resource[] contexts;
+ if (graphName == null) {
+ // no contexts == any contexts
+ contexts = new Resource[0];
+ } else {
+ BlankNodeOrIRI g = graphName.orElse(null);
+ Resource context = (Resource) rdf4jTermFactory.asValue(g);
+ contexts = new Resource[] { context };
+ }
+ return contexts;
+ }
+
+ @Override
+ public void remove(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contexts);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JQuad> stream() {
+ return stream(null, null, null, null);
+ }
+
+ @Override
+ public Stream<RDF4JQuad> stream(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ RepositoryConnection conn = getRepositoryConnection();
+ // NOTE: connection will be closed outside by the Iterations.stream()
+ RepositoryResult<Statement> statements = conn.getStatements(subj, pred, obj, includeInferred, contexts);
+ return Iterations.stream(statements).map(this::asTripleLike);
+ }
+
+ @Override
+ protected RDF4JQuad asTripleLike(Statement s) {
+ return rdf4jTermFactory.asQuad(s);
+ }
+
+ @Override
+ public Graph getGraph() {
+ // default context only
+ return new RepositoryGraphImpl(repository, includeInferred, (Resource)null);
+ }
+
+ @Override
+ public Optional<Graph> getGraph(BlankNodeOrIRI graphName) {
+ // NOTE: May be null to indicate default context
+ Resource context = (Resource) rdf4jTermFactory.asValue(graphName);
+ return Optional.of(new RepositoryGraphImpl(repository, includeInferred, context));
+ }
+
+ @Override
+ public Stream<BlankNodeOrIRI> getGraphNames() {
+ RepositoryConnection conn = getRepositoryConnection();
+ RepositoryResult<Resource> contexts = conn.getContextIDs();
--- End diff --
I'm passing on a stream from RDF4J's `Iterations` class - so I assume its documentation is correct. But I'll add javadoc to describe the stream should be closed.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81252246
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JIRI.java ---
@@ -0,0 +1,35 @@
+/**
+ * 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;
+
+/**
+ * Marker interface for RDF4J implementations of IRI.
+ *
+ */
+public interface RDF4JIRI
+ extends RDF4JTerm<org.eclipse.rdf4j.model.IRI>, org.apache.commons.rdf.api.IRI {
+
+ /**
+ * Return the corresponding RDF4J {@link org.eclipse.rdf4j.model.IRI}.
+ *
+ * @return The corresponding RDF4J IRI
+ */
+ public org.eclipse.rdf4j.model.IRI asValue();
--- End diff --
It also seems like this is a null override based on the generics setup for asValue in RDF4JTerm.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81260586
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java ---
@@ -0,0 +1,164 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+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.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements Graph, RDF4JGraph {
+
+ private final Resource[] contextFilter;
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, boolean unionGraph) {
--- End diff --
It may be just adding complexity for users to have this constructor. Relying on the typical RDF4J pattern in the other constructor should be sufficient.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by afs <gi...@git.apache.org>.
Github user afs commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81965052
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraphLike.java ---
@@ -0,0 +1,63 @@
+/**
+ * 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;
+
+import java.util.Optional;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.GraphLike;
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.TripleLike;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * Marker interface for RDF4J implementations of GraphLike.
+ *
+ * @see RDF4JGraph
+ *
+ */
+public interface RDF4JGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
--- End diff --
(not sure where to comment)
"Generalised RDF" is actually a concept in RDF 1.1. The generalized RDF 1.1 came about because JSON-LD as bnodes for graph names ... and the perma-thread on literals-as-subjects. So the WG put in the terminology for all of that.
RDF 1.1 (Generalized) does not have "quad", just RDF Dataset, Graphs, Triples and RDF Terms. Quads are reasonably natural in that a dataset is a set of triples (default graph) and an set of quads (named graphs).
Commons RDF can either a common subset of all it integrates or try to espouse it's own take. At the moment, it seems to me, getting it users matters. Going too much into the details, and instead being almost a bit loose in the interests of time, could be better way to go.
As a usage : a SHACL Core engine would be a good target. It is an algorithm that can be used with various systems. SHACL Core does not use SPARQL; some definitions in SHACL Core give both a textual and SPARQL version.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81672592
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java ---
@@ -0,0 +1,164 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+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.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements Graph, RDF4JGraph {
+
+ private final Resource[] contextFilter;
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, boolean unionGraph) {
--- End diff --
I unpublished all constructors and added an `InternalRDF4JFactory` with caveats in its javadoc.
(It needs to be public to cross the package barrier to `.impl`)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81342364
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java ---
@@ -0,0 +1,134 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+public final class ModelGraphImpl implements RDF4JGraph {
+
+ private Model model;
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ public ModelGraphImpl(Model model) {
+ this.model = model;
+ this.rdf4jTermFactory = new RDF4JTermFactory();
+ }
+
+ public ModelGraphImpl(Model model, RDF4JTermFactory rdf4jTermFactory) {
+ this.model = model;
+ this.rdf4jTermFactory = rdf4jTermFactory;
+ }
+
+ @Override
+ public void add(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.add(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void add(Triple triple) {
+ model.add(rdf4jTermFactory.asStatement(triple));
+ }
+
+ public Optional<Model> asModel() {
+ return Optional.of(model);
+ }
+
+ @Override
+ public Optional<Repository> asRepository() {
+ return Optional.empty();
+ }
+
+ @Override
+ public void clear() {
+ model.clear();
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.contains(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public boolean contains(Triple triple) {
+ return model.contains(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.remove(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void remove(Triple triple) {
+ model.remove(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public long size() {
+ int size = model.size();
+ if (size < Integer.MAX_VALUE) {
+ return size;
+ } else {
+ // TODO: Check if this can really happen with RDF4J models
+ // Collection.size() can't help us, we'll have to count
+ return model.parallelStream().count();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream() {
+ return model.parallelStream().map(rdf4jTermFactory::asTriple);
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.filter(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object)).parallelStream()
+ .map(rdf4jTermFactory::asTriple);
+ }
+
+ @Override
+ public Optional<Resource[]> getContextFilter() {
+ // ModelGraph always do the unionGraph
+ return Optional.empty();
+ // TODO: Should we support contextFilter like in RepositoryGraphImpl?
--- End diff --
I had hoped it would be OK to let `Model` not deal with complex cases - perhaps I misunderstood RDF4J in thinking it is mainly a "triple store" rather than a "quad store" as it does not seem to support many context-related operations.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81249430
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraphLike.java ---
@@ -0,0 +1,63 @@
+/**
+ * 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;
+
+import java.util.Optional;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.GraphLike;
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.TripleLike;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * Marker interface for RDF4J implementations of GraphLike.
+ *
+ * @see RDF4JGraph
+ *
+ */
+public interface RDF4JGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
--- End diff --
Without looking at context for why GraphLike or TripleLike exist, the way the generics are setup here gives warning signs to me that it may need to be streamlined.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81256362
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/IRIImpl.java ---
@@ -0,0 +1,61 @@
+/**
+ * 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 org.apache.commons.rdf.rdf4j.RDF4JIRI;
+
+public final class IRIImpl extends AbstractRDFTerm<org.eclipse.rdf4j.model.IRI>
+ implements RDF4JIRI {
+
+ public IRIImpl(org.eclipse.rdf4j.model.IRI iri) {
+ super(iri);
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) { return true; }
+ if (obj instanceof IRIImpl) {
+ IRIImpl impl = (IRIImpl) obj;
+ return asValue().equals(impl.asValue());
+ }
+ if (obj instanceof org.apache.commons.rdf.api.IRI) {
+ org.apache.commons.rdf.api.IRI iri = (org.apache.commons.rdf.api.IRI) obj;
+ return value.toString().equals(iri.getIRIString());
+ }
+ return false;
+ }
+
+ @Override
+ public String getIRIString() {
+ return value.toString();
+ }
+
+ public int hashCode() {
+ // Same definition
+ return value.hashCode();
+ }
+
+ @Override
+ public String ntriplesString() {
+ return "<" + value.toString() + ">";
--- End diff --
Does this need any escaping to be compatible with N-Triples. Ie, does ">" need to be escaped or is that always done for all IRIs.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81260356
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java ---
@@ -0,0 +1,192 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JQuad;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryDatasetImpl extends AbstractRepositoryGraphLike<Quad> implements RDF4JDataset, Dataset {
+
+ public RepositoryDatasetImpl(Repository repository, boolean includeInferred) {
+ super(repository, includeInferred);
+ }
+
+ public RepositoryDatasetImpl(Repository repository) {
+ super(repository);
+ }
+
+
+ @Override
+ public void add(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred);
+ }
+ }
+
+ @Override
+ public void remove(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear();
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ if (includeInferred) {
+ // We'll need to count them all
+ return stream().count();
+ }
+ // else: Ask directly
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.size();
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ Resource context = (Resource) rdf4jTermFactory.asValue(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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, context);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contexts);
+ }
+ }
+
+ private Resource[] asContexts(Optional<BlankNodeOrIRI> graphName) {
+ Resource[] contexts;
+ if (graphName == null) {
+ // no contexts == any contexts
+ contexts = new Resource[0];
+ } else {
+ BlankNodeOrIRI g = graphName.orElse(null);
+ Resource context = (Resource) rdf4jTermFactory.asValue(g);
+ contexts = new Resource[] { context };
+ }
+ return contexts;
+ }
+
+ @Override
+ public void remove(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contexts);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JQuad> stream() {
+ return stream(null, null, null, null);
+ }
+
+ @Override
+ public Stream<RDF4JQuad> stream(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ RepositoryConnection conn = getRepositoryConnection();
+ // NOTE: connection will be closed outside by the Iterations.stream()
+ RepositoryResult<Statement> statements = conn.getStatements(subj, pred, obj, includeInferred, contexts);
--- End diff --
You still need to reliably close this RepositoryResult in the case where the iteration below fails to complete. You can use try-with-resources as RepositoryResult implements AutoCloseable.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81330211
--- Diff: rdf4j/pom.xml ---
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-rdf-parent</artifactId>
+ <version>0.3.0-incubating-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>commons-rdf-rdf4j</artifactId>
+ <packaging>jar</packaging>
+ <properties>
+ <rdf4j.version>2.0</rdf4j.version>
+ </properties>
+
+ <name>Commons RDF: Integration: RDF4j</name>
+ <description>Eclipse RDF4j implementation of Commons RDF API</description>
+
+ <build>
+ <plugins>
+ <plugin>
+
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <!-- Not sure why this is needed, .impl and .internal is normally hidden
+ by the Bundle Plugin.. -->
+
+ <Export-Package>org.apache.commons.rdf.rdf4j</Export-Package>
+ <Private-Package>org.apache.commons.rdf.rdf4j.impl</Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>commons-rdf-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>commons-rdf-simple</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- Selected rdf4j dependencies We don't use rdf4j-runtime or rdf4j-runtime-osgi
+ here, as they pull in various depenencies like lucene, which might not be
+ needed. -->
+
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-model</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-repository-api</artifactId>
+ </dependency>
+
+ <!-- For RDF4JParserBuilder, these are the RIO dependencies for the standard
+ RDF 1.1 languages -->
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-turtle</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-ntriples</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-nquads</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-rdfxml</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-trig</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-jsonld</artifactId>
+ </dependency>
+ <!-- Languages notably missing, and why:
--- End diff --
I think there's argument either way.. we could have a pure dependency on `rdf4j-model` and `rdf4j-repository-api`- (which would minimize the chances of versioning conflicts and us needing to pull in the rdf4j bom) but then you can't parse any of the useful syntaxes. As a Commons project I think most Maven users would expect it to work "out of the box".
Perhaps the `RDF4JParser` could be in a separate Maven module (it's experimental for 0.3.0 anyway) - or we could just include instructions on how to add the different parser implementations. (I've not written docs on how to use the rdf4j or jena implementation modules yet)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81259860
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java ---
@@ -0,0 +1,134 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+public final class ModelGraphImpl implements RDF4JGraph {
+
+ private Model model;
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ public ModelGraphImpl(Model model) {
+ this.model = model;
+ this.rdf4jTermFactory = new RDF4JTermFactory();
+ }
+
+ public ModelGraphImpl(Model model, RDF4JTermFactory rdf4jTermFactory) {
+ this.model = model;
+ this.rdf4jTermFactory = rdf4jTermFactory;
+ }
+
+ @Override
+ public void add(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.add(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void add(Triple triple) {
+ model.add(rdf4jTermFactory.asStatement(triple));
+ }
+
+ public Optional<Model> asModel() {
+ return Optional.of(model);
+ }
+
+ @Override
+ public Optional<Repository> asRepository() {
+ return Optional.empty();
+ }
+
+ @Override
+ public void clear() {
+ model.clear();
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.contains(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public boolean contains(Triple triple) {
+ return model.contains(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.remove(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void remove(Triple triple) {
+ model.remove(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public long size() {
+ int size = model.size();
+ if (size < Integer.MAX_VALUE) {
+ return size;
+ } else {
+ // TODO: Check if this can really happen with RDF4J models
+ // Collection.size() can't help us, we'll have to count
+ return model.parallelStream().count();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream() {
+ return model.parallelStream().map(rdf4jTermFactory::asTriple);
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.filter(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object)).parallelStream()
+ .map(rdf4jTermFactory::asTriple);
+ }
+
+ @Override
+ public Optional<Resource[]> getContextFilter() {
+ // ModelGraph always do the unionGraph
+ return Optional.empty();
+ // TODO: Should we support contextFilter like in RepositoryGraphImpl?
--- End diff --
There may be some complexity added to some of the stream based methods above if context selection is supported though, so there are tradeoffs.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82313962
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java ---
@@ -0,0 +1,172 @@
+/**
+ * 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.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+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.RDF4JBlankNodeOrIRI;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements Graph, RDF4JGraph {
+
+ private final Resource[] contextMask;
+
+ public RepositoryGraphImpl(Repository repository, boolean handleInitAndShutdown, boolean includeInferred, boolean unionGraph) {
+ super(repository, handleInitAndShutdown, includeInferred);
+ if (unionGraph) {
+ // no context mask, aka any context
+ this.contextMask = new Resource[] { };
+ } else {
+ // default context: null
+ this.contextMask = new Resource[] { null };
+ }
+ }
+
+ public RepositoryGraphImpl(Repository repository, boolean handleInitAndShutdown, boolean includeInferred, Resource... contextMask) {
+ super(repository, handleInitAndShutdown, includeInferred);
+ this.contextMask = Objects.requireNonNull(contextMask);
+ }
+
+
+ @Override
+ public void add(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement, contextMask);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred, contextMask);
+ }
+ }
+
+ @Override
+ public void remove(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement, contextMask);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear(contextMask);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ if (! includeInferred && contextMask.length == 0) {
+ return conn.size();
+ } else {
+ return stream().count();
+ }
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, contextMask);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contextMask);
+ }
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contextMask);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream() {
+ return stream(null, null, null);
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ RepositoryConnection conn = getRepositoryConnection();
+ // FIXME: Is it OK that we don't close the connection?
+ RepositoryResult<Statement> statements = conn.getStatements(subj, pred, obj, includeInferred, contextMask);
+ return Iterations.stream(statements).map(this::asTripleLike);
+ }
+
+ @Override
+ protected RDF4JTriple asTripleLike(Statement statement) {
+ return rdf4jTermFactory.asTriple(statement);
+ }
+
+ @Override
+ public Set<RDF4JBlankNodeOrIRI<Resource>> getContextMask() {
+ Set<RDF4JBlankNodeOrIRI<Resource>> mask = new HashSet<>();
--- End diff --
contextMask is a private final array variable that is inaccessible to users other than through this method. I can't see any other factors that could be used to justify this a premature optimisation.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81659408
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ *
+ * @see #asQuad(Statement)
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public static RDF4JQuad asQuad(final Statement statement, UUID salt) {
+ return new QuadImpl(statement, salt);
+ }
+
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @param value The RDF4J {@link Value} to convert.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException if the value is not a BNode, Literal or IRI
+ */
+ public <T extends Value> RDF4JTerm<T> asRDFTerm(T value) {
+ return asRDFTerm(value, salt);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository) {
+ return new RepositoryDatasetImpl(repository);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred quads are included in the dataset
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository, boolean includeInferred) {
+ return new RepositoryDatasetImpl(repository, includeInferred);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}.
+ * <p>
+ * Changes to the graph are reflected in the model, and vice versa.
+ *
+ * @param model
+ * RDF4J {@link Model} to adapt.
+ * @return Adapted {@link Graph}.
+ */
+ public RDF4JGraph asRDFTermGraph(Model model) {
+ return new ModelGraphImpl(model);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository) {
+ return new RepositoryGraphImpl(repository, false, true);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred triples are included in the graph
+ * @param unionGraph
+ * If true, triples from any context is included in the graph,
+ * otherwise only triples in the default context
+ * <code>null</code>.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, boolean unionGraph) {
+ return new RepositoryGraphImpl(repository, includeInferred, unionGraph);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link Triple} or {@link Quad} as a RDF4J
+ * {@link Statement}.
+ * <p>
+ * If the <code>tripleLike</code> argument is an {@link RDF4JTriple} or
+ * a {@link RDF4JQuad}, then its {@link RDF4JTripleLike#asStatement()} is
+ * returned as-is. Note that this means that a {@link RDF4JTriple} would
+ * preserve its {@link Statement#getContext()}, and that any
+ * {@link BlankNode}s would be deemed equivalent in RDF4J
+ * if they have the same {@link BNode#getID()}.
+ *
+ * @param tripleLike
+ * A {@link Triple} or {@link Quad} to adapt
+ * @return A corresponding {@link Statement}
+ */
+ public Statement asStatement(TripleLike<BlankNodeOrIRI, org.apache.commons.rdf.api.IRI, RDFTerm> tripleLike) {
+ if (tripleLike instanceof RDF4JTripleLike) {
+ // Return original statement - this covers both RDF4JQuad and
+ // RDF4JTriple
+ RDF4JTripleLike rdf4jTriple = (RDF4JTripleLike) tripleLike;
+ return rdf4jTriple.asStatement();
+ }
+
+ org.eclipse.rdf4j.model.Resource subject = (org.eclipse.rdf4j.model.Resource) asValue(tripleLike.getSubject());
+ org.eclipse.rdf4j.model.IRI predicate = (org.eclipse.rdf4j.model.IRI) asValue(tripleLike.getPredicate());
+ Value object = asValue(tripleLike.getObject());
+
+ org.eclipse.rdf4j.model.Resource context = null;
+ if (tripleLike instanceof Quad) {
+ Quad quad = (Quad) tripleLike;
+ context = (org.eclipse.rdf4j.model.Resource) asValue(quad.getGraphName().orElse(null));
+ }
+
+ return getValueFactory().createStatement(subject, predicate, object, context);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this method will use an
+ * internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J statements from multiple
+ * repositories or models, then their {@link BNode}s may have the same
+ * {@link BNode#getID()}, which with this method would become equivalent
+ * according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()}, unless a separate
+ * {@link RDF4JTermFactory} instance is used per RDF4J repository/model.
+ *
+ * @param statement
+ * The RDF4J {@link Statement} to adapt.
+ * @return A {@link RDF4JTriple} that is equivalent to the statement
+ */
+ public RDF4JTriple asTriple(final Statement statement) {
+ return new TripleImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link RDFTerm} as a RDF4J {@link Value}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.apache.commons.rdf.api.BlankNode} is converted to a
+ * {@link org.eclipse.rdf4j.model.BNode}, a
+ * {@link org.apache.commons.rdf.api.IRI} is converted to a
+ * {@link org.eclipse.rdf4j.model.IRI} and a
+ * {@link org.apache.commons.rdf.api.Literal} is converted to a
+ * {@link org.eclipse.rdf4j.model.Literal}.
+ * <p>
+ * If the provided {@link RDFTerm} is <code>null</code>, then the returned
+ * value is <code>null</code>.
+ * <p>
+ * If the provided term is an instance of {@link RDF4JTerm}, then the
+ * {@link RDF4JTerm#asValue()} is returned without any conversion. Note that
+ * this could mean that a {@link Value} from a different kind of
+ * {@link ValueFactory} could be returned.
+ *
+ * @param term
+ * RDFTerm to adapt to RDF4J Value
+ * @return Adapted RDF4J {@link Value}
+ */
+ public Value asValue(RDFTerm term) {
+ if (term == null) {
+ return null;
+ }
+ if (term instanceof RDF4JTerm) {
--- End diff --
Using `else-if` would indicate the order is more crucial than just `if` from my perspective.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82421319
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/BlankNodeImpl.java ---
@@ -0,0 +1,93 @@
+/**
+ * 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.nio.charset.StandardCharsets;
+import java.util.UUID;
+
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNode;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.rio.turtle.TurtleUtil;
+
+public final class BlankNodeImpl extends AbstractRDFTerm<BNode>
+ implements RDF4JBlankNode {
+
+ private transient int hashCode = 0;
+ private long saltUUIDleast;
+ private long saltUUIDmost;
+
+ public BlankNodeImpl(BNode bNode, UUID salt) {
+ super(bNode);
+ // Space-efficient storage of salt UUID
+ saltUUIDmost = salt.getMostSignificantBits();
+ saltUUIDleast = salt.getLeastSignificantBits();
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ // NOTE: Do NOT use Bnode.equals() as it has a more generous
+ // equality based only on the value.getID();
+ if (obj instanceof BlankNode) {
+ BlankNode blankNode = (BlankNode) obj;
+ return uniqueReference().equals(blankNode.uniqueReference());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ if (hashCode != 0) {
+ return hashCode;
+ }
+ return hashCode = uniqueReference().hashCode();
+ }
+
+ private boolean isValidBlankNodeLabel(String id) {
+ // FIXME: Replace with a regular expression?
--- End diff --
Raised as https://issues.apache.org/jira/browse/COMMONSRDF-43
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81342561
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java ---
@@ -0,0 +1,192 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JQuad;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryDatasetImpl extends AbstractRepositoryGraphLike<Quad> implements RDF4JDataset, Dataset {
+
+ public RepositoryDatasetImpl(Repository repository, boolean includeInferred) {
+ super(repository, includeInferred);
+ }
+
+ public RepositoryDatasetImpl(Repository repository) {
+ super(repository);
+ }
+
+
+ @Override
+ public void add(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred);
+ }
+ }
+
+ @Override
+ public void remove(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear();
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ if (includeInferred) {
+ // We'll need to count them all
+ return stream().count();
+ }
+ // else: Ask directly
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.size();
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ Resource context = (Resource) rdf4jTermFactory.asValue(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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, context);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contexts);
+ }
+ }
+
+ private Resource[] asContexts(Optional<BlankNodeOrIRI> graphName) {
+ Resource[] contexts;
+ if (graphName == null) {
+ // no contexts == any contexts
+ contexts = new Resource[0];
+ } else {
+ BlankNodeOrIRI g = graphName.orElse(null);
+ Resource context = (Resource) rdf4jTermFactory.asValue(g);
+ contexts = new Resource[] { context };
+ }
+ return contexts;
+ }
+
+ @Override
+ public void remove(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
--- End diff --
We can add multi-context `.contains()` and `.remove()` to `RDF4JDataset` for consistency.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf issue #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on the issue:
https://github.com/apache/incubator-commonsrdf/pull/24
Here is what the [combined Javadoc](http://stain.github.io/incubator-commonsrdf/COMMONSRDF-35/) looks like, including [org.apache.commons.rdf.rdf4j](http://stain.github.io/incubator-commonsrdf/COMMONSRDF-35/org/apache/commons/rdf/rdf4j/package-summary.html)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82312585
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java ---
@@ -0,0 +1,137 @@
+/**
+ * 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.Collections;
+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.RDFTerm;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNodeOrIRI;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+public final class ModelGraphImpl implements RDF4JGraph {
+
+ private Model model;
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ public ModelGraphImpl(Model model) {
+ this.model = model;
+ this.rdf4jTermFactory = new RDF4JTermFactory();
+ }
+
+ public ModelGraphImpl(Model model, RDF4JTermFactory rdf4jTermFactory) {
+ this.model = model;
+ this.rdf4jTermFactory = rdf4jTermFactory;
+ }
+
+ @Override
+ public void add(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.add(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void add(Triple triple) {
+ model.add(rdf4jTermFactory.asStatement(triple));
+ }
+
+ public Optional<Model> asModel() {
+ return Optional.of(model);
+ }
+
+ @Override
+ public Optional<Repository> asRepository() {
+ return Optional.empty();
+ }
+
+ @Override
+ public void clear() {
+ model.clear();
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.contains(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public boolean contains(Triple triple) {
+ return model.contains(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.remove(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void remove(Triple triple) {
+ model.remove(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public long size() {
+ int size = model.size();
+ if (size < Integer.MAX_VALUE) {
+ return size;
+ } else {
+ // TODO: Check if this can really happen with RDF4J models
+ // Collection.size() can't help us, we'll have to count
+ return model.parallelStream().count();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream() {
+ return model.parallelStream().map(rdf4jTermFactory::asTriple);
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.filter(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object)).parallelStream()
+ .map(rdf4jTermFactory::asTriple);
+ }
+
+ @Override
+ public Set<RDF4JBlankNodeOrIRI<Resource>> getContextMask() {
+ // ModelGraph always do the unionGraph
+ return Collections.emptySet();
+ // TODO: Should we support contextMask like in RepositoryGraphImpl?
--- End diff --
OK, I'll track that in Jira. Probably a similar `AbstractModelGraphLike` can be shared between `ModelGraphImpl` and `RepositoryGraphImpl`.
Why do RDF4J have these two slightly different APIs..? Are both commonly used? I know there was talk of an adapter being contributed from Clerezza.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81660530
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ *
+ * @see #asQuad(Statement)
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public static RDF4JQuad asQuad(final Statement statement, UUID salt) {
+ return new QuadImpl(statement, salt);
+ }
+
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @param value The RDF4J {@link Value} to convert.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException if the value is not a BNode, Literal or IRI
+ */
+ public <T extends Value> RDF4JTerm<T> asRDFTerm(T value) {
+ return asRDFTerm(value, salt);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository) {
+ return new RepositoryDatasetImpl(repository);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred quads are included in the dataset
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository, boolean includeInferred) {
+ return new RepositoryDatasetImpl(repository, includeInferred);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}.
+ * <p>
+ * Changes to the graph are reflected in the model, and vice versa.
+ *
+ * @param model
+ * RDF4J {@link Model} to adapt.
+ * @return Adapted {@link Graph}.
+ */
+ public RDF4JGraph asRDFTermGraph(Model model) {
+ return new ModelGraphImpl(model);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository) {
+ return new RepositoryGraphImpl(repository, false, true);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred triples are included in the graph
+ * @param unionGraph
+ * If true, triples from any context is included in the graph,
+ * otherwise only triples in the default context
+ * <code>null</code>.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, boolean unionGraph) {
+ return new RepositoryGraphImpl(repository, includeInferred, unionGraph);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link Triple} or {@link Quad} as a RDF4J
+ * {@link Statement}.
+ * <p>
+ * If the <code>tripleLike</code> argument is an {@link RDF4JTriple} or
+ * a {@link RDF4JQuad}, then its {@link RDF4JTripleLike#asStatement()} is
+ * returned as-is. Note that this means that a {@link RDF4JTriple} would
+ * preserve its {@link Statement#getContext()}, and that any
+ * {@link BlankNode}s would be deemed equivalent in RDF4J
+ * if they have the same {@link BNode#getID()}.
+ *
+ * @param tripleLike
+ * A {@link Triple} or {@link Quad} to adapt
+ * @return A corresponding {@link Statement}
+ */
+ public Statement asStatement(TripleLike<BlankNodeOrIRI, org.apache.commons.rdf.api.IRI, RDFTerm> tripleLike) {
+ if (tripleLike instanceof RDF4JTripleLike) {
+ // Return original statement - this covers both RDF4JQuad and
+ // RDF4JTriple
+ RDF4JTripleLike rdf4jTriple = (RDF4JTripleLike) tripleLike;
+ return rdf4jTriple.asStatement();
+ }
+
+ org.eclipse.rdf4j.model.Resource subject = (org.eclipse.rdf4j.model.Resource) asValue(tripleLike.getSubject());
+ org.eclipse.rdf4j.model.IRI predicate = (org.eclipse.rdf4j.model.IRI) asValue(tripleLike.getPredicate());
+ Value object = asValue(tripleLike.getObject());
+
+ org.eclipse.rdf4j.model.Resource context = null;
+ if (tripleLike instanceof Quad) {
+ Quad quad = (Quad) tripleLike;
+ context = (org.eclipse.rdf4j.model.Resource) asValue(quad.getGraphName().orElse(null));
+ }
+
+ return getValueFactory().createStatement(subject, predicate, object, context);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this method will use an
+ * internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J statements from multiple
+ * repositories or models, then their {@link BNode}s may have the same
+ * {@link BNode#getID()}, which with this method would become equivalent
+ * according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()}, unless a separate
+ * {@link RDF4JTermFactory} instance is used per RDF4J repository/model.
+ *
+ * @param statement
+ * The RDF4J {@link Statement} to adapt.
+ * @return A {@link RDF4JTriple} that is equivalent to the statement
+ */
+ public RDF4JTriple asTriple(final Statement statement) {
+ return new TripleImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link RDFTerm} as a RDF4J {@link Value}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.apache.commons.rdf.api.BlankNode} is converted to a
+ * {@link org.eclipse.rdf4j.model.BNode}, a
+ * {@link org.apache.commons.rdf.api.IRI} is converted to a
+ * {@link org.eclipse.rdf4j.model.IRI} and a
+ * {@link org.apache.commons.rdf.api.Literal} is converted to a
+ * {@link org.eclipse.rdf4j.model.Literal}.
+ * <p>
+ * If the provided {@link RDFTerm} is <code>null</code>, then the returned
+ * value is <code>null</code>.
+ * <p>
+ * If the provided term is an instance of {@link RDF4JTerm}, then the
+ * {@link RDF4JTerm#asValue()} is returned without any conversion. Note that
+ * this could mean that a {@link Value} from a different kind of
+ * {@link ValueFactory} could be returned.
+ *
+ * @param term
+ * RDFTerm to adapt to RDF4J Value
+ * @return Adapted RDF4J {@link Value}
+ */
+ public Value asValue(RDFTerm term) {
+ if (term == null) {
+ return null;
+ }
+ if (term instanceof RDF4JTerm) {
+ // One of our own - avoid converting again.
+ // (This is crucial to avoid double-escaping in BlankNode)
+ return ((RDF4JTerm<?>) term).asValue();
+ }
+ if (term instanceof org.apache.commons.rdf.api.IRI) {
+ org.apache.commons.rdf.api.IRI iri = (org.apache.commons.rdf.api.IRI) term;
+ return getValueFactory().createIRI(iri.getIRIString());
+ }
+ if (term instanceof org.apache.commons.rdf.api.Literal) {
+ org.apache.commons.rdf.api.Literal literal = (org.apache.commons.rdf.api.Literal) term;
+ String label = literal.getLexicalForm();
+ if (literal.getLanguageTag().isPresent()) {
+ String lang = literal.getLanguageTag().get();
+ return getValueFactory().createLiteral(label, lang);
+ }
+ org.eclipse.rdf4j.model.IRI dataType = (org.eclipse.rdf4j.model.IRI) asValue(literal.getDatatype());
+ return getValueFactory().createLiteral(label, dataType);
+ }
+ if (term instanceof BlankNode) {
+ // This is where it gets tricky to support round trips!
--- End diff --
By round-tripping I meant round-tripping with the same uniqueReference.
Any calls to a particular instance of RDF4J ValueFactory.createBNode(String) with the same String will create an equivalent BNode that will serialise to the same reference in a concrete RDF document created by a single instance of a Rio RDFWriter. However, there are no guarantees that either different ValueFactory objects or implementations, or different RDFWriter objects or implementations, will create an equivalent BNode from the given String or do it in the same way as others.
While the BNode is still in memory, you can rely on BNode.getID() to return the same String as other BlankNodes created from that particular ValueFactory.createBNode(String) object implementation. You can hence use BNode.getID to create the same Commons RDF BlankNode for each RDF4J BNode, but that guarantee is lost if you serialise or use a different ValueFactory or RDFParser object/implementation in future:
https://github.com/eclipse/rdf4j/blob/master/core/model/src/main/java/org/eclipse/rdf4j/model/BNode.java#L20
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82313165
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,603 @@
+/**
+ * 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;
+
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI, Literal)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.InternalRDF4JFactory;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.sail.SailRepository;
+import org.eclipse.rdf4j.sail.Sail;
+import org.eclipse.rdf4j.sail.memory.MemoryStore;
+
+/**
+ * RDF4J implementation of RDFTermFactory.
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally.
+ *
+ */
+public final class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * InternalRDF4JFactory is deliberately abstract
+ */
+ private static InternalRDF4JFactory rdf4j = new InternalRDF4JFactory() {
+ };
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) rdf4j.createBlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) rdf4j.createLiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) rdf4j.createIRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ private final UUID salt;
+
+ private final ValueFactory valueFactory;
+
+ /**
+ * Construct an {@link RDF4JTermFactory}.
+ *
+ */
+ public RDF4JTermFactory() {
+ this(SimpleValueFactory.getInstance(), UUID.randomUUID());
+ }
+
+ /**
+ * Construct an {@link RDF4JTermFactory}.
+ * <p>
+ * This constructor is intended for use with the value factory from
+ * {@link Repository#getValueFactory()} when using
+ * Repository-based graphs and datasets.
+ *
+ * @param valueFactory
+ * The RDF4J {@link ValueFactory} to use
+ */
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this(valueFactory, UUID.randomUUID());
+ }
+
+ /**
+ * Construct an {@link RDF4JTermFactory}.
+ * <p>
+ * This constructor may be used if reproducible
--- End diff --
This comment is unhelpful. Blank Nodes are particularly troublesome already without suggesting that people can alter their identities in unusual ways (different UUID's) and retain working systems.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81249655
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JLiteral.java ---
@@ -0,0 +1,35 @@
+/**
+ * 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;
+
+import org.eclipse.rdf4j.model.Literal;
+
+/**
+ * Marker interface for RDF4J implementations of Literal.
+ *
+ */
+public interface RDF4JLiteral
+ extends RDF4JTerm<org.eclipse.rdf4j.model.Literal>, org.apache.commons.rdf.api.Literal {
+
+ /**
+ * Return the corresponding RDF4J {@link org.eclipse.rdf4j.model.Literal}.
+ *
+ * @return The corresponding RDF4J Literal
+ */
+ Literal asValue();
--- End diff --
Ditto for the comment about IRI, why is the cast method needed here?
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81666472
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java ---
@@ -0,0 +1,134 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+public final class ModelGraphImpl implements RDF4JGraph {
+
+ private Model model;
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ public ModelGraphImpl(Model model) {
+ this.model = model;
+ this.rdf4jTermFactory = new RDF4JTermFactory();
+ }
+
+ public ModelGraphImpl(Model model, RDF4JTermFactory rdf4jTermFactory) {
+ this.model = model;
+ this.rdf4jTermFactory = rdf4jTermFactory;
+ }
+
+ @Override
+ public void add(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.add(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void add(Triple triple) {
+ model.add(rdf4jTermFactory.asStatement(triple));
+ }
+
+ public Optional<Model> asModel() {
+ return Optional.of(model);
+ }
+
+ @Override
+ public Optional<Repository> asRepository() {
+ return Optional.empty();
+ }
+
+ @Override
+ public void clear() {
+ model.clear();
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.contains(
--- End diff --
That is great news that the integration tests are succeeding across implementations!
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81260172
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java ---
@@ -0,0 +1,192 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JQuad;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryDatasetImpl extends AbstractRepositoryGraphLike<Quad> implements RDF4JDataset, Dataset {
+
+ public RepositoryDatasetImpl(Repository repository, boolean includeInferred) {
+ super(repository, includeInferred);
+ }
+
+ public RepositoryDatasetImpl(Repository repository) {
+ super(repository);
+ }
+
+
+ @Override
+ public void add(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred);
+ }
+ }
+
+ @Override
+ public void remove(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear();
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ if (includeInferred) {
+ // We'll need to count them all
+ return stream().count();
+ }
+ // else: Ask directly
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.size();
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ Resource context = (Resource) rdf4jTermFactory.asValue(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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, context);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contexts);
+ }
+ }
+
+ private Resource[] asContexts(Optional<BlankNodeOrIRI> graphName) {
+ Resource[] contexts;
+ if (graphName == null) {
+ // no contexts == any contexts
+ contexts = new Resource[0];
+ } else {
+ BlankNodeOrIRI g = graphName.orElse(null);
+ Resource context = (Resource) rdf4jTermFactory.asValue(g);
+ contexts = new Resource[] { context };
+ }
+ return contexts;
+ }
+
+ @Override
+ public void remove(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
--- End diff --
Personally I would prefer that this method accepted arbitrary numbers of graphs at the same time, but it is an override from the API so that isn't necessary for this pull request.
I have designed applications around the use of Resource... varargs with multiple graphs needing to be searched/updated for each case in the past that would be slightly more complex if I needed to enumerate every possible graph that I was dealing with for the current query.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82317516
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JLiteral.java ---
@@ -0,0 +1,35 @@
+/**
+ * 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;
+
+import org.eclipse.rdf4j.model.Literal;
+
+/**
+ * Marker interface for RDF4J implementations of Literal.
+ *
+ */
+public interface RDF4JLiteral
+ extends RDF4JTerm<org.eclipse.rdf4j.model.Literal>, org.apache.commons.rdf.api.Literal {
+
+ /**
+ * Return the corresponding RDF4J {@link org.eclipse.rdf4j.model.Literal}.
+ *
+ * @return The corresponding RDF4J Literal
+ */
+ Literal asValue();
--- End diff --
I actaully prefer this method now. If generics are removed from RDF4JTerm it would no longer be a null override and would still return a Literal as expected.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81653958
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JDataset.java ---
@@ -0,0 +1,30 @@
+/**
+ * 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;
+
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.api.Quad;
+
+
+/**
+ * Marker interface for RDF4J implementations of Dataset.
+ *
+ */
+public interface RDF4JDataset extends Dataset, RDF4JGraphLike<Quad> {
--- End diff --
It would be simplest if this could match the RDF4J Model.contains contract, but that may not be possible if Commons RDF is already focused on distinguishing Triple collections from Quad collections at the API level:
https://github.com/eclipse/rdf4j/blob/master/core/model/src/main/java/org/eclipse/rdf4j/model/Model.java#L97
The lack of a context (graph) in Model.contains (empty varargs array) indicates that Triple based contains should be used to match on triples without taking into account the Dataset they are contained in. A varargs array with a single null element indicates the default graph should be used to match on just Triples (ie, no graph/context attached to them).
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81674118
--- Diff: rdf4j/src/test/java/org/apache/commons/rdf/rdf4j/NativeStoreGraphTest.java ---
@@ -0,0 +1,66 @@
+/**
+ * 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;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.apache.commons.rdf.api.AbstractGraphTest;
+import org.apache.commons.rdf.api.RDFTermFactory;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.sail.SailRepository;
+import org.eclipse.rdf4j.sail.Sail;
+import org.eclipse.rdf4j.sail.memory.model.MemValueFactory;
+import org.eclipse.rdf4j.sail.nativerdf.NativeStore;
+
+
+public class NativeStoreGraphTest extends AbstractGraphTest {
+
+ public static final class NativeStoreFactory extends RDF4JTermFactory {
+ NativeStoreFactory() {
+ super(new MemValueFactory());
+ }
+ @Override
+ public RDF4JGraph createGraph() {
+ return asRDFTermGraph(createRepository());
+ }
+ }
+
+ public static Repository createRepository() {
+ Path tempDir;
+ try {
+ tempDir = Files.createTempDirectory("test-commonsrdf-rdf4j");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ Sail sail = new NativeStore(tempDir.toFile());
+ SailRepository repository = new SailRepository(sail);
+ repository.initialize();
+ return repository;
+ }
+
+ @Override
+ public RDFTermFactory createFactory() {
+ // FIXME: This valueFactory will be backed by the wrong temporary folder!
--- End diff --
Thanks, does that also work on static fields? I was trying to share the `Repository` to avoid excessive shutdown timeouts - but I guess with the fixed .stream() there might be less of those.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82422322
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRepositoryGraphLike.java ---
@@ -0,0 +1,80 @@
+/**
+ * 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.Optional;
+
+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.TripleLike;
+import org.apache.commons.rdf.rdf4j.RDF4JGraphLike;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+
+public abstract class AbstractRepositoryGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
+ implements RDF4JGraphLike<T> {
+
+ protected Repository repository;
+ protected boolean includeInferred;
+ protected boolean shouldWeShutdown = false;
+ protected RDF4JTermFactory rdf4jTermFactory;
+
+ public AbstractRepositoryGraphLike(Repository repository) {
+ this(repository, false);
+ }
+
+ public AbstractRepositoryGraphLike(Repository repository, boolean includeInferred) {
+ this.repository = repository;
+ this.includeInferred = includeInferred;
+ if (!repository.isInitialized()) {
+ repository.initialize();
+ shouldWeShutdown = true;
+ }
+ rdf4jTermFactory = new RDF4JTermFactory(repository.getValueFactory());
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (shouldWeShutdown) {
+ repository.shutDown();
+ }
+ // else: repository was initialized outside, so we should not shut it
+ // down
+ }
+
+
+ protected abstract T asTripleLike(Statement s);
+
+ protected RepositoryConnection getRepositoryConnection() {
+ return repository.getConnection();
+ }
+
+ public Optional<Repository> asRepository() {
+ return Optional.of(repository);
+ }
+
+ @Override
+ public Optional<Model> asModel() {
+ return Optional.empty();
--- End diff --
I added to the javadoc that at least one of them will not be empty.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by asfgit <gi...@git.apache.org>.
Github user asfgit closed the pull request at:
https://github.com/apache/incubator-commonsrdf/pull/24
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81655494
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraphLike.java ---
@@ -0,0 +1,63 @@
+/**
+ * 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;
+
+import java.util.Optional;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.GraphLike;
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.TripleLike;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * Marker interface for RDF4J implementations of GraphLike.
+ *
+ * @see RDF4JGraph
+ *
+ */
+public interface RDF4JGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
--- End diff --
Rather than naming those interfaces "TripleLike", it may be more useful to be upfront that Commons RDF is based on Generalised RDF by naming them GeneralisedTriple or similar. Ie, to support Jena as a lowest common denominator, the basic entity isn't an RDF-1.1 Triple but a Generalised Triple (assuming that means `<RDFTerm, RDFTerm, RDFTerm>` for the three positions but not familiar with Jena so not sure if the predicate is restricted to `BlankNodeOrIRI` or `IRI`).
One issue with potential uptake of Commons RDF in the community would be to make sure that users could structure their code to avoid the generics arguments that are unnecessary in almost all cases. Ie, if users know that their code cannot accept or deal with Generalised RDF, they should have a simple way of saying that in their APIs, leaving any conversion/reification to the small percentage of users who need Generalised RDF.
I am not yet clear on why `Triple` cannot inherit from `TripleLike<BlankNodeOrIRI, IRI, RDFTerm>`. Ie, I don't see why another heirarchy, for `RDFTripleLike`, needs to be created for the typical RDF user to work through rather than just subinterfacing Triple onto GeneralisedTriple with a different set of generics arguments.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81337946
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRepositoryGraphLike.java ---
@@ -0,0 +1,80 @@
+/**
+ * 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.Optional;
+
+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.TripleLike;
+import org.apache.commons.rdf.rdf4j.RDF4JGraphLike;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+
+public abstract class AbstractRepositoryGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
+ implements RDF4JGraphLike<T> {
+
+ protected Repository repository;
+ protected boolean includeInferred;
+ protected boolean shouldWeShutdown = false;
+ protected RDF4JTermFactory rdf4jTermFactory;
+
+ public AbstractRepositoryGraphLike(Repository repository) {
+ this(repository, false);
+ }
+
+ public AbstractRepositoryGraphLike(Repository repository, boolean includeInferred) {
+ this.repository = repository;
+ this.includeInferred = includeInferred;
+ if (!repository.isInitialized()) {
+ repository.initialize();
+ shouldWeShutdown = true;
+ }
+ rdf4jTermFactory = new RDF4JTermFactory(repository.getValueFactory());
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (shouldWeShutdown) {
+ repository.shutDown();
+ }
+ // else: repository was initialized outside, so we should not shut it
+ // down
+ }
+
+
+ protected abstract T asTripleLike(Statement s);
+
+ protected RepositoryConnection getRepositoryConnection() {
+ return repository.getConnection();
+ }
+
+ public Optional<Repository> asRepository() {
--- End diff --
getRepositoryConnection() is empty in `ModelGraphImpl` - should that instead make a new "Model" repository connection?
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81590241
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java ---
@@ -0,0 +1,164 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+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.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements Graph, RDF4JGraph {
+
+ private final Resource[] contextFilter;
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, boolean unionGraph) {
+ super(repository, includeInferred);
+ if (unionGraph) {
+ // no context filter aka any context
+ this.contextFilter = new Resource[] { };
+ } else {
+ // default context: null
+ this.contextFilter = new Resource[] { null };
+ }
+ }
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, Resource... contextFilter) {
+ super(repository, includeInferred);
+ this.contextFilter = contextFilter;
+ }
+
+
+ @Override
+ public void add(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement, contextFilter);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred, contextFilter);
+ }
+ }
+
+ @Override
+ public void remove(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement, contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear(contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ if (! includeInferred && contextFilter.length == 0) {
+ return conn.size();
+ } else {
+ return stream().count();
+ }
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contextFilter);
+ }
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream() {
+ return stream(null, null, null);
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ RepositoryConnection conn = getRepositoryConnection();
+ // FIXME: Is it OK that we don't close the connection?
+ RepositoryResult<Statement> statements = conn.getStatements(subj, pred, obj, includeInferred, contextFilter);
+ return Iterations.stream(statements).map(this::asTripleLike);
+ }
+
+ @Override
+ protected RDF4JTriple asTripleLike(Statement statement) {
+ return rdf4jTermFactory.asTriple(statement);
+ }
+
+ public Optional<Resource[]> getContextFilter() {
+ // Make sure we clone
+ return Optional.ofNullable(contextFilter).map(f -> f.clone());
--- End diff --
Agreed it can't be null. I've changed it to a `Set<RDF4JBlankNodeOrIRI>`:
```java
public interface RDF4JGraph extends Graph, RDF4JGraphLike<Triple> {
public Set<RDF4JBlankNodeOrIRI<Resource>> getContextMask();
}
```
Just a `Set<BlankNodeOrIRI>` would look neater, but then it's trickier to get to the `Resource`.
Not sure if a convenience method for exposing (or converting) to `Resource[]` would be good, I only needed it [here in RDF4JParser](https://github.com/apache/incubator-commonsrdf/blob/cd368d5889593dfe21b13123258b1145234a4687/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java#L186)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81340583
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java ---
@@ -0,0 +1,134 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+public final class ModelGraphImpl implements RDF4JGraph {
+
+ private Model model;
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ public ModelGraphImpl(Model model) {
+ this.model = model;
+ this.rdf4jTermFactory = new RDF4JTermFactory();
+ }
+
+ public ModelGraphImpl(Model model, RDF4JTermFactory rdf4jTermFactory) {
+ this.model = model;
+ this.rdf4jTermFactory = rdf4jTermFactory;
+ }
+
+ @Override
+ public void add(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.add(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void add(Triple triple) {
+ model.add(rdf4jTermFactory.asStatement(triple));
+ }
+
+ public Optional<Model> asModel() {
+ return Optional.of(model);
+ }
+
+ @Override
+ public Optional<Repository> asRepository() {
+ return Optional.empty();
+ }
+
+ @Override
+ public void clear() {
+ model.clear();
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.contains(
--- End diff --
The [integration test](https://github.com/apache/incubator-commonsrdf/blob/jena-jsonld-rdf4j-integration/integration-tests/src/test/java/org/apache/commons/rdf/integrationtests/AllToAllTest.java) try to add foreign blank nodes and then check that they are in `contains()` - which seem to work in all combinations (e.g. jenafactory to rdf4j graph and vice versa).
(that did however uncover a bug in `simple.GraphImpl.contains(Triple)` in this regard)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf issue #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on the issue:
https://github.com/apache/incubator-commonsrdf/pull/24
In order to close the `RepositoryConnection` (and `RepositoryResult`) I added an interface
``` java
public interface ClosableIterable<T> extends java.util.Iterable<T>, AutoCloseable { }
```
which is not very different from RDF4J's `org.eclipse.rdf4j.common.iteration.CloseableIteration` and `CloseableIterationIterator`; but can be used like this:
```java
RDF4JGraph graph; // ..
try (ClosableIterable<Triple> triples : graph.iterate()) {
for (Triple t : triples) {
return t; // OK to terminate for-loop early
}
}
```
It will then close both the `RepositoryResult` and `RepositoryConnection`.
It also closes on the last `.hasNext()` - but that is for convenience only for interoperability with `Graph.iterate()` interface, and would not happen if you break out of the for loop return early (as above).
The only other alternatives to provide a somewhat transparent .iterate() with RDF4J (without the caller having to do say `.begin()` and `.end()`) I can think of would be either a `.finalize()` in the Iterator (but you won't know if/when it will run) and to consume the whole of the iteration in memory and expose a normal java.util.List iterator (which would consume lots of memory and fall over after 2G entries).
Of course interoperability is already somewhat broken with my proposal here as the other `Graph.iterate()` are not (now) ClosableIterable and thus can't be used with the try-with-resources block like that.
I updated `org.apache.commons.rdf.api.AbstractGraphTest` to avoid the RDF4J tests taking a long time (20s timeout pr test if the repository has unclosed connections). For the `.stream()` this was easy (`Stream` implements `AutoClosable`), but for the `Iterable` I had to do:
```java
private void closeIterable(Iterable<Triple> iterate) throws Exception {
if (iterate instanceof AutoCloseable) {
((AutoCloseable) iterate).close();
}
}
```
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81368145
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRepositoryGraphLike.java ---
@@ -0,0 +1,80 @@
+/**
+ * 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.Optional;
+
+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.TripleLike;
+import org.apache.commons.rdf.rdf4j.RDF4JGraphLike;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+
+public abstract class AbstractRepositoryGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
+ implements RDF4JGraphLike<T> {
+
+ protected Repository repository;
+ protected boolean includeInferred;
+ protected boolean shouldWeShutdown = false;
+ protected RDF4JTermFactory rdf4jTermFactory;
+
+ public AbstractRepositoryGraphLike(Repository repository) {
+ this(repository, false);
+ }
+
+ public AbstractRepositoryGraphLike(Repository repository, boolean includeInferred) {
+ this.repository = repository;
+ this.includeInferred = includeInferred;
+ if (!repository.isInitialized()) {
+ repository.initialize();
+ shouldWeShutdown = true;
+ }
+ rdf4jTermFactory = new RDF4JTermFactory(repository.getValueFactory());
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (shouldWeShutdown) {
+ repository.shutDown();
+ }
+ // else: repository was initialized outside, so we should not shut it
+ // down
+ }
+
+
+ protected abstract T asTripleLike(Statement s);
+
+ protected RepositoryConnection getRepositoryConnection() {
+ return repository.getConnection();
+ }
+
+ public Optional<Repository> asRepository() {
+ return Optional.of(repository);
+ }
+
+ @Override
+ public Optional<Model> asModel() {
+ return Optional.empty();
--- End diff --
I tried changing `asModel()` and `asGraph()` to `throw new UnsupportedOperationException()` - but it meant already in the RDF4JParser it breaks:
```java
RDF4JDataset dataset = (RDF4JDataset) getTargetDataset().get();
if (dataset.asRepository().isPresent()) {
return new RDFInserter(dataset.asRepository().get().getConnection());
}
if (dataset.asModel().isPresent()) {
Model model = dataset.asModel().get();
return new AddToModel(model);
}
```
which would then turn into a double [coding by exception](https://en.wikipedia.org/wiki/Coding_by_exception) anti-pattern with a `return` from inside `catch` ..
So I'm inclined to keep these as `Optional`.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81254829
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRepositoryGraphLike.java ---
@@ -0,0 +1,80 @@
+/**
+ * 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.Optional;
+
+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.TripleLike;
+import org.apache.commons.rdf.rdf4j.RDF4JGraphLike;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+
+public abstract class AbstractRepositoryGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
+ implements RDF4JGraphLike<T> {
+
+ protected Repository repository;
+ protected boolean includeInferred;
+ protected boolean shouldWeShutdown = false;
+ protected RDF4JTermFactory rdf4jTermFactory;
+
+ public AbstractRepositoryGraphLike(Repository repository) {
+ this(repository, false);
+ }
+
+ public AbstractRepositoryGraphLike(Repository repository, boolean includeInferred) {
+ this.repository = repository;
+ this.includeInferred = includeInferred;
+ if (!repository.isInitialized()) {
--- End diff --
This corner case doesn't seem to be necessary. The RDF4J contract specifies that the user needs to call this method themselves so you can remove the complexity here based on that.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81457208
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JIRI.java ---
@@ -0,0 +1,35 @@
+/**
+ * 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;
+
+/**
+ * Marker interface for RDF4J implementations of IRI.
+ *
+ */
+public interface RDF4JIRI
+ extends RDF4JTerm<org.eclipse.rdf4j.model.IRI>, org.apache.commons.rdf.api.IRI {
+
+ /**
+ * Return the corresponding RDF4J {@link org.eclipse.rdf4j.model.IRI}.
+ *
+ * @return The corresponding RDF4J IRI
+ */
+ public org.eclipse.rdf4j.model.IRI asValue();
--- End diff --
I removed the null-overrides and instead clarified the specialized generic parameter in the interface javadoc.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81657616
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
--- End diff --
I would prefer if `RDFTermFactory` objects were passed around rather than the comparatively brittle `UUID`. As long as `RDFTermFactory` objects are `Serializable`, the `UUID` should be able to be transparently persisted across distribution.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81668781
--- Diff: rdf4j/src/test/java/org/apache/commons/rdf/rdf4j/Rdf4JRDFTermFactoryTest.java ---
@@ -0,0 +1,37 @@
+/**
+ * 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;
+
+import org.apache.commons.rdf.api.AbstractRDFTermFactoryTest;
+import org.apache.commons.rdf.api.RDFTermFactory;
+import org.junit.Assume;
+
+public class Rdf4JRDFTermFactoryTest extends AbstractRDFTermFactoryTest {
+
+ @Override
+ public RDFTermFactory createFactory() {
+ return new RDF4JTermFactory();
+ }
+
+ @Override
+ public void testInvalidLiteralLang() throws Exception {
+ Assume.assumeTrue("Sesame doesn't check Lang strings",false);
--- End diff --
You can setup individual RDFParsers to check for invalid language strings using ParserConfig, but no, ValueFactory doesn't currently check for invalid language strings per its lenience in general for different types of data.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81332847
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ *
+ * @see #asQuad(Statement)
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public static RDF4JQuad asQuad(final Statement statement, UUID salt) {
+ return new QuadImpl(statement, salt);
+ }
+
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @param value The RDF4J {@link Value} to convert.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException if the value is not a BNode, Literal or IRI
+ */
+ public <T extends Value> RDF4JTerm<T> asRDFTerm(T value) {
+ return asRDFTerm(value, salt);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository) {
+ return new RepositoryDatasetImpl(repository);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred quads are included in the dataset
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository, boolean includeInferred) {
+ return new RepositoryDatasetImpl(repository, includeInferred);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}.
+ * <p>
+ * Changes to the graph are reflected in the model, and vice versa.
+ *
+ * @param model
+ * RDF4J {@link Model} to adapt.
+ * @return Adapted {@link Graph}.
+ */
+ public RDF4JGraph asRDFTermGraph(Model model) {
+ return new ModelGraphImpl(model);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository) {
+ return new RepositoryGraphImpl(repository, false, true);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred triples are included in the graph
+ * @param unionGraph
+ * If true, triples from any context is included in the graph,
+ * otherwise only triples in the default context
+ * <code>null</code>.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, boolean unionGraph) {
--- End diff --
Shall we call the boolean `anyContext` instead to be closer to RDF4J? This is after all dealing with an RDF4J `Repository`.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82311598
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java ---
@@ -0,0 +1,232 @@
+/**
+ * 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.experimental;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFSyntax;
+import org.apache.commons.rdf.experimental.RDFParser;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNodeOrIRI;
+import org.apache.commons.rdf.rdf4j.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.simple.experimental.AbstractRDFParser;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.util.RDFInserter;
+import org.eclipse.rdf4j.repository.util.RDFLoader;
+import org.eclipse.rdf4j.rio.ParserConfig;
+import org.eclipse.rdf4j.rio.RDFFormat;
+import org.eclipse.rdf4j.rio.RDFHandler;
+import org.eclipse.rdf4j.rio.RDFHandlerException;
+import org.eclipse.rdf4j.rio.Rio;
+import org.eclipse.rdf4j.rio.helpers.AbstractRDFHandler;
+
+/**
+ * RDF4J-based parser.
+ * <p>
+ * This can handle the RDF syntaxes {@link RDFSyntax#JSONLD},
+ * {@link RDFSyntax#NQUADS}, {@link RDFSyntax#NTRIPLES},
+ * {@link RDFSyntax#RDFXML}, {@link RDFSyntax#TRIG} and {@link RDFSyntax#TURTLE}
+ * - additional syntaxes can be supported by including the corresponding
+ * <em>rdf4j-rio-*</em> module on the classpath.
+ *
+ */
+public class RDF4JParser extends AbstractRDFParser<RDF4JParser> implements RDFParser {
+
+ private final class AddToQuadConsumer extends AbstractRDFHandler {
+ private final Consumer<Quad> quadTarget;
+
+ private AddToQuadConsumer(Consumer<Quad> quadTarget) {
+ this.quadTarget = quadTarget;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ // TODO: if getRdfTermFactory() is a non-rdf4j factory, should
+ // we use factory.createQuad() instead?
+ // Unsure what is the promise of setting getRdfTermFactory() --
+ // does it go all the way down to creating BlankNode, IRI and
+ // Literal?
+ quadTarget.accept(rdf4jTermFactory.asQuad(st));
+ // Performance note:
+ // Graph/Quad.add should pick up again our
+ // RDF4JGraphLike.asStatement()
+ // and avoid double conversion.
+ // Additionally the RDF4JQuad and RDF4JTriple implementations
+ // are lazily converting subj/obj/pred/graph.s
+ }
+ }
+
+ private final static class AddToModel extends AbstractRDFHandler {
+ private final Model model;
+
+ public AddToModel(Model model) {
+ this.model = model;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ model.add(st);
+ }
+
+ @Override
+ public void handleNamespace(String prefix, String uri) throws RDFHandlerException {
+ model.setNamespace(prefix, uri);
+ }
+ }
+
+ private RDF4JTermFactory rdf4jTermFactory;
+ private ParserConfig parserConfig = new ParserConfig();
+
+ @Override
+ protected RDF4JTermFactory createRDFTermFactory() {
+ return new RDF4JTermFactory();
+ }
+
+ @Override
+ protected RDF4JParser prepareForParsing() throws IOException, IllegalStateException {
+ RDF4JParser c = prepareForParsing();
+ // Ensure we have an RDF4JTermFactory for conversion.
+ // We'll make a new one if user has provided a non-RDF4J factory
+ c.rdf4jTermFactory = (RDF4JTermFactory) getRdfTermFactory().filter(RDF4JTermFactory.class::isInstance)
--- End diff --
It is unclear how this pattern would actually help users or have any effect at all. Given that there are no constructors for this class, it isn't clear why getRdfTermFactory would return anything relevant to this class at all, so it must always in usual runtimes (without relying on brittle reflection based methods) go through to the orElseGet and create a new factory here.
It also isn't clear why there is an instance variable here that may be duplicating or interacting with another factory in a superclass or subclass somewhere. That will create the ability for some really difficult bugs to pop up that shouldn't be allowed in a strong design.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf issue #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on the issue:
https://github.com/apache/incubator-commonsrdf/pull/24
Adding CloseableIterable just to RDF4J integration module will not help interoperability, as code will actually need to be rewritten to switch to another implementation due to the restrictions on how try-with-resources accepts inputs. If you want that part to work transparently you will need to implement it in the base Commons RDF API.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81260651
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java ---
@@ -0,0 +1,164 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+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.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements Graph, RDF4JGraph {
+
+ private final Resource[] contextFilter;
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, boolean unionGraph) {
+ super(repository, includeInferred);
+ if (unionGraph) {
+ // no context filter aka any context
+ this.contextFilter = new Resource[] { };
+ } else {
+ // default context: null
+ this.contextFilter = new Resource[] { null };
+ }
+ }
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, Resource... contextFilter) {
+ super(repository, includeInferred);
+ this.contextFilter = contextFilter;
+ }
+
+
+ @Override
+ public void add(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement, contextFilter);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred, contextFilter);
+ }
+ }
+
+ @Override
+ public void remove(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement, contextFilter);
+ conn.commit();
--- End diff --
Ditto for comment earlier about committing after removing a single triple. Is it possible to optimise this at all?
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81667185
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java ---
@@ -0,0 +1,192 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JQuad;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryDatasetImpl extends AbstractRepositoryGraphLike<Quad> implements RDF4JDataset, Dataset {
+
+ public RepositoryDatasetImpl(Repository repository, boolean includeInferred) {
+ super(repository, includeInferred);
+ }
+
+ public RepositoryDatasetImpl(Repository repository) {
+ super(repository);
+ }
+
+
+ @Override
+ public void add(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred);
+ }
+ }
+
+ @Override
+ public void remove(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear();
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ if (includeInferred) {
+ // We'll need to count them all
+ return stream().count();
+ }
+ // else: Ask directly
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.size();
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ Resource context = (Resource) rdf4jTermFactory.asValue(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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, context);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contexts);
+ }
+ }
+
+ private Resource[] asContexts(Optional<BlankNodeOrIRI> graphName) {
+ Resource[] contexts;
+ if (graphName == null) {
+ // no contexts == any contexts
+ contexts = new Resource[0];
+ } else {
+ BlankNodeOrIRI g = graphName.orElse(null);
+ Resource context = (Resource) rdf4jTermFactory.asValue(g);
+ contexts = new Resource[] { context };
+ }
+ return contexts;
+ }
+
+ @Override
+ public void remove(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contexts);
+ conn.commit();
--- End diff --
I am not sure how to do it efficiently without explicit begin/end in the Graph/Dataset model. However, as it stands, this method will not be useful for any but the most trivial cases, given the potential overhead for commit each time so it needs work to get into circulation.
If you added begin/end then you could also optimise to reduce the number of calls to getRepositoryConnection that may be resource or time intensive depending on the Repository implementation.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81658617
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ *
+ * @see #asQuad(Statement)
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public static RDF4JQuad asQuad(final Statement statement, UUID salt) {
+ return new QuadImpl(statement, salt);
+ }
+
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @param value The RDF4J {@link Value} to convert.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException if the value is not a BNode, Literal or IRI
+ */
+ public <T extends Value> RDF4JTerm<T> asRDFTerm(T value) {
+ return asRDFTerm(value, salt);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository) {
+ return new RepositoryDatasetImpl(repository);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred quads are included in the dataset
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository, boolean includeInferred) {
+ return new RepositoryDatasetImpl(repository, includeInferred);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}.
+ * <p>
+ * Changes to the graph are reflected in the model, and vice versa.
+ *
+ * @param model
+ * RDF4J {@link Model} to adapt.
+ * @return Adapted {@link Graph}.
+ */
+ public RDF4JGraph asRDFTermGraph(Model model) {
+ return new ModelGraphImpl(model);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository) {
+ return new RepositoryGraphImpl(repository, false, true);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred triples are included in the graph
+ * @param unionGraph
+ * If true, triples from any context is included in the graph,
+ * otherwise only triples in the default context
+ * <code>null</code>.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, boolean unionGraph) {
--- End diff --
The biggest issue with naming a boolean is that there are four cases able to be supported by the varargs version, and only two cases able to be supported by the boolean. The boolean supports
1. "match regardless of context", and;
2. "match only default context"
, while the varargs supports
1. "match regardless of context" (empty Resource array), and;
2. "match only default context" (Resource array with a single null element), and;
3. "match specific context" (Resource array with a single non-null element), and;
4. "match specific and possibly default contexts" (Resource array with more than one element, one of which can be null to match the default context also)
The name "unionGraph" is fairly clear with its positive case (ie, case 1 above), but it doesn't indicate immediately what its negative case will be, as from an RDF4J user perspective, they are used to having to distinguish between case 2 and 3 and it isn't clear which one would be chosen just from the signature.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81339793
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/IRIImpl.java ---
@@ -0,0 +1,61 @@
+/**
+ * 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 org.apache.commons.rdf.rdf4j.RDF4JIRI;
+
+public final class IRIImpl extends AbstractRDFTerm<org.eclipse.rdf4j.model.IRI>
+ implements RDF4JIRI {
+
+ public IRIImpl(org.eclipse.rdf4j.model.IRI iri) {
+ super(iri);
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) { return true; }
+ if (obj instanceof IRIImpl) {
+ IRIImpl impl = (IRIImpl) obj;
+ return asValue().equals(impl.asValue());
+ }
+ if (obj instanceof org.apache.commons.rdf.api.IRI) {
+ org.apache.commons.rdf.api.IRI iri = (org.apache.commons.rdf.api.IRI) obj;
+ return value.toString().equals(iri.getIRIString());
+ }
+ return false;
+ }
+
+ @Override
+ public String getIRIString() {
+ return value.toString();
+ }
+
+ public int hashCode() {
+ // Same definition
+ return value.hashCode();
+ }
+
+ @Override
+ public String ntriplesString() {
+ return "<" + value.toString() + ">";
--- End diff --
`>` is not a [valid IRI character](https://tools.ietf.org/html/rfc3987#section-2.2) - I don't know if RDF4J enforces this outside parsers but thought it could be used "as is".
However [org.eclipse.rdf4j.model.IRI.toString()](http://rdf4j.org/javadoc/2.0/org/eclipse/rdf4j/model/IRI.html#toString--) is not very strict in what it defines as the "string representation" - is it safe to use, or should that javadoc be improved or an equivalent of a stronger `getIRIString()` be added to RDF4J?
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81338387
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/BlankNodeImpl.java ---
@@ -0,0 +1,93 @@
+/**
+ * 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.nio.charset.StandardCharsets;
+import java.util.UUID;
+
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNode;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.rio.turtle.TurtleUtil;
+
+public final class BlankNodeImpl extends AbstractRDFTerm<BNode>
+ implements RDF4JBlankNode {
+
+ private transient int hashCode = 0;
+ private long saltUUIDleast;
+ private long saltUUIDmost;
+
+ public BlankNodeImpl(BNode bNode, UUID salt) {
+ super(bNode);
+ // Space-efficient storage of salt UUID
+ saltUUIDmost = salt.getMostSignificantBits();
+ saltUUIDleast = salt.getLeastSignificantBits();
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ // NOTE: Do NOT use Bnode.equals() as it has a more generous
+ // equality based only on the value.getID();
+ if (obj instanceof BlankNode) {
+ BlankNode blankNode = (BlankNode) obj;
+ return uniqueReference().equals(blankNode.uniqueReference());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ if (hashCode != 0) {
+ return hashCode;
+ }
+ return hashCode = uniqueReference().hashCode();
+ }
+
+ private boolean isValidBlankNodeLabel(String id) {
+ // FIXME: Replace with a regular expression?
--- End diff --
Agree - that would also remove a necessary dependency on `rdf4j-rio-turtle`.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82313578
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,603 @@
+/**
+ * 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;
+
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI, Literal)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.InternalRDF4JFactory;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.sail.SailRepository;
+import org.eclipse.rdf4j.sail.Sail;
+import org.eclipse.rdf4j.sail.memory.MemoryStore;
+
+/**
+ * RDF4J implementation of RDFTermFactory.
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally.
+ *
+ */
+public final class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * InternalRDF4JFactory is deliberately abstract
+ */
+ private static InternalRDF4JFactory rdf4j = new InternalRDF4JFactory() {
+ };
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) rdf4j.createBlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) rdf4j.createLiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) rdf4j.createIRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ private final UUID salt;
+
+ private final ValueFactory valueFactory;
+
+ /**
+ * Construct an {@link RDF4JTermFactory}.
+ *
+ */
+ public RDF4JTermFactory() {
+ this(SimpleValueFactory.getInstance(), UUID.randomUUID());
+ }
+
+ /**
+ * Construct an {@link RDF4JTermFactory}.
+ * <p>
+ * This constructor is intended for use with the value factory from
+ * {@link Repository#getValueFactory()} when using
+ * Repository-based graphs and datasets.
+ *
+ * @param valueFactory
+ * The RDF4J {@link ValueFactory} to use
+ */
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this(valueFactory, UUID.randomUUID());
+ }
+
+ /**
+ * Construct an {@link RDF4JTermFactory}.
+ * <p>
+ * This constructor may be used if reproducible
+ * {@link BlankNode#uniqueReference()} in {@link BlankNode} is desirable.
+ *
+ * @param salt
+ * An {@link UUID} salt to be used by any created
+ * {@link BlankNode}s for the purpose of
+ * {@link BlankNode#uniqueReference()}
+ */
+ public RDF4JTermFactory(UUID salt) {
+ this(SimpleValueFactory.getInstance(), salt);
+ }
+ /**
+ * Construct an {@link RDF4JTermFactory}.
+ * <p>
+ * This constructor may be used if reproducible
+ * {@link BlankNode#uniqueReference()} in {@link BlankNode} is desirable.
+ *
+ * @param valueFactory
+ * The RDF4J {@link ValueFactory} to use
+ * @param salt
+ * An {@link UUID} salt to be used by any created
+ * {@link BlankNode}s for the purpose of
+ * {@link BlankNode#uniqueReference()}
+ */
+ public RDF4JTermFactory(ValueFactory valueFactory, UUID salt) {
+ this.valueFactory = valueFactory;
+ this.salt = salt;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this method will use an
+ * internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s multiple
+ * repositories or models, then their {@link BNode}s may have the same
+ * {@link BNode#getID()}, which with this method would become equivalent
+ * according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()}, unless a separate
+ * {@link RDF4JTermFactory} instance is used per RDF4J repository/model.
+ *
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return rdf4j.createQuadImpl(statement, salt);
+ }
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this method will use an
+ * internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from multiple
--- End diff --
Remove this and retain the paragraph above, for reasons detailed in previous comment.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81253817
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ *
+ * @see #asQuad(Statement)
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public static RDF4JQuad asQuad(final Statement statement, UUID salt) {
+ return new QuadImpl(statement, salt);
+ }
+
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @param value The RDF4J {@link Value} to convert.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException if the value is not a BNode, Literal or IRI
+ */
+ public <T extends Value> RDF4JTerm<T> asRDFTerm(T value) {
+ return asRDFTerm(value, salt);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository) {
+ return new RepositoryDatasetImpl(repository);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred quads are included in the dataset
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository, boolean includeInferred) {
+ return new RepositoryDatasetImpl(repository, includeInferred);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}.
+ * <p>
+ * Changes to the graph are reflected in the model, and vice versa.
+ *
+ * @param model
+ * RDF4J {@link Model} to adapt.
+ * @return Adapted {@link Graph}.
+ */
+ public RDF4JGraph asRDFTermGraph(Model model) {
+ return new ModelGraphImpl(model);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository) {
+ return new RepositoryGraphImpl(repository, false, true);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred triples are included in the graph
+ * @param unionGraph
+ * If true, triples from any context is included in the graph,
+ * otherwise only triples in the default context
+ * <code>null</code>.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, boolean unionGraph) {
+ return new RepositoryGraphImpl(repository, includeInferred, unionGraph);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link Triple} or {@link Quad} as a RDF4J
+ * {@link Statement}.
+ * <p>
+ * If the <code>tripleLike</code> argument is an {@link RDF4JTriple} or
+ * a {@link RDF4JQuad}, then its {@link RDF4JTripleLike#asStatement()} is
+ * returned as-is. Note that this means that a {@link RDF4JTriple} would
+ * preserve its {@link Statement#getContext()}, and that any
+ * {@link BlankNode}s would be deemed equivalent in RDF4J
+ * if they have the same {@link BNode#getID()}.
+ *
+ * @param tripleLike
+ * A {@link Triple} or {@link Quad} to adapt
+ * @return A corresponding {@link Statement}
+ */
+ public Statement asStatement(TripleLike<BlankNodeOrIRI, org.apache.commons.rdf.api.IRI, RDFTerm> tripleLike) {
+ if (tripleLike instanceof RDF4JTripleLike) {
+ // Return original statement - this covers both RDF4JQuad and
+ // RDF4JTriple
+ RDF4JTripleLike rdf4jTriple = (RDF4JTripleLike) tripleLike;
+ return rdf4jTriple.asStatement();
+ }
+
+ org.eclipse.rdf4j.model.Resource subject = (org.eclipse.rdf4j.model.Resource) asValue(tripleLike.getSubject());
+ org.eclipse.rdf4j.model.IRI predicate = (org.eclipse.rdf4j.model.IRI) asValue(tripleLike.getPredicate());
+ Value object = asValue(tripleLike.getObject());
+
+ org.eclipse.rdf4j.model.Resource context = null;
+ if (tripleLike instanceof Quad) {
+ Quad quad = (Quad) tripleLike;
+ context = (org.eclipse.rdf4j.model.Resource) asValue(quad.getGraphName().orElse(null));
+ }
+
+ return getValueFactory().createStatement(subject, predicate, object, context);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this method will use an
+ * internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J statements from multiple
+ * repositories or models, then their {@link BNode}s may have the same
+ * {@link BNode#getID()}, which with this method would become equivalent
+ * according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()}, unless a separate
+ * {@link RDF4JTermFactory} instance is used per RDF4J repository/model.
+ *
+ * @param statement
+ * The RDF4J {@link Statement} to adapt.
+ * @return A {@link RDF4JTriple} that is equivalent to the statement
+ */
+ public RDF4JTriple asTriple(final Statement statement) {
+ return new TripleImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link RDFTerm} as a RDF4J {@link Value}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.apache.commons.rdf.api.BlankNode} is converted to a
+ * {@link org.eclipse.rdf4j.model.BNode}, a
+ * {@link org.apache.commons.rdf.api.IRI} is converted to a
+ * {@link org.eclipse.rdf4j.model.IRI} and a
+ * {@link org.apache.commons.rdf.api.Literal} is converted to a
+ * {@link org.eclipse.rdf4j.model.Literal}.
+ * <p>
+ * If the provided {@link RDFTerm} is <code>null</code>, then the returned
+ * value is <code>null</code>.
+ * <p>
+ * If the provided term is an instance of {@link RDF4JTerm}, then the
+ * {@link RDF4JTerm#asValue()} is returned without any conversion. Note that
+ * this could mean that a {@link Value} from a different kind of
+ * {@link ValueFactory} could be returned.
+ *
+ * @param term
+ * RDFTerm to adapt to RDF4J Value
+ * @return Adapted RDF4J {@link Value}
+ */
+ public Value asValue(RDFTerm term) {
+ if (term == null) {
+ return null;
+ }
+ if (term instanceof RDF4JTerm) {
+ // One of our own - avoid converting again.
+ // (This is crucial to avoid double-escaping in BlankNode)
+ return ((RDF4JTerm<?>) term).asValue();
+ }
+ if (term instanceof org.apache.commons.rdf.api.IRI) {
+ org.apache.commons.rdf.api.IRI iri = (org.apache.commons.rdf.api.IRI) term;
+ return getValueFactory().createIRI(iri.getIRIString());
+ }
+ if (term instanceof org.apache.commons.rdf.api.Literal) {
+ org.apache.commons.rdf.api.Literal literal = (org.apache.commons.rdf.api.Literal) term;
+ String label = literal.getLexicalForm();
+ if (literal.getLanguageTag().isPresent()) {
+ String lang = literal.getLanguageTag().get();
+ return getValueFactory().createLiteral(label, lang);
+ }
+ org.eclipse.rdf4j.model.IRI dataType = (org.eclipse.rdf4j.model.IRI) asValue(literal.getDatatype());
+ return getValueFactory().createLiteral(label, dataType);
+ }
+ if (term instanceof BlankNode) {
+ // This is where it gets tricky to support round trips!
--- End diff --
Round tripping back to RDF4J after this conversion is not possible in general. The best you can hope for is to consistently pass BlankNodes/BNodes across in each direction, which this seems to do as long as getValueFactory() returns the same value for all of the blank nodes you are passing through.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81260462
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java ---
@@ -0,0 +1,192 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JQuad;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryDatasetImpl extends AbstractRepositoryGraphLike<Quad> implements RDF4JDataset, Dataset {
+
+ public RepositoryDatasetImpl(Repository repository, boolean includeInferred) {
+ super(repository, includeInferred);
+ }
+
+ public RepositoryDatasetImpl(Repository repository) {
+ super(repository);
+ }
+
+
+ @Override
+ public void add(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred);
+ }
+ }
+
+ @Override
+ public void remove(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear();
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ if (includeInferred) {
+ // We'll need to count them all
+ return stream().count();
+ }
+ // else: Ask directly
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.size();
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ Resource context = (Resource) rdf4jTermFactory.asValue(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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, context);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contexts);
+ }
+ }
+
+ private Resource[] asContexts(Optional<BlankNodeOrIRI> graphName) {
+ Resource[] contexts;
+ if (graphName == null) {
+ // no contexts == any contexts
+ contexts = new Resource[0];
+ } else {
+ BlankNodeOrIRI g = graphName.orElse(null);
+ Resource context = (Resource) rdf4jTermFactory.asValue(g);
+ contexts = new Resource[] { context };
+ }
+ return contexts;
+ }
+
+ @Override
+ public void remove(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contexts);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JQuad> stream() {
+ return stream(null, null, null, null);
+ }
+
+ @Override
+ public Stream<RDF4JQuad> stream(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ RepositoryConnection conn = getRepositoryConnection();
+ // NOTE: connection will be closed outside by the Iterations.stream()
+ RepositoryResult<Statement> statements = conn.getStatements(subj, pred, obj, includeInferred, contexts);
+ return Iterations.stream(statements).map(this::asTripleLike);
+ }
+
+ @Override
+ protected RDF4JQuad asTripleLike(Statement s) {
+ return rdf4jTermFactory.asQuad(s);
+ }
+
+ @Override
+ public Graph getGraph() {
+ // default context only
+ return new RepositoryGraphImpl(repository, includeInferred, (Resource)null);
+ }
+
+ @Override
+ public Optional<Graph> getGraph(BlankNodeOrIRI graphName) {
+ // NOTE: May be null to indicate default context
+ Resource context = (Resource) rdf4jTermFactory.asValue(graphName);
+ return Optional.of(new RepositoryGraphImpl(repository, includeInferred, context));
+ }
+
+ @Override
+ public Stream<BlankNodeOrIRI> getGraphNames() {
+ RepositoryConnection conn = getRepositoryConnection();
+ RepositoryResult<Resource> contexts = conn.getContextIDs();
--- End diff --
Ditto for reliably closing this RepositoryResult object.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf issue #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on the issue:
https://github.com/apache/incubator-commonsrdf/pull/24
Thanks for the great and thorough review, @ansell! I think this helped get a better shape of the interfaces.
I used some of the feedback also on the `jena` module, which now also reduced most of the `UUID` exposure.
RDF4J is interesting because of the difference in semantics around datasets - I think one value of Commons RDF is that we give a (hopefully) unified view of semantics between the implementations - and then of course users can "upgrade" to native RDF4J if they want other semantics or more functionalities.
I'll raise in Jira the remaining issues I am afraid I don't have time to look at right now, and go ahead to merge this to `master`.
Once merged we can see if we can normalize the converter method names between the factories.
Then add the integration tests, and roll for a `0.3.0-incubating` release.
Cheers!
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82313253
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,603 @@
+/**
+ * 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;
+
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI, Literal)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.InternalRDF4JFactory;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.sail.SailRepository;
+import org.eclipse.rdf4j.sail.Sail;
+import org.eclipse.rdf4j.sail.memory.MemoryStore;
+
+/**
+ * RDF4J implementation of RDFTermFactory.
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally.
+ *
+ */
+public final class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * InternalRDF4JFactory is deliberately abstract
+ */
+ private static InternalRDF4JFactory rdf4j = new InternalRDF4JFactory() {
+ };
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) rdf4j.createBlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) rdf4j.createLiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) rdf4j.createIRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ private final UUID salt;
+
+ private final ValueFactory valueFactory;
+
+ /**
+ * Construct an {@link RDF4JTermFactory}.
+ *
+ */
+ public RDF4JTermFactory() {
+ this(SimpleValueFactory.getInstance(), UUID.randomUUID());
+ }
+
+ /**
+ * Construct an {@link RDF4JTermFactory}.
+ * <p>
+ * This constructor is intended for use with the value factory from
+ * {@link Repository#getValueFactory()} when using
+ * Repository-based graphs and datasets.
+ *
+ * @param valueFactory
+ * The RDF4J {@link ValueFactory} to use
+ */
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this(valueFactory, UUID.randomUUID());
+ }
+
+ /**
+ * Construct an {@link RDF4JTermFactory}.
+ * <p>
+ * This constructor may be used if reproducible
+ * {@link BlankNode#uniqueReference()} in {@link BlankNode} is desirable.
+ *
+ * @param salt
+ * An {@link UUID} salt to be used by any created
+ * {@link BlankNode}s for the purpose of
--- End diff --
This javadoc needs to be enhanced. The uniqueReference method is just a variable access. The key is actually in the equals contract.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81454827
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java ---
@@ -0,0 +1,66 @@
+/**
+ * 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;
+
+import java.util.Optional;
+
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+
+/**
+ * Marker interface for RDF4J implementations of Graph.
+ *
+ * @see ModelGraphImpl
+ * @see RepositoryGraphImpl
+ */
+public interface RDF4JGraph extends Graph, RDF4JGraphLike<Triple> {
+
+ /**
+ * Return a copy of the context filter, if present.
+ * <p>
+ * If {@link Optional#isPresent()}, the filter determines which
+ * <em>contexts</em> in the corresponding RDF4J {@link Model} or
+ * {@link Repository} that this graph reflect. Modifications to the graph
+ * (e.g. {@link #add(Triple)} will be performed for all the specified
+ * contexts, while retrieval (e.g. {@link #contains(Triple)}) will succeed
+ * if the triple is in at least one of the specified contexts.
+ * <p>
+ * The context filter array may contain <code>null</code>, indicating the
+ * default context (the <em>default graph</em> in RDF datasets).
+ * <p>
+ * If the context filter is {@link Optional#empty()}, then this is a
+ * <em>union graph</em> which triples reflecting statements in any contexts.
+ * Triples added to the graph will be added in the default context
+ * <code>null</code>.
--- End diff --
Should `RDF4JGraph.getContextFilter()` (or what we call it) return RDF4J `Resource` or Commons RDF `BlankNodeOrIRI` instances? (`Resource` is not exposed anywhere else in `RDF4JGraph`)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81335437
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java ---
@@ -0,0 +1,197 @@
+/**
+ * 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.experimental;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFSyntax;
+import org.apache.commons.rdf.experimental.RDFParser;
+import org.apache.commons.rdf.rdf4j.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.simple.experimental.AbstractRDFParser;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.repository.util.RDFInserter;
+import org.eclipse.rdf4j.repository.util.RDFLoader;
+import org.eclipse.rdf4j.rio.ParserConfig;
+import org.eclipse.rdf4j.rio.RDFFormat;
+import org.eclipse.rdf4j.rio.RDFHandler;
+import org.eclipse.rdf4j.rio.RDFHandlerException;
+import org.eclipse.rdf4j.rio.Rio;
+import org.eclipse.rdf4j.rio.helpers.AbstractRDFHandler;
+
+/**
+ * RDF4J-based parser.
+ * <p>
+ * This can handle the RDF syntaxes {@link RDFSyntax#JSONLD},
+ * {@link RDFSyntax#NQUADS}, {@link RDFSyntax#NTRIPLES},
+ * {@link RDFSyntax#RDFXML}, {@link RDFSyntax#TRIG} and {@link RDFSyntax#TURTLE}
+ * - additional syntaxes can be supported by including the corresponding
+ * <em>rdf4j-rio-*</em> module on the classpath.
+ *
+ */
+public class RDF4JParser extends AbstractRDFParser<RDF4JParser> implements RDFParser {
+
+ private final class AddToQuadConsumer extends AbstractRDFHandler {
+ private final Consumer<Quad> quadTarget;
+
+ private AddToQuadConsumer(Consumer<Quad> quadTarget) {
+ this.quadTarget = quadTarget;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ // TODO: if getRdfTermFactory() is a non-rdf4j factory, should
+ // we use factory.createQuad() instead?
+ // Unsure what is the promise of setting getRdfTermFactory() --
+ // does it go all the way down to creating BlankNode, IRI and
+ // Literal?
+ quadTarget.accept(rdf4jTermFactory.asQuad(st));
+ // Performance note:
+ // Graph/Quad.add should pick up again our
+ // RDF4JGraphLike.asStatement()
+ // and avoid double conversion.
+ // Additionally the RDF4JQuad and RDF4JTriple implementations
+ // are lazily converting subj/obj/pred/graph.s
+ }
+ }
+
+ private final static class AddToModel extends AbstractRDFHandler {
+ private final Model model;
+
+ public AddToModel(Model model) {
+ this.model = model;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ model.add(st);
+ }
+
+ @Override
+ public void handleNamespace(String prefix, String uri) throws RDFHandlerException {
+ model.setNamespace(prefix, uri);
+ }
+ }
+
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ @Override
+ protected RDF4JTermFactory createRDFTermFactory() {
+ return new RDF4JTermFactory();
+ }
+
+ @Override
+ protected RDF4JParser prepareForParsing() throws IOException, IllegalStateException {
+ RDF4JParser c = prepareForParsing();
+ // Ensure we have an RDF4JTermFactory for conversion.
+ // We'll make a new one if user has provided a non-RDF4J factory
+ c.rdf4jTermFactory = (RDF4JTermFactory) getRdfTermFactory().filter(RDF4JTermFactory.class::isInstance)
+ .orElseGet(c::createRDFTermFactory);
+ return c;
+ }
+
+ @Override
+ protected void parseSynchronusly() throws IOException {
+ Optional<RDFFormat> formatByMimeType = getContentType().flatMap(Rio::getParserFormatForMIMEType);
+ String base = getBase().map(IRI::getIRIString).orElse(null);
+
+ ParserConfig parserConfig = new ParserConfig();
+ // TODO: Should we need to set anything?
--- End diff --
Great, so I'll add `setParserConfig()` and `getParserConfig()`.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81337249
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRepositoryGraphLike.java ---
@@ -0,0 +1,80 @@
+/**
+ * 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.Optional;
+
+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.TripleLike;
+import org.apache.commons.rdf.rdf4j.RDF4JGraphLike;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+
+public abstract class AbstractRepositoryGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
+ implements RDF4JGraphLike<T> {
+
+ protected Repository repository;
+ protected boolean includeInferred;
+ protected boolean shouldWeShutdown = false;
+ protected RDF4JTermFactory rdf4jTermFactory;
+
+ public AbstractRepositoryGraphLike(Repository repository) {
+ this(repository, false);
+ }
+
+ public AbstractRepositoryGraphLike(Repository repository, boolean includeInferred) {
+ this.repository = repository;
+ this.includeInferred = includeInferred;
+ if (!repository.isInitialized()) {
--- End diff --
Not sure what's the difference from Commons RDF being an "RDF4J user" or the outer Commons RDF caller being a "RDF4J user" unless the caller is running `repository.initialize()` in a separate thread at the same time as passing it to RDF4JTermFactory (which sounds like asking for trouble).
If I remove this I think we can no longer do `repository.shutdown()` from `Graph.close()` - e.g. you can no longer do the `new BufferedInputStream(new InputStream)` pattern:
```
Triple t;
Sail sail = new NativeStore(file);
try (Graph g = RDF4JTermFactory.asGraph(new SailRepository(sail)) {
g.add(t);
}
```
I think this exact scenario was why we make `api.Graph` be `AutoClosable` in the first place :)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82309923
--- Diff: rdf4j/pom.xml ---
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-rdf-parent</artifactId>
+ <version>0.3.0-incubating-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>commons-rdf-rdf4j</artifactId>
+ <packaging>jar</packaging>
+ <properties>
+ <rdf4j.version>2.0</rdf4j.version>
+ </properties>
+
+ <name>Commons RDF: Integration: RDF4j</name>
+ <description>Eclipse RDF4j implementation of Commons RDF API</description>
+
+ <build>
+ <plugins>
+ <plugin>
+
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <!-- Not sure why this is needed, .impl and .internal is normally hidden
+ by the Bundle Plugin.. -->
+
+ <Export-Package>org.apache.commons.rdf.rdf4j</Export-Package>
+ <Private-Package>org.apache.commons.rdf.rdf4j.impl</Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>commons-rdf-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>commons-rdf-simple</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- Selected rdf4j dependencies We don't use rdf4j-runtime or rdf4j-runtime-osgi
+ here, as they pull in various depenencies like lucene, which might not be
+ needed. -->
+
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-model</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-repository-api</artifactId>
+ </dependency>
+
+ <!-- For RDF4JParserBuilder, these are the RIO dependencies for the standard
+ RDF 1.1 languages -->
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-turtle</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-ntriples</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-nquads</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-rdfxml</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-trig</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-jsonld</artifactId>
+ </dependency>
+ <!-- Languages notably missing, and why:
--- End diff --
I am still not sure why you think that RDF4J users would be expecting only a subset of the RDF4J libraries to be available if they choose to inherit from here. There should be no more chance of versioning conflicts for one or 15 modules if a user includes the bom for dependency management.
Unlike some large multi-module projects, all of the RDF4J modules have synchronised releases, so there is no issue with identifying the latest or compatible versions of each.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81249170
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java ---
@@ -0,0 +1,66 @@
+/**
+ * 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;
+
+import java.util.Optional;
+
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+
+/**
+ * Marker interface for RDF4J implementations of Graph.
+ *
+ * @see ModelGraphImpl
+ * @see RepositoryGraphImpl
+ */
+public interface RDF4JGraph extends Graph, RDF4JGraphLike<Triple> {
+
+ /**
+ * Return a copy of the context filter, if present.
+ * <p>
+ * If {@link Optional#isPresent()}, the filter determines which
+ * <em>contexts</em> in the corresponding RDF4J {@link Model} or
+ * {@link Repository} that this graph reflect. Modifications to the graph
+ * (e.g. {@link #add(Triple)} will be performed for all the specified
+ * contexts, while retrieval (e.g. {@link #contains(Triple)}) will succeed
+ * if the triple is in at least one of the specified contexts.
+ * <p>
+ * The context filter array may contain <code>null</code>, indicating the
+ * default context (the <em>default graph</em> in RDF datasets).
+ * <p>
+ * If the context filter is {@link Optional#empty()}, then this is a
+ * <em>union graph</em> which triples reflecting statements in any contexts.
+ * Triples added to the graph will be added in the default context
+ * <code>null</code>.
+ * <p>
+ * The filter array is a copy, and thus any modifications are not reflected
+ * in the RDF4JGraph.
+ *
+ * @return The context filter as an array of {@link Resource}s, or
+ * {@link Optional#empty()} indicating the union graph (any
+ * context).
+ */
+ public Optional<Resource[]> getContextFilter();
--- End diff --
I would tend to not refer to this as a filter, but that is just personal taste. Some alternatives could be getContextMask or simply getContexts.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81338100
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRepositoryGraphLike.java ---
@@ -0,0 +1,80 @@
+/**
+ * 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.Optional;
+
+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.TripleLike;
+import org.apache.commons.rdf.rdf4j.RDF4JGraphLike;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+
+public abstract class AbstractRepositoryGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
+ implements RDF4JGraphLike<T> {
+
+ protected Repository repository;
+ protected boolean includeInferred;
+ protected boolean shouldWeShutdown = false;
+ protected RDF4JTermFactory rdf4jTermFactory;
+
+ public AbstractRepositoryGraphLike(Repository repository) {
+ this(repository, false);
+ }
+
+ public AbstractRepositoryGraphLike(Repository repository, boolean includeInferred) {
+ this.repository = repository;
+ this.includeInferred = includeInferred;
+ if (!repository.isInitialized()) {
+ repository.initialize();
+ shouldWeShutdown = true;
+ }
+ rdf4jTermFactory = new RDF4JTermFactory(repository.getValueFactory());
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (shouldWeShutdown) {
+ repository.shutDown();
+ }
+ // else: repository was initialized outside, so we should not shut it
+ // down
+ }
+
+
+ protected abstract T asTripleLike(Statement s);
+
+ protected RepositoryConnection getRepositoryConnection() {
+ return repository.getConnection();
+ }
+
+ public Optional<Repository> asRepository() {
+ return Optional.of(repository);
+ }
+
+ @Override
+ public Optional<Model> asModel() {
+ return Optional.empty();
--- End diff --
As a `RDF4JGraph` can have either a `Model` or a `Repository` - or at some point in the future possibly both - isn't the best for users to see them as `Optional` and deal with it rather than look around for exceptions?
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81253176
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ *
+ * @see #asQuad(Statement)
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public static RDF4JQuad asQuad(final Statement statement, UUID salt) {
+ return new QuadImpl(statement, salt);
+ }
+
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @param value The RDF4J {@link Value} to convert.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException if the value is not a BNode, Literal or IRI
+ */
+ public <T extends Value> RDF4JTerm<T> asRDFTerm(T value) {
+ return asRDFTerm(value, salt);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository) {
+ return new RepositoryDatasetImpl(repository);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred quads are included in the dataset
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository, boolean includeInferred) {
+ return new RepositoryDatasetImpl(repository, includeInferred);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}.
+ * <p>
+ * Changes to the graph are reflected in the model, and vice versa.
+ *
+ * @param model
+ * RDF4J {@link Model} to adapt.
+ * @return Adapted {@link Graph}.
+ */
+ public RDF4JGraph asRDFTermGraph(Model model) {
+ return new ModelGraphImpl(model);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository) {
+ return new RepositoryGraphImpl(repository, false, true);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred triples are included in the graph
+ * @param unionGraph
+ * If true, triples from any context is included in the graph,
+ * otherwise only triples in the default context
+ * <code>null</code>.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, boolean unionGraph) {
+ return new RepositoryGraphImpl(repository, includeInferred, unionGraph);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link Triple} or {@link Quad} as a RDF4J
+ * {@link Statement}.
+ * <p>
+ * If the <code>tripleLike</code> argument is an {@link RDF4JTriple} or
+ * a {@link RDF4JQuad}, then its {@link RDF4JTripleLike#asStatement()} is
+ * returned as-is. Note that this means that a {@link RDF4JTriple} would
+ * preserve its {@link Statement#getContext()}, and that any
+ * {@link BlankNode}s would be deemed equivalent in RDF4J
+ * if they have the same {@link BNode#getID()}.
+ *
+ * @param tripleLike
+ * A {@link Triple} or {@link Quad} to adapt
+ * @return A corresponding {@link Statement}
+ */
+ public Statement asStatement(TripleLike<BlankNodeOrIRI, org.apache.commons.rdf.api.IRI, RDFTerm> tripleLike) {
+ if (tripleLike instanceof RDF4JTripleLike) {
+ // Return original statement - this covers both RDF4JQuad and
+ // RDF4JTriple
+ RDF4JTripleLike rdf4jTriple = (RDF4JTripleLike) tripleLike;
+ return rdf4jTriple.asStatement();
+ }
+
+ org.eclipse.rdf4j.model.Resource subject = (org.eclipse.rdf4j.model.Resource) asValue(tripleLike.getSubject());
+ org.eclipse.rdf4j.model.IRI predicate = (org.eclipse.rdf4j.model.IRI) asValue(tripleLike.getPredicate());
+ Value object = asValue(tripleLike.getObject());
+
+ org.eclipse.rdf4j.model.Resource context = null;
+ if (tripleLike instanceof Quad) {
+ Quad quad = (Quad) tripleLike;
+ context = (org.eclipse.rdf4j.model.Resource) asValue(quad.getGraphName().orElse(null));
+ }
+
+ return getValueFactory().createStatement(subject, predicate, object, context);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this method will use an
+ * internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J statements from multiple
+ * repositories or models, then their {@link BNode}s may have the same
+ * {@link BNode#getID()}, which with this method would become equivalent
+ * according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()}, unless a separate
+ * {@link RDF4JTermFactory} instance is used per RDF4J repository/model.
+ *
+ * @param statement
+ * The RDF4J {@link Statement} to adapt.
+ * @return A {@link RDF4JTriple} that is equivalent to the statement
+ */
+ public RDF4JTriple asTriple(final Statement statement) {
+ return new TripleImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link RDFTerm} as a RDF4J {@link Value}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.apache.commons.rdf.api.BlankNode} is converted to a
+ * {@link org.eclipse.rdf4j.model.BNode}, a
+ * {@link org.apache.commons.rdf.api.IRI} is converted to a
+ * {@link org.eclipse.rdf4j.model.IRI} and a
+ * {@link org.apache.commons.rdf.api.Literal} is converted to a
+ * {@link org.eclipse.rdf4j.model.Literal}.
+ * <p>
+ * If the provided {@link RDFTerm} is <code>null</code>, then the returned
+ * value is <code>null</code>.
+ * <p>
+ * If the provided term is an instance of {@link RDF4JTerm}, then the
+ * {@link RDF4JTerm#asValue()} is returned without any conversion. Note that
+ * this could mean that a {@link Value} from a different kind of
+ * {@link ValueFactory} could be returned.
+ *
+ * @param term
+ * RDFTerm to adapt to RDF4J Value
+ * @return Adapted RDF4J {@link Value}
+ */
+ public Value asValue(RDFTerm term) {
+ if (term == null) {
+ return null;
+ }
+ if (term instanceof RDF4JTerm) {
+ // One of our own - avoid converting again.
+ // (This is crucial to avoid double-escaping in BlankNode)
+ return ((RDF4JTerm<?>) term).asValue();
+ }
+ if (term instanceof org.apache.commons.rdf.api.IRI) {
+ org.apache.commons.rdf.api.IRI iri = (org.apache.commons.rdf.api.IRI) term;
+ return getValueFactory().createIRI(iri.getIRIString());
+ }
+ if (term instanceof org.apache.commons.rdf.api.Literal) {
+ org.apache.commons.rdf.api.Literal literal = (org.apache.commons.rdf.api.Literal) term;
+ String label = literal.getLexicalForm();
+ if (literal.getLanguageTag().isPresent()) {
+ String lang = literal.getLanguageTag().get();
+ return getValueFactory().createLiteral(label, lang);
+ }
+ org.eclipse.rdf4j.model.IRI dataType = (org.eclipse.rdf4j.model.IRI) asValue(literal.getDatatype());
+ return getValueFactory().createLiteral(label, dataType);
+ }
+ if (term instanceof BlankNode) {
+ // This is where it gets tricky to support round trips!
+ BlankNode blankNode = (BlankNode) term;
+ // FIXME: The uniqueReference might not be a valid BlankNode
+ // identifier..
+ // does it have to be in RDF4J?
--- End diff --
No there is no contractual requirement for the string to have any particular structure, and if there are cases where it is an issue I will fix them as they are bugs.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81668567
--- Diff: rdf4j/src/test/java/org/apache/commons/rdf/rdf4j/NativeStoreGraphTest.java ---
@@ -0,0 +1,66 @@
+/**
+ * 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;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.apache.commons.rdf.api.AbstractGraphTest;
+import org.apache.commons.rdf.api.RDFTermFactory;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.sail.SailRepository;
+import org.eclipse.rdf4j.sail.Sail;
+import org.eclipse.rdf4j.sail.memory.model.MemValueFactory;
+import org.eclipse.rdf4j.sail.nativerdf.NativeStore;
+
+
+public class NativeStoreGraphTest extends AbstractGraphTest {
+
+ public static final class NativeStoreFactory extends RDF4JTermFactory {
+ NativeStoreFactory() {
+ super(new MemValueFactory());
+ }
+ @Override
+ public RDF4JGraph createGraph() {
+ return asRDFTermGraph(createRepository());
+ }
+ }
+
+ public static Repository createRepository() {
+ Path tempDir;
+ try {
+ tempDir = Files.createTempDirectory("test-commonsrdf-rdf4j");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ Sail sail = new NativeStore(tempDir.toFile());
+ SailRepository repository = new SailRepository(sail);
+ repository.initialize();
+ return repository;
+ }
+
+ @Override
+ public RDFTermFactory createFactory() {
+ // FIXME: This valueFactory will be backed by the wrong temporary folder!
--- End diff --
You could use the following code to ensure that JUnit creates and cleans up a unique temporary directory for each test method:
```
@Rule
// Note, this has to be public so JUnit can see it
public TemporaryFolder tempDir = new TemporaryFolder();
private Path testDir;
@Before
public void setUp() {
testDir = tempDir.newFolder("test-commonsrdf-rdf4j").toPath();
}
```
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82312351
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java ---
@@ -0,0 +1,172 @@
+/**
+ * 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.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+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.RDF4JBlankNodeOrIRI;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements Graph, RDF4JGraph {
+
+ private final Resource[] contextMask;
+
+ public RepositoryGraphImpl(Repository repository, boolean handleInitAndShutdown, boolean includeInferred, boolean unionGraph) {
+ super(repository, handleInitAndShutdown, includeInferred);
+ if (unionGraph) {
+ // no context mask, aka any context
+ this.contextMask = new Resource[] { };
+ } else {
+ // default context: null
+ this.contextMask = new Resource[] { null };
+ }
+ }
+
+ public RepositoryGraphImpl(Repository repository, boolean handleInitAndShutdown, boolean includeInferred, Resource... contextMask) {
+ super(repository, handleInitAndShutdown, includeInferred);
+ this.contextMask = Objects.requireNonNull(contextMask);
+ }
+
+
+ @Override
+ public void add(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement, contextMask);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred, contextMask);
+ }
+ }
+
+ @Override
+ public void remove(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement, contextMask);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear(contextMask);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ if (! includeInferred && contextMask.length == 0) {
+ return conn.size();
+ } else {
+ return stream().count();
+ }
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, contextMask);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contextMask);
+ }
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contextMask);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream() {
+ return stream(null, null, null);
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ RepositoryConnection conn = getRepositoryConnection();
+ // FIXME: Is it OK that we don't close the connection?
+ RepositoryResult<Statement> statements = conn.getStatements(subj, pred, obj, includeInferred, contextMask);
+ return Iterations.stream(statements).map(this::asTripleLike);
+ }
+
+ @Override
+ protected RDF4JTriple asTripleLike(Statement statement) {
+ return rdf4jTermFactory.asTriple(statement);
+ }
+
+ @Override
+ public Set<RDF4JBlankNodeOrIRI<Resource>> getContextMask() {
+ Set<RDF4JBlankNodeOrIRI<Resource>> mask = new HashSet<>();
--- End diff --
Agree in principle - however I think that would be premature optimisation, `getContextMask()` is more of an "inspection hatch" method that probably won't be called much, so I don't think it needs to be stored in memory.
(That kind of caching might be much more beneficial for `org.apache.commons.rdf.rdf4j.impl.TripleImpl`)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81254962
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRepositoryGraphLike.java ---
@@ -0,0 +1,80 @@
+/**
+ * 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.Optional;
+
+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.TripleLike;
+import org.apache.commons.rdf.rdf4j.RDF4JGraphLike;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+
+public abstract class AbstractRepositoryGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
+ implements RDF4JGraphLike<T> {
+
+ protected Repository repository;
+ protected boolean includeInferred;
+ protected boolean shouldWeShutdown = false;
+ protected RDF4JTermFactory rdf4jTermFactory;
+
+ public AbstractRepositoryGraphLike(Repository repository) {
+ this(repository, false);
+ }
+
+ public AbstractRepositoryGraphLike(Repository repository, boolean includeInferred) {
+ this.repository = repository;
+ this.includeInferred = includeInferred;
+ if (!repository.isInitialized()) {
+ repository.initialize();
+ shouldWeShutdown = true;
+ }
+ rdf4jTermFactory = new RDF4JTermFactory(repository.getValueFactory());
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (shouldWeShutdown) {
--- End diff --
Don't call repository.shutDown here. Always rely on the user calling it themselves, as they may just be using this as a wrapper for a long term instance of Repository, which you can't directly infer from isInitialized in general, so easier to never call shutDown from here.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81249586
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JIRI.java ---
@@ -0,0 +1,35 @@
+/**
+ * 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;
+
+/**
+ * Marker interface for RDF4J implementations of IRI.
+ *
+ */
+public interface RDF4JIRI
+ extends RDF4JTerm<org.eclipse.rdf4j.model.IRI>, org.apache.commons.rdf.api.IRI {
+
+ /**
+ * Return the corresponding RDF4J {@link org.eclipse.rdf4j.model.IRI}.
+ *
+ * @return The corresponding RDF4J IRI
+ */
+ public org.eclipse.rdf4j.model.IRI asValue();
--- End diff --
This is making my brain hurt. If this class is already an instance of org.eclipse.rdf4j.model.IRI, why do we need to have a cast?
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81673103
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java ---
@@ -0,0 +1,164 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+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.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements Graph, RDF4JGraph {
+
+ private final Resource[] contextFilter;
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, boolean unionGraph) {
+ super(repository, includeInferred);
+ if (unionGraph) {
+ // no context filter aka any context
+ this.contextFilter = new Resource[] { };
+ } else {
+ // default context: null
+ this.contextFilter = new Resource[] { null };
+ }
+ }
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, Resource... contextFilter) {
+ super(repository, includeInferred);
+ this.contextFilter = contextFilter;
+ }
+
+
+ @Override
+ public void add(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement, contextFilter);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred, contextFilter);
+ }
+ }
+
+ @Override
+ public void remove(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement, contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear(contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ if (! includeInferred && contextFilter.length == 0) {
+ return conn.size();
+ } else {
+ return stream().count();
+ }
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contextFilter);
+ }
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream() {
+ return stream(null, null, null);
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ RepositoryConnection conn = getRepositoryConnection();
+ // FIXME: Is it OK that we don't close the connection?
+ RepositoryResult<Statement> statements = conn.getStatements(subj, pred, obj, includeInferred, contextFilter);
--- End diff --
Thanks - now fixed (assuming the stream consumer calls `.close()` or uses a `try..each` loop).
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81259096
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java ---
@@ -0,0 +1,134 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+public final class ModelGraphImpl implements RDF4JGraph {
+
+ private Model model;
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ public ModelGraphImpl(Model model) {
+ this.model = model;
+ this.rdf4jTermFactory = new RDF4JTermFactory();
+ }
+
+ public ModelGraphImpl(Model model, RDF4JTermFactory rdf4jTermFactory) {
+ this.model = model;
+ this.rdf4jTermFactory = rdf4jTermFactory;
+ }
+
+ @Override
+ public void add(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.add(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void add(Triple triple) {
+ model.add(rdf4jTermFactory.asStatement(triple));
+ }
+
+ public Optional<Model> asModel() {
+ return Optional.of(model);
+ }
+
+ @Override
+ public Optional<Repository> asRepository() {
+ return Optional.empty();
--- End diff --
As above, I would prefer this throw an exception to indicate that it may function in future when someone implements a ModelRepository in RDF4J (or Marmotta sends their implementation upstream), but it currently doesn't actually work. Using Optional is not a good substitute for UnsupportedOperationException in my view.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81332462
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ *
+ * @see #asQuad(Statement)
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public static RDF4JQuad asQuad(final Statement statement, UUID salt) {
+ return new QuadImpl(statement, salt);
+ }
+
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @param value The RDF4J {@link Value} to convert.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException if the value is not a BNode, Literal or IRI
+ */
+ public <T extends Value> RDF4JTerm<T> asRDFTerm(T value) {
+ return asRDFTerm(value, salt);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository) {
+ return new RepositoryDatasetImpl(repository);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred quads are included in the dataset
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository, boolean includeInferred) {
+ return new RepositoryDatasetImpl(repository, includeInferred);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}.
+ * <p>
+ * Changes to the graph are reflected in the model, and vice versa.
+ *
+ * @param model
+ * RDF4J {@link Model} to adapt.
+ * @return Adapted {@link Graph}.
+ */
+ public RDF4JGraph asRDFTermGraph(Model model) {
+ return new ModelGraphImpl(model);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository) {
+ return new RepositoryGraphImpl(repository, false, true);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred triples are included in the graph
+ * @param unionGraph
+ * If true, triples from any context is included in the graph,
+ * otherwise only triples in the default context
+ * <code>null</code>.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, boolean unionGraph) {
--- End diff --
the constructor behind that method does:
```java
if (unionGraph) {
// no context filter aka any context
this.contextFilter = new Resource[] { };
} else {
// default context: null
this.contextFilter = new Resource[] { null };
}
```
I think both of those should be quite common uses of `RDF4JGraph` - to select a particular graph you can also access it from [RDF4JDataset.getGraph(BlankNodeOrIRI)](http://stain.github.io/incubator-commonsrdf/integration/org/apache/commons/rdf/api/Dataset.html#getGraph-org.apache.commons.rdf.api.BlankNodeOrIRI-) -- but I agree on adding the `...` factory method so you can also expose the multi-context filter.
I'll add
```java
public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, BlankNodeOrIRI... contextFilter)
```
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81255412
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRepositoryGraphLike.java ---
@@ -0,0 +1,80 @@
+/**
+ * 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.Optional;
+
+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.TripleLike;
+import org.apache.commons.rdf.rdf4j.RDF4JGraphLike;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+
+public abstract class AbstractRepositoryGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
+ implements RDF4JGraphLike<T> {
+
+ protected Repository repository;
+ protected boolean includeInferred;
+ protected boolean shouldWeShutdown = false;
+ protected RDF4JTermFactory rdf4jTermFactory;
+
+ public AbstractRepositoryGraphLike(Repository repository) {
+ this(repository, false);
+ }
+
+ public AbstractRepositoryGraphLike(Repository repository, boolean includeInferred) {
+ this.repository = repository;
+ this.includeInferred = includeInferred;
+ if (!repository.isInitialized()) {
+ repository.initialize();
+ shouldWeShutdown = true;
+ }
+ rdf4jTermFactory = new RDF4JTermFactory(repository.getValueFactory());
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (shouldWeShutdown) {
+ repository.shutDown();
+ }
+ // else: repository was initialized outside, so we should not shut it
+ // down
+ }
+
+
+ protected abstract T asTripleLike(Statement s);
+
+ protected RepositoryConnection getRepositoryConnection() {
+ return repository.getConnection();
+ }
+
+ public Optional<Repository> asRepository() {
+ return Optional.of(repository);
+ }
+
+ @Override
+ public Optional<Model> asModel() {
+ return Optional.empty();
--- End diff --
It would be better for this to throw an exception rather than pretend that it is empty. In the long term I would expect this to return an actual RepositoryModel wrapper instance (similar to RepositoryGraph from sesametools), but that hasn't been implemented in RDF4J yet.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81676587
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JQuad.java ---
@@ -0,0 +1,28 @@
+/**
+ * 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;
+
+import org.apache.commons.rdf.api.Quad;
+
+/**
+ * Marker interface for RDF4J implementations of Quad.
+ *
+ */
+public interface RDF4JQuad extends Quad, RDF4JTripleLike {
--- End diff --
Good that RDF4J goes "quad first"!
That would simplify a lot both here and in jsonld-java integration, I agree. However `Triple` is where we started and also a prime type in Jena. RDF 1.1 does not really define a 'quad' as much as it defines a "triple". Also many non-expert users are likely to just want to stay at the RDF graph level and could be confused if their 'contains' call fails.
And so I think we should still support triples and graphs for the RDF4J integration.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82313012
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,603 @@
+/**
+ * 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;
+
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI, Literal)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.InternalRDF4JFactory;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.sail.SailRepository;
+import org.eclipse.rdf4j.sail.Sail;
+import org.eclipse.rdf4j.sail.memory.MemoryStore;
+
+/**
+ * RDF4J implementation of RDFTermFactory.
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally.
+ *
+ */
+public final class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * InternalRDF4JFactory is deliberately abstract
+ */
+ private static InternalRDF4JFactory rdf4j = new InternalRDF4JFactory() {
+ };
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
--- End diff --
I would change this to "MUST" be the same for all statements from the same Repository or Model or Rio RDFParser. There is no other rational way to perform the transformation and retain peoples sanity.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82317932
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java ---
@@ -0,0 +1,206 @@
+/**
+ * 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.experimental;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFSyntax;
+import org.apache.commons.rdf.experimental.RDFParser;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNodeOrIRI;
+import org.apache.commons.rdf.rdf4j.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.simple.experimental.AbstractRDFParser;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.util.RDFInserter;
+import org.eclipse.rdf4j.repository.util.RDFLoader;
+import org.eclipse.rdf4j.rio.ParserConfig;
+import org.eclipse.rdf4j.rio.RDFFormat;
+import org.eclipse.rdf4j.rio.RDFHandler;
+import org.eclipse.rdf4j.rio.RDFHandlerException;
+import org.eclipse.rdf4j.rio.Rio;
+import org.eclipse.rdf4j.rio.helpers.AbstractRDFHandler;
+
+/**
+ * RDF4J-based parser.
+ * <p>
+ * This can handle the RDF syntaxes {@link RDFSyntax#JSONLD},
+ * {@link RDFSyntax#NQUADS}, {@link RDFSyntax#NTRIPLES},
+ * {@link RDFSyntax#RDFXML}, {@link RDFSyntax#TRIG} and {@link RDFSyntax#TURTLE}
+ * - additional syntaxes can be supported by including the corresponding
+ * <em>rdf4j-rio-*</em> module on the classpath.
+ *
+ */
+public class RDF4JParser extends AbstractRDFParser<RDF4JParser> implements RDFParser {
+
+ private final class AddToQuadConsumer extends AbstractRDFHandler {
+ private final Consumer<Quad> quadTarget;
+
+ private AddToQuadConsumer(Consumer<Quad> quadTarget) {
+ this.quadTarget = quadTarget;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ // TODO: if getRdfTermFactory() is a non-rdf4j factory, should
+ // we use factory.createQuad() instead?
+ // Unsure what is the promise of setting getRdfTermFactory() --
+ // does it go all the way down to creating BlankNode, IRI and
+ // Literal?
+ quadTarget.accept(rdf4jTermFactory.asQuad(st));
+ // Performance note:
+ // Graph/Quad.add should pick up again our
+ // RDF4JGraphLike.asStatement()
+ // and avoid double conversion.
+ // Additionally the RDF4JQuad and RDF4JTriple implementations
+ // are lazily converting subj/obj/pred/graph.s
+ }
+ }
+
+ private final static class AddToModel extends AbstractRDFHandler {
+ private final Model model;
+
+ public AddToModel(Model model) {
+ this.model = model;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ model.add(st);
+ }
+
+ @Override
+ public void handleNamespace(String prefix, String uri) throws RDFHandlerException {
+ model.setNamespace(prefix, uri);
+ }
+ }
+
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ @Override
+ protected RDF4JTermFactory createRDFTermFactory() {
+ return new RDF4JTermFactory();
+ }
+
+ @Override
+ protected RDF4JParser prepareForParsing() throws IOException, IllegalStateException {
+ RDF4JParser c = prepareForParsing();
+ // Ensure we have an RDF4JTermFactory for conversion.
+ // We'll make a new one if user has provided a non-RDF4J factory
+ c.rdf4jTermFactory = (RDF4JTermFactory) getRdfTermFactory().filter(RDF4JTermFactory.class::isInstance)
+ .orElseGet(c::createRDFTermFactory);
+ return c;
+ }
+
+ @Override
+ protected void parseSynchronusly() throws IOException {
+ Optional<RDFFormat> formatByMimeType = getContentType().flatMap(Rio::getParserFormatForMIMEType);
+ String base = getBase().map(IRI::getIRIString).orElse(null);
+
+ ParserConfig parserConfig = new ParserConfig();
+ // TODO: Should we need to set anything?
+ RDFLoader loader = new RDFLoader(parserConfig, rdf4jTermFactory.getValueFactory());
+ RDFHandler rdfHandler = makeRDFHandler();
+ if (getSourceFile().isPresent()) {
+ // NOTE: While we could have used
+ // loader.load(sourcePath.toFile()
+ // if the path fs provider == FileSystems.getDefault(),
+ // that RDFLoader method does not use absolute path
+ // as the base URI, so to be consistent
+ // we'll always do it with our own input stream
+ //
+ // That means we may have to guess format by extensions:
+ Optional<RDFFormat> formatByFilename = getSourceFile().map(Path::getFileName).map(Path::toString)
+ .flatMap(Rio::getParserFormatForFileName);
+ // TODO: for the excited.. what about the extension after following symlinks?
+
+ RDFFormat format = formatByMimeType.orElse(formatByFilename.orElse(null));
+ try (InputStream in = Files.newInputStream(getSourceFile().get())) {
+ loader.load(in, base, format, rdfHandler);
+ }
+ } else if (getSourceIri().isPresent()) {
+ try {
+ // TODO: Handle international IRIs properly
+ // (Unicode support for for hostname, path and query)
+ URL url = new URL(getSourceIri().get().getIRIString());
+ // TODO: This probably does not support https:// -> http:// redirections
+ loader.load(url, base, formatByMimeType.orElse(null), makeRDFHandler());
+ } catch (MalformedURLException ex) {
+ throw new IOException("Can't handle source URL: " + getSourceIri().get(), ex);
+ }
+ }
+ // must be getSourceInputStream then, this is guaranteed by super.checkSource();
+ loader.load(getSourceInputStream().get(), base, formatByMimeType.orElse(null), rdfHandler);
+ }
+
+ protected RDFHandler makeRDFHandler() {
+
+ // TODO: Can we join the below DF4JDataset and RDF4JGraph cases
--- End diff --
Feel free to implement a `Graph`/`Triple` lifecycle independent of the `Dataset`/`Quad` lifecycle, but it doesn't seem like it has any particular benefit or attraction for RDF4J users who have always had `getContext()` as a method on `Statement`.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82422220
--- Diff: rdf4j/pom.xml ---
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-rdf-parent</artifactId>
+ <version>0.3.0-incubating-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>commons-rdf-rdf4j</artifactId>
+ <packaging>jar</packaging>
+ <properties>
+ <rdf4j.version>2.0</rdf4j.version>
+ </properties>
+
+ <name>Commons RDF: Integration: RDF4j</name>
+ <description>Eclipse RDF4j implementation of Commons RDF API</description>
+
+ <build>
+ <plugins>
+ <plugin>
+
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <!-- Not sure why this is needed, .impl and .internal is normally hidden
+ by the Bundle Plugin.. -->
+
+ <Export-Package>org.apache.commons.rdf.rdf4j</Export-Package>
+ <Private-Package>org.apache.commons.rdf.rdf4j.impl</Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>commons-rdf-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>commons-rdf-simple</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- Selected rdf4j dependencies We don't use rdf4j-runtime or rdf4j-runtime-osgi
+ here, as they pull in various depenencies like lucene, which might not be
+ needed. -->
+
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-model</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-repository-api</artifactId>
+ </dependency>
+
+ <!-- For RDF4JParserBuilder, these are the RIO dependencies for the standard
+ RDF 1.1 languages -->
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-turtle</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-ntriples</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-nquads</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-rdfxml</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-trig</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-jsonld</artifactId>
+ </dependency>
+ <!-- Languages notably missing, and why:
--- End diff --
They should not need the rest of RDF4J, but can use the normal RDF4J all-in dependency if they like ; it would be compatible. I think this can go into docs.
Adding everything seemed to add multiple external libraries that might not be needed or might be in conflict with something else in a Commons RDF user's project (which after all might be doing integration).
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81657373
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JQuad.java ---
@@ -0,0 +1,28 @@
+/**
+ * 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;
+
+import org.apache.commons.rdf.api.Quad;
+
+/**
+ * Marker interface for RDF4J implementations of Quad.
+ *
+ */
+public interface RDF4JQuad extends Quad, RDF4JTripleLike {
--- End diff --
In practice, RDF4J only supports RDF-1.1 `Quad`'s in terms of the equals contract. Ie, if a context is missing it is assumed to be the default graph and still a `Statement` or `Quad`. Ie, in RDF4J the Statement.getContext() for the equals contract is always present, and just represents the default graph if it is null.
Knowing that may simplify the implementation here as there is no need to deal with `RDF4JTriple`/`Triple`/`RDF4JTripleLike`/`TripleLike`, or Generalised RDF given that restriction and you can just focus everything on `Quad`.
The contract for Statement.equals changed in RDF4J compared to Sesame, where the graph was always not used for .equals, making any implementation of Commons RDF for Sesame distinctly different to RDF4J:
https://github.com/eclipse/rdf4j/blob/master/core/model/src/main/java/org/eclipse/rdf4j/model/Statement.java#L47
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81666766
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java ---
@@ -0,0 +1,134 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+public final class ModelGraphImpl implements RDF4JGraph {
+
+ private Model model;
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ public ModelGraphImpl(Model model) {
+ this.model = model;
+ this.rdf4jTermFactory = new RDF4JTermFactory();
+ }
+
+ public ModelGraphImpl(Model model, RDF4JTermFactory rdf4jTermFactory) {
+ this.model = model;
+ this.rdf4jTermFactory = rdf4jTermFactory;
+ }
+
+ @Override
+ public void add(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.add(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void add(Triple triple) {
+ model.add(rdf4jTermFactory.asStatement(triple));
+ }
+
+ public Optional<Model> asModel() {
+ return Optional.of(model);
+ }
+
+ @Override
+ public Optional<Repository> asRepository() {
+ return Optional.empty();
+ }
+
+ @Override
+ public void clear() {
+ model.clear();
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.contains(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public boolean contains(Triple triple) {
+ return model.contains(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.remove(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void remove(Triple triple) {
+ model.remove(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public long size() {
+ int size = model.size();
+ if (size < Integer.MAX_VALUE) {
+ return size;
+ } else {
+ // TODO: Check if this can really happen with RDF4J models
+ // Collection.size() can't help us, we'll have to count
+ return model.parallelStream().count();
--- End diff --
It is probably useful to leave it here. It is common knowledge that in general `Collection.size()` doesn't have `O(1)`, so this is fine for those corner cases.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81260895
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java ---
@@ -0,0 +1,164 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+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.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements Graph, RDF4JGraph {
+
+ private final Resource[] contextFilter;
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, boolean unionGraph) {
+ super(repository, includeInferred);
+ if (unionGraph) {
+ // no context filter aka any context
+ this.contextFilter = new Resource[] { };
+ } else {
+ // default context: null
+ this.contextFilter = new Resource[] { null };
+ }
+ }
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, Resource... contextFilter) {
+ super(repository, includeInferred);
+ this.contextFilter = contextFilter;
+ }
+
+
+ @Override
+ public void add(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement, contextFilter);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred, contextFilter);
+ }
+ }
+
+ @Override
+ public void remove(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement, contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear(contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ if (! includeInferred && contextFilter.length == 0) {
+ return conn.size();
+ } else {
+ return stream().count();
+ }
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contextFilter);
+ }
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream() {
+ return stream(null, null, null);
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ RepositoryConnection conn = getRepositoryConnection();
+ // FIXME: Is it OK that we don't close the connection?
+ RepositoryResult<Statement> statements = conn.getStatements(subj, pred, obj, includeInferred, contextFilter);
+ return Iterations.stream(statements).map(this::asTripleLike);
+ }
+
+ @Override
+ protected RDF4JTriple asTripleLike(Statement statement) {
+ return rdf4jTermFactory.asTriple(statement);
+ }
+
+ public Optional<Resource[]> getContextFilter() {
+ // Make sure we clone
+ return Optional.ofNullable(contextFilter).map(f -> f.clone());
--- End diff --
contextFilter should never be null so this could instead be Optional.of
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81248908
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java ---
@@ -0,0 +1,66 @@
+/**
+ * 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;
+
+import java.util.Optional;
+
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+
+/**
+ * Marker interface for RDF4J implementations of Graph.
+ *
+ * @see ModelGraphImpl
+ * @see RepositoryGraphImpl
+ */
+public interface RDF4JGraph extends Graph, RDF4JGraphLike<Triple> {
+
+ /**
+ * Return a copy of the context filter, if present.
+ * <p>
+ * If {@link Optional#isPresent()}, the filter determines which
+ * <em>contexts</em> in the corresponding RDF4J {@link Model} or
+ * {@link Repository} that this graph reflect. Modifications to the graph
+ * (e.g. {@link #add(Triple)} will be performed for all the specified
+ * contexts, while retrieval (e.g. {@link #contains(Triple)}) will succeed
+ * if the triple is in at least one of the specified contexts.
+ * <p>
+ * The context filter array may contain <code>null</code>, indicating the
+ * default context (the <em>default graph</em> in RDF datasets).
+ * <p>
+ * If the context filter is {@link Optional#empty()}, then this is a
+ * <em>union graph</em> which triples reflecting statements in any contexts.
+ * Triples added to the graph will be added in the default context
+ * <code>null</code>.
--- End diff --
Need to clarify whether this would be Optional.ofNullable(null) or Optional.of(new Resource[1] { null }). To my undeerstanding, unless something changed without me noticing, the convention in RDF4J matches Sesame, in that the first option (raw null) is never allowed for context Resource[] or Resource... (varargs), and the second option, the null element in an array, must be used for the default graph.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81329576
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JQuad.java ---
@@ -0,0 +1,28 @@
+/**
+ * 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;
+
+import org.apache.commons.rdf.api.Quad;
+
+/**
+ * Marker interface for RDF4J implementations of Quad.
+ *
+ */
+public interface RDF4JQuad extends Quad, RDF4JTripleLike {
--- End diff --
Both [Quad](http://stain.github.io/incubator-commonsrdf/integration/org/apache/commons/rdf/api/Quad.html) and [Triple](http://stain.github.io/incubator-commonsrdf/integration/org/apache/commons/rdf/api/Triple.html) are [TripleLike](http://stain.github.io/incubator-commonsrdf/integration/org/apache/commons/rdf/api/TripleLike.html) in CommonsRDF, they both have methods `getSubject()`, `getPredicate()` and `getObject()`. However `Quad` and `Triple` have different equality semantics (quad also considers the graph label) - which is particularly important for a `Statement` because a Triple can be in multiple contexts.
`Quad` can't be a subtype of `Triple` as you don't get bidirectional `.equals()` (or we would have to require `Triple.equals()` to recognize `Quad`) - but they can share the "duck typing" interface `TripleLike` for users who don't care about equality, but just want to access say the `getSubject()` method. See #19 for discussion.
To determine if a _triple like_ is `Triple` or `Quad`, use `instanceof`. (It may be a generalized triple, which is neither).
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82311764
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java ---
@@ -0,0 +1,232 @@
+/**
+ * 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.experimental;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFSyntax;
+import org.apache.commons.rdf.experimental.RDFParser;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNodeOrIRI;
+import org.apache.commons.rdf.rdf4j.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.simple.experimental.AbstractRDFParser;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.util.RDFInserter;
+import org.eclipse.rdf4j.repository.util.RDFLoader;
+import org.eclipse.rdf4j.rio.ParserConfig;
+import org.eclipse.rdf4j.rio.RDFFormat;
+import org.eclipse.rdf4j.rio.RDFHandler;
+import org.eclipse.rdf4j.rio.RDFHandlerException;
+import org.eclipse.rdf4j.rio.Rio;
+import org.eclipse.rdf4j.rio.helpers.AbstractRDFHandler;
+
+/**
+ * RDF4J-based parser.
+ * <p>
+ * This can handle the RDF syntaxes {@link RDFSyntax#JSONLD},
+ * {@link RDFSyntax#NQUADS}, {@link RDFSyntax#NTRIPLES},
+ * {@link RDFSyntax#RDFXML}, {@link RDFSyntax#TRIG} and {@link RDFSyntax#TURTLE}
+ * - additional syntaxes can be supported by including the corresponding
+ * <em>rdf4j-rio-*</em> module on the classpath.
+ *
+ */
+public class RDF4JParser extends AbstractRDFParser<RDF4JParser> implements RDFParser {
+
+ private final class AddToQuadConsumer extends AbstractRDFHandler {
+ private final Consumer<Quad> quadTarget;
+
+ private AddToQuadConsumer(Consumer<Quad> quadTarget) {
+ this.quadTarget = quadTarget;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ // TODO: if getRdfTermFactory() is a non-rdf4j factory, should
+ // we use factory.createQuad() instead?
+ // Unsure what is the promise of setting getRdfTermFactory() --
+ // does it go all the way down to creating BlankNode, IRI and
+ // Literal?
+ quadTarget.accept(rdf4jTermFactory.asQuad(st));
+ // Performance note:
+ // Graph/Quad.add should pick up again our
+ // RDF4JGraphLike.asStatement()
+ // and avoid double conversion.
+ // Additionally the RDF4JQuad and RDF4JTriple implementations
+ // are lazily converting subj/obj/pred/graph.s
+ }
+ }
+
+ private final static class AddToModel extends AbstractRDFHandler {
+ private final Model model;
+
+ public AddToModel(Model model) {
+ this.model = model;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ model.add(st);
+ }
+
+ @Override
+ public void handleNamespace(String prefix, String uri) throws RDFHandlerException {
+ model.setNamespace(prefix, uri);
+ }
+ }
+
+ private RDF4JTermFactory rdf4jTermFactory;
+ private ParserConfig parserConfig = new ParserConfig();
+
+ @Override
+ protected RDF4JTermFactory createRDFTermFactory() {
+ return new RDF4JTermFactory();
+ }
+
+ @Override
+ protected RDF4JParser prepareForParsing() throws IOException, IllegalStateException {
+ RDF4JParser c = prepareForParsing();
+ // Ensure we have an RDF4JTermFactory for conversion.
+ // We'll make a new one if user has provided a non-RDF4J factory
+ c.rdf4jTermFactory = (RDF4JTermFactory) getRdfTermFactory().filter(RDF4JTermFactory.class::isInstance)
+ .orElseGet(c::createRDFTermFactory);
+ return c;
+ }
+
+ @Override
+ protected void parseSynchronusly() throws IOException {
+ Optional<RDFFormat> formatByMimeType = getContentType().flatMap(Rio::getParserFormatForMIMEType);
+ String base = getBase().map(IRI::getIRIString).orElse(null);
+
+ ParserConfig parserConfig = getParserConfig();
+ // TODO: Should we need to set anything?
+ RDFLoader loader = new RDFLoader(parserConfig, rdf4jTermFactory.getValueFactory());
+ RDFHandler rdfHandler = makeRDFHandler();
+ if (getSourceFile().isPresent()) {
+ // NOTE: While we could have used
+ // loader.load(sourcePath.toFile()
+ // if the path fs provider == FileSystems.getDefault(),
+ // that RDFLoader method does not use absolute path
+ // as the base URI, so to be consistent
+ // we'll always do it with our own input stream
+ //
+ // That means we may have to guess format by extensions:
+ Optional<RDFFormat> formatByFilename = getSourceFile().map(Path::getFileName).map(Path::toString)
+ .flatMap(Rio::getParserFormatForFileName);
+ // TODO: for the excited.. what about the extension after following symlinks?
+
+ RDFFormat format = formatByMimeType.orElse(formatByFilename.orElse(null));
+ try (InputStream in = Files.newInputStream(getSourceFile().get())) {
+ loader.load(in, base, format, rdfHandler);
+ }
+ } else if (getSourceIri().isPresent()) {
+ try {
+ // TODO: Handle international IRIs properly
+ // (Unicode support for for hostname, path and query)
+ URL url = new URL(getSourceIri().get().getIRIString());
+ // TODO: This probably does not support https:// -> http:// redirections
+ loader.load(url, base, formatByMimeType.orElse(null), makeRDFHandler());
+ } catch (MalformedURLException ex) {
+ throw new IOException("Can't handle source URL: " + getSourceIri().get(), ex);
+ }
+ }
+ // must be getSourceInputStream then, this is guaranteed by super.checkSource();
+ loader.load(getSourceInputStream().get(), base, formatByMimeType.orElse(null), rdfHandler);
+ }
+
+ /**
+ * Get the RDF4J {@link ParserConfig} to use.
+ * <p>
+ * If no parser config is set, the default configuration is provided.
+ * <p>
+ * <strong>Note:</strong> The parser config is mutable - changes in the
+ * returned config is reflected in this instance of the parser.
+ * To avoid mutation, create a new {@link ParserConfig} and set
--- End diff --
I am a little confused about why you feel you need to comment about this here. If they inject another instance, any other thread can still see it just like they can the original instance.
It may be better to avoid encouraging multi-threaded use of this class, as it isn't necessary to do so in a long term pattern and creates many more issues than it seems to be worth.
I haven't encountered multi-threaded parsers often, but if you are actually intending for this to be a multi-threaded parser, the parserConfig variable must be "volatile" to fit with the JVM model, otherwise changes to the variable using setParserConfig are never guaranteed to be propagated across threads.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81667445
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java ---
@@ -0,0 +1,172 @@
+/**
+ * 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.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+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.RDF4JBlankNodeOrIRI;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements Graph, RDF4JGraph {
+
+ private final Resource[] contextMask;
+
+ public RepositoryGraphImpl(Repository repository, boolean handleInitAndShutdown, boolean includeInferred, boolean unionGraph) {
+ super(repository, handleInitAndShutdown, includeInferred);
+ if (unionGraph) {
+ // no context mask, aka any context
+ this.contextMask = new Resource[] { };
+ } else {
+ // default context: null
+ this.contextMask = new Resource[] { null };
+ }
+ }
+
+ public RepositoryGraphImpl(Repository repository, boolean handleInitAndShutdown, boolean includeInferred, Resource... contextMask) {
+ super(repository, handleInitAndShutdown, includeInferred);
+ this.contextMask = Objects.requireNonNull(contextMask);
+ }
+
+
+ @Override
+ public void add(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement, contextMask);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred, contextMask);
+ }
+ }
+
+ @Override
+ public void remove(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement, contextMask);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear(contextMask);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ if (! includeInferred && contextMask.length == 0) {
+ return conn.size();
+ } else {
+ return stream().count();
+ }
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, contextMask);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contextMask);
+ }
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contextMask);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream() {
+ return stream(null, null, null);
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ RepositoryConnection conn = getRepositoryConnection();
+ // FIXME: Is it OK that we don't close the connection?
+ RepositoryResult<Statement> statements = conn.getStatements(subj, pred, obj, includeInferred, contextMask);
+ return Iterations.stream(statements).map(this::asTripleLike);
+ }
+
+ @Override
+ protected RDF4JTriple asTripleLike(Statement statement) {
+ return rdf4jTermFactory.asTriple(statement);
+ }
+
+ @Override
+ public Set<RDF4JBlankNodeOrIRI<Resource>> getContextMask() {
+ Set<RDF4JBlankNodeOrIRI<Resource>> mask = new HashSet<>();
--- End diff --
Not sure how often this method will be used, but this set should not become very large in any normal situations, compared to the rest of the data, so this could be prederived in the constructor and stored in an instance variable next to contextMask.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81661560
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java ---
@@ -0,0 +1,206 @@
+/**
+ * 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.experimental;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFSyntax;
+import org.apache.commons.rdf.experimental.RDFParser;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNodeOrIRI;
+import org.apache.commons.rdf.rdf4j.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.simple.experimental.AbstractRDFParser;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.util.RDFInserter;
+import org.eclipse.rdf4j.repository.util.RDFLoader;
+import org.eclipse.rdf4j.rio.ParserConfig;
+import org.eclipse.rdf4j.rio.RDFFormat;
+import org.eclipse.rdf4j.rio.RDFHandler;
+import org.eclipse.rdf4j.rio.RDFHandlerException;
+import org.eclipse.rdf4j.rio.Rio;
+import org.eclipse.rdf4j.rio.helpers.AbstractRDFHandler;
+
+/**
+ * RDF4J-based parser.
+ * <p>
+ * This can handle the RDF syntaxes {@link RDFSyntax#JSONLD},
+ * {@link RDFSyntax#NQUADS}, {@link RDFSyntax#NTRIPLES},
+ * {@link RDFSyntax#RDFXML}, {@link RDFSyntax#TRIG} and {@link RDFSyntax#TURTLE}
+ * - additional syntaxes can be supported by including the corresponding
+ * <em>rdf4j-rio-*</em> module on the classpath.
+ *
+ */
+public class RDF4JParser extends AbstractRDFParser<RDF4JParser> implements RDFParser {
+
+ private final class AddToQuadConsumer extends AbstractRDFHandler {
+ private final Consumer<Quad> quadTarget;
+
+ private AddToQuadConsumer(Consumer<Quad> quadTarget) {
+ this.quadTarget = quadTarget;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ // TODO: if getRdfTermFactory() is a non-rdf4j factory, should
+ // we use factory.createQuad() instead?
+ // Unsure what is the promise of setting getRdfTermFactory() --
+ // does it go all the way down to creating BlankNode, IRI and
+ // Literal?
+ quadTarget.accept(rdf4jTermFactory.asQuad(st));
+ // Performance note:
+ // Graph/Quad.add should pick up again our
+ // RDF4JGraphLike.asStatement()
+ // and avoid double conversion.
+ // Additionally the RDF4JQuad and RDF4JTriple implementations
+ // are lazily converting subj/obj/pred/graph.s
+ }
+ }
+
+ private final static class AddToModel extends AbstractRDFHandler {
+ private final Model model;
+
+ public AddToModel(Model model) {
+ this.model = model;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ model.add(st);
+ }
+
+ @Override
+ public void handleNamespace(String prefix, String uri) throws RDFHandlerException {
+ model.setNamespace(prefix, uri);
+ }
+ }
+
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ @Override
+ protected RDF4JTermFactory createRDFTermFactory() {
+ return new RDF4JTermFactory();
+ }
+
+ @Override
+ protected RDF4JParser prepareForParsing() throws IOException, IllegalStateException {
+ RDF4JParser c = prepareForParsing();
+ // Ensure we have an RDF4JTermFactory for conversion.
+ // We'll make a new one if user has provided a non-RDF4J factory
+ c.rdf4jTermFactory = (RDF4JTermFactory) getRdfTermFactory().filter(RDF4JTermFactory.class::isInstance)
+ .orElseGet(c::createRDFTermFactory);
+ return c;
+ }
+
+ @Override
+ protected void parseSynchronusly() throws IOException {
+ Optional<RDFFormat> formatByMimeType = getContentType().flatMap(Rio::getParserFormatForMIMEType);
+ String base = getBase().map(IRI::getIRIString).orElse(null);
+
+ ParserConfig parserConfig = new ParserConfig();
+ // TODO: Should we need to set anything?
+ RDFLoader loader = new RDFLoader(parserConfig, rdf4jTermFactory.getValueFactory());
+ RDFHandler rdfHandler = makeRDFHandler();
+ if (getSourceFile().isPresent()) {
+ // NOTE: While we could have used
+ // loader.load(sourcePath.toFile()
+ // if the path fs provider == FileSystems.getDefault(),
+ // that RDFLoader method does not use absolute path
+ // as the base URI, so to be consistent
+ // we'll always do it with our own input stream
+ //
+ // That means we may have to guess format by extensions:
+ Optional<RDFFormat> formatByFilename = getSourceFile().map(Path::getFileName).map(Path::toString)
+ .flatMap(Rio::getParserFormatForFileName);
+ // TODO: for the excited.. what about the extension after following symlinks?
+
+ RDFFormat format = formatByMimeType.orElse(formatByFilename.orElse(null));
+ try (InputStream in = Files.newInputStream(getSourceFile().get())) {
+ loader.load(in, base, format, rdfHandler);
+ }
+ } else if (getSourceIri().isPresent()) {
+ try {
+ // TODO: Handle international IRIs properly
+ // (Unicode support for for hostname, path and query)
+ URL url = new URL(getSourceIri().get().getIRIString());
+ // TODO: This probably does not support https:// -> http:// redirections
+ loader.load(url, base, formatByMimeType.orElse(null), makeRDFHandler());
+ } catch (MalformedURLException ex) {
+ throw new IOException("Can't handle source URL: " + getSourceIri().get(), ex);
+ }
+ }
+ // must be getSourceInputStream then, this is guaranteed by super.checkSource();
+ loader.load(getSourceInputStream().get(), base, formatByMimeType.orElse(null), rdfHandler);
+ }
+
+ protected RDFHandler makeRDFHandler() {
+
+ // TODO: Can we join the below DF4JDataset and RDF4JGraph cases
--- End diff --
You only need to support `Dataset`, as `Model`/`Repository`/`Sail` are all based on `Quad`s rather than `Triple`s, per my comment earlier in the review about all `Statement`s being `Quad`s
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81253030
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ *
+ * @see #asQuad(Statement)
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public static RDF4JQuad asQuad(final Statement statement, UUID salt) {
+ return new QuadImpl(statement, salt);
+ }
+
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @param value The RDF4J {@link Value} to convert.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException if the value is not a BNode, Literal or IRI
+ */
+ public <T extends Value> RDF4JTerm<T> asRDFTerm(T value) {
+ return asRDFTerm(value, salt);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository) {
+ return new RepositoryDatasetImpl(repository);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred quads are included in the dataset
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository, boolean includeInferred) {
+ return new RepositoryDatasetImpl(repository, includeInferred);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}.
+ * <p>
+ * Changes to the graph are reflected in the model, and vice versa.
+ *
+ * @param model
+ * RDF4J {@link Model} to adapt.
+ * @return Adapted {@link Graph}.
+ */
+ public RDF4JGraph asRDFTermGraph(Model model) {
+ return new ModelGraphImpl(model);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository) {
+ return new RepositoryGraphImpl(repository, false, true);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred triples are included in the graph
+ * @param unionGraph
+ * If true, triples from any context is included in the graph,
+ * otherwise only triples in the default context
+ * <code>null</code>.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, boolean unionGraph) {
+ return new RepositoryGraphImpl(repository, includeInferred, unionGraph);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link Triple} or {@link Quad} as a RDF4J
+ * {@link Statement}.
+ * <p>
+ * If the <code>tripleLike</code> argument is an {@link RDF4JTriple} or
+ * a {@link RDF4JQuad}, then its {@link RDF4JTripleLike#asStatement()} is
+ * returned as-is. Note that this means that a {@link RDF4JTriple} would
+ * preserve its {@link Statement#getContext()}, and that any
+ * {@link BlankNode}s would be deemed equivalent in RDF4J
+ * if they have the same {@link BNode#getID()}.
+ *
+ * @param tripleLike
+ * A {@link Triple} or {@link Quad} to adapt
+ * @return A corresponding {@link Statement}
+ */
+ public Statement asStatement(TripleLike<BlankNodeOrIRI, org.apache.commons.rdf.api.IRI, RDFTerm> tripleLike) {
+ if (tripleLike instanceof RDF4JTripleLike) {
+ // Return original statement - this covers both RDF4JQuad and
+ // RDF4JTriple
+ RDF4JTripleLike rdf4jTriple = (RDF4JTripleLike) tripleLike;
+ return rdf4jTriple.asStatement();
+ }
+
+ org.eclipse.rdf4j.model.Resource subject = (org.eclipse.rdf4j.model.Resource) asValue(tripleLike.getSubject());
+ org.eclipse.rdf4j.model.IRI predicate = (org.eclipse.rdf4j.model.IRI) asValue(tripleLike.getPredicate());
+ Value object = asValue(tripleLike.getObject());
+
+ org.eclipse.rdf4j.model.Resource context = null;
+ if (tripleLike instanceof Quad) {
+ Quad quad = (Quad) tripleLike;
+ context = (org.eclipse.rdf4j.model.Resource) asValue(quad.getGraphName().orElse(null));
+ }
+
+ return getValueFactory().createStatement(subject, predicate, object, context);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this method will use an
+ * internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J statements from multiple
+ * repositories or models, then their {@link BNode}s may have the same
+ * {@link BNode#getID()}, which with this method would become equivalent
+ * according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()}, unless a separate
+ * {@link RDF4JTermFactory} instance is used per RDF4J repository/model.
+ *
+ * @param statement
+ * The RDF4J {@link Statement} to adapt.
+ * @return A {@link RDF4JTriple} that is equivalent to the statement
+ */
+ public RDF4JTriple asTriple(final Statement statement) {
+ return new TripleImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link RDFTerm} as a RDF4J {@link Value}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.apache.commons.rdf.api.BlankNode} is converted to a
+ * {@link org.eclipse.rdf4j.model.BNode}, a
+ * {@link org.apache.commons.rdf.api.IRI} is converted to a
+ * {@link org.eclipse.rdf4j.model.IRI} and a
+ * {@link org.apache.commons.rdf.api.Literal} is converted to a
+ * {@link org.eclipse.rdf4j.model.Literal}.
+ * <p>
+ * If the provided {@link RDFTerm} is <code>null</code>, then the returned
+ * value is <code>null</code>.
+ * <p>
+ * If the provided term is an instance of {@link RDF4JTerm}, then the
+ * {@link RDF4JTerm#asValue()} is returned without any conversion. Note that
+ * this could mean that a {@link Value} from a different kind of
+ * {@link ValueFactory} could be returned.
+ *
+ * @param term
+ * RDFTerm to adapt to RDF4J Value
+ * @return Adapted RDF4J {@link Value}
+ */
+ public Value asValue(RDFTerm term) {
+ if (term == null) {
+ return null;
+ }
+ if (term instanceof RDF4JTerm) {
--- End diff --
It is typical to chain these operations with else if rather than if for each case.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81335130
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ *
+ * @see #asQuad(Statement)
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public static RDF4JQuad asQuad(final Statement statement, UUID salt) {
+ return new QuadImpl(statement, salt);
+ }
+
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @param value The RDF4J {@link Value} to convert.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException if the value is not a BNode, Literal or IRI
+ */
+ public <T extends Value> RDF4JTerm<T> asRDFTerm(T value) {
+ return asRDFTerm(value, salt);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository) {
+ return new RepositoryDatasetImpl(repository);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred quads are included in the dataset
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository, boolean includeInferred) {
+ return new RepositoryDatasetImpl(repository, includeInferred);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}.
+ * <p>
+ * Changes to the graph are reflected in the model, and vice versa.
+ *
+ * @param model
+ * RDF4J {@link Model} to adapt.
+ * @return Adapted {@link Graph}.
+ */
+ public RDF4JGraph asRDFTermGraph(Model model) {
+ return new ModelGraphImpl(model);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository) {
+ return new RepositoryGraphImpl(repository, false, true);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred triples are included in the graph
+ * @param unionGraph
+ * If true, triples from any context is included in the graph,
+ * otherwise only triples in the default context
+ * <code>null</code>.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, boolean unionGraph) {
+ return new RepositoryGraphImpl(repository, includeInferred, unionGraph);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link Triple} or {@link Quad} as a RDF4J
+ * {@link Statement}.
+ * <p>
+ * If the <code>tripleLike</code> argument is an {@link RDF4JTriple} or
+ * a {@link RDF4JQuad}, then its {@link RDF4JTripleLike#asStatement()} is
+ * returned as-is. Note that this means that a {@link RDF4JTriple} would
+ * preserve its {@link Statement#getContext()}, and that any
+ * {@link BlankNode}s would be deemed equivalent in RDF4J
+ * if they have the same {@link BNode#getID()}.
+ *
+ * @param tripleLike
+ * A {@link Triple} or {@link Quad} to adapt
+ * @return A corresponding {@link Statement}
+ */
+ public Statement asStatement(TripleLike<BlankNodeOrIRI, org.apache.commons.rdf.api.IRI, RDFTerm> tripleLike) {
+ if (tripleLike instanceof RDF4JTripleLike) {
+ // Return original statement - this covers both RDF4JQuad and
+ // RDF4JTriple
+ RDF4JTripleLike rdf4jTriple = (RDF4JTripleLike) tripleLike;
+ return rdf4jTriple.asStatement();
+ }
+
+ org.eclipse.rdf4j.model.Resource subject = (org.eclipse.rdf4j.model.Resource) asValue(tripleLike.getSubject());
+ org.eclipse.rdf4j.model.IRI predicate = (org.eclipse.rdf4j.model.IRI) asValue(tripleLike.getPredicate());
+ Value object = asValue(tripleLike.getObject());
+
+ org.eclipse.rdf4j.model.Resource context = null;
+ if (tripleLike instanceof Quad) {
+ Quad quad = (Quad) tripleLike;
+ context = (org.eclipse.rdf4j.model.Resource) asValue(quad.getGraphName().orElse(null));
+ }
+
+ return getValueFactory().createStatement(subject, predicate, object, context);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this method will use an
+ * internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J statements from multiple
+ * repositories or models, then their {@link BNode}s may have the same
+ * {@link BNode#getID()}, which with this method would become equivalent
+ * according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()}, unless a separate
+ * {@link RDF4JTermFactory} instance is used per RDF4J repository/model.
+ *
+ * @param statement
+ * The RDF4J {@link Statement} to adapt.
+ * @return A {@link RDF4JTriple} that is equivalent to the statement
+ */
+ public RDF4JTriple asTriple(final Statement statement) {
+ return new TripleImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link RDFTerm} as a RDF4J {@link Value}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.apache.commons.rdf.api.BlankNode} is converted to a
+ * {@link org.eclipse.rdf4j.model.BNode}, a
+ * {@link org.apache.commons.rdf.api.IRI} is converted to a
+ * {@link org.eclipse.rdf4j.model.IRI} and a
+ * {@link org.apache.commons.rdf.api.Literal} is converted to a
+ * {@link org.eclipse.rdf4j.model.Literal}.
+ * <p>
+ * If the provided {@link RDFTerm} is <code>null</code>, then the returned
+ * value is <code>null</code>.
+ * <p>
+ * If the provided term is an instance of {@link RDF4JTerm}, then the
+ * {@link RDF4JTerm#asValue()} is returned without any conversion. Note that
+ * this could mean that a {@link Value} from a different kind of
+ * {@link ValueFactory} could be returned.
+ *
+ * @param term
+ * RDFTerm to adapt to RDF4J Value
+ * @return Adapted RDF4J {@link Value}
+ */
+ public Value asValue(RDFTerm term) {
+ if (term == null) {
+ return null;
+ }
+ if (term instanceof RDF4JTerm) {
+ // One of our own - avoid converting again.
+ // (This is crucial to avoid double-escaping in BlankNode)
+ return ((RDF4JTerm<?>) term).asValue();
+ }
+ if (term instanceof org.apache.commons.rdf.api.IRI) {
+ org.apache.commons.rdf.api.IRI iri = (org.apache.commons.rdf.api.IRI) term;
+ return getValueFactory().createIRI(iri.getIRIString());
+ }
+ if (term instanceof org.apache.commons.rdf.api.Literal) {
+ org.apache.commons.rdf.api.Literal literal = (org.apache.commons.rdf.api.Literal) term;
+ String label = literal.getLexicalForm();
+ if (literal.getLanguageTag().isPresent()) {
+ String lang = literal.getLanguageTag().get();
+ return getValueFactory().createLiteral(label, lang);
+ }
+ org.eclipse.rdf4j.model.IRI dataType = (org.eclipse.rdf4j.model.IRI) asValue(literal.getDatatype());
+ return getValueFactory().createLiteral(label, dataType);
+ }
+ if (term instanceof BlankNode) {
+ // This is where it gets tricky to support round trips!
+ BlankNode blankNode = (BlankNode) term;
+ // FIXME: The uniqueReference might not be a valid BlankNode
+ // identifier..
+ // does it have to be in RDF4J?
--- End diff --
OK, I'll remove the `FIXME` and let you know if anything explodes :)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81248439
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JDataset.java ---
@@ -0,0 +1,30 @@
+/**
+ * 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;
+
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.api.Quad;
+
+
+/**
+ * Marker interface for RDF4J implementations of Dataset.
+ *
+ */
+public interface RDF4JDataset extends Dataset, RDF4JGraphLike<Quad> {
--- End diff --
Not having been around CommonsRDF for a while, I wasn't familiar with GraphLike. What is the distinction between that and Dataset?
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82311315
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java ---
@@ -0,0 +1,232 @@
+/**
+ * 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.experimental;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFSyntax;
+import org.apache.commons.rdf.experimental.RDFParser;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNodeOrIRI;
+import org.apache.commons.rdf.rdf4j.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.simple.experimental.AbstractRDFParser;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.util.RDFInserter;
+import org.eclipse.rdf4j.repository.util.RDFLoader;
+import org.eclipse.rdf4j.rio.ParserConfig;
+import org.eclipse.rdf4j.rio.RDFFormat;
+import org.eclipse.rdf4j.rio.RDFHandler;
+import org.eclipse.rdf4j.rio.RDFHandlerException;
+import org.eclipse.rdf4j.rio.Rio;
+import org.eclipse.rdf4j.rio.helpers.AbstractRDFHandler;
+
+/**
+ * RDF4J-based parser.
+ * <p>
+ * This can handle the RDF syntaxes {@link RDFSyntax#JSONLD},
+ * {@link RDFSyntax#NQUADS}, {@link RDFSyntax#NTRIPLES},
+ * {@link RDFSyntax#RDFXML}, {@link RDFSyntax#TRIG} and {@link RDFSyntax#TURTLE}
+ * - additional syntaxes can be supported by including the corresponding
+ * <em>rdf4j-rio-*</em> module on the classpath.
+ *
+ */
+public class RDF4JParser extends AbstractRDFParser<RDF4JParser> implements RDFParser {
--- End diff --
Why are you sending RDF4JParser upstream to its parent as a generics type? Particular interesting as Java does not have access to the generic type as a variable at runtime, so it cannot directly be used to enhance anything in the abstract class.
Everything that an abstract implementation of RDFParser could require must be in the RDFParser contract. If it requires anything else you need to modify the RDFParser contract.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82316729
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraphLike.java ---
@@ -0,0 +1,63 @@
+/**
+ * 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;
+
+import java.util.Optional;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.GraphLike;
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.TripleLike;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * Marker interface for RDF4J implementations of GraphLike.
+ *
+ * @see RDF4JGraph
+ *
+ */
+public interface RDF4JGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
--- End diff --
How about adding the following interfaces to Commons RDF API, rather than experimenting inside of the integration modules that is unhelpful in the long term for reuse of similar patterns. (Note that the appropriate generics type declarations such as "`T extends RDFTerm`" have not been added to the signatures below but they would be necessary in practice):
* `GeneralisedTriple<RDFTerm, RDFTerm, RDFTerm>`
* `GeneralisedQuad<BlankNodeOrIRI, RDFTerm, RDFTerm, RDFTerm> implements GeneralisedTriple<RDFTerm, RDFTerm, RDFTerm>`
* `Triple implements GeneralisedTriple<BlankNodeOrIRI, IRI, RDFTerm>`
* `Quad implements Triple, GeneralisedQuad<BlankNodeOrIRI, BlankNodeOrIRI, IRI, RDFTerm>`
* `GeneralisedGraph<GeneralisedTriple, RDFTerm, RDFTerm, RDFTerm>` (need the copied generic types for methods that don't just accept GeneralisedTriple)
* `GeneralisedDataset<GeneralisedQuad, BlankNodeOrIRI, RDFTerm, RDFTerm, RDFTerm>`
* `Graph implements GeneralisedGraph<Triple, BlankNodeOrIRI, IRI, RDFTerm>`
* `Dataset implements GeneralisedDataset<Quad, BlankNodeOrIRI, BlankNodeOrIRI, IRI, RDFTerm>`
The key is that the commonly reused interfaces `Triple`/`Quad`/`Graph`/`Dataset` now do not have the confusing "Like" suffix, and they have no generics arguments to remove an extra barrier to reuse. All implementations of Triple will be specialised subsets of GeneralisedTriple, so it doesn't seem to be an issue to uptake to represent the APIs this way.
Inheriting `Quad` from `Triple` and other similar instances isn't a design issue IMO, as correct code should be written to check `instanceof Quad` before it checks `instanceof Triple` if the user wants to preserve the dataset reference.
Even though Quad is not defined in terms of RDF-1.1, there will be no simple way to integrate with RDF4J without some version of it. It is also a commonly used term in the community, even if it didn't make it into the RDF-1.1 specification so it doesn't introduce new issues for understandability.
Implementing a Triple-level integration for RDF4J would not be a useful pursuit IMO given the background of the RDF4J Statement interface always having had a getContext method. I would prefer if this integration went just for `Quad<->Statement` translation in its initial versions to get it completed sooner rather than later.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81259579
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java ---
@@ -0,0 +1,134 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+public final class ModelGraphImpl implements RDF4JGraph {
+
+ private Model model;
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ public ModelGraphImpl(Model model) {
+ this.model = model;
+ this.rdf4jTermFactory = new RDF4JTermFactory();
+ }
+
+ public ModelGraphImpl(Model model, RDF4JTermFactory rdf4jTermFactory) {
+ this.model = model;
+ this.rdf4jTermFactory = rdf4jTermFactory;
+ }
+
+ @Override
+ public void add(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.add(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void add(Triple triple) {
+ model.add(rdf4jTermFactory.asStatement(triple));
+ }
+
+ public Optional<Model> asModel() {
+ return Optional.of(model);
+ }
+
+ @Override
+ public Optional<Repository> asRepository() {
+ return Optional.empty();
+ }
+
+ @Override
+ public void clear() {
+ model.clear();
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.contains(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public boolean contains(Triple triple) {
+ return model.contains(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.remove(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void remove(Triple triple) {
+ model.remove(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public long size() {
+ int size = model.size();
+ if (size < Integer.MAX_VALUE) {
+ return size;
+ } else {
+ // TODO: Check if this can really happen with RDF4J models
+ // Collection.size() can't help us, we'll have to count
+ return model.parallelStream().count();
--- End diff --
I doubt it is possible or practical for in-memory implementations of Model, but going over Integer.MAX_VALUE definitely occurs for Repository in some cases.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81323444
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraphLike.java ---
@@ -0,0 +1,63 @@
+/**
+ * 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;
+
+import java.util.Optional;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.GraphLike;
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.TripleLike;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * Marker interface for RDF4J implementations of GraphLike.
+ *
+ * @see RDF4JGraph
+ *
+ */
+public interface RDF4JGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
--- End diff --
Yeah, it's tricky because Java does not have the equivalent of `owl:equivalentClass` and we wanted `TripleLike` to also be useful for generalized RDF (as in Jena - [createGeneralizedTriple](http://stain.github.io/incubator-commonsrdf/COMMONSRDF-35/org/apache/commons/rdf/jena/JenaRDFTermFactory.html#createGeneralizedTriple-org.apache.commons.rdf.api.RDFTerm-org.apache.commons.rdf.api.RDFTerm-org.apache.commons.rdf.api.RDFTerm-)).
so if we make:
```
public interface RDFTripleLike extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm> {}
```
then that would simplify uses like `RDF4JGraphLike` (both Graph and Dataset requires the those RDF types for s/p/o), but it would mean you could not do "upcasting" from `TripleLike`:
```
TripleLike<BlankNodeOrIRI, IRI, RDFTerm> t; // get from outside
rdfThingie.write((RDFTripleLike)t);
```
So `TripleLike` would then be a bit more pointless than it is now for most users :)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81260255
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java ---
@@ -0,0 +1,192 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JQuad;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryDatasetImpl extends AbstractRepositoryGraphLike<Quad> implements RDF4JDataset, Dataset {
+
+ public RepositoryDatasetImpl(Repository repository, boolean includeInferred) {
+ super(repository, includeInferred);
+ }
+
+ public RepositoryDatasetImpl(Repository repository) {
+ super(repository);
+ }
+
+
+ @Override
+ public void add(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred);
+ }
+ }
+
+ @Override
+ public void remove(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear();
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ if (includeInferred) {
+ // We'll need to count them all
+ return stream().count();
+ }
+ // else: Ask directly
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.size();
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ Resource context = (Resource) rdf4jTermFactory.asValue(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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, context);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contexts);
+ }
+ }
+
+ private Resource[] asContexts(Optional<BlankNodeOrIRI> graphName) {
+ Resource[] contexts;
+ if (graphName == null) {
+ // no contexts == any contexts
+ contexts = new Resource[0];
+ } else {
+ BlankNodeOrIRI g = graphName.orElse(null);
+ Resource context = (Resource) rdf4jTermFactory.asValue(g);
+ contexts = new Resource[] { context };
+ }
+ return contexts;
+ }
+
+ @Override
+ public void remove(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contexts);
+ conn.commit();
--- End diff --
committing after removing a single triple is likely to cause large performance issues in the long term.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81666841
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java ---
@@ -0,0 +1,137 @@
+/**
+ * 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.Collections;
+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.RDFTerm;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNodeOrIRI;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+public final class ModelGraphImpl implements RDF4JGraph {
+
+ private Model model;
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ public ModelGraphImpl(Model model) {
+ this.model = model;
+ this.rdf4jTermFactory = new RDF4JTermFactory();
+ }
+
+ public ModelGraphImpl(Model model, RDF4JTermFactory rdf4jTermFactory) {
+ this.model = model;
+ this.rdf4jTermFactory = rdf4jTermFactory;
+ }
+
+ @Override
+ public void add(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.add(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void add(Triple triple) {
+ model.add(rdf4jTermFactory.asStatement(triple));
+ }
+
+ public Optional<Model> asModel() {
+ return Optional.of(model);
+ }
+
+ @Override
+ public Optional<Repository> asRepository() {
+ return Optional.empty();
+ }
+
+ @Override
+ public void clear() {
+ model.clear();
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.contains(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public boolean contains(Triple triple) {
+ return model.contains(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.remove(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void remove(Triple triple) {
+ model.remove(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public long size() {
+ int size = model.size();
+ if (size < Integer.MAX_VALUE) {
+ return size;
+ } else {
+ // TODO: Check if this can really happen with RDF4J models
+ // Collection.size() can't help us, we'll have to count
+ return model.parallelStream().count();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream() {
+ return model.parallelStream().map(rdf4jTermFactory::asTriple);
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.filter(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object)).parallelStream()
+ .map(rdf4jTermFactory::asTriple);
+ }
+
+ @Override
+ public Set<RDF4JBlankNodeOrIRI<Resource>> getContextMask() {
+ // ModelGraph always do the unionGraph
+ return Collections.emptySet();
+ // TODO: Should we support contextMask like in RepositoryGraphImpl?
--- End diff --
Yes, Model's always contain Quads in RDF4J, so would definitely be useful to operate on them the same as Repository.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81662340
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java ---
@@ -0,0 +1,206 @@
+/**
+ * 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.experimental;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFSyntax;
+import org.apache.commons.rdf.experimental.RDFParser;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNodeOrIRI;
+import org.apache.commons.rdf.rdf4j.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.simple.experimental.AbstractRDFParser;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.util.RDFInserter;
+import org.eclipse.rdf4j.repository.util.RDFLoader;
+import org.eclipse.rdf4j.rio.ParserConfig;
+import org.eclipse.rdf4j.rio.RDFFormat;
+import org.eclipse.rdf4j.rio.RDFHandler;
+import org.eclipse.rdf4j.rio.RDFHandlerException;
+import org.eclipse.rdf4j.rio.Rio;
+import org.eclipse.rdf4j.rio.helpers.AbstractRDFHandler;
+
+/**
+ * RDF4J-based parser.
+ * <p>
+ * This can handle the RDF syntaxes {@link RDFSyntax#JSONLD},
+ * {@link RDFSyntax#NQUADS}, {@link RDFSyntax#NTRIPLES},
+ * {@link RDFSyntax#RDFXML}, {@link RDFSyntax#TRIG} and {@link RDFSyntax#TURTLE}
+ * - additional syntaxes can be supported by including the corresponding
+ * <em>rdf4j-rio-*</em> module on the classpath.
+ *
+ */
+public class RDF4JParser extends AbstractRDFParser<RDF4JParser> implements RDFParser {
+
+ private final class AddToQuadConsumer extends AbstractRDFHandler {
+ private final Consumer<Quad> quadTarget;
+
+ private AddToQuadConsumer(Consumer<Quad> quadTarget) {
+ this.quadTarget = quadTarget;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ // TODO: if getRdfTermFactory() is a non-rdf4j factory, should
+ // we use factory.createQuad() instead?
+ // Unsure what is the promise of setting getRdfTermFactory() --
+ // does it go all the way down to creating BlankNode, IRI and
+ // Literal?
+ quadTarget.accept(rdf4jTermFactory.asQuad(st));
+ // Performance note:
+ // Graph/Quad.add should pick up again our
+ // RDF4JGraphLike.asStatement()
+ // and avoid double conversion.
+ // Additionally the RDF4JQuad and RDF4JTriple implementations
+ // are lazily converting subj/obj/pred/graph.s
+ }
+ }
+
+ private final static class AddToModel extends AbstractRDFHandler {
+ private final Model model;
+
+ public AddToModel(Model model) {
+ this.model = model;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ model.add(st);
+ }
+
+ @Override
+ public void handleNamespace(String prefix, String uri) throws RDFHandlerException {
+ model.setNamespace(prefix, uri);
+ }
+ }
+
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ @Override
+ protected RDF4JTermFactory createRDFTermFactory() {
+ return new RDF4JTermFactory();
+ }
+
+ @Override
+ protected RDF4JParser prepareForParsing() throws IOException, IllegalStateException {
+ RDF4JParser c = prepareForParsing();
+ // Ensure we have an RDF4JTermFactory for conversion.
+ // We'll make a new one if user has provided a non-RDF4J factory
+ c.rdf4jTermFactory = (RDF4JTermFactory) getRdfTermFactory().filter(RDF4JTermFactory.class::isInstance)
+ .orElseGet(c::createRDFTermFactory);
+ return c;
+ }
+
+ @Override
+ protected void parseSynchronusly() throws IOException {
--- End diff --
Note that RDF4J has an internal implementation of parseAsynchronously using a Queue that takes an RDFParser and an InputStream as its main inputs, if there are other possible implementations here that are async:
https://github.com/eclipse/rdf4j/blob/master/core/http/client/src/main/java/org/eclipse/rdf4j/http/client/BackgroundGraphResult.java
Note that it is currently in the http-client module, but it has no reliance on a particular InputStream implementation so we could move it out of that package into rio-api if necessary to support it easily here.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81328382
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JIRI.java ---
@@ -0,0 +1,35 @@
+/**
+ * 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;
+
+/**
+ * Marker interface for RDF4J implementations of IRI.
+ *
+ */
+public interface RDF4JIRI
+ extends RDF4JTerm<org.eclipse.rdf4j.model.IRI>, org.apache.commons.rdf.api.IRI {
+
+ /**
+ * Return the corresponding RDF4J {@link org.eclipse.rdf4j.model.IRI}.
+ *
+ * @return The corresponding RDF4J IRI
+ */
+ public org.eclipse.rdf4j.model.IRI asValue();
--- End diff --
http://www.javapractices.com/topic/TopicAction.do?Id=17 says
>
If you extend a concrete class, and add a new field which contributes to equals, then it's not possible to write a perfectly correct equals method for the new class. Instead, you should use composition instead of inheritance. (See Effective Java by Joshua Bloch for more information.)
So in Commons RDF and RDF4J it's possible to do such inheritance because both have a defined `.equals()` - however that is also what prevents them from being directly compatible in `RDF4JIRI`. Thus `RDF4JIRIImpl` uses composition.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81254180
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java ---
@@ -0,0 +1,197 @@
+/**
+ * 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.experimental;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFSyntax;
+import org.apache.commons.rdf.experimental.RDFParser;
+import org.apache.commons.rdf.rdf4j.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.simple.experimental.AbstractRDFParser;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.repository.util.RDFInserter;
+import org.eclipse.rdf4j.repository.util.RDFLoader;
+import org.eclipse.rdf4j.rio.ParserConfig;
+import org.eclipse.rdf4j.rio.RDFFormat;
+import org.eclipse.rdf4j.rio.RDFHandler;
+import org.eclipse.rdf4j.rio.RDFHandlerException;
+import org.eclipse.rdf4j.rio.Rio;
+import org.eclipse.rdf4j.rio.helpers.AbstractRDFHandler;
+
+/**
+ * RDF4J-based parser.
+ * <p>
+ * This can handle the RDF syntaxes {@link RDFSyntax#JSONLD},
+ * {@link RDFSyntax#NQUADS}, {@link RDFSyntax#NTRIPLES},
+ * {@link RDFSyntax#RDFXML}, {@link RDFSyntax#TRIG} and {@link RDFSyntax#TURTLE}
+ * - additional syntaxes can be supported by including the corresponding
+ * <em>rdf4j-rio-*</em> module on the classpath.
+ *
+ */
+public class RDF4JParser extends AbstractRDFParser<RDF4JParser> implements RDFParser {
+
+ private final class AddToQuadConsumer extends AbstractRDFHandler {
+ private final Consumer<Quad> quadTarget;
+
+ private AddToQuadConsumer(Consumer<Quad> quadTarget) {
+ this.quadTarget = quadTarget;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ // TODO: if getRdfTermFactory() is a non-rdf4j factory, should
+ // we use factory.createQuad() instead?
+ // Unsure what is the promise of setting getRdfTermFactory() --
+ // does it go all the way down to creating BlankNode, IRI and
+ // Literal?
+ quadTarget.accept(rdf4jTermFactory.asQuad(st));
+ // Performance note:
+ // Graph/Quad.add should pick up again our
+ // RDF4JGraphLike.asStatement()
+ // and avoid double conversion.
+ // Additionally the RDF4JQuad and RDF4JTriple implementations
+ // are lazily converting subj/obj/pred/graph.s
+ }
+ }
+
+ private final static class AddToModel extends AbstractRDFHandler {
+ private final Model model;
+
+ public AddToModel(Model model) {
+ this.model = model;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ model.add(st);
+ }
+
+ @Override
+ public void handleNamespace(String prefix, String uri) throws RDFHandlerException {
+ model.setNamespace(prefix, uri);
+ }
+ }
+
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ @Override
+ protected RDF4JTermFactory createRDFTermFactory() {
+ return new RDF4JTermFactory();
+ }
+
+ @Override
+ protected RDF4JParser prepareForParsing() throws IOException, IllegalStateException {
+ RDF4JParser c = prepareForParsing();
+ // Ensure we have an RDF4JTermFactory for conversion.
+ // We'll make a new one if user has provided a non-RDF4J factory
+ c.rdf4jTermFactory = (RDF4JTermFactory) getRdfTermFactory().filter(RDF4JTermFactory.class::isInstance)
+ .orElseGet(c::createRDFTermFactory);
+ return c;
+ }
+
+ @Override
+ protected void parseSynchronusly() throws IOException {
+ Optional<RDFFormat> formatByMimeType = getContentType().flatMap(Rio::getParserFormatForMIMEType);
+ String base = getBase().map(IRI::getIRIString).orElse(null);
+
+ ParserConfig parserConfig = new ParserConfig();
+ // TODO: Should we need to set anything?
--- End diff --
The ParserConfig above needs to be exposed if you want configurability. It is guaranteed to be threadsafe (uses ConcurrentHashMap internally, but if you are still able to find thread-safety bugs then I will fix them), so you can have it as an instance variable that the user can access and mutate as necessary.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82310244
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java ---
@@ -0,0 +1,232 @@
+/**
+ * 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.experimental;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFSyntax;
+import org.apache.commons.rdf.experimental.RDFParser;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNodeOrIRI;
+import org.apache.commons.rdf.rdf4j.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.simple.experimental.AbstractRDFParser;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.util.RDFInserter;
+import org.eclipse.rdf4j.repository.util.RDFLoader;
+import org.eclipse.rdf4j.rio.ParserConfig;
+import org.eclipse.rdf4j.rio.RDFFormat;
+import org.eclipse.rdf4j.rio.RDFHandler;
+import org.eclipse.rdf4j.rio.RDFHandlerException;
+import org.eclipse.rdf4j.rio.Rio;
+import org.eclipse.rdf4j.rio.helpers.AbstractRDFHandler;
+
+/**
+ * RDF4J-based parser.
+ * <p>
+ * This can handle the RDF syntaxes {@link RDFSyntax#JSONLD},
+ * {@link RDFSyntax#NQUADS}, {@link RDFSyntax#NTRIPLES},
+ * {@link RDFSyntax#RDFXML}, {@link RDFSyntax#TRIG} and {@link RDFSyntax#TURTLE}
+ * - additional syntaxes can be supported by including the corresponding
+ * <em>rdf4j-rio-*</em> module on the classpath.
+ *
+ */
+public class RDF4JParser extends AbstractRDFParser<RDF4JParser> implements RDFParser {
+
+ private final class AddToQuadConsumer extends AbstractRDFHandler {
+ private final Consumer<Quad> quadTarget;
+
+ private AddToQuadConsumer(Consumer<Quad> quadTarget) {
+ this.quadTarget = quadTarget;
+ }
+
+ public void handleStatement(org.eclipse.rdf4j.model.Statement st)
+ throws org.eclipse.rdf4j.rio.RDFHandlerException {
+ // TODO: if getRdfTermFactory() is a non-rdf4j factory, should
--- End diff --
This comment seems to have been nullified by the use of RDF4JTermFactory as the type for the instance variable.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82313531
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,603 @@
+/**
+ * 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;
+
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI, Literal)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.InternalRDF4JFactory;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.sail.SailRepository;
+import org.eclipse.rdf4j.sail.Sail;
+import org.eclipse.rdf4j.sail.memory.MemoryStore;
+
+/**
+ * RDF4J implementation of RDFTermFactory.
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally.
+ *
+ */
+public final class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * InternalRDF4JFactory is deliberately abstract
+ */
+ private static InternalRDF4JFactory rdf4j = new InternalRDF4JFactory() {
+ };
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) rdf4j.createBlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) rdf4j.createLiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) rdf4j.createIRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ private final UUID salt;
+
+ private final ValueFactory valueFactory;
+
+ /**
+ * Construct an {@link RDF4JTermFactory}.
+ *
+ */
+ public RDF4JTermFactory() {
+ this(SimpleValueFactory.getInstance(), UUID.randomUUID());
+ }
+
+ /**
+ * Construct an {@link RDF4JTermFactory}.
+ * <p>
+ * This constructor is intended for use with the value factory from
+ * {@link Repository#getValueFactory()} when using
+ * Repository-based graphs and datasets.
+ *
+ * @param valueFactory
+ * The RDF4J {@link ValueFactory} to use
+ */
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this(valueFactory, UUID.randomUUID());
+ }
+
+ /**
+ * Construct an {@link RDF4JTermFactory}.
+ * <p>
+ * This constructor may be used if reproducible
+ * {@link BlankNode#uniqueReference()} in {@link BlankNode} is desirable.
+ *
+ * @param salt
+ * An {@link UUID} salt to be used by any created
+ * {@link BlankNode}s for the purpose of
+ * {@link BlankNode#uniqueReference()}
+ */
+ public RDF4JTermFactory(UUID salt) {
+ this(SimpleValueFactory.getInstance(), salt);
+ }
+ /**
+ * Construct an {@link RDF4JTermFactory}.
+ * <p>
+ * This constructor may be used if reproducible
+ * {@link BlankNode#uniqueReference()} in {@link BlankNode} is desirable.
+ *
+ * @param valueFactory
+ * The RDF4J {@link ValueFactory} to use
+ * @param salt
+ * An {@link UUID} salt to be used by any created
+ * {@link BlankNode}s for the purpose of
+ * {@link BlankNode#uniqueReference()}
+ */
+ public RDF4JTermFactory(ValueFactory valueFactory, UUID salt) {
+ this.valueFactory = valueFactory;
+ this.salt = salt;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this method will use an
+ * internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s multiple
--- End diff --
This is not a theoretical issue for RDF4J users. They are already aware of how and when BNode identities are preserved across graphs, per the historical Sesame model and more recently the RDF-1.1 Dataset model.
Commenting on it here, particularly with a "strong" markup label, as if it is an unusual condition isn't helpful. I would remove it and just leave the simple statement in the paragraph above.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81251599
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
--- End diff --
It is likely to cause issues that there are also static methods that accept an arbitrary salt UUID, while this uses an internal private salt that is almost guaranteed (as far as practicable, which is the reasoning behind UUID) to be different to anything the user submits to the other methods.
It may prevent errors in the future if there are only instance methods for these operations, so that the state (the salt, essentially) can be maintained privately and not flow into user code.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82421109
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JLiteral.java ---
@@ -0,0 +1,35 @@
+/**
+ * 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;
+
+import org.eclipse.rdf4j.model.Literal;
+
+/**
+ * Marker interface for RDF4J implementations of Literal.
+ *
+ */
+public interface RDF4JLiteral
+ extends RDF4JTerm<org.eclipse.rdf4j.model.Literal>, org.apache.commons.rdf.api.Literal {
+
+ /**
+ * Return the corresponding RDF4J {@link org.eclipse.rdf4j.model.Literal}.
+ *
+ * @return The corresponding RDF4J Literal
+ */
+ Literal asValue();
--- End diff --
Done :-)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82312854
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,603 @@
+/**
+ * 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;
+
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI, Literal)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.InternalRDF4JFactory;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.sail.SailRepository;
+import org.eclipse.rdf4j.sail.Sail;
+import org.eclipse.rdf4j.sail.memory.MemoryStore;
+
+/**
+ * RDF4J implementation of RDFTermFactory.
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally.
+ *
+ */
+public final class RDF4JTermFactory implements RDFTermFactory {
--- End diff --
This shouldn't be final by default. This will limit reuse without any particular reason. It also makes some of the extension methods that seem to allow other implementations of this seem a little strange.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82312544
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,603 @@
+/**
+ * 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;
+
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI, Literal)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.api.Quad;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.InternalRDF4JFactory;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.sail.SailRepository;
+import org.eclipse.rdf4j.sail.Sail;
+import org.eclipse.rdf4j.sail.memory.MemoryStore;
+
+/**
+ * RDF4J implementation of RDFTermFactory.
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally.
+ *
+ */
+public final class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * InternalRDF4JFactory is deliberately abstract
--- End diff --
This javadoc doesn't help explain the existence of this variable and hinders comprehension of the class as a whole. Ie, why is the implementation split up like this, and why should any class be deliberately abstract without having any abstract methods.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81672271
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRepositoryGraphLike.java ---
@@ -0,0 +1,80 @@
+/**
+ * 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.Optional;
+
+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.TripleLike;
+import org.apache.commons.rdf.rdf4j.RDF4JGraphLike;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+
+public abstract class AbstractRepositoryGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
+ implements RDF4JGraphLike<T> {
+
+ protected Repository repository;
+ protected boolean includeInferred;
+ protected boolean shouldWeShutdown = false;
+ protected RDF4JTermFactory rdf4jTermFactory;
+
+ public AbstractRepositoryGraphLike(Repository repository) {
+ this(repository, false);
+ }
+
+ public AbstractRepositoryGraphLike(Repository repository, boolean includeInferred) {
+ this.repository = repository;
+ this.includeInferred = includeInferred;
+ if (!repository.isInitialized()) {
--- End diff --
I've changed the constructors to not shutdown by default.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81590765
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java ---
@@ -0,0 +1,164 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+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.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements Graph, RDF4JGraph {
+
+ private final Resource[] contextFilter;
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, boolean unionGraph) {
+ super(repository, includeInferred);
+ if (unionGraph) {
+ // no context filter aka any context
+ this.contextFilter = new Resource[] { };
+ } else {
+ // default context: null
+ this.contextFilter = new Resource[] { null };
+ }
+ }
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, Resource... contextFilter) {
+ super(repository, includeInferred);
+ this.contextFilter = contextFilter;
+ }
+
+
+ @Override
+ public void add(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement, contextFilter);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred, contextFilter);
+ }
+ }
+
+ @Override
+ public void remove(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement, contextFilter);
+ conn.commit();
--- End diff --
Perhaps some kind of `ThreadLocal` or transaction argument..?
Or ask for a `TransactionGraph` that only does `.commit()` on `.close()`?
Is a `RepositoryConnection` thread safe, or would I need `ThreadLocal`s?
I think it might be weird if the `Graph` out of the box didn't autocommit as the other implementations do - so optimizing for faster should be something you do explicitly (Commons RDF does not know how you manage your threads)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81340071
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java ---
@@ -0,0 +1,134 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+public final class ModelGraphImpl implements RDF4JGraph {
+
+ private Model model;
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ public ModelGraphImpl(Model model) {
+ this.model = model;
+ this.rdf4jTermFactory = new RDF4JTermFactory();
+ }
+
+ public ModelGraphImpl(Model model, RDF4JTermFactory rdf4jTermFactory) {
+ this.model = model;
+ this.rdf4jTermFactory = rdf4jTermFactory;
+ }
+
+ @Override
+ public void add(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.add(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void add(Triple triple) {
+ model.add(rdf4jTermFactory.asStatement(triple));
+ }
+
+ public Optional<Model> asModel() {
+ return Optional.of(model);
+ }
+
+ @Override
+ public Optional<Repository> asRepository() {
+ return Optional.empty();
--- End diff --
So the suggestion is to rather document `UnsupportedOperationException` on both - and eventually get to always supporting both methods? (In which case `Optional` would be silly)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81249803
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JQuad.java ---
@@ -0,0 +1,28 @@
+/**
+ * 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;
+
+import org.apache.commons.rdf.api.Quad;
+
+/**
+ * Marker interface for RDF4J implementations of Quad.
+ *
+ */
+public interface RDF4JQuad extends Quad, RDF4JTripleLike {
--- End diff --
Why is a quad inheriting from a TripleLike? Wouldn't that cause issues with attempting to determine if something is a Quad or a Triple?
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81590851
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java ---
@@ -0,0 +1,164 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+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.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements Graph, RDF4JGraph {
+
+ private final Resource[] contextFilter;
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, boolean unionGraph) {
--- End diff --
I agree, I'll reduce the "constructor space".
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82317108
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraphLike.java ---
@@ -0,0 +1,63 @@
+/**
+ * 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;
+
+import java.util.Optional;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.GraphLike;
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.TripleLike;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * Marker interface for RDF4J implementations of GraphLike.
+ *
+ * @see RDF4JGraph
+ *
+ */
+public interface RDF4JGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
+ extends GraphLike<T, BlankNodeOrIRI, IRI, RDFTerm>, AutoCloseable {
+
+ /**
+ * Return the corresponding RDF4J {@link Model}, if present.
+ * <p>
+ * The return value is {@link Optional#isPresent()} if this is backed by a
+ * Model.
+ * <p>
+ * Changes to the Model are reflected in both directions.
+ *
+ * @return The corresponding RDF4J Model.
+ */
+ public Optional<Model> asModel();
+
+ /**
+ * Return the corresponding RDF4J {@link Repository}, if present.
+ * <p>
+ * The return value is {@link Optional#isPresent()} if this is backed by a
+ * Repository.
--- End diff --
The return value isn't `Optional.isPresent()`. It will return `true` for `Optional.isPresent()` and `Optional.get()` will then need to be called to get the underlying `Repository`. Easier to refer to `Optional.empty()` as the return value when it is not backed by a `Repository`.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81672500
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java ---
@@ -0,0 +1,192 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JQuad;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryDatasetImpl extends AbstractRepositoryGraphLike<Quad> implements RDF4JDataset, Dataset {
+
+ public RepositoryDatasetImpl(Repository repository, boolean includeInferred) {
+ super(repository, includeInferred);
+ }
+
+ public RepositoryDatasetImpl(Repository repository) {
+ super(repository);
+ }
+
+
+ @Override
+ public void add(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred);
+ }
+ }
+
+ @Override
+ public void remove(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear();
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ if (includeInferred) {
+ // We'll need to count them all
+ return stream().count();
+ }
+ // else: Ask directly
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.size();
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ Resource context = (Resource) rdf4jTermFactory.asValue(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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, context);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contexts);
+ }
+ }
+
+ private Resource[] asContexts(Optional<BlankNodeOrIRI> graphName) {
+ Resource[] contexts;
+ if (graphName == null) {
+ // no contexts == any contexts
+ contexts = new Resource[0];
+ } else {
+ BlankNodeOrIRI g = graphName.orElse(null);
+ Resource context = (Resource) rdf4jTermFactory.asValue(g);
+ contexts = new Resource[] { context };
+ }
+ return contexts;
+ }
+
+ @Override
+ public void remove(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contexts);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JQuad> stream() {
+ return stream(null, null, null, null);
+ }
+
+ @Override
+ public Stream<RDF4JQuad> stream(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ RepositoryConnection conn = getRepositoryConnection();
+ // NOTE: connection will be closed outside by the Iterations.stream()
+ RepositoryResult<Statement> statements = conn.getStatements(subj, pred, obj, includeInferred, contexts);
--- End diff --
No, I was wrong.. the stream does close the `RepositoryResult`, but the repository result does not therefore close the connection (which makes sense).
This cause the unit test to be slow shutting down (it takes 20 seconds before it times out on open connections)
I added `stream.onClose(conn::close)` which closed it correctly given regular try..with blocks outside.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81591788
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java ---
@@ -0,0 +1,192 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JQuad;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryDatasetImpl extends AbstractRepositoryGraphLike<Quad> implements RDF4JDataset, Dataset {
+
+ public RepositoryDatasetImpl(Repository repository, boolean includeInferred) {
+ super(repository, includeInferred);
+ }
+
+ public RepositoryDatasetImpl(Repository repository) {
+ super(repository);
+ }
+
+
+ @Override
+ public void add(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred);
+ }
+ }
+
+ @Override
+ public void remove(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear();
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ if (includeInferred) {
+ // We'll need to count them all
+ return stream().count();
+ }
+ // else: Ask directly
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.size();
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ Resource context = (Resource) rdf4jTermFactory.asValue(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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, context);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contexts);
+ }
+ }
+
+ private Resource[] asContexts(Optional<BlankNodeOrIRI> graphName) {
+ Resource[] contexts;
+ if (graphName == null) {
+ // no contexts == any contexts
+ contexts = new Resource[0];
+ } else {
+ BlankNodeOrIRI g = graphName.orElse(null);
+ Resource context = (Resource) rdf4jTermFactory.asValue(g);
+ contexts = new Resource[] { context };
+ }
+ return contexts;
+ }
+
+ @Override
+ public void remove(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contexts);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JQuad> stream() {
+ return stream(null, null, null, null);
+ }
+
+ @Override
+ public Stream<RDF4JQuad> stream(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ RepositoryConnection conn = getRepositoryConnection();
+ // NOTE: connection will be closed outside by the Iterations.stream()
+ RepositoryResult<Statement> statements = conn.getStatements(subj, pred, obj, includeInferred, contexts);
--- End diff --
The Stream is consumed outside and is closable.. shall we just add this to the javadoc of `RDF4JGraph.stream()` that use of the stream must be closed (e.g. try-with-resources)? (Note that this is not really true in `ModelGraph`)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81335041
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ *
+ * @see #asQuad(Statement)
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public static RDF4JQuad asQuad(final Statement statement, UUID salt) {
+ return new QuadImpl(statement, salt);
+ }
+
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @param value The RDF4J {@link Value} to convert.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException if the value is not a BNode, Literal or IRI
+ */
+ public <T extends Value> RDF4JTerm<T> asRDFTerm(T value) {
+ return asRDFTerm(value, salt);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository) {
+ return new RepositoryDatasetImpl(repository);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred quads are included in the dataset
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository, boolean includeInferred) {
+ return new RepositoryDatasetImpl(repository, includeInferred);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}.
+ * <p>
+ * Changes to the graph are reflected in the model, and vice versa.
+ *
+ * @param model
+ * RDF4J {@link Model} to adapt.
+ * @return Adapted {@link Graph}.
+ */
+ public RDF4JGraph asRDFTermGraph(Model model) {
+ return new ModelGraphImpl(model);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository) {
+ return new RepositoryGraphImpl(repository, false, true);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred triples are included in the graph
+ * @param unionGraph
+ * If true, triples from any context is included in the graph,
+ * otherwise only triples in the default context
+ * <code>null</code>.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, boolean unionGraph) {
+ return new RepositoryGraphImpl(repository, includeInferred, unionGraph);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link Triple} or {@link Quad} as a RDF4J
+ * {@link Statement}.
+ * <p>
+ * If the <code>tripleLike</code> argument is an {@link RDF4JTriple} or
+ * a {@link RDF4JQuad}, then its {@link RDF4JTripleLike#asStatement()} is
+ * returned as-is. Note that this means that a {@link RDF4JTriple} would
+ * preserve its {@link Statement#getContext()}, and that any
+ * {@link BlankNode}s would be deemed equivalent in RDF4J
+ * if they have the same {@link BNode#getID()}.
+ *
+ * @param tripleLike
+ * A {@link Triple} or {@link Quad} to adapt
+ * @return A corresponding {@link Statement}
+ */
+ public Statement asStatement(TripleLike<BlankNodeOrIRI, org.apache.commons.rdf.api.IRI, RDFTerm> tripleLike) {
+ if (tripleLike instanceof RDF4JTripleLike) {
+ // Return original statement - this covers both RDF4JQuad and
+ // RDF4JTriple
+ RDF4JTripleLike rdf4jTriple = (RDF4JTripleLike) tripleLike;
+ return rdf4jTriple.asStatement();
+ }
+
+ org.eclipse.rdf4j.model.Resource subject = (org.eclipse.rdf4j.model.Resource) asValue(tripleLike.getSubject());
+ org.eclipse.rdf4j.model.IRI predicate = (org.eclipse.rdf4j.model.IRI) asValue(tripleLike.getPredicate());
+ Value object = asValue(tripleLike.getObject());
+
+ org.eclipse.rdf4j.model.Resource context = null;
+ if (tripleLike instanceof Quad) {
+ Quad quad = (Quad) tripleLike;
+ context = (org.eclipse.rdf4j.model.Resource) asValue(quad.getGraphName().orElse(null));
+ }
+
+ return getValueFactory().createStatement(subject, predicate, object, context);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this method will use an
+ * internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J statements from multiple
+ * repositories or models, then their {@link BNode}s may have the same
+ * {@link BNode#getID()}, which with this method would become equivalent
+ * according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()}, unless a separate
+ * {@link RDF4JTermFactory} instance is used per RDF4J repository/model.
+ *
+ * @param statement
+ * The RDF4J {@link Statement} to adapt.
+ * @return A {@link RDF4JTriple} that is equivalent to the statement
+ */
+ public RDF4JTriple asTriple(final Statement statement) {
+ return new TripleImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link RDFTerm} as a RDF4J {@link Value}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.apache.commons.rdf.api.BlankNode} is converted to a
+ * {@link org.eclipse.rdf4j.model.BNode}, a
+ * {@link org.apache.commons.rdf.api.IRI} is converted to a
+ * {@link org.eclipse.rdf4j.model.IRI} and a
+ * {@link org.apache.commons.rdf.api.Literal} is converted to a
+ * {@link org.eclipse.rdf4j.model.Literal}.
+ * <p>
+ * If the provided {@link RDFTerm} is <code>null</code>, then the returned
+ * value is <code>null</code>.
+ * <p>
+ * If the provided term is an instance of {@link RDF4JTerm}, then the
+ * {@link RDF4JTerm#asValue()} is returned without any conversion. Note that
+ * this could mean that a {@link Value} from a different kind of
+ * {@link ValueFactory} could be returned.
+ *
+ * @param term
+ * RDFTerm to adapt to RDF4J Value
+ * @return Adapted RDF4J {@link Value}
+ */
+ public Value asValue(RDFTerm term) {
+ if (term == null) {
+ return null;
+ }
+ if (term instanceof RDF4JTerm) {
+ // One of our own - avoid converting again.
+ // (This is crucial to avoid double-escaping in BlankNode)
+ return ((RDF4JTerm<?>) term).asValue();
+ }
+ if (term instanceof org.apache.commons.rdf.api.IRI) {
+ org.apache.commons.rdf.api.IRI iri = (org.apache.commons.rdf.api.IRI) term;
+ return getValueFactory().createIRI(iri.getIRIString());
+ }
+ if (term instanceof org.apache.commons.rdf.api.Literal) {
+ org.apache.commons.rdf.api.Literal literal = (org.apache.commons.rdf.api.Literal) term;
+ String label = literal.getLexicalForm();
+ if (literal.getLanguageTag().isPresent()) {
+ String lang = literal.getLanguageTag().get();
+ return getValueFactory().createLiteral(label, lang);
+ }
+ org.eclipse.rdf4j.model.IRI dataType = (org.eclipse.rdf4j.model.IRI) asValue(literal.getDatatype());
+ return getValueFactory().createLiteral(label, dataType);
+ }
+ if (term instanceof BlankNode) {
+ // This is where it gets tricky to support round trips!
--- End diff --
I tested rdf4j-to-rdf4j roundtrip as part of the [integration-test branch](https://github.com/apache/incubator-commonsrdf/blob/jena-jsonld-rdf4j-integration/integration-tests/src/test/java/org/apache/commons/rdf/integrationtests/AllToAllTest.java).
I think the roundtrip could break if you pass blanknodes between:
* rdf4j
* jena
* rdf4j
as you would loose the .uniqueReference() and/or `.ntriplesString()` along the way. I think if we want to support that scenario we would have to go deeper, e.g. have UUID-based blanknode labels and try our best to recognize them again.
(The JSONLD-Java `RDFTermFactory` [does this](https://github.com/apache/incubator-commonsrdf/blob/jsonld-java/jsonld-java/src/main/java/org/apache/commons/rdf/jsonldjava/JsonLdRDFTermFactory.java#L98) by recognizing the prefix in the unique reference)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81678453
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
--- End diff --
I've removed all except `asValue(Node, UUID)` in the factory. This is needed from `Quad` and `Triple` as they (at least now) generate on demand their RDFTerm instances of getSubject() etc.
Not sure why `java.util.UUID` is considered brittle, it's immutable. :-) I think now with the constructors hidden it's minimized how to 'do the wrong thing'. I added javadoc for the RDF4JTermFactory constructor
If `Triple` and `Quad` instead keep the `RDF4JTermFactory` it means they also hold a reference to the `ValueFactory` (which they don't need) - remember a Triple or Quad is what could make itself way into "other" code and so I wanted them to have as little references as possible.
A `java.util.UUID` is quite a small object (final class, two longs) - and if for some reason needed, the code could even be optimized to keep those longs directly in the QuadImpl/TripleImpl. Or they could cache/pregenerate their getSubject/getPredicate/getObject() and not need any of the references-- it's hard to tell at this stage what is the best optimization.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81324930
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JIRI.java ---
@@ -0,0 +1,35 @@
+/**
+ * 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;
+
+/**
+ * Marker interface for RDF4J implementations of IRI.
+ *
+ */
+public interface RDF4JIRI
+ extends RDF4JTerm<org.eclipse.rdf4j.model.IRI>, org.apache.commons.rdf.api.IRI {
+
+ /**
+ * Return the corresponding RDF4J {@link org.eclipse.rdf4j.model.IRI}.
+ *
+ * @return The corresponding RDF4J IRI
+ */
+ public org.eclipse.rdf4j.model.IRI asValue();
--- End diff --
`RDF4JIRI` is not an instance of `org.eclipse.rdf4j.model.IRI` **and** `org.apache.commons.rdf.api.IRI` - however it's a `RDF4JTerm` specialization with the rdf4j `IRI` as its [encapsulated field](https://github.com/apache/incubator-commonsrdf/blob/06711f9c2832609680b9775de39456b5b2b71ccb/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRDFTerm.java).
It's an interesting idea to make `RDF4JIRI` implement both interfaces - but then we would be violating the `false` definition for Commons RDF [IRI.equals()](http://stain.github.io/incubator-commonsrdf/COMMONSRDF-35/org/apache/commons/rdf/api/IRI.html#equals-java.lang.Object-) and [RDF4J IRI.equals()](http://rdf4j.org/javadoc/2.0/org/eclipse/rdf4j/model/IRI.html#equals-java.lang.Object-) -- perhaps both definitions could be loosened to only define the `true` case and be open-ended - but it means you could have:
```java
org.eclipse.rdf4j.model.IRI a; // from regular RDF4j
org.apache.commons.rdf.rdf4j.RDF4JIRI b; // from RDF4JTermFactory
org.apache.commons.rdf.api.IRI c; // from JenaRDFTermFactory
```
and equalities:
```java
assert a.equals(b);
assert b.equals(a);
assert b.equals(c);
assert c.equals(b);
```
but confusingly NOT
```java
org.eclipse.rdf4j.model.IRI a; // from regular RDF4j
org.apache.commons.rdf.rdf4j.RDF4JIRI b; // from RDF4JTermFactory
org.apache.commons.rdf.api.IRI c; // from JenaRDFTermFactory
assert a.equals(c);
assert c.equals(a);
```
which could lead to fun behaviour in say a HashMap..
To support it properly I think we would need to make `org.eclipse.rdf4j.model.IRI` extend `org.apache.commons.rdf.api.IRI` directly.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81252333
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JLiteral.java ---
@@ -0,0 +1,35 @@
+/**
+ * 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;
+
+import org.eclipse.rdf4j.model.Literal;
+
+/**
+ * Marker interface for RDF4J implementations of Literal.
+ *
+ */
+public interface RDF4JLiteral
+ extends RDF4JTerm<org.eclipse.rdf4j.model.Literal>, org.apache.commons.rdf.api.Literal {
+
+ /**
+ * Return the corresponding RDF4J {@link org.eclipse.rdf4j.model.Literal}.
+ *
+ * @return The corresponding RDF4J Literal
+ */
+ Literal asValue();
--- End diff --
Ditto for this looking like a null override (ie, doesn't change what RDF4JTerm already allowed).
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81338553
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/BlankNodeImpl.java ---
@@ -0,0 +1,93 @@
+/**
+ * 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.nio.charset.StandardCharsets;
+import java.util.UUID;
+
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.rdf4j.RDF4JBlankNode;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.rio.turtle.TurtleUtil;
+
+public final class BlankNodeImpl extends AbstractRDFTerm<BNode>
+ implements RDF4JBlankNode {
+
+ private transient int hashCode = 0;
+ private long saltUUIDleast;
+ private long saltUUIDmost;
+
+ public BlankNodeImpl(BNode bNode, UUID salt) {
+ super(bNode);
+ // Space-efficient storage of salt UUID
+ saltUUIDmost = salt.getMostSignificantBits();
+ saltUUIDleast = salt.getLeastSignificantBits();
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ // NOTE: Do NOT use Bnode.equals() as it has a more generous
+ // equality based only on the value.getID();
+ if (obj instanceof BlankNode) {
+ BlankNode blankNode = (BlankNode) obj;
+ return uniqueReference().equals(blankNode.uniqueReference());
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ if (hashCode != 0) {
+ return hashCode;
+ }
+ return hashCode = uniqueReference().hashCode();
+ }
+
+ private boolean isValidBlankNodeLabel(String id) {
+ // FIXME: Replace with a regular expression?
+ if (id.isEmpty()) {
+ return false;
+ }
+ if (! TurtleUtil.isBLANK_NODE_LABEL_StartChar(id.codePointAt(0))) {
--- End diff --
Not sure what is the "API" or not in the various modules of RDF4J.. how can we document that more clearly? Using `.impl` packages often is a good hint.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81321953
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JDataset.java ---
@@ -0,0 +1,30 @@
+/**
+ * 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;
+
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.api.Quad;
+
+
+/**
+ * Marker interface for RDF4J implementations of Dataset.
+ *
+ */
+public interface RDF4JDataset extends Dataset, RDF4JGraphLike<Quad> {
--- End diff --
[GraphLike](http://stain.github.io/incubator-commonsrdf/COMMONSRDF-35/org/apache/commons/rdf/api/GraphLike.html) is the common interface between `Graph` and `Dataset` - operating over `TripleLike` entries.
This is mainly useful for general code that can deal with both graph and dataset (e.g. a parser/writer that iterates over `TripleLike`) - a `Graph` and `Dataset` would have different equality semantics on operations like `.contains()` and `remove()`.
We might not need a corresponding [RDF4JGraphLike](http://stain.github.io/incubator-commonsrdf/COMMONSRDF-35/org/apache/commons/rdf/rdf4j/RDF4JGraphLike.html) - it exposes `.asModel()` and `asRepository()`.
Internally in `rdf4j/` there's an abstract class [AbstractRepositoryGraphLike](http://stain.github.io/incubator-commonsrdf/COMMONSRDF-35/org/apache/commons/rdf/rdf4j/impl/AbstractRepositoryGraphLike.html) which shares the code of [RepositoryDatasetImpl](http://stain.github.io/incubator-commonsrdf/COMMONSRDF-35/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.html) (implementing `Dataset`) and [RepositoryGraphImpl](http://stain.github.io/incubator-commonsrdf/COMMONSRDF-35/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.html) (implementing `Graph`).
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81334041
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ *
+ * @see #asQuad(Statement)
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public static RDF4JQuad asQuad(final Statement statement, UUID salt) {
+ return new QuadImpl(statement, salt);
+ }
+
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @param value The RDF4J {@link Value} to convert.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException if the value is not a BNode, Literal or IRI
+ */
+ public <T extends Value> RDF4JTerm<T> asRDFTerm(T value) {
+ return asRDFTerm(value, salt);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository) {
+ return new RepositoryDatasetImpl(repository);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred quads are included in the dataset
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository, boolean includeInferred) {
+ return new RepositoryDatasetImpl(repository, includeInferred);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}.
+ * <p>
+ * Changes to the graph are reflected in the model, and vice versa.
+ *
+ * @param model
+ * RDF4J {@link Model} to adapt.
+ * @return Adapted {@link Graph}.
+ */
+ public RDF4JGraph asRDFTermGraph(Model model) {
+ return new ModelGraphImpl(model);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository) {
+ return new RepositoryGraphImpl(repository, false, true);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred triples are included in the graph
+ * @param unionGraph
+ * If true, triples from any context is included in the graph,
+ * otherwise only triples in the default context
+ * <code>null</code>.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, boolean unionGraph) {
+ return new RepositoryGraphImpl(repository, includeInferred, unionGraph);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link Triple} or {@link Quad} as a RDF4J
+ * {@link Statement}.
+ * <p>
+ * If the <code>tripleLike</code> argument is an {@link RDF4JTriple} or
+ * a {@link RDF4JQuad}, then its {@link RDF4JTripleLike#asStatement()} is
+ * returned as-is. Note that this means that a {@link RDF4JTriple} would
+ * preserve its {@link Statement#getContext()}, and that any
+ * {@link BlankNode}s would be deemed equivalent in RDF4J
+ * if they have the same {@link BNode#getID()}.
+ *
+ * @param tripleLike
+ * A {@link Triple} or {@link Quad} to adapt
+ * @return A corresponding {@link Statement}
+ */
+ public Statement asStatement(TripleLike<BlankNodeOrIRI, org.apache.commons.rdf.api.IRI, RDFTerm> tripleLike) {
+ if (tripleLike instanceof RDF4JTripleLike) {
+ // Return original statement - this covers both RDF4JQuad and
+ // RDF4JTriple
+ RDF4JTripleLike rdf4jTriple = (RDF4JTripleLike) tripleLike;
+ return rdf4jTriple.asStatement();
+ }
+
+ org.eclipse.rdf4j.model.Resource subject = (org.eclipse.rdf4j.model.Resource) asValue(tripleLike.getSubject());
+ org.eclipse.rdf4j.model.IRI predicate = (org.eclipse.rdf4j.model.IRI) asValue(tripleLike.getPredicate());
+ Value object = asValue(tripleLike.getObject());
+
+ org.eclipse.rdf4j.model.Resource context = null;
+ if (tripleLike instanceof Quad) {
+ Quad quad = (Quad) tripleLike;
+ context = (org.eclipse.rdf4j.model.Resource) asValue(quad.getGraphName().orElse(null));
+ }
+
+ return getValueFactory().createStatement(subject, predicate, object, context);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this method will use an
+ * internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J statements from multiple
+ * repositories or models, then their {@link BNode}s may have the same
+ * {@link BNode#getID()}, which with this method would become equivalent
+ * according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()}, unless a separate
+ * {@link RDF4JTermFactory} instance is used per RDF4J repository/model.
+ *
+ * @param statement
+ * The RDF4J {@link Statement} to adapt.
+ * @return A {@link RDF4JTriple} that is equivalent to the statement
+ */
+ public RDF4JTriple asTriple(final Statement statement) {
+ return new TripleImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link RDFTerm} as a RDF4J {@link Value}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.apache.commons.rdf.api.BlankNode} is converted to a
+ * {@link org.eclipse.rdf4j.model.BNode}, a
+ * {@link org.apache.commons.rdf.api.IRI} is converted to a
+ * {@link org.eclipse.rdf4j.model.IRI} and a
+ * {@link org.apache.commons.rdf.api.Literal} is converted to a
+ * {@link org.eclipse.rdf4j.model.Literal}.
+ * <p>
+ * If the provided {@link RDFTerm} is <code>null</code>, then the returned
+ * value is <code>null</code>.
+ * <p>
+ * If the provided term is an instance of {@link RDF4JTerm}, then the
+ * {@link RDF4JTerm#asValue()} is returned without any conversion. Note that
+ * this could mean that a {@link Value} from a different kind of
+ * {@link ValueFactory} could be returned.
+ *
+ * @param term
+ * RDFTerm to adapt to RDF4J Value
+ * @return Adapted RDF4J {@link Value}
+ */
+ public Value asValue(RDFTerm term) {
+ if (term == null) {
+ return null;
+ }
+ if (term instanceof RDF4JTerm) {
--- End diff --
Here of course the order is crucial as it needs to catch `RDF4JTerm` first.
I feel my style is less "nested". They are semantically the same as each `if` block does a `return`.
..but there's the danger that in the future someone edits an if-block and accidentally don't `return` (it would fall through to `throw new IllegalArgumentException`) - so I'll change to a more classical `if.. else if .. else if.. else` blocks.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81252832
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ *
+ * @see #asQuad(Statement)
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public static RDF4JQuad asQuad(final Statement statement, UUID salt) {
+ return new QuadImpl(statement, salt);
+ }
+
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @param value The RDF4J {@link Value} to convert.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException if the value is not a BNode, Literal or IRI
+ */
+ public <T extends Value> RDF4JTerm<T> asRDFTerm(T value) {
+ return asRDFTerm(value, salt);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository) {
+ return new RepositoryDatasetImpl(repository);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred quads are included in the dataset
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository, boolean includeInferred) {
+ return new RepositoryDatasetImpl(repository, includeInferred);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}.
+ * <p>
+ * Changes to the graph are reflected in the model, and vice versa.
+ *
+ * @param model
+ * RDF4J {@link Model} to adapt.
+ * @return Adapted {@link Graph}.
+ */
+ public RDF4JGraph asRDFTermGraph(Model model) {
+ return new ModelGraphImpl(model);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository) {
+ return new RepositoryGraphImpl(repository, false, true);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred triples are included in the graph
+ * @param unionGraph
+ * If true, triples from any context is included in the graph,
+ * otherwise only triples in the default context
+ * <code>null</code>.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, boolean unionGraph) {
+ return new RepositoryGraphImpl(repository, includeInferred, unionGraph);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link Triple} or {@link Quad} as a RDF4J
+ * {@link Statement}.
+ * <p>
+ * If the <code>tripleLike</code> argument is an {@link RDF4JTriple} or
+ * a {@link RDF4JQuad}, then its {@link RDF4JTripleLike#asStatement()} is
+ * returned as-is. Note that this means that a {@link RDF4JTriple} would
+ * preserve its {@link Statement#getContext()}, and that any
+ * {@link BlankNode}s would be deemed equivalent in RDF4J
+ * if they have the same {@link BNode#getID()}.
+ *
+ * @param tripleLike
+ * A {@link Triple} or {@link Quad} to adapt
+ * @return A corresponding {@link Statement}
+ */
+ public Statement asStatement(TripleLike<BlankNodeOrIRI, org.apache.commons.rdf.api.IRI, RDFTerm> tripleLike) {
+ if (tripleLike instanceof RDF4JTripleLike) {
+ // Return original statement - this covers both RDF4JQuad and
+ // RDF4JTriple
+ RDF4JTripleLike rdf4jTriple = (RDF4JTripleLike) tripleLike;
--- End diff --
This would look a little simpler if you did the cast inline below instead of creating a temporary variable here. The compiler or JVM will likely optimise the variable away so no actual difference in practice, just not usual to cast to a variable for one operation.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81259365
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java ---
@@ -0,0 +1,134 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+public final class ModelGraphImpl implements RDF4JGraph {
+
+ private Model model;
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ public ModelGraphImpl(Model model) {
+ this.model = model;
+ this.rdf4jTermFactory = new RDF4JTermFactory();
+ }
+
+ public ModelGraphImpl(Model model, RDF4JTermFactory rdf4jTermFactory) {
+ this.model = model;
+ this.rdf4jTermFactory = rdf4jTermFactory;
+ }
+
+ @Override
+ public void add(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.add(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void add(Triple triple) {
+ model.add(rdf4jTermFactory.asStatement(triple));
+ }
+
+ public Optional<Model> asModel() {
+ return Optional.of(model);
+ }
+
+ @Override
+ public Optional<Repository> asRepository() {
+ return Optional.empty();
+ }
+
+ @Override
+ public void clear() {
+ model.clear();
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.contains(
--- End diff --
Does this method currently work for all BlankNodes (or is it documented to be precarious in those situations)? Ie. is it tested to work in all of the various corner cases for BNode to BlankNode conversion/wrapping or are their known and declared cases where it isn't expected to work consistently.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81252063
--- Diff: rdf4j/pom.xml ---
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-rdf-parent</artifactId>
+ <version>0.3.0-incubating-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>commons-rdf-rdf4j</artifactId>
+ <packaging>jar</packaging>
+ <properties>
+ <rdf4j.version>2.0</rdf4j.version>
+ </properties>
+
+ <name>Commons RDF: Integration: RDF4j</name>
+ <description>Eclipse RDF4j implementation of Commons RDF API</description>
+
+ <build>
+ <plugins>
+ <plugin>
+
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <!-- Not sure why this is needed, .impl and .internal is normally hidden
+ by the Bundle Plugin.. -->
+
+ <Export-Package>org.apache.commons.rdf.rdf4j</Export-Package>
+ <Private-Package>org.apache.commons.rdf.rdf4j.impl</Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>commons-rdf-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.parent.groupId}</groupId>
+ <artifactId>commons-rdf-simple</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- Selected rdf4j dependencies We don't use rdf4j-runtime or rdf4j-runtime-osgi
+ here, as they pull in various depenencies like lucene, which might not be
+ needed. -->
+
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-model</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-repository-api</artifactId>
+ </dependency>
+
+ <!-- For RDF4JParserBuilder, these are the RIO dependencies for the standard
+ RDF 1.1 languages -->
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-turtle</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-ntriples</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-nquads</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-rdfxml</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-trig</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.rdf4j</groupId>
+ <artifactId>rdf4j-rio-jsonld</artifactId>
+ </dependency>
+ <!-- Languages notably missing, and why:
--- End diff --
This reasoning seems a little tenuous for an integration module, but if that is your preference then that is fine. Users typically pull in any others that they require specifically themselves anyway.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81342717
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java ---
@@ -0,0 +1,192 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.RDF4JDataset;
+import org.apache.commons.rdf.rdf4j.RDF4JQuad;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryDatasetImpl extends AbstractRepositoryGraphLike<Quad> implements RDF4JDataset, Dataset {
+
+ public RepositoryDatasetImpl(Repository repository, boolean includeInferred) {
+ super(repository, includeInferred);
+ }
+
+ public RepositoryDatasetImpl(Repository repository) {
+ super(repository);
+ }
+
+
+ @Override
+ public void add(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred);
+ }
+ }
+
+ @Override
+ public void remove(Quad tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear();
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ if (includeInferred) {
+ // We'll need to count them all
+ return stream().count();
+ }
+ // else: Ask directly
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.size();
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ Resource context = (Resource) rdf4jTermFactory.asValue(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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, context);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contexts);
+ }
+ }
+
+ private Resource[] asContexts(Optional<BlankNodeOrIRI> graphName) {
+ Resource[] contexts;
+ if (graphName == null) {
+ // no contexts == any contexts
+ contexts = new Resource[0];
+ } else {
+ BlankNodeOrIRI g = graphName.orElse(null);
+ Resource context = (Resource) rdf4jTermFactory.asValue(g);
+ contexts = new Resource[] { context };
+ }
+ return contexts;
+ }
+
+ @Override
+ public void remove(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ Resource[] contexts = asContexts(graphName);
+
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contexts);
+ conn.commit();
--- End diff --
How can we support having the transaction on the "outside" of the `Graph` / `Dataset`..? ADd some kind of `.begin()` and `.end()` method?
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82317429
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JIRI.java ---
@@ -0,0 +1,35 @@
+/**
+ * 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;
+
+/**
+ * Marker interface for RDF4J implementations of IRI.
+ *
+ */
+public interface RDF4JIRI
+ extends RDF4JTerm<org.eclipse.rdf4j.model.IRI>, org.apache.commons.rdf.api.IRI {
+
+ /**
+ * Return the corresponding RDF4J {@link org.eclipse.rdf4j.model.IRI}.
+ *
+ * @return The corresponding RDF4J IRI
+ */
+ public org.eclipse.rdf4j.model.IRI asValue();
--- End diff --
See my comment about removing the generics parameter from RDF4JTerm so it would no longer be a null override, but would be using typical Java return value extension to redefine the return value. That would simplify understanding here IMO, with "asValue" returning "IRI", but having no reason to have to pass that on to the super interface, as the heirarchy already matches the Value->IRI heirarchy from RDF4J so should work smoothly.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81665039
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRepositoryGraphLike.java ---
@@ -0,0 +1,80 @@
+/**
+ * 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.Optional;
+
+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.TripleLike;
+import org.apache.commons.rdf.rdf4j.RDF4JGraphLike;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+
+public abstract class AbstractRepositoryGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
+ implements RDF4JGraphLike<T> {
+
+ protected Repository repository;
+ protected boolean includeInferred;
+ protected boolean shouldWeShutdown = false;
+ protected RDF4JTermFactory rdf4jTermFactory;
+
+ public AbstractRepositoryGraphLike(Repository repository) {
+ this(repository, false);
+ }
+
+ public AbstractRepositoryGraphLike(Repository repository, boolean includeInferred) {
+ this.repository = repository;
+ this.includeInferred = includeInferred;
+ if (!repository.isInitialized()) {
+ repository.initialize();
+ shouldWeShutdown = true;
+ }
+ rdf4jTermFactory = new RDF4JTermFactory(repository.getValueFactory());
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (shouldWeShutdown) {
+ repository.shutDown();
+ }
+ // else: repository was initialized outside, so we should not shut it
+ // down
+ }
+
+
+ protected abstract T asTripleLike(Statement s);
+
+ protected RepositoryConnection getRepositoryConnection() {
+ return repository.getConnection();
+ }
+
+ public Optional<Repository> asRepository() {
+ return Optional.of(repository);
+ }
+
+ @Override
+ public Optional<Model> asModel() {
+ return Optional.empty();
--- End diff --
Returning an Optional does work to do what you want here, in the absence of general implementations of ModelRepository and RepositoryModel to transparently represent one as the other.
You could use a hasFeatureX/hasFeatureY pattern to avoid exceptions, but Optional works well if the contract is clear about what Optional.empty() means.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r82312390
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTerm.java ---
@@ -0,0 +1,38 @@
+/**
+ * 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;
+
+import org.apache.commons.rdf.api.RDFTerm;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.IRI;
+import org.eclipse.rdf4j.model.Literal;
+import org.eclipse.rdf4j.model.Value;
+
+/**
+ * Marker interface for RDF4J implementations of RDFTerm.
+ *
+ */
+public interface RDF4JTerm<T extends Value> extends RDFTerm {
--- End diff --
This generics argument can never be accessed at runtime. Hence, it may be better to declare asValue as directly returning "Value" here. Then, in each of the 3-4 concrete classes that it can be implemented in, and which the user can use instanceof to match against, it can have a concrete return type that is a sub-interface of Value and can be used to enhance the variable without having any effect here. Ie, in RDF4J literal asValue can be changed to return Literal, without having generics confusing the situation.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81255159
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRepositoryGraphLike.java ---
@@ -0,0 +1,80 @@
+/**
+ * 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.Optional;
+
+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.TripleLike;
+import org.apache.commons.rdf.rdf4j.RDF4JGraphLike;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+
+public abstract class AbstractRepositoryGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
+ implements RDF4JGraphLike<T> {
+
+ protected Repository repository;
+ protected boolean includeInferred;
+ protected boolean shouldWeShutdown = false;
+ protected RDF4JTermFactory rdf4jTermFactory;
+
+ public AbstractRepositoryGraphLike(Repository repository) {
+ this(repository, false);
+ }
+
+ public AbstractRepositoryGraphLike(Repository repository, boolean includeInferred) {
+ this.repository = repository;
+ this.includeInferred = includeInferred;
+ if (!repository.isInitialized()) {
+ repository.initialize();
+ shouldWeShutdown = true;
+ }
+ rdf4jTermFactory = new RDF4JTermFactory(repository.getValueFactory());
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (shouldWeShutdown) {
+ repository.shutDown();
+ }
+ // else: repository was initialized outside, so we should not shut it
+ // down
+ }
+
+
+ protected abstract T asTripleLike(Statement s);
+
+ protected RepositoryConnection getRepositoryConnection() {
+ return repository.getConnection();
+ }
+
+ public Optional<Repository> asRepository() {
--- End diff --
Not sure why this is optional, as it doesn't use Optional.ofNullable internally and we never expect it to be null. An inline call to Objects.requireNotNull should be in the constructor as the guarantee.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81675667
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JDataset.java ---
@@ -0,0 +1,30 @@
+/**
+ * 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;
+
+import org.apache.commons.rdf.api.Dataset;
+import org.apache.commons.rdf.api.Quad;
+
+
+/**
+ * Marker interface for RDF4J implementations of Dataset.
+ *
+ */
+public interface RDF4JDataset extends Dataset, RDF4JGraphLike<Quad> {
--- End diff --
I think it would be possible to expand `ModelGraphImpl` to also support contexts and even a `ModelDataset` - so I'll add that to Jira.
I think it makes sense for now that it keeps the current behaviour which uses an empty varargs array underneath (aka the "union graph" or "disregarding contexts") - the first goal should be to have "equivalent" integration.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81342168
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/ModelGraphImpl.java ---
@@ -0,0 +1,134 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTermFactory;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+public final class ModelGraphImpl implements RDF4JGraph {
+
+ private Model model;
+ private RDF4JTermFactory rdf4jTermFactory;
+
+ public ModelGraphImpl(Model model) {
+ this.model = model;
+ this.rdf4jTermFactory = new RDF4JTermFactory();
+ }
+
+ public ModelGraphImpl(Model model, RDF4JTermFactory rdf4jTermFactory) {
+ this.model = model;
+ this.rdf4jTermFactory = rdf4jTermFactory;
+ }
+
+ @Override
+ public void add(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.add(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void add(Triple triple) {
+ model.add(rdf4jTermFactory.asStatement(triple));
+ }
+
+ public Optional<Model> asModel() {
+ return Optional.of(model);
+ }
+
+ @Override
+ public Optional<Repository> asRepository() {
+ return Optional.empty();
+ }
+
+ @Override
+ public void clear() {
+ model.clear();
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ return model.contains(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public boolean contains(Triple triple) {
+ return model.contains(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) {
+ model.remove(
+ (Resource)rdf4jTermFactory.asValue(subject),
+ (org.eclipse.rdf4j.model.IRI)rdf4jTermFactory.asValue(predicate),
+ rdf4jTermFactory.asValue(object));
+ }
+
+ @Override
+ public void remove(Triple triple) {
+ model.remove(rdf4jTermFactory.asStatement(triple));
+ }
+
+ @Override
+ public long size() {
+ int size = model.size();
+ if (size < Integer.MAX_VALUE) {
+ return size;
+ } else {
+ // TODO: Check if this can really happen with RDF4J models
+ // Collection.size() can't help us, we'll have to count
+ return model.parallelStream().count();
--- End diff --
Right.. so I shall I remove that edge case in `ModelGraphImpl` or could there be (in the future) a Model that is backed by a massive Repository?
BTW - the repository tries to ask `conn.size()` when it can:
https://github.com/apache/incubator-commonsrdf/blob/rdf4j/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryDatasetImpl.java#L86
https://github.com/apache/incubator-commonsrdf/blob/rdf4j/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java#L94
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81322365
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java ---
@@ -0,0 +1,66 @@
+/**
+ * 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;
+
+import java.util.Optional;
+
+import org.apache.commons.rdf.api.Graph;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.repository.Repository;
+
+
+/**
+ * Marker interface for RDF4J implementations of Graph.
+ *
+ * @see ModelGraphImpl
+ * @see RepositoryGraphImpl
+ */
+public interface RDF4JGraph extends Graph, RDF4JGraphLike<Triple> {
+
+ /**
+ * Return a copy of the context filter, if present.
+ * <p>
+ * If {@link Optional#isPresent()}, the filter determines which
+ * <em>contexts</em> in the corresponding RDF4J {@link Model} or
+ * {@link Repository} that this graph reflect. Modifications to the graph
+ * (e.g. {@link #add(Triple)} will be performed for all the specified
+ * contexts, while retrieval (e.g. {@link #contains(Triple)}) will succeed
+ * if the triple is in at least one of the specified contexts.
+ * <p>
+ * The context filter array may contain <code>null</code>, indicating the
+ * default context (the <em>default graph</em> in RDF datasets).
+ * <p>
+ * If the context filter is {@link Optional#empty()}, then this is a
+ * <em>union graph</em> which triples reflecting statements in any contexts.
+ * Triples added to the graph will be added in the default context
+ * <code>null</code>.
--- End diff --
Yes, this was very confusing from RDF4J's API as I am not sure where the nulls are allowed and how adding to the default graph should be best done - I understood it that it needs to be an a `new Resource[]{null}` array, not just `null`.
(When calling the varargs you would need to cast as `(Resource)null` or make the array explicitly to get it right)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81333230
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ *
+ * @see #asQuad(Statement)
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public static RDF4JQuad asQuad(final Statement statement, UUID salt) {
+ return new QuadImpl(statement, salt);
+ }
+
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @param value The RDF4J {@link Value} to convert.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException if the value is not a BNode, Literal or IRI
+ */
+ public <T extends Value> RDF4JTerm<T> asRDFTerm(T value) {
+ return asRDFTerm(value, salt);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository) {
+ return new RepositoryDatasetImpl(repository);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred quads are included in the dataset
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository, boolean includeInferred) {
+ return new RepositoryDatasetImpl(repository, includeInferred);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}.
+ * <p>
+ * Changes to the graph are reflected in the model, and vice versa.
+ *
+ * @param model
+ * RDF4J {@link Model} to adapt.
+ * @return Adapted {@link Graph}.
+ */
+ public RDF4JGraph asRDFTermGraph(Model model) {
+ return new ModelGraphImpl(model);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository) {
+ return new RepositoryGraphImpl(repository, false, true);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred triples are included in the graph
+ * @param unionGraph
+ * If true, triples from any context is included in the graph,
+ * otherwise only triples in the default context
+ * <code>null</code>.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, boolean unionGraph) {
+ return new RepositoryGraphImpl(repository, includeInferred, unionGraph);
+ }
+
+ /**
+ * Adapt a Commons RDF {@link Triple} or {@link Quad} as a RDF4J
+ * {@link Statement}.
+ * <p>
+ * If the <code>tripleLike</code> argument is an {@link RDF4JTriple} or
+ * a {@link RDF4JQuad}, then its {@link RDF4JTripleLike#asStatement()} is
+ * returned as-is. Note that this means that a {@link RDF4JTriple} would
+ * preserve its {@link Statement#getContext()}, and that any
+ * {@link BlankNode}s would be deemed equivalent in RDF4J
+ * if they have the same {@link BNode#getID()}.
+ *
+ * @param tripleLike
+ * A {@link Triple} or {@link Quad} to adapt
+ * @return A corresponding {@link Statement}
+ */
+ public Statement asStatement(TripleLike<BlankNodeOrIRI, org.apache.commons.rdf.api.IRI, RDFTerm> tripleLike) {
+ if (tripleLike instanceof RDF4JTripleLike) {
+ // Return original statement - this covers both RDF4JQuad and
+ // RDF4JTriple
+ RDF4JTripleLike rdf4jTriple = (RDF4JTripleLike) tripleLike;
--- End diff --
(You just found where `RDF4JTripleLike` is useful :)
Just a question of style I guess.. to avoid `()()` in
```java
((RDF4JTripleLike) tripleLike).asStatement()
```
the factory is long enough, so I'll go with your one-liner.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81666096
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/IRIImpl.java ---
@@ -0,0 +1,61 @@
+/**
+ * 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 org.apache.commons.rdf.rdf4j.RDF4JIRI;
+
+public final class IRIImpl extends AbstractRDFTerm<org.eclipse.rdf4j.model.IRI>
+ implements RDF4JIRI {
+
+ public IRIImpl(org.eclipse.rdf4j.model.IRI iri) {
+ super(iri);
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) { return true; }
+ if (obj instanceof IRIImpl) {
+ IRIImpl impl = (IRIImpl) obj;
+ return asValue().equals(impl.asValue());
+ }
+ if (obj instanceof org.apache.commons.rdf.api.IRI) {
+ org.apache.commons.rdf.api.IRI iri = (org.apache.commons.rdf.api.IRI) obj;
+ return value.toString().equals(iri.getIRIString());
+ }
+ return false;
+ }
+
+ @Override
+ public String getIRIString() {
+ return value.toString();
+ }
+
+ public int hashCode() {
+ // Same definition
+ return value.hashCode();
+ }
+
+ @Override
+ public String ntriplesString() {
+ return "<" + value.toString() + ">";
--- End diff --
RDFWriter implementations should always check IRI's for which characters they need to escape, however, this area is likely to have a lot of bugs, as it is principally fuzz tested given the scope (Unicode) cannot be thoroughly unit tested. the IRI.toString method isn't likely to be used directly, and in general RDF4J is fairly relaxed about what it supports (via RDFParserConfig settings) because some users prefer to be able to transport with irregular data rather than fail early.
My presumption here was that ntriplesString was designed to be more strict about what it emitted compared to the Object.toString override because it followed the rules of a particular concrete format, RDF-1.1 N-Triples.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81252575
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ *
+ * @see #asQuad(Statement)
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public static RDF4JQuad asQuad(final Statement statement, UUID salt) {
+ return new QuadImpl(statement, salt);
+ }
+
+
+ /**
+ *
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J values from
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @param value The RDF4J {@link Value} to convert.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException if the value is not a BNode, Literal or IRI
+ */
+ public <T extends Value> RDF4JTerm<T> asRDFTerm(T value) {
+ return asRDFTerm(value, salt);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository) {
+ return new RepositoryDatasetImpl(repository);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
+ * <p>
+ * Changes to the dataset are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred quads are included in the dataset
+ * @return A {@link Dataset} backed by the RDF4J repository.
+ */
+ public RDF4JDataset asRDFTermDataset(Repository repository, boolean includeInferred) {
+ return new RepositoryDatasetImpl(repository, includeInferred);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Model} as a Commons RDF {@link Graph}.
+ * <p>
+ * Changes to the graph are reflected in the model, and vice versa.
+ *
+ * @param model
+ * RDF4J {@link Model} to adapt.
+ * @return Adapted {@link Graph}.
+ */
+ public RDF4JGraph asRDFTermGraph(Model model) {
+ return new ModelGraphImpl(model);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository) {
+ return new RepositoryGraphImpl(repository, false, true);
+ }
+
+ /**
+ * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}.
+ * <p>
+ * The graph will include triples in any contexts (e.g. the union graph).
+ * <p>
+ * Changes to the graph are reflected in the repository, and vice versa.
+ *
+ * @param repository
+ * RDF4J {@link Repository} to connect to.
+ * @param includeInferred
+ * If true, any inferred triples are included in the graph
+ * @param unionGraph
+ * If true, triples from any context is included in the graph,
+ * otherwise only triples in the default context
+ * <code>null</code>.
+ * @return A {@link Graph} backed by the RDF4J repository.
+ */
+ public RDF4JGraph asRDFTermGraph(Repository repository, boolean includeInferred, boolean unionGraph) {
--- End diff --
UnionGraph isn't terminology that is used in RDF4J. What is stopping you from change this to Resource... (varargs) to match the RDF4J API?
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by ansell <gi...@git.apache.org>.
Github user ansell commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81260779
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/RepositoryGraphImpl.java ---
@@ -0,0 +1,164 @@
+/**
+ * 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.Optional;
+import java.util.stream.Stream;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+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.RDF4JGraph;
+import org.apache.commons.rdf.rdf4j.RDF4JTriple;
+import org.eclipse.rdf4j.common.iteration.Iterations;
+import org.eclipse.rdf4j.model.Resource;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.repository.Repository;
+import org.eclipse.rdf4j.repository.RepositoryConnection;
+import org.eclipse.rdf4j.repository.RepositoryResult;
+
+public class RepositoryGraphImpl extends AbstractRepositoryGraphLike<Triple> implements Graph, RDF4JGraph {
+
+ private final Resource[] contextFilter;
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, boolean unionGraph) {
+ super(repository, includeInferred);
+ if (unionGraph) {
+ // no context filter aka any context
+ this.contextFilter = new Resource[] { };
+ } else {
+ // default context: null
+ this.contextFilter = new Resource[] { null };
+ }
+ }
+
+ public RepositoryGraphImpl(Repository repository, boolean includeInferred, Resource... contextFilter) {
+ super(repository, includeInferred);
+ this.contextFilter = contextFilter;
+ }
+
+
+ @Override
+ public void add(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(statement, contextFilter);
+ conn.commit();
+ }
+ }
+
+
+ @Override
+ public boolean contains(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(statement, includeInferred, contextFilter);
+ }
+ }
+
+ @Override
+ public void remove(Triple tripleLike) {
+ Statement statement = rdf4jTermFactory.asStatement(tripleLike);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(statement, contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public void clear() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.clear(contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public long size() {
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ if (! includeInferred && contextFilter.length == 0) {
+ return conn.size();
+ } else {
+ return stream().count();
+ }
+ }
+ }
+
+
+ @Override
+ public void add(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.add(subj, pred, obj, contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public boolean contains(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ return conn.hasStatement(subj, pred, obj, includeInferred, contextFilter);
+ }
+ }
+
+ @Override
+ public void remove(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ try (RepositoryConnection conn = getRepositoryConnection()) {
+ conn.remove(subj, pred, obj, contextFilter);
+ conn.commit();
+ }
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream() {
+ return stream(null, null, null);
+ }
+
+ @Override
+ public Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, IRI predicate, RDFTerm object) {
+ 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);
+ RepositoryConnection conn = getRepositoryConnection();
+ // FIXME: Is it OK that we don't close the connection?
+ RepositoryResult<Statement> statements = conn.getStatements(subj, pred, obj, includeInferred, contextFilter);
--- End diff --
RepositoryResult must be closed consistently using try-with-resources rather than relying on close-on-exhaust that Iterations may trigger below.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81331455
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTermFactory.java ---
@@ -0,0 +1,509 @@
+/**
+ * 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;
+
+import java.util.UUID;
+
+// To avoid confusion, avoid importing
+// classes that are in both
+// commons.rdf and openrdf.model (e.g. IRI)
+import org.apache.commons.rdf.api.BlankNode;
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.Dataset;
+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.api.RDFTermFactory;
+import org.apache.commons.rdf.api.Triple;
+import org.apache.commons.rdf.api.TripleLike;
+import org.apache.commons.rdf.rdf4j.impl.BlankNodeImpl;
+import org.apache.commons.rdf.rdf4j.impl.IRIImpl;
+import org.apache.commons.rdf.rdf4j.impl.LiteralImpl;
+import org.apache.commons.rdf.rdf4j.impl.ModelGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.QuadImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryDatasetImpl;
+import org.apache.commons.rdf.rdf4j.impl.RepositoryGraphImpl;
+import org.apache.commons.rdf.rdf4j.impl.TripleImpl;
+import org.eclipse.rdf4j.model.BNode;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.model.Statement;
+import org.eclipse.rdf4j.model.Value;
+import org.eclipse.rdf4j.model.ValueFactory;
+import org.eclipse.rdf4j.model.impl.LinkedHashModel;
+import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * RDF4J implementation of RDFTermFactory
+ * <p>
+ * The {@link #RDF4JTermFactory()} constructor uses a {@link SimpleValueFactory}
+ * to create corresponding RDF4J {@link Value} instances. Alternatively, this
+ * factory can be constructed with a different {@link ValueFactory} using
+ * {@link #RDF4JTermFactory(ValueFactory)}.
+ * <p>
+ * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to
+ * an RDFTerm. Note that adapted {@link BNode}s are considered equal if they are
+ * converted with the same {@link RDF4JTermFactory} instance and have the same
+ * {@link BNode#getID()}.
+ * <p>
+ * {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
+ * To use other models, see {@link #asRDFTermGraph(Model)}.
+ * <p>
+ * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
+ * use {@link #asRDFTermDataset(Repository)} or
+ * {@link #asRDFTermGraph(Repository)}.
+ * <p>
+ * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement}
+ * to a Commons RDF {@link Triple}, and equivalent {@link #asQuad(Statement)} to
+ * convert a {@link Quad}.
+ * <p>
+ * To convert any {@link Triple} or {@link Quad} to to RDF4J {@link Statement},
+ * use {@link #asStatement(TripleLike)}. This recognises previously converted
+ * {@link RDF4JTriple}s and {@link RDF4JQuad}s without re-converting their
+ * {@link RDF4JTripleLike#asStatement()}.
+ * <p>
+ * Likewise, {@link #asValue(RDFTerm)} can be used to convert any Commons RDF
+ * {@link RDFTerm} to a corresponding RDF4J {@link Value}. This recognises
+ * previously converted {@link RDF4JTerm}s without re-converting their
+ * {@link RDF4JTerm#asValue()}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this factory contains an
+ * internal {@link UUID} salt that is used by adapter methods like
+ * {@link #asQuad(Statement)}, {@link #asTriple(Statement)},
+ * {@link #asRDFTerm(Value)} as well as {@link #createBlankNode(String)}. As
+ * RDF4J {@link BNode} instances from multiple repositories or models may have
+ * the same {@link BNode#getID()}, converting them with the above methods might
+ * cause accidental {@link BlankNode} equivalence. Note that the {@link Graph}
+ * and {@link Dataset} adapter methods like
+ * {@link #asRDFTermDataset(Repository)} and {@link #asRDFTermGraph(Model)}
+ * therefore uses a unique {@link RDF4JTermFactory} internally. An alternative
+ * is to use the static methods {@link #asRDFTerm(Value, UUID)},
+ * {@link #asQuad(Statement, UUID)} or {@link #asTriple(Statement, UUID)} with
+ * a provided {@link UUID} salt.
+ *
+ */
+public class RDF4JTermFactory implements RDFTermFactory {
+
+ /**
+ * Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
+ * <p>
+ * The value will be of the same kind as the term, e.g. a
+ * {@link org.eclipse.rdf4j.model.BNode} is converted to a
+ * {@link org.apache.commons.rdf.api.BlankNode}, a
+ * {@link org.eclipse.rdf4j.model.IRI} is converted to a
+ * {@link org.apache.commons.rdf.api.IRI} and a
+ * {@link org.eclipse.rdf4j.model.Literal}. is converted to a
+ * {@link org.apache.commons.rdf.api.Literal}
+ *
+ * @param value
+ * The RDF4J {@link Value} to convert.
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @param <T>
+ * The subclass of {@link Value}, e.g. {@link BNode}
+ * @return A {@link RDFTerm} that corresponds to the RDF4J value
+ * @throws IllegalArgumentException
+ * if the value is not a BNode, Literal or IRI
+ */
+ @SuppressWarnings("unchecked")
+ public static <T extends Value> RDF4JTerm<T> asRDFTerm(final T value, UUID salt) {
+ if (value instanceof BNode) {
+ return (RDF4JTerm<T>) new BlankNodeImpl((BNode) value, salt);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.Literal) {
+ return (RDF4JTerm<T>) new LiteralImpl((org.eclipse.rdf4j.model.Literal) value);
+ }
+ if (value instanceof org.eclipse.rdf4j.model.IRI) {
+ return (RDF4JTerm<T>) new IRIImpl((org.eclipse.rdf4j.model.IRI) value);
+ }
+ throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Triple}.
+ *
+ * @param statement
+ * The statement to convert
+ * @param salt
+ * A {@link UUID} salt to use for uniquely mapping any
+ * {@link BNode}s. The salt should typically be the same for
+ * multiple statements in the same {@link Repository} or
+ * {@link Model} to ensure {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()} works as intended.
+ * @return A {@link Triple} that corresponds to the RDF4J statement
+ */
+ public static RDF4JTriple asTriple(final Statement statement, UUID salt) {
+ return new TripleImpl(statement, salt);
+ }
+
+ private UUID salt = UUID.randomUUID();
+
+ private final ValueFactory valueFactory;
+
+ public RDF4JTermFactory() {
+ this.valueFactory = SimpleValueFactory.getInstance();
+ }
+
+ public RDF4JTermFactory(ValueFactory valueFactory) {
+ this.valueFactory = valueFactory;
+ }
+
+ /**
+ * Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
+ * <p>
+ * For the purpose of {@link BlankNode} equivalence, this
+ * method will use an internal salt UUID that is unique per instance of
+ * {@link RDF4JTermFactory}.
+ * <p>
+ * <strong>NOTE:</strong> If combining RDF4J {@link Statement}s
+ * multiple repositories or models, then their {@link BNode}s
+ * may have the same {@link BNode#getID()}, which with this method
+ * would become equivalent according to {@link BlankNode#equals(Object)} and
+ * {@link BlankNode#uniqueReference()},
+ * unless a separate {@link RDF4JTermFactory}
+ * instance is used per RDF4J repository/model.
+ *
+ * @see #asQuad(Statement, UUID)
+ * @param statement
+ * The statement to convert
+ * @return A {@link RDF4JQuad} that is equivalent to the statement
+ */
+ public RDF4JQuad asQuad(final Statement statement) {
+ return new QuadImpl(statement, salt);
--- End diff --
Yes, I think it would make more sense to hide the salt more and remove those static methods, perhaps have just a `RDF4JTermFactory(UUID)` constructor. Then the factory is not so locked into having to use UUID for salt.
_The reason to support a fixed `UUID` overall is if the user deliberately want them to be compatible - e.g. in a distributed architecture where two cloud instances are constructing named bnodes to be added to the same remote SAIL, or if you want reproducible output. (similar to fixed random seeds in simulations)._
I'll change it to just a constructor - removing the static methods will simplify the factory.
In the [JenaRDFTermFactory](http://stain.github.io/incubator-commonsrdf/integration/org/apache/commons/rdf/jena/JenaRDFTermFactory.html) there's a different approach which I'm not sure what your views are on - the static methods there allow any `RDFTermFactory` to be passed in (it would use the `createBlankNode(String)` directly)
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---
[GitHub] incubator-commonsrdf pull request #24: COMMONSRDF-35 Add rdf4j integration
Posted by stain <gi...@git.apache.org>.
Github user stain commented on a diff in the pull request:
https://github.com/apache/incubator-commonsrdf/pull/24#discussion_r81675157
--- Diff: rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraphLike.java ---
@@ -0,0 +1,63 @@
+/**
+ * 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;
+
+import java.util.Optional;
+
+import org.apache.commons.rdf.api.BlankNodeOrIRI;
+import org.apache.commons.rdf.api.GraphLike;
+import org.apache.commons.rdf.api.IRI;
+import org.apache.commons.rdf.api.RDFTerm;
+import org.apache.commons.rdf.api.TripleLike;
+import org.eclipse.rdf4j.model.Model;
+import org.eclipse.rdf4j.repository.Repository;
+
+/**
+ * Marker interface for RDF4J implementations of GraphLike.
+ *
+ * @see RDF4JGraph
+ *
+ */
+public interface RDF4JGraphLike<T extends TripleLike<BlankNodeOrIRI, IRI, RDFTerm>>
--- End diff --
`Triple` does inherit from `TripleLike<BlankNodeOrIRI, IRI, RDFTerm>` - that's the whole point :)
The only thing `RDFTripleLike` adds compared to `Triple` is the `asStatement()` method - which is probably useful for integration purposes.
But I think we could add a `GeneralizedTriple` interface to avoid exposure of `TripleLike` generics - but perhaps only to the jena module for now. JSONLD-Java should in theory also support that (as JSON-LD does) - at least having blank nodes for properties.
But I think that it can be hard - at least at this point - to say what is the "common generalized triple" at the API module.
---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---