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

org.jnosql.artemis.graph.AbstractGraphTemplate Maven / Gradle / Ivy

The newest version!
/*
 *  Copyright (c) 2017 Otávio Santana and others
 *   All rights reserved. This program and the accompanying materials
 *   are made available under the terms of the Eclipse Public License v1.0
 *   and Apache License v2.0 which accompanies this distribution.
 *   The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 *   and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
 *
 *   You may elect to redistribute this code under either of these licenses.
 *
 *   Contributors:
 *
 *   Otavio Santana
 */
package org.jnosql.artemis.graph;

import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Transaction;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.jnosql.artemis.EntityNotFoundException;
import org.jnosql.artemis.IdNotFoundException;
import org.jnosql.artemis.reflection.ClassRepresentation;
import org.jnosql.artemis.reflection.ClassRepresentations;
import org.jnosql.artemis.reflection.FieldRepresentation;
import org.jnosql.artemis.reflection.Reflections;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.Objects.isNull;
import static java.util.Objects.requireNonNull;
import static org.apache.tinkerpop.gremlin.structure.T.id;

public abstract class AbstractGraphTemplate implements GraphTemplate {
    private static final Function, GraphTraversal> INITIAL_VERTEX =
            g -> (GraphTraversal) g;

    private static final Function, GraphTraversal> INITIAL_EDGE =
            g -> (GraphTraversal) g;


    protected abstract Graph getGraph();

    protected abstract ClassRepresentations getClassRepresentations();

    protected abstract GraphConverter getConverter();

    protected abstract GraphWorkflow getFlow();

    protected abstract Reflections getReflections();

    @Override
    public  T insert(T entity) {
        requireNonNull(entity, "entity is required");
        checkId(entity);
        UnaryOperator save = v -> v;

        return getFlow().flow(entity, save);
    }

    @Override
    public  T update(T entity) {
        requireNonNull(entity, "entity is required");
        checkId(entity);
        if (isIdNull(entity)) {
            throw new NullPointerException("to update a graph id cannot be null");
        }
        getVertex(entity).orElseThrow(() -> new EntityNotFoundException("Entity does not find in the update"));

        UnaryOperator update = e -> getConverter().toVertex(entity);
        return getFlow().flow(entity, update);
    }

    @Override
    public  void delete(T idValue) {
        requireNonNull(idValue, "id is required");
        List vertices = getGraph().traversal().V(idValue).toList();
        vertices.forEach(Vertex::remove);

    }

    @Override
    public  void deleteEdge(T idEdge) {
        requireNonNull(idEdge, "idEdge is required");
        List edges = getGraph().traversal().E(idEdge).toList();
        edges.forEach(Edge::remove);
    }

    @Override
    public  Optional find(ID idValue) {
        requireNonNull(idValue, "id is required");
        Optional vertex = getGraph().traversal().V(idValue).tryNext();
        return vertex.map(getConverter()::toEntity);
    }

    @Override
    public  EdgeEntity edge(OUT outgoing, String label, IN incoming) {

        requireNonNull(incoming, "incoming is required");
        requireNonNull(label, "label is required");
        requireNonNull(outgoing, "outgoing is required");

        checkId(outgoing);
        checkId(incoming);

        if (isIdNull(outgoing)) {
            throw new NullPointerException("outgoing Id field is required");
        }

        if (isIdNull(incoming)) {
            throw new NullPointerException("incoming Id field is required");
        }


        Vertex outVertex = getVertex(outgoing).orElseThrow(() -> new EntityNotFoundException("Outgoing entity does not found"));
        Vertex inVertex = getVertex(incoming).orElseThrow(() -> new EntityNotFoundException("Incoming entity does not found"));

        final Predicate> predicate = t -> {
            Edge e = t.get();
            return e.inVertex().id().equals(inVertex.id())
                    && e.outVertex().id().equals(outVertex.id());
        };

        Optional edge = getGraph()
                .traversal().V(outVertex.id())
                .out(label).has(id, inVertex.id()).inE(label).filter(predicate).tryNext();

        return edge.map(edge1 -> new DefaultEdgeEntity<>(edge1, incoming, outgoing))
                .orElseGet(() -> new DefaultEdgeEntity<>(outVertex.addEdge(label, inVertex), incoming, outgoing));


    }

