├── .gitignore ├── README.md ├── java ├── .gitignore ├── COMPILE.sh ├── build.gradle └── src │ └── main │ └── java │ └── TinkerPopWrapper.java └── rust ├── .gitignore ├── Cargo.toml └── src ├── graph.rs ├── lib.rs └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apache TinkerPop from Rust 2 | 3 | An example showing how to call [Apache TinkerPop](https://tinkerpop.apache.org) from [Rust](https://www.rust-lang.org) via 4 | [Rucaja](https://github.com/kud1ing/rucaja) (JNI). 5 | 6 | This repository contains two directories: 7 | 8 | * `java` contains a Java project to build a fat JAR `tinkerpop.jar` which contains a wrapper Java class around TinkerPop 9 | and all dependencies. 10 | * `rust` contains Rust code which uses `tinkerpop.jar`. 11 | Run it using `cargo run`. 12 | -------------------------------------------------------------------------------- /java/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | build/ 3 | -------------------------------------------------------------------------------- /java/COMPILE.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | gradle build shadowJar 4 | -------------------------------------------------------------------------------- /java/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | dependencies { 6 | classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.4' 7 | } 8 | } 9 | 10 | apply plugin: 'application' 11 | apply plugin: 'com.github.johnrengelman.shadow' 12 | apply plugin: 'eclipse' 13 | apply plugin: 'java' 14 | apply plugin: 'maven' 15 | 16 | mainClassName = "TinkerPopWrapper" 17 | 18 | repositories { 19 | mavenCentral() 20 | } 21 | 22 | dependencies { 23 | compile group: 'org.apache.tinkerpop', name: 'gremlin-core', version: '3.2.3' 24 | compile group: 'org.apache.tinkerpop', name: 'tinkergraph-gremlin', version: '3.2.3' 25 | } 26 | 27 | shadowJar { 28 | baseName = 'tinkerpop' 29 | classifier = null 30 | version = null 31 | } 32 | -------------------------------------------------------------------------------- /java/src/main/java/TinkerPopWrapper.java: -------------------------------------------------------------------------------- 1 | import org.apache.tinkerpop.gremlin.structure.Edge; 2 | import org.apache.tinkerpop.gremlin.structure.Graph; 3 | import org.apache.tinkerpop.gremlin.structure.Vertex; 4 | import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph; 5 | 6 | /** 7 | * A wrapper class for Apache TinkerPop to simplify access from Rust code. 8 | * 9 | * The Java method signatures can be seen using the Java command-line tool `javap`: 10 | * 11 | * javap -s build/classes/main/TinkerPopWrapper.class 12 | */ 13 | public class TinkerPopWrapper { 14 | 15 | /** 16 | * Adds a vertex to the graph 17 | * 18 | * @param graph 19 | * @return a new vertex 20 | */ 21 | public static Vertex add_vertex_to_graph(Graph graph) { 22 | return graph.addVertex(); 23 | } 24 | 25 | /** 26 | * A wrapper for `System.out.println()` that is easier to use from Rust. 27 | * @param o 28 | */ 29 | public static void println(Object o) { 30 | System.out.println(o); 31 | } 32 | 33 | /** 34 | * Creates and returns a `TinkerGraph`. 35 | * 36 | * @see 37 | * @return a new `TinkerGraph` instance 38 | */ 39 | public static Graph new_tinkergraph() { 40 | return TinkerGraph.open(); 41 | } 42 | 43 | /** 44 | * Adds an edge between two vertices. 45 | * 46 | * @param vertex_out 47 | * @param label 48 | * @param vertex_in 49 | * @return 50 | */ 51 | public static Edge add_edge_between_vertices(Vertex vertex_out, String label, Vertex vertex_in) { 52 | return vertex_out.addEdge(label, vertex_in); 53 | } 54 | 55 | public static void main(String[] args) { 56 | System.out.println(new_tinkergraph()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /rust/.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target/ 3 | -------------------------------------------------------------------------------- /rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Lennart Kudling"] 3 | description = "Rust calls Apache TinkerPop" 4 | documentation = "https://docs.rs/crate/rucaja" 5 | keywords = ["gremlin", "tinkerpop"] 6 | license = "MIT/Apache-2.0" 7 | name = "tinkerpop-rs" 8 | readme = "README.md" 9 | repository = "https://github.com/kud1ing/tinkerpop-rs" 10 | version = "0.1.0" 11 | 12 | [dependencies] 13 | rucaja="0.4.5" 14 | -------------------------------------------------------------------------------- /rust/src/graph.rs: -------------------------------------------------------------------------------- 1 | use rucaja::{JvmAttachment, JvmClass, JvmMethod, JvmObject, JvmString, jvalue_from_jobject}; 2 | use std::ptr::null; 3 | 4 | 5 | /// 6 | pub struct Graph<'a> { 7 | 8 | // The JVM. 9 | jvm_attachment: &'a JvmAttachment, 10 | 11 | // The wrapper JVM class from our fat JAR. 12 | wrapper_class: JvmClass<'a>, 13 | 14 | // Methods from that wrapper class. 15 | method_add_edge_between_vertices: JvmMethod, 16 | method_add_vertex_to_graph: JvmMethod, 17 | method_println: JvmMethod, 18 | 19 | // A `TinkerPop` graph object. 20 | object_graph: JvmObject<'a>, 21 | } 22 | 23 | impl<'a> Graph<'a> { 24 | 25 | /// 26 | pub fn add_edge(&self, vertex1: &JvmObject, predicate: &JvmString, vertex2: &JvmObject) -> Option { 27 | 28 | let args = vec![ 29 | jvalue_from_jobject(vertex1.jvm_ptr()), 30 | jvalue_from_jobject(predicate.jvm_ptr()), 31 | jvalue_from_jobject(vertex2.jvm_ptr()), 32 | ]; 33 | 34 | JvmMethod::call_static_object_method( 35 | self.jvm_attachment, 36 | &self.wrapper_class, 37 | &self.method_add_edge_between_vertices, 38 | args.as_ptr() 39 | ) 40 | } 41 | 42 | /// 43 | pub fn add_vertex(&self) -> Option { 44 | 45 | let args = vec![jvalue_from_jobject(self.object_graph.jvm_ptr())]; 46 | 47 | JvmMethod::call_static_object_method( 48 | self.jvm_attachment, 49 | &self.wrapper_class, 50 | &self.method_add_vertex_to_graph, 51 | args.as_ptr() 52 | ) 53 | } 54 | 55 | /// 56 | pub fn new(jvm_attachment: &JvmAttachment) -> Option { 57 | 58 | // Resolve the Java wrapper class from the fat JAR. 59 | let wrapper_class = JvmClass::get_class(jvm_attachment, "TinkerPopWrapper").expect("Could not find `TinkerPopWrapper`"); 60 | 61 | // Resolve Java methods in that wrapper class. 62 | let method_add_edge_between_vertices = JvmMethod::get_static_method( 63 | jvm_attachment, 64 | &wrapper_class, "add_edge_between_vertices", 65 | "(Lorg/apache/tinkerpop/gremlin/structure/Vertex;Ljava/lang/String;Lorg/apache/tinkerpop/gremlin/structure/Vertex;)Lorg/apache/tinkerpop/gremlin/structure/Edge;" 66 | ).expect("Could not find Java method `add_edge_between_vertices()`"); 67 | 68 | let method_add_vertex_to_graph = JvmMethod::get_static_method( 69 | jvm_attachment, 70 | &wrapper_class, "add_vertex_to_graph", 71 | "(Lorg/apache/tinkerpop/gremlin/structure/Graph;)Lorg/apache/tinkerpop/gremlin/structure/Vertex;" 72 | ).expect("Could not find Java method `add_vertex_to_graph()`"); 73 | 74 | let method_new_tinkergraph = JvmMethod::get_static_method( 75 | jvm_attachment, 76 | &wrapper_class, "new_tinkergraph", 77 | "()Lorg/apache/tinkerpop/gremlin/structure/Graph;" 78 | ).expect("Could not find Java method `new_tinkergraph()`"); 79 | 80 | let method_println = JvmMethod::get_static_method( 81 | jvm_attachment, 82 | &wrapper_class, 83 | "println", 84 | "(Ljava/lang/Object;)V" 85 | ).expect("Could not find Java method `println()`"); 86 | 87 | // Create a `TinkerGraph` object. 88 | let object_graph = JvmMethod::call_static_object_method( 89 | jvm_attachment, 90 | &wrapper_class, 91 | &method_new_tinkergraph, 92 | null() 93 | ).unwrap(); 94 | 95 | Some( 96 | Graph { 97 | jvm_attachment: jvm_attachment, 98 | wrapper_class: wrapper_class, 99 | method_add_edge_between_vertices: method_add_edge_between_vertices, 100 | method_add_vertex_to_graph: method_add_vertex_to_graph, 101 | method_println: method_println, 102 | object_graph: object_graph, 103 | } 104 | ) 105 | } 106 | 107 | /// 108 | pub fn println(&self) { 109 | 110 | let args = vec![jvalue_from_jobject(self.object_graph.jvm_ptr())]; 111 | 112 | JvmMethod::call_static_void_method( 113 | self.jvm_attachment, 114 | &self.wrapper_class, 115 | &self.method_println, 116 | args.as_ptr() 117 | ) 118 | } 119 | } -------------------------------------------------------------------------------- /rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate rucaja; 2 | 3 | pub mod graph; -------------------------------------------------------------------------------- /rust/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate rucaja; 2 | extern crate tinkerpop_rs; 3 | 4 | use rucaja::{Jvm, JvmAttachment, JvmString}; 5 | use tinkerpop_rs::graph::Graph; 6 | 7 | 8 | fn main() { 9 | 10 | // The class path must contain the fat JAR. 11 | let class_path = "-Djava.class.path=../java/build/libs/tinkerpop.jar"; 12 | 13 | let jvm_options = [class_path]; 14 | 15 | // Instantiate the embedded JVM. 16 | let jvm = Jvm::new(&jvm_options); 17 | 18 | // Attach the current native thread to the JVM. 19 | let jvm_attachment = JvmAttachment::new(jvm.jvm()); 20 | 21 | // Instantiate a `TinkerGraph`. 22 | let graph = Graph::new(&jvm_attachment).expect("Could not instantiate graph"); 23 | 24 | // Add vertices. 25 | let v1 = graph.add_vertex().expect("Could not add vertex to graph"); 26 | let v2 = graph.add_vertex().expect("Could not add vertex to graph"); 27 | 28 | // Add an edge between those vertices. 29 | let p = JvmString::new(&jvm_attachment, "likes").expect("Could not create string"); 30 | graph.add_edge(&v1, &p, &v2).expect("Could not add edge"); 31 | 32 | // Print the graph using Java's `System.out.println()`. 33 | graph.println(); 34 | } 35 | --------------------------------------------------------------------------------