com.complexible.common.openrdf.model.Graphs.java Source code

Java tutorial

Introduction

Here is the source code for com.complexible.common.openrdf.model.Graphs.java

Source

/*
 * Copyright (c) 2009-2013 Clark & Parsia, LLC. <http://www.clarkparsia.com>
 *
 * Licensed 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 com.complexible.common.openrdf.model;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.openrdf.model.Graph;
import org.openrdf.model.Literal;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.impl.ValueFactoryImpl;
import org.openrdf.model.util.GraphUtil;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.model.vocabulary.XMLSchema;
import org.openrdf.query.GraphQueryResult;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.RDFParseException;

/**
 * <p>Utility methods for working with Graph objects</p>
 *
 * @author   Michael Grove
 * @since   0.4
 * @version   3.0
 */
public final class Graphs {

    private Graphs() {
        throw new AssertionError();
    }

    /**
     * Wrap the graph as an {@link ExtGraph}
     * @param theGraph  the graph
     * @return          the graph as an ExtGraph
     */
    public static ExtGraph extend(final Graph theGraph) {
        if (theGraph instanceof ExtGraph) {
            return (ExtGraph) theGraph;
        } else {
            return new ExtGraphImpl(theGraph);
        }
    }

    /**
     * Return an immutable version of the specified graph
     * @param theGraph  the graph
     * @return          an immutable version of the graph
     */
    public static ImmutableGraph immutable(final Graph theGraph) {
        return ImmutableGraph.of(theGraph);
    }

    /**
     * Return the contents of the list serialized as an RDF list
     * @param theResources   the list
     * @return            the list as RDF
     */
    public static Graph toList(final Resource... theResources) {
        return toList(Arrays.asList(theResources));
    }

    /**
     * Create a Graph from the RDF in the specified file
     *
     * @param theFile   the file to read the RDF from
     * @return         a new graph containing the RDF from the file
     *
     * @throws IOException         if there was an error reading the file
     * @throws RDFParseException   if the file did not contain valid RDF
     */
    public static Graph of(final File theFile) throws IOException, RDFParseException {
        return GraphIO.readGraph(theFile);
    }

    /**
     * Create a Sesame graph from the GraphQueryResult.  The query result is always closed regardless of whether or not
     * it was successfully transformed into a graph.
     *
     * @param theResult   the result of the query
     * @return         the graph built from the result
     *
     * @throws org.openrdf.query.QueryEvaluationException if there was an error while creating the graph from the query result
     */
    public static Graph newGraph(final GraphQueryResult theResult) throws QueryEvaluationException {
        Graph aGraph = new SetGraph();

        try {
            while (theResult.hasNext()) {
                aGraph.add(theResult.next());
            }
        } finally {
            theResult.close();
        }

        return aGraph;
    }

    /**
     * Return the contents of the list serialized as an RDF list
     * @param theResources   the list
     * @return            the list as RDF
     */
    public static Graph toList(final List<Resource> theResources) {
        Resource aCurr = ValueFactoryImpl.getInstance().createBNode();

        int i = 0;
        Graph aGraph = new SetGraph();
        for (Resource r : theResources) {
            Resource aNext = ValueFactoryImpl.getInstance().createBNode();
            aGraph.add(aCurr, RDF.FIRST, r);
            aGraph.add(aCurr, RDF.REST, ++i < theResources.size() ? aNext : RDF.NIL);
            aCurr = aNext;
        }

        return aGraph;
    }

    /**
     * Return the {@link Statement statements} as a {@link Graph}
     *
     * @param theStatements   the statements that will make up the Graph
     * @return             a Graph containing all the provided statements
     */
    public static Graph newGraph(final Statement... theStatements) {
        Graph aGraph = new SetGraph();

        aGraph.addAll(Arrays.asList(theStatements));

        return aGraph;
    }