    @Override
    public  Optional edge(E edgeId) {
        requireNonNull(edgeId, "edgeId is required");

        Optional edgeOptional = getGraph().traversal().E(edgeId).tryNext();

        if (edgeOptional.isPresent()) {
            Edge edge = edgeOptional.get();
            return Optional.of(getConverter().toEdgeEntity(edge));
        }

        return Optional.empty();
    }


    @Override
    public  Collection getEdges(T entity, Direction direction) {
        return getEdgesImpl(entity, direction);
    }

    @Override
    public  Collection getEdges(T entity, Direction direction, String... labels) {
        return getEdgesImpl(entity, direction, labels);
    }


    @SafeVarargs
    @Override
    public final  Collection getEdges(T entity, Direction direction, Supplier... labels) {
        checkLabelsSupplier(labels);
        return getEdgesImpl(entity, direction, Stream.of(labels).map(Supplier::get).toArray(String[]::new));
    }


    @Override
    public  Collection getEdgesById(ID id, Direction direction, String... labels) {
        return getEdgesByIdImpl(id, direction, labels);
    }

    @Override
    public  Collection getEdgesById(ID id, Direction direction) {
        return getEdgesByIdImpl(id, direction);
    }

    @SafeVarargs
    @Override
    public final  Collection getEdgesById(ID id, Direction direction, Supplier... labels) {
        checkLabelsSupplier(labels);
        return getEdgesByIdImpl(id, direction, Stream.of(labels).map(Supplier::get).toArray(String[]::new));
    }


    @Override
    public VertexTraversal getTraversalVertex(Object... vertexIds) {
        if (Stream.of(vertexIds).anyMatch(Objects::isNull)) {
            throw new NullPointerException("No one vertexId element cannot be null");
        }
        return new DefaultVertexTraversal(() -> getGraph().traversal().V(vertexIds), INITIAL_VERTEX, getConverter());
    }

    @Override
    public EdgeTraversal getTraversalEdge(Object... edgeIds) {
        if (Stream.of(edgeIds).anyMatch(Objects::isNull)) {
            throw new NullPointerException("No one edgeId element cannot be null");
        }
        return new DefaultEdgeTraversal(() -> getGraph().traversal().E(edgeIds), INITIAL_EDGE, getConverter());
    }

    @Override
    public Transaction getTransaction() {
        return getGraph().tx();
    }

    private  Collection getEdgesByIdImpl(ID id, Direction direction, String... labels) {

        requireNonNull(id, "id is required");
        requireNonNull(direction, "direction is required");

        Iterator vertices = getGraph().vertices(id);
        if (vertices.hasNext()) {
            List edges = new ArrayList<>();
            vertices.next().edges(direction, labels).forEachRemaining(edges::add);
            return edges.stream().map(getConverter()::toEdgeEntity).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    private  Collection getEdgesImpl(T entity, Direction direction, String... labels) {
        requireNonNull(entity, "entity is required");

        if (isIdNull(entity)) {
            throw new NullPointerException("Entity id is required");
        }

        if (!getVertex(entity).isPresent()) {
            return Collections.emptyList();
        }
        Object id = getConverter().toVertex(entity).id();
        return getEdgesByIdImpl(id, direction, labels);
    }

    private void checkLabelsSupplier(Supplier[] labels) {
        if (Stream.of(labels).anyMatch(Objects::isNull)) {
            throw new NullPointerException("Item cannot be null");
        }
    }

    private  boolean isIdNull(T entity) {
        ClassRepresentation classRepresentation = getClassRepresentations().get(entity.getClass());
        FieldRepresentation field = classRepresentation.getId().get();
        return isNull(getReflections().getValue(entity, field.getNativeField()));

    }

    private  Optional getVertex(T entity) {
        ClassRepresentation classRepresentation = getClassRepresentations().get(entity.getClass());
        FieldRepresentation field = classRepresentation.getId().get();
        Object id = getReflections().getValue(entity, field.getNativeField());
        Iterator vertices = getGraph().vertices(id);
        if (vertices.hasNext()) {
            return Optional.of(vertices.next());
        }
        return Optional.empty();
    }

    private  void checkId(T entity) {
        ClassRepresentation classRepresentation = getClassRepresentations().get(entity.getClass());
        classRepresentation.getId().orElseThrow(() -> IdNotFoundException.newInstance(entity.getClass()));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy