Search code examples
javac++callbackjava-native-interfaceakka

How to implement a callback function that calls from Java to C++?


I have a native C++ application that creates a JVM via JNI, instantiates a Java class (an Akka Actor) and invokes asynchronous non-blocking functions on it. I do this using JNI in C++ see snippet below.

Now I need to be notified in C++ when an Akka response arrives to my Akka Actor. For this I need to pass a native function pointer to Java so that the Akka Java Actor can callback to C++ when the response arrives. How can I do that?

Note that using thread synchronization primitives within the Akka Actor would be completely wrong because the Actor would not be able to receive messages if blocked awaiting for some monitor e.g. a CountDownLatch.

JavaVM* jvm = NULL;
JNIEnv *env = NULL;
JavaVMInitArgs vm_args;
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = "-Djava.class.path=/home/azg/code/hpcmom/target/1.1.9-SNAPSHOT/hpcmom-cmaes/hpcmom-cmaes-1.1.9-SNAPSHOT.jar";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_TRUE;
JNI_GetDefaultJavaVMInitArgs(&vm_args);

// create JVM
JNI_CreateJavaVM(&jvm, (void**) &env, &vm_args);
if (jvm == NULL) {
    throw std::runtime_error("failed creating JVM");
} else {
    log_info << "succeeded creating JVM";
}

// find CmaesClient class
jclass cmaesClass = env->FindClass("com/sfoam/hpcmom/cmaes/CmaesClient");
if (cmaesClass == NULL) {
    throw std::runtime_error("failed finding CmaesClient class");
} else {
    log_info << "succeeded finding CmaesClient class";
}

Solution

  • In your native code, store the address of your callback function in a long. Pass the long to your Java code and store it there, as a long.

    When its time for the callback to occur, have Java pass the function's address as a long into a native JNI function.

    In the native JNI function, cast the long as a function pointer, and invoke it.