ShadowySpirits commented on issue #1572:
URL: 
https://github.com/apache/incubator-opendal/issues/1572#issuecomment-1519880511

   > Findings for JNI x async -
   > 
   > * 
https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/aws_engineer/using_jni.html
   > * [Why JNIEnv / JObject is not Send and how and I do an asynchronous 
callback? jni-rs/jni-rs#310](https://github.com/jni-rs/jni-rs/discussions/310)
   
   I found a possible solution: we can store JavaVM as thread local variable, 
and when we need to execute Java code, attach the rust-managed thread to obtain 
`Jenv`. Additionally, we cloud hold Jenv as thread local variable.
   
   ```rust
   #[no_mangle]
   pub extern "system" fn Java_org_apache_opendal_Operator_getOperator0(
       env: JNIEnv,
       _class: JClass,
       input: JString,
       params: JObject,
   ) -> jlong {
       // build operator
       let operator = 1;
   
       let java_vm = Arc::new(env.get_java_vm().unwrap());
   
       let runtime = Builder::new_multi_thread()
           .worker_threads(4)
           .on_thread_start(move || {
               JAVA_VM.with(|cell| {
                   *cell.borrow_mut() = Some(java_vm.clone());
               });
               // println!("thread started {:?}", box_ptr);
           })
           .build()
           .unwrap();
       
       Box::into_raw(Box::new((operator, runtime))) as jlong
   }
   ```
   
   And then we can use async/await without suspending the caller thread.
   
   ```rust
   #[no_mangle]
   pub unsafe extern "system" fn Java_org_apache_opendal_Operator_async_write(
       mut env: JNIEnv,
       _class: JClass,
       ptr: *mut (Operator, Runtime),
       file: JString,
       content: JString,
       future: JObject,
   ) {
       let (op, runtime) = &mut *ptr;
   
       let file: String = env.get_string(&file).unwrap().into();
       let content: String = env.get_string(&content).unwrap().into();
       let future = env.new_global_ref(future).unwrap();
   
       let x = async move {
           op.write(&file, content).await.unwrap();
           JAVA_VM.with(|cell| {
               let java_vm = cell.borrow();
               let java_vm = java_vm.as_ref().unwrap();
               let mut env = java_vm.attach_current_thread().unwrap();
               env.call_method(
                   future,
                   "complete",
                   "(Ljava/lang/Object;)Z",
                   &[JValue::Bool(1)],
               )
               .unwrap();
           });
       };
       runtime.spawn(x);
   }
   ```
   
   If the community approves this solution, I'd love to add asynchronous API to 
Java binding.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to