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, &params);
     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}")

Reply via email to