
org.apache.commons.rdf.rdf4j.RDF4J Maven / Gradle / Ivy
Show all versions of commons-rdf-rdf4j Show documentation
/**
* 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.Arrays;
import java.util.EnumSet;
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.RDF;
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.IRI;
import org.eclipse.rdf4j.model.Literal;
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 RDF.
*
* The {@link #RDF4J()} 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 #RDF4J(ValueFactory)}.
*
* {@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 RDF4J} instance and have the same
* {@link BNode#getID()}.
*
* {@link #createGraph()} creates a new Graph backed by {@link LinkedHashModel}.
* To use other models, see {@link #asGraph(Model)}.
*
* To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph},
* use {@link #asDataset(Repository, Option...)} or
* {@link #asGraph(Repository, Option...)}.
*
* {@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}.
*
* 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()}.
*
* 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()}.
*
* 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 #asDataset(Repository, Option...)} and
* {@link #asGraph(Repository, Option...)} therefore uses a unique {@link RDF4J}
* internally.
*
* @see RDF
*
*/
public final class RDF4J implements RDF {
/**
* InternalRDF4JFactory is deliberately abstract
*/
private static InternalRDF4JFactory rdf4j = new InternalRDF4JFactory() {
};
public enum Option {
/**
* The Graph/Dataset should include any inferred statements
*/
includeInferred,
/**
* The graph/dataset should handle {@link Repository#initialize()} (if
* needed) and {@link Repository#shutDown()} on {@link Graph#close()} /
* {@link Dataset#close()}.
*/
handleInitAndShutdown
}
private final UUID salt;
private final ValueFactory valueFactory;
/**
* Construct an {@link RDF4J}.
*
*/
public RDF4J() {
this(SimpleValueFactory.getInstance(), UUID.randomUUID());
}
/**
* Construct an {@link RDF4J}.
*
* 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 RDF4J(final ValueFactory valueFactory) {
this(valueFactory, UUID.randomUUID());
}
/**
* Construct an {@link RDF4J}.
*
* 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 RDF4J(final UUID salt) {
this(SimpleValueFactory.getInstance(), salt);
}
/**
* Construct an {@link RDF4J}.
*
* 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 RDF4J(final ValueFactory valueFactory, final UUID salt) {
this.valueFactory = valueFactory;
this.salt = salt;
}
/**
* Adapt a RDF4J {@link Statement} as a Commons RDF {@link Quad}.
*
* For the purpose of {@link BlankNode} equivalence, this method will use an
* internal salt UUID that is unique per instance of {@link RDF4J}.
*
* NOTE: 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 RDF4J}
* 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}.
*
* 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}
*
* For the purpose of {@link BlankNode} equivalence, this method will use an
* internal salt UUID that is unique per instance of {@link RDF4J}.
*
* NOTE: 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 RDF4J}
* instance is used per RDF4J repository/model.
*
* @param value
* The RDF4J {@link Value} to convert.
* @return A {@link RDFTerm} that corresponds to the RDF4J value
* @throws IllegalArgumentException
* if the value is not a BNode, Literal or IRI
*/
public RDF4JTerm asRDFTerm(final Value value) {
return asRDFTerm(value, salt);
}
/**
*
* Adapt a RDF4J
* {@link org.eclipse.rdf4j.model.BNode} as a Commons RDF
* {@link org.apache.commons.rdf.api.BlankNode}
*
* For the purpose of {@link BlankNode} equivalence, this method will use an
* internal salt UUID that is unique per instance of {@link RDF4J}.
*
* NOTE: 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 RDF4J}
* instance is used per RDF4J repository/model.
*
* @param value
* The RDF4J {@link BNode} to convert.
* @return A {@link RDF4JBlankNode} that corresponds to the RDF4J BNode
*/
public RDF4JBlankNode asRDFTerm(final BNode value) {
return rdf4j.createBlankNodeImpl(value, salt);
}
/**
*
* Adapt a RDF4J
* {@link org.eclipse.rdf4j.model.Literal} as a Commons RDF
* {@link org.apache.commons.rdf.api.Literal}
*
* @param value
* The RDF4J {@link Literal} to convert.
* @return A {@link RDF4JLiteral} that corresponds to the RDF4J literal
*/
public RDF4JLiteral asRDFTerm(final Literal value) {
return rdf4j.createLiteralImpl(value);
}
/**
*
* Adapt a RDF4J
* {@link org.eclipse.rdf4j.model.IRI} as a Commons RDF
* {@link org.apache.commons.rdf.api.IRI}
*
* @param value
* The RDF4J {@link Value} to convert.
* @return A {@link RDF4JIRI} that corresponds to the RDF4J IRI
*/
public RDF4JIRI asRDFTerm(final org.eclipse.rdf4j.model.IRI value) {
return rdf4j.createIRIImpl(value);
}
/**
*
* Adapt a RDF4J
* {@link org.eclipse.rdf4j.model.Resource} as a Commons RDF
* {@link org.apache.commons.rdf.api.BlankNodeOrIRI}
*
* @param value
* The RDF4J {@link Value} to convert.
* @return A {@link RDF4JBlankNodeOrIRI} that corresponds to the RDF4J Resource
*/
public RDF4JBlankNodeOrIRI asRDFTerm(final org.eclipse.rdf4j.model.Resource value) {
if(value instanceof IRI){
return asRDFTerm((IRI)value);
} else if (value instanceof BNode){
return asRDFTerm((BNode)value);
}
throw new IllegalArgumentException("Value is not a BNode or IRI: " + value.getClass());
}
/**
* Adapt a RDF4J {@link Value} as a Commons RDF {@link RDFTerm}.
*
* 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.
* @return A {@link RDFTerm} that corresponds to the RDF4J value
* @throws IllegalArgumentException
* if the value is not a BNode, Literal or IRI
*/
public static RDF4JTerm asRDFTerm(final Value value, final UUID salt) {
if (value instanceof BNode) {
return rdf4j.createBlankNodeImpl((BNode) value, salt);
}
if (value instanceof org.eclipse.rdf4j.model.Literal) {
return rdf4j.createLiteralImpl((org.eclipse.rdf4j.model.Literal) value);
}
if (value instanceof org.eclipse.rdf4j.model.IRI) {
return rdf4j.createIRIImpl((org.eclipse.rdf4j.model.IRI) value);
}
throw new IllegalArgumentException("Value is not a BNode, Literal or IRI: " + value.getClass());
}
/**
* Adapt an RDF4J {@link Repository} as a Commons RDF {@link Dataset}.
*
* Changes to the dataset are reflected in the repository, and vice versa.
*
* Note: Some operations on the {@link RDF4JDataset}
* requires the use of try-with-resources to close underlying
* {@link RepositoryConnection}s, including {@link RDF4JDataset#iterate()},
* {@link RDF4JDataset#stream()} and {@link RDF4JDataset#getGraphNames()}.
*
* @param repository
* RDF4J {@link Repository} to connect to.
* @param options
* Zero or more {@link Option}
* @return A {@link Dataset} backed by the RDF4J repository.
*/
public RDF4JDataset asDataset(final Repository repository, final Option... options) {
final EnumSet