Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(binding/java): make Metadata a POJO #3277

Merged
merged 7 commits into from
Oct 14, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
12 changes: 7 additions & 5 deletions bindings/java/src/blocking_operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ use jni::objects::JByteArray;
use jni::objects::JClass;
use jni::objects::JObject;
use jni::objects::JString;
use jni::sys::{jbyteArray, jlong};
use jni::sys::jbyteArray;
use jni::sys::jobject;
use jni::JNIEnv;

use opendal::BlockingOperator;

use crate::jstring_to_string;
use crate::make_metadata;
use crate::Result;

/// # Safety
Expand Down Expand Up @@ -98,17 +100,17 @@ pub unsafe extern "system" fn Java_org_apache_opendal_BlockingOperator_stat(
_: JClass,
op: *mut BlockingOperator,
path: JString,
) -> jlong {
) -> jobject {
intern_stat(&mut env, &mut *op, path).unwrap_or_else(|e| {
e.throw(&mut env);
0
JObject::default().into_raw()
})
}

fn intern_stat(env: &mut JNIEnv, op: &mut BlockingOperator, path: JString) -> Result<jlong> {
fn intern_stat(env: &mut JNIEnv, op: &mut BlockingOperator, path: JString) -> Result<jobject> {
let path = jstring_to_string(env, &path)?;
let metadata = op.stat(&path)?;
Ok(Box::into_raw(Box::new(metadata)) as jlong)
Ok(make_metadata(env, metadata)?.into_raw())
}

/// # Safety
Expand Down
54 changes: 53 additions & 1 deletion bindings/java/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@ use jni::JavaVM;
use once_cell::sync::OnceCell;
use opendal::raw::PresignedRequest;
use opendal::Capability;
use opendal::EntryMode;
use opendal::Metadata;
use opendal::OperatorInfo;
use tokio::runtime::Builder;
use tokio::runtime::Runtime;

mod blocking_operator;
mod error;
mod metadata;
mod operator;

pub(crate) type Result<T> = std::result::Result<T, error::Error>;
Expand Down Expand Up @@ -222,6 +223,57 @@ fn make_capability<'a>(env: &mut JNIEnv<'a>, cap: Capability) -> Result<JObject<
Ok(capability)
}

fn make_metadata<'a>(env: &mut JNIEnv<'a>, metadata: Metadata) -> Result<JObject<'a>> {
let mode = match metadata.mode() {
EntryMode::FILE => 0,
EntryMode::DIR => 1,
EntryMode::Unknown => 2,
};

let last_modified = metadata.last_modified().map_or_else(
|| Ok::<JObject<'_>, Error>(JObject::null()),
|v| {
Ok(env.new_object(
"java/util/Date",
"(J)V",
&[JValue::Long(v.timestamp_millis())],
)?)
},
)?;

let cache_control = string_to_jstring(env, metadata.cache_control())?;
let content_disposition = string_to_jstring(env, metadata.content_disposition())?;
let content_md5 = string_to_jstring(env, metadata.content_md5())?;
let content_type = string_to_jstring(env, metadata.content_type())?;
let etag = string_to_jstring(env, metadata.etag())?;
let version = string_to_jstring(env, metadata.version())?;

let result = env
.new_object(
"org/apache/opendal/Metadata",
"(IJLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Date;Ljava/lang/String;)V",
&[
JValue::Int(mode as jint),
JValue::Long(metadata.content_length() as jlong),
JValue::Object(&content_disposition),
JValue::Object(&content_md5),
JValue::Object(&content_type),
JValue::Object(&cache_control),
JValue::Object(&etag),
JValue::Object(&last_modified),
JValue::Object(&version),
],
)?;
Ok(result)
}

fn string_to_jstring<'a>(env: &mut JNIEnv<'a>, s: Option<&str>) -> Result<JObject<'a>> {
s.map_or_else(
|| Ok(JObject::null()),
|v| Ok(env.new_string(v.to_string())?.into()),
)
}

/// # Safety
///
/// The caller must guarantee that the Object passed in is an instance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void delete(String path) {
}

