Java publishing (#151)

* bindings/java: Add prefix to native methods

* bindings/java: Add javadocs and missing methods to Engine

* Setup publishing uber-JAR via GitHub workflow

* bindings/java: Update README

* bindings/java: Improve native library loading from JAR

* bindings/java: Fix usage of `working-directory`

* bindings/java: Pass required `distribution` parameter to `actions/setup-java@v4`

* bindings/java: Use Corretto distribution

This is because Microsoft doesn't provide JDK8,
see https://learn.microsoft.com/en-us/java/openjdk/download#openjdk-8.

* bindings/java: Install GCC toolchain for `aarch64-unknown-linux-gnu`

* bindings/java: Upload artifacts with different names from each step

* bindings/java: Upload built JARs to GitHub
This commit is contained in:
Burak
2024-02-23 00:00:07 +01:00
committed by GitHub
parent 3a86c83827
commit 22047287b4
9 changed files with 460 additions and 287 deletions

87
.github/workflows/publish-java.yml vendored Normal file
View File

@@ -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 }}

View File

@@ -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
<dependencies>
<dependency>
<groupId>com.microsoft.regorus</groupId>
<artifactId>regorus-java</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>
```
## 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}}]}]}
```
```
## 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
```

View File

@@ -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

View File

@@ -4,8 +4,7 @@
Licensed under the MIT License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.microsoft.regorus</groupId>
@@ -16,12 +15,27 @@
<description>Java bindings for Regorus - a fast, lightweight Rego interpreter written in Rust</description>
<url>https://github.com/microsoft/regorus/bindings/java</url>
<licenses>
<license>
<name>MIT License</name>
<url>https://opensource.org/blog/license/mit</url>
</license>
</licenses>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<distributionManagement>
<repository>
<id>ossrh</id>
<name>Central Repository OSSRH</name>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
@@ -38,114 +52,80 @@
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
<resources>
<resource>
<!--
Include native/ folder in built JAR.
During CI build we build native libraries for various platforms
and put them into native/ folder.
See `.github/publish-java.yml`.
-->
<directory>${project.basedir}/native</directory>
</resource>
</resources>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.7.0</version>
</extension>
</extensions>
<!-- Adapted from https://github.com/apache/opendal/blob/93e5f65bbf30df2fed4bdd95bb0685c73c6418c2/bindings/java/pom.xml -->
<plugins>
<plugin>
<artifactId>exec-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<version>3.1.0</version>
<executions>
<execution>
<id>compile-native-code</id>
<phase>compile</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>python3</executable>
<arguments>
<argument>${project.basedir}/tools/build.py</argument>
<argument>--classifier</argument>
<argument>${os.detected.classifier}</argument>
</arguments>
</configuration>
</execution>
</executions>
<artifactId>exec-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<version>3.1.0</version>
<executions>
<execution>
<!-- Build a debug release for tests -->
<id>build-native-lib-for-test</id>
<phase>test-compile</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>python3</executable>
<arguments>
<argument>${project.basedir}/tools/testbuild.py</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<!-- Add debug build to Java path, so it's discoverable by JVM. This is only for tests. -->
<argLine>-Djava.library.path=${project.basedir}/target/debug:${java.library.path}</argLine>
</configuration>
</plugin>
<!-- Build javadoc JAR, this is required by Maven Central. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<!-- Generate the fallback JAR that does not contain the native library. -->
<execution>
<id>default-jar</id>
<configuration>
<excludes>
<exclude>native/**</exclude>
</excludes>
</configuration>
</execution>
<!-- Generate the JAR that contains the native library in it. -->
<execution>
<id>native-jar</id>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>${os.detected.classifier}</classifier>
<includes>
<include>native/**</include>
</includes>
</configuration>
</execution>
</executions>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.3</version>
<executions>
<execution>
<id>attach-javadoc</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<!-- Build sources JAR, this is required by Maven Central. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>

View File

@@ -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,

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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)

View File

@@ -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)