nl.knaw.huygens.timbuctoo.storage.graph.tinkerpop.TinkerPopLowLevelAPI.java Source code

Java tutorial

Introduction

Here is the source code for nl.knaw.huygens.timbuctoo.storage.graph.tinkerpop.TinkerPopLowLevelAPI.java

Source

package nl.knaw.huygens.timbuctoo.storage.graph.tinkerpop;

/*
 * #%L
 * Timbuctoo core
 * =======
 * Copyright (C) 2012 - 2015 Huygens ING
 * =======
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */

import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Element;
import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.GraphQuery;
import com.tinkerpop.blueprints.Vertex;
import nl.knaw.huygens.timbuctoo.config.TypeNames;
import nl.knaw.huygens.timbuctoo.model.DomainEntity;
import nl.knaw.huygens.timbuctoo.model.Entity;
import nl.knaw.huygens.timbuctoo.model.Relation;
import nl.knaw.huygens.timbuctoo.storage.graph.SystemRelationType;
import nl.knaw.huygens.timbuctoo.storage.graph.TimbuctooQuery;
import nl.knaw.huygens.timbuctoo.storage.graph.tinkerpop.query.IsOfTypePredicate;
import nl.knaw.huygens.timbuctoo.storage.graph.tinkerpop.query.TinkerPopGraphQueryBuilderFactory;
import nl.knaw.huygens.timbuctoo.storage.graph.tinkerpop.query.TinkerPopResultFilter;
import nl.knaw.huygens.timbuctoo.storage.graph.tinkerpop.query.TinkerPopResultFilterBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;
import java.util.Map;

import static nl.knaw.huygens.timbuctoo.model.Entity.DB_ID_PROP_NAME;
import static nl.knaw.huygens.timbuctoo.model.Entity.DB_REV_PROP_NAME;
import static nl.knaw.huygens.timbuctoo.storage.graph.tinkerpop.ElementFields.ELEMENT_TYPES;
import static nl.knaw.huygens.timbuctoo.storage.graph.tinkerpop.ElementFields.IS_LATEST;
import static nl.knaw.huygens.timbuctoo.storage.graph.tinkerpop.ElementHelper.getIdProperty;
import static nl.knaw.huygens.timbuctoo.storage.graph.tinkerpop.ElementHelper.getRevisionProperty;

class TinkerPopLowLevelAPI {

    private static final String VERSION_OF_LABEL = SystemRelationType.VERSION_OF.name();
    public static final Logger LOG = LoggerFactory.getLogger(TinkerPopLowLevelAPI.class);
    public static final IsOfTypePredicate IS_TYPE_OF = new IsOfTypePredicate();
    private final Graph db;
    private final VertexDuplicator vertexDuplicator;
    private final EdgeManipulator edgeManipulator;
    private TinkerPopGraphQueryBuilderFactory queryBuilderFactory;
    private TinkerPopResultFilterBuilder resultFilterBuilder;

    public TinkerPopLowLevelAPI(Graph db) {
        this(db, new VertexDuplicator(db), new EdgeManipulator(), new TinkerPopGraphQueryBuilderFactory(db),
                new TinkerPopResultFilterBuilder());
    }

    public TinkerPopLowLevelAPI(Graph db, VertexDuplicator vertexDuplicator, EdgeManipulator edgeManipulator,
            TinkerPopGraphQueryBuilderFactory queryBuilderFactory,
            TinkerPopResultFilterBuilder resultFilterBuilder) {
        this.db = db;
        this.vertexDuplicator = vertexDuplicator;
        this.edgeManipulator = edgeManipulator;
        this.queryBuilderFactory = queryBuilderFactory;
        this.resultFilterBuilder = resultFilterBuilder;
    }

    public <T extends Entity> Vertex getLatestVertexById(Class<T> type, String id) {
        // this is needed to check if the type array contains the value requeste type
        Iterable<Vertex> foundVertices = queryLatestByType(type).has(DB_ID_PROP_NAME, id) //
                .vertices();

        return getFirstFromIterable(foundVertices);
    }

