diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 39e3832b..dd30cfe1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -55,11 +55,9 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- with:
- gradle-version: 8.12.1
- name: Gradle Test
- run: gradle jvmTest --info
+ run: ./gradlew jvmTest --info
markdown_lint:
runs-on: ubuntu-latest
diff --git a/.github/workflows/publish-android.yml b/.github/workflows/publish-android.yml
index 77f9f611..380e5444 100644
--- a/.github/workflows/publish-android.yml
+++ b/.github/workflows/publish-android.yml
@@ -58,12 +58,6 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- with:
- gradle-version: 8.12.1
-
- - name: Gradle Wrapper
- run: |
- gradle wrapper
- name: Set pub mode env var
# Note: This step is intended to allow publishing snapshot packages.
diff --git a/.github/workflows/publish-dokka.yml b/.github/workflows/publish-dokka.yml
index b5fe106d..4964557b 100644
--- a/.github/workflows/publish-dokka.yml
+++ b/.github/workflows/publish-dokka.yml
@@ -27,15 +27,9 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- with:
- gradle-version: 8.12.1
-
- - name: Gradle Wrapper
- run: |
- gradle wrapper
- name: Build doc
- run: gradle dokkaGenerate
+ run: ./gradlew dokkaGenerate
- name: Deploy doc
if: ${{ inputs.live-run || false }}
diff --git a/.github/workflows/publish-jvm.yml b/.github/workflows/publish-jvm.yml
index 7caf1b48..ce0ba5e6 100644
--- a/.github/workflows/publish-jvm.yml
+++ b/.github/workflows/publish-jvm.yml
@@ -163,12 +163,6 @@ jobs:
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
- with:
- gradle-version: 8.12.1
-
- - name: Gradle Wrapper
- run: |
- gradle wrapper
- name: Set pub mode env var
# Note: This step is intended to allow publishing snapshot packages.
diff --git a/README.md b/README.md
index affbaa42..1c214a6d 100644
--- a/README.md
+++ b/README.md
@@ -114,12 +114,17 @@ Basically:
- Rust ([Installation guide](https://doc.rust-lang.org/cargo/getting-started/installation.html))
- Kotlin ([Installation guide](https://kotlinlang.org/docs/getting-started.html#backend))
-- Gradle ([Installation guide](https://gradle.org/install/))
and in case of targeting Android you'll also need:
- Android SDK ([Installation guide](https://developer.android.com/about/versions/11/setup-sdk))
+## Gradle wrapper
+
+This repository ships a [Gradle wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html) (`./gradlew` / `gradlew.bat`), so no system-wide Gradle installation is required. The wrapper pins the build to **Gradle 8.12.1** and verifies the distribution checksum before use, ensuring a reproducible and tamper-evident build environment.
+
+Use `./gradlew` in place of `gradle` for all commands listed below.
+
##
JVM
To publish a library for a JVM project into Maven local, run
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..a4b76b95
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..63532c5e
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,8 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
+distributionSha256Sum=8d97a97984f6cbd2b85fe4c60a743440a347544bf18818048e611f5288d46c94
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 00000000..057afac5
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,251 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 00000000..640d6868
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,94 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 2d17a6a4..776fcd77 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -22,6 +22,7 @@ pluginManagement {
rootProject.name = "zenoh-java"
include(":zenoh-java")
+include(":zenoh-jni-runtime")
include(":examples")
include(":zenoh-jni")
diff --git a/zenoh-java/build.gradle.kts b/zenoh-java/build.gradle.kts
index 123d7499..dfb36284 100644
--- a/zenoh-java/build.gradle.kts
+++ b/zenoh-java/build.gradle.kts
@@ -12,8 +12,6 @@
// ZettaScale Zenoh Team,
//
-import com.nishtahir.CargoExtension
-
plugins {
kotlin("multiplatform")
kotlin("plugin.serialization")
@@ -30,13 +28,11 @@ val release = project.findProperty("release")?.toString()?.toBoolean() == true
// Modifying this property will affect the release workflows!
val isRemotePublication = project.findProperty("remotePublication")?.toString()?.toBoolean() == true
-var buildMode = if (release) BuildMode.RELEASE else BuildMode.DEBUG
+var buildMode = if (release) "release" else "debug"
if (androidEnabled) {
apply(plugin = "com.android.library")
- apply(plugin = "org.mozilla.rust-android-gradle.rust-android")
- configureCargo()
configureAndroid()
}
@@ -66,34 +62,35 @@ kotlin {
sourceSets {
val commonMain by getting {
dependencies {
+ api(project(":zenoh-jni-runtime"))
implementation("commons-net:commons-net:3.9.0")
implementation("com.google.guava:guava:33.3.1-jre")
}
}
+ // jvmAndAndroidMain is an intermediate source set between commonMain and both jvmMain/androidMain.
+ // ZSerializer and ZDeserializer use java.lang.reflect.Type (via Guava's TypeToken) —
+ // available on JVM and Android (ART), but absent on Kotlin/Native and Kotlin/JS targets.
+ // Placing them here (rather than commonMain) ensures those targets can be added in the
+ // future without compilation errors.
+ // Note: named jvmAndAndroidMain (not javaMain) to avoid conflicting with the DokkaSourceSetSpec
+ // that Dokka auto-registers for the Java compilation created by withJava().
+ val jvmAndAndroidMain by creating { dependsOn(commonMain) }
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}
if (androidEnabled) {
+ val androidMain by getting { dependsOn(jvmAndAndroidMain) }
val androidUnitTest by getting {
dependencies {
implementation(kotlin("test-junit"))
}
}
}
- val jvmMain by getting {
- if (isRemotePublication) {
- // The line below is intended to load the native libraries that are crosscompiled on GitHub actions when publishing a JVM package.
- resources.srcDir("../jni-libs").include("*/**")
- } else {
- resources.srcDir("../zenoh-jni/target/$buildMode").include(arrayListOf("*.dylib", "*.so", "*.dll"))
- }
- }
+ val jvmMain by getting { dependsOn(jvmAndAndroidMain) }
- val jvmTest by getting {
- resources.srcDir("../zenoh-jni/target/$buildMode").include(arrayListOf("*.dylib", "*.so", "*.dll"))
- }
+ val jvmTest by getting {}
}
val javadocJar by tasks.registering(Jar::class) {
@@ -161,55 +158,8 @@ tasks.withType {
}
}
-tasks.whenObjectAdded {
- if ((this.name == "mergeDebugJniLibFolders" || this.name == "mergeReleaseJniLibFolders")) {
- this.dependsOn("cargoBuild")
- }
-}
-
tasks.named("compileKotlinJvm") {
- dependsOn("buildZenohJni")
-}
-
-tasks.register("buildZenohJni") {
- doLast {
- if (!isRemotePublication) {
- // This is intended for local publications. For publications done through GitHub workflows,
- // the zenoh-jni build is achieved and loaded differently from the CI
- buildZenohJNI(buildMode)
- }
- }
-}
-
-fun buildZenohJNI(mode: BuildMode = BuildMode.DEBUG) {
- val cargoCommand = mutableListOf("cargo", "build")
-
- if (mode == BuildMode.RELEASE) {
- cargoCommand.add("--release")
- }
-
- val result = project.exec {
- commandLine(*(cargoCommand.toTypedArray()), "--manifest-path", "../zenoh-jni/Cargo.toml")
- }
-
- if (result.exitValue != 0) {
- throw GradleException("Failed to build Zenoh-JNI.")
- }
-
- Thread.sleep(1000)
-}
-
-enum class BuildMode {
- DEBUG {
- override fun toString(): String {
- return "debug"
- }
- },
- RELEASE {
- override fun toString(): String {
- return "release"
- }
- }
+ dependsOn(":zenoh-jni-runtime:buildZenohJni")
}
fun Project.configureAndroid() {
@@ -249,20 +199,3 @@ fun Project.configureAndroid() {
}
}
}
-
-fun Project.configureCargo() {
- extensions.configure("cargo") {
- pythonCommand = "python3"
- module = "../zenoh-jni"
- libname = "zenoh-jni"
- targetIncludes = arrayOf("libzenoh_jni.so")
- targetDirectory = "../zenoh-jni/target/"
- profile = "release"
- targets = arrayListOf(
- "arm",
- "arm64",
- "x86",
- "x86_64",
- )
- }
-}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt
index 91bc0e01..a2a334cc 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt
+++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt
@@ -46,7 +46,7 @@ class Config internal constructor(internal val jniConfig: JNIConfig) {
*/
@JvmStatic
fun loadDefault(): Config {
- return JNIConfig.loadDefaultConfig()
+ return Config(JNIConfig.loadDefault())
}
/**
@@ -59,7 +59,7 @@ class Config internal constructor(internal val jniConfig: JNIConfig) {
@JvmStatic
@Throws(ZError::class)
fun fromFile(file: File): Config {
- return JNIConfig.loadConfigFile(file)
+ return Config(JNIConfig.loadFromFile(file.toString()))
}
/**
@@ -72,7 +72,7 @@ class Config internal constructor(internal val jniConfig: JNIConfig) {
@JvmStatic
@Throws(ZError::class)
fun fromFile(path: Path): Config {
- return JNIConfig.loadConfigFile(path)
+ return Config(JNIConfig.loadFromFile(path.toString()))
}
/**
@@ -87,7 +87,7 @@ class Config internal constructor(internal val jniConfig: JNIConfig) {
@JvmStatic
@Throws(ZError::class)
fun fromJson(config: String): Config {
- return JNIConfig.loadJsonConfig(config)
+ return Config(JNIConfig.loadFromJson(config))
}
/**
@@ -102,7 +102,7 @@ class Config internal constructor(internal val jniConfig: JNIConfig) {
@JvmStatic
@Throws(ZError::class)
fun fromJson5(config: String): Config {
- return JNIConfig.loadJson5Config(config)
+ return Config(JNIConfig.loadFromJson(config))
}
/**
@@ -117,7 +117,7 @@ class Config internal constructor(internal val jniConfig: JNIConfig) {
@JvmStatic
@Throws(ZError::class)
fun fromYaml(config: String): Config {
- return JNIConfig.loadYamlConfig(config)
+ return Config(JNIConfig.loadFromYaml(config))
}
/**
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt
index eba6681c..1b6101bf 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt
+++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt
@@ -15,6 +15,7 @@
package io.zenoh
import io.zenoh.exceptions.ZError
+import io.zenoh.jni.JNILogger
/** Logger class to redirect the Rust logs from Zenoh to the kotlin environment. */
internal class Logger {
@@ -23,11 +24,6 @@ internal class Logger {
internal const val LOG_ENV: String = "RUST_LOG"
- @Throws(ZError::class)
- fun start(filter: String) {
- startLogsViaJNI(filter)
- }
-
/**
* Redirects the rust logs either to logcat for Android systems or to the standard output (for non-android
* systems).
@@ -35,6 +31,6 @@ internal class Logger {
* See https://docs.rs/env_logger/latest/env_logger/index.html for accepted filter format.
*/
@Throws(ZError::class)
- private external fun startLogsViaJNI(filter: String)
+ fun start(filter: String) = JNILogger.startLogs(filter)
}
}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt
index d3b125f9..e60e6b4f 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt
+++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt
@@ -15,23 +15,40 @@
package io.zenoh
import io.zenoh.annotations.Unstable
+import io.zenoh.bytes.Encoding
import io.zenoh.bytes.IntoZBytes
import io.zenoh.bytes.ZBytes
+import io.zenoh.bytes.into
+import io.zenoh.config.EntityGlobalId
import io.zenoh.config.ZenohId
import io.zenoh.exceptions.ZError
import io.zenoh.handlers.BlockingQueueHandler
import io.zenoh.handlers.Callback
import io.zenoh.handlers.Handler
+import io.zenoh.jni.JNIKeyExpr
+import io.zenoh.jni.JNIPublisher
+import io.zenoh.jni.JNIQuery
+import io.zenoh.jni.JNIQuerier
+import io.zenoh.jni.JNIQueryable
import io.zenoh.jni.JNISession
+import io.zenoh.jni.JNISubscriber
+import io.zenoh.jni.callbacks.JNIGetCallback
+import io.zenoh.jni.callbacks.JNIQueryableCallback
+import io.zenoh.jni.callbacks.JNISubscriberCallback
import io.zenoh.keyexpr.KeyExpr
import io.zenoh.liveliness.Liveliness
import io.zenoh.pubsub.*
+import io.zenoh.qos.CongestionControl
+import io.zenoh.qos.Priority
+import io.zenoh.qos.QoS
import io.zenoh.query.*
import io.zenoh.query.Query
import io.zenoh.query.Queryable
import io.zenoh.sample.Sample
+import io.zenoh.sample.SampleKind
import io.zenoh.session.SessionDeclaration
import io.zenoh.session.SessionInfo
+import org.apache.commons.net.ntp.TimeStamp
import java.lang.ref.WeakReference
import java.util.*
import java.util.concurrent.BlockingQueue
@@ -383,9 +400,9 @@ class Session private constructor(private val config: Config) : AutoCloseable {
@Throws(ZError::class)
fun declareKeyExpr(keyExpr: String): KeyExpr {
return jniSession?.run {
- val keyexpr = declareKeyExpr(keyExpr)
- strongDeclarations.add(keyexpr)
- keyexpr
+ val ke = KeyExpr(keyExpr, declareKeyExpr(keyExpr))
+ strongDeclarations.add(ke)
+ ke
} ?: throw sessionClosedException
}
@@ -400,8 +417,11 @@ class Session private constructor(private val config: Config) : AutoCloseable {
*/
@Throws(ZError::class)
fun undeclare(keyExpr: KeyExpr) {
- return jniSession?.run {
- undeclareKeyExpr(keyExpr)
+ jniSession?.run {
+ keyExpr.jniKeyExpr?.run {
+ undeclareKeyExpr(this)
+ keyExpr.jniKeyExpr = null
+ } ?: throw ZError("Attempting to undeclare a non declared key expression.")
} ?: throw (sessionClosedException)
}
@@ -576,7 +596,20 @@ class Session private constructor(private val config: Config) : AutoCloseable {
@Throws(ZError::class)
internal fun resolvePublisher(keyExpr: KeyExpr, options: PublisherOptions): Publisher {
return jniSession?.run {
- val publisher = declarePublisher(keyExpr, options)
+ val publisher = Publisher(
+ keyExpr,
+ options.congestionControl,
+ options.priority,
+ options.encoding,
+ declarePublisher(
+ keyExpr.jniKeyExpr,
+ keyExpr.keyExpr,
+ options.congestionControl.value,
+ options.priority.value,
+ options.express,
+ options.reliability.ordinal
+ )
+ )
weakDeclarations.add(WeakReference(publisher))
publisher
} ?: throw (sessionClosedException)
@@ -587,7 +620,22 @@ class Session private constructor(private val config: Config) : AutoCloseable {
keyExpr: KeyExpr, handler: Handler
): HandlerSubscriber {
return jniSession?.run {
- val subscriber = declareSubscriberWithHandler(keyExpr, handler)
+ val subCallback =
+ JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express, priority, congestionControl ->
+ val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
+ handler.handle(
+ Sample(
+ KeyExpr(keyExpr1, null),
+ payload.into(),
+ Encoding(encodingId, schema = encodingSchema),
+ SampleKind.fromInt(kind),
+ timestamp,
+ QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
+ attachmentBytes?.into()
+ )
+ )
+ }
+ val subscriber = HandlerSubscriber(keyExpr, declareSubscriber(keyExpr.jniKeyExpr, keyExpr.keyExpr, subCallback, handler::onClose), handler.receiver())
strongDeclarations.add(subscriber)
subscriber
} ?: throw (sessionClosedException)
@@ -598,7 +646,22 @@ class Session private constructor(private val config: Config) : AutoCloseable {
keyExpr: KeyExpr, callback: Callback
): CallbackSubscriber {
return jniSession?.run {
- val subscriber = declareSubscriberWithCallback(keyExpr, callback)
+ val subCallback =
+ JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express, priority, congestionControl ->
+ val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
+ callback.run(
+ Sample(
+ KeyExpr(keyExpr1, null),
+ payload.into(),
+ Encoding(encodingId, schema = encodingSchema),
+ SampleKind.fromInt(kind),
+ timestamp,
+ QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
+ attachmentBytes?.into()
+ )
+ )
+ }
+ val subscriber = CallbackSubscriber(keyExpr, declareSubscriber(keyExpr.jniKeyExpr, keyExpr.keyExpr, subCallback, fun() {}))
strongDeclarations.add(subscriber)
subscriber
} ?: throw (sessionClosedException)
@@ -609,7 +672,24 @@ class Session private constructor(private val config: Config) : AutoCloseable {
keyExpr: KeyExpr, handler: Handler, options: QueryableOptions
): HandlerQueryable {
return jniSession?.run {
- val queryable = declareQueryableWithHandler(keyExpr, handler, options)
+ val queryCallback =
+ JNIQueryableCallback { keyExpr1, selectorParams, payload, encodingId, encodingSchema, attachmentBytes, queryPtr, acceptReplies ->
+ val jniQuery = JNIQuery(queryPtr)
+ val keyExpr2 = KeyExpr(keyExpr1, null)
+ val selector = if (selectorParams.isEmpty()) Selector(keyExpr2) else Selector(keyExpr2, Parameters.from(selectorParams))
+ handler.handle(
+ Query(
+ keyExpr2,
+ selector,
+ payload?.into(),
+ payload?.let { Encoding(encodingId, schema = encodingSchema) },
+ attachmentBytes?.into(),
+ ReplyKeyExpr.entries[acceptReplies],
+ jniQuery
+ )
+ )
+ }
+ val queryable = HandlerQueryable(keyExpr, declareQueryable(keyExpr.jniKeyExpr, keyExpr.keyExpr, queryCallback, handler::onClose, options.complete), handler.receiver())
strongDeclarations.add(queryable)
queryable
} ?: throw (sessionClosedException)
@@ -620,18 +700,50 @@ class Session private constructor(private val config: Config) : AutoCloseable {
keyExpr: KeyExpr, callback: Callback, options: QueryableOptions
): CallbackQueryable {
return jniSession?.run {
- val queryable = declareQueryableWithCallback(keyExpr, callback, options)
+ val queryCallback =
+ JNIQueryableCallback { keyExpr1, selectorParams, payload, encodingId, encodingSchema, attachmentBytes, queryPtr, acceptReplies ->
+ val jniQuery = JNIQuery(queryPtr)
+ val keyExpr2 = KeyExpr(keyExpr1, null)
+ val selector = if (selectorParams.isEmpty()) Selector(keyExpr2) else Selector(keyExpr2, Parameters.from(selectorParams))
+ callback.run(
+ Query(
+ keyExpr2,
+ selector,
+ payload?.into(),
+ payload?.let { Encoding(encodingId, schema = encodingSchema) },
+ attachmentBytes?.into(),
+ ReplyKeyExpr.entries[acceptReplies],
+ jniQuery
+ )
+ )
+ }
+ val queryable = CallbackQueryable(keyExpr, declareQueryable(keyExpr.jniKeyExpr, keyExpr.keyExpr, queryCallback, fun() {}, options.complete))
strongDeclarations.add(queryable)
queryable
} ?: throw (sessionClosedException)
}
+ @OptIn(Unstable::class)
private fun resolveQuerier(
keyExpr: KeyExpr,
options: QuerierOptions
): Querier {
return jniSession?.run {
- val querier = declareQuerier(keyExpr, options)
+ val querier = Querier(
+ keyExpr,
+ QoS(congestionControl = options.congestionControl, priority = options.priority, express = options.express),
+ declareQuerier(
+ keyExpr.jniKeyExpr,
+ keyExpr.keyExpr,
+ options.target.ordinal,
+ options.consolidationMode.ordinal,
+ options.congestionControl.value,
+ options.priority.value,
+ options.express,
+ options.timeout.toMillis(),
+ options.acceptReplies.ordinal
+ )
+ )
weakDeclarations.add(WeakReference(querier))
querier
} ?: throw sessionClosedException
@@ -643,11 +755,48 @@ class Session private constructor(private val config: Config) : AutoCloseable {
handler: Handler,
options: GetOptions
): R {
- return jniSession?.performGetWithHandler(
- selector,
- handler,
- options
- ) ?: throw sessionClosedException
+ return jniSession?.run {
+ val getCallback = JNIGetCallback { replierZid, replierEid, success, keyExpr, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express, priority, congestionControl ->
+ val reply: Reply = if (success) {
+ val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
+ Reply.Success(
+ replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) },
+ Sample(
+ KeyExpr(keyExpr!!, null),
+ payload.into(),
+ Encoding(encodingId, schema = encodingSchema),
+ SampleKind.fromInt(kind),
+ timestamp,
+ QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
+ attachmentBytes?.into()
+ )
+ )
+ } else {
+ Reply.Error(replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, payload.into(), Encoding(encodingId, schema = encodingSchema))
+ }
+ handler.handle(reply)
+ }
+ val sel = selector.into()
+ get(
+ sel.keyExpr.jniKeyExpr,
+ sel.keyExpr.keyExpr,
+ sel.parameters?.toString(),
+ getCallback,
+ handler::onClose,
+ options.timeout.toMillis(),
+ options.target.ordinal,
+ options.consolidation.ordinal,
+ options.attachment?.into()?.bytes,
+ options.payload?.into()?.bytes,
+ options.encoding?.id ?: Encoding.defaultEncoding().id,
+ options.encoding?.schema,
+ options.qos.congestionControl.value,
+ options.qos.priority.value,
+ options.qos.express,
+ options.acceptReplies.ordinal
+ )
+ handler.receiver()
+ } ?: throw sessionClosedException
}
@Throws(ZError::class)
@@ -656,42 +805,102 @@ class Session private constructor(private val config: Config) : AutoCloseable {
callback: Callback,
options: GetOptions
) {
- return jniSession?.performGetWithCallback(
- selector,
- callback,
- options
- ) ?: throw sessionClosedException
+ jniSession?.run {
+ val getCallback = JNIGetCallback { replierZid, replierEid, success, keyExpr, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express, priority, congestionControl ->
+ val reply: Reply = if (success) {
+ val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
+ Reply.Success(
+ replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) },
+ Sample(
+ KeyExpr(keyExpr!!, null),
+ payload.into(),
+ Encoding(encodingId, schema = encodingSchema),
+ SampleKind.fromInt(kind),
+ timestamp,
+ QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
+ attachmentBytes?.into()
+ )
+ )
+ } else {
+ Reply.Error(replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, payload.into(), Encoding(encodingId, schema = encodingSchema))
+ }
+ callback.run(reply)
+ }
+ val sel = selector.into()
+ get(
+ sel.keyExpr.jniKeyExpr,
+ sel.keyExpr.keyExpr,
+ sel.parameters?.toString(),
+ getCallback,
+ fun() {},
+ options.timeout.toMillis(),
+ options.target.ordinal,
+ options.consolidation.ordinal,
+ options.attachment?.into()?.bytes,
+ options.payload?.into()?.bytes,
+ options.encoding?.id ?: Encoding.defaultEncoding().id,
+ options.encoding?.schema,
+ options.qos.congestionControl.value,
+ options.qos.priority.value,
+ options.qos.express,
+ options.acceptReplies.ordinal
+ )
+ } ?: throw sessionClosedException
}
@Throws(ZError::class)
internal fun resolvePut(keyExpr: KeyExpr, payload: IntoZBytes, putOptions: PutOptions) {
- jniSession?.run { performPut(keyExpr, payload, putOptions) }
+ jniSession?.run {
+ val encoding = putOptions.encoding ?: Encoding.defaultEncoding()
+ put(
+ keyExpr.jniKeyExpr,
+ keyExpr.keyExpr,
+ payload.into().bytes,
+ encoding.id,
+ encoding.schema,
+ putOptions.congestionControl.value,
+ putOptions.priority.value,
+ putOptions.express,
+ putOptions.attachment?.into()?.bytes,
+ putOptions.reliability.ordinal
+ )
+ }
}
@Throws(ZError::class)
internal fun resolveDelete(keyExpr: KeyExpr, deleteOptions: DeleteOptions) {
- jniSession?.run { performDelete(keyExpr, deleteOptions) }
+ jniSession?.run {
+ delete(
+ keyExpr.jniKeyExpr,
+ keyExpr.keyExpr,
+ deleteOptions.congestionControl.value,
+ deleteOptions.priority.value,
+ deleteOptions.express,
+ deleteOptions.attachment?.into()?.bytes,
+ deleteOptions.reliability.ordinal
+ )
+ }
}
@Throws(ZError::class)
internal fun zid(): ZenohId {
- return jniSession?.zid() ?: throw sessionClosedException
+ return jniSession?.run { ZenohId(getZid()) } ?: throw sessionClosedException
}
@Throws(ZError::class)
internal fun getPeersId(): List {
- return jniSession?.peersZid() ?: throw sessionClosedException
+ return jniSession?.run { getPeersZid().map { ZenohId(it) } } ?: throw sessionClosedException
}
@Throws(ZError::class)
internal fun getRoutersId(): List {
- return jniSession?.routersZid() ?: throw sessionClosedException
+ return jniSession?.run { getRoutersZid().map { ZenohId(it) } } ?: throw sessionClosedException
}
/** Launches the session through the jni session, returning the [Session] on success. */
@Throws(ZError::class)
private fun launch(): Session {
- this.jniSession = JNISession.open(config)
+ this.jniSession = JNISession.open(config.jniConfig)
return this
}
}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt
index 7a5931f8..e0c60c6c 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt
+++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt
@@ -15,11 +15,14 @@
package io.zenoh
import io.zenoh.Logger.Companion.LOG_ENV
+import io.zenoh.config.WhatAmI
+import io.zenoh.config.ZenohId
import io.zenoh.exceptions.ZError
import io.zenoh.handlers.BlockingQueueHandler
import io.zenoh.handlers.Callback
import io.zenoh.handlers.Handler
import io.zenoh.jni.JNIScout
+import io.zenoh.jni.callbacks.JNIScoutCallback
import io.zenoh.scouting.*
import java.util.*
import java.util.concurrent.BlockingQueue
@@ -53,10 +56,11 @@ object Zenoh {
@Throws(ZError::class)
fun scout(scoutOptions: ScoutOptions = ScoutOptions()): HandlerScout>> {
val handler = BlockingQueueHandler(LinkedBlockingDeque>())
- return JNIScout.scoutWithHandler(
- scoutOptions.whatAmI, handler::handle, fun() { handler.onClose() },
- receiver = handler.receiver(), config = scoutOptions.config
- )
+ val scoutCallback = JNIScoutCallback { whatAmI, id, locators ->
+ handler.handle(Hello(WhatAmI.fromInt(whatAmI), ZenohId(id), locators))
+ }
+ val binaryWhatAmI = scoutOptions.whatAmI.map { it.value }.reduce { acc, it -> acc or it }
+ return HandlerScout(JNIScout.scout(binaryWhatAmI, scoutCallback, handler::onClose, scoutOptions.config?.jniConfig), handler.receiver())
}
/**
@@ -74,10 +78,11 @@ object Zenoh {
@JvmStatic
@Throws(ZError::class)
fun scout(handler: Handler, scoutOptions: ScoutOptions = ScoutOptions()): HandlerScout {
- return JNIScout.scoutWithHandler(
- scoutOptions.whatAmI, handler::handle, fun() { handler.onClose() },
- receiver = handler.receiver(), config = scoutOptions.config
- )
+ val scoutCallback = JNIScoutCallback { whatAmI, id, locators ->
+ handler.handle(Hello(WhatAmI.fromInt(whatAmI), ZenohId(id), locators))
+ }
+ val binaryWhatAmI = scoutOptions.whatAmI.map { it.value }.reduce { acc, it -> acc or it }
+ return HandlerScout(JNIScout.scout(binaryWhatAmI, scoutCallback, handler::onClose, scoutOptions.config?.jniConfig), handler.receiver())
}
/**
@@ -94,9 +99,11 @@ object Zenoh {
@JvmStatic
@Throws(ZError::class)
fun scout(callback: Callback, scoutOptions: ScoutOptions = ScoutOptions()): CallbackScout {
- return JNIScout.scoutWithCallback(
- scoutOptions.whatAmI, callback, config = scoutOptions.config
- )
+ val scoutCallback = JNIScoutCallback { whatAmI, id, locators ->
+ callback.run(Hello(WhatAmI.fromInt(whatAmI), ZenohId(id), locators))
+ }
+ val binaryWhatAmI = scoutOptions.whatAmI.map { it.value }.reduce { acc, it -> acc or it }
+ return CallbackScout(JNIScout.scout(binaryWhatAmI, scoutCallback, fun() {}, scoutOptions.config?.jniConfig))
}
/**
@@ -136,9 +143,3 @@ object Zenoh {
logLevelProp?.let { Logger.start(it) } ?: Logger.start(fallbackFilter)
}
}
-
-/**
- * Static singleton class to load the Zenoh native library once and only once, as well as the logger in function of the
- * log level configuration.
- */
-internal expect object ZenohLoad
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/config/ZenohId.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/config/ZenohId.kt
index 9787fced..53304190 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/config/ZenohId.kt
+++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/config/ZenohId.kt
@@ -23,7 +23,7 @@ import kotlin.math.absoluteValue
data class ZenohId internal constructor(internal val bytes: ByteArray) {
override fun toString(): String {
- return JNIZenohId.toStringViaJNI(bytes)
+ return JNIZenohId.toString(bytes)
}
override fun equals(other: Any?): Boolean {
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILiveliness.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILiveliness.kt
deleted file mode 100644
index 0225c32b..00000000
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILiveliness.kt
+++ /dev/null
@@ -1,188 +0,0 @@
-//
-// Copyright (c) 2023 ZettaScale Technology
-//
-// This program and the accompanying materials are made available under the
-// terms of the Eclipse Public License 2.0 which is available at
-// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
-// which is available at https://www.apache.org/licenses/LICENSE-2.0.
-//
-// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
-//
-// Contributors:
-// ZettaScale Zenoh Team,
-//
-
-package io.zenoh.jni
-
-import io.zenoh.bytes.Encoding
-import io.zenoh.bytes.into
-import io.zenoh.config.EntityGlobalId
-import io.zenoh.config.ZenohId
-import io.zenoh.exceptions.ZError
-import io.zenoh.handlers.Callback
-import io.zenoh.jni.callbacks.JNIGetCallback
-import io.zenoh.jni.callbacks.JNIOnCloseCallback
-import io.zenoh.jni.callbacks.JNISubscriberCallback
-import io.zenoh.keyexpr.KeyExpr
-import io.zenoh.liveliness.LivelinessToken
-import io.zenoh.pubsub.CallbackSubscriber
-import io.zenoh.pubsub.HandlerSubscriber
-import io.zenoh.qos.CongestionControl
-import io.zenoh.qos.Priority
-import io.zenoh.qos.QoS
-import io.zenoh.query.Reply
-import io.zenoh.sample.Sample
-import io.zenoh.sample.SampleKind
-import org.apache.commons.net.ntp.TimeStamp
-import java.time.Duration
-
-internal object JNILiveliness {
-
- @Throws(ZError::class)
- fun get(
- jniSession: JNISession,
- keyExpr: KeyExpr,
- callback: Callback,
- receiver: R,
- timeout: Duration,
- onClose: Runnable
- ): R {
- val getCallback = JNIGetCallback {
- replierZid: ByteArray?,
- replierEid: Int,
- success: Boolean,
- keyExpr2: String?,
- payload: ByteArray,
- encodingId: Int,
- encodingSchema: String?,
- kind: Int,
- timestampNTP64: Long,
- timestampIsValid: Boolean,
- attachmentBytes: ByteArray?,
- express: Boolean,
- priority: Int,
- congestionControl: Int,
- ->
- val reply: Reply
- if (success) {
- val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
- val sample = Sample(
- KeyExpr(keyExpr2!!, null),
- payload.into(),
- Encoding(encodingId, schema = encodingSchema),
- SampleKind.fromInt(kind),
- timestamp,
- QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
- attachmentBytes?.into()
- )
- reply = Reply.Success(replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, sample)
- } else {
- reply = Reply.Error(
- replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) },
- payload.into(),
- Encoding(encodingId, schema = encodingSchema)
- )
- }
- callback.run(reply)
- }
- getViaJNI(
- jniSession.sessionPtr,
- keyExpr.jniKeyExpr?.ptr ?: 0,
- keyExpr.keyExpr,
- getCallback,
- timeout.toMillis(),
- onClose::run
- )
- return receiver
- }
-
- fun declareToken(jniSession: JNISession, keyExpr: KeyExpr): LivelinessToken {
- val ptr = declareTokenViaJNI(jniSession.sessionPtr, keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr)
- return LivelinessToken(JNILivelinessToken(ptr))
- }
-
- fun declareSubscriber(
- jniSession: JNISession,
- keyExpr: KeyExpr,
- callback: Callback,
- history: Boolean,
- onClose: () -> Unit
- ): CallbackSubscriber {
- val subCallback =
- JNISubscriberCallback { keyExpr2, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int ->
- val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
- val sample = Sample(
- KeyExpr(keyExpr2, null),
- payload.into(),
- Encoding(encodingId, schema = encodingSchema),
- SampleKind.fromInt(kind),
- timestamp,
- QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
- attachmentBytes?.into()
- )
- callback.run(sample)
- }
- val ptr = declareSubscriberViaJNI(
- jniSession.sessionPtr,
- keyExpr.jniKeyExpr?.ptr ?: 0,
- keyExpr.keyExpr,
- subCallback,
- history,
- onClose
- )
- return CallbackSubscriber(keyExpr, JNISubscriber(ptr))
- }
-
- fun declareSubscriber(
- jniSession: JNISession,
- keyExpr: KeyExpr,
- callback: Callback,
- receiver: R,
- history: Boolean,
- onClose: () -> Unit
- ): HandlerSubscriber {
- val subCallback =
- JNISubscriberCallback { keyExpr2, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int ->
- val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
- val sample = Sample(
- KeyExpr(keyExpr2, null),
- payload.into(),
- Encoding(encodingId, schema = encodingSchema),
- SampleKind.fromInt(kind),
- timestamp,
- QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
- attachmentBytes?.into()
- )
- callback.run(sample)
- }
- val ptr = declareSubscriberViaJNI(
- jniSession.sessionPtr,
- keyExpr.jniKeyExpr?.ptr ?: 0,
- keyExpr.keyExpr,
- subCallback,
- history,
- onClose
- )
- return HandlerSubscriber(keyExpr, JNISubscriber(ptr), receiver)
- }
-
- private external fun getViaJNI(
- sessionPtr: Long,
- keyExprPtr: Long,
- keyExprString: String,
- callback: JNIGetCallback,
- timeoutMs: Long,
- onClose: JNIOnCloseCallback
- )
-
- private external fun declareTokenViaJNI(sessionPtr: Long, keyExprPtr: Long, keyExprString: String): Long
-
- private external fun declareSubscriberViaJNI(
- sessionPtr: Long,
- keyExprPtr: Long,
- keyExprString: String,
- callback: JNISubscriberCallback,
- history: Boolean,
- onClose: JNIOnCloseCallback
- ): Long
-}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILivelinessToken.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILivelinessToken.kt
deleted file mode 100644
index 991c860a..00000000
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILivelinessToken.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.zenoh.jni
-
-internal class JNILivelinessToken(val ptr: Long) {
-
- fun undeclare() {
- undeclareViaJNI(this.ptr)
- }
-
- companion object {
- external fun undeclareViaJNI(ptr: Long)
- }
-}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt
deleted file mode 100644
index 6e694271..00000000
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-// Copyright (c) 2023 ZettaScale Technology
-//
-// This program and the accompanying materials are made available under the
-// terms of the Eclipse Public License 2.0 which is available at
-// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
-// which is available at https://www.apache.org/licenses/LICENSE-2.0.
-//
-// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
-//
-// Contributors:
-// ZettaScale Zenoh Team,
-//
-
-package io.zenoh.jni
-
-import io.zenoh.exceptions.ZError
-import io.zenoh.bytes.Encoding
-import io.zenoh.bytes.IntoZBytes
-
-/**
- * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.pubsub.Publisher].
- *
- * @property ptr: raw pointer to the underlying native Publisher.
- */
-internal class JNIPublisher(private val ptr: Long) {
-
- /**
- * Put operation.
- *
- * @param payload Payload of the put.
- * @param encoding Encoding of the payload.
- * @param attachment Optional attachment.
- */
- @Throws(ZError::class)
- fun put(payload: IntoZBytes, encoding: Encoding?, attachment: IntoZBytes?) {
- val resolvedEncoding = encoding ?: Encoding.defaultEncoding()
- putViaJNI(payload.into().bytes, resolvedEncoding.id, resolvedEncoding.schema, attachment?.into()?.bytes, ptr)
- }
-
- /**
- * Delete operation.
- *
- * @param attachment Optional attachment.
- */
- @Throws(ZError::class)
- fun delete(attachment: IntoZBytes?) {
- deleteViaJNI(attachment?.into()?.bytes, ptr)
- }
-
- /**
- * Close and free the underlying publisher pointer.
- *
- * Further operations with this publisher should not be performed anymore.
- */
- fun close() {
- freePtrViaJNI(ptr)
- }
-
- @Throws(ZError::class)
- private external fun putViaJNI(
- valuePayload: ByteArray, encodingId: Int, encodingSchema: String?, attachment: ByteArray?, ptr: Long
- )
-
- @Throws(ZError::class)
- private external fun deleteViaJNI(attachment: ByteArray?, ptr: Long)
-
- private external fun freePtrViaJNI(ptr: Long)
-
-}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuerier.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuerier.kt
deleted file mode 100644
index c026ed1c..00000000
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuerier.kt
+++ /dev/null
@@ -1,137 +0,0 @@
-//
-// Copyright (c) 2023 ZettaScale Technology
-//
-// This program and the accompanying materials are made available under the
-// terms of the Eclipse Public License 2.0 which is available at
-// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
-// which is available at https://www.apache.org/licenses/LICENSE-2.0.
-//
-// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
-//
-// Contributors:
-// ZettaScale Zenoh Team,
-//
-
-package io.zenoh.jni
-
-import io.zenoh.annotations.Unstable
-import io.zenoh.bytes.Encoding
-import io.zenoh.bytes.IntoZBytes
-import io.zenoh.bytes.into
-import io.zenoh.config.EntityGlobalId
-import io.zenoh.config.ZenohId
-import io.zenoh.exceptions.ZError
-import io.zenoh.handlers.Callback
-import io.zenoh.handlers.Handler
-import io.zenoh.jni.callbacks.JNIGetCallback
-import io.zenoh.jni.callbacks.JNIOnCloseCallback
-import io.zenoh.keyexpr.KeyExpr
-import io.zenoh.qos.CongestionControl
-import io.zenoh.qos.Priority
-import io.zenoh.qos.QoS
-import io.zenoh.query.Parameters
-import io.zenoh.query.Querier
-import io.zenoh.query.Reply
-import io.zenoh.sample.Sample
-import io.zenoh.sample.SampleKind
-import org.apache.commons.net.ntp.TimeStamp
-
-internal class JNIQuerier(val ptr: Long) {
-
- @OptIn(Unstable::class)
- @Throws(ZError::class)
- fun performGetWithCallback(keyExpr: KeyExpr, callback: Callback, options: Querier.GetOptions) {
- performGet(keyExpr, options.parameters, callback, fun() {}, Unit, options.attachment, options.payload, options.encoding)
- }
-
- @OptIn(Unstable::class)
- @Throws(ZError::class)
- fun performGetWithHandler(keyExpr: KeyExpr, handler: Handler, options: Querier.GetOptions): R {
- return performGet(keyExpr, options.parameters, handler::handle, handler::onClose, handler.receiver(), options.attachment, options.payload, options.encoding)
- }
-
- @Throws(ZError::class)
- private fun performGet(
- keyExpr: KeyExpr,
- parameters: Parameters?,
- callback: Callback,
- onClose: () -> Unit,
- receiver: R,
- attachment: IntoZBytes?,
- payload: IntoZBytes?,
- encoding: Encoding?
- ): R {
- val getCallback = JNIGetCallback {
- replierZid: ByteArray?,
- replierEid: Int,
- success: Boolean,
- keyExpr2: String?,
- payload2: ByteArray,
- encodingId: Int,
- encodingSchema: String?,
- kind: Int,
- timestampNTP64: Long,
- timestampIsValid: Boolean,
- attachmentBytes: ByteArray?,
- express: Boolean,
- priority: Int,
- congestionControl: Int,
- ->
- val reply: Reply
- if (success) {
- val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
- val sample = Sample(
- KeyExpr(keyExpr2!!, null),
- payload2.into(),
- Encoding(encodingId, schema = encodingSchema),
- SampleKind.fromInt(kind),
- timestamp,
- QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
- attachmentBytes?.into()
- )
- reply = Reply.Success(replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, sample)
- } else {
- reply = Reply.Error(
- replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) },
- payload2.into(),
- Encoding(encodingId, schema = encodingSchema)
- )
- }
- callback.run(reply)
- }
-
- getViaJNI(this.ptr,
- keyExpr.jniKeyExpr?.ptr ?: 0,
- keyExpr.keyExpr,
- parameters?.toString(),
- getCallback,
- onClose,
- attachment?.into()?.bytes,
- payload?.into()?.bytes,
- encoding?.id ?: Encoding.defaultEncoding().id,
- encoding?.schema
- )
- return receiver
- }
-
- fun close() {
- freePtrViaJNI(ptr)
- }
-
- @Throws(ZError::class)
- private external fun getViaJNI(
- querierPtr: Long,
- keyExprPtr: Long,
- keyExprString: String,
- parameters: String?,
- callback: JNIGetCallback,
- onClose: JNIOnCloseCallback,
- attachmentBytes: ByteArray?,
- payload: ByteArray?,
- encodingId: Int,
- encodingSchema: String?,
- )
-
- private external fun freePtrViaJNI(ptr: Long)
-
-}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt
deleted file mode 100644
index 0b1683f0..00000000
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt
+++ /dev/null
@@ -1,106 +0,0 @@
-//
-// Copyright (c) 2023 ZettaScale Technology
-//
-// This program and the accompanying materials are made available under the
-// terms of the Eclipse Public License 2.0 which is available at
-// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
-// which is available at https://www.apache.org/licenses/LICENSE-2.0.
-//
-// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
-//
-// Contributors:
-// ZettaScale Zenoh Team,
-//
-
-package io.zenoh.jni
-
-import io.zenoh.exceptions.ZError
-import io.zenoh.keyexpr.KeyExpr
-import io.zenoh.bytes.Encoding
-import io.zenoh.qos.QoS
-import io.zenoh.bytes.IntoZBytes
-import io.zenoh.sample.Sample
-import org.apache.commons.net.ntp.TimeStamp
-
-/**
- * Adapter class for interacting with a Query using JNI.
- *
- * This class serves as an adapter for interacting with a Query through JNI (Java Native Interface).
- *
- * @property ptr The raw pointer to the underlying native query.
- */
-internal class JNIQuery(private val ptr: Long) {
-
- fun replySuccess(sample: Sample) {
- val timestampEnabled = sample.timestamp != null
- replySuccessViaJNI(
- ptr,
- sample.keyExpr.jniKeyExpr?.ptr ?: 0,
- sample.keyExpr.keyExpr,
- sample.payload.bytes,
- sample.encoding.id,
- sample.encoding.schema,
- timestampEnabled,
- if (timestampEnabled) sample.timestamp!!.ntpValue() else 0,
- sample.attachment?.bytes,
- sample.qos.express
- )
- }
-
- fun replyError(error: IntoZBytes, encoding: Encoding) {
- replyErrorViaJNI(ptr, error.into().bytes, encoding.id, encoding.schema)
- }
-
- fun replyDelete(keyExpr: KeyExpr, timestamp: TimeStamp?, attachment: IntoZBytes?, qos: QoS) {
- val timestampEnabled = timestamp != null
- replyDeleteViaJNI(
- ptr,
- keyExpr.jniKeyExpr?.ptr ?: 0,
- keyExpr.keyExpr,
- timestampEnabled,
- if (timestampEnabled) timestamp!!.ntpValue() else 0,
- attachment?.into()?.bytes,
- qos.express
- )
- }
-
- fun close() {
- freePtrViaJNI(ptr)
- }
-
- @Throws(ZError::class)
- private external fun replySuccessViaJNI(
- queryPtr: Long,
- keyExprPtr: Long,
- keyExprString: String,
- valuePayload: ByteArray,
- valueEncodingId: Int,
- valueEncodingSchema: String?,
- timestampEnabled: Boolean,
- timestampNtp64: Long,
- attachment: ByteArray?,
- qosExpress: Boolean,
- )
-
- @Throws(ZError::class)
- private external fun replyErrorViaJNI(
- queryPtr: Long,
- errorValuePayload: ByteArray,
- errorValueEncoding: Int,
- encodingSchema: String?,
- )
-
- @Throws(ZError::class)
- private external fun replyDeleteViaJNI(
- queryPtr: Long,
- keyExprPtr: Long,
- keyExprString: String,
- timestampEnabled: Boolean,
- timestampNtp64: Long,
- attachment: ByteArray?,
- qosExpress: Boolean,
- )
-
- /** Frees the underlying native Query. */
- private external fun freePtrViaJNI(ptr: Long)
-}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt
deleted file mode 100644
index f2e1c49c..00000000
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-//
-// Copyright (c) 2023 ZettaScale Technology
-//
-// This program and the accompanying materials are made available under the
-// terms of the Eclipse Public License 2.0 which is available at
-// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
-// which is available at https://www.apache.org/licenses/LICENSE-2.0.
-//
-// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
-//
-// Contributors:
-// ZettaScale Zenoh Team,
-//
-
-package io.zenoh.jni
-
-import io.zenoh.Config
-import io.zenoh.ZenohLoad
-import io.zenoh.exceptions.ZError
-import io.zenoh.handlers.Callback
-import io.zenoh.jni.callbacks.JNIScoutCallback
-import io.zenoh.config.ZenohId
-import io.zenoh.scouting.Hello
-import io.zenoh.config.WhatAmI
-import io.zenoh.jni.callbacks.JNIOnCloseCallback
-import io.zenoh.scouting.CallbackScout
-import io.zenoh.scouting.HandlerScout
-
-/**
- * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.scouting.Scout]
- *
- * @property ptr: raw pointer to the underlying native scout.
- */
-internal class JNIScout(private val ptr: Long) {
-
- companion object {
-
- init {
- ZenohLoad
- }
-
- @Throws(ZError::class)
- fun scoutWithHandler(
- whatAmI: Set,
- callback: Callback,
- onClose: () -> Unit,
- config: Config?,
- receiver: R
- ): HandlerScout {
- val scoutCallback = JNIScoutCallback { whatAmI2: Int, id: ByteArray, locators: List ->
- callback.run(Hello(WhatAmI.fromInt(whatAmI2), ZenohId(id), locators))
- }
- val binaryWhatAmI: Int = whatAmI.map { it.value }.reduce { acc, it -> acc or it }
- val ptr = scoutViaJNI(binaryWhatAmI, scoutCallback, onClose,config?.jniConfig?.ptr ?: 0)
- return HandlerScout(JNIScout(ptr), receiver)
- }
-
- @Throws(ZError::class)
- fun scoutWithCallback(
- whatAmI: Set,
- callback: Callback,
- config: Config?,
- ): CallbackScout {
- val scoutCallback = JNIScoutCallback { whatAmI2: Int, id: ByteArray, locators: List ->
- callback.run(Hello(WhatAmI.fromInt(whatAmI2), ZenohId(id), locators))
- }
- val binaryWhatAmI: Int = whatAmI.map { it.value }.reduce { acc, it -> acc or it }
- val ptr = scoutViaJNI(binaryWhatAmI, scoutCallback, fun() {},config?.jniConfig?.ptr ?: 0)
- return CallbackScout(JNIScout(ptr))
- }
-
- @Throws(ZError::class)
- private external fun scoutViaJNI(
- whatAmI: Int,
- callback: JNIScoutCallback,
- onClose: JNIOnCloseCallback,
- configPtr: Long,
- ): Long
-
- @Throws(ZError::class)
- external fun freePtrViaJNI(ptr: Long)
- }
-
- fun close() {
- freePtrViaJNI(ptr)
- }
-}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt
deleted file mode 100644
index 096a6c59..00000000
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt
+++ /dev/null
@@ -1,548 +0,0 @@
-//
-// Copyright (c) 2023 ZettaScale Technology
-//
-// This program and the accompanying materials are made available under the
-// terms of the Eclipse Public License 2.0 which is available at
-// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
-// which is available at https://www.apache.org/licenses/LICENSE-2.0.
-//
-// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
-//
-// Contributors:
-// ZettaScale Zenoh Team,
-//
-
-package io.zenoh.jni
-
-import io.zenoh.*
-import io.zenoh.bytes.Encoding
-import io.zenoh.exceptions.ZError
-import io.zenoh.handlers.Callback
-import io.zenoh.jni.callbacks.JNIOnCloseCallback
-import io.zenoh.jni.callbacks.JNIGetCallback
-import io.zenoh.jni.callbacks.JNIQueryableCallback
-import io.zenoh.jni.callbacks.JNISubscriberCallback
-import io.zenoh.keyexpr.KeyExpr
-import io.zenoh.bytes.IntoZBytes
-import io.zenoh.config.ZenohId
-import io.zenoh.bytes.into
-import io.zenoh.Config
-import io.zenoh.annotations.Unstable
-import io.zenoh.config.EntityGlobalId
-import io.zenoh.handlers.Handler
-import io.zenoh.pubsub.*
-import io.zenoh.qos.CongestionControl
-import io.zenoh.qos.Priority
-import io.zenoh.qos.QoS
-import io.zenoh.query.*
-import io.zenoh.sample.Sample
-import io.zenoh.sample.SampleKind
-import org.apache.commons.net.ntp.TimeStamp
-
-/** Adapter class to handle the communication with the Zenoh JNI code for a [Session]. */
-internal class JNISession(val sessionPtr: Long) {
-
- companion object {
- init {
- ZenohLoad
- }
-
- @Throws(ZError::class)
- fun open(config: Config): JNISession {
- val sessionPtr = openSessionViaJNI(config.jniConfig.ptr)
- return JNISession(sessionPtr)
- }
-
- @Throws(ZError::class)
- private external fun openSessionViaJNI(configPtr: Long): Long
- }
-
- fun close() {
- closeSessionViaJNI(sessionPtr)
- }
-
- @Throws(ZError::class)
- fun declarePublisher(keyExpr: KeyExpr, publisherOptions: PublisherOptions): Publisher {
- val publisherRawPtr = declarePublisherViaJNI(
- keyExpr.jniKeyExpr?.ptr ?: 0,
- keyExpr.keyExpr,
- sessionPtr,
- publisherOptions.congestionControl.value,
- publisherOptions.priority.value,
- publisherOptions.express,
- publisherOptions.reliability.ordinal
- )
- return Publisher(
- keyExpr,
- publisherOptions.congestionControl,
- publisherOptions.priority,
- publisherOptions.encoding,
- JNIPublisher(publisherRawPtr),
- )
- }
-
- @Throws(ZError::class)
- fun declareSubscriberWithHandler(
- keyExpr: KeyExpr, handler: Handler
- ): HandlerSubscriber {
- val subCallback =
- JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int ->
- val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
- val sample = Sample(
- KeyExpr(keyExpr1, null),
- payload.into(),
- Encoding(encodingId, schema = encodingSchema),
- SampleKind.fromInt(kind),
- timestamp,
- QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
- attachmentBytes?.into()
- )
- handler.handle(sample)
- }
- val subscriberRawPtr = declareSubscriberViaJNI(
- keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr, subCallback, handler::onClose
- )
- return HandlerSubscriber(keyExpr, JNISubscriber(subscriberRawPtr), handler.receiver())
- }
-
- @Throws(ZError::class)
- fun declareSubscriberWithCallback(
- keyExpr: KeyExpr, callback: Callback
- ): CallbackSubscriber {
- val subCallback =
- JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int ->
- val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
- val sample = Sample(
- KeyExpr(keyExpr1, null),
- payload.into(),
- Encoding(encodingId, schema = encodingSchema),
- SampleKind.fromInt(kind),
- timestamp,
- QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
- attachmentBytes?.into()
- )
- callback.run(sample)
- }
- val subscriberRawPtr = declareSubscriberViaJNI(
- keyExpr.jniKeyExpr?.ptr ?: 0,
- keyExpr.keyExpr,
- sessionPtr,
- subCallback,
- fun() {}
- )
- return CallbackSubscriber(keyExpr, JNISubscriber(subscriberRawPtr))
- }
-
- @Throws(ZError::class)
- fun declareQueryableWithCallback(
- keyExpr: KeyExpr, callback: Callback, config: QueryableOptions
- ): CallbackQueryable {
- val queryCallback =
- JNIQueryableCallback { keyExpr1: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long, acceptReplies: Int ->
- val jniQuery = JNIQuery(queryPtr)
- val keyExpr2 = KeyExpr(keyExpr1, null)
- val selector = if (selectorParams.isEmpty()) {
- Selector(keyExpr2)
- } else {
- Selector(keyExpr2, Parameters.from(selectorParams))
- }
- val replyKeyExpr = ReplyKeyExpr.entries[acceptReplies]
- val query = Query(
- keyExpr2,
- selector,
- payload?.into(),
- payload?.let { Encoding(encodingId, schema = encodingSchema) },
- attachmentBytes?.into(),
- replyKeyExpr,
- jniQuery
- )
- callback.run(query)
- }
- val queryableRawPtr = declareQueryableViaJNI(
- keyExpr.jniKeyExpr?.ptr ?: 0,
- keyExpr.keyExpr,
- sessionPtr,
- queryCallback,
- fun() {},
- config.complete
- )
- return CallbackQueryable(keyExpr, JNIQueryable(queryableRawPtr))
- }
-
- @Throws(ZError::class)
- fun declareQueryableWithHandler(
- keyExpr: KeyExpr, handler: Handler, config: QueryableOptions
- ): HandlerQueryable {
- val queryCallback =
- JNIQueryableCallback { keyExpr1: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long, acceptReplies: Int ->
- val jniQuery = JNIQuery(queryPtr)
- val keyExpr2 = KeyExpr(keyExpr1, null)
- val selector = if (selectorParams.isEmpty()) {
- Selector(keyExpr2)
- } else {
- Selector(keyExpr2, Parameters.from(selectorParams))
- }
- val replyKeyExpr = ReplyKeyExpr.entries[acceptReplies]
- val query = Query(
- keyExpr2,
- selector,
- payload?.into(),
- payload?.let { Encoding(encodingId, schema = encodingSchema) },
- attachmentBytes?.into(),
- replyKeyExpr,
- jniQuery
- )
- handler.handle(query)
- }
- val queryableRawPtr = declareQueryableViaJNI(
- keyExpr.jniKeyExpr?.ptr ?: 0,
- keyExpr.keyExpr,
- sessionPtr,
- queryCallback,
- handler::onClose,
- config.complete
- )
- return HandlerQueryable(keyExpr, JNIQueryable(queryableRawPtr), handler.receiver())
- }
-
- @OptIn(Unstable::class)
- fun declareQuerier(
- keyExpr: KeyExpr,
- options: QuerierOptions
- ): Querier {
- val querierRawPtr = declareQuerierViaJNI(
- keyExpr.jniKeyExpr?.ptr ?: 0,
- keyExpr.keyExpr,
- sessionPtr,
- options.target.ordinal,
- options.consolidationMode.ordinal,
- options.congestionControl.value,
- options.priority.value,
- options.express,
- options.timeout.toMillis(),
- options.acceptReplies.ordinal
- )
- return Querier(
- keyExpr,
- QoS(
- congestionControl = options.congestionControl,
- priority = options.priority,
- express = options.express
- ),
- JNIQuerier(querierRawPtr)
- )
- }
-
- @Throws(ZError::class)
- fun performGetWithCallback(
- intoSelector: IntoSelector,
- callback: Callback,
- options: GetOptions
- ) {
- val getCallback = JNIGetCallback {
- replierZid: ByteArray?,
- replierEid: Int,
- success: Boolean,
- keyExpr: String?,
- payload1: ByteArray,
- encodingId: Int,
- encodingSchema: String?,
- kind: Int,
- timestampNTP64: Long,
- timestampIsValid: Boolean,
- attachmentBytes: ByteArray?,
- express: Boolean,
- priority: Int,
- congestionControl: Int,
- ->
- val reply: Reply
- if (success) {
- val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
- val sample = Sample(
- KeyExpr(keyExpr!!, null),
- payload1.into(),
- Encoding(encodingId, schema = encodingSchema),
- SampleKind.fromInt(kind),
- timestamp,
- QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
- attachmentBytes?.into()
- )
- reply = Reply.Success(replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, sample)
- } else {
- reply = Reply.Error(
- replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) },
- payload1.into(),
- Encoding(encodingId, schema = encodingSchema)
- )
- }
- callback.run(reply)
- }
-
- val selector = intoSelector.into()
- getViaJNI(
- selector.keyExpr.jniKeyExpr?.ptr ?: 0,
- selector.keyExpr.keyExpr,
- selector.parameters?.toString(),
- sessionPtr,
- getCallback,
- fun() {},
- options.timeout.toMillis(),
- options.target.ordinal,
- options.consolidation.ordinal,
- options.attachment?.into()?.bytes,
- options.payload?.into()?.bytes,
- options.encoding?.id ?: Encoding.defaultEncoding().id,
- options.encoding?.schema,
- options.qos.congestionControl.value,
- options.qos.priority.value,
- options.qos.express,
- options.acceptReplies.ordinal
- )
- }
-
- @Throws(ZError::class)
- fun performGetWithHandler(
- intoSelector: IntoSelector,
- handler: Handler,
- options: GetOptions
- ): R {
- val getCallback = JNIGetCallback {
- replierZid: ByteArray?,
- replierEid: Int,
- success: Boolean,
- keyExpr: String?,
- payload1: ByteArray,
- encodingId: Int,
- encodingSchema: String?,
- kind: Int,
- timestampNTP64: Long,
- timestampIsValid: Boolean,
- attachmentBytes: ByteArray?,
- express: Boolean,
- priority: Int,
- congestionControl: Int,
- ->
- val reply: Reply
- if (success) {
- val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
- val sample = Sample(
- KeyExpr(keyExpr!!, null),
- payload1.into(),
- Encoding(encodingId, schema = encodingSchema),
- SampleKind.fromInt(kind),
- timestamp,
- QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
- attachmentBytes?.into()
- )
- reply = Reply.Success(replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, sample)
- } else {
- reply = Reply.Error(
- replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) },
- payload1.into(),
- Encoding(encodingId, schema = encodingSchema)
- )
- }
- handler.handle(reply)
- }
-
- val selector = intoSelector.into()
- getViaJNI(
- selector.keyExpr.jniKeyExpr?.ptr ?: 0,
- selector.keyExpr.keyExpr,
- selector.parameters?.toString(),
- sessionPtr,
- getCallback,
- handler::onClose,
- options.timeout.toMillis(),
- options.target.ordinal,
- options.consolidation.ordinal,
- options.attachment?.into()?.bytes,
- options.payload?.into()?.bytes,
- options.encoding?.id ?: Encoding.defaultEncoding().id,
- options.encoding?.schema,
- options.qos.congestionControl.value,
- options.qos.priority.value,
- options.qos.express,
- options.acceptReplies.ordinal
- )
- return handler.receiver()
- }
-
- @Throws(ZError::class)
- fun declareKeyExpr(keyExpr: String): KeyExpr {
- val ptr = declareKeyExprViaJNI(sessionPtr, keyExpr)
- return KeyExpr(keyExpr, JNIKeyExpr(ptr))
- }
-
- @Throws(ZError::class)
- fun undeclareKeyExpr(keyExpr: KeyExpr) {
- keyExpr.jniKeyExpr?.run {
- undeclareKeyExprViaJNI(sessionPtr, this.ptr)
- keyExpr.jniKeyExpr = null
- } ?: throw ZError("Attempting to undeclare a non declared key expression.")
- }
-
- @Throws(ZError::class)
- fun performPut(
- keyExpr: KeyExpr,
- payload: IntoZBytes,
- options: PutOptions,
- ) {
- val encoding = options.encoding ?: Encoding.defaultEncoding()
- putViaJNI(
- keyExpr.jniKeyExpr?.ptr ?: 0,
- keyExpr.keyExpr,
- sessionPtr,
- payload.into().bytes,
- encoding.id,
- encoding.schema,
- options.congestionControl.value,
- options.priority.value,
- options.express,
- options.attachment?.into()?.bytes,
- options.reliability.ordinal
- )
- }
-
- @Throws(ZError::class)
- fun performDelete(
- keyExpr: KeyExpr,
- options: DeleteOptions,
- ) {
- deleteViaJNI(
- keyExpr.jniKeyExpr?.ptr ?: 0,
- keyExpr.keyExpr,
- sessionPtr,
- options.congestionControl.value,
- options.priority.value,
- options.express,
- options.attachment?.into()?.bytes,
- options.reliability.ordinal
- )
- }
-
- @Throws(ZError::class)
- fun zid(): ZenohId {
- return ZenohId(getZidViaJNI(sessionPtr))
- }
-
- @Throws(ZError::class)
- fun peersZid(): List {
- return getPeersZidViaJNI(sessionPtr).map { ZenohId(it) }
- }
-
- @Throws(ZError::class)
- fun routersZid(): List {
- return getRoutersZidViaJNI(sessionPtr).map { ZenohId(it) }
- }
-
- @Throws(ZError::class)
- private external fun getZidViaJNI(ptr: Long): ByteArray
-
- @Throws(ZError::class)
- private external fun getPeersZidViaJNI(ptr: Long): List
-
- @Throws(ZError::class)
- private external fun getRoutersZidViaJNI(ptr: Long): List
-
- @Throws(ZError::class)
- private external fun closeSessionViaJNI(ptr: Long)
-
- @Throws(ZError::class)
- private external fun declarePublisherViaJNI(
- keyExprPtr: Long,
- keyExprString: String,
- sessionPtr: Long,
- congestionControl: Int,
- priority: Int,
- express: Boolean,
- reliability: Int
- ): Long
-
- @Throws(ZError::class)
- private external fun declareSubscriberViaJNI(
- keyExprPtr: Long,
- keyExprString: String,
- sessionPtr: Long,
- callback: JNISubscriberCallback,
- onClose: JNIOnCloseCallback,
- ): Long
-
- @Throws(ZError::class)
- private external fun declareQueryableViaJNI(
- keyExprPtr: Long,
- keyExprString: String,
- sessionPtr: Long,
- callback: JNIQueryableCallback,
- onClose: JNIOnCloseCallback,
- complete: Boolean
- ): Long
-
- @Throws(ZError::class)
- private external fun declareQuerierViaJNI(
- keyExprPtr: Long,
- keyExprString: String,
- sessionPtr: Long,
- target: Int,
- consolidation: Int,
- congestionControl: Int,
- priority: Int,
- express: Boolean,
- timeoutMs: Long,
- acceptReplies: Int
- ): Long
-
- @Throws(ZError::class)
- private external fun declareKeyExprViaJNI(sessionPtr: Long, keyExpr: String): Long
-
- @Throws(ZError::class)
- private external fun undeclareKeyExprViaJNI(sessionPtr: Long, keyExprPtr: Long)
-
- @Throws(ZError::class)
- private external fun getViaJNI(
- keyExprPtr: Long,
- keyExprString: String,
- selectorParams: String?,
- sessionPtr: Long,
- callback: JNIGetCallback,
- onClose: JNIOnCloseCallback,
- timeoutMs: Long,
- target: Int,
- consolidation: Int,
- attachmentBytes: ByteArray?,
- payload: ByteArray?,
- encodingId: Int,
- encodingSchema: String?,
- congestionControl: Int,
- priority: Int,
- express: Boolean,
- acceptReplies: Int,
- )
-
- @Throws(ZError::class)
- private external fun putViaJNI(
- keyExprPtr: Long,
- keyExprString: String,
- sessionPtr: Long,
- valuePayload: ByteArray,
- valueEncoding: Int,
- valueEncodingSchema: String?,
- congestionControl: Int,
- priority: Int,
- express: Boolean,
- attachmentBytes: ByteArray?,
- reliability: Int
- )
-
- @Throws(ZError::class)
- private external fun deleteViaJNI(
- keyExprPtr: Long,
- keyExprString: String,
- sessionPtr: Long,
- congestionControl: Int,
- priority: Int,
- express: Boolean,
- attachmentBytes: ByteArray?,
- reliability: Int
- )
-}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt
index b5fe6110..bf0461a2 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt
+++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt
@@ -79,7 +79,7 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn
@JvmStatic
@Throws(ZError::class)
fun tryFrom(keyExpr: String): KeyExpr {
- return JNIKeyExpr.tryFrom(keyExpr)
+ return KeyExpr(JNIKeyExpr.tryFrom(keyExpr))
}
/**
@@ -95,7 +95,7 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn
@JvmStatic
@Throws(ZError::class)
fun autocanonize(keyExpr: String): KeyExpr {
- return JNIKeyExpr.autocanonize(keyExpr)
+ return KeyExpr(JNIKeyExpr.autocanonize(keyExpr))
}
}
@@ -106,7 +106,7 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn
*/
@Throws(ZError::class)
fun intersects(other: KeyExpr): Boolean {
- return JNIKeyExpr.intersects(this, other)
+ return JNIKeyExpr.intersects(jniKeyExpr, keyExpr, other.jniKeyExpr, other.keyExpr)
}
/**
@@ -116,7 +116,7 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn
*/
@Throws(ZError::class)
fun includes(other: KeyExpr): Boolean {
- return JNIKeyExpr.includes(this, other)
+ return JNIKeyExpr.includes(jniKeyExpr, keyExpr, other.jniKeyExpr, other.keyExpr)
}
/**
@@ -126,7 +126,7 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn
*/
@Throws(ZError::class)
fun relationTo(other: KeyExpr): SetIntersectionLevel {
- return JNIKeyExpr.relationTo(this, other)
+ return SetIntersectionLevel.fromInt(JNIKeyExpr.relationTo(jniKeyExpr, keyExpr, other.jniKeyExpr, other.keyExpr))
}
/**
@@ -135,7 +135,7 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn
*/
@Throws(ZError::class)
fun join(other: String): KeyExpr {
- return JNIKeyExpr.joinViaJNI(this, other)
+ return KeyExpr(JNIKeyExpr.join(jniKeyExpr, keyExpr, other))
}
/**
@@ -144,7 +144,7 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn
*/
@Throws(ZError::class)
fun concat(other: String): KeyExpr {
- return JNIKeyExpr.concatViaJNI(this, other)
+ return KeyExpr(JNIKeyExpr.concat(jniKeyExpr, keyExpr, other))
}
override fun toString(): String {
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt
index 96711557..62aff6c5 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt
+++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt
@@ -15,17 +15,27 @@
package io.zenoh.liveliness
import io.zenoh.Session
+import io.zenoh.bytes.Encoding
+import io.zenoh.bytes.into
+import io.zenoh.config.EntityGlobalId
+import io.zenoh.config.ZenohId
import io.zenoh.exceptions.ZError
import io.zenoh.handlers.BlockingQueueHandler
import io.zenoh.handlers.Callback
import io.zenoh.handlers.Handler
-import io.zenoh.jni.JNILiveliness
+import io.zenoh.jni.callbacks.JNIGetCallback
+import io.zenoh.jni.callbacks.JNISubscriberCallback
import io.zenoh.keyexpr.KeyExpr
import io.zenoh.pubsub.CallbackSubscriber
import io.zenoh.pubsub.HandlerSubscriber
import io.zenoh.pubsub.Subscriber
+import io.zenoh.qos.CongestionControl
+import io.zenoh.qos.Priority
+import io.zenoh.qos.QoS
import io.zenoh.query.Reply
import io.zenoh.sample.Sample
+import io.zenoh.sample.SampleKind
+import org.apache.commons.net.ntp.TimeStamp
import java.time.Duration
import java.util.*
import java.util.concurrent.BlockingQueue
@@ -49,7 +59,7 @@ class Liveliness internal constructor(private val session: Session) {
@Throws(ZError::class)
fun declareToken(keyExpr: KeyExpr): LivelinessToken {
val jniSession = session.jniSession ?: throw Session.sessionClosedException
- return JNILiveliness.declareToken(jniSession, keyExpr)
+ return LivelinessToken(jniSession.declareLivelinessToken(keyExpr.jniKeyExpr, keyExpr.keyExpr))
}
/**
@@ -66,14 +76,15 @@ class Liveliness internal constructor(private val session: Session) {
): BlockingQueue> {
val jniSession = session.jniSession ?: throw Session.sessionClosedException
val handler = BlockingQueueHandler(LinkedBlockingDeque())
- return JNILiveliness.get(
- jniSession,
- keyExpr,
- handler::handle,
- receiver = handler.receiver(),
- timeout,
- onClose = handler::onClose
+ val getCallback = buildGetCallback(handler::handle)
+ jniSession.livelinessGet(
+ keyExpr.jniKeyExpr,
+ keyExpr.keyExpr,
+ getCallback,
+ timeout.toMillis(),
+ handler::onClose
)
+ return handler.receiver()
}
/**
@@ -89,7 +100,13 @@ class Liveliness internal constructor(private val session: Session) {
keyExpr: KeyExpr, callback: Callback, timeout: Duration = Duration.ofMillis(10000)
) {
val jniSession = session.jniSession ?: throw Session.sessionClosedException
- return JNILiveliness.get(jniSession, keyExpr, callback, Unit, timeout, {})
+ jniSession.livelinessGet(
+ keyExpr.jniKeyExpr,
+ keyExpr.keyExpr,
+ buildGetCallback(callback),
+ timeout.toMillis(),
+ fun() {}
+ )
}
/**
@@ -106,17 +123,38 @@ class Liveliness internal constructor(private val session: Session) {
keyExpr: KeyExpr, handler: Handler, timeout: Duration = Duration.ofMillis(10000)
): R {
val jniSession = session.jniSession ?: throw Session.sessionClosedException
- val callback = handler::handle
- return JNILiveliness.get(
- jniSession,
- keyExpr,
- callback,
- handler.receiver(),
- timeout,
- onClose = handler::onClose
+ jniSession.livelinessGet(
+ keyExpr.jniKeyExpr,
+ keyExpr.keyExpr,
+ buildGetCallback(handler::handle),
+ timeout.toMillis(),
+ handler::onClose
)
+ return handler.receiver()
}
+ private fun buildGetCallback(callback: Callback): JNIGetCallback =
+ JNIGetCallback { replierZid, replierEid, success, keyExpr2, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express, priority, congestionControl ->
+ val reply: Reply = if (success) {
+ val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
+ Reply.Success(
+ replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) },
+ Sample(
+ KeyExpr(keyExpr2!!, null),
+ payload.into(),
+ Encoding(encodingId, schema = encodingSchema),
+ SampleKind.fromInt(kind),
+ timestamp,
+ QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
+ attachmentBytes?.into()
+ )
+ )
+ } else {
+ Reply.Error(replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, payload.into(), Encoding(encodingId, schema = encodingSchema))
+ }
+ callback.run(reply)
+ }
+
/**
* Create a [Subscriber] for liveliness changes matching the given key expression.
*
@@ -131,14 +169,8 @@ class Liveliness internal constructor(private val session: Session) {
): HandlerSubscriber>> {
val handler = BlockingQueueHandler(LinkedBlockingDeque())
val jniSession = session.jniSession ?: throw Session.sessionClosedException
- return JNILiveliness.declareSubscriber(
- jniSession,
- keyExpr,
- handler::handle,
- handler.receiver(),
- options.history,
- handler::onClose
- )
+ val subCallback = buildSubscriberCallback(handler::handle)
+ return HandlerSubscriber(keyExpr, jniSession.declareLivelinessSubscriber(keyExpr.jniKeyExpr, keyExpr.keyExpr, subCallback, options.history, handler::onClose), handler.receiver())
}
/**
@@ -156,13 +188,8 @@ class Liveliness internal constructor(private val session: Session) {
options: LivelinessSubscriberOptions = LivelinessSubscriberOptions()
): CallbackSubscriber {
val jniSession = session.jniSession ?: throw Session.sessionClosedException
- return JNILiveliness.declareSubscriber(
- jniSession,
- keyExpr,
- callback,
- options.history,
- fun() {}
- )
+ val subCallback = buildSubscriberCallback(callback)
+ return CallbackSubscriber(keyExpr, jniSession.declareLivelinessSubscriber(keyExpr.jniKeyExpr, keyExpr.keyExpr, subCallback, options.history, fun() {}))
}
/**
@@ -181,15 +208,25 @@ class Liveliness internal constructor(private val session: Session) {
options: LivelinessSubscriberOptions = LivelinessSubscriberOptions()
): HandlerSubscriber {
val jniSession = session.jniSession ?: throw Session.sessionClosedException
- return JNILiveliness.declareSubscriber(
- jniSession,
- keyExpr,
- handler::handle,
- handler.receiver(),
- options.history,
- handler::onClose
- )
+ val subCallback = buildSubscriberCallback(handler::handle)
+ return HandlerSubscriber(keyExpr, jniSession.declareLivelinessSubscriber(keyExpr.jniKeyExpr, keyExpr.keyExpr, subCallback, options.history, handler::onClose), handler.receiver())
}
+
+ private fun buildSubscriberCallback(callback: Callback): JNISubscriberCallback =
+ JNISubscriberCallback { keyExpr2, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express, priority, congestionControl ->
+ val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
+ callback.run(
+ Sample(
+ KeyExpr(keyExpr2, null),
+ payload.into(),
+ Encoding(encodingId, schema = encodingSchema),
+ SampleKind.fromInt(kind),
+ timestamp,
+ QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
+ attachmentBytes?.into()
+ )
+ )
+ }
}
/**
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt
index d0a9de2e..9ec8641a 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt
+++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt
@@ -79,13 +79,14 @@ class Publisher internal constructor(
/** Performs a PUT operation on the specified [keyExpr] with the specified [payload]. */
@Throws(ZError::class)
fun put(payload: IntoZBytes) {
- jniPublisher?.put(payload, encoding, null) ?: throw publisherNotValid
+ jniPublisher?.put(payload.into().bytes, encoding.id, encoding.schema, null) ?: throw publisherNotValid
}
/** Performs a PUT operation on the specified [keyExpr] with the specified [payload]. */
@Throws(ZError::class)
fun put(payload: IntoZBytes, options: PutOptions) {
- jniPublisher?.put(payload, options.encoding ?: this.encoding, options.attachment) ?: throw publisherNotValid
+ val enc = options.encoding ?: this.encoding
+ jniPublisher?.put(payload.into().bytes, enc.id, enc.schema, options.attachment?.into()?.bytes) ?: throw publisherNotValid
}
/** Performs a PUT operation on the specified [keyExpr] with the specified [payload]. */
@@ -102,7 +103,7 @@ class Publisher internal constructor(
@JvmOverloads
@Throws(ZError::class)
fun delete(options: DeleteOptions = DeleteOptions()) {
- jniPublisher?.delete(options.attachment) ?: throw(publisherNotValid)
+ jniPublisher?.delete(options.attachment?.into()?.bytes) ?: throw(publisherNotValid)
}
/**
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Querier.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Querier.kt
index 541d056b..faca37a8 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Querier.kt
+++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Querier.kt
@@ -18,16 +18,23 @@ import io.zenoh.annotations.Unstable
import io.zenoh.bytes.Encoding
import io.zenoh.bytes.IntoZBytes
import io.zenoh.bytes.ZBytes
+import io.zenoh.bytes.into
+import io.zenoh.config.EntityGlobalId
+import io.zenoh.config.ZenohId
import io.zenoh.exceptions.ZError
import io.zenoh.handlers.BlockingQueueHandler
import io.zenoh.handlers.Callback
import io.zenoh.handlers.Handler
import io.zenoh.jni.JNIQuerier
+import io.zenoh.jni.callbacks.JNIGetCallback
import io.zenoh.keyexpr.KeyExpr
import io.zenoh.qos.CongestionControl
import io.zenoh.qos.Priority
import io.zenoh.qos.QoS
+import io.zenoh.sample.Sample
+import io.zenoh.sample.SampleKind
import io.zenoh.session.SessionDeclaration
+import org.apache.commons.net.ntp.TimeStamp
import java.time.Duration
import java.util.Optional
import java.util.concurrent.BlockingQueue
@@ -143,11 +150,74 @@ class Querier internal constructor(val keyExpr: KeyExpr, val qos: QoS, private v
}
private fun resolveGetWithCallback(keyExpr: KeyExpr, callback: Callback, options: GetOptions) {
- jniQuerier?.performGetWithCallback(keyExpr, callback, options) ?: throw ZError("Querier is not valid.")
+ val jni = jniQuerier ?: throw ZError("Querier is not valid.")
+ val getCallback = JNIGetCallback { replierZid, replierEid, success, keyExpr2, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express, priority, congestionControl ->
+ val reply: Reply = if (success) {
+ val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
+ Reply.Success(
+ replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) },
+ Sample(
+ KeyExpr(keyExpr2!!, null),
+ payload.into(),
+ Encoding(encodingId, schema = encodingSchema),
+ SampleKind.fromInt(kind),
+ timestamp,
+ QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
+ attachmentBytes?.into()
+ )
+ )
+ } else {
+ Reply.Error(replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, payload.into(), Encoding(encodingId, schema = encodingSchema))
+ }
+ callback.run(reply)
+ }
+ jni.get(
+ keyExpr.jniKeyExpr,
+ keyExpr.keyExpr,
+ options.parameters?.toString(),
+ getCallback,
+ fun() {},
+ options.attachment?.into()?.bytes,
+ options.payload?.into()?.bytes,
+ options.encoding?.id ?: Encoding.defaultEncoding().id,
+ options.encoding?.schema
+ )
}
private fun resolveGetWithHandler(keyExpr: KeyExpr, handler: Handler, options: GetOptions): R {
- return jniQuerier?.performGetWithHandler(keyExpr, handler, options) ?: throw ZError("Querier is not valid.")
+ val jni = jniQuerier ?: throw ZError("Querier is not valid.")
+ val getCallback = JNIGetCallback { replierZid, replierEid, success, keyExpr2, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express, priority, congestionControl ->
+ val reply: Reply = if (success) {
+ val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null
+ Reply.Success(
+ replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) },
+ Sample(
+ KeyExpr(keyExpr2!!, null),
+ payload.into(),
+ Encoding(encodingId, schema = encodingSchema),
+ SampleKind.fromInt(kind),
+ timestamp,
+ QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express),
+ attachmentBytes?.into()
+ )
+ )
+ } else {
+ Reply.Error(replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, payload.into(), Encoding(encodingId, schema = encodingSchema))
+ }
+ handler.handle(reply)
+ }
+ jni.get(
+ keyExpr.jniKeyExpr,
+ keyExpr.keyExpr,
+ options.parameters?.toString(),
+ getCallback,
+ handler::onClose,
+ options.attachment?.into()?.bytes,
+ options.payload?.into()?.bytes,
+ options.encoding?.id ?: Encoding.defaultEncoding().id,
+ options.encoding?.schema
+ )
+ return handler.receiver()
}
}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt
index 3a8184da..c2128efa 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt
+++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt
@@ -24,6 +24,7 @@ import io.zenoh.keyexpr.KeyExpr
import io.zenoh.qos.QoS
import io.zenoh.sample.Sample
import io.zenoh.sample.SampleKind
+import org.apache.commons.net.ntp.TimeStamp
/**
* Represents a Zenoh Query in Kotlin.
@@ -61,17 +62,22 @@ class Query internal constructor(
@Throws(ZError::class)
@JvmOverloads
fun reply(keyExpr: KeyExpr, payload: IntoZBytes, options: ReplyOptions = ReplyOptions()) {
- val sample = Sample(
- keyExpr,
- payload.into(),
- options.encoding,
- SampleKind.PUT,
- options.timeStamp,
- QoS(options.congestionControl, options.priority, options.express),
- options.attachment?.into()
- )
+ val zbytes = payload.into()
+ val encoding = options.encoding
+ val timestamp = options.timeStamp
+ val timestampEnabled = timestamp != null
jniQuery?.apply {
- replySuccess(sample)
+ replySuccess(
+ keyExpr.jniKeyExpr,
+ keyExpr.keyExpr,
+ zbytes.bytes,
+ encoding?.id ?: Encoding.defaultEncoding().id,
+ encoding?.schema,
+ timestampEnabled,
+ if (timestampEnabled) timestamp!!.ntpValue() else 0,
+ options.attachment?.into()?.bytes,
+ QoS(options.congestionControl, options.priority, options.express).express
+ )
jniQuery = null
} ?: throw (ZError("Query is invalid"))
}
@@ -98,12 +104,16 @@ class Query internal constructor(
@JvmOverloads
@Throws(ZError::class)
fun replyDel(keyExpr: KeyExpr, options: ReplyDelOptions = ReplyDelOptions()) {
+ val timestamp = options.timeStamp
+ val timestampEnabled = timestamp != null
jniQuery?.apply {
replyDelete(
- keyExpr,
- options.timeStamp,
- options.attachment,
- QoS(options.congestionControl, options.priority, options.express),
+ keyExpr.jniKeyExpr,
+ keyExpr.keyExpr,
+ timestampEnabled,
+ if (timestampEnabled) timestamp!!.ntpValue() else 0,
+ options.attachment?.into()?.bytes,
+ QoS(options.congestionControl, options.priority, options.express).express
)
jniQuery = null
} ?: throw (ZError("Query is invalid"))
@@ -118,8 +128,9 @@ class Query internal constructor(
@JvmOverloads
@Throws(ZError::class)
fun replyErr(message: IntoZBytes, options: ReplyErrOptions = ReplyErrOptions()) {
+ val encoding = options.encoding
jniQuery?.apply {
- replyError(message.into(), options.encoding)
+ replyError(message.into().bytes, encoding?.id ?: Encoding.defaultEncoding().id, encoding?.schema)
jniQuery = null
} ?: throw (ZError("Query is invalid"))
}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserializer.kt b/zenoh-java/src/jvmAndAndroidMain/kotlin/io/zenoh/ext/ZDeserializer.kt
similarity index 98%
rename from zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserializer.kt
rename to zenoh-java/src/jvmAndAndroidMain/kotlin/io/zenoh/ext/ZDeserializer.kt
index 1d039cbe..fadbac89 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserializer.kt
+++ b/zenoh-java/src/jvmAndAndroidMain/kotlin/io/zenoh/ext/ZDeserializer.kt
@@ -106,6 +106,6 @@ abstract class ZDeserializer: TypeToken() {
*/
fun deserialize(zbytes: IntoZBytes): T {
@Suppress("UNCHECKED_CAST")
- return JNIZBytes.deserializeViaJNI(zbytes.into(), this.type) as T
+ return JNIZBytes.deserialize(zbytes.into().bytes, this.type) as T
}
}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerializer.kt b/zenoh-java/src/jvmAndAndroidMain/kotlin/io/zenoh/ext/ZSerializer.kt
similarity index 98%
rename from zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerializer.kt
rename to zenoh-java/src/jvmAndAndroidMain/kotlin/io/zenoh/ext/ZSerializer.kt
index 8ee4a1b7..5f47b7eb 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerializer.kt
+++ b/zenoh-java/src/jvmAndAndroidMain/kotlin/io/zenoh/ext/ZSerializer.kt
@@ -104,6 +104,6 @@ abstract class ZSerializer: TypeToken() {
* Serialize [t] into a [ZBytes].
*/
fun serialize(t: T): ZBytes {
- return JNIZBytes.serializeViaJNI(t as Any, this.type)
+ return ZBytes(JNIZBytes.serialize(t as Any, this.type))
}
}
diff --git a/zenoh-jni-runtime/build.gradle.kts b/zenoh-jni-runtime/build.gradle.kts
new file mode 100644
index 00000000..5e6d4def
--- /dev/null
+++ b/zenoh-jni-runtime/build.gradle.kts
@@ -0,0 +1,252 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+import com.nishtahir.CargoExtension
+
+plugins {
+ kotlin("multiplatform")
+ `maven-publish`
+ signing
+}
+
+val androidEnabled = project.findProperty("android")?.toString()?.toBoolean() == true
+val release = project.findProperty("release")?.toString()?.toBoolean() == true
+
+// If the publication is meant to be done on a remote repository (Maven central).
+// Modifying this property will affect the release workflows!
+val isRemotePublication = project.findProperty("remotePublication")?.toString()?.toBoolean() == true
+
+var buildMode = if (release) BuildMode.RELEASE else BuildMode.DEBUG
+
+if (androidEnabled) {
+ apply(plugin = "com.android.library")
+ apply(plugin = "org.mozilla.rust-android-gradle.rust-android")
+
+ configureCargo()
+ configureAndroid()
+}
+
+kotlin {
+ jvmToolchain(11)
+ jvm {
+ compilations.all {
+ kotlinOptions.jvmTarget = "11"
+ }
+ testRuns["test"].executionTask.configure {
+ val zenohPaths = "../zenoh-jni/target/$buildMode"
+ jvmArgs("-Djava.library.path=$zenohPaths")
+ }
+ if (!androidEnabled) {
+ withJava()
+ }
+ }
+ if (androidEnabled) {
+ androidTarget {
+ publishLibraryVariants("release")
+ }
+ }
+
+ @Suppress("Unused")
+ sourceSets {
+ val commonMain by getting {}
+ // jvmAndAndroidMain is an intermediate source set between commonMain and both jvmMain/androidMain.
+ // It holds code that uses java.lang.reflect.Type — available on JVM and Android (ART),
+ // but absent on Kotlin/Native and Kotlin/JS targets. Placing such code here (rather than
+ // commonMain) ensures those targets can be added in the future without compilation errors.
+ // Note: named jvmAndAndroidMain (not javaMain) to avoid conflicting with the DokkaSourceSetSpec
+ // that Dokka auto-registers for the Java compilation created by withJava().
+ val jvmAndAndroidMain by creating { dependsOn(commonMain) }
+ val commonTest by getting {
+ dependencies {
+ implementation(kotlin("test"))
+ }
+ }
+ if (androidEnabled) {
+ val androidMain by getting { dependsOn(jvmAndAndroidMain) }
+ val androidUnitTest by getting {
+ dependencies {
+ implementation(kotlin("test-junit"))
+ }
+ }
+ }
+ val jvmMain by getting {
+ dependsOn(jvmAndAndroidMain)
+ if (isRemotePublication) {
+ resources.srcDir("../jni-libs").include("*/**")
+ } else {
+ resources.srcDir("../zenoh-jni/target/$buildMode").include(arrayListOf("*.dylib", "*.so", "*.dll"))
+ }
+ }
+
+ val jvmTest by getting {
+ resources.srcDir("../zenoh-jni/target/$buildMode").include(arrayListOf("*.dylib", "*.so", "*.dll"))
+ dependencies {
+ implementation(kotlin("test-junit"))
+ }
+ }
+ }
+
+ publishing {
+ publications.withType {
+ groupId = "org.eclipse.zenoh"
+ artifactId = "zenoh-jni-runtime"
+ version = rootProject.version.toString()
+
+ pom {
+ name.set("Zenoh JNI Runtime")
+ description.set("The Eclipse Zenoh JNI runtime layer for zenoh-java and zenoh-kotlin.")
+ url.set("https://zenoh.io/")
+
+ licenses {
+ license {
+ name.set("Eclipse Public License 2.0 OR Apache License 2.0")
+ url.set("http://www.eclipse.org/legal/epl-2.0")
+ }
+ }
+ developers {
+ developer {
+ id.set("ZettaScale")
+ name.set("ZettaScale Zenoh Team")
+ email.set("zenoh@zettascale.tech")
+ }
+ }
+ scm {
+ connection.set("scm:git:https://github.com/eclipse-zenoh/zenoh-java.git")
+ developerConnection.set("scm:git:https://github.com/eclipse-zenoh/zenoh-java.git")
+ url.set("https://github.com/eclipse-zenoh/zenoh-java")
+ }
+ }
+ }
+ }
+}
+
+signing {
+ isRequired = isRemotePublication
+ useInMemoryPgpKeys(System.getenv("ORG_GPG_SUBKEY_ID"), System.getenv("ORG_GPG_PRIVATE_KEY"), System.getenv("ORG_GPG_PASSPHRASE"))
+ sign(publishing.publications)
+}
+
+tasks.withType().configureEach {
+ dependsOn(tasks.withType())
+}
+
+tasks.withType {
+ doFirst {
+ systemProperty("java.library.path", "../zenoh-jni/target/$buildMode")
+ }
+}
+
+tasks.whenObjectAdded {
+ if ((this.name == "mergeDebugJniLibFolders" || this.name == "mergeReleaseJniLibFolders")) {
+ this.dependsOn("cargoBuild")
+ }
+}
+
+tasks.named("compileKotlinJvm") {
+ dependsOn("buildZenohJni")
+}
+
+tasks.register("buildZenohJni") {
+ doLast {
+ if (!isRemotePublication) {
+ buildZenohJNI(buildMode)
+ }
+ }
+}
+
+fun buildZenohJNI(mode: BuildMode = BuildMode.DEBUG) {
+ val cargoCommand = mutableListOf("cargo", "build")
+
+ if (mode == BuildMode.RELEASE) {
+ cargoCommand.add("--release")
+ }
+
+ val result = project.exec {
+ commandLine(*(cargoCommand.toTypedArray()), "--manifest-path", "../zenoh-jni/Cargo.toml")
+ }
+
+ if (result.exitValue != 0) {
+ throw GradleException("Failed to build Zenoh-JNI.")
+ }
+
+ Thread.sleep(1000)
+}
+
+enum class BuildMode {
+ DEBUG {
+ override fun toString(): String {
+ return "debug"
+ }
+ },
+ RELEASE {
+ override fun toString(): String {
+ return "release"
+ }
+ }
+}
+
+fun Project.configureAndroid() {
+ extensions.configure("android") {
+ namespace = "io.zenoh.jni"
+ compileSdk = 30
+
+ ndkVersion = "26.0.10792818"
+
+ defaultConfig {
+ minSdk = 30
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+
+ buildTypes {
+ getByName("release") {
+ isMinifyEnabled = false
+ }
+ getByName("debug") {
+ isMinifyEnabled = false
+ }
+ }
+ sourceSets {
+ getByName("main") {
+ manifest.srcFile("src/androidMain/AndroidManifest.xml")
+ }
+ }
+ publishing {
+ singleVariant("release") {
+ withSourcesJar()
+ withJavadocJar()
+ }
+ }
+ }
+}
+
+fun Project.configureCargo() {
+ extensions.configure("cargo") {
+ pythonCommand = "python3"
+ module = "../zenoh-jni"
+ libname = "zenoh-jni"
+ targetIncludes = arrayOf("libzenoh_jni.so")
+ targetDirectory = "../zenoh-jni/target/"
+ profile = "release"
+ targets = arrayListOf(
+ "arm",
+ "arm64",
+ "x86",
+ "x86_64",
+ )
+ }
+}
diff --git a/zenoh-jni-runtime/src/androidMain/AndroidManifest.xml b/zenoh-jni-runtime/src/androidMain/AndroidManifest.xml
new file mode 100644
index 00000000..4fb03756
--- /dev/null
+++ b/zenoh-jni-runtime/src/androidMain/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/zenoh-java/src/androidMain/kotlin/io.zenoh/Zenoh.kt b/zenoh-jni-runtime/src/androidMain/kotlin/io/zenoh/ZenohLoad.kt
similarity index 79%
rename from zenoh-java/src/androidMain/kotlin/io.zenoh/Zenoh.kt
rename to zenoh-jni-runtime/src/androidMain/kotlin/io/zenoh/ZenohLoad.kt
index 74d42e51..15de9e38 100644
--- a/zenoh-java/src/androidMain/kotlin/io.zenoh/Zenoh.kt
+++ b/zenoh-jni-runtime/src/androidMain/kotlin/io/zenoh/ZenohLoad.kt
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2023 ZettaScale Technology
+// Copyright (c) 2026 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
@@ -15,10 +15,9 @@
package io.zenoh
/**
- * Static singleton class to load the Zenoh native library once and only once, as well as the logger in function of the
- * log level configuration.
+ * Static singleton class to load the Zenoh native library once and only once.
*/
-internal actual object ZenohLoad {
+public actual object ZenohLoad {
private const val ZENOH_LIB_NAME = "zenoh_jni"
init {
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZenohId.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/ZenohLoad.kt
similarity index 65%
rename from zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZenohId.kt
rename to zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/ZenohLoad.kt
index 53ecb5dc..a2d21403 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZenohId.kt
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/ZenohLoad.kt
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2023 ZettaScale Technology
+// Copyright (c) 2026 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
@@ -12,16 +12,9 @@
// ZettaScale Zenoh Team,
//
-package io.zenoh.jni
+package io.zenoh
-import io.zenoh.ZenohLoad
-
-internal object JNIZenohId {
-
- init {
- ZenohLoad
- }
-
- external fun toStringViaJNI(bytes: ByteArray): String
-
-}
+/**
+ * Static singleton object to load the Zenoh native library once and only once.
+ */
+public expect object ZenohLoad
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/ZError.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/exceptions/ZError.kt
similarity index 92%
rename from zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/ZError.kt
rename to zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/exceptions/ZError.kt
index c63a19ce..1984bd23 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/ZError.kt
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/exceptions/ZError.kt
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2023 ZettaScale Technology
+// Copyright (c) 2026 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
diff --git a/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIAdvancedPublisher.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIAdvancedPublisher.kt
new file mode 100644
index 00000000..62d822f6
--- /dev/null
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIAdvancedPublisher.kt
@@ -0,0 +1,75 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni
+
+import io.zenoh.exceptions.ZError
+import io.zenoh.jni.callbacks.JNIMatchingListenerCallback
+import io.zenoh.jni.callbacks.JNIOnCloseCallback
+
+/**
+ * Adapter class for a native Zenoh AdvancedPublisher.
+ *
+ * @property ptr Raw pointer to the underlying native AdvancedPublisher.
+ */
+public class JNIAdvancedPublisher(private val ptr: Long) {
+
+ @Throws(ZError::class)
+ fun put(payload: ByteArray, encodingId: Int, encodingSchema: String?, attachment: ByteArray?) {
+ putViaJNI(ptr, payload, encodingId, encodingSchema, attachment)
+ }
+
+ @Throws(ZError::class)
+ fun delete(attachment: ByteArray?) {
+ deleteViaJNI(ptr, attachment)
+ }
+
+ @Throws(ZError::class)
+ fun declareMatchingListener(callback: JNIMatchingListenerCallback, onClose: JNIOnCloseCallback): JNIMatchingListener =
+ JNIMatchingListener(declareMatchingListenerViaJNI(ptr, callback, onClose))
+
+ @Throws(ZError::class)
+ fun declareBackgroundMatchingListener(callback: JNIMatchingListenerCallback, onClose: JNIOnCloseCallback) =
+ declareBackgroundMatchingListenerViaJNI(ptr, callback, onClose)
+
+ @Throws(ZError::class)
+ fun getMatchingStatus(): Boolean = getMatchingStatusViaJNI(ptr)
+
+ fun close() {
+ freePtrViaJNI(ptr)
+ }
+
+ @Throws(ZError::class)
+ private external fun putViaJNI(
+ ptr: Long, payload: ByteArray, encodingId: Int, encodingSchema: String?, attachment: ByteArray?
+ )
+
+ @Throws(ZError::class)
+ private external fun deleteViaJNI(ptr: Long, attachment: ByteArray?)
+
+ @Throws(ZError::class)
+ private external fun declareMatchingListenerViaJNI(
+ ptr: Long, callback: JNIMatchingListenerCallback, onClose: JNIOnCloseCallback
+ ): Long
+
+ @Throws(ZError::class)
+ private external fun declareBackgroundMatchingListenerViaJNI(
+ ptr: Long, callback: JNIMatchingListenerCallback, onClose: JNIOnCloseCallback
+ )
+
+ @Throws(ZError::class)
+ private external fun getMatchingStatusViaJNI(ptr: Long): Boolean
+
+ private external fun freePtrViaJNI(ptr: Long)
+}
diff --git a/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIAdvancedSubscriber.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIAdvancedSubscriber.kt
new file mode 100644
index 00000000..084b00f9
--- /dev/null
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIAdvancedSubscriber.kt
@@ -0,0 +1,80 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni
+
+import io.zenoh.exceptions.ZError
+import io.zenoh.jni.callbacks.JNIOnCloseCallback
+import io.zenoh.jni.callbacks.JNISampleMissListenerCallback
+import io.zenoh.jni.callbacks.JNISubscriberCallback
+
+/**
+ * Adapter class for a native Zenoh AdvancedSubscriber.
+ *
+ * @property ptr Raw pointer to the underlying native AdvancedSubscriber.
+ */
+public class JNIAdvancedSubscriber(private val ptr: Long) {
+
+ @Throws(ZError::class)
+ fun declareDetectPublishersSubscriber(
+ history: Boolean,
+ callback: JNISubscriberCallback,
+ onClose: JNIOnCloseCallback,
+ ): JNISubscriber = JNISubscriber(declareDetectPublishersSubscriberViaJNI(ptr, history, callback, onClose))
+
+ @Throws(ZError::class)
+ fun declareBackgroundDetectPublishersSubscriber(
+ history: Boolean,
+ callback: JNISubscriberCallback,
+ onClose: JNIOnCloseCallback,
+ ) = declareBackgroundDetectPublishersSubscriberViaJNI(ptr, history, callback, onClose)
+
+ @Throws(ZError::class)
+ fun declareSampleMissListener(
+ callback: JNISampleMissListenerCallback,
+ onClose: JNIOnCloseCallback,
+ ): JNISampleMissListener = JNISampleMissListener(declareSampleMissListenerViaJNI(ptr, callback, onClose))
+
+ @Throws(ZError::class)
+ fun declareBackgroundSampleMissListener(
+ callback: JNISampleMissListenerCallback,
+ onClose: JNIOnCloseCallback,
+ ) = declareBackgroundSampleMissListenerViaJNI(ptr, callback, onClose)
+
+ fun close() {
+ freePtrViaJNI(ptr)
+ }
+
+ @Throws(ZError::class)
+ private external fun declareDetectPublishersSubscriberViaJNI(
+ ptr: Long, history: Boolean, callback: JNISubscriberCallback, onClose: JNIOnCloseCallback
+ ): Long
+
+ @Throws(ZError::class)
+ private external fun declareBackgroundDetectPublishersSubscriberViaJNI(
+ ptr: Long, history: Boolean, callback: JNISubscriberCallback, onClose: JNIOnCloseCallback
+ )
+
+ @Throws(ZError::class)
+ private external fun declareSampleMissListenerViaJNI(
+ ptr: Long, callback: JNISampleMissListenerCallback, onClose: JNIOnCloseCallback
+ ): Long
+
+ @Throws(ZError::class)
+ private external fun declareBackgroundSampleMissListenerViaJNI(
+ ptr: Long, callback: JNISampleMissListenerCallback, onClose: JNIOnCloseCallback
+ )
+
+ private external fun freePtrViaJNI(ptr: Long)
+}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIConfig.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIConfig.kt
similarity index 56%
rename from zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIConfig.kt
rename to zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIConfig.kt
index ea278988..9cdd403c 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIConfig.kt
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIConfig.kt
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2023 ZettaScale Technology
+// Copyright (c) 2026 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
@@ -14,13 +14,11 @@
package io.zenoh.jni
-import io.zenoh.Config
import io.zenoh.ZenohLoad
import io.zenoh.exceptions.ZError
-import java.io.File
-import java.nio.file.Path
-internal class JNIConfig(internal val ptr: Long) {
+/** Adapter for the native Zenoh config. */
+public class JNIConfig(internal val ptr: Long) {
companion object {
@@ -28,37 +26,17 @@ internal class JNIConfig(internal val ptr: Long) {
ZenohLoad
}
- fun loadDefaultConfig(): Config {
- val cfgPtr = loadDefaultConfigViaJNI()
- return Config(JNIConfig(cfgPtr))
- }
-
@Throws(ZError::class)
- fun loadConfigFile(path: Path): Config {
- val cfgPtr = loadConfigFileViaJNI(path.toString())
- return Config(JNIConfig(cfgPtr))
- }
+ fun loadDefault(): JNIConfig = JNIConfig(loadDefaultConfigViaJNI())
@Throws(ZError::class)
- fun loadConfigFile(file: File): Config = loadConfigFile(file.toPath())
+ fun loadFromFile(path: String): JNIConfig = JNIConfig(loadConfigFileViaJNI(path))
@Throws(ZError::class)
- fun loadJsonConfig(rawConfig: String): Config {
- val cfgPtr = loadJsonConfigViaJNI(rawConfig)
- return Config(JNIConfig(cfgPtr))
- }
+ fun loadFromJson(rawConfig: String): JNIConfig = JNIConfig(loadJsonConfigViaJNI(rawConfig))
@Throws(ZError::class)
- fun loadJson5Config(rawConfig: String): Config {
- val cfgPtr = loadJsonConfigViaJNI(rawConfig)
- return Config(JNIConfig(cfgPtr))
- }
-
- @Throws(ZError::class)
- fun loadYamlConfig(rawConfig: String): Config {
- val cfgPtr = loadYamlConfigViaJNI(rawConfig)
- return Config(JNIConfig(cfgPtr))
- }
+ fun loadFromYaml(rawConfig: String): JNIConfig = JNIConfig(loadYamlConfigViaJNI(rawConfig))
@Throws(ZError::class)
private external fun loadDefaultConfigViaJNI(): Long
@@ -78,7 +56,6 @@ internal class JNIConfig(internal val ptr: Long) {
@Throws(ZError::class)
private external fun insertJson5ViaJNI(ptr: Long, key: String, value: String): Long
- /** Frees the underlying native config. */
private external fun freePtrViaJNI(ptr: Long)
@Throws(ZError::class)
@@ -90,12 +67,13 @@ internal class JNIConfig(internal val ptr: Long) {
}
@Throws(ZError::class)
- fun getJson(key: String): String {
- return getJsonViaJNI(ptr, key)
- }
+ fun getId(): ByteArray = getIdViaJNI(ptr)
+
+ @Throws(ZError::class)
+ fun getJson(key: String): String = getJsonViaJNI(ptr, key)
@Throws(ZError::class)
fun insertJson5(key: String, value: String) {
- insertJson5ViaJNI(this.ptr, key, value)
+ insertJson5ViaJNI(ptr, key, value)
}
}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt
similarity index 52%
rename from zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt
rename to zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt
index 29e419e3..c13395c2 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2023 ZettaScale Technology
+// Copyright (c) 2026 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
@@ -16,10 +16,9 @@ package io.zenoh.jni
import io.zenoh.ZenohLoad
import io.zenoh.exceptions.ZError
-import io.zenoh.keyexpr.KeyExpr
-import io.zenoh.keyexpr.SetIntersectionLevel
-internal class JNIKeyExpr(internal val ptr: Long) {
+/** Adapter for native Zenoh key expressions. */
+public class JNIKeyExpr(internal val ptr: Long) {
companion object {
init {
@@ -27,57 +26,37 @@ internal class JNIKeyExpr(internal val ptr: Long) {
}
@Throws(ZError::class)
- fun tryFrom(keyExpr: String): KeyExpr {
- return KeyExpr(tryFromViaJNI(keyExpr))
- }
+ fun tryFrom(keyExpr: String): String = tryFromViaJNI(keyExpr)
@Throws(ZError::class)
- fun autocanonize(keyExpr: String): KeyExpr {
- return KeyExpr(autocanonizeViaJNI(keyExpr))
- }
+ fun autocanonize(keyExpr: String): String = autocanonizeViaJNI(keyExpr)
@Throws(ZError::class)
- fun intersects(keyExprA: KeyExpr, keyExprB: KeyExpr): Boolean = intersectsViaJNI(
- keyExprA.jniKeyExpr?.ptr ?: 0,
- keyExprA.keyExpr,
- keyExprB.jniKeyExpr?.ptr ?: 0,
- keyExprB.keyExpr
- )
+ private external fun tryFromViaJNI(keyExpr: String): String
@Throws(ZError::class)
- fun includes(keyExprA: KeyExpr, keyExprB: KeyExpr): Boolean = includesViaJNI(
- keyExprA.jniKeyExpr?.ptr ?: 0,
- keyExprA.keyExpr,
- keyExprB.jniKeyExpr?.ptr ?: 0,
- keyExprB.keyExpr
- )
+ private external fun autocanonizeViaJNI(keyExpr: String): String
@Throws(ZError::class)
- fun relationTo(keyExpr: KeyExpr, other: KeyExpr): SetIntersectionLevel {
- val intersection = relationToViaJNI(
- keyExpr.jniKeyExpr?.ptr ?: 0,
- keyExpr.keyExpr,
- other.jniKeyExpr?.ptr ?: 0,
- other.keyExpr
- )
- return SetIntersectionLevel.fromInt(intersection)
- }
+ fun intersects(a: JNIKeyExpr?, aStr: String, b: JNIKeyExpr?, bStr: String): Boolean =
+ intersectsViaJNI(a?.ptr ?: 0, aStr, b?.ptr ?: 0, bStr)
@Throws(ZError::class)
- fun joinViaJNI(keyExpr: KeyExpr, other: String): KeyExpr {
- return KeyExpr(joinViaJNI(keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, other))
- }
+ fun includes(a: JNIKeyExpr?, aStr: String, b: JNIKeyExpr?, bStr: String): Boolean =
+ includesViaJNI(a?.ptr ?: 0, aStr, b?.ptr ?: 0, bStr)
+ /** Returns SetIntersectionLevel ordinal as Int. Callers convert to SetIntersectionLevel. */
@Throws(ZError::class)
- fun concatViaJNI(keyExpr: KeyExpr, other: String): KeyExpr {
- return KeyExpr(concatViaJNI(keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, other))
- }
+ fun relationTo(a: JNIKeyExpr?, aStr: String, b: JNIKeyExpr?, bStr: String): Int =
+ relationToViaJNI(a?.ptr ?: 0, aStr, b?.ptr ?: 0, bStr)
@Throws(ZError::class)
- private external fun tryFromViaJNI(keyExpr: String): String
+ fun join(a: JNIKeyExpr?, aStr: String, other: String): String =
+ joinViaJNI(a?.ptr ?: 0, aStr, other)
@Throws(ZError::class)
- private external fun autocanonizeViaJNI(keyExpr: String): String
+ fun concat(a: JNIKeyExpr?, aStr: String, other: String): String =
+ concatViaJNI(a?.ptr ?: 0, aStr, other)
@Throws(ZError::class)
private external fun intersectsViaJNI(ptrA: Long, keyExprA: String, ptrB: Long, keyExprB: String): Boolean
@@ -99,6 +78,5 @@ internal class JNIKeyExpr(internal val ptr: Long) {
freePtrViaJNI(ptr)
}
- /** Frees the underlying native KeyExpr. */
private external fun freePtrViaJNI(ptr: Long)
}
diff --git a/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNILivelinessToken.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNILivelinessToken.kt
new file mode 100644
index 00000000..1f88d3ad
--- /dev/null
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNILivelinessToken.kt
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni
+
+/** Adapter class for a native Zenoh LivelinessToken. */
+public class JNILivelinessToken(private val ptr: Long) {
+
+ fun undeclare() {
+ undeclareViaJNI(ptr)
+ }
+
+ private external fun undeclareViaJNI(ptr: Long)
+}
diff --git a/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNILogger.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNILogger.kt
new file mode 100644
index 00000000..47c0de53
--- /dev/null
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNILogger.kt
@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni
+
+import io.zenoh.ZenohLoad
+import io.zenoh.exceptions.ZError
+
+/** Adapter for initializing Rust logging through JNI. */
+public object JNILogger {
+
+ init {
+ ZenohLoad
+ }
+
+ /**
+ * Redirects Rust logs either to logcat (Android) or standard output.
+ *
+ * See https://docs.rs/env_logger/latest/env_logger/index.html for accepted filter format.
+ */
+ @Throws(ZError::class)
+ fun startLogs(filter: String) = startLogsViaJNI(filter)
+
+ @Throws(ZError::class)
+ private external fun startLogsViaJNI(filter: String)
+}
diff --git a/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIMatchingListener.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIMatchingListener.kt
new file mode 100644
index 00000000..7c58edee
--- /dev/null
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIMatchingListener.kt
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni
+
+/** Adapter class for a native Zenoh MatchingListener. */
+public class JNIMatchingListener(private val ptr: Long) {
+
+ fun close() {
+ freePtrViaJNI(ptr)
+ }
+
+ private external fun freePtrViaJNI(ptr: Long)
+}
diff --git a/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt
new file mode 100644
index 00000000..7f800597
--- /dev/null
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt
@@ -0,0 +1,49 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni
+
+import io.zenoh.exceptions.ZError
+
+/**
+ * Adapter class for a native Zenoh publisher. Uses primitive types for put/delete.
+ *
+ * @property ptr Raw pointer to the underlying native Publisher.
+ */
+public class JNIPublisher(private val ptr: Long) {
+
+ @Throws(ZError::class)
+ fun put(payload: ByteArray, encodingId: Int, encodingSchema: String?, attachment: ByteArray?) {
+ putViaJNI(ptr, payload, encodingId, encodingSchema, attachment)
+ }
+
+ @Throws(ZError::class)
+ fun delete(attachment: ByteArray?) {
+ deleteViaJNI(ptr, attachment)
+ }
+
+ fun close() {
+ freePtrViaJNI(ptr)
+ }
+
+ @Throws(ZError::class)
+ private external fun putViaJNI(
+ ptr: Long, valuePayload: ByteArray, encodingId: Int, encodingSchema: String?, attachment: ByteArray?
+ )
+
+ @Throws(ZError::class)
+ private external fun deleteViaJNI(ptr: Long, attachment: ByteArray?)
+
+ private external fun freePtrViaJNI(ptr: Long)
+}
diff --git a/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIQuerier.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIQuerier.kt
new file mode 100644
index 00000000..7757c086
--- /dev/null
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIQuerier.kt
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni
+
+import io.zenoh.exceptions.ZError
+import io.zenoh.jni.callbacks.JNIGetCallback
+import io.zenoh.jni.callbacks.JNIOnCloseCallback
+
+/** Adapter class for a native Zenoh querier. */
+public class JNIQuerier(private val ptr: Long) {
+
+ @Throws(ZError::class)
+ fun get(
+ jniKeyExpr: JNIKeyExpr?,
+ keyExprString: String,
+ parameters: String?,
+ callback: JNIGetCallback,
+ onClose: JNIOnCloseCallback,
+ attachmentBytes: ByteArray?,
+ payload: ByteArray?,
+ encodingId: Int,
+ encodingSchema: String?,
+ ) {
+ getViaJNI(ptr, jniKeyExpr?.ptr ?: 0, keyExprString, parameters, callback, onClose, attachmentBytes, payload, encodingId, encodingSchema)
+ }
+
+ @Throws(ZError::class)
+ private external fun getViaJNI(
+ querierPtr: Long,
+ keyExprPtr: Long,
+ keyExprString: String,
+ parameters: String?,
+ callback: JNIGetCallback,
+ onClose: JNIOnCloseCallback,
+ attachmentBytes: ByteArray?,
+ payload: ByteArray?,
+ encodingId: Int,
+ encodingSchema: String?,
+ )
+
+ private external fun freePtrViaJNI(ptr: Long)
+
+ fun close() {
+ freePtrViaJNI(ptr)
+ }
+}
diff --git a/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt
new file mode 100644
index 00000000..78bd5dc3
--- /dev/null
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt
@@ -0,0 +1,96 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni
+
+import io.zenoh.exceptions.ZError
+
+/**
+ * Adapter class for interacting with a native Zenoh Query using JNI.
+ *
+ * @property ptr The raw pointer to the underlying native query.
+ */
+public class JNIQuery(private val ptr: Long) {
+
+ @Throws(ZError::class)
+ fun replySuccess(
+ jniKeyExpr: JNIKeyExpr?,
+ keyExprString: String,
+ payload: ByteArray,
+ encodingId: Int,
+ encodingSchema: String?,
+ timestampEnabled: Boolean,
+ timestampNtp64: Long,
+ attachment: ByteArray?,
+ qosExpress: Boolean,
+ ) {
+ replySuccessViaJNI(ptr, jniKeyExpr?.ptr ?: 0, keyExprString, payload, encodingId, encodingSchema, timestampEnabled, timestampNtp64, attachment, qosExpress)
+ }
+
+ @Throws(ZError::class)
+ fun replyError(errorPayload: ByteArray, encodingId: Int, encodingSchema: String?) {
+ replyErrorViaJNI(ptr, errorPayload, encodingId, encodingSchema)
+ }
+
+ @Throws(ZError::class)
+ fun replyDelete(
+ jniKeyExpr: JNIKeyExpr?,
+ keyExprString: String,
+ timestampEnabled: Boolean,
+ timestampNtp64: Long,
+ attachment: ByteArray?,
+ qosExpress: Boolean,
+ ) {
+ replyDeleteViaJNI(ptr, jniKeyExpr?.ptr ?: 0, keyExprString, timestampEnabled, timestampNtp64, attachment, qosExpress)
+ }
+
+ fun close() {
+ freePtrViaJNI(ptr)
+ }
+
+ @Throws(ZError::class)
+ private external fun replySuccessViaJNI(
+ queryPtr: Long,
+ keyExprPtr: Long,
+ keyExprString: String,
+ valuePayload: ByteArray,
+ valueEncodingId: Int,
+ valueEncodingSchema: String?,
+ timestampEnabled: Boolean,
+ timestampNtp64: Long,
+ attachment: ByteArray?,
+ qosExpress: Boolean,
+ )
+
+ @Throws(ZError::class)
+ private external fun replyErrorViaJNI(
+ queryPtr: Long,
+ errorValuePayload: ByteArray,
+ errorValueEncoding: Int,
+ encodingSchema: String?,
+ )
+
+ @Throws(ZError::class)
+ private external fun replyDeleteViaJNI(
+ queryPtr: Long,
+ keyExprPtr: Long,
+ keyExprString: String,
+ timestampEnabled: Boolean,
+ timestampNtp64: Long,
+ attachment: ByteArray?,
+ qosExpress: Boolean,
+ )
+
+ private external fun freePtrViaJNI(ptr: Long)
+}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQueryable.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIQueryable.kt
similarity index 79%
rename from zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQueryable.kt
rename to zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIQueryable.kt
index e5f7d3ce..ba64f7e9 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQueryable.kt
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIQueryable.kt
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2023 ZettaScale Technology
+// Copyright (c) 2026 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
@@ -15,16 +15,15 @@
package io.zenoh.jni
/**
- * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.query.Queryable]
+ * Adapter class to handle the interactions with Zenoh through JNI for a Queryable.
*
* @property ptr: raw pointer to the underlying native Queryable.
*/
-internal class JNIQueryable(val ptr: Long) {
+public class JNIQueryable(private val ptr: Long) {
fun close() {
freePtrViaJNI(ptr)
}
- /** Frees the underlying native Queryable. */
private external fun freePtrViaJNI(ptr: Long)
}
diff --git a/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNISampleMissListener.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNISampleMissListener.kt
new file mode 100644
index 00000000..dea27edf
--- /dev/null
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNISampleMissListener.kt
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni
+
+/** Adapter class for a native Zenoh SampleMissListener. */
+public class JNISampleMissListener(private val ptr: Long) {
+
+ fun close() {
+ freePtrViaJNI(ptr)
+ }
+
+ private external fun freePtrViaJNI(ptr: Long)
+}
diff --git a/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt
new file mode 100644
index 00000000..1b3d1bd0
--- /dev/null
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt
@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni
+
+import io.zenoh.ZenohLoad
+import io.zenoh.exceptions.ZError
+import io.zenoh.jni.callbacks.JNIOnCloseCallback
+import io.zenoh.jni.callbacks.JNIScoutCallback
+
+/**
+ * Adapter class to handle the interactions with Zenoh through JNI for a Scout.
+ *
+ * @property ptr: raw pointer to the underlying native scout.
+ */
+public class JNIScout(private val ptr: Long) {
+
+ companion object {
+ init {
+ ZenohLoad
+ }
+
+ @Throws(ZError::class)
+ fun scout(
+ whatAmI: Int,
+ callback: JNIScoutCallback,
+ onClose: JNIOnCloseCallback,
+ config: JNIConfig?,
+ ): JNIScout = JNIScout(scoutViaJNI(whatAmI, callback, onClose, config?.ptr ?: 0))
+
+ @Throws(ZError::class)
+ private external fun scoutViaJNI(
+ whatAmI: Int,
+ callback: JNIScoutCallback,
+ onClose: JNIOnCloseCallback,
+ configPtr: Long,
+ ): Long
+
+ private external fun freePtrViaJNI(ptr: Long)
+ }
+
+ fun close() {
+ freePtrViaJNI(ptr)
+ }
+}
diff --git a/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt
new file mode 100644
index 00000000..688b3eb0
--- /dev/null
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt
@@ -0,0 +1,375 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni
+
+import io.zenoh.ZenohLoad
+import io.zenoh.exceptions.ZError
+import io.zenoh.jni.callbacks.JNIGetCallback
+import io.zenoh.jni.callbacks.JNIOnCloseCallback
+import io.zenoh.jni.callbacks.JNIQueryableCallback
+import io.zenoh.jni.callbacks.JNISubscriberCallback
+
+/** Adapter class to handle communication with the Zenoh JNI code for a Session. */
+public class JNISession(internal val sessionPtr: Long) {
+
+ companion object {
+ init {
+ ZenohLoad
+ }
+
+ @Throws(ZError::class)
+ fun open(config: JNIConfig): JNISession {
+ val sessionPtr = openSessionViaJNI(config.ptr)
+ return JNISession(sessionPtr)
+ }
+
+ @JvmStatic
+ @Throws(ZError::class)
+ private external fun openSessionViaJNI(configPtr: Long): Long
+ }
+
+ @Throws(ZError::class)
+ private external fun closeSessionViaJNI(ptr: Long)
+
+ @Throws(ZError::class)
+ fun declarePublisher(
+ jniKeyExpr: JNIKeyExpr?,
+ keyExprString: String,
+ congestionControl: Int,
+ priority: Int,
+ express: Boolean,
+ reliability: Int
+ ): JNIPublisher = JNIPublisher(declarePublisherViaJNI(sessionPtr, jniKeyExpr?.ptr ?: 0, keyExprString, congestionControl, priority, express, reliability))
+
+ @Throws(ZError::class)
+ private external fun declarePublisherViaJNI(
+ sessionPtr: Long,
+ keyExprPtr: Long,
+ keyExprString: String,
+ congestionControl: Int,
+ priority: Int,
+ express: Boolean,
+ reliability: Int
+ ): Long
+
+ @Throws(ZError::class)
+ fun declareSubscriber(
+ jniKeyExpr: JNIKeyExpr?,
+ keyExprString: String,
+ callback: JNISubscriberCallback,
+ onClose: JNIOnCloseCallback,
+ ): JNISubscriber = JNISubscriber(declareSubscriberViaJNI(sessionPtr, jniKeyExpr?.ptr ?: 0, keyExprString, callback, onClose))
+
+ @Throws(ZError::class)
+ private external fun declareSubscriberViaJNI(
+ sessionPtr: Long,
+ keyExprPtr: Long,
+ keyExprString: String,
+ callback: JNISubscriberCallback,
+ onClose: JNIOnCloseCallback,
+ ): Long
+
+ @Throws(ZError::class)
+ fun declareQueryable(
+ jniKeyExpr: JNIKeyExpr?,
+ keyExprString: String,
+ callback: JNIQueryableCallback,
+ onClose: JNIOnCloseCallback,
+ complete: Boolean
+ ): JNIQueryable = JNIQueryable(declareQueryableViaJNI(sessionPtr, jniKeyExpr?.ptr ?: 0, keyExprString, callback, onClose, complete))
+
+ @Throws(ZError::class)
+ private external fun declareQueryableViaJNI(
+ sessionPtr: Long,
+ keyExprPtr: Long,
+ keyExprString: String,
+ callback: JNIQueryableCallback,
+ onClose: JNIOnCloseCallback,
+ complete: Boolean
+ ): Long
+
+ @Throws(ZError::class)
+ fun declareQuerier(
+ jniKeyExpr: JNIKeyExpr?,
+ keyExprString: String,
+ target: Int,
+ consolidation: Int,
+ congestionControl: Int,
+ priority: Int,
+ express: Boolean,
+ timeoutMs: Long,
+ acceptReplies: Int
+ ): JNIQuerier = JNIQuerier(declareQuerierViaJNI(sessionPtr, jniKeyExpr?.ptr ?: 0, keyExprString, target, consolidation, congestionControl, priority, express, timeoutMs, acceptReplies))
+
+ @Throws(ZError::class)
+ private external fun declareQuerierViaJNI(
+ sessionPtr: Long,
+ keyExprPtr: Long,
+ keyExprString: String,
+ target: Int,
+ consolidation: Int,
+ congestionControl: Int,
+ priority: Int,
+ express: Boolean,
+ timeoutMs: Long,
+ acceptReplies: Int
+ ): Long
+
+ @Throws(ZError::class)
+ fun declareKeyExpr(keyExpr: String): JNIKeyExpr = JNIKeyExpr(declareKeyExprViaJNI(sessionPtr, keyExpr))
+
+ @Throws(ZError::class)
+ private external fun declareKeyExprViaJNI(sessionPtr: Long, keyExpr: String): Long
+
+ @Throws(ZError::class)
+ fun undeclareKeyExpr(jniKeyExpr: JNIKeyExpr) = undeclareKeyExprViaJNI(sessionPtr, jniKeyExpr.ptr)
+
+ @Throws(ZError::class)
+ private external fun undeclareKeyExprViaJNI(sessionPtr: Long, keyExprPtr: Long)
+
+ @Throws(ZError::class)
+ fun get(
+ jniKeyExpr: JNIKeyExpr?,
+ keyExprString: String,
+ selectorParams: String?,
+ callback: JNIGetCallback,
+ onClose: JNIOnCloseCallback,
+ timeoutMs: Long,
+ target: Int,
+ consolidation: Int,
+ attachmentBytes: ByteArray?,
+ payload: ByteArray?,
+ encodingId: Int,
+ encodingSchema: String?,
+ congestionControl: Int,
+ priority: Int,
+ express: Boolean,
+ acceptReplies: Int,
+ ) = getViaJNI(sessionPtr, jniKeyExpr?.ptr ?: 0, keyExprString, selectorParams, callback, onClose, timeoutMs, target, consolidation, attachmentBytes, payload, encodingId, encodingSchema, congestionControl, priority, express, acceptReplies)
+
+ @Throws(ZError::class)
+ private external fun getViaJNI(
+ sessionPtr: Long,
+ keyExprPtr: Long,
+ keyExprString: String,
+ selectorParams: String?,
+ callback: JNIGetCallback,
+ onClose: JNIOnCloseCallback,
+ timeoutMs: Long,
+ target: Int,
+ consolidation: Int,
+ attachmentBytes: ByteArray?,
+ payload: ByteArray?,
+ encodingId: Int,
+ encodingSchema: String?,
+ congestionControl: Int,
+ priority: Int,
+ express: Boolean,
+ acceptReplies: Int,
+ )
+
+ @Throws(ZError::class)
+ fun put(
+ jniKeyExpr: JNIKeyExpr?,
+ keyExprString: String,
+ valuePayload: ByteArray,
+ valueEncoding: Int,
+ valueEncodingSchema: String?,
+ congestionControl: Int,
+ priority: Int,
+ express: Boolean,
+ attachmentBytes: ByteArray?,
+ reliability: Int
+ ) = putViaJNI(sessionPtr, jniKeyExpr?.ptr ?: 0, keyExprString, valuePayload, valueEncoding, valueEncodingSchema, congestionControl, priority, express, attachmentBytes, reliability)
+
+ @Throws(ZError::class)
+ private external fun putViaJNI(
+ sessionPtr: Long,
+ keyExprPtr: Long,
+ keyExprString: String,
+ valuePayload: ByteArray,
+ valueEncoding: Int,
+ valueEncodingSchema: String?,
+ congestionControl: Int,
+ priority: Int,
+ express: Boolean,
+ attachmentBytes: ByteArray?,
+ reliability: Int
+ )
+
+ @Throws(ZError::class)
+ fun delete(
+ jniKeyExpr: JNIKeyExpr?,
+ keyExprString: String,
+ congestionControl: Int,
+ priority: Int,
+ express: Boolean,
+ attachmentBytes: ByteArray?,
+ reliability: Int
+ ) = deleteViaJNI(sessionPtr, jniKeyExpr?.ptr ?: 0, keyExprString, congestionControl, priority, express, attachmentBytes, reliability)
+
+ @Throws(ZError::class)
+ private external fun deleteViaJNI(
+ sessionPtr: Long,
+ keyExprPtr: Long,
+ keyExprString: String,
+ congestionControl: Int,
+ priority: Int,
+ express: Boolean,
+ attachmentBytes: ByteArray?,
+ reliability: Int
+ )
+
+ @Throws(ZError::class)
+ fun getZid(): ByteArray = getZidViaJNI(sessionPtr)
+
+ @Throws(ZError::class)
+ private external fun getZidViaJNI(ptr: Long): ByteArray
+
+ @Throws(ZError::class)
+ fun getPeersZid(): List = getPeersZidViaJNI(sessionPtr)
+
+ @Throws(ZError::class)
+ private external fun getPeersZidViaJNI(ptr: Long): List
+
+ @Throws(ZError::class)
+ fun getRoutersZid(): List = getRoutersZidViaJNI(sessionPtr)
+
+ @Throws(ZError::class)
+ private external fun getRoutersZidViaJNI(ptr: Long): List
+
+ @Throws(ZError::class)
+ fun declareAdvancedSubscriber(
+ jniKeyExpr: JNIKeyExpr?,
+ keyExprStr: String,
+ historyConfigEnabled: Boolean,
+ historyDetectLatePublishers: Boolean,
+ historyMaxSamples: Long,
+ historyMaxAgeSeconds: Double,
+ recoveryConfigEnabled: Boolean,
+ recoveryConfigIsHeartbeat: Boolean,
+ recoveryQueryPeriodMs: Long,
+ subscriberDetection: Boolean,
+ callback: JNISubscriberCallback,
+ onClose: JNIOnCloseCallback,
+ ): JNIAdvancedSubscriber = JNIAdvancedSubscriber(declareAdvancedSubscriberViaJNI(sessionPtr, jniKeyExpr?.ptr ?: 0, keyExprStr, historyConfigEnabled, historyDetectLatePublishers, historyMaxSamples, historyMaxAgeSeconds, recoveryConfigEnabled, recoveryConfigIsHeartbeat, recoveryQueryPeriodMs, subscriberDetection, callback, onClose))
+
+ @Throws(ZError::class)
+ private external fun declareAdvancedSubscriberViaJNI(
+ sessionPtr: Long,
+ keyExprPtr: Long,
+ keyExprStr: String,
+ historyConfigEnabled: Boolean,
+ historyDetectLatePublishers: Boolean,
+ historyMaxSamples: Long,
+ historyMaxAgeSeconds: Double,
+ recoveryConfigEnabled: Boolean,
+ recoveryConfigIsHeartbeat: Boolean,
+ recoveryQueryPeriodMs: Long,
+ subscriberDetection: Boolean,
+ callback: JNISubscriberCallback,
+ onClose: JNIOnCloseCallback,
+ ): Long
+
+ @Throws(ZError::class)
+ fun declareAdvancedPublisher(
+ jniKeyExpr: JNIKeyExpr?,
+ keyExprStr: String,
+ congestionControl: Int,
+ priority: Int,
+ isExpress: Boolean,
+ reliability: Int,
+ cacheEnabled: Boolean,
+ cacheMaxSamples: Long,
+ cacheRepliesPriority: Int,
+ cacheRepliesCongestionControl: Int,
+ cacheRepliesIsExpress: Boolean,
+ sampleMissDetectionEnabled: Boolean,
+ sampleMissDetectionEnableHeartbeat: Boolean,
+ sampleMissDetectionHeartbeatMs: Long,
+ sampleMissDetectionHeartbeatIsSporadic: Boolean,
+ publisherDetection: Boolean,
+ ): JNIAdvancedPublisher = JNIAdvancedPublisher(declareAdvancedPublisherViaJNI(sessionPtr, jniKeyExpr?.ptr ?: 0, keyExprStr, congestionControl, priority, isExpress, reliability, cacheEnabled, cacheMaxSamples, cacheRepliesPriority, cacheRepliesCongestionControl, cacheRepliesIsExpress, sampleMissDetectionEnabled, sampleMissDetectionEnableHeartbeat, sampleMissDetectionHeartbeatMs, sampleMissDetectionHeartbeatIsSporadic, publisherDetection))
+
+ @Throws(ZError::class)
+ private external fun declareAdvancedPublisherViaJNI(
+ sessionPtr: Long,
+ keyExprPtr: Long,
+ keyExprStr: String,
+ congestionControl: Int,
+ priority: Int,
+ isExpress: Boolean,
+ reliability: Int,
+ cacheEnabled: Boolean,
+ cacheMaxSamples: Long,
+ cacheRepliesPriority: Int,
+ cacheRepliesCongestionControl: Int,
+ cacheRepliesIsExpress: Boolean,
+ sampleMissDetectionEnabled: Boolean,
+ sampleMissDetectionEnableHeartbeat: Boolean,
+ sampleMissDetectionHeartbeatMs: Long,
+ sampleMissDetectionHeartbeatIsSporadic: Boolean,
+ publisherDetection: Boolean,
+ ): Long
+
+ @Throws(ZError::class)
+ fun declareLivelinessToken(jniKeyExpr: JNIKeyExpr?, keyExprString: String): JNILivelinessToken =
+ JNILivelinessToken(declareLivelinessTokenViaJNI(sessionPtr, jniKeyExpr?.ptr ?: 0, keyExprString))
+
+ @Throws(ZError::class)
+ private external fun declareLivelinessTokenViaJNI(sessionPtr: Long, keyExprPtr: Long, keyExprString: String): Long
+
+ @Throws(ZError::class)
+ fun declareLivelinessSubscriber(
+ jniKeyExpr: JNIKeyExpr?,
+ keyExprString: String,
+ callback: JNISubscriberCallback,
+ history: Boolean,
+ onClose: JNIOnCloseCallback,
+ ): JNISubscriber = JNISubscriber(declareLivelinessSubscriberViaJNI(sessionPtr, jniKeyExpr?.ptr ?: 0, keyExprString, callback, history, onClose))
+
+ @Throws(ZError::class)
+ private external fun declareLivelinessSubscriberViaJNI(
+ sessionPtr: Long,
+ keyExprPtr: Long,
+ keyExprString: String,
+ callback: JNISubscriberCallback,
+ history: Boolean,
+ onClose: JNIOnCloseCallback,
+ ): Long
+
+ @Throws(ZError::class)
+ fun livelinessGet(
+ jniKeyExpr: JNIKeyExpr?,
+ keyExprString: String,
+ callback: JNIGetCallback,
+ timeoutMs: Long,
+ onClose: JNIOnCloseCallback,
+ ) = livelinessGetViaJNI(sessionPtr, jniKeyExpr?.ptr ?: 0, keyExprString, callback, timeoutMs, onClose)
+
+ @Throws(ZError::class)
+ private external fun livelinessGetViaJNI(
+ sessionPtr: Long,
+ keyExprPtr: Long,
+ keyExprString: String,
+ callback: JNIGetCallback,
+ timeoutMs: Long,
+ onClose: JNIOnCloseCallback,
+ )
+
+ fun close() {
+ closeSessionViaJNI(sessionPtr)
+ }
+}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISubscriber.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNISubscriber.kt
similarity index 78%
rename from zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISubscriber.kt
rename to zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNISubscriber.kt
index 1bb80543..b9877d70 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISubscriber.kt
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNISubscriber.kt
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2023 ZettaScale Technology
+// Copyright (c) 2026 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
@@ -15,17 +15,15 @@
package io.zenoh.jni
/**
- * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.pubsub.Subscriber]
+ * Adapter class to handle the interactions with Zenoh through JNI for a Subscriber.
*
* @property ptr: raw pointer to the underlying native Subscriber.
*/
-internal class JNISubscriber(private val ptr: Long) {
+public class JNISubscriber(private val ptr: Long) {
fun close() {
freePtrViaJNI(ptr)
}
- /** Frees the underlying native Subscriber. */
private external fun freePtrViaJNI(ptr: Long)
-
}
diff --git a/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIZenohId.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIZenohId.kt
new file mode 100644
index 00000000..0eb1f394
--- /dev/null
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIZenohId.kt
@@ -0,0 +1,29 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni
+
+import io.zenoh.ZenohLoad
+
+/** Adapter object for interacting with Zenoh IDs through JNI. */
+public object JNIZenohId {
+
+ init {
+ ZenohLoad
+ }
+
+ fun toString(bytes: ByteArray): String = toStringViaJNI(bytes)
+
+ private external fun toStringViaJNI(bytes: ByteArray): String
+}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIGetCallback.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIGetCallback.kt
similarity index 91%
rename from zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIGetCallback.kt
rename to zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIGetCallback.kt
index 14f3c8e9..fe7da688 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIGetCallback.kt
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIGetCallback.kt
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2023 ZettaScale Technology
+// Copyright (c) 2026 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
@@ -14,7 +14,7 @@
package io.zenoh.jni.callbacks
-internal fun interface JNIGetCallback {
+public fun interface JNIGetCallback {
fun run(
replierZid: ByteArray?,
diff --git a/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIMatchingListenerCallback.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIMatchingListenerCallback.kt
new file mode 100644
index 00000000..4b133b08
--- /dev/null
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIMatchingListenerCallback.kt
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni.callbacks
+
+/** Callback for matching listener notifications; receives true when matching subscribers exist. */
+public fun interface JNIMatchingListenerCallback {
+ fun run(matching: Boolean)
+}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIOnCloseCallback.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIOnCloseCallback.kt
similarity index 84%
rename from zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIOnCloseCallback.kt
rename to zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIOnCloseCallback.kt
index b58fa23d..62760b54 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIOnCloseCallback.kt
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIOnCloseCallback.kt
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2023 ZettaScale Technology
+// Copyright (c) 2026 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
@@ -14,7 +14,7 @@
package io.zenoh.jni.callbacks
-internal fun interface JNIOnCloseCallback {
+public fun interface JNIOnCloseCallback {
fun run()
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIQueryableCallback.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIQueryableCallback.kt
similarity index 56%
rename from zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIQueryableCallback.kt
rename to zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIQueryableCallback.kt
index addf1430..8dc3bce8 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIQueryableCallback.kt
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIQueryableCallback.kt
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2023 ZettaScale Technology
+// Copyright (c) 2026 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
@@ -14,13 +14,15 @@
package io.zenoh.jni.callbacks
-internal fun interface JNIQueryableCallback {
- fun run(keyExpr: String,
- selectorParams: String,
- payload: ByteArray?,
- encodingId: Int,
- encodingSchema: String?,
- attachmentBytes: ByteArray?,
- queryPtr: Long,
- acceptReplies: Int)
+public fun interface JNIQueryableCallback {
+ fun run(
+ keyExpr: String,
+ selectorParams: String,
+ payload: ByteArray?,
+ encodingId: Int,
+ encodingSchema: String?,
+ attachmentBytes: ByteArray?,
+ queryPtr: Long,
+ acceptReplies: Int,
+ )
}
diff --git a/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNISampleMissListenerCallback.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNISampleMissListenerCallback.kt
new file mode 100644
index 00000000..bc5f09cc
--- /dev/null
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNISampleMissListenerCallback.kt
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni.callbacks
+
+/** Callback for sample miss listener notifications. Parameters encode the source entity global id and missed count. */
+public fun interface JNISampleMissListenerCallback {
+ fun run(zidLower: Long, zidUpper: Long, eid: Long, nb: Long)
+}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIScoutCallback.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIScoutCallback.kt
similarity index 85%
rename from zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIScoutCallback.kt
rename to zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIScoutCallback.kt
index 0a8b20e9..57e2390f 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIScoutCallback.kt
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIScoutCallback.kt
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2023 ZettaScale Technology
+// Copyright (c) 2026 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
@@ -14,7 +14,7 @@
package io.zenoh.jni.callbacks
-internal fun interface JNIScoutCallback {
+public fun interface JNIScoutCallback {
fun run(whatAmI: Int, zid: ByteArray, locators: List)
}
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNISubscriberCallback.kt b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNISubscriberCallback.kt
similarity index 89%
rename from zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNISubscriberCallback.kt
rename to zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNISubscriberCallback.kt
index 76373c72..013fc6ac 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNISubscriberCallback.kt
+++ b/zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNISubscriberCallback.kt
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2023 ZettaScale Technology
+// Copyright (c) 2026 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
@@ -14,7 +14,7 @@
package io.zenoh.jni.callbacks
-internal fun interface JNISubscriberCallback {
+public fun interface JNISubscriberCallback {
fun run(
keyExpr: String,
payload: ByteArray,
diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZBytes.kt b/zenoh-jni-runtime/src/jvmAndAndroidMain/kotlin/io/zenoh/jni/JNIZBytes.kt
similarity index 64%
rename from zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZBytes.kt
rename to zenoh-jni-runtime/src/jvmAndAndroidMain/kotlin/io/zenoh/jni/JNIZBytes.kt
index 799b9cac..f9690eec 100644
--- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZBytes.kt
+++ b/zenoh-jni-runtime/src/jvmAndAndroidMain/kotlin/io/zenoh/jni/JNIZBytes.kt
@@ -15,19 +15,21 @@
package io.zenoh.jni
import io.zenoh.ZenohLoad
-import io.zenoh.bytes.ZBytes
import java.lang.reflect.Type
-@PublishedApi
-internal object JNIZBytes {
+object JNIZBytes {
init {
ZenohLoad
}
+ fun serialize(any: Any, type: Type): ByteArray = serializeViaJNI(any, type)
+
+ fun deserialize(bytes: ByteArray, type: Type): Any = deserializeViaJNI(bytes, type)
+
@JvmStatic
- external fun serializeViaJNI(any: Any, type: Type): ZBytes
+ private external fun serializeViaJNI(any: Any, type: Type): ByteArray
@JvmStatic
- external fun deserializeViaJNI(zBytes: ZBytes, type: Type): Any
+ private external fun deserializeViaJNI(bytes: ByteArray, type: Type): Any
}
diff --git a/zenoh-jni-runtime/src/jvmAndAndroidMain/kotlin/io/zenoh/jni/JNIZBytesKotlin.kt b/zenoh-jni-runtime/src/jvmAndAndroidMain/kotlin/io/zenoh/jni/JNIZBytesKotlin.kt
new file mode 100644
index 00000000..3570b9e6
--- /dev/null
+++ b/zenoh-jni-runtime/src/jvmAndAndroidMain/kotlin/io/zenoh/jni/JNIZBytesKotlin.kt
@@ -0,0 +1,49 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh.jni
+
+import io.zenoh.ZenohLoad
+import kotlin.reflect.KType
+
+/**
+ * JNI bridge for Kotlin-type-aware serialization/deserialization.
+ *
+ * Uses [KType] (obtained via `typeOf()` with reified generics) instead of
+ * [java.lang.reflect.Type], making this bridge usable from commonMain Kotlin
+ * code and compatible with Kotlin-specific types (unsigned integers, Pair, Triple).
+ *
+ * Supported types:
+ * - Primitives: Boolean, Byte, Short, Int, Long, Float, Double
+ * - Unsigned (Kotlin-only): UByte, UShort, UInt, ULong
+ * - Text/Binary: String, ByteArray
+ * - Collections: List, Map (recursive)
+ * - Tuples: Pair, Triple
+ */
+object JNIZBytesKotlin {
+
+ init {
+ ZenohLoad
+ }
+
+ fun serialize(any: Any, kType: KType): ByteArray = serializeViaJNI(any, kType)
+
+ fun deserialize(bytes: ByteArray, kType: KType): Any = deserializeViaJNI(bytes, kType)
+
+ @JvmStatic
+ private external fun serializeViaJNI(any: Any, kType: KType): ByteArray
+
+ @JvmStatic
+ private external fun deserializeViaJNI(bytes: ByteArray, kType: KType): Any
+}
diff --git a/zenoh-java/src/jvmMain/kotlin/io/zenoh/Target.kt b/zenoh-jni-runtime/src/jvmMain/kotlin/io/zenoh/Target.kt
similarity index 95%
rename from zenoh-java/src/jvmMain/kotlin/io/zenoh/Target.kt
rename to zenoh-jni-runtime/src/jvmMain/kotlin/io/zenoh/Target.kt
index f3f28256..6460f7ce 100644
--- a/zenoh-java/src/jvmMain/kotlin/io/zenoh/Target.kt
+++ b/zenoh-jni-runtime/src/jvmMain/kotlin/io/zenoh/Target.kt
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2023 ZettaScale Technology
+// Copyright (c) 2026 ZettaScale Technology
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
diff --git a/zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-jni-runtime/src/jvmMain/kotlin/io/zenoh/ZenohLoad.kt
similarity index 99%
rename from zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt
rename to zenoh-jni-runtime/src/jvmMain/kotlin/io/zenoh/ZenohLoad.kt
index 8da47656..aa542844 100644
--- a/zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt
+++ b/zenoh-jni-runtime/src/jvmMain/kotlin/io/zenoh/ZenohLoad.kt
@@ -24,7 +24,7 @@ import java.util.zip.ZipInputStream
* Static singleton class to load the Zenoh native library once and only once, as well as the logger in function of the
* log level configuration.
*/
-internal actual object ZenohLoad {
+public actual object ZenohLoad {
private const val ZENOH_LIB_NAME = "zenoh_jni"
init {
diff --git a/zenoh-jni-runtime/src/jvmTest/kotlin/io/zenoh/ZBytesInteropTests.kt b/zenoh-jni-runtime/src/jvmTest/kotlin/io/zenoh/ZBytesInteropTests.kt
new file mode 100644
index 00000000..5e8f6bd5
--- /dev/null
+++ b/zenoh-jni-runtime/src/jvmTest/kotlin/io/zenoh/ZBytesInteropTests.kt
@@ -0,0 +1,308 @@
+//
+// Copyright (c) 2026 ZettaScale Technology
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License 2.0 which is available at
+// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+//
+// Contributors:
+// ZettaScale Zenoh Team,
+//
+
+package io.zenoh
+
+import io.zenoh.jni.JNIZBytes
+import io.zenoh.jni.JNIZBytesKotlin
+import kotlin.reflect.typeOf
+import kotlin.test.Test
+import kotlin.test.assertContentEquals
+import kotlin.test.assertEquals
+
+/**
+ * Tests for Java/Kotlin serialization interoperability at the JNI bridge layer.
+ *
+ * Two groups:
+ * 1. Kotlin round-trips — serialize and deserialize via [JNIZBytesKotlin] (KType path), covering
+ * all supported KotlinType variants including unsigned integers and Pair/Triple.
+ * 2. Cross-path interop — verify that [JNIZBytes] (Java Type path) and [JNIZBytesKotlin]
+ * (KType path) produce identical wire bytes for the common types they share.
+ */
+class ZBytesInteropTests {
+
+ // -------------------------------------------------------------------------
+ // Group 1: Kotlin round-trips via JNIZBytesKotlin
+ // -------------------------------------------------------------------------
+
+ @Test
+ fun testBooleanKotlinRoundTrip() {
+ val input = true
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf())
+ assertEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf()) as Boolean)
+ }
+
+ @Test
+ fun testByteKotlinRoundTrip() {
+ val input: Byte = 42
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf())
+ assertEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf()) as Byte)
+ }
+
+ @Test
+ fun testShortKotlinRoundTrip() {
+ val input: Short = 1234
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf())
+ assertEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf()) as Short)
+ }
+
+ @Test
+ fun testIntKotlinRoundTrip() {
+ val input = 1234567
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf())
+ assertEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf()) as Int)
+ }
+
+ @Test
+ fun testLongKotlinRoundTrip() {
+ val input = 123456789012345L
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf())
+ assertEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf()) as Long)
+ }
+
+ @Test
+ fun testFloatKotlinRoundTrip() {
+ val input = 3.1415f
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf())
+ assertEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf()) as Float, 0.0001f)
+ }
+
+ @Test
+ fun testDoubleKotlinRoundTrip() {
+ val input = 2.718281828
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf())
+ assertEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf()) as Double, 0.000000001)
+ }
+
+ @Test
+ fun testStringKotlinRoundTrip() {
+ val input = "hello zenoh"
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf())
+ assertEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf()) as String)
+ }
+
+ @Test
+ fun testByteArrayKotlinRoundTrip() {
+ val input = byteArrayOf(1, 2, 3, 4, 5)
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf())
+ assertContentEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf()) as ByteArray)
+ }
+
+ // Kotlin-only unsigned types
+
+ @Test
+ fun testUByteKotlinRoundTrip() {
+ val input: UByte = 200u
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf())
+ assertEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf()) as UByte)
+ }
+
+ @Test
+ fun testUShortKotlinRoundTrip() {
+ val input: UShort = 60000u
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf())
+ assertEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf()) as UShort)
+ }
+
+ @Test
+ fun testUIntKotlinRoundTrip() {
+ val input: UInt = 3000000000u
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf())
+ assertEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf()) as UInt)
+ }
+
+ @Test
+ fun testULongKotlinRoundTrip() {
+ val input: ULong = 10000000000000000000u
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf())
+ assertEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf()) as ULong)
+ }
+
+ // Collections
+
+ @Test
+ fun testListOfIntKotlinRoundTrip() {
+ val input = listOf(1, 2, 3, 4, 5)
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf>())
+ @Suppress("UNCHECKED_CAST")
+ assertEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf>()) as List)
+ }
+
+ @Test
+ fun testListOfStringKotlinRoundTrip() {
+ val input = listOf("a", "b", "c")
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf>())
+ @Suppress("UNCHECKED_CAST")
+ assertEquals(input, JNIZBytesKotlin.deserialize(bytes, typeOf>()) as List)
+ }
+
+ @Test
+ fun testMapOfStringToIntKotlinRoundTrip() {
+ val input = mapOf("one" to 1, "two" to 2, "three" to 3)
+ val bytes = JNIZBytesKotlin.serialize(input, typeOf