    /**
     * Return the {@link Iterator} of {@link Statement statements} as a new {@link Graph}
     *
     * @param theStatements   the statements that will make up the Graph
     * @return            a Graph containing all the provided statements
     */
    public static Graph newGraph(final Iterator<Statement> theStatements) {
        final Graph aGraph = new SetGraph();

        while (theStatements.hasNext()) {
            aGraph.add(theStatements.next());
        }

        return aGraph;
    }

    /**
     * Return the {@link Iterable} of {@link Statement statements} as a {@link Graph}
     *
     * @param theStatements   the statements that will make up the Graph
     * @return             a Graph containing all the provided statements
     */
    public static Graph newGraph(final Iterable<Statement> theStatements) {
        final ExtGraphImpl aGraph = new ExtGraphImpl();

        for (Statement aStmt : theStatements) {
            aGraph.add(aStmt);
        }

        return aGraph;
    }

    /**
     * Return a new {@link #contextGraph} whose contents are the statements contained in the array.
     *
     * @param theStatements   the statements for the new graph
     * @return            the new graph
     */
    public static Graph newContextGraph(final Statement... theStatements) {
        return newContextGraph(Iterators.forArray(theStatements));
    }

    /**
     * Return a new {@link #contextGraph} whose contents are the statements contained in the iterator.
     *
     * @param theStatements the statements for the new graph
     * @return             the new graph
     */
    public static Graph newContextGraph(final Iterator<Statement> theStatements) {
        Graph aGraph = contextGraph();

        while (theStatements.hasNext()) {
            aGraph.add(theStatements.next());
        }

        return aGraph;
    }

    /**
     * Return a new {@link #contextGraph} whose contents are the statements contained in the {@link Iterable}.
     *
     * @param theStatements   the statements for the new graph
     * @return            the new graph
     */
    public static Graph newContextGraph(final Iterable<Statement> theStatements) {
        return newContextGraph(theStatements.iterator());
    }

    /**
     * Returns a copy of the provided graph where all the statements belong to the specified context.
     * This will overwrite any existing contexts on the statements in the graph.
     * 
     * @param theGraph      the graph
     * @param theResource   the context for all the statements in the graph
     * @return             the new graph
     */
    public static Graph withContext(final Graph theGraph, final Resource theResource) {
        final Graph aGraph = contextGraph();

        for (Statement aStmt : theGraph) {
            if (Objects.equal(aStmt.getContext(), theResource)) {
                aGraph.add(aStmt);
            } else {
                aGraph.add(aStmt.getSubject(), aStmt.getPredicate(), aStmt.getObject(), theResource);
            }
        }

        return aGraph;
    }

    /**
     * Return a new Graph which is the union of all the provided graphs.  Be careful if you are using statements w/ a context as the equals method for Statement
     * does not take into account context, so two statements with the same SPO, but different contexts will be considered the same statement and only one will
     * be included in the union.  You can use {@link ContextAwareStatement} which implements equals & hashcode taking into account the context if you need to use
     * Statements with contexts where context is considered in this way.
     * 
     * @param theGraphs the graphs to union
     * @return         the union of the graphs
     */
    public static Graph union(final Graph... theGraphs) {
        SetGraph aSetGraph = new SetGraph();

        for (Graph aGraph : theGraphs) {
            aSetGraph.addAll(aGraph);
        }

        return aSetGraph;
    }

    /**
     * Return a new (empty) graph whose ValueFactory is an instance of {@link ContextAwareValueFactory}
     * @return a new "context aware" graph
     */
    public static Graph contextGraph() {
        return new DelegatingGraph(new SetGraph()) {
            @Override
            public boolean add(final Statement e) {
                // SetGraph uses the context aware value factory, so we just need to xform the statement here
                // to a statement that uses that value factory
                return super.add(e.getSubject(), e.getPredicate(), e.getObject(), e.getContext());
            }
        };
    }

