Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions jnosql-tinkerpop/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,48 @@
<artifactId>neo4j-tinkerpop-api-impl</artifactId>
<version>${neo4j.connector.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.tinkerpop</groupId>
<artifactId>tinkergraph-gremlin</artifactId>
<version>${tinkerpop.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.arangodb</groupId>
<artifactId>arangodb-tinkerpop-provider</artifactId>
<version>3.2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<!--
Allow discovery of static inner test classes by overriding excludes rules.
By default **/*$* is excluded.
-->
<exclude/>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@

import java.util.function.Function;

public enum CommunicationEntityConverter implements Function<Vertex, CommunicationEntity>{
INSTANCE;
import static org.eclipse.jnosql.databases.tinkerpop.communication.TinkerpopGraphDatabaseManager.ID;

public enum CommunicationEntityConverter implements Function<Vertex, CommunicationEntity> {
INSTANCE;

@Override
public CommunicationEntity apply(Vertex vertex) {
var entity = CommunicationEntity.of(vertex.label());
vertex.properties().forEachRemaining(p -> entity.add(p.key(), p.value()));
entity.add(DefaultTinkerpopGraphDatabaseManager.ID_PROPERTY, vertex.id());
entity.add(ID, vertex.id());
return entity;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@
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.T;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.eclipse.jnosql.communication.CommunicationException;
import org.eclipse.jnosql.communication.ValueUtil;
import org.eclipse.jnosql.communication.graph.CommunicationEdge;
import org.eclipse.jnosql.communication.semistructured.CommunicationEntity;
import org.eclipse.jnosql.communication.semistructured.DeleteQuery;
import org.eclipse.jnosql.communication.semistructured.Element;
import org.eclipse.jnosql.communication.semistructured.SelectQuery;

import java.time.Duration;
Expand Down Expand Up @@ -52,7 +54,6 @@
*/
public class DefaultTinkerpopGraphDatabaseManager implements TinkerpopGraphDatabaseManager {

public static final String ID_PROPERTY = "_id";
private final Graph graph;

DefaultTinkerpopGraphDatabaseManager(Graph graph) {
Expand All @@ -71,13 +72,8 @@ public String name() {

@Override
public CommunicationEntity insert(CommunicationEntity entity) {

Objects.requireNonNull(entity, "entity is required");
Vertex vertex = graph.addVertex(entity.name());
entity.elements().forEach(e -> vertex.property(e.name(), ValueUtil.convert(e.value())));
entity.add(ID_PROPERTY, vertex.id());
vertex.property(ID_PROPERTY, vertex.id());
GraphTransactionUtil.transaction(graph);
addVertex(entity);
return entity;
}

Expand All @@ -101,14 +97,16 @@ public Iterable<CommunicationEntity> insert(Iterable<CommunicationEntity> iterab
@Override
public CommunicationEntity update(CommunicationEntity entity) {
Objects.requireNonNull(entity, "entity is required");
entity.find(ID_PROPERTY).ifPresent(id -> {
Iterator<Vertex> vertices = graph.vertices(id.get());
if(!vertices.hasNext()) {
throw new EmptyResultException("The entity does not exist with the id: " + id);
}
Vertex vertex = vertices.next();
entity.elements().forEach(e -> vertex.property(e.name(), ValueUtil.convert(e.value())));
});
Object id = entity.find(ID).map(Element::get)
.orElseThrow(() -> new IllegalArgumentException("Entity must have an ID"));
Iterator<Vertex> vertices = graph.vertices(id);
if (!vertices.hasNext()) {
throw new EmptyResultException("The entity does not exist with the id: " + id);
}
Vertex vertex = vertices.next();
entity.elements().stream()
.filter(it -> !ID.equals(it.name()))
.forEach(e -> vertex.property(e.name(), ValueUtil.convert(e.value())));
GraphTransactionUtil.transaction(graph);
return entity;
}
Expand Down Expand Up @@ -198,11 +196,11 @@ public void remove(CommunicationEntity source, String label, CommunicationEntity
Objects.requireNonNull(target, "target is required");
Objects.requireNonNull(label, "label is required");

Vertex sourceVertex = findVertexById(source.find(ID_PROPERTY)
Vertex sourceVertex = findVertexById(source.find(ID)
.orElseThrow(() -> new CommunicationException("Source entity must have an ID")).get())
.orElseThrow(() -> new EmptyResultException("Source entity not found"));

Vertex targetVertex = findVertexById(target.find(ID_PROPERTY)
Vertex targetVertex = findVertexById(target.find(ID)
.orElseThrow(() -> new CommunicationException("Target entity must have an ID")).get())
.orElseThrow(() -> new EmptyResultException("Target entity not found"));

Expand Down Expand Up @@ -241,27 +239,34 @@ public <K> Optional<CommunicationEdge> findEdgeById(K id) {

var edge = traversal.next();
var source = CommunicationEntity.of(edge.outVertex().label());
source.add(ID_PROPERTY, edge.outVertex().id());
source.add(ID, edge.outVertex().id());

var target = CommunicationEntity.of(edge.inVertex().label());
target.add(ID_PROPERTY, edge.inVertex().id());
target.add(ID, edge.inVertex().id());

Map<String, Object> properties = new HashMap<>();
edge.properties().forEachRemaining(p -> properties.put(p.key(), p.value()));

return Optional.of(new TinkerpopCommunicationEdge(id, source, target, edge.label(), properties));
}

private Vertex addVertex(CommunicationEntity entity) {
Object[] args = Stream.concat(
Stream.of(T.label, entity.name()),
entity.elements().stream().flatMap(it -> ID.equals(it.name()) ?
Stream.of(T.id, it.get()) :
Stream.of(it.name(), ValueUtil.convert(it.value())))
).toArray();
Vertex vertex = graph.addVertex(args);
entity.add(ID, vertex.id());
GraphTransactionUtil.transaction(graph);
return vertex;
}

private Vertex findOrCreateVertex(CommunicationEntity entity) {
return entity.find(ID_PROPERTY)
return entity.find(ID)
.flatMap(id -> findVertexById(id.get()))
.orElseGet(() -> {
var newVertex = graph.addVertex(entity.name());
entity.elements().forEach(e -> newVertex.property(e.name(), ValueUtil.convert(e.value())));
newVertex.property(ID_PROPERTY, newVertex.id());
entity.add(ID_PROPERTY, newVertex.id());
return newVertex;
});
.orElseGet(() -> addVertex(entity));
}

private Optional<Vertex> findVertexById(Object id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.eclipse.jnosql.databases.tinkerpop.communication;

import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.T;
import org.eclipse.jnosql.communication.graph.GraphDatabaseManager;
import org.eclipse.jnosql.communication.semistructured.DatabaseManager;

Expand All @@ -35,6 +36,8 @@
*/
public interface TinkerpopGraphDatabaseManager extends GraphDatabaseManager, Supplier<Graph> {

String ID = T.id.getAccessor();

/**
* Creates a new instance of DefaultGraphDatabaseManager with the specified TinkerPop Graph.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2022 Contributors to the Eclipse Foundation
* 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.eclipse.jnosql.databases.tinkerpop.cdi;

import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;

enum ArangoDeployment {
INSTANCE;

private final GenericContainer<?> arangodb =
new GenericContainer<>("arangodb/arangodb:latest")
.withExposedPorts(8529)
.withEnv("ARANGO_NO_AUTH", "1")
.waitingFor(Wait.forHttp("/")
.forStatusCode(200));

{
arangodb.start();
}

public GenericContainer<?> getContainer() {
return arangodb;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2022 Contributors to the Eclipse Foundation
* 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
* Michele Rastelli
*/
package org.eclipse.jnosql.databases.tinkerpop.cdi;

import com.arangodb.tinkerpop.gremlin.structure.ArangoDBGraph;
import com.arangodb.tinkerpop.gremlin.structure.ArangoDBGraphConfig;
import org.apache.commons.configuration2.BaseConfiguration;
import org.apache.commons.configuration2.Configuration;
import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.util.GraphFactory;
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerTransactionGraph;
import org.testcontainers.containers.GenericContainer;

import java.io.File;
import java.util.List;
import java.util.function.Supplier;
import java.util.logging.Logger;

import static java.lang.System.currentTimeMillis;

public enum TestGraphSupplier implements Supplier<Graph> {

NEO4J {
private static final Logger LOGGER = Logger.getLogger(TestGraphSupplier.class.getName());

@Override
public Graph get() {
String directory = new File("").getAbsolutePath() + "/target/neo4j-graph/" + currentTimeMillis();
LOGGER.info("Starting Neo4j at directory: " + directory);
return Neo4jGraph.open(directory);
}
},

ARANGODB {
@Override
public Graph get() {
GenericContainer<?> container = ArangoDeployment.INSTANCE.getContainer();
Configuration configuration = new BaseConfiguration();
configuration.addProperty("gremlin.graph", ArangoDBGraph.class.getName());
configuration.addProperty("gremlin.arangodb.conf.graph.enableDataDefinition", true);
configuration.addProperty("gremlin.arangodb.conf.graph.type", ArangoDBGraphConfig.GraphType.COMPLEX.name());
configuration.addProperty("gremlin.arangodb.conf.graph.edgeDefinitions", List.of(
"reads:[Human]->[Magazine]",
"knows:[Person]->[Person]",
"eats:[Creature]->[Creature]",
"loves:[Human]->[Human]",
"likes:[Human]->[Creature]",
"friend:[Person]->[Person]"
));
configuration.addProperty("gremlin.arangodb.conf.driver.hosts", container.getHost() + ":" + container.getFirstMappedPort());
return GraphFactory.open(configuration);
}
},

TINKER_GRAPH {
@Override
public Graph get() {
Configuration configuration = new BaseConfiguration();
configuration.setProperty(TinkerGraph.GREMLIN_TINKERGRAPH_VERTEX_ID_MANAGER, TinkerGraph.DefaultIdManager.STRING.name());
configuration.setProperty(TinkerGraph.GREMLIN_TINKERGRAPH_EDGE_ID_MANAGER, TinkerGraph.DefaultIdManager.STRING.name());
configuration.setProperty(TinkerGraph.GREMLIN_TINKERGRAPH_VERTEX_PROPERTY_ID_MANAGER, TinkerGraph.DefaultIdManager.STRING.name());
return TinkerTransactionGraph.open(configuration);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2022 Contributors to the Eclipse Foundation
* 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
* Michele Rastelli
*/
package org.eclipse.jnosql.databases.tinkerpop.cdi.arangodb;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.Priority;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Alternative;
import jakarta.enterprise.inject.Disposes;
import jakarta.enterprise.inject.Produces;
import jakarta.interceptor.Interceptor;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.eclipse.jnosql.databases.tinkerpop.cdi.TestGraphSupplier;

import java.util.function.Supplier;
import java.util.logging.Logger;

@ApplicationScoped
@Alternative
@Priority(Interceptor.Priority.APPLICATION)
public class ArangoDBGraphProducer implements Supplier<Graph> {

private static final Logger LOGGER = Logger.getLogger(ArangoDBGraphProducer.class.getName());

private Graph graph;

@PostConstruct
public void init() {
graph = TestGraphSupplier.ARANGODB.get();
LOGGER.info("Graph database created");
}

@Produces
@ApplicationScoped
@Override
public Graph get() {
return graph;
}

public void dispose(@Disposes Graph graph) throws Exception {
LOGGER.info("Graph database closing");
graph.close();
LOGGER.info("Graph Database closed");
}

}
Loading