    public Vertex getLatestVertexById(String id) {
        Iterable<Vertex> vertices = queryLatest().has(DB_ID_PROP_NAME, id).vertices();

        return getFirstFromIterable(vertices);
    }

    private GraphQuery queryLatest() {
        return db.query().has(IS_LATEST, true);
    }

    private <T extends Entity> GraphQuery queryLatestByType(Class<T> type) {
        return queryByType(type).has(IS_LATEST, true);
    }

    private <T extends Entity> GraphQuery queryByType(Class<T> type) {
        return db.query() //
                .has(ELEMENT_TYPES, IS_TYPE_OF, TypeNames.getInternalName(type));
    }

    public Vertex getVertexWithRevision(Class<? extends DomainEntity> type, String id, int revision) {
        Iterable<Vertex> vertices = queryByType(type)//
                .has(DB_ID_PROP_NAME, id)//
                .has(DB_REV_PROP_NAME, revision)//
                .vertices();

        return getFirstFromIterable(vertices);
    }

    private <T extends Element> T getFirstFromIterable(Iterable<T> elements) {
        T element = null;
        Iterator<T> iterator = elements.iterator();

        if (iterator.hasNext()) {
            element = iterator.next();
        }

        return element;
    }

    public Edge getLatestEdgeById(Class<? extends Relation> relationType, String id) {
        Iterable<Edge> edges = queryLatestByType(relationType).has(DB_ID_PROP_NAME, id).edges();

        return getFirstFromIterable(edges);
    }

    public Iterator<Vertex> getLatestVerticesOf(Class<? extends Entity> type) {
        Stopwatch retrieveStopwatch = Stopwatch.createStarted();
        LOG.debug("Retrieve vertices of type [{}]", type);
        Stopwatch queryStopwatch = Stopwatch.createStarted();

        LOG.debug("Query vertices of type [{}]", type);
        Iterable<Vertex> vertices = queryByType(type).has(IS_LATEST, true).vertices();
        LOG.debug("Query vertices of type [{}] ended in [{}]", type, queryStopwatch.stop());

        LOG.debug("Retrieve vertices of type [{}] ended in [{}]", type, retrieveStopwatch.stop());
        return vertices.iterator();

    }

    public void duplicate(Vertex vertex) {
        vertexDuplicator.duplicate(vertex);
    }

    public void duplicate(Edge edge) {
        edgeManipulator.duplicate(edge);
    }

    public Edge getEdgeWithRevision(Class<? extends Relation> relationType, String id, int revision) {
        Iterable<Edge> edges = db.query().has(DB_ID_PROP_NAME, id).has(DB_REV_PROP_NAME, revision).edges();
        return getFirstFromIterable(edges);
    }

    public Iterator<Edge> getLatestEdgesOf(Class<? extends Relation> type) {
        Stopwatch stopwatch = Stopwatch.createStarted();
        LOG.debug("Begin get latest edges for [{}]", type);

        Stopwatch queryStopwatch = Stopwatch.createStarted();
        LOG.debug("Begin query latest edges for [{}]", type);
        Iterable<Edge> edges = queryLatestByType(type).edges();
        LOG.debug("End querying latest edges for [{}] in [{}]", type, queryStopwatch.stop());

        LOG.debug("End get latest edges for [{}] in [{}]", type, stopwatch.stop());
        return edges.iterator();
    }

    /**
     * Filter the latest edges from the iterable. It also filters the system edges, like VERSION_OF.
     * @param edges the edges to the latest from
     * @return the latest non-system edges
     */
    public Iterator<Edge> getLatestEdges(Iterable<Edge> edges) {

        Map<String, Edge> latestEdgeMap = Maps.newHashMap();
        for (Iterator<Edge> iterator = edges.iterator(); iterator.hasNext();) {
            Edge edge = iterator.next();

            String id = getIdProperty(edge);

            Edge mappedEdge = latestEdgeMap.get(id);

            if (!isVersionOfEdge(edge) && (mappedEdge == null || isLaterEdge(edge, mappedEdge))) {
                latestEdgeMap.put(id, edge);
            }

        }

        return latestEdgeMap.values().iterator();
    }

