diff --git a/.github/workflows/publish-java.yml b/.github/workflows/publish-java.yml new file mode 100644 index 0000000..b95d06a --- /dev/null +++ b/.github/workflows/publish-java.yml @@ -0,0 +1,87 @@ +name: publish-java + +on: workflow_dispatch + +permissions: + contents: read + +jobs: + build: + name: Build for ${{ matrix.target }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + extension: so + - target: aarch64-unknown-linux-gnu + os: ubuntu-latest + extension: so + - target: x86_64-apple-darwin + os: macos-latest + extension: dylib + - target: aarch64-apple-darwin + os: macos-latest + extension: dylib + - target: x86_64-pc-windows-msvc + os: windows-latest + extension: dll + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-java@v4 + with: + java-version: 8 + distribution: "corretto" + - uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + + - if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }} + run: | + sudo apt-get update + sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + # Setup for cargo + echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV + + - run: cargo build --release --target ${{ matrix.target }} --manifest-path ./bindings/java/Cargo.toml + - run: mkdir -p native/${{ matrix.target }} + - run: mv target/${{ matrix.target }}/release/*.${{ matrix.extension }} ./native/${{ matrix.target }}/ + - uses: actions/upload-artifact@v4 + with: + name: native-libraries-${{ matrix.target }} + path: native/ + + release: + name: Release + runs-on: ubuntu-latest + needs: build + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-java@v4 + with: + java-version: 8 + distribution: "corretto" + server-id: ossrh + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + - uses: actions/download-artifact@v4 + with: + pattern: native-libraries-* + merge-multiple: true + path: ./bindings/java/native/ + - run: mvn package + working-directory: ./bindings/java + - uses: actions/upload-artifact@v4 + with: + name: built-jars + path: ./bindings/java/target/regorus-java-*.jar + - run: mvn deploy + working-directory: ./bindings/java + env: + MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} diff --git a/bindings/java/README.md b/bindings/java/README.md index de2f788..9c7e603 100644 --- a/bindings/java/README.md +++ b/bindings/java/README.md @@ -8,19 +8,38 @@ See main [Regorus page](https://github.com/microsoft/regorus) for more details about the project. -Regorus can be used in Java via `com.microsoft.regorus` package. (It is not yet available in Maven Central, but can be manually built.) +## Usage -## Building +Regorus Java is published to Maven Central with native libraries for the following: -You can build this binding using [Maven](https://maven.apache.org/): -```shell -$ mvn package -$ file target/regorus-java-0.0.1* -target/regorus-java-0.0.1-osx-aarch_64.jar: Zip archive data, at least v1.0 to extract, compression method=deflate -target/regorus-java-0.0.1.jar: Zip archive data, at least v1.0 to extract, compression method=deflate +- 64-bit Linux (kernel 3.2+, glibc 2.17+) +- ARM64 Linux (kernel 4.1, glibc 2.17+) +- 64-bit macOS (10.12+, Sierra+) +- ARM64 macOS (11.0+, Big Sur+) +- 64-bit MSVC (Windows 7+) + +If you need to run it in a different OS or an architecture you need to manually [build it](#Building). + +If you're on one of the supported platforms, you can just pull prebuilt JAR from Maven Central by declaring a dependency on `com.microsoft.regorus:regorus-java`. + +With [Maven](https://maven.apache.org/): +```xml + + + com.microsoft.regorus + regorus-java + 0.0.1 + + ``` -## Usage +With [Gradle](https://gradle.org/): +```kotlin +// build.gradle.kts +implementation("com.microsoft.regorus:regorus-java:0.0.1") +``` + +Afterwards you can use it as follows: ```java import com.microsoft.regorus.Engine; @@ -28,13 +47,13 @@ import com.microsoft.regorus.Engine; public class Test { public static void main(String[] args) { try (Engine engine = new Engine()) { - engine.pubAddPolicy( + engine.addPolicy( "hello.rego", "package test\nmessage = concat(\", \", [input.message, data.message])" ); - engine.pubAddDataJson("{\"message\":\"World!\"}"); - engine.pubSetInputJson("{\"message\":\"Hello\"}"); - String resJson = engine.pubEvalQuery("data.test.message"); + engine.addDataJson("{\"message\":\"World!\"}"); + engine.setInputJson("{\"message\":\"Hello\"}"); + String resJson = engine.evalQuery("data.test.message"); System.out.println(resJson); } @@ -42,8 +61,37 @@ public class Test { } ``` -and run it with: +And you can see the following output once you run it: ```shell -$ java -cp target/regorus-java-0.0.1.jar:target/regorus-java-0.0.1-osx-aarch_64.jar Test.java {"result":[{"expressions":[{"value":"Hello, World!","text":"data.test.message","location":{"row":1,"col":1}}]}]} -``` \ No newline at end of file +``` + +## Building + +In order to build Regorus Java for a target platform, you need to install Rust target +for that target platform first: + +```bash +$ rustup target add aarch64-apple-darwin +``` + +Afterwards, you can build native library for that target using: +```bash +$ cargo build --release --target aarch64-apple-darwin +``` + +You will then have a native library at `../../target/aarch64-apple-darwin/release/libregorus_java.dylib` depending on your target. + +You can then build a JAR from source using: +```bash +$ mvn package +``` + +And you will have a JAR at `./target/regorus-java-0.0.1.jar`. + +You need to make sure both of the artifacts in Java's classpath. +For example with `java` CLI: +```bash +$ java -Djava.library.path=../../target/aarch64-apple-darwin/release/ -cp target/regorus-java-0.0.1.jar Test.java +``` + diff --git a/bindings/java/com_microsoft_regorus_Engine.h b/bindings/java/com_microsoft_regorus_Engine.h index c5e1638..86f7e2f 100644 --- a/bindings/java/com_microsoft_regorus_Engine.h +++ b/bindings/java/com_microsoft_regorus_Engine.h @@ -9,74 +9,82 @@ extern "C" { #endif /* * Class: com_microsoft_regorus_Engine - * Method: newEngine + * Method: nativeNewEngine * Signature: ()J */ -JNIEXPORT jlong JNICALL Java_com_microsoft_regorus_Engine_newEngine +JNIEXPORT jlong JNICALL Java_com_microsoft_regorus_Engine_nativeNewEngine (JNIEnv *, jclass); /* * Class: com_microsoft_regorus_Engine - * Method: addPolicy + * Method: nativeAddPolicy * Signature: (JLjava/lang/String;Ljava/lang/String;)V */ -JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_addPolicy +JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_nativeAddPolicy (JNIEnv *, jclass, jlong, jstring, jstring); /* * Class: com_microsoft_regorus_Engine - * Method: addPolicyFromFile + * Method: nativeAddPolicyFromFile * Signature: (JLjava/lang/String;)V */ -JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_addPolicyFromFile +JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_nativeAddPolicyFromFile (JNIEnv *, jclass, jlong, jstring); /* * Class: com_microsoft_regorus_Engine - * Method: addDataJson - * Signature: (JLjava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_addDataJson - (JNIEnv *, jclass, jlong, jstring); - -/* - * Class: com_microsoft_regorus_Engine - * Method: addDataJsonFromFile - * Signature: (JLjava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_addDataJsonFromFile - (JNIEnv *, jclass, jlong, jstring); - -/* - * Class: com_microsoft_regorus_Engine - * Method: setInputJson - * Signature: (JLjava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_setInputJson - (JNIEnv *, jclass, jlong, jstring); - -/* - * Class: com_microsoft_regorus_Engine - * Method: setInputJsonFromFile - * Signature: (JLjava/lang/String;)V - */ -JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_setInputJsonFromFile - (JNIEnv *, jclass, jlong, jstring); - -/* - * Class: com_microsoft_regorus_Engine - * Method: evalQuery - * Signature: (JLjava/lang/String;)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_microsoft_regorus_Engine_evalQuery - (JNIEnv *, jclass, jlong, jstring); - -/* - * Class: com_microsoft_regorus_Engine - * Method: destroyEngine + * Method: nativeClearData * Signature: (J)V */ -JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_destroyEngine +JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_nativeClearData + (JNIEnv *, jclass, jlong); + +/* + * Class: com_microsoft_regorus_Engine + * Method: nativeAddDataJson + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_nativeAddDataJson + (JNIEnv *, jclass, jlong, jstring); + +/* + * Class: com_microsoft_regorus_Engine + * Method: nativeAddDataJsonFromFile + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_nativeAddDataJsonFromFile + (JNIEnv *, jclass, jlong, jstring); + +/* + * Class: com_microsoft_regorus_Engine + * Method: nativeSetInputJson + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_nativeSetInputJson + (JNIEnv *, jclass, jlong, jstring); + +/* + * Class: com_microsoft_regorus_Engine + * Method: nativeSetInputJsonFromFile + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_nativeSetInputJsonFromFile + (JNIEnv *, jclass, jlong, jstring); + +/* + * Class: com_microsoft_regorus_Engine + * Method: nativeEvalQuery + * Signature: (JLjava/lang/String;)Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_com_microsoft_regorus_Engine_nativeEvalQuery + (JNIEnv *, jclass, jlong, jstring); + +/* + * Class: com_microsoft_regorus_Engine + * Method: nativeDestroyEngine + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_microsoft_regorus_Engine_nativeDestroyEngine (JNIEnv *, jclass, jlong); #ifdef __cplusplus diff --git a/bindings/java/pom.xml b/bindings/java/pom.xml index f8edba5..6b5ed29 100644 --- a/bindings/java/pom.xml +++ b/bindings/java/pom.xml @@ -4,8 +4,7 @@ Licensed under the MIT License. --> - + 4.0.0 com.microsoft.regorus @@ -16,12 +15,27 @@ Java bindings for Regorus - a fast, lightweight Rego interpreter written in Rust https://github.com/microsoft/regorus/bindings/java + + + MIT License + https://opensource.org/blog/license/mit + + + UTF-8 1.8 1.8 + + + ossrh + Central Repository OSSRH + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + junit @@ -38,114 +52,80 @@ - - - - maven-clean-plugin - 3.1.0 - - - maven-site-plugin - 3.7.1 - - - maven-project-info-reports-plugin - 3.0.0 - - - - maven-resources-plugin - 3.0.2 - - - maven-compiler-plugin - 3.8.0 - - - maven-surefire-plugin - 2.22.1 - - - maven-jar-plugin - 3.0.2 - - - maven-install-plugin - 2.5.2 - - - maven-deploy-plugin - 2.8.2 - - - + + + + ${project.basedir}/native + + - - - kr.motd.maven - os-maven-plugin - 1.7.0 - - - - - exec-maven-plugin - org.codehaus.mojo - 3.1.0 - - - compile-native-code - compile - - exec - - - python3 - - ${project.basedir}/tools/build.py - --classifier - ${os.detected.classifier} - - - - + exec-maven-plugin + org.codehaus.mojo + 3.1.0 + + + + build-native-lib-for-test + test-compile + + exec + + + python3 + + ${project.basedir}/tools/testbuild.py + + + + + - org.apache.maven.plugins - maven-surefire-plugin - 3.1.2 + maven-surefire-plugin + 3.2.5 + + + -Djava.library.path=${project.basedir}/target/debug:${java.library.path} + + + - org.apache.maven.plugins - maven-jar-plugin - - - - default-jar - - - native/** - - - - - - native-jar - - jar - - - ${os.detected.classifier} - - native/** - - - - + org.apache.maven.plugins + maven-javadoc-plugin + 3.6.3 + + + attach-javadoc + + jar + + + - + + + + org.apache.maven.plugins + maven-source-plugin + 3.3.0 + + + attach-sources + + jar + + + + + diff --git a/bindings/java/src/lib.rs b/bindings/java/src/lib.rs index 98ffd22..304ae71 100644 --- a/bindings/java/src/lib.rs +++ b/bindings/java/src/lib.rs @@ -9,7 +9,7 @@ use jni::JNIEnv; use regorus::{Engine, Value}; #[no_mangle] -pub extern "system" fn Java_com_microsoft_regorus_Engine_newEngine( +pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeNewEngine( _env: JNIEnv, _class: JClass, ) -> jlong { @@ -18,7 +18,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_newEngine( } #[no_mangle] -pub extern "system" fn Java_com_microsoft_regorus_Engine_addPolicy( +pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddPolicy( env: JNIEnv, _class: JClass, engine_ptr: jlong, @@ -35,7 +35,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_addPolicy( } #[no_mangle] -pub extern "system" fn Java_com_microsoft_regorus_Engine_addPolicyFromFile( +pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddPolicyFromFile( env: JNIEnv, _class: JClass, engine_ptr: jlong, @@ -50,7 +50,20 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_addPolicyFromFile( } #[no_mangle] -pub extern "system" fn Java_com_microsoft_regorus_Engine_addDataJson( +pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeClearData( + env: JNIEnv, + _class: JClass, + engine_ptr: jlong, +) { + let _ = throw_err(env, |_env| { + let engine = unsafe { &mut *(engine_ptr as *mut Engine) }; + engine.clear_data(); + Ok(()) + }); +} + +#[no_mangle] +pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddDataJson( env: JNIEnv, _class: JClass, engine_ptr: jlong, @@ -65,7 +78,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_addDataJson( } #[no_mangle] -pub extern "system" fn Java_com_microsoft_regorus_Engine_addDataJsonFromFile( +pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeAddDataJsonFromFile( env: JNIEnv, _class: JClass, engine_ptr: jlong, @@ -80,7 +93,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_addDataJsonFromFile( } #[no_mangle] -pub extern "system" fn Java_com_microsoft_regorus_Engine_setInputJson( +pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetInputJson( env: JNIEnv, _class: JClass, engine_ptr: jlong, @@ -95,7 +108,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_setInputJson( } #[no_mangle] -pub extern "system" fn Java_com_microsoft_regorus_Engine_setInputJsonFromFile( +pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeSetInputJsonFromFile( env: JNIEnv, _class: JClass, engine_ptr: jlong, @@ -110,7 +123,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_setInputJsonFromFile( } #[no_mangle] -pub extern "system" fn Java_com_microsoft_regorus_Engine_evalQuery( +pub extern "system" fn Java_com_microsoft_regorus_Engine_nativeEvalQuery( env: JNIEnv, _class: JClass, engine_ptr: jlong, @@ -131,7 +144,7 @@ pub extern "system" fn Java_com_microsoft_regorus_Engine_evalQuery( } #[no_mangle] -pub unsafe extern "system" fn Java_com_microsoft_regorus_Engine_destroyEngine( +pub unsafe extern "system" fn Java_com_microsoft_regorus_Engine_nativeDestroyEngine( _env: JNIEnv, _class: JClass, engine_ptr: jlong, diff --git a/bindings/java/src/main/java/com/microsoft/regorus/Engine.java b/bindings/java/src/main/java/com/microsoft/regorus/Engine.java index 17b2ed3..11fc072 100644 --- a/bindings/java/src/main/java/com/microsoft/regorus/Engine.java +++ b/bindings/java/src/main/java/com/microsoft/regorus/Engine.java @@ -13,77 +13,163 @@ import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.concurrent.atomic.AtomicReference; +/** + * Regorus Engine. + */ public class Engine implements AutoCloseable { // Methods exposed from Rust side, you can run // `javac -h . src/main/java/com/microsoft/regorus/Engine.java` to update // expected native header at `bindings/java/com_microsoft_regorus_Engine.h` // if you update the native API. - private static native long newEngine(); - private static native void addPolicy(long enginePtr, String path, String rego); - private static native void addPolicyFromFile(long enginePtr, String path); - private static native void addDataJson(long enginePtr, String data); - private static native void addDataJsonFromFile(long enginePtr, String path); - private static native void setInputJson(long enginePtr, String input); - private static native void setInputJsonFromFile(long enginePtr, String path); - private static native String evalQuery(long enginePtr, String query); - private static native void destroyEngine(long enginePtr); + private static native long nativeNewEngine(); + private static native void nativeAddPolicy(long enginePtr, String path, String rego); + private static native void nativeAddPolicyFromFile(long enginePtr, String path); + private static native void nativeClearData(long enginePtr); + private static native void nativeAddDataJson(long enginePtr, String data); + private static native void nativeAddDataJsonFromFile(long enginePtr, String path); + private static native void nativeSetInputJson(long enginePtr, String input); + private static native void nativeSetInputJsonFromFile(long enginePtr, String path); + private static native String nativeEvalQuery(long enginePtr, String query); + private static native void nativeDestroyEngine(long enginePtr); // Pointer to Engine allocated on Rust's heap, all native methods works on // engine expects this pointer. It is free'd in `close` method. private final long enginePtr; + /** + * Creates a new Regorus Engine. + */ public Engine() { - enginePtr = newEngine(); + enginePtr = nativeNewEngine(); } - public void pubAddPolicy(String path, String rego) { - addPolicy(enginePtr, path, rego); + /** + * Adds an inline Rego policy. + * + * @param filename Filename of this Rego policy. + * @param rego Rego policy. + */ + public void addPolicy(String filename, String rego) { + nativeAddPolicy(enginePtr, filename, rego); } - public void pubAddDataJson(String path) { - addDataJson(enginePtr, path); + /** + * Adds a Rego policy from given path. + * + * @param path Path of the Rego policy. + */ + public void addPolicyFromFile(String path) { + nativeAddPolicyFromFile(enginePtr, path); } - public void pubSetInputJson(String path) { - setInputJson(enginePtr, path); + /** + * Clears the data document. + */ + public void clearData() { + nativeClearData(enginePtr); } - public String pubEvalQuery(String path) { - return evalQuery(enginePtr, path); + /** + * Adds inline data document from given JSON. + * The specified data document is merged into existing data document. + * It will throw an error if new data conflicts with the existing document. + * + * Example: + * addDataJson("[]") - Throws as it's not an object. + * addDataJson('{"a": 1}') - Fine + * addDataJson('{"b": 2}') - Fine, now {"a": 1, "b": 2} + * addDataJson('{"b": 3}') - Throws as `b` conflicts. + * + * @see clearData + * + * @throws RuntimeException If data conflicts with the existing document + * or data is not an object. + * + * @param data Inline data document. + */ + public void addDataJson(String data) throws RuntimeException { + nativeAddDataJson(enginePtr, data); + } + + /** + * Adds data document from given JSON file. + * The specified data document is merged into existing data document. + * It will throw an error if new data conflicts with the existing document. + * + * @see addDataJson + * @see clearData + * + * @throws RuntimeException If data conflicts with the existing document + * or data is not an object. + * + * @param path Path to JSON data document. + */ + public void addDataJsonFromFile(String path) throws RuntimeException { + nativeAddDataJsonFromFile(enginePtr, path); + } + + /** + * Sets inline JSON input. + * + * @param input inline JSON input. + */ + public void setInputJson(String input) { + nativeSetInputJson(enginePtr, input); + } + + /** + * Sets JSON input from given path. + * + * @param path Path to JSON input. + */ + public void setInputJsonFromFile(String path) { + nativeSetInputJsonFromFile(enginePtr, path); + } + + /** + * Evaluates given Rego query and returns a JSON string as a result. + * + * @param query The Rego query. + * + * @return Query results as a JSON string. + */ + public String evalQuery(String query) { + return nativeEvalQuery(enginePtr, query); } @Override public void close() { - destroyEngine(enginePtr); + nativeDestroyEngine(enginePtr); } - // Loading native library from jar is adapted from: + // Loading native library from JAR is adapted from: // https://github.com/apache/opendal/blob/93e5f65bbf30df2fed4bdd95bb0685c73c6418c2/bindings/java/src/main/java/org/apache/opendal/NativeLibrary.java // https://github.com/apache/opendal/blob/93e5f65bbf30df2fed4bdd95bb0685c73c6418c2/bindings/java/src/main/java/org/apache/opendal/Environment.java - private static final String classifier; static { - final StringBuilder classifierBuilder = new StringBuilder(); - final String os = System.getProperty("os.name").toLowerCase(); - if (os.startsWith("windows")) { - classifierBuilder.append("windows"); - } else if (os.startsWith("mac")) { - classifierBuilder.append("osx"); - } else { - classifierBuilder.append("linux"); - } - classifierBuilder.append("-"); + // Build a Rust target triple, like: 'aarch64-unknown-linux-gnu'. + final StringBuilder targetTripleBuilder = new StringBuilder(); + final String arch = System.getProperty("os.arch").toLowerCase(); if (arch.equals("aarch64")) { - classifierBuilder.append("aarch_64"); + targetTripleBuilder.append("aarch64"); } else { - classifierBuilder.append("x86_64"); + targetTripleBuilder.append("x86_64"); } - classifier = classifierBuilder.toString(); + targetTripleBuilder.append("-"); - loadNativeLibrary(); + final String os = System.getProperty("os.name").toLowerCase(); + if (os.startsWith("windows")) { + targetTripleBuilder.append("pc-windows-msvc"); + } else if (os.startsWith("mac")) { + targetTripleBuilder.append("apple-darwin"); + } else { + targetTripleBuilder.append("unknown-linux-gnu"); + } + + loadNativeLibrary(targetTripleBuilder.toString()); } - private static void loadNativeLibrary() { + private static void loadNativeLibrary(String targetTriple) { try { // try dynamic library - the search path can be configured via "-Djava.library.path" System.loadLibrary("regorus_java"); @@ -92,10 +178,14 @@ public class Engine implements AutoCloseable { // ignore - try from classpath } - final String libraryPath = bundledLibraryPath(); + // Native libraries will be bundles into JARs like: + // `aarch64-apple-darwin/libregorus_java.dylib` + final String libraryName = System.mapLibraryName("regorus_java"); + final String libraryPath = "/" + targetTriple + "/" + libraryName; + try (final InputStream is = Engine.class.getResourceAsStream(libraryPath)) { if (is == null) { - throw new RuntimeException("cannot find " + libraryPath); + throw new RuntimeException("Cannot find " + libraryPath + "\nSee https://github.com/microsoft/regorus/tree/main/bindings/java for help."); } final int dot = libraryPath.indexOf('.'); final File tmpFile = File.createTempFile(libraryPath.substring(0, dot), libraryPath.substring(dot)); @@ -106,9 +196,4 @@ public class Engine implements AutoCloseable { throw new RuntimeException(exception); } } - - private static String bundledLibraryPath() { - final String libraryName = System.mapLibraryName("regorus_java"); - return "/native/" + classifier + "/" + libraryName; - } } diff --git a/bindings/java/src/test/java/com/microsoft/regorus/EngineTest.java b/bindings/java/src/test/java/com/microsoft/regorus/EngineTest.java index 3807e5f..ae6f7dc 100644 --- a/bindings/java/src/test/java/com/microsoft/regorus/EngineTest.java +++ b/bindings/java/src/test/java/com/microsoft/regorus/EngineTest.java @@ -17,13 +17,13 @@ public class EngineTest extends TestCase { String resJson; try (Engine engine = new Engine()) { - engine.pubAddPolicy( + engine.addPolicy( "hello.rego", "package test\nmessage = concat(\", \", [input.message, data.message])" ); - engine.pubAddDataJson("{\"message\":\"World!\"}"); - engine.pubSetInputJson("{\"message\":\"Hello\"}"); - resJson = engine.pubEvalQuery("data.test.message"); + engine.addDataJson("{\"message\":\"World!\"}"); + engine.setInputJson("{\"message\":\"Hello\"}"); + resJson = engine.evalQuery("data.test.message"); } Gson gson = new Gson(); diff --git a/bindings/java/tools/build.py b/bindings/java/tools/build.py deleted file mode 100644 index 4d2eed1..0000000 --- a/bindings/java/tools/build.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) Microsoft Corporation. -# Licensed under the MIT License. -# -# This script adapted from: -# https://github.com/apache/opendal/blob/93e5f65bbf30df2fed4bdd95bb0685c73c6418c2/bindings/java/tools/build.py - -from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser -from pathlib import Path -import shutil -import subprocess - -def classifier_to_target(classifier: str) -> str: - if classifier == 'osx-aarch_64': - return 'aarch64-apple-darwin' - if classifier == 'osx-x86_64': - return 'x86_64-apple-darwin' - if classifier == 'linux-aarch_64': - return 'aarch64-unknown-linux-gnu' - if classifier == 'linux-x86_64': - return 'x86_64-unknown-linux-gnu' - if classifier == 'windows-x86_64': - return 'x86_64-pc-windows-msvc' - raise Exception(f'Unsupported classifier: {classifier}') - -def get_cargo_artifact_name(classifier: str) -> str: - if classifier.startswith('osx'): - return 'libregorus_java.dylib' - if classifier.startswith('linux'): - return 'libregorus_java.so' - if classifier.startswith('windows'): - return 'regorus_java.dll' - raise Exception(f'Unsupported classifier: {classifier}') - - -if __name__ == '__main__': - basedir = Path(__file__).parent.parent - - parser = ArgumentParser() - parser.add_argument('--classifier', type=str, required=True) - args = parser.parse_args() - - target = classifier_to_target(args.classifier) - - # Setup target. - command = ['rustup', 'target', 'add', target] - print('$ ' + subprocess.list2cmdline(command)) - subprocess.run(command, cwd=basedir, check=True) - - cmd = ['cargo', 'build', '--target', target] - - output = basedir / 'target' / 'bindings' - Path(output).mkdir(exist_ok=True, parents=True) - cmd += ['--target-dir', str(output)] - - print('$ ' + subprocess.list2cmdline(cmd)) - subprocess.run(cmd, cwd=basedir, check=True) - - # History reason of cargo profiles. - profile = 'debug' - artifact = get_cargo_artifact_name(args.classifier) - src = output / target / profile / artifact - dst = basedir / 'target' / 'classes' / 'native' / args.classifier / artifact - dst.parent.mkdir(exist_ok=True, parents=True) - shutil.copy2(src, dst) diff --git a/bindings/java/tools/testbuild.py b/bindings/java/tools/testbuild.py new file mode 100644 index 0000000..088a3c8 --- /dev/null +++ b/bindings/java/tools/testbuild.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# +# Builds Regorus Java to use in Java tests. See `pom.xml`. + +from pathlib import Path +import subprocess + +if __name__ == "__main__": + basedir = Path(__file__).parent.parent + + output = basedir / "target" + Path(output).mkdir(exist_ok=True, parents=True) + cmd = ["cargo", "build", "--target-dir", str(output)] + print("$ " + subprocess.list2cmdline(cmd)) + subprocess.run(cmd, cwd=basedir, check=True)