Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions bindings/java/src/async_operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// specific language governing permissions and limitations
// under the License.

use std::collections::HashMap;
use std::str::FromStr;
use std::time::Duration;

Expand All @@ -29,6 +30,7 @@ use jni::sys::jobject;
use jni::sys::jsize;
use jni::JNIEnv;
use opendal::layers::BlockingLayer;
use opendal::layers::CompleteLayer;
use opendal::raw::PresignedRequest;
use opendal::Operator;
use opendal::Scheme;
Expand Down Expand Up @@ -564,8 +566,9 @@ pub unsafe extern "system" fn Java_org_apache_opendal_AsyncOperator_list(
op: *mut Operator,
executor: *const Executor,
path: JString,
options: JObject,
) -> jlong {
intern_list(&mut env, op, executor, path).unwrap_or_else(|e| {
intern_list(&mut env, op, executor, path, options).unwrap_or_else(|e| {
e.throw(&mut env);
0
})
Expand All @@ -576,22 +579,41 @@ fn intern_list(
op: *mut Operator,
executor: *const Executor,
path: JString,
options: JObject,
) -> Result<jlong> {
let op = unsafe { &mut *op };
let id = request_id(env)?;

let path = jstring_to_string(env, &path)?;

let recursive = if env.call_method(&options, "isRecursive", "()Z", &[])?.z()? {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i had some trouble on passing the options to the async block so that is the best way i can do. please let me know if that is not suitable, i may need some help on how to pass this arround. thanks

"true"
} else {
"false"
};

let opts = HashMap::from([("recursive", recursive)]);

executor_or_default(env, executor)?.spawn(async move {
let result = do_list(op, path).await;
let result = do_list(op, path, opts).await;
complete_future(id, result.map(JValueOwned::Object))
});

Ok(id)
}

async fn do_list<'local>(op: &mut Operator, path: String) -> Result<JObject<'local>> {
let obs = op.list(&path).await?;
async fn do_list<'local>(
op: &mut Operator,
path: String,
options: HashMap<&str, &str>,
) -> Result<JObject<'local>> {
let layered_op = op.clone().layer(CompleteLayer);

let mut list_op = layered_op.list_with(&path);
if let Some(&"true") = options.get("recursive") {
list_op = list_op.recursive(true);
}
let obs = list_op.await?;

let mut env = unsafe { get_current_env() };
let jarray = env.new_object_array(
Expand Down
12 changes: 11 additions & 1 deletion bindings/java/src/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ use jni::sys::jboolean;
use jni::sys::jfloat;
use jni::sys::jlong;
use jni::JNIEnv;
use opendal::layers::ConcurrentLimitLayer;
use opendal::layers::RetryLayer;
use opendal::layers::{CompleteLayer, ConcurrentLimitLayer};
use opendal::Operator;

#[no_mangle]
Expand Down Expand Up @@ -62,3 +62,13 @@ pub extern "system" fn Java_org_apache_opendal_layer_ConcurrentLimitLayer_doLaye
let concurrent_limit = ConcurrentLimitLayer::new(permits as usize);
Box::into_raw(Box::new(op.clone().layer(concurrent_limit))) as jlong
}

#[no_mangle]
pub extern "system" fn Java_org_apache_opendal_layer_CompleteLayer_doLayer(
_: JNIEnv,
_: JClass,
op: *mut Operator,
) -> jlong {
let op = unsafe { &*op };
Box::into_raw(Box::new(op.clone().layer(CompleteLayer))) as jlong
}
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,14 @@ public CompletableFuture<Void> removeAll(String path) {
}

public CompletableFuture<List<Entry>> list(String path) {
final long requestId = list(nativeHandle, executorHandle, path);
final long requestId =
list(nativeHandle, executorHandle, path, ListOptions.builder().build());
final CompletableFuture<Entry[]> result = AsyncRegistry.take(requestId);
return Objects.requireNonNull(result).thenApplyAsync(Arrays::asList);
}

public CompletableFuture<List<Entry>> list(String path, ListOptions options) {
final long requestId = list(nativeHandle, executorHandle, path, options);
final CompletableFuture<Entry[]> result = AsyncRegistry.take(requestId);
return Objects.requireNonNull(result).thenApplyAsync(Arrays::asList);
}
Expand Down Expand Up @@ -310,5 +317,5 @@ private static native long write(

private static native long removeAll(long nativeHandle, long executorHandle, String path);

private static native long list(long nativeHandle, long executorHandle, String path);
private static native long list(long nativeHandle, long executorHandle, String path, ListOptions options);
}
37 changes: 37 additions & 0 deletions bindings/java/src/main/java/org/apache/opendal/ListOptions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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 lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ListOptions {

/**
* Return files in sub-directory as well.
*/
private boolean recursive;
}
11 changes: 8 additions & 3 deletions bindings/java/src/main/java/org/apache/opendal/Operator.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.opendal.layer.CompleteLayer;

/**
* Operator represents an underneath OpenDAL operator that accesses data synchronously.
Expand Down Expand Up @@ -53,7 +54,7 @@ public static Operator of(ServiceConfig config) {
*/
public static Operator of(String scheme, Map<String, String> map) {
try (final AsyncOperator operator = AsyncOperator.of(scheme, map)) {
return operator.blocking();
return operator.layer(new CompleteLayer()).blocking();
}
}

Expand Down Expand Up @@ -128,7 +129,11 @@ public void removeAll(String path) {
}

public List<Entry> list(String path) {
return Arrays.asList(list(nativeHandle, path));
return Arrays.asList(list(nativeHandle, path, ListOptions.builder().build()));
}

public List<Entry> list(String path, ListOptions options) {
return Arrays.asList(list(nativeHandle, path, options));
}

@Override
Expand All @@ -152,5 +157,5 @@ public List<Entry> list(String path) {

private static native void removeAll(long op, String path);

private static native Entry[] list(long op, String path);
private static native Entry[] list(long op, String path, ListOptions options);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* 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.layer;

import org.apache.opendal.Layer;

public class CompleteLayer extends Layer {

@Override
protected long layer(long nativeOp) {
return doLayer(nativeOp);
}

private static native long doLayer(long nativeHandle);
}
18 changes: 15 additions & 3 deletions bindings/java/src/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,16 +277,28 @@ pub unsafe extern "system" fn Java_org_apache_opendal_Operator_list(
_: JClass,
op: *mut BlockingOperator,
path: JString,
options: JObject,
) -> jobjectArray {
intern_list(&mut env, &mut *op, path).unwrap_or_else(|e| {
intern_list(&mut env, &mut *op, path, options).unwrap_or_else(|e| {
e.throw(&mut env);
JObject::default().into_raw()
})
}

fn intern_list(env: &mut JNIEnv, op: &mut BlockingOperator, path: JString) -> Result<jobjectArray> {
fn intern_list(
env: &mut JNIEnv,
op: &mut BlockingOperator,
path: JString,
options: JObject,
) -> Result<jobjectArray> {
let path = jstring_to_string(env, &path)?;
let obs = op.list(&path)?;

let mut list_op = op.list_with(&path);
if env.call_method(&options, "isRecursive", "()Z", &[])?.z()? {
list_op = list_op.recursive(true);
}

let obs = list_op.call()?;

let jarray = env.new_object_array(
obs.len() as jsize,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.stream.Collectors;
import org.apache.opendal.Capability;
import org.apache.opendal.Entry;
import org.apache.opendal.ListOptions;
import org.apache.opendal.Metadata;
import org.apache.opendal.OpenDALException;
import org.apache.opendal.test.condition.OpenDALExceptionCondition;
Expand Down Expand Up @@ -224,4 +225,30 @@ public void testRemoveAll() {

asyncOp().removeAll(parent + "/").join();
}

@Test
public void testListRecursive() {
final String dir = String.format("%s/%s/", UUID.randomUUID(), UUID.randomUUID());
final String fileName = UUID.randomUUID().toString();
final String filePath = String.format("%s%s", dir, fileName);
final String dirName = String.format("%s/", UUID.randomUUID());
final String dirPath = String.format("%s%s", dir, dirName);
final String content = "test_list_nested_dir";
final String nestedFile = String.format("%s%s", dirPath, UUID.randomUUID());

asyncOp().createDir(dir).join();
asyncOp().write(filePath, content).join();
asyncOp().createDir(dirPath).join();
asyncOp().write(nestedFile, content).join();

final List<Entry> entries = asyncOp()
.list(dir, ListOptions.builder().recursive(true).build())
.join();
assertThat(entries).hasSize(4);

final List<Entry> noRecursiveEntries = asyncOp()
.list(dir, ListOptions.builder().recursive(false).build())
.join();
assertThat(noRecursiveEntries).hasSize(3);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.UUID;
import org.apache.opendal.Capability;
import org.apache.opendal.Entry;
import org.apache.opendal.ListOptions;
import org.apache.opendal.Metadata;
import org.apache.opendal.OpenDALException;
import org.apache.opendal.test.condition.OpenDALExceptionCondition;
Expand Down Expand Up @@ -108,4 +109,28 @@ public void testBlockingRemoveAll() {

op().removeAll(parent + "/");
}

@Test
public void testListRecursive() {
final String dir = String.format("%s/%s/", UUID.randomUUID(), UUID.randomUUID());
final String fileName = UUID.randomUUID().toString();
final String filePath = String.format("%s%s", dir, fileName);
final String dirName = String.format("%s/", UUID.randomUUID());
final String dirPath = String.format("%s%s", dir, dirName);
final String content = "test_list_nested_dir";
final String nestedFile = String.format("%s%s", dirPath, UUID.randomUUID());

op().createDir(dir);
op().write(filePath, content);
op().createDir(dirPath);
op().write(nestedFile, content);

final List<Entry> entries =
op().list(dir, ListOptions.builder().recursive(true).build());
assertThat(entries).hasSize(4);

final List<Entry> noRecursiveEntries =
op().list(dir, ListOptions.builder().recursive(false).build());
assertThat(noRecursiveEntries).hasSize(3);
}
}
2 changes: 1 addition & 1 deletion core/src/layers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ mod error_context;
pub(crate) use error_context::ErrorContextLayer;

mod complete;
pub(crate) use complete::CompleteLayer;
pub use complete::CompleteLayer;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CompleteLayer is applied by default. We don't need to apply it again.


mod concurrent_limit;
pub use concurrent_limit::ConcurrentLimitLayer;
Expand Down
Loading