All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tinkerpop.blueprints.oupls.sail.pg.PropertyGraphSailConnection Maven / Gradle / Ivy

package com.tinkerpop.blueprints.oupls.sail.pg;

import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Element;
import com.tinkerpop.blueprints.Vertex;
import info.aduna.iteration.CloseableIteration;
import net.fortytwo.sesametools.SailConnectionTripleSource;
import org.openrdf.model.Literal;
import org.openrdf.model.Namespace;
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.NamespaceImpl;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.model.vocabulary.XMLSchema;
import org.openrdf.query.BindingSet;
import org.openrdf.query.Dataset;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.algebra.TupleExpr;
import org.openrdf.query.algebra.UpdateExpr;
import org.openrdf.query.algebra.evaluation.TripleSource;
import org.openrdf.query.algebra.evaluation.impl.EvaluationStrategyImpl;
import org.openrdf.sail.SailException;
import org.openrdf.sail.helpers.SailBase;
import org.openrdf.sail.helpers.SailConnectionBase;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;

/**
 * Connection to a PropertyGraphSail
 *
 * @author Joshua Shinavier (http://fortytwo.net)
 */
class PropertyGraphSailConnection extends SailConnectionBase {
    private static final Map namespaces = new HashMap();

    static {
        addNamespace("prop", PropertyGraphSail.PROPERTY_NS);
        addNamespace("pgm", PropertyGraphSail.ONTOLOGY_NS);
        addNamespace("vertex", PropertyGraphSail.VERTEX_NS);
        addNamespace("edge", PropertyGraphSail.EDGE_NS);
        addNamespace("rdf", RDF.NAMESPACE);
    }

    private final PropertyGraphSail.PropertyGraphContext context;

    private boolean open = true;

    private final ElementGenerator allVertexStatements;
    private final ElementGenerator vertexIds;
    private final ElementGenerator vertexProps;
    private final ElementGenerator vertexTypes;
    private final ElementGenerator allEdgeStatements;
    // TODO: generator for predicate-specific statements
    private final FirstClassEdgeGenerator labels;
    private final FirstClassEdgeGenerator heads;
    private final FirstClassEdgeGenerator tails;
    private final FirstClassEdgeGenerator edgeTypes;
    private final FirstClassEdgeGenerator edgeIds;
    private final FirstClassEdgeGenerator edgeProps;
    private final RelationGenerator allInRelations;
    private final RelationGenerator allOutRelations;

    private final boolean firstClassEdges;

    public PropertyGraphSailConnection(final SailBase sailBase,
                                       final PropertyGraphSail.PropertyGraphContext context,
                                       final boolean firstClassEdges) {
        super(sailBase);

        this.context = context;
        this.firstClassEdges = firstClassEdges;

        allVertexStatements = new VertexGenerator();
        allVertexStatements.setDoId(true);
        allVertexStatements.setDoProperties(true);
        allVertexStatements.setDoType(true);

        if (firstClassEdges) {
            allEdgeStatements = new FirstClassEdgeGenerator();
            allEdgeStatements.setDoId(true);
            allEdgeStatements.setDoProperties(true);
            allEdgeStatements.setDoType(true);
            ((FirstClassEdgeGenerator) allEdgeStatements).setDoHead(true);
            ((FirstClassEdgeGenerator) allEdgeStatements).setDoTail(true);
            ((FirstClassEdgeGenerator) allEdgeStatements).setDoLabel(true);
            allInRelations = null;
            allOutRelations = null;
        } else {
            allEdgeStatements = new SimpleEdgeGenerator(null);
            allInRelations = new RelationGenerator(null, true);
            allOutRelations = new RelationGenerator(null, false);
        }

        vertexTypes = new VertexGenerator();
        vertexTypes.setDoType(true);

        vertexIds = new VertexGenerator();
        vertexIds.setDoId(true);

        vertexProps = new VertexGenerator();
        vertexProps.setDoProperties(true);

        if (firstClassEdges) {
            edgeTypes = new FirstClassEdgeGenerator();
            edgeTypes.setDoType(true);

            labels = new FirstClassEdgeGenerator();
            labels.setDoLabel(true);

            heads = new FirstClassEdgeGenerator();
            heads.setDoHead(true);

            tails = new FirstClassEdgeGenerator();
            tails.setDoTail(true);

            edgeIds = new FirstClassEdgeGenerator();
            edgeIds.setDoId(true);

            edgeProps = new FirstClassEdgeGenerator();
            edgeProps.setDoProperties(true);
        } else {
            edgeTypes = null;
            labels = null;
            heads = null;
            tails = null;
            edgeIds = null;
            edgeProps = null;
        }
    }

    private static void addNamespace(final String prefix,
                                     final String uri) {
        Namespace n = new NamespaceImpl(prefix, uri);
        namespaces.put(prefix, n);
    }

    protected boolean isOpenInternal() throws SailException {
        return open;
    }

    protected void closeInternal() throws SailException {
        open = false;
    }

    protected CloseableIteration evaluateInternal(final TupleExpr query,
                                                                                                  final Dataset dataset,
                                                                                                  final BindingSet bindings,
                                                                                                  final boolean includeInferred) throws SailException {
        try {
            TripleSource tripleSource = new SailConnectionTripleSource(this, context.valueFactory, includeInferred);
            EvaluationStrategyImpl strategy = new EvaluationStrategyImpl(tripleSource, dataset);
            return strategy.evaluate(query, bindings);
        } catch (QueryEvaluationException e) {
            throw new SailException(e);
        }
    }

    public void executeUpdate(UpdateExpr updateExpr, Dataset dataset, BindingSet bindingSet, boolean b) throws SailException {
        // Do nothing.
    }

    protected CloseableIteration getContextIDsInternal() throws SailException {
        throw new UnsupportedOperationException();
    }