    private boolean isVersionOfEdge(Edge edge) {
        return VERSION_OF_LABEL.equals(edge.getLabel());
    }

    private boolean isLaterEdge(Edge edge, Edge mappedEdge) {
        return getRevisionProperty(edge) > getRevisionProperty(mappedEdge);
    }

    public Iterator<Vertex> getVerticesWithId(Class<? extends Entity> type, String id) {
        return queryByType(type).has(DB_ID_PROP_NAME, id).vertices().iterator();
    }

    public Iterator<Vertex> findLatestVerticesByProperty(Class<? extends Entity> type, String propertyName,
            String propertyValue) {
        Iterable<Vertex> vertices = queryByType(type).has(IS_LATEST, true).has(propertyName, propertyValue)
                .vertices();

        return vertices.iterator();
    }

    public Iterator<Vertex> findVerticesWithoutProperty(Class<? extends DomainEntity> type, String propertyName) {
        Iterable<Vertex> vertices = queryByType(type).hasNot(propertyName).vertices();

        return vertices.iterator();
    }

    public Iterator<Edge> findEdgesWithoutProperty(Class<? extends Relation> relationType, String propertyName) {
        Iterable<Edge> edges = db.query().hasNot(propertyName).edges();

        return edges.iterator();
    }

    public Iterator<Edge> findLatestEdgesByProperty(Class<? extends Relation> type, String propertyName,
            String propertyValue) {
        Iterable<Edge> edges = queryLatest().has(propertyName, propertyValue).edges();

        return edges.iterator();
    }

    /**
     * Returns all the latest outgoing edges of the latest version of
     * the vertex with the id property with the value of sourceId.
     *
     * @param type     the type of the relation to find
     * @param sourceId the id of the vertex to find the edges for
     * @return the found edges or an empty iterator non are found
     */
    public Iterator<Edge> findEdgesBySource(Class<? extends Relation> type, String sourceId) {
        return getEdgesByVertex(sourceId, Direction.OUT);
    }

    /**
     * Returns all the latest incoming edges of the latest version of
     * the vertex with the id property with the value of targetId.
     *
     * @param type     the type of the relation to find
     * @param targetId the id of the vertex to find the edges for
     * @return the found edges or an empty iterator non are found
     */
    public Iterator<Edge> findEdgesByTarget(Class<? extends Relation> type, String targetId) {
        return getEdgesByVertex(targetId, Direction.IN);
    }

    private Iterator<Edge> getEdgesByVertex(String vertexId, Direction direction) {
        Iterable<Vertex> vertices = queryLatest().has(DB_ID_PROP_NAME, vertexId).vertices();

        Iterator<Vertex> iterator = vertices.iterator();
        if (iterator.hasNext()) {
            Iterable<Edge> outgoingEdges = iterator.next().query().direction(direction).has(IS_LATEST, true)
                    .edges();

            return outgoingEdges.iterator();
        }

        return Lists.<Edge>newArrayList().iterator();
    }

    public Iterator<Edge> findEdges(Class<? extends Relation> type, TimbuctooQuery query) {
        Iterable<Edge> edges = query.createGraphQuery(queryBuilderFactory.newQueryBuilder(type)).edges();

        TinkerPopResultFilter<Edge> filter = resultFilterBuilder.buildFor(query);

        Iterable<Edge> filteredEdges = filter.filter(edges);

        return filteredEdges.iterator();
    }

    public <T extends Entity> Iterator<Vertex> findVertices(Class<T> type, TimbuctooQuery query) {
        Iterable<Vertex> vertices = query.createGraphQuery(queryBuilderFactory.newQueryBuilder(type)).vertices();

        TinkerPopResultFilter<Vertex> resultFilter = resultFilterBuilder.buildFor(query);

        Iterable<Vertex> filteredVertices = resultFilter.filter(vertices);

        return filteredVertices.iterator();
    }

}