http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/413dd09a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4J.java ---------------------------------------------------------------------- diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4J.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4J.java index 7f70c75..8df26e0 100644 --- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4J.java +++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4J.java @@ -53,9 +53,9 @@ import org.eclipse.rdf4j.sail.memory.MemoryStore; /** * RDF4J implementation of RDF. * <p> - * 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 + * 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)}. * <p> * {@link #asRDFTerm(Value)} can be used to convert any RDF4J {@link Value} to @@ -67,8 +67,7 @@ import org.eclipse.rdf4j.sail.memory.MemoryStore; * To use other models, see {@link #asGraph(Model)}. * <p> * To adapt a RDF4J {@link Repository} as a {@link Dataset} or {@link Graph}, - * use {@link #asDataset(Repository, Option...)} - * or + * use {@link #asDataset(Repository, Option...)} or * {@link #asGraph(Repository, Option...)}. * <p> * {@link #asTriple(Statement)} can be used to convert a RDF4J {@link Statement} @@ -93,511 +92,495 @@ import org.eclipse.rdf4j.sail.memory.MemoryStore; * 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. + * {@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}. - * <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 RDF4J(ValueFactory valueFactory) { - this(valueFactory, UUID.randomUUID()); - } - - /** - * Construct an {@link RDF4J}. - * <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 RDF4J(UUID salt) { - this(SimpleValueFactory.getInstance(), salt); - } - /** - * Construct an {@link RDF4J}. - * <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 RDF4J(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 RDF4J}. - * <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 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}. - * <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 RDF4J}. - * <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 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(Value value) { - return asRDFTerm(value, 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} - * - * @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, 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}. - * <p> - * Changes to the dataset are reflected in the repository, and vice versa. - * <p> - * <strong>Note:</strong> 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(Repository repository, Option... options) { - EnumSet<Option> opts = optionSet(options); - return rdf4j.createRepositoryDatasetImpl(repository, - opts.contains(Option.handleInitAndShutdown), - opts.contains(Option.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 asGraph(Model model) { - return rdf4j.createModelGraphImpl(model, this); - } - - /** - * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}. - * <p> - * The graph will only include triples in the default graph (equivalent to - * context <code>new Resource[0]{null})</code> in RDF4J). - * <p> - * Changes to the graph are reflected in the repository, and vice versa. - * <p> - * <strong>Note:</strong> Some operations on the {@link RDF4JGraph} - * requires the use of try-with-resources to close underlying - * {@link RepositoryConnection}s, including - * {@link RDF4JGraph#iterate()} and - * {@link RDF4JGraph#stream()}. - * - * @param repository - * RDF4J {@link Repository} to connect to. - * @param options - * Zero or more {@link Option} - * @return A {@link Graph} backed by the RDF4J repository. - */ - public RDF4JGraph asGraph(Repository repository, Option... options) { - EnumSet<Option> opts = optionSet(options); - return rdf4j.createRepositoryGraphImpl(repository, - opts.contains(Option.handleInitAndShutdown), - opts.contains(Option.includeInferred), - new Resource[]{null}); // default graph - } - - /** - * 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 options - * Zero or more {@link Option} - * @return A union {@link Graph} backed by the RDF4J repository. - */ - public RDF4JGraph asGraphUnion(Repository repository, Option... options) { - EnumSet<Option> opts = optionSet(options); - return rdf4j.createRepositoryGraphImpl(repository, - opts.contains(Option.handleInitAndShutdown), - opts.contains(Option.includeInferred), - new Resource[]{}); // union graph - - } - - /** - * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}. - * <p> - * The graph will include triples in the specified contexts. - * <p> - * Changes to the graph are reflected in the repository, and vice versa. - * Triples added/removed to the graph are reflected in all the specified - * contexts. - * <p> - * <strong>Note:</strong> Some operations on the {@link RDF4JGraph} - * requires the use of try-with-resources to close underlying - * {@link RepositoryConnection}s, including - * {@link RDF4JGraph#iterate()} and - * {@link RDF4JGraph#stream()}. - * - * @param repository - * RDF4J {@link Repository} to connect to. - * @param contexts - * A {@link Set} of {@link BlankNodeOrIRI} specifying the graph - * names to use as a context. The set may include the value - * <code>null</code> to indicate the default graph. The empty set - * indicates any context, e.g. the <em>union graph</em>. - * @param option - * Zero or more {@link Option}s - * @return A {@link Graph} backed by the RDF4J repository. - */ - public RDF4JGraph asGraph(Repository repository, Set<? extends BlankNodeOrIRI> contexts, - Option... option) { - EnumSet<Option> opts = optionSet(option); - /** NOTE: asValue() deliberately CAN handle <code>null</code> */ - Resource[] resources = contexts.stream().map(g -> (Resource) asValue(g)).toArray(Resource[]::new); - return rdf4j.createRepositoryGraphImpl(Objects.requireNonNull(repository), - opts.contains(Option.handleInitAndShutdown), - opts.contains(Option.includeInferred), - resources); - } - - /** - * 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 tripleLike) { - if (tripleLike instanceof RDF4JTripleLike) { - // Return original statement - this covers both RDF4JQuad and - // RDF4JTriple - return ((RDF4JTripleLike) tripleLike).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 RDF4J}. - * <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 RDF4J} 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 rdf4j.createTripleImpl(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? - return getValueFactory().createBNode(blankNode.uniqueReference()); - } - throw new IllegalArgumentException("RDFTerm was not an IRI, Literal or BlankNode: " + term.getClass()); - } - - @Override - public RDF4JBlankNode createBlankNode() { - BNode bnode = getValueFactory().createBNode(); - return (RDF4JBlankNode) asRDFTerm(bnode); - } - - @Override - public RDF4JBlankNode createBlankNode(String name) { - BNode bnode = getValueFactory().createBNode(name); - return (RDF4JBlankNode) asRDFTerm(bnode); - } - - /** - * {@inheritDoc} - * <p> - * <strong>Note:</strong> 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()}. - * - */ - @Override - public RDF4JDataset createDataset() { - Sail sail = new MemoryStore(); - Repository repository = new SailRepository(sail); - return rdf4j.createRepositoryDatasetImpl(repository, true, false); - } - - @Override - public RDF4JGraph createGraph() { - return asGraph(new LinkedHashModel()); - } - - @Override - public RDF4JIRI createIRI(String iri) throws IllegalArgumentException { - return (RDF4JIRI) asRDFTerm(getValueFactory().createIRI(iri)); - } - - @Override - public RDF4JLiteral createLiteral(String lexicalForm) - throws IllegalArgumentException { - org.eclipse.rdf4j.model.Literal lit = getValueFactory().createLiteral(lexicalForm); - return (RDF4JLiteral) asRDFTerm(lit); - } - - @Override - public org.apache.commons.rdf.api.Literal createLiteral(String lexicalForm, org.apache.commons.rdf.api.IRI dataType) - throws IllegalArgumentException { - org.eclipse.rdf4j.model.IRI iri = getValueFactory().createIRI(dataType.getIRIString()); - org.eclipse.rdf4j.model.Literal lit = getValueFactory().createLiteral(lexicalForm, iri); - return (org.apache.commons.rdf.api.Literal) asRDFTerm(lit); - } - - @Override - public org.apache.commons.rdf.api.Literal createLiteral(String lexicalForm, String languageTag) - throws IllegalArgumentException { - org.eclipse.rdf4j.model.Literal lit = getValueFactory().createLiteral(lexicalForm, languageTag); - return (org.apache.commons.rdf.api.Literal) asRDFTerm(lit); - } - - @Override - public RDF4JTriple createTriple(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) - throws IllegalArgumentException { - final Statement statement = getValueFactory().createStatement( - (org.eclipse.rdf4j.model.Resource) asValue(subject), (org.eclipse.rdf4j.model.IRI) asValue(predicate), - asValue(object)); - return asTriple(statement); - } - - @Override - public Quad createQuad(BlankNodeOrIRI graphName, BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, - RDFTerm object) throws IllegalArgumentException { - final Statement statement = getValueFactory().createStatement( - (org.eclipse.rdf4j.model.Resource) asValue(subject), (org.eclipse.rdf4j.model.IRI) asValue(predicate), - asValue(object), (org.eclipse.rdf4j.model.Resource) asValue(graphName)); - return asQuad(statement); - } - - public ValueFactory getValueFactory() { - return valueFactory; - } - - private EnumSet<Option> optionSet(Option... options) { - EnumSet<Option> opts = EnumSet.noneOf(Option.class); - opts.addAll(Arrays.asList(options)); - return opts; - } - - - + /** + * 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}. + * <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 RDF4J(ValueFactory valueFactory) { + this(valueFactory, UUID.randomUUID()); + } + + /** + * Construct an {@link RDF4J}. + * <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 RDF4J(UUID salt) { + this(SimpleValueFactory.getInstance(), salt); + } + + /** + * Construct an {@link RDF4J}. + * <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 RDF4J(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 RDF4J}. + * <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 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}. + * <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 RDF4J}. + * <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 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(Value value) { + return asRDFTerm(value, 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} + * + * @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, 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}. + * <p> + * Changes to the dataset are reflected in the repository, and vice versa. + * <p> + * <strong>Note:</strong> 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(Repository repository, Option... options) { + EnumSet<Option> opts = optionSet(options); + return rdf4j.createRepositoryDatasetImpl(repository, opts.contains(Option.handleInitAndShutdown), + opts.contains(Option.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 asGraph(Model model) { + return rdf4j.createModelGraphImpl(model, this); + } + + /** + * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}. + * <p> + * The graph will only include triples in the default graph (equivalent to + * context <code>new Resource[0]{null})</code> in RDF4J). + * <p> + * Changes to the graph are reflected in the repository, and vice versa. + * <p> + * <strong>Note:</strong> Some operations on the {@link RDF4JGraph} requires + * the use of try-with-resources to close underlying + * {@link RepositoryConnection}s, including {@link RDF4JGraph#iterate()} and + * {@link RDF4JGraph#stream()}. + * + * @param repository + * RDF4J {@link Repository} to connect to. + * @param options + * Zero or more {@link Option} + * @return A {@link Graph} backed by the RDF4J repository. + */ + public RDF4JGraph asGraph(Repository repository, Option... options) { + EnumSet<Option> opts = optionSet(options); + return rdf4j.createRepositoryGraphImpl(repository, opts.contains(Option.handleInitAndShutdown), + opts.contains(Option.includeInferred), new Resource[] { null }); // default + // graph + } + + /** + * 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 options + * Zero or more {@link Option} + * @return A union {@link Graph} backed by the RDF4J repository. + */ + public RDF4JGraph asGraphUnion(Repository repository, Option... options) { + EnumSet<Option> opts = optionSet(options); + return rdf4j.createRepositoryGraphImpl(repository, opts.contains(Option.handleInitAndShutdown), + opts.contains(Option.includeInferred), new Resource[] {}); // union + // graph + + } + + /** + * Adapt an RDF4J {@link Repository} as a Commons RDF {@link Graph}. + * <p> + * The graph will include triples in the specified contexts. + * <p> + * Changes to the graph are reflected in the repository, and vice versa. + * Triples added/removed to the graph are reflected in all the specified + * contexts. + * <p> + * <strong>Note:</strong> Some operations on the {@link RDF4JGraph} requires + * the use of try-with-resources to close underlying + * {@link RepositoryConnection}s, including {@link RDF4JGraph#iterate()} and + * {@link RDF4JGraph#stream()}. + * + * @param repository + * RDF4J {@link Repository} to connect to. + * @param contexts + * A {@link Set} of {@link BlankNodeOrIRI} specifying the graph + * names to use as a context. The set may include the value + * <code>null</code> to indicate the default graph. The empty set + * indicates any context, e.g. the <em>union graph</em>. + * @param option + * Zero or more {@link Option}s + * @return A {@link Graph} backed by the RDF4J repository. + */ + public RDF4JGraph asGraph(Repository repository, Set<? extends BlankNodeOrIRI> contexts, Option... option) { + EnumSet<Option> opts = optionSet(option); + /** NOTE: asValue() deliberately CAN handle <code>null</code> */ + Resource[] resources = contexts.stream().map(g -> (Resource) asValue(g)).toArray(Resource[]::new); + return rdf4j.createRepositoryGraphImpl(Objects.requireNonNull(repository), + opts.contains(Option.handleInitAndShutdown), opts.contains(Option.includeInferred), resources); + } + + /** + * 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 tripleLike) { + if (tripleLike instanceof RDF4JTripleLike) { + // Return original statement - this covers both RDF4JQuad and + // RDF4JTriple + return ((RDF4JTripleLike) tripleLike).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 RDF4J}. + * <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 RDF4J} + * 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 rdf4j.createTripleImpl(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? + return getValueFactory().createBNode(blankNode.uniqueReference()); + } + throw new IllegalArgumentException("RDFTerm was not an IRI, Literal or BlankNode: " + term.getClass()); + } + + @Override + public RDF4JBlankNode createBlankNode() { + BNode bnode = getValueFactory().createBNode(); + return (RDF4JBlankNode) asRDFTerm(bnode); + } + + @Override + public RDF4JBlankNode createBlankNode(String name) { + BNode bnode = getValueFactory().createBNode(name); + return (RDF4JBlankNode) asRDFTerm(bnode); + } + + /** + * {@inheritDoc} + * <p> + * <strong>Note:</strong> 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()}. + * + */ + @Override + public RDF4JDataset createDataset() { + Sail sail = new MemoryStore(); + Repository repository = new SailRepository(sail); + return rdf4j.createRepositoryDatasetImpl(repository, true, false); + } + + @Override + public RDF4JGraph createGraph() { + return asGraph(new LinkedHashModel()); + } + + @Override + public RDF4JIRI createIRI(String iri) throws IllegalArgumentException { + return (RDF4JIRI) asRDFTerm(getValueFactory().createIRI(iri)); + } + + @Override + public RDF4JLiteral createLiteral(String lexicalForm) throws IllegalArgumentException { + org.eclipse.rdf4j.model.Literal lit = getValueFactory().createLiteral(lexicalForm); + return (RDF4JLiteral) asRDFTerm(lit); + } + + @Override + public org.apache.commons.rdf.api.Literal createLiteral(String lexicalForm, org.apache.commons.rdf.api.IRI dataType) + throws IllegalArgumentException { + org.eclipse.rdf4j.model.IRI iri = getValueFactory().createIRI(dataType.getIRIString()); + org.eclipse.rdf4j.model.Literal lit = getValueFactory().createLiteral(lexicalForm, iri); + return (org.apache.commons.rdf.api.Literal) asRDFTerm(lit); + } + + @Override + public org.apache.commons.rdf.api.Literal createLiteral(String lexicalForm, String languageTag) + throws IllegalArgumentException { + org.eclipse.rdf4j.model.Literal lit = getValueFactory().createLiteral(lexicalForm, languageTag); + return (org.apache.commons.rdf.api.Literal) asRDFTerm(lit); + } + + @Override + public RDF4JTriple createTriple(BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, RDFTerm object) + throws IllegalArgumentException { + final Statement statement = getValueFactory().createStatement( + (org.eclipse.rdf4j.model.Resource) asValue(subject), (org.eclipse.rdf4j.model.IRI) asValue(predicate), + asValue(object)); + return asTriple(statement); + } + + @Override + public Quad createQuad(BlankNodeOrIRI graphName, BlankNodeOrIRI subject, org.apache.commons.rdf.api.IRI predicate, + RDFTerm object) throws IllegalArgumentException { + final Statement statement = getValueFactory().createStatement( + (org.eclipse.rdf4j.model.Resource) asValue(subject), (org.eclipse.rdf4j.model.IRI) asValue(predicate), + asValue(object), (org.eclipse.rdf4j.model.Resource) asValue(graphName)); + return asQuad(statement); + } + + public ValueFactory getValueFactory() { + return valueFactory; + } + + private EnumSet<Option> optionSet(Option... options) { + EnumSet<Option> opts = EnumSet.noneOf(Option.class); + opts.addAll(Arrays.asList(options)); + return opts; + } + }
http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/413dd09a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JBlankNode.java ---------------------------------------------------------------------- diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JBlankNode.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JBlankNode.java index 15ca381..14099e0 100644 --- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JBlankNode.java +++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JBlankNode.java @@ -21,17 +21,17 @@ import org.apache.commons.rdf.api.BlankNode; import org.eclipse.rdf4j.model.BNode; /** - * Marker interface for RDF4J implementations of - * Commons RDF {@link org.apache.commons.rdf.api.BlankNode}. + * Marker interface for RDF4J implementations of Commons RDF + * {@link org.apache.commons.rdf.api.BlankNode}. * <p> - * The underlying RDF4J {@link BNode} instance can - * be retrieved with {@link #asValue()}. + * The underlying RDF4J {@link BNode} instance can be retrieved with + * {@link #asValue()}. * - * @see RDF4J#createBlankNode() + * @see RDF4J#createBlankNode() */ public interface RDF4JBlankNode extends RDF4JBlankNodeOrIRI, BlankNode { - - @Override - public BNode asValue(); - + + @Override + public BNode asValue(); + } http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/413dd09a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JBlankNodeOrIRI.java ---------------------------------------------------------------------- diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JBlankNodeOrIRI.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JBlankNodeOrIRI.java index 75b5a32..dd7259e 100644 --- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JBlankNodeOrIRI.java +++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JBlankNodeOrIRI.java @@ -31,7 +31,7 @@ import org.eclipse.rdf4j.model.Resource; */ public interface RDF4JBlankNodeOrIRI extends RDF4JTerm, BlankNodeOrIRI { - @Override - public Resource asValue(); - + @Override + public Resource asValue(); + } http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/413dd09a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JDataset.java ---------------------------------------------------------------------- diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JDataset.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JDataset.java index 7b5cbaa..5740f44 100644 --- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JDataset.java +++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JDataset.java @@ -27,7 +27,6 @@ import org.apache.commons.rdf.api.Quad; import org.apache.commons.rdf.api.RDFTerm; import org.apache.commons.rdf.rdf4j.RDF4J.Option; - /** * Marker interface for RDF4J implementations of Dataset. * @@ -35,106 +34,109 @@ import org.apache.commons.rdf.rdf4j.RDF4J.Option; * @see RDF4J#asDataset(org.eclipse.rdf4j.repository.Repository, Option...) */ public interface RDF4JDataset extends Dataset, RDF4JGraphLike<Quad> { - - /** - * {@inheritDoc} - * <p> - * Note that for datasets backed by a repository ({@link #asRepository()} is - * present), the stream <strong>must be closed</strong> with - * {@link Stream#close()}. - * <p> - * This can generally achieved using a try-with-resources block, e.g.: - * <pre> - * int subjects; - * try (Stream<RDF4JQuad> s : graph.stream()) { - * subjects = s.map(RDF4JQuad::getSubject).distinct().count() - * } - * </pre> - */ - @Override - Stream<RDF4JQuad> stream(); - - /** - * {@inheritDoc} - * <p> - * Note that for datasets backed by a repository ({@link #asRepository()} is - * present), the stream <strong>must be closed</strong> with - * {@link Stream#close()}. - * <p> - * This can generally achieved using a try-with-resources block, e.g.: - * <pre> - * int subjects; - * try (Stream<RDF4JQuad> s : graph.stream()) { - * subjects = s.map(RDF4JQuad::getSubject).distinct().count() - * } - * </pre> - */ - @Override - Stream<RDF4JQuad> stream(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, - RDFTerm object); - /** - * {@inheritDoc} - * <p> - * Note that for datasets backed by a repository ({@link #asRepository()} is - * present), the stream <strong>must be closed</strong> with - * {@link Stream#close()}. - * <p> - * This can generally achieved using a try-with-resources block, e.g.: - * <pre> - * int graphs; - * try (Stream<BlankNodeOrIRI> s : graph.stream()) { - * graphs = s.count() - * } - * </pre> - */ - @Override - Stream<BlankNodeOrIRI> getGraphNames(); - + /** + * {@inheritDoc} + * <p> + * Note that for datasets backed by a repository ({@link #asRepository()} is + * present), the stream <strong>must be closed</strong> with + * {@link Stream#close()}. + * <p> + * This can generally achieved using a try-with-resources block, e.g.: + * + * <pre> + * int subjects; + * try (Stream<RDF4JQuad> s : graph.stream()) { + * subjects = s.map(RDF4JQuad::getSubject).distinct().count() + * } + * </pre> + */ + @Override + Stream<RDF4JQuad> stream(); + + /** + * {@inheritDoc} + * <p> + * Note that for datasets backed by a repository ({@link #asRepository()} is + * present), the stream <strong>must be closed</strong> with + * {@link Stream#close()}. + * <p> + * This can generally achieved using a try-with-resources block, e.g.: + * + * <pre> + * int subjects; + * try (Stream<RDF4JQuad> s : graph.stream()) { + * subjects = s.map(RDF4JQuad::getSubject).distinct().count() + * } + * </pre> + */ + @Override + Stream<RDF4JQuad> stream(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object); - /** - * {@inheritDoc} - * <p> - * Note that for datasets backed by a repository ({@link #asRepository()} is - * present), the iterable <strong>must be closed</strong> with - * {@link ClosableIterable#close()}. - * <p> - * This can generally achieved using a try-with-resources block, e.g.: - * <pre> - * try (ClosableIterable<Quad> s : graph.iterate()) { + /** + * {@inheritDoc} + * <p> + * Note that for datasets backed by a repository ({@link #asRepository()} is + * present), the stream <strong>must be closed</strong> with + * {@link Stream#close()}. + * <p> + * This can generally achieved using a try-with-resources block, e.g.: + * + * <pre> + * int graphs; + * try (Stream<BlankNodeOrIRI> s : graph.stream()) { + * graphs = s.count() + * } + * </pre> + */ + @Override + Stream<BlankNodeOrIRI> getGraphNames(); + + /** + * {@inheritDoc} + * <p> + * Note that for datasets backed by a repository ({@link #asRepository()} is + * present), the iterable <strong>must be closed</strong> with + * {@link ClosableIterable#close()}. + * <p> + * This can generally achieved using a try-with-resources block, e.g.: + * + * <pre> + * try (ClosableIterable<Quad> s : graph.iterate()) { * for (Quad q : quads) { * return q; // OK to terminate for-loop early * } - * } - * </pre> - * If you don't use a try-with-resources block, the iterator will - * attempt to close the ClosableIterable - * when reaching the end of the iteration. - */ - @Override - ClosableIterable<Quad> iterate(); - + * } + * </pre> + * + * If you don't use a try-with-resources block, the iterator will attempt to + * close the ClosableIterable when reaching the end of the iteration. + */ + @Override + ClosableIterable<Quad> iterate(); - /** - * {@inheritDoc} - * <p> - * Note that for datasets backed by a repository ({@link #asRepository()} is - * present), the iterable <strong>must be closed</strong> with - * {@link ClosableIterable#close()}. - * <p> - * This can generally achieved using a try-with-resources block, e.g.: - * <pre> - * try (ClosableIterable<Quad> s : graph.iterate(g,s,p,o)) { + /** + * {@inheritDoc} + * <p> + * Note that for datasets backed by a repository ({@link #asRepository()} is + * present), the iterable <strong>must be closed</strong> with + * {@link ClosableIterable#close()}. + * <p> + * This can generally achieved using a try-with-resources block, e.g.: + * + * <pre> + * try (ClosableIterable<Quad> s : graph.iterate(g,s,p,o)) { * for (Quad q : quads) { * return q; // OK to terminate for-loop early * } - * } - * </pre> - * If you don't use a try-with-resources block, the iterator will - * attempt to close the ClosableIterable - * when reaching the end of the iteration. - */ - @Override - ClosableIterable<Quad> iterate(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, RDFTerm object); - + * } + * </pre> + * + * If you don't use a try-with-resources block, the iterator will attempt to + * close the ClosableIterable when reaching the end of the iteration. + */ + @Override + ClosableIterable<Quad> iterate(Optional<BlankNodeOrIRI> graphName, BlankNodeOrIRI subject, IRI predicate, + RDFTerm object); + } http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/413dd09a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java ---------------------------------------------------------------------- diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java index 65cdf67..ab52310 100644 --- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java +++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraph.java @@ -30,7 +30,6 @@ import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.repository.Repository; import org.apache.commons.rdf.rdf4j.RDF4J.Option; - /** * Marker interface for RDF4J implementations of Graph. * @@ -42,115 +41,117 @@ import org.apache.commons.rdf.rdf4j.RDF4J.Option; * @see RDF4JDataset#getGraph(BlankNodeOrIRI) */ public interface RDF4JGraph extends Graph, RDF4JGraphLike<Triple> { - - /** - * Return a copy of the context mask as a {@link Set} of - * {@link RDF4JBlankNodeOrIRI} graph names. - * <p> - * If the set is not {@link Set#isEmpty()}, the mask 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 mask array may contain <code>null</code>, indicating the - * default context (the <em>default graph</em> in RDF datasets). - * <p> - * If the context mask is {@link Set#isEmpty()}, then this is a <em>union - * graph</em> which triples reflect statements in any contexts. Triples - * added to the graph will be added in the default context, e.g. equivalent - * to <code>new Resource[1]{null}</code>) in RDF4J. - * <p> - * Note that the context mask itself cannot be <code>null</code>. - * <p> - * The returned set is an immutable copy; to specify a different mask, use - * {@link RDF4J#asGraph(Repository, Set, Option...)} - * - * @return The context mask as a set of {@link BlankNodeOrIRI} graph names, which - * may contain the value <code>null</code>. - */ - public Set<RDF4JBlankNodeOrIRI> getContextMask(); - - /** - * {@inheritDoc} - * <p> - * Note that for graphs backed by a repository ({@link #asRepository()} is - * present), the stream <strong>must be closed</strong> with - * {@link Stream#close()}. - * <p> - * This can generally achieved using a try-with-resources block, e.g.: - * - * <pre> - * int subjects; - * try (Stream<RDF4JTriple> s : graph.stream()) { - * subjects = s.map(RDF4JTriple::getSubject).distinct().count() - * } - * </pre> - */ - @Override - Stream<RDF4JTriple> stream(); - /** - * {@inheritDoc} - * <p> - * Note that for graphs backed by a repository ({@link #asRepository()} is - * present), the stream <strong>must be closed</strong> with - * {@link Stream#close()}. - * <p> - * This can generally achieved using a try-with-resources block, e.g.: - * <pre> - * int subjects; - * try (Stream<RDF4JTriple> s : graph.stream(s,p,o)) { - * subjects = s.map(RDF4JTriple::getSubject).distinct().count() - * } - * </pre> - */ - @Override - Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, IRI predicate, RDFTerm object); - - - /** - * {@inheritDoc} - * <p> - * Note that for graphs backed by a repository ({@link #asRepository()} is - * present), the iterable <strong>must be closed</strong> with - * {@link ClosableIterable#close()}. - * <p> - * This can generally achieved using a try-with-resources block, e.g.: - * <pre> - * try (ClosableIterable<Triple> s : graph.iterate()) { + /** + * Return a copy of the context mask as a {@link Set} of + * {@link RDF4JBlankNodeOrIRI} graph names. + * <p> + * If the set is not {@link Set#isEmpty()}, the mask 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 mask array may contain <code>null</code>, indicating the + * default context (the <em>default graph</em> in RDF datasets). + * <p> + * If the context mask is {@link Set#isEmpty()}, then this is a <em>union + * graph</em> which triples reflect statements in any contexts. Triples + * added to the graph will be added in the default context, e.g. equivalent + * to <code>new Resource[1]{null}</code>) in RDF4J. + * <p> + * Note that the context mask itself cannot be <code>null</code>. + * <p> + * The returned set is an immutable copy; to specify a different mask, use + * {@link RDF4J#asGraph(Repository, Set, Option...)} + * + * @return The context mask as a set of {@link BlankNodeOrIRI} graph names, + * which may contain the value <code>null</code>. + */ + public Set<RDF4JBlankNodeOrIRI> getContextMask(); + + /** + * {@inheritDoc} + * <p> + * Note that for graphs backed by a repository ({@link #asRepository()} is + * present), the stream <strong>must be closed</strong> with + * {@link Stream#close()}. + * <p> + * This can generally achieved using a try-with-resources block, e.g.: + * + * <pre> + * int subjects; + * try (Stream<RDF4JTriple> s : graph.stream()) { + * subjects = s.map(RDF4JTriple::getSubject).distinct().count() + * } + * </pre> + */ + @Override + Stream<RDF4JTriple> stream(); + + /** + * {@inheritDoc} + * <p> + * Note that for graphs backed by a repository ({@link #asRepository()} is + * present), the stream <strong>must be closed</strong> with + * {@link Stream#close()}. + * <p> + * This can generally achieved using a try-with-resources block, e.g.: + * + * <pre> + * int subjects; + * try (Stream<RDF4JTriple> s : graph.stream(s,p,o)) { + * subjects = s.map(RDF4JTriple::getSubject).distinct().count() + * } + * </pre> + */ + @Override + Stream<RDF4JTriple> stream(BlankNodeOrIRI subject, IRI predicate, RDFTerm object); + + /** + * {@inheritDoc} + * <p> + * Note that for graphs backed by a repository ({@link #asRepository()} is + * present), the iterable <strong>must be closed</strong> with + * {@link ClosableIterable#close()}. + * <p> + * This can generally achieved using a try-with-resources block, e.g.: + * + * <pre> + * try (ClosableIterable<Triple> s : graph.iterate()) { * for (Triple t : triples) { * return t; // OK to terminate for-loop early * } - * } - * </pre> - * If you don't use a try-with-resources block, the iterator will - * attempt to close the ClosableIterable - * when reaching the end of the iteration. - */ - @Override - ClosableIterable<Triple> iterate() throws ConcurrentModificationException, IllegalStateException; + * } + * </pre> + * + * If you don't use a try-with-resources block, the iterator will attempt to + * close the ClosableIterable when reaching the end of the iteration. + */ + @Override + ClosableIterable<Triple> iterate() throws ConcurrentModificationException, IllegalStateException; - /** - * {@inheritDoc} - * <p> - * Note that for graphs backed by a repository ({@link #asRepository()} is - * present), the iterable <strong>must be closed</strong> with - * {@link ClosableIterable#close()}. - * <p> - * This can generally achieved using a try-with-resources block, e.g.: - * <pre> - * try (ClosableIterable<Triple> s : graph.iterate(s,p,o)) { + /** + * {@inheritDoc} + * <p> + * Note that for graphs backed by a repository ({@link #asRepository()} is + * present), the iterable <strong>must be closed</strong> with + * {@link ClosableIterable#close()}. + * <p> + * This can generally achieved using a try-with-resources block, e.g.: + * + * <pre> + * try (ClosableIterable<Triple> s : graph.iterate(s,p,o)) { * for (Triple t : triples) { * return t; // OK to terminate for-loop early * } - * } - * </pre> - * If you don't use a try-with-resources block, the iterator will - * attempt to close the ClosableIterable - * when reaching the end of the iteration. - */ - @Override - ClosableIterable<Triple> iterate(BlankNodeOrIRI subject, IRI predicate, RDFTerm object); + * } + * </pre> + * + * If you don't use a try-with-resources block, the iterator will attempt to + * close the ClosableIterable when reaching the end of the iteration. + */ + @Override + ClosableIterable<Triple> iterate(BlankNodeOrIRI subject, IRI predicate, RDFTerm object); } http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/413dd09a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraphLike.java ---------------------------------------------------------------------- diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraphLike.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraphLike.java index 430369a..4b69bee 100644 --- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraphLike.java +++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JGraphLike.java @@ -37,31 +37,30 @@ import org.eclipse.rdf4j.repository.Repository; * @see RDF4JDataset * @see RDF4JGraph */ -public interface RDF4JGraphLike<T extends TripleLike> - extends GraphLike<T>, AutoCloseable { +public interface RDF4JGraphLike<T extends TripleLike> extends GraphLike<T>, 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 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. - * <p> - * Changes to the Repository are reflected in both directions. - * - * @return The corresponding RDF4J Repository. - */ - public Optional<Repository> asRepository(); + /** + * Return the corresponding RDF4J {@link Repository}, if present. + * <p> + * The return value is {@link Optional#isPresent()} if this is backed by a + * Repository. + * <p> + * Changes to the Repository are reflected in both directions. + * + * @return The corresponding RDF4J Repository. + */ + public Optional<Repository> asRepository(); } http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/413dd09a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JIRI.java ---------------------------------------------------------------------- diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JIRI.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JIRI.java index 72c83fa..642ed58 100644 --- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JIRI.java +++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JIRI.java @@ -18,18 +18,17 @@ package org.apache.commons.rdf.rdf4j; /** - * Marker interface for RDF4J implementations of - * Commons RDF {@link org.apache.commons.rdf.api.IRI}. + * Marker interface for RDF4J implementations of Commons RDF + * {@link org.apache.commons.rdf.api.IRI}. * <p> - * The underlying RDF4J {@link org.eclipse.rdf4j.model.IRI} - * instance can be retrieved with {@link #asValue()}. + * The underlying RDF4J {@link org.eclipse.rdf4j.model.IRI} instance can be + * retrieved with {@link #asValue()}. * * @see RDF4J#createIRI(String) */ -public interface RDF4JIRI - extends RDF4JBlankNodeOrIRI, org.apache.commons.rdf.api.IRI { - - @Override - org.eclipse.rdf4j.model.IRI asValue(); - +public interface RDF4JIRI extends RDF4JBlankNodeOrIRI, org.apache.commons.rdf.api.IRI { + + @Override + org.eclipse.rdf4j.model.IRI asValue(); + } http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/413dd09a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JQuad.java ---------------------------------------------------------------------- diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JQuad.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JQuad.java index 23b6cdf..7fedfde 100644 --- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JQuad.java +++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JQuad.java @@ -22,8 +22,10 @@ import org.apache.commons.rdf.api.Quad; /** * Marker interface for RDF4J implementations of Quad. * - * @see RDF4J#createQuad(org.apache.commons.rdf.api.BlankNodeOrIRI, org.apache.commons.rdf.api.BlankNodeOrIRI, org.apache.commons.rdf.api.IRI, org.apache.commons.rdf.api.RDFTerm) + * @see RDF4J#createQuad(org.apache.commons.rdf.api.BlankNodeOrIRI, + * org.apache.commons.rdf.api.BlankNodeOrIRI, + * org.apache.commons.rdf.api.IRI, org.apache.commons.rdf.api.RDFTerm) */ public interface RDF4JQuad extends Quad, RDF4JTripleLike { - + } http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/413dd09a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTerm.java ---------------------------------------------------------------------- diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTerm.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTerm.java index e500651..1f7b841 100644 --- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTerm.java +++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTerm.java @@ -25,14 +25,15 @@ import org.eclipse.rdf4j.model.Value; /** * Marker interface for RDF4J implementations of RDFTerm. - * + * */ public interface RDF4JTerm extends RDFTerm { - - /** - * Return the RDF4J {@link Value} that this RDFTerm represents. - * - * @return The wrapped {@link Value} (e.g. a {@link Literal}, {@link IRI} or {@link BNode}. - */ - public Value asValue(); + + /** + * Return the RDF4J {@link Value} that this RDFTerm represents. + * + * @return The wrapped {@link Value} (e.g. a {@link Literal}, {@link IRI} or + * {@link BNode}. + */ + public Value asValue(); } http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/413dd09a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTriple.java ---------------------------------------------------------------------- diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTriple.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTriple.java index ca32d94..55388ab 100644 --- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTriple.java +++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTriple.java @@ -22,8 +22,9 @@ import org.apache.commons.rdf.api.Triple; /** * Marker interface for RDF4J implementations of Triple. * - * @see RDF4J#createTriple(org.apache.commons.rdf.api.BlankNodeOrIRI, org.apache.commons.rdf.api.IRI, org.apache.commons.rdf.api.RDFTerm) + * @see RDF4J#createTriple(org.apache.commons.rdf.api.BlankNodeOrIRI, + * org.apache.commons.rdf.api.IRI, org.apache.commons.rdf.api.RDFTerm) */ public interface RDF4JTriple extends Triple, RDF4JTripleLike { - + } http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/413dd09a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTripleLike.java ---------------------------------------------------------------------- diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTripleLike.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTripleLike.java index e204e77..222c2c8 100644 --- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTripleLike.java +++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/RDF4JTripleLike.java @@ -23,20 +23,21 @@ import org.eclipse.rdf4j.model.Statement; /** * Marker interface for RDF4J implementations of {@link TripleLike} statements. * <p> - * This interface is in common with the more specific {@link RDF4JTriple} or + * This interface is in common with the more specific {@link RDF4JTriple} or * {@link RDF4JQuad}. * <p> - * This is backed by a {@link Statement} retrievable with {@link #asStatement()}. + * This is backed by a {@link Statement} retrievable with + * {@link #asStatement()}. * * @see RDF4JTriple * @see RDF4JQuad */ public interface RDF4JTripleLike extends TripleLike { - - /** - * Return the corresponding RDF4J {@link Statement}. - * - * @return The corresponding RDF4J Statement. - */ - public Statement asStatement(); + + /** + * Return the corresponding RDF4J {@link Statement}. + * + * @return The corresponding RDF4J Statement. + */ + public Statement asStatement(); } http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/413dd09a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java ---------------------------------------------------------------------- diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java index 26b3647..87328cd 100644 --- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java +++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/RDF4JParser.java @@ -59,174 +59,178 @@ import org.eclipse.rdf4j.rio.helpers.AbstractRDFHandler; */ 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 RDF4J rdf4jTermFactory; - private ParserConfig parserConfig = new ParserConfig(); - - @Override - protected RDF4J createRDFTermFactory() { - return new RDF4J(); - } - - @Override - protected RDF4JParser prepareForParsing() throws IOException, IllegalStateException { - RDF4JParser c = super.prepareForParsing(); - // Ensure we have an RDF4J for conversion. - // We'll make a new one if user has provided a non-RDF4J factory - c.rdf4jTermFactory = (RDF4J) getRdfTermFactory().filter(RDF4J.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 - * {@link #setParserConfig(ParserConfig)}. - * - * @return The RDF4J {@link ParserConfig} - */ - public ParserConfig getParserConfig() { - return parserConfig; - } - - /** - * Set an RDF4J {@link ParserConfig} to use - * - * @param parserConfig Parser configuration - */ - public void setParserConfig(ParserConfig parserConfig) { - this.parserConfig = parserConfig; - } - - protected RDFHandler makeRDFHandler() { - - // TODO: Can we join the below DF4JDataset and RDF4JGraph cases - // using RDF4JGraphLike<TripleLike<BlankNodeOrIRI,IRI,RDFTerm>> - // or will that need tricky generics types? - - if (getTargetDataset().filter(RDF4JDataset.class::isInstance).isPresent()) { - // One of us, we can add them as Statements directly - 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); - } - // Not backed by Repository or Model? - // Third-party RDF4JDataset subclass, so we'll fall through to the - // getTarget() handling further down - } else if (getTargetGraph().filter(RDF4JGraph.class::isInstance).isPresent()) { - RDF4JGraph graph = (RDF4JGraph) getTargetGraph().get(); - - if (graph.asRepository().isPresent()) { - RDFInserter inserter = new RDFInserter(graph.asRepository().get().getConnection()); - if (! graph.getContextMask().isEmpty()) { - Stream<RDF4JBlankNodeOrIRI> b = graph.getContextMask().stream(); - Stream<Resource> c = b.map(RDF4JBlankNodeOrIRI::asValue); - Resource[] contexts = c.toArray(Resource[]::new); - inserter.enforceContext(contexts); - } - return inserter; - } - if (graph.asModel().isPresent() && graph.getContextMask().isEmpty()) { - // the model accepts any quad - Model model = graph.asModel().get(); - return new AddToModel(model); - } - // else - fall through - } - - // Fall thorough: let target() consume our converted quads. - return new AddToQuadConsumer(getTarget()); - } + 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 RDF4J rdf4jTermFactory; + private ParserConfig parserConfig = new ParserConfig(); + + @Override + protected RDF4J createRDFTermFactory() { + return new RDF4J(); + } + + @Override + protected RDF4JParser prepareForParsing() throws IOException, IllegalStateException { + RDF4JParser c = super.prepareForParsing(); + // Ensure we have an RDF4J for conversion. + // We'll make a new one if user has provided a non-RDF4J factory + c.rdf4jTermFactory = (RDF4J) getRdfTermFactory().filter(RDF4J.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 + * {@link #setParserConfig(ParserConfig)}. + * + * @return The RDF4J {@link ParserConfig} + */ + public ParserConfig getParserConfig() { + return parserConfig; + } + + /** + * Set an RDF4J {@link ParserConfig} to use + * + * @param parserConfig + * Parser configuration + */ + public void setParserConfig(ParserConfig parserConfig) { + this.parserConfig = parserConfig; + } + + protected RDFHandler makeRDFHandler() { + + // TODO: Can we join the below DF4JDataset and RDF4JGraph cases + // using RDF4JGraphLike<TripleLike<BlankNodeOrIRI,IRI,RDFTerm>> + // or will that need tricky generics types? + + if (getTargetDataset().filter(RDF4JDataset.class::isInstance).isPresent()) { + // One of us, we can add them as Statements directly + 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); + } + // Not backed by Repository or Model? + // Third-party RDF4JDataset subclass, so we'll fall through to the + // getTarget() handling further down + } else if (getTargetGraph().filter(RDF4JGraph.class::isInstance).isPresent()) { + RDF4JGraph graph = (RDF4JGraph) getTargetGraph().get(); + + if (graph.asRepository().isPresent()) { + RDFInserter inserter = new RDFInserter(graph.asRepository().get().getConnection()); + if (!graph.getContextMask().isEmpty()) { + Stream<RDF4JBlankNodeOrIRI> b = graph.getContextMask().stream(); + Stream<Resource> c = b.map(RDF4JBlankNodeOrIRI::asValue); + Resource[] contexts = c.toArray(Resource[]::new); + inserter.enforceContext(contexts); + } + return inserter; + } + if (graph.asModel().isPresent() && graph.getContextMask().isEmpty()) { + // the model accepts any quad + Model model = graph.asModel().get(); + return new AddToModel(model); + } + // else - fall through + } + + // Fall thorough: let target() consume our converted quads. + return new AddToQuadConsumer(getTarget()); + } } http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/413dd09a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/package-info.java ---------------------------------------------------------------------- diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/package-info.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/package-info.java index 217d003..4f5b070 100644 --- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/package-info.java +++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/experimental/package-info.java @@ -18,15 +18,13 @@ /** * Experimental Commons RDF RDF4J implementations. * <p> - * Classes in this package should be considered <strong>at - * risk</strong>; they might change or be removed in the next minor update of - * Commons RDF. + * Classes in this package should be considered <strong>at risk</strong>; they + * might change or be removed in the next minor update of Commons RDF. * <p> * When a class has stabilized, it will move to the * {@link org.apache.commons.rdf.rdf4j} package. * <ul> - * <li>{@link RDF4JParser} - an RDF4J-backed - * implementations of + * <li>{@link RDF4JParser} - an RDF4J-backed implementations of * {@link org.apache.commons.rdf.experimental.RDFParser}.</li> * </ul> */ http://git-wip-us.apache.org/repos/asf/incubator-commonsrdf/blob/413dd09a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRDFTerm.java ---------------------------------------------------------------------- diff --git a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRDFTerm.java b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRDFTerm.java index b54c715..7fce346 100644 --- a/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRDFTerm.java +++ b/rdf4j/src/main/java/org/apache/commons/rdf/rdf4j/impl/AbstractRDFTerm.java @@ -21,13 +21,13 @@ import org.apache.commons.rdf.rdf4j.RDF4JTerm; import org.eclipse.rdf4j.model.Value; abstract class AbstractRDFTerm<T extends Value> implements RDF4JTerm { - T value; + T value; - AbstractRDFTerm(T value) { - this.value = value; - } - - public T asValue() { - return value; - } + AbstractRDFTerm(T value) { + this.value = value; + } + + public T asValue() { + return value; + } } \ No newline at end of file