bindings/java/src/lib.rs (169 lines of code) (raw):

// 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. use std::collections::HashMap; use jni::objects::JObject; use jni::objects::JValue; use jni::sys::jboolean; use jni::sys::jint; use jni::sys::jlong; use jni::JNIEnv; use opendal::raw::PresignedRequest; use opendal::Capability; use opendal::Entry; use opendal::EntryMode; use opendal::Metadata; use opendal::OperatorInfo; mod async_operator; mod convert; mod error; mod executor; mod layer; mod operator; mod operator_input_stream; mod operator_output_stream; mod utility; pub(crate) type Result<T> = std::result::Result<T, error::Error>; fn make_presigned_request<'a>(env: &mut JNIEnv<'a>, req: PresignedRequest) -> Result<JObject<'a>> { let method = env.new_string(req.method().as_str())?; let uri = env.new_string(req.uri().to_string())?; let headers = { let mut map = HashMap::new(); for (k, v) in req.header().iter() { let key = k.to_string(); let value = v.to_str().map_err(|err| { opendal::Error::new(opendal::ErrorKind::Unexpected, err.to_string()) })?; map.insert(key, value.to_owned()); } map }; let headers = convert::hashmap_to_jmap(env, &headers)?; let result = env.new_object( "org/apache/opendal/PresignedRequest", "(Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;)V", &[ JValue::Object(&method), JValue::Object(&uri), JValue::Object(&headers), ], )?; Ok(result) } fn make_operator_info<'a>(env: &mut JNIEnv<'a>, info: OperatorInfo) -> Result<JObject<'a>> { let scheme = env.new_string(info.scheme().to_string())?; let root = env.new_string(info.root().to_string())?; let name = env.new_string(info.name().to_string())?; let full_capability_obj = make_capability(env, info.full_capability())?; let native_capability_obj = make_capability(env, info.native_capability())?; let result = env .new_object( "org/apache/opendal/OperatorInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lorg/apache/opendal/Capability;Lorg/apache/opendal/Capability;)V", &[ JValue::Object(&scheme), JValue::Object(&root), JValue::Object(&name), JValue::Object(&full_capability_obj), JValue::Object(&native_capability_obj), ], )?; Ok(result) } fn make_capability<'a>(env: &mut JNIEnv<'a>, cap: Capability) -> Result<JObject<'a>> { let capability = env.new_object( "org/apache/opendal/Capability", "(ZZZZZZZZZZZZZZZZZZZJJZZZZZZZZZZZZZZ)V", &[ JValue::Bool(cap.stat as jboolean), JValue::Bool(cap.stat_with_if_match as jboolean), JValue::Bool(cap.stat_with_if_none_match as jboolean), JValue::Bool(cap.read as jboolean), JValue::Bool(cap.read_with_if_match as jboolean), JValue::Bool(cap.read_with_if_none_match as jboolean), JValue::Bool(cap.read_with_override_cache_control as jboolean), JValue::Bool(cap.read_with_override_content_disposition as jboolean), JValue::Bool(cap.read_with_override_content_type as jboolean), JValue::Bool(cap.write as jboolean), JValue::Bool(cap.write_can_multi as jboolean), JValue::Bool(cap.write_can_append as jboolean), JValue::Bool(cap.write_with_content_type as jboolean), JValue::Bool(cap.write_with_content_disposition as jboolean), JValue::Bool(cap.write_with_cache_control as jboolean), JValue::Bool(cap.write_with_if_match as jboolean), JValue::Bool(cap.write_with_if_none_match as jboolean), JValue::Bool(cap.write_with_if_not_exists as jboolean), JValue::Bool(cap.write_with_user_metadata as jboolean), JValue::Long(convert::usize_to_jlong(cap.write_multi_max_size)), JValue::Long(convert::usize_to_jlong(cap.write_multi_min_size)), JValue::Bool(cap.create_dir as jboolean), JValue::Bool(cap.delete as jboolean), JValue::Bool(cap.copy as jboolean), JValue::Bool(cap.rename as jboolean), JValue::Bool(cap.list as jboolean), JValue::Bool(cap.list_with_limit as jboolean), JValue::Bool(cap.list_with_start_after as jboolean), JValue::Bool(cap.list_with_recursive as jboolean), JValue::Bool(cap.presign as jboolean), JValue::Bool(cap.presign_read as jboolean), JValue::Bool(cap.presign_stat as jboolean), JValue::Bool(cap.presign_write as jboolean), JValue::Bool(cap.shared as jboolean), JValue::Bool(cap.blocking as jboolean), ], )?; 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::Error>(JObject::null()), |v| { Ok(env .call_static_method( "java/time/Instant", "ofEpochSecond", "(JJ)Ljava/time/Instant;", &[ JValue::Long(v.timestamp()), JValue::Long(v.timestamp_subsec_nanos() as jlong), ], )? .l()?) }, )?; let cache_control = convert::string_to_jstring(env, metadata.cache_control())?; let content_disposition = convert::string_to_jstring(env, metadata.content_disposition())?; let content_md5 = convert::string_to_jstring(env, metadata.content_md5())?; let content_type = convert::string_to_jstring(env, metadata.content_type())?; let etag = convert::string_to_jstring(env, metadata.etag())?; let version = convert::string_to_jstring(env, metadata.version())?; let content_length = metadata.content_length() as jlong; 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/time/Instant;Ljava/lang/String;)V", &[ JValue::Int(mode as jint), JValue::Long(content_length), 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 make_entry<'a>(env: &mut JNIEnv<'a>, entry: Entry) -> Result<JObject<'a>> { let path = env.new_string(entry.path())?; let metadata = make_metadata(env, entry.metadata().to_owned())?; Ok(env.new_object( "org/apache/opendal/Entry", "(Ljava/lang/String;Lorg/apache/opendal/Metadata;)V", &[JValue::Object(&path), JValue::Object(&metadata)], )?) }