X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fjava.c;h=a8ffd8e3ddc158c83b0b9792ff859681b55e5445;hp=890df17c4440d8abfac8dc24a1e6cfe3f3abaf49;hb=61a1fa91ba73e4fe3a34949f77c5f017056f2b7a;hpb=aab902bb10a4e0a65abda511e6e362c554a2dcc6 diff --git a/src/java.c b/src/java.c index 890df17c..a8ffd8e3 100644 --- a/src/java.c +++ b/src/java.c @@ -24,6 +24,7 @@ #include "collectd.h" #include "plugin.h" #include "common.h" +#include "filter_chain.h" #include #include @@ -52,14 +53,6 @@ struct java_plugin_class_s /* {{{ */ typedef struct java_plugin_class_s java_plugin_class_t; /* }}} */ -struct java_plugin_config_s /* {{{ */ -{ - char *name; - oconfig_item_t *ci; -}; -typedef struct java_plugin_config_s java_plugin_config_t; -/* }}} */ - #define CB_TYPE_CONFIG 1 #define CB_TYPE_INIT 2 #define CB_TYPE_READ 3 @@ -68,6 +61,8 @@ typedef struct java_plugin_config_s java_plugin_config_t; #define CB_TYPE_SHUTDOWN 6 #define CB_TYPE_LOG 7 #define CB_TYPE_NOTIFICATION 8 +#define CB_TYPE_MATCH 9 +#define CB_TYPE_TARGET 10 struct cjni_callback_info_s /* {{{ */ { char *name; @@ -93,15 +88,13 @@ static size_t jvm_argc = 0; static java_plugin_class_t *java_classes_list = NULL; static size_t java_classes_list_len; -/* List of `config_item_t's for Java plugins */ -static java_plugin_config_t *java_plugin_configs = NULL; -static size_t java_plugin_configs_num = 0; - /* List of config, init, and shutdown callbacks. */ static cjni_callback_info_t *java_callbacks = NULL; static size_t java_callbacks_num = 0; static pthread_mutex_t java_callbacks_lock = PTHREAD_MUTEX_INITIALIZER; +static oconfig_item_t *config_block = NULL; + /* * Prototypes * @@ -120,6 +113,13 @@ static int cjni_flush (int timeout, const char *identifier, user_data_t *ud); static void cjni_log (int severity, const char *message, user_data_t *ud); static int cjni_notification (const notification_t *n, user_data_t *ud); +/* Create, destroy, and match/invoke functions, used by both, matches AND + * targets. */ +static int cjni_match_target_create (const oconfig_item_t *ci, void **user_data); +static int cjni_match_target_destroy (void **user_data); +static int cjni_match_target_invoke (const data_set_t *ds, value_list_t *vl, + notification_meta_t **meta, void **user_data); + /* * C to Java conversion functions */ @@ -229,7 +229,7 @@ static jobject ctoj_jlong_to_number (JNIEnv *jvm_env, jlong value) /* {{{ */ jmethodID m_long_constructor; /* Look up the java.lang.Long class */ - c_long = (*jvm_env)->FindClass (jvm_env, "java.lang.Long"); + c_long = (*jvm_env)->FindClass (jvm_env, "java/lang/Long"); if (c_long == NULL) { ERROR ("java plugin: ctoj_jlong_to_number: Looking up the " @@ -257,7 +257,7 @@ static jobject ctoj_jdouble_to_number (JNIEnv *jvm_env, jdouble value) /* {{{ */ jmethodID m_double_constructor; /* Look up the java.lang.Long class */ - c_double = (*jvm_env)->FindClass (jvm_env, "java.lang.Double"); + c_double = (*jvm_env)->FindClass (jvm_env, "java/lang/Double"); if (c_double == NULL) { ERROR ("java plugin: ctoj_jdouble_to_number: Looking up the " @@ -286,11 +286,15 @@ static jobject ctoj_value_to_number (JNIEnv *jvm_env, /* {{{ */ return (ctoj_jlong_to_number (jvm_env, (jlong) value.counter)); else if (ds_type == DS_TYPE_GAUGE) return (ctoj_jdouble_to_number (jvm_env, (jdouble) value.gauge)); + if (ds_type == DS_TYPE_DERIVE) + return (ctoj_jlong_to_number (jvm_env, (jlong) value.derive)); + if (ds_type == DS_TYPE_ABSOLUTE) + return (ctoj_jlong_to_number (jvm_env, (jlong) value.absolute)); else return (NULL); } /* }}} jobject ctoj_value_to_number */ -/* Convert a data_source_t to a org.collectd.api.DataSource */ +/* Convert a data_source_t to a org/collectd/api/DataSource */ static jobject ctoj_data_source (JNIEnv *jvm_env, /* {{{ */ const data_source_t *dsrc) { @@ -301,11 +305,11 @@ static jobject ctoj_data_source (JNIEnv *jvm_env, /* {{{ */ /* Look up the DataSource class */ c_datasource = (*jvm_env)->FindClass (jvm_env, - "org.collectd.api.DataSource"); + "org/collectd/api/DataSource"); if (c_datasource == NULL) { ERROR ("java plugin: ctoj_data_source: " - "FindClass (org.collectd.api.DataSource) failed."); + "FindClass (org/collectd/api/DataSource) failed."); return (NULL); } @@ -376,7 +380,7 @@ static jobject ctoj_data_source (JNIEnv *jvm_env, /* {{{ */ return (o_datasource); } /* }}} jobject ctoj_data_source */ -/* Convert a oconfig_value_t to a org.collectd.api.OConfigValue */ +/* Convert a oconfig_value_t to a org/collectd/api/OConfigValue */ static jobject ctoj_oconfig_value (JNIEnv *jvm_env, /* {{{ */ oconfig_value_t ocvalue) { @@ -389,11 +393,11 @@ static jobject ctoj_oconfig_value (JNIEnv *jvm_env, /* {{{ */ o_argument = NULL; c_ocvalue = (*jvm_env)->FindClass (jvm_env, - "org.collectd.api.OConfigValue"); + "org/collectd/api/OConfigValue"); if (c_ocvalue == NULL) { ERROR ("java plugin: ctoj_oconfig_value: " - "FindClass (org.collectd.api.OConfigValue) failed."); + "FindClass (org/collectd/api/OConfigValue) failed."); return (NULL); } @@ -476,7 +480,7 @@ static jobject ctoj_oconfig_value (JNIEnv *jvm_env, /* {{{ */ return (o_ocvalue); } /* }}} jobject ctoj_oconfig_value */ -/* Convert a oconfig_item_t to a org.collectd.api.OConfigItem */ +/* Convert a oconfig_item_t to a org/collectd/api/OConfigItem */ static jobject ctoj_oconfig_item (JNIEnv *jvm_env, /* {{{ */ const oconfig_item_t *ci) { @@ -488,11 +492,11 @@ static jobject ctoj_oconfig_item (JNIEnv *jvm_env, /* {{{ */ jobject o_ocitem; int i; - c_ocitem = (*jvm_env)->FindClass (jvm_env, "org.collectd.api.OConfigItem"); + c_ocitem = (*jvm_env)->FindClass (jvm_env, "org/collectd/api/OConfigItem"); if (c_ocitem == NULL) { ERROR ("java plugin: ctoj_oconfig_item: " - "FindClass (org.collectd.api.OConfigItem) failed."); + "FindClass (org/collectd/api/OConfigItem) failed."); return (NULL); } @@ -582,14 +586,14 @@ static jobject ctoj_oconfig_item (JNIEnv *jvm_env, /* {{{ */ return (NULL); } - (*jvm_env)->CallVoidMethod (jvm_env, o_ocitem, m_addvalue, o_child); + (*jvm_env)->CallVoidMethod (jvm_env, o_ocitem, m_addchild, o_child); (*jvm_env)->DeleteLocalRef (jvm_env, o_child); } /* }}} for (i = 0; i < ci->children_num; i++) */ return (o_ocitem); } /* }}} jobject ctoj_oconfig_item */ -/* Convert a data_set_t to a org.collectd.api.DataSet */ +/* Convert a data_set_t to a org/collectd/api/DataSet */ static jobject ctoj_data_set (JNIEnv *jvm_env, const data_set_t *ds) /* {{{ */ { jclass c_dataset; @@ -599,18 +603,18 @@ static jobject ctoj_data_set (JNIEnv *jvm_env, const data_set_t *ds) /* {{{ */ jobject o_dataset; int i; - /* Look up the org.collectd.api.DataSet class */ - c_dataset = (*jvm_env)->FindClass (jvm_env, "org.collectd.api.DataSet"); + /* Look up the org/collectd/api/DataSet class */ + c_dataset = (*jvm_env)->FindClass (jvm_env, "org/collectd/api/DataSet"); if (c_dataset == NULL) { ERROR ("java plugin: ctoj_data_set: Looking up the " - "org.collectd.api.DataSet class failed."); + "org/collectd/api/DataSet class failed."); return (NULL); } /* Search for the `DataSet (String type)' constructor. */ m_constructor = (*jvm_env)->GetMethodID (jvm_env, - c_dataset, "", "(Ljava.lang.String;)V"); + c_dataset, "", "(Ljava/lang/String;)V"); if (m_constructor == NULL) { ERROR ("java plugin: ctoj_data_set: Looking up the " @@ -620,7 +624,7 @@ static jobject ctoj_data_set (JNIEnv *jvm_env, const data_set_t *ds) /* {{{ */ /* Search for the `void addDataSource (DataSource)' method. */ m_add = (*jvm_env)->GetMethodID (jvm_env, - c_dataset, "addDataSource", "(Lorg.collectd.api.DataSource;)V"); + c_dataset, "addDataSource", "(Lorg/collectd/api/DataSource;)V"); if (m_add == NULL) { ERROR ("java plugin: ctoj_data_set: Looking up the " @@ -707,7 +711,7 @@ static int ctoj_value_list_add_data_set (JNIEnv *jvm_env, /* {{{ */ /* Look for the `void setDataSource (List ds)' method. */ m_setdataset = (*jvm_env)->GetMethodID (jvm_env, c_valuelist, - "setDataSet", "(Lorg.collectd.api.DataSet;)V"); + "setDataSet", "(Lorg/collectd/api/DataSet;)V"); if (m_setdataset == NULL) { ERROR ("java plugin: ctoj_value_list_add_data_set: " @@ -734,7 +738,7 @@ static int ctoj_value_list_add_data_set (JNIEnv *jvm_env, /* {{{ */ return (0); } /* }}} int ctoj_value_list_add_data_set */ -/* Convert a value_list_t (and data_set_t) to a org.collectd.api.ValueList */ +/* Convert a value_list_t (and data_set_t) to a org/collectd/api/ValueList */ static jobject ctoj_value_list (JNIEnv *jvm_env, /* {{{ */ const data_set_t *ds, const value_list_t *vl) { @@ -747,11 +751,11 @@ static jobject ctoj_value_list (JNIEnv *jvm_env, /* {{{ */ /* First, create a new ValueList instance.. * Look up the class.. */ c_valuelist = (*jvm_env)->FindClass (jvm_env, - "org.collectd.api.ValueList"); + "org/collectd/api/ValueList"); if (c_valuelist == NULL) { ERROR ("java plugin: ctoj_value_list: " - "FindClass (org.collectd.api.ValueList) failed."); + "FindClass (org/collectd/api/ValueList) failed."); return (NULL); } @@ -840,7 +844,7 @@ static jobject ctoj_value_list (JNIEnv *jvm_env, /* {{{ */ return (o_valuelist); } /* }}} jobject ctoj_value_list */ -/* Convert a notification_t to a org.collectd.api.Notification */ +/* Convert a notification_t to a org/collectd/api/Notification */ static jobject ctoj_notification (JNIEnv *jvm_env, /* {{{ */ const notification_t *n) { @@ -852,11 +856,11 @@ static jobject ctoj_notification (JNIEnv *jvm_env, /* {{{ */ /* First, create a new Notification instance.. * Look up the class.. */ c_notification = (*jvm_env)->FindClass (jvm_env, - "org.collectd.api.Notification"); + "org/collectd/api/Notification"); if (c_notification == NULL) { ERROR ("java plugin: ctoj_notification: " - "FindClass (org.collectd.api.Notification) failed."); + "FindClass (org/collectd/api/Notification) failed."); return (NULL); } @@ -1044,33 +1048,39 @@ static int jtoc_value (JNIEnv *jvm_env, /* {{{ */ class_ptr = (*jvm_env)->GetObjectClass (jvm_env, object_ptr); - if (ds_type == DS_TYPE_COUNTER) + if (ds_type == DS_TYPE_GAUGE) { - jlong tmp_long; + jdouble tmp_double; - status = jtoc_long (jvm_env, &tmp_long, - class_ptr, object_ptr, "longValue"); + status = jtoc_double (jvm_env, &tmp_double, + class_ptr, object_ptr, "doubleValue"); if (status != 0) { ERROR ("java plugin: jtoc_value: " - "jtoc_long failed."); + "jtoc_double failed."); return (-1); } - (*ret_value).counter = (counter_t) tmp_long; + (*ret_value).gauge = (gauge_t) tmp_double; } else { - jdouble tmp_double; + jlong tmp_long; - status = jtoc_double (jvm_env, &tmp_double, - class_ptr, object_ptr, "doubleValue"); + status = jtoc_long (jvm_env, &tmp_long, + class_ptr, object_ptr, "longValue"); if (status != 0) { ERROR ("java plugin: jtoc_value: " - "jtoc_double failed."); + "jtoc_long failed."); return (-1); } - (*ret_value).gauge = (gauge_t) tmp_double; + + if (ds_type == DS_TYPE_DERIVE) + (*ret_value).derive = (derive_t) tmp_long; + else if (ds_type == DS_TYPE_ABSOLUTE) + (*ret_value).absolute = (absolute_t) tmp_long; + else + (*ret_value).counter = (counter_t) tmp_long; } return (0); @@ -1181,7 +1191,7 @@ static int jtoc_values_array (JNIEnv *jvm_env, /* {{{ */ return (0); } /* }}} int jtoc_values_array */ -/* Convert a org.collectd.api.ValueList to a value_list_t. */ +/* Convert a org/collectd/api/ValueList to a value_list_t. */ static int jtoc_value_list (JNIEnv *jvm_env, value_list_t *vl, /* {{{ */ jobject object_ptr) { @@ -1253,7 +1263,7 @@ static int jtoc_value_list (JNIEnv *jvm_env, value_list_t *vl, /* {{{ */ return (0); } /* }}} int jtoc_value_list */ -/* Convert a org.collectd.api.Notification to a notification_t. */ +/* Convert a org/collectd/api/Notification to a notification_t. */ static int jtoc_notification (JNIEnv *jvm_env, notification_t *n, /* {{{ */ jobject object_ptr) { @@ -1409,7 +1419,8 @@ static jint JNICALL cjni_api_register_read (JNIEnv *jvm_env, /* {{{ */ ud.data = (void *) cbi; ud.free_func = cjni_callback_info_destroy; - plugin_register_complex_read (cbi->name, cjni_read, &ud); + plugin_register_complex_read (/* group = */ NULL, cbi->name, cjni_read, + /* interval = */ NULL, &ud); (*jvm_env)->DeleteLocalRef (jvm_env, o_read); @@ -1516,6 +1527,85 @@ static jint JNICALL cjni_api_register_notification (JNIEnv *jvm_env, /* {{{ */ return (0); } /* }}} jint cjni_api_register_notification */ +static jint JNICALL cjni_api_register_match_target (JNIEnv *jvm_env, /* {{{ */ + jobject this, jobject o_name, jobject o_match, int type) +{ + int status; + const char *c_name; + + c_name = (*jvm_env)->GetStringUTFChars (jvm_env, o_name, 0); + if (c_name == NULL) + { + ERROR ("java plugin: cjni_api_register_match_target: " + "GetStringUTFChars failed."); + return (-1); + } + + status = cjni_callback_register (jvm_env, o_name, o_match, type); + if (status != 0) + { + (*jvm_env)->ReleaseStringUTFChars (jvm_env, o_name, c_name); + return (-1); + } + + if (type == CB_TYPE_MATCH) + { + match_proc_t m_proc; + + memset (&m_proc, 0, sizeof (m_proc)); + m_proc.create = cjni_match_target_create; + m_proc.destroy = cjni_match_target_destroy; + m_proc.match = (void *) cjni_match_target_invoke; + + status = fc_register_match (c_name, m_proc); + } + else if (type == CB_TYPE_TARGET) + { + target_proc_t t_proc; + + memset (&t_proc, 0, sizeof (t_proc)); + t_proc.create = cjni_match_target_create; + t_proc.destroy = cjni_match_target_destroy; + t_proc.invoke = cjni_match_target_invoke; + + status = fc_register_target (c_name, t_proc); + } + else + { + ERROR ("java plugin: cjni_api_register_match_target: " + "Don't know whether to create a match or a target."); + (*jvm_env)->ReleaseStringUTFChars (jvm_env, o_name, c_name); + return (-1); + } + + if (status != 0) + { + ERROR ("java plugin: cjni_api_register_match_target: " + "%s failed.", + (type == CB_TYPE_MATCH) ? "fc_register_match" : "fc_register_target"); + (*jvm_env)->ReleaseStringUTFChars (jvm_env, o_name, c_name); + return (-1); + } + + (*jvm_env)->ReleaseStringUTFChars (jvm_env, o_name, c_name); + + return (0); +} /* }}} jint cjni_api_register_match_target */ + +static jint JNICALL cjni_api_register_match (JNIEnv *jvm_env, /* {{{ */ + jobject this, jobject o_name, jobject o_match) +{ + return (cjni_api_register_match_target (jvm_env, this, o_name, o_match, + CB_TYPE_MATCH)); +} /* }}} jint cjni_api_register_match */ + +static jint JNICALL cjni_api_register_target (JNIEnv *jvm_env, /* {{{ */ + jobject this, jobject o_name, jobject o_target) +{ + return (cjni_api_register_match_target (jvm_env, this, o_name, o_target, + CB_TYPE_TARGET)); +} /* }}} jint cjni_api_register_target */ + static void JNICALL cjni_api_log (JNIEnv *jvm_env, /* {{{ */ jobject this, jint severity, jobject o_message) { @@ -1586,6 +1676,14 @@ static JNINativeMethod jni_api_functions[] = /* {{{ */ "(Ljava/lang/String;Lorg/collectd/api/CollectdNotificationInterface;)I", cjni_api_register_notification }, + { "registerMatch", + "(Ljava/lang/String;Lorg/collectd/api/CollectdMatchFactoryInterface;)I", + cjni_api_register_match }, + + { "registerTarget", + "(Ljava/lang/String;Lorg/collectd/api/CollectdTargetFactoryInterface;)I", + cjni_api_register_target }, + { "log", "(ILjava/lang/String;)V", cjni_api_log }, @@ -1646,7 +1744,19 @@ static cjni_callback_info_t *cjni_callback_info_create (JNIEnv *jvm_env, /* {{{ case CB_TYPE_NOTIFICATION: method_name = "notification"; - method_signature = "(LLorg/collectd/api/Notification;)I"; + method_signature = "(Lorg/collectd/api/Notification;)I"; + break; + + case CB_TYPE_MATCH: + method_name = "createMatch"; + method_signature = "(Lorg/collectd/api/OConfigItem;)" + "Lorg/collectd/api/CollectdMatchInterface;"; + break; + + case CB_TYPE_TARGET: + method_name = "createTarget"; + method_signature = "(Lorg/collectd/api/OConfigItem;)" + "Lorg/collectd/api/CollectdTargetInterface;"; break; default: @@ -1684,7 +1794,15 @@ static cjni_callback_info_t *cjni_callback_info_create (JNIEnv *jvm_env, /* {{{ (*jvm_env)->ReleaseStringUTFChars (jvm_env, o_name, c_name); - cbi->class = (*jvm_env)->GetObjectClass (jvm_env, o_callback); + cbi->object = (*jvm_env)->NewGlobalRef (jvm_env, o_callback); + if (cbi->object == NULL) + { + ERROR ("java plugin: cjni_callback_info_create: NewGlobalRef failed."); + free (cbi); + return (NULL); + } + + cbi->class = (*jvm_env)->GetObjectClass (jvm_env, cbi->object); if (cbi->class == NULL) { ERROR ("java plugin: cjni_callback_info_create: GetObjectClass failed."); @@ -1692,8 +1810,6 @@ static cjni_callback_info_t *cjni_callback_info_create (JNIEnv *jvm_env, /* {{{ return (NULL); } - cbi->object = o_callback; - cbi->method = (*jvm_env)->GetMethodID (jvm_env, cbi->class, method_name, method_signature); if (cbi->method == NULL) @@ -1705,8 +1821,6 @@ static cjni_callback_info_t *cjni_callback_info_create (JNIEnv *jvm_env, /* {{{ return (NULL); } - (*jvm_env)->NewGlobalRef (jvm_env, o_callback); - return (cbi); } /* }}} cjni_callback_info_t cjni_callback_info_create */ @@ -1741,6 +1855,14 @@ static int cjni_callback_register (JNIEnv *jvm_env, /* {{{ */ type_str = "shutdown"; break; + case CB_TYPE_MATCH: + type_str = "match"; + break; + + case CB_TYPE_TARGET: + type_str = "target"; + break; + default: type_str = ""; } @@ -1772,6 +1894,119 @@ static int cjni_callback_register (JNIEnv *jvm_env, /* {{{ */ return (0); } /* }}} int cjni_callback_register */ +/* Callback for `pthread_key_create'. It frees the data contained in + * `jvm_env_key' and prints a warning if the reference counter is not zero. */ +static void cjni_jvm_env_destroy (void *args) /* {{{ */ +{ + cjni_jvm_env_t *cjni_env; + + if (args == NULL) + return; + + cjni_env = (cjni_jvm_env_t *) args; + + if (cjni_env->reference_counter > 0) + { + ERROR ("java plugin: cjni_jvm_env_destroy: " + "cjni_env->reference_counter = %i;", cjni_env->reference_counter); + } + + if (cjni_env->jvm_env != NULL) + { + ERROR ("java plugin: cjni_jvm_env_destroy: cjni_env->jvm_env = %p;", + (void *) cjni_env->jvm_env); + } + + /* The pointer is allocated in `cjni_thread_attach' */ + free (cjni_env); +} /* }}} void cjni_jvm_env_destroy */ + +/* Register ``native'' functions with the JVM. Native functions are C-functions + * that can be called by Java code. */ +static int cjni_init_native (JNIEnv *jvm_env) /* {{{ */ +{ + jclass api_class_ptr; + int status; + + api_class_ptr = (*jvm_env)->FindClass (jvm_env, "org/collectd/api/Collectd"); + if (api_class_ptr == NULL) + { + ERROR ("cjni_init_native: Cannot find the API class \"org.collectd.api" + ".Collectd\". Please set the correct class path " + "using 'JVMArg \"-Djava.class.path=...\"'."); + return (-1); + } + + status = (*jvm_env)->RegisterNatives (jvm_env, api_class_ptr, + jni_api_functions, (jint) jni_api_functions_num); + if (status != 0) + { + ERROR ("cjni_init_native: RegisterNatives failed with status %i.", status); + return (-1); + } + + return (0); +} /* }}} int cjni_init_native */ + +/* Create the JVM. This is called when the first thread tries to access the JVM + * via cjni_thread_attach. */ +static int cjni_create_jvm (void) /* {{{ */ +{ + JNIEnv *jvm_env; + JavaVMInitArgs vm_args; + JavaVMOption vm_options[jvm_argc]; + + int status; + size_t i; + + if (jvm != NULL) + return (0); + + status = pthread_key_create (&jvm_env_key, cjni_jvm_env_destroy); + if (status != 0) + { + ERROR ("java plugin: cjni_create_jvm: pthread_key_create failed " + "with status %i.", status); + return (-1); + } + + jvm_env = NULL; + + memset (&vm_args, 0, sizeof (vm_args)); + vm_args.version = JNI_VERSION_1_2; + vm_args.options = vm_options; + vm_args.nOptions = (jint) jvm_argc; + + for (i = 0; i < jvm_argc; i++) + { + DEBUG ("java plugin: cjni_create_jvm: jvm_argv[%zu] = %s", + i, jvm_argv[i]); + vm_args.options[i].optionString = jvm_argv[i]; + } + + status = JNI_CreateJavaVM (&jvm, (void *) &jvm_env, (void *) &vm_args); + if (status != 0) + { + ERROR ("java plugin: cjni_create_jvm: " + "JNI_CreateJavaVM failed with status %i.", + status); + return (-1); + } + assert (jvm != NULL); + assert (jvm_env != NULL); + + /* Call RegisterNatives */ + status = cjni_init_native (jvm_env); + if (status != 0) + { + ERROR ("java plugin: cjni_create_jvm: cjni_init_native failed."); + return (-1); + } + + DEBUG ("java plugin: The JVM has been created."); + return (0); +} /* }}} int cjni_create_jvm */ + /* Increase the reference counter to the JVM for this thread. If it was zero, * attach the JVM first. */ static JNIEnv *cjni_thread_attach (void) /* {{{ */ @@ -1779,6 +2014,21 @@ static JNIEnv *cjni_thread_attach (void) /* {{{ */ cjni_jvm_env_t *cjni_env; JNIEnv *jvm_env; + /* If we're the first thread to access the JVM, we'll have to create it + * first.. */ + if (jvm == NULL) + { + int status; + + status = cjni_create_jvm (); + if (status != 0) + { + ERROR ("java plugin: cjni_thread_attach: cjni_create_jvm failed."); + return (NULL); + } + } + assert (jvm != NULL); + cjni_env = pthread_getspecific (jvm_env_key); if (cjni_env == NULL) { @@ -1866,34 +2116,6 @@ static int cjni_thread_detach (void) /* {{{ */ return (0); } /* }}} JNIEnv *cjni_thread_attach */ -/* Callback for `pthread_key_create'. It frees the data contained in - * `jvm_env_key' and prints a warning if the reference counter is not zero. */ -static void cjni_jvm_env_destroy (void *args) /* {{{ */ -{ - cjni_jvm_env_t *cjni_env; - - if (args == NULL) - return; - - cjni_env = (cjni_jvm_env_t *) args; - - if (cjni_env->reference_counter > 0) - { - ERROR ("java plugin: cjni_jvm_env_destroy: " - "cjni_env->reference_counter = %i;", cjni_env->reference_counter); - } - - if (cjni_env->jvm_env != NULL) - { - ERROR ("java plugin: cjni_jvm_env_destroy: cjni_env->jvm_env = %p;", - (void *) cjni_env->jvm_env); - } - - /* The pointer is allocated in `cjni_thread_attach' */ - free (cjni_env); -} /* }}} void cjni_jvm_env_destroy */ - -/* Boring configuration functions.. {{{ */ static int cjni_config_add_jvm_arg (oconfig_item_t *ci) /* {{{ */ { char **tmp; @@ -1904,6 +2126,15 @@ static int cjni_config_add_jvm_arg (oconfig_item_t *ci) /* {{{ */ return (-1); } + if (jvm != NULL) + { + ERROR ("java plugin: All `JVMArg' options MUST appear before all " + "`LoadPlugin' options! The JVM is already started and I have to " + "ignore this argument: %s", + ci->values[0].value.string); + return (-1); + } + tmp = (char **) realloc (jvm_argv, sizeof (char *) * (jvm_argc + 1)); if (tmp == NULL) { @@ -1925,7 +2156,10 @@ static int cjni_config_add_jvm_arg (oconfig_item_t *ci) /* {{{ */ static int cjni_config_load_plugin (oconfig_item_t *ci) /* {{{ */ { - java_plugin_class_t *tmp; + JNIEnv *jvm_env; + java_plugin_class_t *class; + jmethodID constructor_id; + jobject tmp_object; if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) { @@ -1933,25 +2167,82 @@ static int cjni_config_load_plugin (oconfig_item_t *ci) /* {{{ */ return (-1); } - tmp = (java_plugin_class_t *) realloc (java_classes_list, + jvm_env = cjni_thread_attach (); + if (jvm_env == NULL) + return (-1); + + class = (java_plugin_class_t *) realloc (java_classes_list, (java_classes_list_len + 1) * sizeof (*java_classes_list)); - if (tmp == NULL) + if (class == NULL) { ERROR ("java plugin: realloc failed."); + cjni_thread_detach (); return (-1); } - java_classes_list = tmp; - tmp = java_classes_list + java_classes_list_len; + java_classes_list = class; + class = java_classes_list + java_classes_list_len; - memset (tmp, 0, sizeof (*tmp)); - tmp->name = strdup (ci->values[0].value.string); - if (tmp->name == NULL) + memset (class, 0, sizeof (*class)); + class->name = strdup (ci->values[0].value.string); + if (class->name == NULL) { ERROR ("java plugin: strdup failed."); + cjni_thread_detach (); return (-1); } - tmp->class = NULL; - tmp->object = NULL; + class->class = NULL; + class->object = NULL; + + { /* Replace all dots ('.') with slashes ('/'). Dots are usually used + thorough the Java community, but (Sun's) `FindClass' and friends need + slashes. */ + size_t i; + for (i = 0; class->name[i] != 0; i++) + if (class->name[i] == '.') + class->name[i] = '/'; + } + + DEBUG ("java plugin: Loading class %s", class->name); + + class->class = (*jvm_env)->FindClass (jvm_env, class->name); + if (class->class == NULL) + { + ERROR ("java plugin: cjni_config_load_plugin: FindClass (%s) failed.", + class->name); + cjni_thread_detach (); + free (class->name); + return (-1); + } + + constructor_id = (*jvm_env)->GetMethodID (jvm_env, class->class, + "", "()V"); + if (constructor_id == NULL) + { + ERROR ("java plugin: cjni_config_load_plugin: " + "Could not find the constructor for `%s'.", + class->name); + cjni_thread_detach (); + free (class->name); + return (-1); + } + + tmp_object = (*jvm_env)->NewObject (jvm_env, class->class, + constructor_id); + if (tmp_object != NULL) + class->object = (*jvm_env)->NewGlobalRef (jvm_env, tmp_object); + else + class->object = NULL; + if (class->object == NULL) + { + ERROR ("java plugin: cjni_config_load_plugin: " + "Could create a new `%s' object.", + class->name); + cjni_thread_detach (); + free (class->name); + return (-1); + } + + cjni_thread_detach (); java_classes_list_len++; @@ -1960,10 +2251,15 @@ static int cjni_config_load_plugin (oconfig_item_t *ci) /* {{{ */ static int cjni_config_plugin_block (oconfig_item_t *ci) /* {{{ */ { - java_plugin_config_t *tmp; - char *name; + JNIEnv *jvm_env; + cjni_callback_info_t *cbi; + jobject o_ocitem; + const char *name; size_t i; + jclass class; + jmethodID method; + if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) { WARNING ("java plugin: `Plugin' blocks " @@ -1971,57 +2267,57 @@ static int cjni_config_plugin_block (oconfig_item_t *ci) /* {{{ */ return (-1); } - name = strdup (ci->values[0].value.string); - if (name == NULL) + name = ci->values[0].value.string; + + cbi = NULL; + for (i = 0; i < java_callbacks_num; i++) { - ERROR ("java plugin: cjni_config_plugin_block: strdup faiiled."); - return (-1); + if (java_callbacks[i].type != CB_TYPE_CONFIG) + continue; + + if (strcmp (name, java_callbacks[i].name) != 0) + continue; + + cbi = java_callbacks + i; + break; } - for (i = 0; i < java_plugin_configs_num; i++) + if (cbi == NULL) { - if (strcmp (java_plugin_configs[i].name, name) == 0) - { - WARNING ("java plugin: There is more than one block. " - "This is currently not supported - " - "only the first block will be used!", - name); - free (name); - return (0); - } + NOTICE ("java plugin: Configuration block for `%s' found, but no such " + "configuration callback has been registered. Please make sure, the " + "`LoadPlugin' lines precede the `Plugin' blocks.", + name); + return (0); } - tmp = (java_plugin_config_t *) realloc (java_plugin_configs, - (java_plugin_configs_num + 1) * sizeof (*java_plugin_configs)); - if (tmp == NULL) - { - ERROR ("java plugin: cjni_config_plugin_block: realloc failed."); - free (name); + DEBUG ("java plugin: Configuring %s", name); + + jvm_env = cjni_thread_attach (); + if (jvm_env == NULL) return (-1); - } - java_plugin_configs = tmp; - tmp = java_plugin_configs + java_plugin_configs_num; - tmp->name = name; - tmp->ci = oconfig_clone (ci); - if (tmp->ci == NULL) + o_ocitem = ctoj_oconfig_item (jvm_env, ci); + if (o_ocitem == NULL) { - ERROR ("java plugin: cjni_config_plugin_block: " - "oconfig_clone failed for `%s'.", - name); - free (name); + ERROR ("java plugin: cjni_config_plugin_block: ctoj_oconfig_item failed."); + cjni_thread_detach (); return (-1); } - DEBUG ("java plugin: cjni_config_plugin_block: " - "Successfully copied config for `%s'.", - name); + class = (*jvm_env)->GetObjectClass (jvm_env, cbi->object); + method = (*jvm_env)->GetMethodID (jvm_env, class, + "config", "(Lorg/collectd/api/OConfigItem;)I"); + + (*jvm_env)->CallIntMethod (jvm_env, + cbi->object, method, o_ocitem); - java_plugin_configs_num++; + (*jvm_env)->DeleteLocalRef (jvm_env, o_ocitem); + cjni_thread_detach (); return (0); } /* }}} int cjni_config_plugin_block */ -static int cjni_config (oconfig_item_t *ci) /* {{{ */ +static int cjni_config_perform (oconfig_item_t *ci) /* {{{ */ { int success; int errors; @@ -2068,8 +2364,6 @@ static int cjni_config (oconfig_item_t *ci) /* {{{ */ DEBUG ("java plugin: jvm_argc = %zu;", jvm_argc); DEBUG ("java plugin: java_classes_list_len = %zu;", java_classes_list_len); - DEBUG ("java plugin: java_plugin_configs_num = %zu;", - java_plugin_configs_num); if ((success == 0) && (errors > 0)) { @@ -2078,8 +2372,56 @@ static int cjni_config (oconfig_item_t *ci) /* {{{ */ } return (0); -} /* }}} int cjni_config */ -/* }}} */ +} /* }}} int cjni_config_perform */ + +/* Copy the children of `ci' to the global `config_block' variable. */ +static int cjni_config_callback (oconfig_item_t *ci) /* {{{ */ +{ + oconfig_item_t *ci_copy; + oconfig_item_t *tmp; + + assert (ci != NULL); + if (ci->children_num == 0) + return (0); /* nothing to do */ + + ci_copy = oconfig_clone (ci); + if (ci_copy == NULL) + { + ERROR ("java plugin: oconfig_clone failed."); + return (-1); + } + + if (config_block == NULL) + { + config_block = ci_copy; + return (0); + } + + tmp = realloc (config_block->children, + (config_block->children_num + ci_copy->children_num) * sizeof (*tmp)); + if (tmp == NULL) + { + ERROR ("java plugin: realloc failed."); + oconfig_free (ci_copy); + return (-1); + } + config_block->children = tmp; + + /* Copy the pointers */ + memcpy (config_block->children + config_block->children_num, + ci_copy->children, + ci_copy->children_num * sizeof (*ci_copy->children)); + config_block->children_num += ci_copy->children_num; + + /* Delete the pointers from the copy, so `oconfig_free' can't free them. */ + memset (ci_copy->children, 0, + ci_copy->children_num * sizeof (*ci_copy->children)); + ci_copy->children_num = 0; + + oconfig_free (ci_copy); + + return (0); +} /* }}} int cjni_config_callback */ /* Free the data contained in the `user_data_t' pointer passed to `cjni_read' * and `cjni_write'. In particular, delete the global reference to the Java @@ -2346,103 +2688,247 @@ static int cjni_notification (const notification_t *n, /* {{{ */ return (ret_status); } /* }}} int cjni_notification */ -/* Iterate over `java_classes_list' and create one object of each class. This - * will trigger the object's constructors, to the objects can register callback - * methods. */ -static int cjni_load_plugins (JNIEnv *jvm_env) /* {{{ */ +/* Callbacks for matches implemented in Java */ +static int cjni_match_target_create (const oconfig_item_t *ci, /* {{{ */ + void **user_data) { + JNIEnv *jvm_env; + cjni_callback_info_t *cbi_ret; + cjni_callback_info_t *cbi_factory; + const char *name; + jobject o_ci; + jobject o_tmp; + int type; size_t i; - for (i = 0; i < java_classes_list_len; i++) + cbi_ret = NULL; + o_ci = NULL; + jvm_env = NULL; + +#define BAIL_OUT(status) \ + if (cbi_ret != NULL) { \ + free (cbi_ret->name); \ + if ((jvm_env != NULL) && (cbi_ret->object != NULL)) \ + (*jvm_env)->DeleteLocalRef (jvm_env, cbi_ret->object); \ + } \ + free (cbi_ret); \ + if (jvm_env != NULL) { \ + if (o_ci != NULL) \ + (*jvm_env)->DeleteLocalRef (jvm_env, o_ci); \ + cjni_thread_detach (); \ + } \ + return (status) + + if (jvm == NULL) { - java_plugin_class_t *class; - jmethodID constructor_id; + ERROR ("java plugin: cjni_read: jvm == NULL"); + BAIL_OUT (-1); + } - class = java_classes_list + i; + jvm_env = cjni_thread_attach (); + if (jvm_env == NULL) + { + BAIL_OUT (-1); + } - DEBUG ("java plugin: Loading class %s", class->name); + /* Find out whether to create a match or a target. */ + if (strcasecmp ("Match", ci->key) == 0) + type = CB_TYPE_MATCH; + else if (strcasecmp ("Target", ci->key) == 0) + type = CB_TYPE_TARGET; + else + { + ERROR ("java plugin: cjni_match_target_create: Can't figure out whether " + "to create a match or a target."); + BAIL_OUT (-1); + } - class->class = (*jvm_env)->FindClass (jvm_env, class->name); - if (class->class == NULL) - { - ERROR ("java plugin: cjni_load_plugins: FindClass (%s) failed.", - class->name); - continue; - } + /* This is the name of the match we should create. */ + name = ci->values[0].value.string; - constructor_id = (*jvm_env)->GetMethodID (jvm_env, class->class, - "", "()V"); - if (constructor_id == NULL) - { - ERROR ("java plugin: cjni_load_plugins: Could not find the constructor for `%s'.", - class->name); + /* Lets see if we have a matching factory here.. */ + cbi_factory = NULL; + for (i = 0; i < java_callbacks_num; i++) + { + if (java_callbacks[i].type != type) continue; - } - class->object = (*jvm_env)->NewObject (jvm_env, class->class, - constructor_id); - if (class->object == NULL) - { - ERROR ("java plugin: cjni_load_plugins: Could create a new `%s' object.", - class->name); + if (strcmp (name, java_callbacks[i].name) != 0) continue; - } - (*jvm_env)->NewGlobalRef (jvm_env, class->object); - } /* for (i = 0; i < java_classes_list_len; i++) */ + cbi_factory = java_callbacks + i; + break; + } + + /* Nope, no factory for that name.. */ + if (cbi_factory == NULL) + { + ERROR ("java plugin: cjni_match_target_create: " + "No such match factory registered: %s", + name); + BAIL_OUT (-1); + } + + /* We convert `ci' to its Java equivalent.. */ + o_ci = ctoj_oconfig_item (jvm_env, ci); + if (o_ci == NULL) + { + ERROR ("java plugin: cjni_match_target_create: " + "ctoj_oconfig_item failed."); + BAIL_OUT (-1); + } + + /* Allocate a new callback info structure. This is going to be our user_data + * pointer. */ + cbi_ret = (cjni_callback_info_t *) malloc (sizeof (*cbi_ret)); + if (cbi_ret == NULL) + { + ERROR ("java plugin: cjni_match_target_create: malloc failed."); + BAIL_OUT (-1); + } + memset (cbi_ret, 0, sizeof (*cbi_ret)); + cbi_ret->object = NULL; + cbi_ret->type = type; + + /* Lets fill the callback info structure.. First, the name: */ + cbi_ret->name = strdup (name); + if (cbi_ret->name == NULL) + { + ERROR ("java plugin: cjni_match_target_create: strdup failed."); + BAIL_OUT (-1); + } + + /* Then call the factory method so it creates a new object for us. */ + o_tmp = (*jvm_env)->CallObjectMethod (jvm_env, + cbi_factory->object, cbi_factory->method, o_ci); + if (o_tmp == NULL) + { + ERROR ("java plugin: cjni_match_target_create: CallObjectMethod failed."); + BAIL_OUT (-1); + } + + cbi_ret->object = (*jvm_env)->NewGlobalRef (jvm_env, o_tmp); + if (o_tmp == NULL) + { + ERROR ("java plugin: cjni_match_target_create: NewGlobalRef failed."); + BAIL_OUT (-1); + } + + /* This is the class of the match. It is possibly different from the class of + * the match-factory! */ + cbi_ret->class = (*jvm_env)->GetObjectClass (jvm_env, cbi_ret->object); + if (cbi_ret->class == NULL) + { + ERROR ("java plugin: cjni_match_target_create: GetObjectClass failed."); + BAIL_OUT (-1); + } + + /* Lookup the `int match (DataSet, ValueList)' method. */ + cbi_ret->method = (*jvm_env)->GetMethodID (jvm_env, cbi_ret->class, + /* method name = */ (type == CB_TYPE_MATCH) ? "match" : "invoke", + "(Lorg/collectd/api/DataSet;Lorg/collectd/api/ValueList;)I"); + if (cbi_ret->method == NULL) + { + ERROR ("java plugin: cjni_match_target_create: GetMethodID failed."); + BAIL_OUT (-1); + } + + /* Return the newly created match via the user_data pointer. */ + *user_data = (void *) cbi_ret; + + cjni_thread_detach (); + + DEBUG ("java plugin: cjni_match_target_create: " + "Successfully created a `%s' %s.", + cbi_ret->name, (type == CB_TYPE_MATCH) ? "match" : "target"); + + /* Success! */ + return (0); +#undef BAIL_OUT +} /* }}} int cjni_match_target_create */ + +static int cjni_match_target_destroy (void **user_data) /* {{{ */ +{ + cjni_callback_info_destroy (*user_data); + *user_data = NULL; return (0); -} /* }}} int cjni_load_plugins */ +} /* }}} int cjni_match_target_destroy */ -/* Iterate over `java_plugin_configs' and `java_callbacks' and call all - * `config' callback methods for which a configuration is available. */ -static int cjni_config_plugins (JNIEnv *jvm_env) /* {{{ */ +static int cjni_match_target_invoke (const data_set_t *ds, /* {{{ */ + value_list_t *vl, notification_meta_t **meta, void **user_data) { + JNIEnv *jvm_env; + cjni_callback_info_t *cbi; + jobject o_vl; + jobject o_ds; + int ret_status; int status; - size_t i; - size_t j; - for (i = 0; i < java_plugin_configs_num; i++) + if (jvm == NULL) { - jobject o_ocitem; + ERROR ("java plugin: cjni_match_target_invoke: jvm == NULL"); + return (-1); + } - if (java_plugin_configs[i].ci == NULL) - continue; + jvm_env = cjni_thread_attach (); + if (jvm_env == NULL) + return (-1); - for (j = 0; j < java_callbacks_num; j++) - { - if (java_callbacks[j].type != CB_TYPE_CONFIG) - continue; + cbi = (cjni_callback_info_t *) *user_data; - if (strcmp (java_plugin_configs[i].name, java_callbacks[j].name) == 0) - break; - } + o_vl = ctoj_value_list (jvm_env, ds, vl); + if (o_vl == NULL) + { + ERROR ("java plugin: cjni_match_target_invoke: ctoj_value_list failed."); + cjni_thread_detach (); + return (-1); + } - if (j >= java_callbacks_num) - { - NOTICE ("java plugin: Configuration for `%s' is present, but no such " - "configuration callback has been registered.", - java_plugin_configs[i].name); - continue; - } + o_ds = ctoj_data_set (jvm_env, ds); + if (o_ds == NULL) + { + ERROR ("java plugin: cjni_match_target_invoke: ctoj_value_list failed."); + cjni_thread_detach (); + return (-1); + } + + ret_status = (*jvm_env)->CallIntMethod (jvm_env, cbi->object, cbi->method, + o_ds, o_vl); - DEBUG ("java plugin: Configuring %s", java_plugin_configs[i].name); + DEBUG ("java plugin: cjni_match_target_invoke: Method returned %i.", ret_status); - o_ocitem = ctoj_oconfig_item (jvm_env, java_plugin_configs[i].ci); - if (o_ocitem == NULL) + /* If we're executing a target, copy the `ValueList' back to our + * `value_list_t'. */ + if (cbi->type == CB_TYPE_TARGET) + { + value_list_t new_vl; + + memset (&new_vl, 0, sizeof (new_vl)); + status = jtoc_value_list (jvm_env, &new_vl, o_vl); + if (status != 0) { - ERROR ("java plugin: cjni_config_plugins: ctoj_oconfig_item failed."); - continue; + ERROR ("java plugin: cjni_match_target_invoke: " + "jtoc_value_list failed."); } + else /* if (status == 0) */ + { + /* plugin_dispatch_values assures that this is dynamically allocated + * memory. */ + sfree (vl->values); - status = (*jvm_env)->CallIntMethod (jvm_env, - java_callbacks[j].object, java_callbacks[j].method, o_ocitem); - WARNING ("java plugin: Config callback for `%s' returned status %i.", - java_plugin_configs[i].name, status); - } /* for (i = 0; i < java_plugin_configs; i++) */ + /* This will replace the vl->values pointer to a new, dynamically + * allocated piece of memory. */ + memcpy (vl, &new_vl, sizeof (*vl)); + } + } /* if (cbi->type == CB_TYPE_TARGET) */ - return (0); -} /* }}} int cjni_config_plugins */ + status = cjni_thread_detach (); + if (status != 0) + ERROR ("java plugin: cjni_read: cjni_thread_detach failed."); + + return (ret_status); +} /* }}} int cjni_match_target_invoke */ /* Iterate over `java_callbacks' and call all CB_TYPE_INIT callbacks. */ static int cjni_init_plugins (JNIEnv *jvm_env) /* {{{ */ @@ -2511,7 +2997,7 @@ static int cjni_shutdown (void) /* {{{ */ memset (&args, 0, sizeof (args)); args.version = JNI_VERSION_1_2; - status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args); + status = (*jvm)->AttachCurrentThread (jvm, (void *) &jvm_env, &args); if (status != 0) { ERROR ("java plugin: cjni_shutdown: AttachCurrentThread failed with status %i.", @@ -2562,110 +3048,49 @@ static int cjni_shutdown (void) /* {{{ */ jvm_argc = 0; sfree (jvm_argv); - /* Free the copied configuration */ - for (i = 0; i < java_plugin_configs_num; i++) - { - sfree (java_plugin_configs[i].name); - oconfig_free (java_plugin_configs[i].ci); - } - java_plugin_configs_num = 0; - sfree (java_plugin_configs); - return (0); } /* }}} int cjni_shutdown */ -/* Register ``native'' functions with the JVM. Native functions are C-functions - * that can be called by Java code. */ -static int cjni_init_native (JNIEnv *jvm_env) /* {{{ */ -{ - jclass api_class_ptr; - int status; - - api_class_ptr = (*jvm_env)->FindClass (jvm_env, "org.collectd.api.Collectd"); - if (api_class_ptr == NULL) - { - ERROR ("cjni_init_native: Cannot find API class `org.collectd.api.Collectd'."); - return (-1); - } - - status = (*jvm_env)->RegisterNatives (jvm_env, api_class_ptr, - jni_api_functions, (jint) jni_api_functions_num); - if (status != 0) - { - ERROR ("cjni_init_native: RegisterNatives failed with status %i.", status); - return (-1); - } - - return (0); -} /* }}} int cjni_init_native */ - /* Initialization: Create a JVM, load all configured classes and call their * `config' and `init' callback methods. */ static int cjni_init (void) /* {{{ */ { JNIEnv *jvm_env; - JavaVMInitArgs vm_args; - JavaVMOption vm_options[jvm_argc]; - - int status; - size_t i; - if (jvm != NULL) - return (0); - - status = pthread_key_create (&jvm_env_key, cjni_jvm_env_destroy); - if (status != 0) + if ((config_block == NULL) && (jvm == NULL)) { - ERROR ("java plugin: cjni_init: pthread_key_create failed " - "with status %i.", status); + ERROR ("java plugin: cjni_init: No configuration block for " + "the java plugin was found."); return (-1); } - jvm_env = NULL; - - memset (&vm_args, 0, sizeof (vm_args)); - vm_args.version = JNI_VERSION_1_2; - vm_args.options = vm_options; - vm_args.nOptions = (jint) jvm_argc; - - for (i = 0; i < jvm_argc; i++) + if (config_block != NULL) { - DEBUG ("java plugin: cjni_init: jvm_argv[%zu] = %s", i, jvm_argv[i]); - vm_args.options[i].optionString = jvm_argv[i]; + + cjni_config_perform (config_block); + oconfig_free (config_block); + config_block = NULL; } - /* - vm_args.options[0].optionString = "-verbose:jni"; - vm_args.options[1].optionString = "-Djava.class.path=/home/octo/collectd/bindings/java"; - */ - status = JNI_CreateJavaVM (&jvm, (void **) &jvm_env, (void **) &vm_args); - if (status != 0) + if (jvm == NULL) { - ERROR ("cjni_init: JNI_CreateJavaVM failed with status %i.", - status); + ERROR ("java plugin: cjni_init: jvm == NULL"); return (-1); } - assert (jvm != NULL); - assert (jvm_env != NULL); - /* Call RegisterNatives */ - status = cjni_init_native (jvm_env); - if (status != 0) - { - ERROR ("cjni_init: cjni_init_native failed."); + jvm_env = cjni_thread_attach (); + if (jvm_env == NULL) return (-1); - } - cjni_load_plugins (jvm_env); - cjni_config_plugins (jvm_env); cjni_init_plugins (jvm_env); + cjni_thread_detach (); return (0); } /* }}} int cjni_init */ void module_register (void) { - plugin_register_complex_config ("java", cjni_config); + plugin_register_complex_config ("java", cjni_config_callback); plugin_register_init ("java", cjni_init); plugin_register_shutdown ("java", cjni_shutdown); } /* void module_register (void) */