public Metadata stat(String path) {
return new Metadata(stat(nativeHandle, path));
return stat(nativeHandle, path);
}

public void createDir(String path) {
Expand All @@ -91,7 +91,7 @@ public void rename(String sourcePath, String targetPath) {

private static native void delete(long nativeHandle, String path);

private static native long stat(long nativeHandle, String path);
private static native Metadata stat(long nativeHandle, String path);

private static native long createDir(long nativeHandle, String path);

Expand Down
66 changes: 55 additions & 11 deletions bindings/java/src/main/java/org/apache/opendal/Metadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,70 @@

package org.apache.opendal;

import java.util.Date;
import lombok.Data;

/**
* Metadata carries all metadata associated with a path.
*/
public class Metadata extends NativeObject {
protected Metadata(long nativeHandle) {
super(nativeHandle);
@Data
public class Metadata {
public final EntryMode mode;
public final long contentLength;
public final String contentDisposition;
public final String contentMd5;
public final String contentType;
public final String cacheControl;
public final String etag;
public final Date lastModified;
public final String version;

public Metadata(
int mode,
long contentLength,
String contentDisposition,
String contentMd5,
String contentType,
String cacheControl,
String etag,
Date lastModified,
String version) {
this.mode = EntryMode.of(mode);
this.contentLength = contentLength;
this.contentDisposition = contentDisposition;
this.contentMd5 = contentMd5;
this.contentType = contentType;
this.cacheControl = cacheControl;
this.etag = etag;
this.lastModified = lastModified;
this.version = version;
}

public boolean isFile() {
return isFile(nativeHandle);
return mode == EntryMode.FILE;
}

public long getContentLength() {
return getContentLength(nativeHandle);
public boolean isDir() {
return mode == EntryMode.DIR;
}

@Override
protected native void disposeInternal(long handle);
public enum EntryMode {
/// FILE means the path has data to read.
FILE,
/// DIR means the path can be listed.
DIR,
/// Unknown means we don't know what we can do on this path.
UNKNOWN;

private static native boolean isFile(long nativeHandle);

private static native long getContentLength(long nativeHandle);
public static EntryMode of(int mode) {
switch (mode) {
case 0:
return EntryMode.FILE;
case 1:
return EntryMode.DIR;
default:
return EntryMode.UNKNOWN;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,7 @@ public CompletableFuture<Void> append(String path, byte[] content) {

public CompletableFuture<Metadata> stat(String path) {
final long requestId = stat(nativeHandle, path);
final CompletableFuture<Long> f = AsyncRegistry.take(requestId);
return f.thenApply(Metadata::new);
return AsyncRegistry.take(requestId);
}

public CompletableFuture<byte[]> read(String path) {
Expand Down
61 changes: 0 additions & 61 deletions bindings/java/src/metadata.rs

This file was deleted.

8 changes: 5 additions & 3 deletions bindings/java/src/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use crate::get_current_env;
use crate::get_global_runtime;
use crate::jmap_to_hashmap;
use crate::jstring_to_string;
use crate::make_metadata;
use crate::make_operator_info;
use crate::make_presigned_request;
use crate::Result;
Expand Down Expand Up @@ -181,15 +182,16 @@ fn intern_stat(env: &mut JNIEnv, op: *mut Operator, path: JString) -> Result<jlo

unsafe { get_global_runtime() }.spawn(async move {
let result = do_stat(op, path).await;
complete_future(id, result.map(JValueOwned::Long))
complete_future(id, result.map(JValueOwned::Object))
});

Ok(id)
}

async fn do_stat(op: &mut Operator, path: String) -> Result<jlong> {
async fn do_stat<'local>(op: &mut Operator, path: String) -> Result<JObject<'local>> {
let metadata = op.stat(&path).await?;
Ok(Box::into_raw(Box::new(metadata)) as jlong)
let mut env = unsafe { get_current_env() };
make_metadata(&mut env, metadata)
}

/// # Safety
Expand Down
Loading
Loading