    private boolean matchesNullContext(final Resource... contexts) {
        if (0 == contexts.length) {
            return true;
        } else {
            for (Resource c : contexts) {
                if (null == c) {
                    return true;
                }
            }

            return false;
        }
    }

    protected CloseableIteration getStatementsInternal(final Resource subject,
                                                                                           final URI predicate,
                                                                                           final Value object,
                                                                                           final boolean includeInferred,
                                                                                           final Resource... contexts) throws SailException {
        // Statements exist only in the default context.
        if (!matchesNullContext(contexts)) {
            return new StatementIteration();
        }

        // TODO: elements embedded in URIs

        if (null == subject) {
            if (null == object) {
                if (null == predicate) {  // ? ? ?
                    return getStatements_xxx();
                } else {  // ? p ?
                    return getStatements_xPx(predicate);
                }
            } else {
                if (null == predicate) {  // ? ? o
                    return getStatements_xxO(object);
                } else {  // ? p o
                    return getStatements_xPO(predicate, object);
                }
            }
        } else {
            if (null == object) {
                if (null == predicate) {  // s ? ?
                    return getStatements_Sxx(subject);
                } else {  // s p ?
                    return getStatements_SPx(subject, predicate);
                }
            } else {
                if (null == predicate) {  // s ? o
                    return getStatements_SxO(subject, object);
                } else {  // s p o
                    return getStatements_SPO(subject, predicate, object);
                }
            }
        }
    }

    private CloseableIteration getStatements_xxx() throws SailException {
        Iterator edgeIterator = context.graph.getEdges().iterator();
        Iterator vertexIterator = context.graph.getVertices().iterator();
        Source edges = new Source(edgeIterator, allEdgeStatements);
        Source vertices = new Source(vertexIterator, allVertexStatements);
        return new StatementIteration(vertices, edges);
    }

    private CloseableIteration getStatements_Sxx(final Resource subject) throws SailException {
        if (subject instanceof URI) {
            Vertex v = vertexForURI((URI) subject);
            if (null == v) {
                if (!firstClassEdges) {
                    return new StatementIteration();
                }

                Edge e = edgeForURI((URI) subject);
                if (null == e) {
                    return new StatementIteration();
                } else {
                    Source s = new Source(new SingleItemIterator(e), allEdgeStatements);
                    return new StatementIteration(s);
                }
            } else {
                Source s = new Source(new SingleItemIterator(v), allVertexStatements);
                if (firstClassEdges) {
                    return new StatementIteration(s);
                } else {
                    Source s2 = new Source(new SingleItemIterator(v), allOutRelations);
                    return new StatementIteration(s, s2);
                }
            }
        } else {
            return new StatementIteration();
        }
    }

    private CloseableIteration getStatements_SPx(final Resource subject,
                                                                           final URI predicate) throws SailException {
        if (subject instanceof URI) {
            if (predicate.equals(RDF.TYPE)) {
                Vertex v = vertexForURI((URI) subject);
                if (null == v) {
                    if (!firstClassEdges) {
                        return new StatementIteration();
                    }

                    Edge e = edgeForURI((URI) subject);
                    if (null == e) {
                        return new StatementIteration();
                    } else {
                        Source s = new Source(new SingleItemIterator(e), edgeTypes);
                        return new StatementIteration(s);
                    }
                } else {
                    Source s = new Source(new SingleItemIterator(v), vertexTypes);
                    return new StatementIteration(s);
                }
            } else if (predicate.equals(PropertyGraphSail.ID)) {
                Vertex v = vertexForURI((URI) subject);
                if (null == v) {
                    if (!firstClassEdges) {
                        return new StatementIteration();
                    }

                    Edge e = edgeForURI((URI) subject);
                    if (null == e) {
                        return new StatementIteration();
                    } else {
                        Source s = new Source(new SingleItemIterator(e), edgeIds);
                        return new StatementIteration(s);
                    }
                } else {
                    Source s = new Source(new SingleItemIterator(v), vertexIds);
                    return new StatementIteration(s);
                }
            } else if (predicate.equals(PropertyGraphSail.LABEL)) {
                if (!firstClassEdges) {
                    return new StatementIteration();
                }

                Edge e = edgeForURI((URI) subject);
                if (null == e) {
                    return new StatementIteration();
                } else {
                    Source s = new Source(new SingleItemIterator(e), labels);
                    return new StatementIteration(s);
                }
            } else if (predicate.equals(PropertyGraphSail.HEAD)) {
                if (!firstClassEdges) {
                    return new StatementIteration();
                }

                Edge e = edgeForURI((URI) subject);
                if (null == e) {
                    return new StatementIteration();
                } else {
                    Source s = new Source(new SingleItemIterator(e), heads);
                    return new StatementIteration(s);
                }
            } else if (predicate.equals(PropertyGraphSail.TAIL)) {
                if (!firstClassEdges) {
                    return new StatementIteration();
                }

                Edge e = edgeForURI((URI) subject);
                if (null == e) {
                    return new StatementIteration();
                } else {
                    Source s = new Source(new SingleItemIterator(e), tails);
                    return new StatementIteration(s);
                }
            } else if (isPropertyPredicate(predicate)) {
                String key = keyFromPredicate(predicate);
                Vertex v = vertexForURI((URI) subject);
                if (null == v) {
                    if (!firstClassEdges) {
                        return new StatementIteration();
                    }

                    Edge e = edgeForURI((URI) subject);
                    if (null == e) {
                        return new StatementIteration();
                    } else {
                        Source s = new Source(new SingleItemIterator(e), edgePropertiesWithKey(key, predicate));
                        return new StatementIteration(s);
                    }
                } else {
                    Source s = new Source(new SingleItemIterator(v), vertexPropertiesWithKey(key, predicate));
                    return new StatementIteration(s);
                }
            } else if (isRelationPredicate(predicate)) {
                Vertex v = vertexForURI((URI) subject);
                if (null != v) {
                    String label = labelForRelationPredicate(predicate);
                    Source s = new Source(new SingleItemIterator(v), new RelationGenerator(label, false));
                    return new StatementIteration(s);
                } else {
                    return new StatementIteration();
                }
            } else {
                return new StatementIteration();
            }
        } else {
            return new StatementIteration();
        }
    }

