use jni_sys::{
JavaVM, JavaVMInitArgs, JavaVMOption, jboolean, jint, JNI_FALSE, JNI_VERSION_1_8, JNIEnv,
jvalue
};
use jvm_class::JvmClass;
use jvm_method::JvmMethod;
use std::ffi::CString;
use std::ptr;
use std::os::raw::c_void;
pub struct Jvm {
jvm: *mut JavaVM,
jni_environment: *mut JNIEnv,
}
pub unsafe fn jvalue_from_jboolean(arg: jboolean) -> jvalue {
let mut jvalue = jvalue::default();
*jvalue.z() = arg;
jvalue
}
unsafe fn print_and_panic_on_jvm_exception(jni_environment: *mut JNIEnv) {
if !(**jni_environment).ExceptionOccurred.unwrap()(jni_environment).is_null() {
(**jni_environment).ExceptionDescribe.unwrap()(jni_environment);
panic!("An exception occurred");
};
}
unsafe fn print_jvm_exception(jni_environment: *mut JNIEnv) {
if !(**jni_environment).ExceptionOccurred.unwrap()(jni_environment).is_null() {
(**jni_environment).ExceptionDescribe.unwrap()(jni_environment);
};
}
impl Jvm {
pub unsafe fn new(jvm_option_strings: &[&str]) -> Jvm {
let mut jvm = Jvm {
jvm: ptr::null_mut(),
jni_environment: ptr::null_mut(),
};
let mut jvm_option_cstrings : Vec<CString> = Vec::new();
for jvm_option_string in jvm_option_strings {
jvm_option_cstrings.push(CString::new(*jvm_option_string).unwrap());
}
let mut jvm_options : Vec<JavaVMOption> = Vec::new();
for jvm_option_cstring in &jvm_option_cstrings {
let mut jvm_option = JavaVMOption::default();
jvm_option.optionString = jvm_option_cstring.as_ptr() as *mut i8;
jvm_options.push(jvm_option);
}
let mut jvm_arguments = JavaVMInitArgs::default();
jvm_arguments.version = JNI_VERSION_1_8;
jvm_arguments.options = jvm_options.as_mut_ptr();
jvm_arguments.nOptions = jvm_options.len() as i32;
jvm_arguments.ignoreUnrecognized = JNI_FALSE;
let _ = JNI_CreateJavaVM(
&mut jvm.jvm,
(&mut jvm.jni_environment as *mut *mut JNIEnv) as *mut *mut c_void,
(&mut jvm_arguments as *mut JavaVMInitArgs) as *mut c_void
);
jvm
}
pub unsafe fn call_static_boolean_method(
&self, jvm_class: &JvmClass, jvm_method: &JvmMethod, args: *const jvalue
) -> jboolean {
let result : jboolean = (**self.jni_environment).CallStaticBooleanMethodA.unwrap()(
self.jni_environment, *jvm_class.jvm_class_ptr(), *jvm_method.jvm_method_ptr(), args
);
print_and_panic_on_jvm_exception(self.jni_environment);
result
}
pub unsafe fn call_static_void_method(
&self, jvm_class: &JvmClass, jvm_method: &JvmMethod, args: *const jvalue
) {
(**self.jni_environment).CallStaticVoidMethodA.unwrap()(
self.jni_environment, *jvm_class.jvm_class_ptr(), *jvm_method.jvm_method_ptr(), args
);
print_and_panic_on_jvm_exception(self.jni_environment);
}
pub unsafe fn get_class(&self, jvm_class_name: &str) -> Option<JvmClass> {
let jvm_class_name_cstring = CString::new(jvm_class_name).unwrap();
let jvm_class_ptr =
(**self.jni_environment).FindClass.unwrap()(
self.jni_environment, jvm_class_name_cstring.as_ptr()
);
if !(**self.jni_environment).ExceptionOccurred.unwrap()(self.jni_environment).is_null() {
print_jvm_exception(self.jni_environment);
};
if jvm_class_ptr.is_null() {
return None;
}
JvmClass::new(self, jvm_class_ptr)
}
pub unsafe fn get_constructor(&self, jvm_class: &JvmClass, jvm_method_signature: &str) -> Option<JvmMethod> {
self.get_method(jvm_class, "<init>", jvm_method_signature)
}
pub unsafe fn get_method(
&self, jvm_class: &JvmClass, jvm_method_name: &str, jvm_method_signature: &str
) -> Option<JvmMethod> {
let jvm_method_name_cstring = CString::new(jvm_method_name).unwrap();
let jvm_method_signature_cstring = CString::new(jvm_method_signature).unwrap();
let jvm_method_ptr =
(**self.jni_environment).GetMethodID.unwrap()(
self.jni_environment, *jvm_class.jvm_class_ptr(), jvm_method_name_cstring.as_ptr(),
jvm_method_signature_cstring.as_ptr()
);
print_jvm_exception(self.jni_environment);
if jvm_method_ptr.is_null() {
return None;
}
JvmMethod::new(jvm_method_ptr)
}
pub unsafe fn get_static_method(
&self, jvm_class: &JvmClass, jvm_method_name: &str, jvm_method_signature: &str
) -> Option<JvmMethod> {
let jvm_method_name_cstring = CString::new(jvm_method_name).unwrap();
let jvm_method_signature_cstring = CString::new(jvm_method_signature).unwrap();
let jvm_method_ptr =
(**self.jni_environment).GetStaticMethodID.unwrap()(
self.jni_environment, *jvm_class.jvm_class_ptr(), jvm_method_name_cstring.as_ptr(),
jvm_method_signature_cstring.as_ptr()
);
print_jvm_exception(self.jni_environment);
if jvm_method_ptr.is_null() {
return None;
}
JvmMethod::new(jvm_method_ptr)
}
pub fn jni_environment(&self) -> *mut JNIEnv {
self.jni_environment
}
}
impl Drop for Jvm {
fn drop(&mut self) {
unsafe {
(**self.jvm).DestroyJavaVM.unwrap()(self.jvm);
}
}
}
#[link(name="jvm")]
extern {
fn JNI_CreateJavaVM(pvm: *mut *mut JavaVM, penv: *mut *mut c_void, args: *mut c_void) -> jint;
}