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 9cd3ca1f feat(bindings/java): add Stat support (#1894)
9cd3ca1f is described below
commit 9cd3ca1fd5459b237f6b81ff5759753eb77f0648
Author: An Li <[email protected]>
AuthorDate: Tue Apr 11 10:59:32 2023 +0800
feat(bindings/java): add Stat support (#1894)
add Stat support
---
bindings/java/src/lib.rs | 114 ++++++++++++++++-----
.../src/main/java/org/apache/opendal/Metadata.java | 49 +++++++++
.../src/main/java/org/apache/opendal/Operator.java | 9 +-
.../test/java/org/apache/opendal/StepsTest.java | 13 ++-
4 files changed, 152 insertions(+), 33 deletions(-)
diff --git a/bindings/java/src/lib.rs b/bindings/java/src/lib.rs
index 1ee69a23..88d10132 100644
--- a/bindings/java/src/lib.rs
+++ b/bindings/java/src/lib.rs
@@ -22,6 +22,7 @@ use jni::objects::JClass;
use jni::objects::JMap;
use jni::objects::JObject;
use jni::objects::JString;
+use jni::sys::{jboolean, jlong};
use jni::JNIEnv;
use opendal::BlockingOperator;
use opendal::Operator;
@@ -33,7 +34,7 @@ pub extern "system" fn
Java_org_apache_opendal_Operator_getOperator(
_class: JClass,
input: JString,
params: JObject,
-) -> *const i32 {
+) -> jlong {
let input: String = env
.get_string(&input)
.expect("Couldn't get java string!")
@@ -43,7 +44,7 @@ pub extern "system" fn
Java_org_apache_opendal_Operator_getOperator(
let map = convert_map(&mut env, ¶ms);
if let Ok(operator) = build_operator(scheme, map) {
- Box::into_raw(Box::new(operator)) as *const i32
+ Box::into_raw(Box::new(operator)) as jlong
} else {
env.exception_clear().expect("Couldn't clear exception");
env.throw_new(
@@ -51,34 +52,10 @@ pub extern "system" fn
Java_org_apache_opendal_Operator_getOperator(
"Unsupported operator.",
)
.expect("Couldn't throw exception");
- std::ptr::null()
+ 0 as jlong
}
}
-fn convert_map(env: &mut JNIEnv, params: &JObject) -> HashMap<String, String> {
- let mut result: HashMap<String, String> = HashMap::new();
- let _ = JMap::from_env(env, params)
- .unwrap()
- .iter(env)
- .and_then(|mut iter| {
- while let Some(e) = iter.next(env)? {
- let key = JString::from(e.0);
- let value = JString::from(e.1);
- let key: String = env
- .get_string(&key)
- .expect("Couldn't get java string!")
- .into();
- let value: String = env
- .get_string(&value)
- .expect("Couldn't get java string!")
- .into();
- result.insert(key, value);
- }
- Ok(())
- });
- result
-}
-
/// # Safety
///
/// This function should not be called before the Operator are ready.
@@ -88,6 +65,7 @@ pub unsafe extern "system" fn
Java_org_apache_opendal_Operator_freeOperator(
_class: JClass,
ptr: *mut Operator,
) {
+ // Take ownership of the pointer by wrapping it with a Box
let _ = Box::from_raw(ptr);
}
@@ -137,6 +115,64 @@ pub unsafe extern "system" fn
Java_org_apache_opendal_Operator_read<'local>(
output
}
+/// # Safety
+///
+/// This function should not be called before the Operator are ready.
+#[no_mangle]
+pub unsafe extern "system" fn Java_org_apache_opendal_Operator_stat(
+ mut env: JNIEnv,
+ _class: JClass,
+ ptr: *mut BlockingOperator,
+ file: JString,
+) -> jlong {
+ let op = &mut *ptr;
+ let file: String = env
+ .get_string(&file)
+ .expect("Couldn't get java string!")
+ .into();
+ let metadata = op.stat(&file).unwrap();
+ Box::into_raw(Box::new(metadata)) as jlong
+}
+
+/// # Safety
+///
+/// This function should not be called before the Stat are ready.
+#[no_mangle]
+pub unsafe extern "system" fn Java_org_apache_opendal_Metadata_isFile(
+ mut _env: JNIEnv,
+ _class: JClass,
+ ptr: *mut opendal::Metadata,
+) -> jboolean {
+ let metadata = &mut *ptr;
+ metadata.is_file() as jboolean
+}
+
+/// # Safety
+///
+/// This function should not be called before the Stat are ready.
+#[no_mangle]
+pub unsafe extern "system" fn
Java_org_apache_opendal_Metadata_getContentLength(
+ mut _env: JNIEnv,
+ _class: JClass,
+ ptr: *mut opendal::Metadata,
+) -> jlong {
+ let metadata = &mut *ptr;
+ metadata.content_length() as jlong
+}
+
+/// # Safety
+///
+/// This function should not be called before the Stat are ready.
+#[no_mangle]
+pub unsafe extern "system" fn Java_org_apache_opendal_Metadata_freeStat(
+ mut _env: JNIEnv,
+ _class: JClass,
+ ptr: *mut opendal::Metadata,
+) {
+ // Take ownership of the pointer by wrapping it with a Box
+ let _ = Box::from_raw(ptr);
+}
+
/// # Safety
///
/// This function should not be called before the Operator are ready.
@@ -188,3 +224,27 @@ fn build_operator(
Ok(op)
}
+
+fn convert_map(env: &mut JNIEnv, params: &JObject) -> HashMap<String, String> {
+ let mut result: HashMap<String, String> = HashMap::new();
+ let _ = JMap::from_env(env, params)
+ .unwrap()
+ .iter(env)
+ .and_then(|mut iter| {
+ while let Some(e) = iter.next(env)? {
+ let key = JString::from(e.0);
+ let value = JString::from(e.1);
+ let key: String = env
+ .get_string(&key)
+ .expect("Couldn't get java string!")
+ .into();
+ let value: String = env
+ .get_string(&value)
+ .expect("Couldn't get java string!")
+ .into();
+ result.insert(key, value);
+ }
+ Ok(())
+ });
+ result
+}
diff --git a/bindings/java/src/main/java/org/apache/opendal/Metadata.java
b/bindings/java/src/main/java/org/apache/opendal/Metadata.java
new file mode 100644
index 00000000..28121503
--- /dev/null
+++ b/bindings/java/src/main/java/org/apache/opendal/Metadata.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+public class Metadata {
+
+ long ptr;
+
+ private native void freeStat(long statPtr);
+
+ private native boolean isFile(long statPtr);
+
+ private native long getContentLength(long statPtr);
+
+
+ public Metadata(long ptr) {
+ this.ptr = ptr;
+ }
+
+ public boolean isFile() {
+ return isFile(this.ptr);
+ }
+
+ @Override
+ protected void finalize() {
+ freeStat(this.ptr);
+ }
+
+ public long getContentLength() {
+ return getContentLength(this.ptr);
+ }
+}
diff --git a/bindings/java/src/main/java/org/apache/opendal/Operator.java
b/bindings/java/src/main/java/org/apache/opendal/Operator.java
index 7a033bee..a51d71e6 100644
--- a/bindings/java/src/main/java/org/apache/opendal/Operator.java
+++ b/bindings/java/src/main/java/org/apache/opendal/Operator.java
@@ -46,7 +46,7 @@ public class Operator {
private native long getOperator(String type, Map<String, String> params);
- private native void freeOperator(long ptr);
+ protected native void freeOperator(long ptr);
private native void write(long ptr, String fileName, String content);
@@ -54,6 +54,8 @@ public class Operator {
private native void delete(long ptr, String fileName);
+ private native long stat(long ptr, String file);
+
public void write(String fileName, String content) {
write(this.ptr, fileName, content);
@@ -67,6 +69,11 @@ public class Operator {
delete(this.ptr, s);
}
+ public Metadata stat(String fileName) {
+ long statPtr = stat(this.ptr, fileName);
+ return new Metadata(statPtr);
+ }
+
@Override
protected void finalize() throws Throwable {
super.finalize();
diff --git a/bindings/java/src/test/java/org/apache/opendal/StepsTest.java
b/bindings/java/src/test/java/org/apache/opendal/StepsTest.java
index bca3c774..a4f411f0 100644
--- a/bindings/java/src/test/java/org/apache/opendal/StepsTest.java
+++ b/bindings/java/src/test/java/org/apache/opendal/StepsTest.java
@@ -26,7 +26,7 @@ import io.cucumber.java.en.When;
import java.util.HashMap;
import java.util.Map;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.*;
public class StepsTest {
@@ -46,21 +46,24 @@ public class StepsTest {
@Then("The blocking file {string} should exist")
- public void the_blocking_file_test_should_exist(String content) {
-
+ public void the_blocking_file_test_should_exist(String fileName) {
+ Metadata metadata = this.operator.stat(fileName);
+ assertNotNull(metadata);
}
@Then("The blocking file {string} entry mode must be file")
public void the_blocking_file_test_entry_mode_must_be_file(String
fileName) {
+ Metadata metadata = this.operator.stat(fileName);
+ assertTrue(metadata.isFile());
}
@Then("The blocking file {string} content length must be {int}")
public void the_blocking_file_test_content_length_must_be_13(String
fileName, int length) {
- String content = this.operator.read(fileName);
+ Metadata metadata = this.operator.stat(fileName);
- assertEquals(content.length(), length);
+ assertEquals(metadata.getContentLength(), length);
}
@Then("The blocking file {string} must have content {string}")