Skip to content

Commit

Permalink
feat(binding/java): make Metadata a POJO (#3277)
Browse files Browse the repository at this point in the history
  • Loading branch information
G-XD authored Oct 14, 2023
1 parent c5ea00a commit 3108bd3
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 109 deletions.
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;
}
}
}
}
3 changes: 1 addition & 2 deletions bindings/java/src/main/java/org/apache/opendal/Operator.java
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

0 comments on commit 3108bd3

Please sign in to comment.