use JNI for java interop

main
Ziyang Hu 2 years ago
parent 909823b10d
commit e725c0f6c7

104
Cargo.lock generated

@ -2,16 +2,6 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "Inflector"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
dependencies = [
"lazy_static",
"regex",
]
[[package]]
name = "addr2line"
version = "0.17.0"
@ -396,7 +386,7 @@ dependencies = [
"clap_lex",
"indexmap",
"once_cell",
"strsim 0.10.0",
"strsim",
"termcolor",
"textwrap 0.16.0",
]
@ -561,8 +551,8 @@ name = "cozo_java"
version = "0.1.3"
dependencies = [
"cozo",
"jni",
"lazy_static",
"robusta_jni",
]
[[package]]
@ -726,41 +716,6 @@ dependencies = [
"syn",
]
[[package]]
name = "darling"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim 0.9.3",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]]
name = "deflate"
version = "1.0.0"
@ -829,16 +784,6 @@ dependencies = [
"termcolor",
]
[[package]]
name = "error-chain"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
dependencies = [
"backtrace",
"version_check",
]
[[package]]
name = "fail"
version = "0.4.0"
@ -1310,12 +1255,6 @@ dependencies = [
"cxx-build",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.3.0"
@ -1389,15 +1328,15 @@ checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
[[package]]
name = "jni"
version = "0.17.0"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36bcc950632e48b86da402c5c077590583da5ac0d480103611d5374e7c967a3c"
checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c"
dependencies = [
"cesu8",
"combine",
"error-chain",
"jni-sys",
"log",
"thiserror",
"walkdir",
]
@ -2479,33 +2418,6 @@ dependencies = [
"rmp",
]
[[package]]
name = "robusta-codegen"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f66a33c846c7b892c2fd20ff58ba34859e6d83e491d51ce94f678cc7157ad774"
dependencies = [
"Inflector",
"darling",
"proc-macro-error",
"proc-macro2",
"quote",
"rand 0.7.3",
"syn",
]
[[package]]
name = "robusta_jni"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a61f3ca304f439f93ae5f59f2fe65f4c2693b253c7656dc242c061996a4b01f8"
dependencies = [
"jni",
"paste",
"robusta-codegen",
"static_assertions",
]
[[package]]
name = "rouille"
version = "3.6.1"
@ -2838,12 +2750,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
name = "strsim"
version = "0.10.0"

@ -0,0 +1 @@
*.class

@ -19,7 +19,7 @@ io-uring = ["cozo/io-uring"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
robusta_jni = "0.2.0"
jni = "0.20.0"
# , features = ["compact"]
cozo = { version = "0.1.3", path = "../cozo-core", default_features = false }
cozo = { version = "0.1.3", path = "../cozo-core", default_features = false, features = ["compact"] }
lazy_static = "1.4.0"

@ -0,0 +1,19 @@
package org.cozodb;
public class CozoJavaBridge {
private static native int openDb(String kind, String path);
private static native boolean closeDb(int id);
private static native String runQuery(int id, String script, String params);
private static native String exportRelations(int id, String rel);
private static native String importRelations(int id, String data);
private static native String backup(int id, String file);
private static native String restore(int id, String file);
static {
System.loadLibrary("cozo_java");
}
public static void main(String[] args) {
System.out.println("OK");
}
}

@ -1,10 +1,6 @@
#!/usr/bin/env bash
export ANDROID_HOME=/Users/$USER/Library/Android/sdk
export NDK_HOME=/Users/$USER/Library/Android/sdk/ndk/23.1.7779620/
export PATH=$PATH:$HOME/Library/Android/sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/darwin-x86_64/bin/
export CC=aarch64-linux-android23-clang
export CXX=aarch64-linux-android23-clang++
export LD=$HOME/Library/Android/sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/darwin-x86_64/bin/ld
export LD_LIBRARY_PATH=/Users/zh217/Library/Android/sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/darwin-x86_64/sysroot/usr/lib/aarch64-linux-android/26
cargo build --release -p cozo_c --target=aarch64-linux-android
cross build -p cozo_java --release --target=aarch64-linux-android
cross build -p cozo_java --release --target=armv7-linux-androideabi
cross build -p cozo_java --release --target=i686-linux-android
cross build -p cozo_java --release --target=x86_64-linux-android

@ -0,0 +1,69 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_cozodb_CozoJavaBridge */
#ifndef _Included_org_cozodb_CozoJavaBridge
#define _Included_org_cozodb_CozoJavaBridge
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_cozodb_CozoJavaBridge
* Method: openDb
* Signature: (Ljava/lang/String;Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_org_cozodb_CozoJavaBridge_openDb
(JNIEnv *, jclass, jstring, jstring);
/*
* Class: org_cozodb_CozoJavaBridge
* Method: closeDb
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL Java_org_cozodb_CozoJavaBridge_closeDb
(JNIEnv *, jclass, jint);
/*
* Class: org_cozodb_CozoJavaBridge
* Method: runQuery
* Signature: (ILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_org_cozodb_CozoJavaBridge_runQuery
(JNIEnv *, jclass, jint, jstring, jstring);
/*
* Class: org_cozodb_CozoJavaBridge
* Method: exportRelations
* Signature: (ILjava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_org_cozodb_CozoJavaBridge_exportRelations
(JNIEnv *, jclass, jint, jstring);
/*
* Class: org_cozodb_CozoJavaBridge
* Method: importRelations
* Signature: (ILjava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_org_cozodb_CozoJavaBridge_importRelations
(JNIEnv *, jclass, jint, jstring);
/*
* Class: org_cozodb_CozoJavaBridge
* Method: backup
* Signature: (ILjava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_org_cozodb_CozoJavaBridge_backup
(JNIEnv *, jclass, jint, jstring);
/*
* Class: org_cozodb_CozoJavaBridge
* Method: restore
* Signature: (ILjava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_org_cozodb_CozoJavaBridge_restore
(JNIEnv *, jclass, jint, jstring);
#ifdef __cplusplus
}
#endif
#endif

@ -6,13 +6,13 @@
* You can obtain one at https://mozilla.org/MPL/2.0/.
*/
use std::collections::BTreeMap;
use std::sync::atomic::AtomicI32;
use std::sync::atomic::{AtomicI32, Ordering};
use std::sync::Mutex;
use jni::objects::{JClass, JString};
use jni::sys::{jboolean, jint, jstring};
use jni::JNIEnv;
use lazy_static::lazy_static;
use robusta_jni::bridge;
use robusta_jni::jni::errors::Error as JniError;
use robusta_jni::jni::errors::Result as JniResult;
use cozo::*;
@ -29,76 +29,133 @@ lazy_static! {
};
}
fn get_db(id: i32) -> JniResult<DbInstance> {
let db_ref = {
fn get_db(id: i32) -> Option<DbInstance> {
let dbs = HANDLES.dbs.lock().unwrap();
dbs.get(&id).cloned()
};
db_ref.ok_or_else(|| JniError::from("database already closed"))
}
#[bridge]
mod jni {
use std::sync::atomic::Ordering;
use robusta_jni::convert::{IntoJavaValue, Signature, TryFromJavaValue, TryIntoJavaValue};
use robusta_jni::jni::errors::Error as JniError;
use robusta_jni::jni::errors::Result as JniResult;
use robusta_jni::jni::objects::AutoLocal;
use cozo::*;
use crate::{get_db, HANDLES};
#[derive(Signature, TryIntoJavaValue, IntoJavaValue, TryFromJavaValue)]
#[package(org.cozodb)]
pub struct CozoDb<'env: 'borrow, 'borrow> {
#[instance]
raw: AutoLocal<'env, 'borrow>,
}
impl<'env: 'borrow, 'borrow> CozoDb<'env, 'borrow> {
pub extern "jni" fn openDb(kind: String, path: String) -> JniResult<i32> {
match DbInstance::new(&kind, &path, Default::default()) {
#[no_mangle]
pub extern "system" fn Java_org_cozodb_CozoJavaBridge_openDb(
env: JNIEnv,
_class: JClass,
kind: JString,
path: JString,
) -> jint {
let kind: String = env.get_string(kind).unwrap().into();
let path: String = env.get_string(path).unwrap().into();
let id = match DbInstance::new(&kind, &path, Default::default()) {
Ok(db) => {
let id = HANDLES.current.fetch_add(1, Ordering::AcqRel);
let mut dbs = HANDLES.dbs.lock().unwrap();
dbs.insert(id, db);
Ok(id)
id
}
Err(err) => Err(JniError::from(format!("{:?}", err))),
Err(err) => {
eprintln!("{:?}", err);
-1
}
}
pub extern "jni" fn closeDb(id: i32) -> JniResult<bool> {
};
id
}
#[no_mangle]
pub extern "system" fn Java_org_cozodb_CozoJavaBridge_closeDb(
_env: JNIEnv,
_class: JClass,
id: jint,
) -> jboolean {
let db = {
let mut dbs = HANDLES.dbs.lock().unwrap();
dbs.remove(&id)
};
Ok(db.is_some())
db.is_some().into()
}
const DB_NOT_FOUND: &str = r#"{"ok":false,"message":"database not found"}"#;
#[no_mangle]
pub extern "system" fn Java_org_cozodb_CozoJavaBridge_runQuery(
env: JNIEnv,
_class: JClass,
id: jint,
script: JString,
params_str: JString,
) -> jstring {
let script: String = env.get_string(script).unwrap().into();
let params_str: String = env.get_string(params_str).unwrap().into();
match get_db(id) {
None => env.new_string(DB_NOT_FOUND).unwrap().into_raw(),
Some(db) => {
let res = db.run_script_str(&script, &params_str);
env.new_string(res).unwrap().into_raw()
}
}
}
#[no_mangle]
pub extern "system" fn Java_org_cozodb_CozoJavaBridge_exportRelations(
env: JNIEnv,
_class: JClass,
id: jint,
rel: JString,
) -> jstring {
let rel: String = env.get_string(rel).unwrap().into();
match get_db(id) {
None => env.new_string(DB_NOT_FOUND).unwrap().into_raw(),
Some(db) => {
let res = db.export_relations_str(&rel);
env.new_string(res).unwrap().into_raw()
}
}
pub extern "jni" fn runQuery(
id: i32,
script: String,
params_str: String,
) -> JniResult<String> {
let db = get_db(id)?;
Ok(db.run_script_str(&script, &params_str))
}
#[no_mangle]
pub extern "system" fn Java_org_cozodb_CozoJavaBridge_importRelations(
env: JNIEnv,
_class: JClass,
id: jint,
data: JString,
) -> jstring {
let data: String = env.get_string(data).unwrap().into();
match get_db(id) {
None => env.new_string(DB_NOT_FOUND).unwrap().into_raw(),
Some(db) => {
let res = db.import_relation_str(&data);
env.new_string(res).unwrap().into_raw()
}
pub extern "jni" fn exportRelations(id: i32, relations_str: String) -> JniResult<String> {
let db = get_db(id)?;
Ok(db.export_relations_str(&relations_str))
}
pub extern "jni" fn importRelation(id: i32, data: String) -> JniResult<String> {
let db = get_db(id)?;
Ok(db.import_relation_str(&data))
}
#[no_mangle]
pub extern "system" fn Java_org_cozodb_CozoJavaBridge_backup(
env: JNIEnv,
_class: JClass,
id: jint,
file: JString,
) -> jstring {
let file: String = env.get_string(file).unwrap().into();
match get_db(id) {
None => env.new_string(DB_NOT_FOUND).unwrap().into_raw(),
Some(db) => {
let res = db.backup_db_str(&file);
env.new_string(res).unwrap().into_raw()
}
pub extern "jni" fn backup(id: i32, out_file: String) -> JniResult<String> {
let db = get_db(id)?;
Ok(db.backup_db_str(&out_file))
}
pub extern "jni" fn restore(id: i32, in_file: String) -> JniResult<String> {
let db = get_db(id)?;
Ok(db.restore_backup_str(&in_file))
}
#[no_mangle]
pub extern "system" fn Java_org_cozodb_CozoJavaBridge_restore(
env: JNIEnv,
_class: JClass,
id: jint,
file: JString,
) -> jstring {
let file: String = env.get_string(file).unwrap().into();
match get_db(id) {
None => env.new_string(DB_NOT_FOUND).unwrap().into_raw(),
Some(db) => {
let res = db.restore_backup_str(&file);
env.new_string(res).unwrap().into_raw()
}
}
}

Loading…
Cancel
Save