This is an automated email from the ASF dual-hosted git repository.
xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git
The following commit(s) were added to refs/heads/main by this push:
new eae0115cc feat(bindings/java): auto enable blocking layer (#3049)
eae0115cc is described below
commit eae0115cc6405fdfdcc56f28f92fd6b7fc51b448
Author: tison <[email protected]>
AuthorDate: Wed Sep 13 16:43:54 2023 +0800
feat(bindings/java): auto enable blocking layer (#3049)
* feat(bindings/java): support configure layers
Signed-off-by: tison <[email protected]>
* refactor: hardcode blocking layer
Signed-off-by: tison <[email protected]>
* test: add tests for Redis Service x Java Binding
Signed-off-by: tison <[email protected]>
* style: spotless
Signed-off-by: tison <[email protected]>
---------
Signed-off-by: tison <[email protected]>
---
bindings/java/pom.xml | 25 ++++++-
bindings/java/src/blocking_operator.rs | 12 +++-
bindings/java/src/error.rs | 7 +-
bindings/java/src/metadata.rs | 4 +-
bindings/java/src/operator.rs | 10 ++-
.../java/org/apache/opendal/RedisServiceTest.java | 79 ++++++++++++++++++++++
6 files changed, 128 insertions(+), 9 deletions(-)
diff --git a/bindings/java/pom.xml b/bindings/java/pom.xml
index b41b61bf3..a02c305b1 100644
--- a/bindings/java/pom.xml
+++ b/bindings/java/pom.xml
@@ -53,10 +53,11 @@
<maven.compiler.target>1.8</maven.compiler.target>
<jni.classifier>${os.detected.classifier}</jni.classifier>
- <suffix.snapshot /> <!-- used by snapshots releases -->
<assertj-version>3.23.1</assertj-version>
<lombok.version>1.18.26</lombok.version>
+ <slf4j.version>2.0.7</slf4j.version>
+ <testcontainers.version>1.18.3</testcontainers.version>
<maven-surefire-plugin.version>3.0.0</maven-surefire-plugin.version>
<exec-maven-plugin.version>3.1.0</exec-maven-plugin.version>
@@ -73,6 +74,13 @@
<type>pom</type>
<scope>import</scope>
</dependency>
+ <dependency>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers-bom</artifactId>
+ <version>${testcontainers.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
@@ -90,6 +98,11 @@
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>${slf4j.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
@@ -125,6 +138,16 @@
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
diff --git a/bindings/java/src/blocking_operator.rs
b/bindings/java/src/blocking_operator.rs
index ff1c894a1..6b936e349 100644
--- a/bindings/java/src/blocking_operator.rs
+++ b/bindings/java/src/blocking_operator.rs
@@ -24,12 +24,14 @@ use jni::objects::JString;
use jni::sys::jlong;
use jni::sys::jstring;
use jni::JNIEnv;
+
+use opendal::layers::BlockingLayer;
use opendal::BlockingOperator;
use opendal::Operator;
use opendal::Scheme;
-use crate::jmap_to_hashmap;
use crate::Result;
+use crate::{get_global_runtime, jmap_to_hashmap};
#[no_mangle]
pub extern "system" fn Java_org_apache_opendal_BlockingOperator_constructor(
@@ -47,7 +49,11 @@ pub extern "system" fn
Java_org_apache_opendal_BlockingOperator_constructor(
fn intern_constructor(env: &mut JNIEnv, scheme: JString, map: JObject) ->
Result<jlong> {
let scheme = Scheme::from_str(env.get_string(&scheme)?.to_str()?)?;
let map = jmap_to_hashmap(env, &map)?;
- let op = Operator::via_map(scheme, map)?;
+ let mut op = Operator::via_map(scheme, map)?;
+ if !op.info().full_capability().blocking {
+ let _guard = unsafe { get_global_runtime() }.enter();
+ op = op.layer(BlockingLayer::create()?);
+ }
Ok(Box::into_raw(Box::new(op.blocking())) as jlong)
}
@@ -57,7 +63,7 @@ fn intern_constructor(env: &mut JNIEnv, scheme: JString, map:
JObject) -> Result
#[no_mangle]
pub unsafe extern "system" fn
Java_org_apache_opendal_BlockingOperator_disposeInternal(
_: JNIEnv,
- _: JClass,
+ _: JObject,
op: *mut BlockingOperator,
) {
drop(Box::from_raw(op));
diff --git a/bindings/java/src/error.rs b/bindings/java/src/error.rs
index d47561e9b..8a99c4f49 100644
--- a/bindings/java/src/error.rs
+++ b/bindings/java/src/error.rs
@@ -31,7 +31,12 @@ pub(crate) struct Error {
impl Error {
pub(crate) fn throw(&self, env: &mut JNIEnv) {
if let Err(err) = self.do_throw(env) {
- env.fatal_error(err.to_string());
+ match err {
+ jni::errors::Error::JavaException => {
+ // other calls throws exception; safely ignored
+ }
+ _ => env.fatal_error(err.to_string()),
+ }
}
}
diff --git a/bindings/java/src/metadata.rs b/bindings/java/src/metadata.rs
index 3295bc0ec..5f2e14ea4 100644
--- a/bindings/java/src/metadata.rs
+++ b/bindings/java/src/metadata.rs
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-use jni::objects::JClass;
+use jni::objects::{JClass, JObject};
use jni::sys::jboolean;
use jni::sys::jlong;
use jni::JNIEnv;
@@ -53,7 +53,7 @@ pub unsafe extern "system" fn
Java_org_apache_opendal_Metadata_getContentLength(
#[no_mangle]
pub unsafe extern "system" fn Java_org_apache_opendal_Metadata_disposeInternal(
_: JNIEnv,
- _: JClass,
+ _: JObject,
ptr: *mut Metadata,
) {
drop(Box::from_raw(ptr));
diff --git a/bindings/java/src/operator.rs b/bindings/java/src/operator.rs
index 7730bd038..43ae74cc4 100644
--- a/bindings/java/src/operator.rs
+++ b/bindings/java/src/operator.rs
@@ -25,6 +25,8 @@ use jni::objects::JValue;
use jni::objects::JValueOwned;
use jni::sys::jlong;
use jni::JNIEnv;
+
+use opendal::layers::BlockingLayer;
use opendal::Operator;
use opendal::Scheme;
@@ -49,7 +51,11 @@ pub extern "system" fn
Java_org_apache_opendal_Operator_constructor(
fn intern_constructor(env: &mut JNIEnv, scheme: JString, map: JObject) ->
Result<jlong> {
let scheme = Scheme::from_str(env.get_string(&scheme)?.to_str()?)?;
let map = jmap_to_hashmap(env, &map)?;
- let op = Operator::via_map(scheme, map)?;
+ let mut op = Operator::via_map(scheme, map)?;
+ if !op.info().full_capability().blocking {
+ let _guard = unsafe { get_global_runtime() }.enter();
+ op = op.layer(BlockingLayer::create()?);
+ }
Ok(Box::into_raw(Box::new(op)) as jlong)
}
@@ -59,7 +65,7 @@ fn intern_constructor(env: &mut JNIEnv, scheme: JString, map:
JObject) -> Result
#[no_mangle]
pub unsafe extern "system" fn Java_org_apache_opendal_Operator_disposeInternal(
_: JNIEnv,
- _: JClass,
+ _: JObject,
op: *mut Operator,
) {
drop(Box::from_raw(op));
diff --git
a/bindings/java/src/test/java/org/apache/opendal/RedisServiceTest.java
b/bindings/java/src/test/java/org/apache/opendal/RedisServiceTest.java
new file mode 100644
index 000000000..364893189
--- /dev/null
+++ b/bindings/java/src/test/java/org/apache/opendal/RedisServiceTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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.
+ */
+
+package org.apache.opendal;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletionException;
+import lombok.Cleanup;
+import org.junit.jupiter.api.Test;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+@Testcontainers
+public class RedisServiceTest {
+
+ @Container
+ private final GenericContainer<?> redisContainer = new
GenericContainer<>("redis:7.2.1").withExposedPorts(6379);
+
+ @Test
+ public void testAccessRedisService() {
+ assertThat(redisContainer.isRunning()).isTrue();
+
+ final Map<String, String> params = new HashMap<>();
+ params.put("root", "/tmp");
+ params.put("endpoint", "tcp://127.0.0.1:6379");
+ @Cleanup final Operator op = new Operator("Redis", params);
+
+ op.write("testAccessRedisService", "Odin").join();
+ assertThat(op.read("testAccessRedisService").join()).isEqualTo("Odin");
+ op.delete("testAccessRedisService").join();
+ op.stat("testAccessRedisService")
+ .handle((r, e) -> {
+ assertThat(r).isNull();
+
assertThat(e).isInstanceOf(CompletionException.class).hasCauseInstanceOf(OpenDALException.class);
+ OpenDALException.Code code = ((OpenDALException)
e.getCause()).getCode();
+ assertThat(code).isEqualTo(OpenDALException.Code.NotFound);
+ return null;
+ })
+ .join();
+ }
+
+ @Test
+ public void testAccessRedisServiceBlocking() {
+ assertThat(redisContainer.isRunning()).isTrue();
+
+ final Map<String, String> params = new HashMap<>();
+ params.put("root", "/tmp");
+ params.put("endpoint", "tcp://127.0.0.1:6379");
+ @Cleanup final BlockingOperator op = new BlockingOperator("Redis",
params);
+
+ op.write("testAccessRedisServiceBlocking", "Odin");
+
assertThat(op.read("testAccessRedisServiceBlocking")).isEqualTo("Odin");
+ op.delete("testAccessRedisServiceBlocking");
+ assertThatExceptionOfType(OpenDALException.class)
+ .isThrownBy(() -> op.stat("testAccessRedisServiceBlocking"))
+ .extracting(OpenDALException::getCode)
+ .isEqualTo(OpenDALException.Code.NotFound);
+ }
+}