    private CloseableIteration getStatements_SxO(final Resource subject,
                                                                           final Value object) throws SailException {
        if (subject instanceof URI) {
            Collection sources = new LinkedList();

            Vertex v = vertexForURI((URI) subject);
            Edge e = edgeForURI((URI) subject);
            Object val = literalToObject(object);
            Vertex vObj = object instanceof URI ? vertexForURI((URI) object) : null;

            // vertex id
            if (null != val && null != v) {
                if (v.getId().equals(val)) {
                    Source s = new Source(new SingleItemIterator(v), vertexIds);
                    sources.add(s);
                }
            }

            // vertex type
            if (null != v && object instanceof URI && ((URI) object).equals(PropertyGraphSail.VERTEX)) {
                Source s = new Source(new SingleItemIterator(v), vertexTypes);
                sources.add(s);
            }

            // vertex properties
            if (null != val && null != v) {
                Source vertices = new Source(
                        new SingleItemIterator(v),
                        vertexPropertiesWithValue(val, (Literal) object));
                sources.add(vertices);
            }

            if (firstClassEdges) {
                // edge id
                if (null != val && null != e) {
                    if (e.getId().equals(val)) {
                        Source s = new Source(new SingleItemIterator(e), edgeIds);
                        sources.add(s);
                    }
                }

                // label
                if (null != val && (val instanceof String)) {
                    if (null != e && e.getLabel().equals(val)) {
                        Source s = new Source(new SingleItemIterator(e), labels);
                        sources.add(s);
                    }
                }

                // head
                if (null != e && null != vObj && e.getVertex(Direction.IN).equals(vObj)) {
                    Source s = new Source(new SingleItemIterator(e), heads);
                    sources.add(s);
                }

                // tail
                if (null != e && null != vObj && e.getVertex(Direction.OUT).equals(vObj)) {
                    Source s = new Source(new SingleItemIterator(e), tails);
                    sources.add(s);
                }

                // edge type
                if (null != e && object instanceof URI && ((URI) object).equals(PropertyGraphSail.VERTEX)) {
                    Source s = new Source(new SingleItemIterator(e), edgeTypes);
                    sources.add(s);
                }

                // edge properties
                if (null != val && null != e) {
                    Source edges = new Source(
                            new SingleItemIterator(e),
                            edgePropertiesWithValue(val, (Literal) object));
                    sources.add(edges);
                }
            } else {
                if (null != v && null != vObj) {
                    Collection edges = new LinkedList();
                    for (Edge ev : v.getEdges(Direction.OUT)) {
                        if (ev.getVertex(Direction.IN).equals(vObj)) {
                            edges.add(ev);
                        }
                    }
                    if (edges.size() > 0) {
                        sources.add(new Source(edges.iterator(), allEdgeStatements));
                    }
                }
            }

            if (sources.size() > 0) {
                Source[] s = new Source[sources.size()];
                sources.toArray(s);
                return new StatementIteration(s);
            } else {
                return new StatementIteration();
            }
        } else {
            return new StatementIteration();
        }
    }