    /**
     * Create a {@link Predicate filtered} copy of the provided {@link Graph}
     *
     * @param theGraph      the graph to filter
     * @param thePredicate   the predicate to use for filtering
     * @return            the filtered graph
     */
    public static Graph filter(final Graph theGraph, final Predicate<Statement> thePredicate) {
        final SetGraph aGraph = new SetGraph();
        for (Statement aStmt : theGraph) {
            if (thePredicate.apply(aStmt)) {
                aGraph.add(aStmt);
            }
        }
        return aGraph;
    }

    public static boolean contains(final Iterable<Statement> theGraph, final Resource theSubject,
            final URI thePredicate, final Value theObject, final Resource... theContexts) {
        return !Iterables.isEmpty(filter(theGraph, theSubject, thePredicate, theObject, theContexts));
    }

    public static Iterable<Statement> filter(final Iterable<Statement> theGraph, final Resource theSubject,
            final URI thePredicate, final Value theObject, final Resource... theContexts) {
        return Iterables.filter(theGraph, new Predicate<Statement>() {
            @Override
            public boolean apply(final Statement theStatement) {
                if (theSubject != null && !theSubject.equals(theStatement.getSubject())) {
                    return false;
                }
                if (thePredicate != null && !thePredicate.equals(theStatement.getPredicate())) {
                    return false;
                }
                if (theObject != null && !theObject.equals(theStatement.getObject())) {
                    return false;
                }

                if (theContexts == null || theContexts.length == 0) {
                    // no context specified, SPO were all equal, so this is equals as null/empty context is a wildcard
                    return true;
                } else {
                    Resource aContext = theStatement.getContext();

                    for (Resource aCxt : theContexts) {
                        if (aCxt == null && aContext == null) {
                            return true;
                        }
                        if (aCxt != null && aCxt.equals(aContext)) {
                            return true;
                        }
                    }

                    return false;
                }
            }
        });
    }

    /**
     * {@link Function Transform} the contents of the {@link Graph}.  This returns a copy of the original
     * graph with the transformation applied
     *
     * @param theGraph      the graph to transform
     * @param theFunction   the function for the transform
     * @return            the transformed graph
     */
    public static Graph transform(final Graph theGraph, final Function<Statement, Statement> theFunction) {
        final SetGraph aGraph = new SetGraph();
        for (Statement aStmt : theGraph) {
            aGraph.add(theFunction.apply(aStmt));
        }
        return aGraph;
    }

    /**
     * Find a {@link Statement} which satisfies the given {@link Predicate}
     *
     * @param theGraph      the Graph
     * @param thePredicate   the predicate
     * @return            {@link Optional Optionally}, the first Statement to satisfy the Predicate, or an absent Optional if none do
     */
    public static Optional<Statement> find(final Graph theGraph, final Predicate<Statement> thePredicate) {
        for (Statement aStmt : theGraph) {
            if (thePredicate.apply(aStmt)) {
                return Optional.of(aStmt);
            }
        }
        return Optional.absent();
    }

