Skip to content

Commit 108f459

Browse files
authored
Merge pull request #337 from rashtao/feature/arangodb-tinkerpop
Make jnosql-tinkerpop work with ArangoDB and TinkerGraph
2 parents 511e6c7 + 60a0df5 commit 108f459

30 files changed

+593
-203
lines changed

jnosql-tinkerpop/pom.xml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,48 @@
6464
<artifactId>neo4j-tinkerpop-api-impl</artifactId>
6565
<version>${neo4j.connector.version}</version>
6666
<scope>test</scope>
67+
<exclusions>
68+
<exclusion>
69+
<groupId>org.slf4j</groupId>
70+
<artifactId>slf4j-nop</artifactId>
71+
</exclusion>
72+
</exclusions>
73+
</dependency>
74+
<dependency>
75+
<groupId>org.apache.tinkerpop</groupId>
76+
<artifactId>tinkergraph-gremlin</artifactId>
77+
<version>${tinkerpop.version}</version>
78+
<scope>test</scope>
79+
</dependency>
80+
<dependency>
81+
<groupId>com.arangodb</groupId>
82+
<artifactId>arangodb-tinkerpop-provider</artifactId>
83+
<version>3.2.1</version>
84+
<scope>test</scope>
85+
</dependency>
86+
<dependency>
87+
<groupId>org.slf4j</groupId>
88+
<artifactId>slf4j-simple</artifactId>
89+
<version>1.7.25</version>
90+
<scope>test</scope>
6791
</dependency>
6892
</dependencies>
6993