    private CloseableIteration getStatements_SPO(final Resource subject,
                                                                           final URI predicate,
                                                                           final Value object) throws SailException {
        if (predicate.equals(RDF.TYPE)) {
            if (subject instanceof URI) {
                Vertex v = vertexForURI((URI) subject);
                if (null == v) {
                    if (!firstClassEdges) {
                        return new StatementIteration();
                    }

                    Edge e = edgeForURI((URI) subject);
                    if (null == e) {
                        return new StatementIteration();
                    } else {
                        if (object.equals(PropertyGraphSail.EDGE)) {
                            Source s = new Source(new SingleItemIterator(e), edgeTypes);
                            return new StatementIteration(s);
                        } else {
                            return new StatementIteration();
                        }
                    }
                } else {
                    if (object.equals(PropertyGraphSail.VERTEX)) {
                        Source s = new Source(new SingleItemIterator(v), vertexTypes);
                        return new StatementIteration(s);
                    } else {
                        return new StatementIteration();
                    }
                }
            } else {
                return new StatementIteration();
            }
        } else if (predicate.equals(PropertyGraphSail.ID)) {
            Object id = literalToObject(object);
            if (null == id || !(subject instanceof URI)) {
                return new StatementIteration();
            } else {
                Vertex v = vertexForURI((URI) subject);
                if (null == v) {
                    if (!firstClassEdges) {
                        return new StatementIteration();
                    }

                    Edge e = edgeForURI((URI) subject);
                    if (null == e) {
                        return new StatementIteration();
                    } else {
                        if (e.getId().equals(id)) {
                            Source s = new Source(new SingleItemIterator(e), edgeIds);
                            return new StatementIteration(s);
                        } else {
                            return new StatementIteration();
                        }
                    }
                } else {
                    if (v.getId().equals(id)) {
                        Source s = new Source(new SingleItemIterator(v), vertexIds);
                        return new StatementIteration(s);
                    } else {
                        return new StatementIteration();
                    }
                }
            }
        } else if (predicate.equals(PropertyGraphSail.LABEL)) {
            if (!firstClassEdges) {
                return new StatementIteration();
            }

            Object label = literalToObject(object);
            if (null == label || !(label instanceof String) || !(subject instanceof URI)) {
                return new StatementIteration();
            } else {
                Edge e = edgeForURI((URI) subject);
                if (null == e || !e.getLabel().equals(label)) {
                    return new StatementIteration();
                } else {
                    Source s = new Source(new SingleItemIterator(e), labels);
                    return new StatementIteration(s);
                }
            }
        } else if (predicate.equals(PropertyGraphSail.HEAD)) {
            if (!firstClassEdges) {
                return new StatementIteration();
            }

            if (!(subject instanceof URI) || !(object instanceof URI)) {
                return new StatementIteration();
            } else {
                Edge e = edgeForURI((URI) subject);
                Vertex v = vertexForURI((URI) object);
                if (null == e || null == v || !e.getVertex(Direction.IN).equals(v)) {
                    return new StatementIteration();
                } else {
                    Source s = new Source(new SingleItemIterator(e), heads);
                    return new StatementIteration(s);
                }
            }
        } else if (predicate.equals(PropertyGraphSail.TAIL)) {
            if (!firstClassEdges) {
                return new StatementIteration();
            }

            if (!(subject instanceof URI) || !(object instanceof URI)) {
                return new StatementIteration();
            } else {
                Edge e = edgeForURI((URI) subject);
                Vertex v = vertexForURI((URI) object);
                if (null == e || null == v || !e.getVertex(Direction.OUT).equals(v)) {
                    return new StatementIteration();
                } else {
                    Source s = new Source(new SingleItemIterator(e), tails);
                    return new StatementIteration(s);
                }
            }
        } else if (isPropertyPredicate(predicate)) {
            Object val = literalToObject(object);
            if (null == val || !(subject instanceof URI)) {
                return new StatementIteration();
            } else {
                String key = keyFromPredicate(predicate);
                Vertex v = vertexForURI((URI) subject);
                if (null == v) {
                    if (!firstClassEdges) {
                        return new StatementIteration();
                    }

                    Edge e = edgeForURI((URI) subject);
                    if (null == e) {
                        return new StatementIteration();
                    } else {
                        Source edges = new Source(
                                new SingleItemIterator(e),
                                edgePropertiesWithKeyAndValue(key, predicate, val, (Literal) object));
                        return new StatementIteration(edges);
                    }
                } else {
                    Source vertices = new Source(
                            new SingleItemIterator(v),
                            vertexPropertiesWithKeyAndValue(key, predicate, val, (Literal) object));
                    return new StatementIteration(vertices);
                }
            }
        } else if (isRelationPredicate(predicate)) {
            if (!(subject instanceof URI) || !(object instanceof URI)) {
                return new StatementIteration();
            } else {
                String label = labelForRelationPredicate(predicate);

                Vertex vSubj = vertexForURI((URI) subject);
                Vertex vObj = vertexForURI((URI) object);

                if (null != vSubj && null != vObj) {

                    Collection edges = new LinkedList();
                    for (Edge ev : vSubj.getEdges(Direction.OUT, label)) {
                        if (ev.getVertex(Direction.IN).equals(vObj)) {
                            edges.add(ev);
                        }
                    }
                    if (edges.size() > 0) {
                        return new StatementIteration(new Source(edges.iterator(), allEdgeStatements));
                    } else {
                        return new StatementIteration();
                    }
                } else {
                    return new StatementIteration();
                }
            }
        } else {
            return new StatementIteration();
        }
    }

    private CloseableIteration getStatements_xxO(final Value object) throws SailException {
        if (object instanceof URI) {
            Vertex v = vertexForURI((URI) object);
            if (null == v) {
                if (object.equals(PropertyGraphSail.VERTEX)) {
                    Source vertices = new Source(context.graph.getVertices().iterator(), vertexTypes);
                    return new StatementIteration(vertices);
                } else if (object.equals(PropertyGraphSail.EDGE) && firstClassEdges) {
                    Source edges = new Source(context.graph.getEdges().iterator(), edgeTypes);
                    return new StatementIteration(edges);
                } else {
                    return new StatementIteration();
                }
            } else {
                if (firstClassEdges) {
                    Source ins = new Source(v.getEdges(Direction.IN).iterator(), heads);
                    Source outs = new Source(v.getEdges(Direction.OUT).iterator(), tails);
                    return new StatementIteration(ins, outs);
                } else {
                    Source s = new Source(new SingleItemIterator(v), allInRelations);
                    return new StatementIteration(s);
                }
            }
        } else {
            Object val = literalToObject(object);
            if (null == val) {
                return new StatementIteration();
            } else {
                Collection sources = new LinkedList();

                // id
                {
                    Vertex v = context.graph.getVertex(val);
                    if (null != v) {
                        sources.add(new Source(new SingleItemIterator(v), vertexIds));
                    }
                    if (firstClassEdges) {
                        Edge e = context.graph.getEdge(val);
                        if (null != e) {
                            sources.add(new Source(new SingleItemIterator(e), edgeIds));
                        }
                    }
                }

                // label
                if (firstClassEdges) {
                    // TODO: find matching edges faster using indices
                    if (val instanceof String) {
                        Source s = new Source(
                                context.graph.getEdges().iterator(),
                                matchingLabels((String) val, object));
                        sources.add(s);
                    }
                }

                // properties
                {
                    // TODO: find matching vertices and edges faster using indices
                    Source vertices = new Source(
                            context.graph.getVertices().iterator(),
                            vertexPropertiesWithValue(val, (Literal) object));
                    sources.add(vertices);
                    if (firstClassEdges) {
                        Source edges = new Source(
                                context.graph.getEdges().iterator(),
                                edgePropertiesWithValue(val, (Literal) object));
                        sources.add(edges);
                    }
                }

                if (sources.size() > 0) {
                    Source[] s = new Source[sources.size()];
                    sources.toArray(s);
                    return new StatementIteration(s);
                } else {
                    return new StatementIteration();
                }
            }
        }
    }