    /**
     * Return whether or not at least one {@link Statement} satisfies the {@link Predicate}
     *
     * @param theGraph      the graph
     * @param thePredicate   the predicate
     * @return            true if at least one Statement satisfies the Predicate, false otherwise
     */
    public static boolean any(final Graph theGraph, final Predicate<Statement> thePredicate) {
        for (Statement aStmt : theGraph) {
            if (thePredicate.apply(aStmt)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Return whether or not all {@link Statement statements} satisfy the {@link Predicate}
     *
     * @param theGraph      the graph
     * @param thePredicate   the predicate
     * @return            true if at all Statements satisfy the Predicate, false otherwise
     */
    public static boolean all(final Graph theGraph, final Predicate<Statement> thePredicate) {
        for (Statement aStmt : theGraph) {
            if (!thePredicate.apply(aStmt)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Collect the results of the {@link Function} as it is applied to each {@link Statement}.  {@link Optional Absent}
     * values are not collected; the provided function should never return a null value.
     *
     * @param theGraph      the statements
     * @param theFunction   the function
     * @return            the collected values
     */
    public static <T> Collection<T> collect(final Iterable<Statement> theGraph,
            final Function<Statement, Optional<T>> theFunction) {
        final Set<T> aSet = Sets.newHashSet();
        for (Statement aStmt : theGraph) {
            final Optional<T> aResult = theFunction.apply(aStmt);
            if (aResult.isPresent()) {
                aSet.add(aResult.get());
            }
        }
        return aSet;
    }

    /**
     * Collect the results of the {@link Function} as it is applied to each {@link Statement}.  {@link Optional Absent}
     * values are not collected; the provided function should never return a null value.
     *
     * @param theStatementIterator      the statements
     * @param theFunction   the function
     * @return            the collected values
     */
    public static <T> Collection<T> collect(final Iterator<Statement> theStatementIterator,
            final Function<Statement, Optional<T>> theFunction) {
        final Set<T> aSet = Sets.newHashSet();
        while (theStatementIterator.hasNext()) {
            final Statement aStmt = theStatementIterator.next();

            Optional<T> aResult = theFunction.apply(aStmt);
            if (aResult.isPresent()) {
                aSet.add(aResult.get());
            }
        }
        return aSet;
    }

    /**
     * Return the value of the property for the given subject.  If there are multiple values, only the first value will
     * be returned.  Use {@link GraphUtil#getObjectIterator} if you want all values for the property.
     *
     * @param theGraph   the graph
     * @param theSubj   the subject
     * @param thePred   the property of the subject whose value should be retrieved
     *
     * @return          optionally, the value of the the property for the subject
     *
     * @see org.openrdf.model.util.GraphUtil#getOptionalObject
     */
    public static Optional<Value> getObject(final Graph theGraph, final Resource theSubj, final URI thePred) {
        Iterator<Value> aCollection = GraphUtil.getObjectIterator(theGraph, theSubj, thePred);

        if (aCollection.hasNext()) {
            return Optional.of(aCollection.next());
        } else {
            return Optional.absent();
        }
    }

    /**
     * Return the value of of the property as a Literal
     *
     * @param theGraph   the graph
     * @param theSubj   the resource
     * @param thePred   the property whose value is to be retrieved
     * @return          Optionally, the property value as a literal.  Value will be absent of the SP does not have an O, or the O is not a literal
     *
     * @see #getObject(org.openrdf.model.Graph, org.openrdf.model.Resource, org.openrdf.model.URI)
     */
    public static Optional<Literal> getLiteral(final Graph theGraph, final Resource theSubj, final URI thePred) {
        Optional<Value> aVal = getObject(theGraph, theSubj, thePred);

        if (aVal.isPresent() && aVal.get() instanceof Literal) {
            return Optional.of((Literal) aVal.get());
        } else {
            return Optional.absent();
        }
    }

    /**
     * Return the value of of the property as a Resource
     *
     * @param theGraph   the graph
     * @param theSubj   the resource
     * @param thePred   the property whose value is to be retrieved
     * @return          Optionally, the property value as a Resource.  Value will be absent of the SP does not have an O, or the O is not a Resource
     *
     * @see #getObject(org.openrdf.model.Graph, org.openrdf.model.Resource, org.openrdf.model.URI)
     * @see GraphUtil#getOptionalObjectResource
     */
    public static Optional<Resource> getResource(final Graph theGraph, final Resource theSubj, final URI thePred) {
        Optional<Value> aVal = getObject(theGraph, theSubj, thePred);

        if (aVal.isPresent() && aVal.get() instanceof Resource) {
            return Optional.of((Resource) aVal.get());
        } else {
            return Optional.absent();
        }
    }

    /**
     * Returns the value of the property on the given resource as a boolean.
     *
     * @param theGraph   the graph
     * @param theSubj   the resource
     * @param thePred   the property
     * @return          Optionally, the value of the property as a boolean.  Value will be absent if the SP does not have an O,
     *                or that O is not a literal or not a valid boolean value
     */
    public static Optional<Boolean> getBooleanValue(final Graph theGraph, final Resource theSubj,
            final URI thePred) {
        Optional<Literal> aLitOpt = getLiteral(theGraph, theSubj, thePred);

        if (!aLitOpt.isPresent()) {
            return Optional.absent();
        }

        Literal aLiteral = aLitOpt.get();

        if (((aLiteral.getDatatype() != null && aLiteral.getDatatype().equals(XMLSchema.BOOLEAN))
                || (aLiteral.getLabel().equalsIgnoreCase("true")
                        || aLiteral.getLabel().equalsIgnoreCase("false")))) {
            return Optional.of(Boolean.valueOf(aLiteral.getLabel()));
        } else {
            return Optional.absent();
        }
    }

    /**
     * Returns whether or not the given resource is a rdf:List
     *
     * @param theGraph   the graph
     * @param theRes   the resource to check
     *
     * @return         true if its a list, false otherwise
     */
    public static boolean isList(final Graph theGraph, final Resource theRes) {
        Iterable<Statement> sIter = filter(theGraph, theRes, RDF.FIRST, null);

        return theRes != null && theRes.equals(RDF.NIL) || !Iterables.isEmpty(sIter);
    }

    /**
     * Return the contents of the given list by following the rdf:first/rdf:rest structure of the list
     * @param theGraph   the graph
     * @param theRes   the resource which is the head of the list
     *
     * @return          the contents of the list.
     */
    public static List<Value> asList(final Graph theGraph, final Resource theRes) {
        List<Value> aList = Lists.newArrayList();

        Resource aListRes = theRes;

        while (aListRes != null) {

            Optional<Resource> aFirst = getResource(theGraph, aListRes, RDF.FIRST);
            Optional<Resource> aRest = getResource(theGraph, aListRes, RDF.REST);

            if (aFirst.isPresent()) {
                aList.add(aFirst.get());
            }

            if (aRest.or(RDF.NIL).equals(RDF.NIL)) {
                aListRes = null;
            } else {
                aListRes = aRest.get();
            }
        }

        return aList;
    }

    /**
     * Return an {@link Iterable} of the types of the {@link Resource} in the specified {@link Graph}
     *
     * @param theGraph   the graph
     * @param theRes   the resource
     * @return         the asserted rdf:type's of the resource
     */
    public static Iterable<Resource> getTypes(final Graph theGraph, final Resource theRes) {
        return collect(filter(theGraph, theRes, RDF.TYPE, null).iterator(), Statements.objectAsResource());
    }

    public static void write(final Graph theGraph, final RDFFormat theFormat, final File theFile)
            throws IOException {
        FileOutputStream aOut = new FileOutputStream(theFile);
        try {
            write(theGraph, theFormat, aOut);
        } finally {
            aOut.close();
        }
    }

    public static void write(final Graph theGraph, final RDFFormat theFormat, final OutputStream theStream)
            throws IOException {
        write(theGraph, theFormat, new OutputStreamWriter(theStream));
    }

    public static void write(final Graph theGraph, final RDFFormat theFormat, final Writer theWriter)
            throws IOException {
        GraphIO.writeGraph(theGraph, theWriter, theFormat);
    }

    //    public static TupleQueryResult select(final Graph theGraph, final String theQuery) throws MalformedQueryException, QueryEvaluationException {
    //        Repository aRepo = Repositories.createInMemoryRepo();
    //        try {
    //           Repositories.add(aRepo, theGraph);
    //            return aRepo.selectQuery(QueryLanguage.SPARQL, theQuery);
    //        }
    //        catch (RepositoryException e) {
    //            throw new QueryEvaluationException("There was an error setting up the repository to execute the query", e);
    //        }
    //        finally {
    //            try {
    //                aRepo.shutDown();
    //            }
    //            catch (RepositoryException e) {
    //                // can probably ignore this, its just an in mem repo anyway.
    //            }
    //        }
    //    }
}