17
17
18
18
use std:: str:: FromStr ;
19
19
20
- use jni:: objects:: { JClass , JObject , JString , JValue } ;
21
- use jni:: sys:: { jlong, jobject } ;
20
+ use jni:: objects:: { JClass , JObject , JString , JValue , JValueOwned } ;
21
+ use jni:: sys:: jlong;
22
22
use jni:: JNIEnv ;
23
23
24
24
use opendal:: { Operator , Scheme } ;
25
25
26
- use crate :: error:: Error ;
27
26
use crate :: { get_current_env, Result } ;
28
27
use crate :: { jmap_to_hashmap, RUNTIME } ;
29
28
@@ -69,10 +68,10 @@ pub unsafe extern "system" fn Java_org_apache_opendal_Operator_write(
69
68
op : * mut Operator ,
70
69
file : JString ,
71
70
content : JString ,
72
- ) -> jobject {
71
+ ) -> jlong {
73
72
intern_write ( & mut env, op, file, content) . unwrap_or_else ( |e| {
74
73
e. throw ( & mut env) ;
75
- JObject :: null ( ) . into_raw ( )
74
+ 0
76
75
} )
77
76
}
78
77
@@ -81,41 +80,147 @@ fn intern_write(
81
80
op : * mut Operator ,
82
81
file : JString ,
83
82
content : JString ,
84
- ) -> Result < jobject > {
83
+ ) -> Result < jlong > {
84
+ let op = unsafe { & mut * op } ;
85
+ let id = request_id ( env) ?;
86
+
87
+ let file = env. get_string ( & file) ?. to_str ( ) ?. to_string ( ) ;
88
+ let content = env. get_string ( & content) ?. to_str ( ) ?. to_string ( ) ;
89
+
90
+ let runtime = unsafe { RUNTIME . get_unchecked ( ) } ;
91
+ runtime. spawn ( async move {
92
+ let result = do_write ( op, file, content) . await ;
93
+ complete_future ( id, result. map ( |_| JValueOwned :: Void ) )
94
+ } ) ;
95
+
96
+ Ok ( id)
97
+ }
98
+
99
+ async fn do_write ( op : & mut Operator , file : String , content : String ) -> Result < ( ) > {
100
+ Ok ( op. write ( & file, content) . await ?)
101
+ }
102
+
103
+ /// # Safety
104
+ ///
105
+ /// This function should not be called before the Operator are ready.
106
+ #[ no_mangle]
107
+ pub unsafe extern "system" fn Java_org_apache_opendal_Operator_stat (
108
+ mut env : JNIEnv ,
109
+ _: JClass ,
110
+ op : * mut Operator ,
111
+ file : JString ,
112
+ ) -> jlong {
113
+ intern_stat ( & mut env, op, file) . unwrap_or_else ( |e| {
114
+ e. throw ( & mut env) ;
115
+ 0
116
+ } )
117
+ }
118
+
119
+ fn intern_stat ( env : & mut JNIEnv , op : * mut Operator , file : JString ) -> Result < jlong > {
85
120
let op = unsafe { & mut * op } ;
86
- let file: String = env. get_string ( & file) ?. into ( ) ;
87
- let content: String = env. get_string ( & content) ?. into ( ) ;
121
+ let id = request_id ( env) ?;
122
+
123
+ let file = env. get_string ( & file) ?. to_str ( ) ?. to_string ( ) ;
124
+
125
+ let runtime = unsafe { RUNTIME . get_unchecked ( ) } ;
126
+ runtime. spawn ( async move {
127
+ let result = do_stat ( op, file) . await ;
128
+ complete_future ( id, result. map ( JValueOwned :: Long ) )
129
+ } ) ;
88
130
89
- let class = "java/util/concurrent/CompletableFuture" ;
90
- let f = env. new_object ( class, "()V" , & [ ] ) ?;
131
+ Ok ( id)
132
+ }
133
+
134
+ async fn do_stat ( op : & mut Operator , file : String ) -> Result < jlong > {
135
+ let metadata = op. stat ( & file) . await ?;
136
+ Ok ( Box :: into_raw ( Box :: new ( metadata) ) as jlong )
137
+ }
138
+
139
+ /// # Safety
140
+ ///
141
+ /// This function should not be called before the Operator are ready.
142
+ #[ no_mangle]
143
+ pub unsafe extern "system" fn Java_org_apache_opendal_Operator_read (
144
+ mut env : JNIEnv ,
145
+ _: JClass ,
146
+ op : * mut Operator ,
147
+ file : JString ,
148
+ ) -> jlong {
149
+ intern_read ( & mut env, op, file) . unwrap_or_else ( |e| {
150
+ e. throw ( & mut env) ;
151
+ 0
152
+ } )
153
+ }
154
+
155
+ fn intern_read ( env : & mut JNIEnv , op : * mut Operator , file : JString ) -> Result < jlong > {
156
+ let op = unsafe { & mut * op } ;
157
+ let id = request_id ( env) ?;
91
158
92
- // keep the future alive, so that we can complete it later
93
- // but this approach will be limited by global ref table size (65535)
94
- let future = env. new_global_ref ( & f) ?;
159
+ let file = env. get_string ( & file) ?. to_str ( ) ?. to_string ( ) ;
95
160
96
161
let runtime = unsafe { RUNTIME . get_unchecked ( ) } ;
97
162
runtime. spawn ( async move {
98
- let result = match op. write ( & file, content) . await {
99
- Ok ( ( ) ) => Ok ( JObject :: null ( ) ) ,
100
- Err ( err) => Err ( Error :: from ( err) ) ,
101
- } ;
102
- complete_future ( future. as_ref ( ) , result)
163
+ let result = do_read ( op, file) . await ;
164
+ complete_future ( id, result. map ( JValueOwned :: Object ) )
103
165
} ) ;
104
166
105
- Ok ( f. into_raw ( ) )
167
+ Ok ( id)
168
+ }
169
+
170
+ async fn do_read < ' local > ( op : & mut Operator , file : String ) -> Result < JObject < ' local > > {
171
+ let content = op. read ( & file) . await ?;
172
+ let content = String :: from_utf8 ( content) ?;
173
+
174
+ let env = unsafe { get_current_env ( ) } ;
175
+ let result = env. new_string ( content) ?;
176
+ Ok ( result. into ( ) )
177
+ }
178
+
179
+ fn request_id ( env : & mut JNIEnv ) -> Result < jlong > {
180
+ let registry = env
181
+ . call_static_method (
182
+ "org/apache/opendal/Operator" ,
183
+ "registry" ,
184
+ "()Lorg/apache/opendal/Operator$AsyncRegistry;" ,
185
+ & [ ] ,
186
+ ) ?
187
+ . l ( ) ?;
188
+ Ok ( env. call_method ( registry, "requestId" , "()J" , & [ ] ) ?. j ( ) ?)
106
189
}
107
190
108
- fn complete_future ( future : & JObject , result : Result < JObject > ) {
191
+ fn make_object < ' local > (
192
+ env : & mut JNIEnv < ' local > ,
193
+ value : JValueOwned < ' local > ,
194
+ ) -> Result < JObject < ' local > > {
195
+ let o = match value {
196
+ JValueOwned :: Object ( o) => o,
197
+ JValueOwned :: Byte ( _) => env. new_object ( "java/lang/Long" , "(B)V" , & [ value. borrow ( ) ] ) ?,
198
+ JValueOwned :: Char ( _) => env. new_object ( "java/lang/Char" , "(C)V" , & [ value. borrow ( ) ] ) ?,
199
+ JValueOwned :: Short ( _) => env. new_object ( "java/lang/Short" , "(S)V" , & [ value. borrow ( ) ] ) ?,
200
+ JValueOwned :: Int ( _) => env. new_object ( "java/lang/Integer" , "(I)V" , & [ value. borrow ( ) ] ) ?,
201
+ JValueOwned :: Long ( _) => env. new_object ( "java/lang/Long" , "(J)V" , & [ value. borrow ( ) ] ) ?,
202
+ JValueOwned :: Bool ( _) => env. new_object ( "java/lang/Boolean" , "(Z)V" , & [ value. borrow ( ) ] ) ?,
203
+ JValueOwned :: Float ( _) => env. new_object ( "java/lang/Float" , "(F)V" , & [ value. borrow ( ) ] ) ?,
204
+ JValueOwned :: Double ( _) => env. new_object ( "java/lang/Double" , "(D)V" , & [ value. borrow ( ) ] ) ?,
205
+ JValueOwned :: Void => JObject :: null ( ) ,
206
+ } ;
207
+ Ok ( o)
208
+ }
209
+
210
+ fn complete_future ( id : jlong , result : Result < JValueOwned > ) {
109
211
let mut env = unsafe { get_current_env ( ) } ;
212
+ let future = get_future ( & mut env, id) . unwrap ( ) ;
110
213
match result {
111
- Ok ( result) => env
112
- . call_method (
214
+ Ok ( result) => {
215
+ let result = make_object ( & mut env, result) . unwrap ( ) ;
216
+ env. call_method (
113
217
future,
114
218
"complete" ,
115
219
"(Ljava/lang/Object;)Z" ,
116
220
& [ JValue :: Object ( & result) ] ,
117
221
)
118
- . unwrap ( ) ,
222
+ . unwrap ( )
223
+ }
119
224
Err ( err) => {
120
225
let exception = err. to_exception ( & mut env) . unwrap ( ) ;
121
226
env. call_method (
@@ -128,3 +233,22 @@ fn complete_future(future: &JObject, result: Result<JObject>) {
128
233
}
129
234
} ;
130
235
}
236
+
237
+ fn get_future < ' local > ( env : & mut JNIEnv < ' local > , id : jlong ) -> Result < JObject < ' local > > {
238
+ let registry = env
239
+ . call_static_method (
240
+ "org/apache/opendal/Operator" ,
241
+ "registry" ,
242
+ "()Lorg/apache/opendal/Operator$AsyncRegistry;" ,
243
+ & [ ] ,
244
+ ) ?
245
+ . l ( ) ?;
246
+ Ok ( env
247
+ . call_method (
248
+ registry,
249
+ "get" ,
250
+ "(J)Ljava/util/concurrent/CompletableFuture;" ,
251
+ & [ JValue :: Long ( id) ] ,
252
+ ) ?
253
+ . l ( ) ?)
254
+ }
0 commit comments