    private CloseableIteration getStatements_xPO(final URI predicate,
                                                                           final Value object) throws SailException {
        if (predicate.equals(RDF.TYPE)) {
            if (object.equals(PropertyGraphSail.VERTEX)) {
                Source s = new Source(context.graph.getVertices().iterator(), vertexTypes);
                return new StatementIteration(s);
            } else if (object.equals(PropertyGraphSail.EDGE) && firstClassEdges) {
                Source s = new Source(context.graph.getEdges().iterator(), edgeTypes);
                return new StatementIteration(s);
            } else {
                return new StatementIteration();
            }
        } else if (predicate.equals(PropertyGraphSail.ID)) {
            Object id = literalToObject(object);
            if (null == id) {
                return new StatementIteration();
            } else {
                Vertex v = context.graph.getVertex(id);
                Edge e = firstClassEdges ? context.graph.getEdge(id) : null;
                if (null == v && null == e) {
                    return new StatementIteration();
                } else {
                    Collection s = new LinkedList();
                    if (null != v) {
                        vertexIds.generate(v, s);
                    }
                    if (null != e) {
                        edgeIds.generate(e, s);
                    }
                    return new SimpleCloseableIteration(s.iterator());
                }
            }
        } else if (predicate.equals(PropertyGraphSail.LABEL)) {
            if (!firstClassEdges) {
                return new StatementIteration();
            }

            // TODO: find edges faster using indices
            Object label = literalToObject(object);
            if (null == label || !(label instanceof String)) {
                return new StatementIteration();
            } else {
                Source edges = new Source(
                        context.graph.getEdges().iterator(),
                        matchingLabels((String) label, object));
                return new StatementIteration(edges);
            }
        } else if (predicate.equals(PropertyGraphSail.HEAD)) {
            if (!firstClassEdges) {
                return new StatementIteration();
            }

            Vertex v = object instanceof URI
                    ? vertexForURI((URI) object)
                    : null;
            if (null == v) {
                return new StatementIteration();
            } else {
                Iterator edgeIterator = v.getEdges(Direction.IN).iterator();
                Source edges = new Source(edgeIterator, heads);
                return new StatementIteration(edges);
            }
        } else if (predicate.equals(PropertyGraphSail.TAIL)) {
            if (!firstClassEdges) {
                return new StatementIteration();
            }

            Vertex v = object instanceof URI
                    ? vertexForURI((URI) object)
                    : null;
            if (null == v) {
                return new StatementIteration();
            } else {
                Iterator edgeIterator = v.getEdges(Direction.OUT).iterator();
                Source edges = new Source(edgeIterator, tails);
                return new StatementIteration(edges);
            }
        } else if (isPropertyPredicate(predicate)) {
            Object value = literalToObject(object);
            if (null == value) {
                return new StatementIteration();
            } else {
                // TODO: lookup matching vertices and edges faster using indices
                String key = keyFromPredicate(predicate);
                Source vertices = new Source(
                        context.graph.getVertices().iterator(),
                        vertexPropertiesWithKeyAndValue(key, predicate, value, (Literal) object));
                if (firstClassEdges) {
                    Source edges = new Source(
                            context.graph.getEdges().iterator(),
                            edgePropertiesWithKeyAndValue(key, predicate, value, (Literal) object));
                    return new StatementIteration(vertices, edges);
                } else {
                    return new StatementIteration(vertices);
                }
            }
        } else if (isRelationPredicate(predicate)) {
            if (!(object instanceof URI)) {
                return new StatementIteration();
            } else {
                String label = labelForRelationPredicate(predicate);
                Vertex vObj = vertexForURI((URI) object);

                if (null != vObj) {
                    Source s = new Source(new SingleItemIterator(vObj), new RelationGenerator(label, true));
                    return new StatementIteration(s);
                } else {
                    return new StatementIteration();
                }
            }
        } else {
            return new StatementIteration();
        }
    }

    private CloseableIteration getStatements_xPx(final URI predicate) throws SailException {
        if (predicate.equals(RDF.TYPE)) {
            Source vertices = new Source(context.graph.getVertices().iterator(), vertexTypes);
            if (firstClassEdges) {
                Source edges = new Source(context.graph.getEdges().iterator(), edgeTypes);
                return new StatementIteration(vertices, edges);
            } else {
                return new StatementIteration(vertices);
            }
        } else if (predicate.equals(PropertyGraphSail.ID)) {
            Source vertices = new Source(context.graph.getVertices().iterator(), vertexIds);
            if (firstClassEdges) {
                Source edges = new Source(context.graph.getEdges().iterator(), edgeIds);
                return new StatementIteration(vertices, edges);
            } else {
                return new StatementIteration(vertices);
            }
        } else if (predicate.equals(PropertyGraphSail.LABEL)) {
            if (!firstClassEdges) {
                return new StatementIteration();
            }

            Iterator edgeIterator = context.graph.getEdges().iterator();
            Source edges = new Source(edgeIterator, labels);
            return new StatementIteration(edges);
        } else if (predicate.equals(PropertyGraphSail.HEAD)) {
            if (!firstClassEdges) {
                return new StatementIteration();
            }

            Iterator edgeIterator = context.graph.getEdges().iterator();
            Source edges = new Source(edgeIterator, heads);
            return new StatementIteration(edges);
        } else if (predicate.equals(PropertyGraphSail.TAIL)) {
            if (!firstClassEdges) {
                return new StatementIteration();
            }

            Iterator edgeIterator = context.graph.getEdges().iterator();
            Source edges = new Source(edgeIterator, tails);
            return new StatementIteration(edges);
        } else if (isPropertyPredicate(predicate)) {
            // TODO: find elements faster using indices
            String key = keyFromPredicate(predicate);
            Source vertices = new Source(
                    context.graph.getVertices().iterator(),
                    vertexPropertiesWithKey(key, predicate));
            if (firstClassEdges) {
                Source edges = new Source(
                        context.graph.getEdges().iterator(),
                        edgePropertiesWithKey(key, predicate));
                return new StatementIteration(vertices, edges);
            } else {
                return new StatementIteration(vertices);
            }
        } else if (isRelationPredicate(predicate)) {
            String label = labelForRelationPredicate(predicate);
            Iterator edgeIterator = context.graph.getEdges().iterator();
            Source edges = new Source(edgeIterator, new SimpleEdgeGenerator(label));
            return new StatementIteration(edges);
        } else {
            return new StatementIteration();
        }
    }