7094
<build>
7195
<plugins>
96+
<plugin>
97+
<groupId>org.apache.maven.plugins</groupId>
98+
<artifactId>maven-surefire-plugin</artifactId>
99+
<configuration>
100+
<excludes>
101+
<!--
102+
Allow discovery of static inner test classes by overriding excludes rules.
103+
By default **/*$* is excluded.
104+
-->
105+
<exclude/>
106+
</excludes>
107+
</configuration>
108+
</plugin>
72109
<plugin>
73110
<groupId>org.antlr</groupId>
74111
<artifactId>antlr4-maven-plugin</artifactId>

jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/CommunicationEntityConverter.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@
1919

2020
import java.util.function.Function;
2121

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

24+
public enum CommunicationEntityConverter implements Function<Vertex, CommunicationEntity> {
25+
INSTANCE;
2526

2627
@Override
2728
public CommunicationEntity apply(Vertex vertex) {
2829
var entity = CommunicationEntity.of(vertex.label());
2930
vertex.properties().forEachRemaining(p -> entity.add(p.key(), p.value()));
30-
entity.add(DefaultTinkerpopGraphDatabaseManager.ID_PROPERTY, vertex.id());
31+
entity.add(ID, vertex.id());
3132
return entity;
3233
}
3334
}

jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/DefaultTinkerpopGraphDatabaseManager.java

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
import org.apache.tinkerpop.gremlin.structure.Direction;
2020
import org.apache.tinkerpop.gremlin.structure.Edge;
2121
import org.apache.tinkerpop.gremlin.structure.Graph;
22+
import org.apache.tinkerpop.gremlin.structure.T;
2223
import org.apache.tinkerpop.gremlin.structure.Vertex;
2324
import org.eclipse.jnosql.communication.CommunicationException;
2425
import org.eclipse.jnosql.communication.ValueUtil;
2526
import org.eclipse.jnosql.communication.graph.CommunicationEdge;
2627
import org.eclipse.jnosql.communication.semistructured.CommunicationEntity;
2728
import org.eclipse.jnosql.communication.semistructured.DeleteQuery;
29+
import org.eclipse.jnosql.communication.semistructured.Element;
2830
import org.eclipse.jnosql.communication.semistructured.SelectQuery;
2931

3032
import java.time.Duration;
@@ -52,7 +54,6 @@
5254
*/
5355
public class DefaultTinkerpopGraphDatabaseManager implements TinkerpopGraphDatabaseManager {
5456

55-
public static final String ID_PROPERTY = "_id";
5657
private final Graph graph;
5758

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

7273
@Override
7374
public CommunicationEntity insert(CommunicationEntity entity) {
74-
7575
Objects.requireNonNull(entity, "entity is required");
76-
Vertex vertex = graph.addVertex(entity.name());
77-
entity.elements().forEach(e -> vertex.property(e.name(), ValueUtil.convert(e.value())));
78-
entity.add(ID_PROPERTY, vertex.id());
79-
vertex.property(ID_PROPERTY, vertex.id());
80-
GraphTransactionUtil.transaction(graph);
76+
addVertex(entity);
8177
return entity;
8278
}
8379

@@ -101,14 +97,16 @@ public Iterable<CommunicationEntity> insert(Iterable<CommunicationEntity> iterab
10197
@Override
10298
public CommunicationEntity update(CommunicationEntity entity) {
10399
Objects.requireNonNull(entity, "entity is required");
104-
entity.find(ID_PROPERTY).ifPresent(id -> {
105-
Iterator<Vertex> vertices = graph.vertices(id.get());
106-
if(!vertices.hasNext()) {
107-
throw new EmptyResultException("The entity does not exist with the id: " + id);
108-
}
109-
Vertex vertex = vertices.next();
110-
entity.elements().forEach(e -> vertex.property(e.name(), ValueUtil.convert(e.value())));
111-
});
100+
Object id = entity.find(ID).map(Element::get)
101+
.orElseThrow(() -> new IllegalArgumentException("Entity must have an ID"));
102+
Iterator<Vertex> vertices = graph.vertices(id);
103+
if (!vertices.hasNext()) {
104+
throw new EmptyResultException("The entity does not exist with the id: " + id);
105+
}
106+
Vertex vertex = vertices.next();
107+
entity.elements().stream()
108+
.filter(it -> !ID.equals(it.name()))
109+
.forEach(e -> vertex.property(e.name(), ValueUtil.convert(e.value())));
112110
GraphTransactionUtil.transaction(graph);
113111
return entity;
114112
}
@@ -198,11 +196,11 @@ public void remove(CommunicationEntity source, String label, CommunicationEntity
198196
Objects.requireNonNull(target, "target is required");
199197
Objects.requireNonNull(label, "label is required");
200198

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

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

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

242240
var edge = traversal.next();
243241
var source = CommunicationEntity.of(edge.outVertex().label());
244-
source.add(ID_PROPERTY, edge.outVertex().id());
242+
source.add(ID, edge.outVertex().id());
245243

246244
var target = CommunicationEntity.of(edge.inVertex().label());
247-
target.add(ID_PROPERTY, edge.inVertex().id());
245+
target.add(ID, edge.inVertex().id());
248246

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

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

253+
private Vertex addVertex(CommunicationEntity entity) {
254+
Object[] args = Stream.concat(
255+
Stream.of(T.label, entity.name()),
256+
entity.elements().stream().flatMap(it -> ID.equals(it.name()) ?
257+
Stream.of(T.id, it.get()) :
258+
Stream.of(it.name(), ValueUtil.convert(it.value())))
259+
).toArray();
260+
Vertex vertex = graph.addVertex(args);
261+
entity.add(ID, vertex.id());
262+
GraphTransactionUtil.transaction(graph);
263+
return vertex;
264+
}
265+
255266
private Vertex findOrCreateVertex(CommunicationEntity entity) {
256-
return entity.find(ID_PROPERTY)
267+
return entity.find(ID)
257268
.flatMap(id -> findVertexById(id.get()))
258-
.orElseGet(() -> {
259-
var newVertex = graph.addVertex(entity.name());
260-
entity.elements().forEach(e -> newVertex.property(e.name(), ValueUtil.convert(e.value())));
261-
newVertex.property(ID_PROPERTY, newVertex.id());
262-
entity.add(ID_PROPERTY, newVertex.id());
263-
return newVertex;
264-
});
269+
.orElseGet(() -> addVertex(entity));
265270
}
266271

267272
private Optional<Vertex> findVertexById(Object id) {

jnosql-tinkerpop/src/main/java/org/eclipse/jnosql/databases/tinkerpop/communication/TinkerpopGraphDatabaseManager.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package org.eclipse.jnosql.databases.tinkerpop.communication;
1616

1717
import org.apache.tinkerpop.gremlin.structure.Graph;
18+
import org.apache.tinkerpop.gremlin.structure.T;
1819
import org.eclipse.jnosql.communication.graph.GraphDatabaseManager;
1920
import org.eclipse.jnosql.communication.semistructured.DatabaseManager;
2021

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

39+
String ID = T.id.getAccessor();
40+
3841
/**
3942
* Creates a new instance of DefaultGraphDatabaseManager with the specified TinkerPop Graph.
4043
*
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (c) 2022 Contributors to the Eclipse Foundation
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* and Apache License v2.0 which accompanies this distribution.
6+
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
7+
* and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
8+
*
9+
* You may elect to redistribute this code under either of these licenses.
10+
*
11+
* Contributors:
12+
*
13+
* Otavio Santana
14+
*/
15+
package org.eclipse.jnosql.databases.tinkerpop.cdi;
16+
17+
import org.testcontainers.containers.GenericContainer;
18+
import org.testcontainers.containers.wait.strategy.Wait;
19+
20+
enum ArangoDeployment {
21+
INSTANCE;
22+
23+
private final GenericContainer<?> arangodb =
24+
new GenericContainer<>("arangodb/arangodb:latest")
25+
.withExposedPorts(8529)
26+
.withEnv("ARANGO_NO_AUTH", "1")
27+
.waitingFor(Wait.forHttp("/")
28+
.forStatusCode(200));
29+
30+
{
31+
arangodb.start();
32+
}
33+
34+
public GenericContainer<?> getContainer() {
35+
return arangodb;
36+
}
37+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright (c) 2022 Contributors to the Eclipse Foundation
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* and Apache License v2.0 which accompanies this distribution.
6+
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
7+
* and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
8+
*
9+
* You may elect to redistribute this code under either of these licenses.
10+
*
11+
* Contributors:
12+
*
13+
* Otavio Santana
14+
* Michele Rastelli
15+
*/
16+
package org.eclipse.jnosql.databases.tinkerpop.cdi;
17+
18+
import com.arangodb.tinkerpop.gremlin.structure.ArangoDBGraph;
19+
import com.arangodb.tinkerpop.gremlin.structure.ArangoDBGraphConfig;
20+
import org.apache.commons.configuration2.BaseConfiguration;
21+
import org.apache.commons.configuration2.Configuration;
22+
import org.apache.tinkerpop.gremlin.neo4j.structure.Neo4jGraph;
23+
import org.apache.tinkerpop.gremlin.structure.Graph;
24+
import org.apache.tinkerpop.gremlin.structure.util.GraphFactory;
25+
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
26+
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerTransactionGraph;
27+
import org.testcontainers.containers.GenericContainer;
28+
29+
import java.io.File;
30+
import java.util.List;
31+
import java.util.function.Supplier;
32+
import java.util.logging.Logger;
33+
34+
import static java.lang.System.currentTimeMillis;
35+
36+
public enum TestGraphSupplier implements Supplier<Graph> {
37+
38+
NEO4J {
39+
private static final Logger LOGGER = Logger.getLogger(TestGraphSupplier.class.getName());
40+
41+
@Override
42+
public Graph get() {
43+
String directory = new File("").getAbsolutePath() + "/target/neo4j-graph/" + currentTimeMillis();
44+
LOGGER.info("Starting Neo4j at directory: " + directory);
45+
return Neo4jGraph.open(directory);
46+
}
47+
},
48+
49+
ARANGODB {
50+
@Override
51+
public Graph get() {
52+
GenericContainer<?> container = ArangoDeployment.INSTANCE.getContainer();
53+
Configuration configuration = new BaseConfiguration();
54+
configuration.addProperty("gremlin.graph", ArangoDBGraph.class.getName());
55+
configuration.addProperty("gremlin.arangodb.conf.graph.enableDataDefinition", true);
56+
configuration.addProperty("gremlin.arangodb.conf.graph.type", ArangoDBGraphConfig.GraphType.COMPLEX.name());
57+
configuration.addProperty("gremlin.arangodb.conf.graph.edgeDefinitions", List.of(
58+
"reads:[Human]->[Magazine]",
59+
"knows:[Person]->[Person]",
60+
"eats:[Creature]->[Creature]",
61+
"loves:[Human]->[Human]",
62+
"likes:[Human]->[Creature]",
63+
"friend:[Person]->[Person]"
64+
));
65+
configuration.addProperty("gremlin.arangodb.conf.driver.hosts", container.getHost() + ":" + container.getFirstMappedPort());
66+
return GraphFactory.open(configuration);
67+
}
68+
},
69+
70+
TINKER_GRAPH {
71+
@Override
72+
public Graph get() {
73+
Configuration configuration = new BaseConfiguration();
74+
configuration.setProperty(TinkerGraph.GREMLIN_TINKERGRAPH_VERTEX_ID_MANAGER, TinkerGraph.DefaultIdManager.STRING.name());
75+
configuration.setProperty(TinkerGraph.GREMLIN_TINKERGRAPH_EDGE_ID_MANAGER, TinkerGraph.DefaultIdManager.STRING.name());
76+
configuration.setProperty(TinkerGraph.GREMLIN_TINKERGRAPH_VERTEX_PROPERTY_ID_MANAGER, TinkerGraph.DefaultIdManager.STRING.name());
77+
return TinkerTransactionGraph.open(configuration);
78+
}
79+
}
80+
81+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (c) 2022 Contributors to the Eclipse Foundation
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* and Apache License v2.0 which accompanies this distribution.
6+
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
7+
* and the Apache License v2.0 is available at http://www.opensource.org/licenses/apache2.0.php.
8+
*
9+
* You may elect to redistribute this code under either of these licenses.
10+
*
11+
* Contributors:
12+
*
13+
* Otavio Santana
14+
* Michele Rastelli
15+
*/
16+
package org.eclipse.jnosql.databases.tinkerpop.cdi.arangodb;
17+
18+
import jakarta.annotation.PostConstruct;
19+
import jakarta.annotation.Priority;
20+
import jakarta.enterprise.context.ApplicationScoped;
21+
import jakarta.enterprise.inject.Alternative;
22+
import jakarta.enterprise.inject.Disposes;
23+
import jakarta.enterprise.inject.Produces;
24+
import jakarta.interceptor.Interceptor;
25+
import org.apache.tinkerpop.gremlin.structure.Graph;
26+
import org.eclipse.jnosql.databases.tinkerpop.cdi.TestGraphSupplier;
27+
28+
import java.util.function.Supplier;
29+
import java.util.logging.Logger;
30+
31+
@ApplicationScoped
32+
@Alternative
33+
@Priority(Interceptor.Priority.APPLICATION)
34+
public class ArangoDBGraphProducer implements Supplier<Graph> {
35+
36+
private static final Logger LOGGER = Logger.getLogger(ArangoDBGraphProducer.class.getName());
37+
38+
private Graph graph;
39+
40+
@PostConstruct
41+
public void init() {
42+
graph = TestGraphSupplier.ARANGODB.get();
43+
LOGGER.info("Graph database created");
44+
}
45+
46+
@Produces
47+
@ApplicationScoped
48+
@Override
49+
public Graph get() {
50+
return graph;
51+
}
52+
53+
public void dispose(@Disposes Graph graph) throws Exception {
54+
LOGGER.info("Graph database closing");
55+
graph.close();
56+
LOGGER.info("Graph Database closed");
57+
}
58+
59+
}

0 commit comments

Comments
 (0)