    private boolean isPropertyPredicate(final URI predicate) {
        return predicate.stringValue().startsWith(PropertyGraphSail.PROPERTY_NS);
    }

    private boolean isRelationPredicate(final URI predicate) {
        return predicate.stringValue().startsWith(PropertyGraphSail.RELATION_NS);
    }

    private String labelForRelationPredicate(final URI predicate) {
        return predicate.stringValue().substring(PropertyGraphSail.RELATION_NS.length());
    }

    private String keyFromPredicate(final URI predicate) {
        return predicate.stringValue().substring(PropertyGraphSail.PROPERTY_NS.length());
    }

    protected long sizeInternal(final Resource... contexts) throws SailException {
        if (!matchesNullContext(contexts)) {
            return 0;
        }

        long count = 0;

        for (Edge e : context.graph.getEdges()) {
            if (firstClassEdges) {
                count += 5  // type, id, label, head, tail
                        + e.getPropertyKeys().size();
            } else {
                count++;
            }
        }

        for (Vertex v : context.graph.getVertices()) {
            count += 2 // type, id
                    + v.getPropertyKeys().size();
        }

        return count;
    }

    protected void startTransactionInternal() throws SailException {
        // Do nothing.
    }

    protected void commitInternal() throws SailException {
        // Do nothing.
    }

    protected void rollbackInternal() throws SailException {
        // Do nothing.
    }

    protected void addStatementInternal(Resource resource, URI uri, Value value, Resource... resources) throws SailException {
        // Do nothing.
    }

    protected void removeStatementsInternal(Resource resource, URI uri, Value value, Resource... resources) throws SailException {
        // Do nothing.
    }

    protected void clearInternal(Resource... resources) throws SailException {
        // Do nothing.
    }

    protected CloseableIteration getNamespacesInternal() throws SailException {
        return new SimpleCloseableIteration(namespaces.values().iterator());
    }

    protected String getNamespaceInternal(final String prefix) throws SailException {
        Namespace n = namespaces.get(prefix);
        return null == n ? null : n.getName();
    }

    protected void setNamespaceInternal(String s, String s1) throws SailException {
        // Do nothing.
    }

    protected void removeNamespaceInternal(String s) throws SailException {
        // Do nothing.
    }

    protected void clearNamespacesInternal() throws SailException {
        // Do nothing.
    }

    private static class SingleItemIterator implements Iterator {
        private T item;

        public SingleItemIterator(final T item) {
            this.item = item;
        }

        public boolean hasNext() {
            return null != item;
        }

        public T next() {
            T tmp = item;
            item = null;
            return tmp;
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }
    }

    private Vertex vertexForURI(final URI uri) {
        String s = uri.stringValue();

        return s.startsWith(PropertyGraphSail.VERTEX_NS)
                ? context.graph.getVertex(idFromString(s.substring(PropertyGraphSail.VERTEX_NS.length())))
                : null;
    }

    private Edge edgeForURI(final URI uri) {
        if (firstClassEdges) {
            String s = uri.stringValue();

            return s.startsWith(PropertyGraphSail.EDGE_NS)
                    ? context.graph.getEdge(idFromString(s.substring(PropertyGraphSail.EDGE_NS.length())))
                    : null;
        } else {
            return null;
        }
    }

    private Object literalToObject(final Value v) {
        if (v instanceof Literal) {
            Literal l = (Literal) v;

            URI type = l.getDatatype();
            if (null == type) {
                return l.getLabel();
            } else {
                if (type.equals(XMLSchema.STRING)) {
                    return l.stringValue();
                } else if (type.equals(XMLSchema.LONG)) {
                    return l.longValue();
                } else if (type.equals(XMLSchema.INT)) {
                    return l.intValue();
                } else if (type.equals(XMLSchema.INTEGER)) {
                    return l.integerValue();
                } else if (type.equals(XMLSchema.BYTE)) {
                    return l.byteValue();
                } else if (type.equals(XMLSchema.BOOLEAN)) {
                    return l.booleanValue();
                } else if (type.equals(XMLSchema.SHORT)) {
                    return l.shortValue();
                } else if (type.equals(XMLSchema.FLOAT)) {
                    return l.floatValue();
                } else if (type.equals(XMLSchema.DOUBLE)) {
                    return l.doubleValue();
                } else {
                    return null;
                }
            }
        } else {
            return null;
        }
    }

    private URI uriForVertex(final Vertex v) {
        return context.valueFactory.createURI(PropertyGraphSail.VERTEX_NS + idToString(v.getId()));
    }

    private URI uriForEdge(final Edge e) {
        return context.valueFactory.createURI(PropertyGraphSail.EDGE_NS + idToString(e.getId()));
    }

    private Object idFromString(final String s) {
        return s;
    }

    private String idToString(final Object id) {
        return id.toString();
    }

    private static interface StatementGenerator {
        void generate(T source, Collection results);
    }

    private abstract class ElementGenerator implements StatementGenerator {
        protected boolean doId = false;
        protected boolean doType = false;
        protected boolean doProperties = false;
        protected String[] properties = null;

        public void setDoId(boolean doId) {
            this.doId = doId;
        }

        public void setDoType(boolean doType) {
            this.doType = doType;
        }

        public void setDoProperties(boolean doProperties) {
            this.doProperties = doProperties;
        }

        public void setProperties(String[] properties) {
            this.properties = properties;
        }

        protected void generateCommon(final Element source,
                                      final URI uri,
                                      final Collection results) {
            if (doProperties) {
                if (null != properties) {
                    generatePropertyStatements(source, uri, results, properties);
                } else {
                    generatePropertyStatements(source, uri, results);
                }
            }

            if (doId) {
                generateIdStatement(source, uri, results);
            }
        }
    }

    private class VertexGenerator extends ElementGenerator {
        public void generate(Vertex source, Collection results) {
            URI uri = uriForVertex(source);

            if (doType) {
                generateVertexTypeStatement(uri, results);
            }

            generateCommon(source, uri, results);
        }
    }


    private class FirstClassEdgeGenerator extends ElementGenerator {
        protected boolean doLabel;
        protected boolean doHead;
        protected boolean doTail;

        public void setDoLabel(boolean doLabel) {
            this.doLabel = doLabel;
        }

        public void setDoHead(boolean doHead) {
            this.doHead = doHead;
        }

        public void setDoTail(boolean doTail) {
            this.doTail = doTail;
        }

        public void generate(Edge source, Collection results) {
            URI uri = uriForEdge(source);

            generateCommon(source, uri, results);

            if (doType) {
                generateEdgeTypeStatement(uri, results);
            }

            if (doLabel) {
                generateLabelStatement(source, uri, results);
            }

            if (doHead) {
                URI headUri = uriForVertex(source.getVertex(Direction.IN));
                generateHeadStatement(uri, headUri, results);
            }

            if (doTail) {
                URI tailUri = uriForVertex(source.getVertex(Direction.OUT));
                generateTailStatement(uri, tailUri, results);
            }
        }
    }

    private class SimpleEdgeGenerator extends ElementGenerator {
        private final String label;

        private SimpleEdgeGenerator(final String label) {
            this.label = label;
        }

        public void generate(final Edge source,
                             final Collection results) {
            if (null == label || source.getLabel().equals(label)) {
                createEdgeStatement(source, results);
            }
        }
    }

    private class RelationGenerator extends ElementGenerator {
        private final String label;
        private final boolean inVsOut;

        private RelationGenerator(final String label,
                                  final boolean inVsOut) {
            this.label = label;
            this.inVsOut = inVsOut;
        }

        public void generate(final Vertex source,
                             final Collection results) {
            if (inVsOut) {
                if (null == label) {
                    for (Edge e : source.getEdges(Direction.IN)) {
                        createEdgeStatement(e, results);
                    }
                } else {
                    for (Edge e : source.getEdges(Direction.IN, label)) {
                        createEdgeStatement(e, results);
                    }
                }
            } else {
                if (null == label) {
                    for (Edge e : source.getEdges(Direction.OUT)) {
                        createEdgeStatement(e, results);
                    }
                } else {
                    for (Edge e : source.getEdges(Direction.OUT, label)) {
                        createEdgeStatement(e, results);
                    }
                }
            }
        }
    }

    private void createEdgeStatement(final Edge source,
                                     final Collection results) {
        URI headUri = uriForVertex(source.getVertex(Direction.IN));
        URI tailUri = uriForVertex(source.getVertex(Direction.OUT));
        URI predicate = context.valueFactory.createURI(PropertyGraphSail.RELATION_NS + source.getLabel());

        results.add(context.valueFactory.createStatement(tailUri, predicate, headUri));
    }

    private StatementGenerator matchingLabels(final String label,
                                                    final Value object) {
        return new StatementGenerator() {
            public void generate(Edge source, Collection results) {
                if (source.getLabel().equals(label)) {
                    Statement s = context.valueFactory.createStatement(uriForEdge(source), PropertyGraphSail.LABEL, object);
                    results.add(s);
                }
            }
        };
    }

    private StatementGenerator vertexPropertiesWithKey(final String key,
                                                               final URI pred) {
        return new StatementGenerator() {
            public void generate(Vertex source, Collection results) {
                Object o = source.getProperty(key);
                if (null != o) {
                    Literal object = toLiteral(o);
                    if (null != object) {
                        Statement s = context.valueFactory.createStatement(uriForVertex(source), pred, object);
                        results.add(s);
                    }
                }
            }
        };
    }

    private StatementGenerator edgePropertiesWithKey(final String key,
                                                           final URI pred) {
        return new StatementGenerator() {
            public void generate(Edge source, Collection results) {
                Object o = source.getProperty(key);
                if (null != o) {
                    Literal object = toLiteral(o);
                    if (null != object) {
                        Statement s = context.valueFactory.createStatement(uriForEdge(source), pred, object);
                        results.add(s);
                    }
                }
            }
        };
    }

    private StatementGenerator vertexPropertiesWithValue(final Object value,
                                                                 final Literal object) {
        return new StatementGenerator() {
            public void generate(Vertex source, Collection results) {
                for (String key : source.getPropertyKeys()) {
                    Object v = source.getProperty(key);
                    if (null != v && v.equals(value)) {
                        URI predicate = predicateForPropertyKey(key);
                        Statement s = context.valueFactory.createStatement(uriForVertex(source), predicate, object);
                        results.add(s);
                    }
                }
            }
        };
    }

    private StatementGenerator edgePropertiesWithValue(final Object value,
                                                             final Literal object) {
        return new StatementGenerator() {
            public void generate(Edge source, Collection results) {
                for (String key : source.getPropertyKeys()) {
                    Object v = source.getProperty(key);
                    if (null != v && v.equals(value)) {
                        URI predicate = predicateForPropertyKey(key);
                        Statement s = context.valueFactory.createStatement(uriForEdge(source), predicate, object);
                        results.add(s);
                    }
                }
            }
        };
    }

    private StatementGenerator vertexPropertiesWithKeyAndValue(final String key,
                                                                       final URI pred,
                                                                       final Object value,
                                                                       final Literal object) {
        return new StatementGenerator() {
            public void generate(Vertex source, Collection results) {
                Object o = source.getProperty(key);
                if (null != o && o.equals(value)) {
                    Statement s = context.valueFactory.createStatement(uriForVertex(source), pred, object);
                    results.add(s);
                }
            }
        };
    }

    private StatementGenerator edgePropertiesWithKeyAndValue(final String key,
                                                                   final URI pred,
                                                                   final Object value,
                                                                   final Literal object) {
        return new StatementGenerator() {
            public void generate(Edge source, Collection results) {
                Object o = source.getProperty(key);
                if (null != o && o.equals(value)) {
                    Statement s = context.valueFactory.createStatement(uriForEdge(source), pred, object);
                    results.add(s);
                }
            }
        };
    }

    private URI predicateForPropertyKey(final String key) {
        return context.valueFactory.createURI(PropertyGraphSail.PROPERTY_NS + key);
    }

    private void generateVertexTypeStatement(final URI uri,
                                             final Collection results) {
        Statement s = context.valueFactory.createStatement(uri, RDF.TYPE, PropertyGraphSail.VERTEX);
        results.add(s);
    }

    private void generateEdgeTypeStatement(final URI uri,
                                           final Collection results) {
        Statement s = context.valueFactory.createStatement(uri, RDF.TYPE, PropertyGraphSail.EDGE);
        results.add(s);
    }

    private void generatePropertyStatements(final Element e,
                                            final URI uri,
                                            final Collection results,
                                            final String... keys) {
        if (0 == keys.length) {
            for (String k : e.getPropertyKeys()) {
                Object v = e.getProperty(k);
                Statement s = context.valueFactory.createStatement(
                        uri,
                        context.valueFactory.createURI(PropertyGraphSail.PROPERTY_NS + k),
                        toLiteral(v));
                results.add(s);
            }
        } else {
            for (String k : keys) {
                Object v = e.getProperty(k);
                if (null != v) {
                    Statement s = context.valueFactory.createStatement(
                            uri,
                            context.valueFactory.createURI(PropertyGraphSail.PROPERTY_NS + k),
                            toLiteral(v));
                    results.add(s);
                }
            }
        }
    }

    private void generateIdStatement(final Element e,
                                     final URI uri,
                                     final Collection results) {
        Statement s = context.valueFactory.createStatement(
                uri,
                PropertyGraphSail.ID,
                toLiteral(e.getId()));
        results.add(s);
    }

    private void generateLabelStatement(final Edge e,
                                        final URI uri,
                                        final Collection results) {
        Statement s = context.valueFactory.createStatement(
                uri,
                PropertyGraphSail.LABEL,
                context.valueFactory.createLiteral(e.getLabel()));
        results.add(s);
    }

    private void generateHeadStatement(final URI edgeUri,
                                       final URI headUri,
                                       final Collection results) {
        Statement s = context.valueFactory.createStatement(
                edgeUri,
                PropertyGraphSail.HEAD,
                headUri);
        results.add(s);
    }

    private void generateTailStatement(final URI edgeUri,
                                       final URI tailUri,
                                       final Collection results) {
        Statement s = context.valueFactory.createStatement(
                edgeUri,
                PropertyGraphSail.TAIL,
                tailUri);
        results.add(s);
    }

    private Literal toLiteral(final Object o) {
        if (o instanceof String) {
            return context.valueFactory.createLiteral((String) o);
        } else if (o instanceof Integer) {
            return context.valueFactory.createLiteral((Integer) o);
        } else if (o instanceof Long) {
            return context.valueFactory.createLiteral((Long) o);
        } else if (o instanceof Boolean) {
            return context.valueFactory.createLiteral((Boolean) o);
        } else if (o instanceof Byte) {
            return context.valueFactory.createLiteral((Byte) o);
        } else if (o instanceof Short) {
            return context.valueFactory.createLiteral((Short) o);
        } else if (o instanceof Double) {
            return context.valueFactory.createLiteral((Double) o);
        } else if (o instanceof Float) {
            return context.valueFactory.createLiteral((Float) o);
        } else {
            return null;
            //throw new IllegalArgumentException("object has unsupported datatype: " + o);
        }
    }

    private class Source {
        private final Iterator iterator;
        private final StatementGenerator generator;

        public Source(final Iterator iterator,
                      final StatementGenerator generator) {
            this.iterator = iterator;
            this.generator = generator;
        }

        public boolean hasNext() {
            return iterator.hasNext();
        }

        public void generateNext(final Collection results) {
            generator.generate(iterator.next(), results);
        }
    }

    private class StatementIteration implements CloseableIteration {
        private final Source[] sources;
        private int i = -1;
        private Collection buffer = new LinkedList();
        private Iterator iter;
        private Source currentSource;

        public StatementIteration(final Source... sources) {
            this.sources = sources;

            advanceSource();
            advanceBuffer();
        }

        private boolean advanceSource() {
            i++;
            if (i >= sources.length) {
                return false;
            } else {
                currentSource = sources[i];
                return true;
            }
        }

        private void advanceBuffer() {
            buffer.clear();

            do {
                if (null != currentSource && currentSource.hasNext()) {
                    currentSource.generateNext(buffer);
                    iter = buffer.iterator();
                } else if (!advanceSource()) {
                    iter = null;
                    return;
                }
            } while (buffer.isEmpty());
        }

        public void close() throws SailException {
            // Do nothing.
        }

        public boolean hasNext() throws SailException {
            return null != iter;
        }

        public Statement next() throws SailException {
            Statement s = iter.next();

            if (!iter.hasNext()) {
                advanceBuffer();
            }

            return s;
        }

        public void remove() throws SailException {
            throw new UnsupportedOperationException();
        }
    }

    private class SimpleCloseableIteration implements CloseableIteration {
        private final Iterator wrapped;

        public SimpleCloseableIteration(Iterator wrapped) {
            this.wrapped = wrapped;
        }

        public void close() throws E {
            // Do nothing.
        }

        public boolean hasNext() throws E {
            return wrapped.hasNext();
        }

        public T next() throws E {
            return wrapped.next();
        }

        public void remove() throws E {
            wrapped.remove();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy