X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fjava.c;h=72d3569cf8359f47a2dd46396a96e83d0724dd99;hb=ae736faafccf7f68eb962998b62ea17709fb7244;hp=488e18bd11d3dfd3343f2eaaaad4cf7784c93e25;hpb=fe7552a4e73e55655d44903ea7f9fd053029e2f9;p=collectd.git diff --git a/src/java.c b/src/java.c index 488e18bd..72d3569c 100644 --- a/src/java.c +++ b/src/java.c @@ -48,17 +48,34 @@ struct java_plugin_s /* {{{ */ jmethodID m_config; jmethodID m_init; - jmethodID m_read; jmethodID m_write; jmethodID m_shutdown; }; typedef struct java_plugin_s java_plugin_t; /* }}} */ +struct cjni_jvm_env_s /* {{{ */ +{ + JNIEnv *jvm_env; + int reference_counter; +}; +typedef struct cjni_jvm_env_s cjni_jvm_env_t; +/* }}} */ + +struct cjni_callback_info_s /* {{{ */ +{ + jclass class; + jobject object; + jmethodID method; +}; +typedef struct cjni_callback_info_s cjni_callback_info_t; +/* }}} */ + /* * Global variables */ static JavaVM *jvm = NULL; +static pthread_key_t jvm_env_key; static char **jvm_argv = NULL; static size_t jvm_argc = 0; @@ -66,6 +83,14 @@ static size_t jvm_argc = 0; static java_plugin_t *java_plugins = NULL; static size_t java_plugins_num = 0; +/* + * Prototypes + * + * Mostly functions that are needed by the Java interface functions. + */ +static void cjni_callback_info_destroy (void *arg); +static int cjni_read (user_data_t *user_data); + /* * C to Java conversion functions */ @@ -102,9 +127,6 @@ static int ctoj_string (JNIEnv *jvm_env, /* {{{ */ /* Decrease reference counter on the java.lang.String object. */ (*jvm_env)->DeleteLocalRef (jvm_env, o_string); - DEBUG ("java plugin: ctoj_string: ->%s (%s);", - method_name, (string != NULL) ? string : ""); - return (0); } /* }}} int ctoj_string */ @@ -126,9 +148,6 @@ static int ctoj_int (JNIEnv *jvm_env, /* {{{ */ (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, value); - DEBUG ("java plugin: ctoj_int: ->%s (%i);", - method_name, (int) value); - return (0); } /* }}} int ctoj_int */ @@ -150,9 +169,6 @@ static int ctoj_long (JNIEnv *jvm_env, /* {{{ */ (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, value); - DEBUG ("java plugin: ctoj_long: ->%s (%"PRIi64");", - method_name, (int64_t) value); - return (0); } /* }}} int ctoj_long */ @@ -174,9 +190,6 @@ static int ctoj_double (JNIEnv *jvm_env, /* {{{ */ (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, value); - DEBUG ("java plugin: ctoj_double: ->%s (%g);", - method_name, (double) value); - return (0); } /* }}} int ctoj_double */ @@ -248,7 +261,7 @@ static jobject ctoj_value_to_number (JNIEnv *jvm_env, /* {{{ */ return (NULL); } /* }}} jobject ctoj_value_to_number */ -/* Convert a data_source_t to a org.collectd.protocol.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) { @@ -259,11 +272,11 @@ static jobject ctoj_data_source (JNIEnv *jvm_env, /* {{{ */ /* Look up the DataSource class */ c_datasource = (*jvm_env)->FindClass (jvm_env, - "org.collectd.protocol.DataSource"); + "org.collectd.api.DataSource"); if (c_datasource == NULL) { ERROR ("java plugin: ctoj_data_source: " - "FindClass (org.collectd.protocol.DataSource) failed."); + "FindClass (org.collectd.api.DataSource) failed."); return (NULL); } @@ -547,56 +560,67 @@ static jobject ctoj_oconfig_item (JNIEnv *jvm_env, /* {{{ */ return (o_ocitem); } /* }}} jobject ctoj_oconfig_item */ -/* Convert a data_set_t to a java.util.List */ +/* 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_arraylist; + jclass c_dataset; jmethodID m_constructor; jmethodID m_add; + jobject o_type; jobject o_dataset; int i; - /* Look up the java.util.ArrayList class */ - c_arraylist = (*jvm_env)->FindClass (jvm_env, "java.util.ArrayList"); - if (c_arraylist == NULL) + /* 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 " - "java.util.ArrayList class failed."); + "org.collectd.api.DataSet class failed."); return (NULL); } - /* Search for the `ArrayList (int capacity)' constructor. */ + /* Search for the `DataSet (String type)' constructor. */ m_constructor = (*jvm_env)->GetMethodID (jvm_env, - c_arraylist, "", "()V"); + c_dataset, "", "(Ljava.lang.String;)V"); if (m_constructor == NULL) { ERROR ("java plugin: ctoj_data_set: Looking up the " - "`ArrayList (void)' constructor failed."); + "`DataSet (String)' constructor failed."); return (NULL); } - /* Search for the `boolean add (Object element)' method. */ + /* Search for the `void addDataSource (DataSource)' method. */ m_add = (*jvm_env)->GetMethodID (jvm_env, - c_arraylist, "add", "(Ljava/lang/Object;)Z"); + c_dataset, "addDataSource", "(Lorg.collectd.api.DataSource;)V"); if (m_add == NULL) { ERROR ("java plugin: ctoj_data_set: Looking up the " - "`add (Object)' method failed."); + "`addDataSource (DataSource)' method failed."); + return (NULL); + } + + o_type = (*jvm_env)->NewStringUTF (jvm_env, ds->type); + if (o_type == NULL) + { + ERROR ("java plugin: ctoj_data_set: Creating a String object failed."); return (NULL); } - o_dataset = (*jvm_env)->NewObject (jvm_env, c_arraylist, m_constructor); + o_dataset = (*jvm_env)->NewObject (jvm_env, + c_dataset, m_constructor, o_type); if (o_dataset == NULL) { - ERROR ("java plugin: ctoj_data_set: " - "Creating an ArrayList object failed."); + ERROR ("java plugin: ctoj_data_set: Creating a DataSet object failed."); + (*jvm_env)->DeleteLocalRef (jvm_env, o_type); return (NULL); } + /* Decrease reference counter on the java.lang.String object. */ + (*jvm_env)->DeleteLocalRef (jvm_env, o_type); + for (i = 0; i < ds->ds_num; i++) { jobject o_datasource; - jboolean status; o_datasource = ctoj_data_source (jvm_env, ds->ds + i); if (o_datasource == NULL) @@ -607,15 +631,7 @@ static jobject ctoj_data_set (JNIEnv *jvm_env, const data_set_t *ds) /* {{{ */ return (NULL); } - status = (*jvm_env)->CallBooleanMethod (jvm_env, - o_dataset, m_add, o_datasource); - if (!status) - { - ERROR ("java plugin: ctoj_data_set: ArrayList.add returned FALSE."); - (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource); - (*jvm_env)->DeleteLocalRef (jvm_env, o_dataset); - return (NULL); - } + (*jvm_env)->CallVoidMethod (jvm_env, o_dataset, m_add, o_datasource); (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource); } /* for (i = 0; i < ds->ds_num; i++) */ @@ -657,20 +673,20 @@ static int ctoj_value_list_add_value (JNIEnv *jvm_env, /* {{{ */ static int ctoj_value_list_add_data_set (JNIEnv *jvm_env, /* {{{ */ jclass c_valuelist, jobject o_valuelist, const data_set_t *ds) { - jmethodID m_setdatasource; + jmethodID m_setdataset; jobject o_dataset; /* Look for the `void setDataSource (List ds)' method. */ - m_setdatasource = (*jvm_env)->GetMethodID (jvm_env, c_valuelist, - "setDataSource", "(Ljava/util/List;)V"); - if (m_setdatasource == NULL) + m_setdataset = (*jvm_env)->GetMethodID (jvm_env, c_valuelist, + "setDataSet", "(Lorg.collectd.api.DataSet;)V"); + if (m_setdataset == NULL) { ERROR ("java plugin: ctoj_value_list_add_data_set: " - "Cannot find the `void setDataSource (List ds)' method."); + "Cannot find the `void setDataSet (DataSet)' method."); return (-1); } - /* Create a List object. */ + /* Create a DataSet object. */ o_dataset = ctoj_data_set (jvm_env, ds); if (o_dataset == NULL) { @@ -681,7 +697,7 @@ static int ctoj_value_list_add_data_set (JNIEnv *jvm_env, /* {{{ */ /* Actually call the method. */ (*jvm_env)->CallVoidMethod (jvm_env, - o_valuelist, m_setdatasource, o_dataset); + o_valuelist, m_setdataset, o_dataset); /* Decrease reference counter on the List object. */ (*jvm_env)->DeleteLocalRef (jvm_env, o_dataset); @@ -701,11 +717,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.protocol.ValueList"); + "org.collectd.api.ValueList"); if (c_valuelist == NULL) { ERROR ("java plugin: ctoj_value_list: " - "FindClass (org.collectd.protocol.ValueList) failed."); + "FindClass (org.collectd.api.ValueList) failed."); return (NULL); } @@ -830,8 +846,6 @@ static int jtoc_string (JNIEnv *jvm_env, /* {{{ */ return (-1); } - DEBUG ("java plugin: jtoc_string: ->%s() = %s", method_name, c_str); - sstrncpy (buffer, c_str, buffer_size); (*jvm_env)->ReleaseStringUTFChars (jvm_env, string_obj, c_str); @@ -857,9 +871,6 @@ static int jtoc_long (JNIEnv *jvm_env, /* {{{ */ *ret_value = (*jvm_env)->CallLongMethod (jvm_env, object_ptr, method_id); - DEBUG ("java plugin: jtoc_long: ->%s() = %li", - method_name, (long int) *ret_value); - return (0); } /* }}} int jtoc_long */ @@ -880,9 +891,6 @@ static int jtoc_double (JNIEnv *jvm_env, /* {{{ */ *ret_value = (*jvm_env)->CallDoubleMethod (jvm_env, object_ptr, method_id); - DEBUG ("java plugin: jtoc_double: ->%s() = %g", - method_name, (double) *ret_value); - return (0); } /* }}} int jtoc_double */ @@ -1029,7 +1037,7 @@ static int jtoc_values_array (JNIEnv *jvm_env, /* {{{ */ return (0); } /* }}} int jtoc_values_array */ -/* Convert a org.collectd.protocol.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) { @@ -1100,6 +1108,45 @@ static int jtoc_value_list (JNIEnv *jvm_env, value_list_t *vl, /* {{{ */ return (0); } /* }}} int jtoc_value_list */ +static cjni_callback_info_t *cjni_callback_info_create (JNIEnv *jvm_env, /* {{{ */ + jobject obj, const char *method_name, const char *signature) +{ + cjni_callback_info_t *cbi; + + cbi = (cjni_callback_info_t *) malloc (sizeof (*cbi)); + if (cbi == NULL) + { + ERROR ("java plugin: cjni_callback_info_create: malloc failed."); + return (NULL); + } + memset (cbi, 0, sizeof (*cbi)); + + cbi->class = (*jvm_env)->GetObjectClass (jvm_env, obj); + if (cbi->class == NULL) + { + ERROR ("java plugin: cjni_callback_info_create: GetObjectClass failed."); + free (cbi); + return (NULL); + } + + cbi->object = obj; + + cbi->method = (*jvm_env)->GetMethodID (jvm_env, cbi->class, + method_name, signature); + if (cbi->method == NULL) + { + ERROR ("java plugin: cjni_callback_info_create: " + "Cannot find the `%s' method with signature `%s'.", + method_name, signature); + free (cbi); + return (NULL); + } + + (*jvm_env)->NewGlobalRef (jvm_env, obj); + + return (cbi); +} /* }}} cjni_callback_info_t cjni_callback_info_create */ + /* * Functions accessible from Java */ @@ -1125,9 +1172,76 @@ static jint JNICALL cjni_api_dispatch_values (JNIEnv *jvm_env, /* {{{ */ return (status); } /* }}} jint cjni_api_dispatch_values */ +static jobject JNICALL cjni_api_get_ds (JNIEnv *jvm_env, /* {{{ */ + jobject this, jobject o_string_type) +{ + const char *ds_name; + const data_set_t *ds; + jobject o_dataset; + + ds_name = (*jvm_env)->GetStringUTFChars (jvm_env, o_string_type, 0); + if (ds_name == NULL) + { + ERROR ("java plugin: cjni_api_get_ds: GetStringUTFChars failed."); + return (NULL); + } + + ds = plugin_get_ds (ds_name); + DEBUG ("java plugin: cjni_api_get_ds: " + "plugin_get_ds (%s) = %p;", ds_name, (void *) ds); + + (*jvm_env)->ReleaseStringUTFChars (jvm_env, o_string_type, ds_name); + + if (ds == NULL) + return (NULL); + + o_dataset = ctoj_data_set (jvm_env, ds); + return (o_dataset); +} /* }}} jint cjni_api_get_ds */ + +static jint JNICALL cjni_api_register_read (JNIEnv *jvm_env, /* {{{ */ + jobject this, jobject o_name, jobject o_read) +{ + const char *c_name; + user_data_t ud; + cjni_callback_info_t *cbi; + + c_name = (*jvm_env)->GetStringUTFChars (jvm_env, o_name, 0); + if (c_name == NULL) + { + ERROR ("java plugin: cjni_api_register_read: GetStringUTFChars failed."); + return (-1); + } + + cbi = cjni_callback_info_create (jvm_env, o_read, "Read", "()I"); + if (cbi == NULL) + return (-1); + + memset (&ud, 0, sizeof (ud)); + ud.data = (void *) cbi; + ud.free_func = cjni_callback_info_destroy; + + plugin_register_complex_read (c_name, cjni_read, &ud); + + (*jvm_env)->ReleaseStringUTFChars (jvm_env, o_name, c_name); + (*jvm_env)->DeleteLocalRef (jvm_env, o_read); + + return (0); +} /* }}} jint cjni_api_register_read */ + static JNINativeMethod jni_api_functions[] = { - { "DispatchValues", "(Lorg/collectd/protocol/ValueList;)I", cjni_api_dispatch_values } + { "DispatchValues", + "(Lorg/collectd/api/ValueList;)I", + cjni_api_dispatch_values }, + + { "GetDS", + "(Ljava/lang/String;)Lorg/collectd/api/DataSet;", + cjni_api_get_ds }, + + { "RegisterRead", + "(Ljava/lang/String;Lorg/collectd/api/CollectdReadInterface;)I", + cjni_api_register_read } }; static size_t jni_api_functions_num = sizeof (jni_api_functions) / sizeof (jni_api_functions[0]); @@ -1135,6 +1249,153 @@ static size_t jni_api_functions_num = sizeof (jni_api_functions) /* * Functions */ +static JNIEnv *cjni_thread_attach (void) /* {{{ */ +{ + cjni_jvm_env_t *cjni_env; + JNIEnv *jvm_env; + + cjni_env = pthread_getspecific (jvm_env_key); + if (cjni_env == NULL) + { + /* This pointer is free'd in `cjni_jvm_env_destroy'. */ + cjni_env = (cjni_jvm_env_t *) malloc (sizeof (*cjni_env)); + if (cjni_env == NULL) + { + ERROR ("java plugin: cjni_thread_attach: malloc failed."); + return (NULL); + } + memset (cjni_env, 0, sizeof (*cjni_env)); + cjni_env->reference_counter = 0; + cjni_env->jvm_env = NULL; + + pthread_setspecific (jvm_env_key, cjni_env); + } + + if (cjni_env->reference_counter > 0) + { + cjni_env->reference_counter++; + jvm_env = cjni_env->jvm_env; + } + else + { + int status; + JavaVMAttachArgs args; + + assert (cjni_env->jvm_env == NULL); + + memset (&args, 0, sizeof (args)); + args.version = JNI_VERSION_1_2; + + status = (*jvm)->AttachCurrentThread (jvm, (void *) &jvm_env, (void *) &args); + if (status != 0) + { + ERROR ("java plugin: cjni_thread_attach: AttachCurrentThread failed " + "with status %i.", status); + return (NULL); + } + + cjni_env->reference_counter = 1; + cjni_env->jvm_env = jvm_env; + } + + DEBUG ("java plugin: cjni_thread_attach: cjni_env->reference_counter = %i", + cjni_env->reference_counter); + assert (jvm_env != NULL); + return (jvm_env); +} /* }}} JNIEnv *cjni_thread_attach */ + +static int cjni_thread_detach (void) /* {{{ */ +{ + cjni_jvm_env_t *cjni_env; + int status; + + cjni_env = pthread_getspecific (jvm_env_key); + if (cjni_env == NULL) + { + ERROR ("java plugin: cjni_thread_detach: pthread_getspecific failed."); + return (-1); + } + + assert (cjni_env->reference_counter > 0); + assert (cjni_env->jvm_env != NULL); + + cjni_env->reference_counter--; + DEBUG ("java plugin: cjni_thread_detach: cjni_env->reference_counter = %i", + cjni_env->reference_counter); + + if (cjni_env->reference_counter > 0) + return (0); + + status = (*jvm)->DetachCurrentThread (jvm); + if (status != 0) + { + ERROR ("java plugin: cjni_thread_detach: DetachCurrentThread failed " + "with status %i.", status); + } + + cjni_env->reference_counter = 0; + cjni_env->jvm_env = NULL; + + return (0); +} /* }}} JNIEnv *cjni_thread_attach */ + +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 */ + +/* + * Delete a global reference, set by the various `Register*' functions. + */ +static void cjni_callback_info_destroy (void *arg) /* {{{ */ +{ + JNIEnv *jni_env; + cjni_callback_info_t *cbi; + + DEBUG ("java plugin: cjni_callback_info_destroy (arg = %p);", arg); + + if (arg == NULL) + return; + + jni_env = cjni_thread_attach (); + if (jni_env == NULL) + { + ERROR ("java plugin: cjni_callback_info_destroy: cjni_thread_attach failed."); + return; + } + + cbi = (cjni_callback_info_t *) arg; + + (*jni_env)->DeleteGlobalRef (jni_env, cbi->object); + + cbi->method = NULL; + cbi->object = NULL; + cbi->class = NULL; + free (cbi); + + cjni_thread_detach (); +} /* }}} void cjni_callback_info_destroy */ + static int cjni_config_add_jvm_arg (oconfig_item_t *ci) /* {{{ */ { char **tmp; @@ -1198,7 +1459,6 @@ static int cjni_config_load_plugin (oconfig_item_t *ci) /* {{{ */ jp->flags = 0; jp->m_config = NULL; jp->m_init = NULL; - jp->m_read = NULL; jp->m_write = NULL; jp->m_shutdown = NULL; @@ -1312,241 +1572,160 @@ static int cjni_config (oconfig_item_t *ci) /* {{{ */ return (0); } /* }}} int cjni_config */ -static int cjni_init_one_plugin (JNIEnv *jvm_env, java_plugin_t *jp) /* {{{ */ +static int cjni_write_one_plugin (JNIEnv *jvm_env, /* {{{ */ + java_plugin_t *jp, jobject vl_java) { - jmethodID constructor_id; int status; - jp->class_ptr = (*jvm_env)->FindClass (jvm_env, jp->class_name); - if (jp->class_ptr == NULL) + if ((jp == NULL) + || ((jp->flags & CJNI_FLAG_ENABLED) == 0) + || (jp->m_write == NULL)) + return (0); + + DEBUG ("java plugin: Calling: %s.Write(ValueList)", jp->class_name); + + status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr, + jp->m_write, vl_java); + if (status != 0) { - ERROR ("cjni_init_one_plugin: FindClass (%s) failed.", - jp->class_name); + ERROR ("java plugin: cjni_write_one_plugin: " + "Calling `Write' on an `%s' object failed with status %i.", + jp->class_name, status); return (-1); } - constructor_id = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr, - "", "()V"); - if (constructor_id == NULL) + return (0); +} /* }}} int cjni_write_one_plugin */ + +static int cjni_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */ + user_data_t __attribute__((unused)) *user_data) +{ + JNIEnv *jvm_env; + java_plugin_t *jp; + jobject vl_java; + int status; + + if (jvm == NULL) { - ERROR ("cjni_init_one_plugin: Could not find the constructor for `%s'.", - jp->class_name); + ERROR ("java plugin: cjni_write: jvm == NULL"); return (-1); } - jp->object_ptr = (*jvm_env)->NewObject (jvm_env, jp->class_ptr, - constructor_id); - if (jp->object_ptr == NULL) + if ((user_data == NULL) || (user_data->data == NULL)) { - ERROR ("cjni_init_one_plugin: Could create a new `%s' object.", - jp->class_name); + ERROR ("java plugin: cjni_read: Invalid user data."); return (-1); } - jp->m_config = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr, - "Config", "(Lorg/collectd/api/OConfigItem;)I"); - DEBUG ("java plugin: cjni_init_one_plugin: " - "jp->class_name = %s; jp->m_config = %p;", - jp->class_name, (void *) jp->m_config); + jvm_env = cjni_thread_attach (); + if (jvm_env == NULL) + return (-1); - jp->m_init = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr, - "Init", "()I"); - DEBUG ("java plugin: cjni_init_one_plugin: " - "jp->class_name = %s; jp->m_init = %p;", - jp->class_name, (void *) jp->m_init); + vl_java = ctoj_value_list (jvm_env, ds, vl); + if (vl_java == NULL) + { + ERROR ("java plugin: cjni_write_plugins: ctoj_value_list failed."); + return (-1); + } - jp->m_read = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr, - "Read", "()I"); - DEBUG ("java plugin: cjni_init_one_plugin: " - "jp->class_name = %s; jp->m_read = %p;", - jp->class_name, (void *) jp->m_read); + jp = (java_plugin_t *) user_data->data; - jp->m_write = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr, - "Write", "(Lorg/collectd/protocol/ValueList;)I"); - DEBUG ("java plugin: cjni_init_one_plugin: " - "jp->class_name = %s; jp->m_write = %p;", - jp->class_name, (void *) jp->m_write); + cjni_write_one_plugin (jvm_env, jp, vl_java); - jp->m_shutdown = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr, - "Shutdown", "()I"); - DEBUG ("java plugin: cjni_init_one_plugin: " - "jp->class_name = %s; jp->m_shutdown = %p;", - jp->class_name, (void *) jp->m_shutdown); + (*jvm_env)->DeleteLocalRef (jvm_env, vl_java); - if (jp->ci != NULL) - { - if (jp->m_config == NULL) - { - WARNING ("java plugin: Configuration for the `%s' plugin is present, " - "but plugin doesn't provide a configuration method.", - jp->class_name); - } - else - { - jobject o_ocitem; + status = cjni_thread_detach (); + if (status != 0) + return (-1); - o_ocitem = ctoj_oconfig_item (jvm_env, jp->ci); - if (o_ocitem == NULL) - { - ERROR ("java plugin: Creating an OConfigItem object failed. " - "Can't pass configuration information to the `%s' plugin!", - jp->class_name); - } - else - { - status = (*jvm_env)->CallIntMethod (jvm_env, - jp->object_ptr, jp->m_config, o_ocitem); - if (status != 0) - { - ERROR ("java plugin: cjni_init_one_plugin: " - "Configuring the `%s' object failed with status %i.", - jp->class_name, status); - } - (*jvm_env)->DeleteLocalRef (jvm_env, o_ocitem); - } - } - } /* if (jp->ci != NULL) */ + return (0); +} /* }}} int cjni_write */ - if (jp->m_init != NULL) - { - status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr, - jp->m_init); - if (status != 0) - { - ERROR ("java plugin: cjni_init_one_plugin: " - "Initializing `%s' object failed with status %i.", - jp->class_name, status); - return (-1); - } - } - jp->flags |= CJNI_FLAG_ENABLED; - - return (0); -} /* }}} int cjni_init_one_plugin */ - -static int cjni_init_plugins (JNIEnv *jvm_env) /* {{{ */ -{ - size_t j; - - for (j = 0; j < java_plugins_num; j++) - cjni_init_one_plugin (jvm_env, &java_plugins[j]); - - return (0); -} /* }}} int cjni_init_plugins */ - -static int cjni_init_native (JNIEnv *jvm_env) /* {{{ */ +static int cjni_shutdown_one_plugin (JNIEnv *jvm_env, /* {{{ */ + java_plugin_t *jp) { - jclass api_class_ptr; int status; - api_class_ptr = (*jvm_env)->FindClass (jvm_env, "org.collectd.api.CollectdAPI"); - if (api_class_ptr == NULL) - { - ERROR ("cjni_init_native: Cannot find API class `org.collectd.api.CollectdAPI'."); - return (-1); - } + if ((jp == NULL) + || ((jp->flags & CJNI_FLAG_ENABLED) == 0) + || (jp->m_shutdown == NULL)) + return (0); - status = (*jvm_env)->RegisterNatives (jvm_env, api_class_ptr, - jni_api_functions, (jint) jni_api_functions_num); + status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr, + jp->m_shutdown); if (status != 0) { - ERROR ("cjni_init_native: RegisterNatives failed with status %i.", status); + ERROR ("cjni_shutdown_one_plugin: Destroying an `%s' object failed " + "with status %i.", jp->class_name, status); return (-1); } + jp->flags &= ~CJNI_FLAG_ENABLED; return (0); -} /* }}} int cjni_init_native */ +} /* }}} int cjni_shutdown_one_plugin */ -static int cjni_init (void) /* {{{ */ +static int cjni_shutdown_plugins (JNIEnv *jvm_env) /* {{{ */ { - JNIEnv *jvm_env; - JavaVMInitArgs vm_args; - JavaVMOption vm_options[jvm_argc]; + size_t j; + + for (j = 0; j < java_plugins_num; j++) + cjni_shutdown_one_plugin (jvm_env, &java_plugins[j]); + + return (0); +} /* }}} int cjni_shutdown_plugins */ +static int cjni_shutdown (void) /* {{{ */ +{ + JNIEnv *jvm_env; + JavaVMAttachArgs args; int status; size_t i; - if (jvm != NULL) + if (jvm == NULL) return (0); jvm_env = NULL; + memset (&args, 0, sizeof (args)); + args.version = JNI_VERSION_1_2; - 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_init: jvm_argv[%zu] = %s", i, jvm_argv[i]); - vm_args.options[i].optionString = jvm_argv[i]; - } - /* - 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) - { - ERROR ("cjni_init: JNI_CreateJavaVM failed with status %i.", - status); - return (-1); - } - assert (jvm != NULL); - assert (jvm_env != NULL); - - /* Call RegisterNatives */ - status = cjni_init_native (jvm_env); + status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args); if (status != 0) { - ERROR ("cjni_init: cjni_init_native failed."); + ERROR ("java plugin: cjni_read: AttachCurrentThread failed with status %i.", + status); return (-1); } - cjni_init_plugins (jvm_env); - - return (0); -} /* }}} int cjni_init */ - -static int cjni_read_one_plugin (JNIEnv *jvm_env, java_plugin_t *jp) /* {{{ */ -{ - int status; + cjni_shutdown_plugins (jvm_env); - if ((jp == NULL) - || ((jp->flags & CJNI_FLAG_ENABLED) == 0) - || (jp->m_read == NULL)) - return (0); + (*jvm)->DestroyJavaVM (jvm); + jvm = NULL; + jvm_env = NULL; - DEBUG ("java plugin: Calling: %s.Read()", jp->class_name); + pthread_key_delete (jvm_env_key); - status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr, - jp->m_read); - if (status != 0) + for (i = 0; i < jvm_argc; i++) { - ERROR ("java plugin: cjni_read_one_plugin: " - "Calling `Read' on an `%s' object failed with status %i.", - jp->class_name, status); - return (-1); + sfree (jvm_argv[i]); } + sfree (jvm_argv); + jvm_argc = 0; - return (0); -} /* }}} int cjni_read_one_plugin */ - -static int cjni_read_plugins (JNIEnv *jvm_env) /* {{{ */ -{ - size_t j; - - for (j = 0; j < java_plugins_num; j++) - cjni_read_one_plugin (jvm_env, &java_plugins[j]); + for (i = 0; i < java_plugins_num; i++) + { + sfree (java_plugins[i].class_name); + oconfig_free (java_plugins[i].ci); + } + sfree (java_plugins); + java_plugins_num = 0; return (0); -} /* }}} int cjni_read_plugins */ +} /* }}} int cjni_shutdown */ -static int cjni_read (void) /* {{{ */ +static int cjni_read (user_data_t *user_data) /* {{{ */ { JNIEnv *jvm_env; - JavaVMAttachArgs args; + cjni_callback_info_t *cbi; int status; if (jvm == NULL) @@ -1555,201 +1734,261 @@ static int cjni_read (void) /* {{{ */ return (-1); } - jvm_env = NULL; - memset (&args, 0, sizeof (args)); - args.version = JNI_VERSION_1_2; - - status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args); - if (status != 0) + if ((user_data == NULL) || (user_data->data == NULL)) { - ERROR ("java plugin: cjni_read: AttachCurrentThread failed with status %i.", - status); + ERROR ("java plugin: cjni_read: Invalid user data."); return (-1); } - cjni_read_plugins (jvm_env); + jvm_env = cjni_thread_attach (); + if (jvm_env == NULL) + return (-1); - status = (*jvm)->DetachCurrentThread (jvm); + cbi = (cjni_callback_info_t *) user_data->data; + + status = (*jvm_env)->CallIntMethod (jvm_env, cbi->object, + cbi->method); + + status = cjni_thread_detach (); if (status != 0) { - ERROR ("java plugin: cjni_read: DetachCurrentThread failed with status %i.", - status); + ERROR ("java plugin: cjni_read: cjni_thread_detach failed."); return (-1); } - return (0); + return (status); } /* }}} int cjni_read */ -static int cjni_write_one_plugin (JNIEnv *jvm_env, /* {{{ */ - java_plugin_t *jp, jobject vl_java) +static int cjni_init_one_plugin (JNIEnv *jvm_env, java_plugin_t *jp) /* {{{ */ { + char plugin_name[128]; + jmethodID constructor_id; int status; - if ((jp == NULL) - || ((jp->flags & CJNI_FLAG_ENABLED) == 0) - || (jp->m_write == NULL)) - return (0); - - DEBUG ("java plugin: Calling: %s.Write(ValueList)", jp->class_name); - - status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr, - jp->m_write, vl_java); - if (status != 0) + jp->class_ptr = (*jvm_env)->FindClass (jvm_env, jp->class_name); + if (jp->class_ptr == NULL) { - ERROR ("java plugin: cjni_write_one_plugin: " - "Calling `Write' on an `%s' object failed with status %i.", - jp->class_name, status); + ERROR ("cjni_init_one_plugin: FindClass (%s) failed.", + jp->class_name); return (-1); } - return (0); -} /* }}} int cjni_write_one_plugin */ - -static int cjni_write_plugins (JNIEnv *jvm_env, /* {{{ */ - const data_set_t *ds, const value_list_t *vl) -{ - size_t j; - - jobject vl_java; + constructor_id = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr, + "", "()V"); + if (constructor_id == NULL) + { + ERROR ("cjni_init_one_plugin: Could not find the constructor for `%s'.", + jp->class_name); + return (-1); + } - vl_java = ctoj_value_list (jvm_env, ds, vl); - if (vl_java == NULL) + jp->object_ptr = (*jvm_env)->NewObject (jvm_env, jp->class_ptr, + constructor_id); + if (jp->object_ptr == NULL) { - ERROR ("java plugin: cjni_write_plugins: ctoj_value_list failed."); + ERROR ("cjni_init_one_plugin: Could create a new `%s' object.", + jp->class_name); return (-1); } - for (j = 0; j < java_plugins_num; j++) - cjni_write_one_plugin (jvm_env, &java_plugins[j], vl_java); + jp->m_config = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr, + "Config", "(Lorg/collectd/api/OConfigItem;)I"); + DEBUG ("java plugin: cjni_init_one_plugin: " + "jp->class_name = %s; jp->m_config = %p;", + jp->class_name, (void *) jp->m_config); - (*jvm_env)->DeleteLocalRef (jvm_env, vl_java); + jp->m_init = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr, + "Init", "()I"); + DEBUG ("java plugin: cjni_init_one_plugin: " + "jp->class_name = %s; jp->m_init = %p;", + jp->class_name, (void *) jp->m_init); - return (0); -} /* }}} int cjni_write_plugins */ + jp->m_write = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr, + "Write", "(Lorg/collectd/api/ValueList;)I"); + DEBUG ("java plugin: cjni_init_one_plugin: " + "jp->class_name = %s; jp->m_write = %p;", + jp->class_name, (void *) jp->m_write); -static int cjni_write (const data_set_t *ds, const value_list_t *vl) /* {{{ */ -{ - JNIEnv *jvm_env; - JavaVMAttachArgs args; - int status; + jp->m_shutdown = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr, + "Shutdown", "()I"); + DEBUG ("java plugin: cjni_init_one_plugin: " + "jp->class_name = %s; jp->m_shutdown = %p;", + jp->class_name, (void *) jp->m_shutdown); - if (jvm == NULL) + if (jp->ci != NULL) { - ERROR ("java plugin: cjni_write: jvm == NULL"); - return (-1); - } + if (jp->m_config == NULL) + { + WARNING ("java plugin: Configuration for the `%s' plugin is present, " + "but plugin doesn't provide a configuration method.", + jp->class_name); + } + else /* if (jp->m_config != NULL) */ + { + jobject o_ocitem; - jvm_env = NULL; - memset (&args, 0, sizeof (args)); - args.version = JNI_VERSION_1_2; + o_ocitem = ctoj_oconfig_item (jvm_env, jp->ci); + if (o_ocitem == NULL) + { + ERROR ("java plugin: Creating an OConfigItem object failed. " + "Can't pass configuration information to the `%s' plugin!", + jp->class_name); + } + else /* if (o_ocitem != NULL) */ + { + status = (*jvm_env)->CallIntMethod (jvm_env, + jp->object_ptr, jp->m_config, o_ocitem); + if (status != 0) + { + ERROR ("java plugin: cjni_init_one_plugin: " + "Configuring the `%s' object failed with status %i.", + jp->class_name, status); + (*jvm_env)->DeleteLocalRef (jvm_env, o_ocitem); + return (-1); + } + (*jvm_env)->DeleteLocalRef (jvm_env, o_ocitem); + } /* if (o_ocitem != NULL) */ + } /* if (jp->m_config != NULL) */ + } /* if (jp->ci != NULL) */ - status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args); - if (status != 0) + if (jp->m_init != NULL) { - ERROR ("java plugin: cjni_write: AttachCurrentThread failed with status %i.", - status); - return (-1); + status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr, + jp->m_init); + if (status != 0) + { + ERROR ("java plugin: cjni_init_one_plugin: " + "Initializing `%s' object failed with status %i.", + jp->class_name, status); + return (-1); + } } + jp->flags |= CJNI_FLAG_ENABLED; - cjni_write_plugins (jvm_env, ds, vl); + ssnprintf (plugin_name, sizeof (plugin_name), "java:%s", jp->class_name); - status = (*jvm)->DetachCurrentThread (jvm); - if (status != 0) + if (jp->m_write != NULL) { - ERROR ("java plugin: cjni_write: DetachCurrentThread failed with status %i.", - status); - return (-1); + user_data_t ud; + + memset (&ud, 0, sizeof (ud)); + ud.data = jp; + ud.free_func = NULL; + + plugin_register_write (plugin_name, cjni_write, &ud); } return (0); -} /* }}} int cjni_write */ +} /* }}} int cjni_init_one_plugin */ -static int cjni_shutdown_one_plugin (JNIEnv *jvm_env, /* {{{ */ - java_plugin_t *jp) +static int cjni_init_plugins (JNIEnv *jvm_env) /* {{{ */ { - int status; + int have_shutdown; + size_t j; - if ((jp == NULL) - || ((jp->flags & CJNI_FLAG_ENABLED) == 0) - || (jp->m_shutdown == NULL)) - return (0); + have_shutdown = 0; - status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr, - jp->m_shutdown); - if (status != 0) + for (j = 0; j < java_plugins_num; j++) { - ERROR ("cjni_shutdown_one_plugin: Destroying an `%s' object failed " - "with status %i.", jp->class_name, status); - return (-1); + cjni_init_one_plugin (jvm_env, &java_plugins[j]); + + if (java_plugins[j].m_shutdown != NULL) + have_shutdown++; } - jp->flags &= ~CJNI_FLAG_ENABLED; + + if (have_shutdown > 0) + plugin_register_shutdown ("java", cjni_shutdown); return (0); -} /* }}} int cjni_shutdown_one_plugin */ +} /* }}} int cjni_init_plugins */ -static int cjni_shutdown_plugins (JNIEnv *jvm_env) /* {{{ */ +static int cjni_init_native (JNIEnv *jvm_env) /* {{{ */ { - size_t j; + jclass api_class_ptr; + int status; - for (j = 0; j < java_plugins_num; j++) - cjni_shutdown_one_plugin (jvm_env, &java_plugins[j]); + api_class_ptr = (*jvm_env)->FindClass (jvm_env, "org.collectd.api.CollectdAPI"); + if (api_class_ptr == NULL) + { + ERROR ("cjni_init_native: Cannot find API class `org.collectd.api.CollectdAPI'."); + 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_shutdown_plugins */ +} /* }}} int cjni_init_native */ -static int cjni_shutdown (void) /* {{{ */ +static int cjni_init (void) /* {{{ */ { JNIEnv *jvm_env; - JavaVMAttachArgs args; + JavaVMInitArgs vm_args; + JavaVMOption vm_options[jvm_argc]; + int status; size_t i; - if (jvm == NULL) + if (jvm != NULL) return (0); - jvm_env = NULL; - memset (&args, 0, sizeof (args)); - args.version = JNI_VERSION_1_2; - - status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args); + status = pthread_key_create (&jvm_env_key, cjni_jvm_env_destroy); if (status != 0) { - ERROR ("java plugin: cjni_read: AttachCurrentThread failed with status %i.", - status); + ERROR ("java plugin: cjni_init: pthread_key_create failed " + "with status %i.", status); return (-1); } - cjni_shutdown_plugins (jvm_env); - - (*jvm)->DestroyJavaVM (jvm); - jvm = NULL; 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++) { - sfree (jvm_argv[i]); + DEBUG ("java plugin: cjni_init: jvm_argv[%zu] = %s", i, jvm_argv[i]); + vm_args.options[i].optionString = jvm_argv[i]; } - sfree (jvm_argv); - jvm_argc = 0; + /* + vm_args.options[0].optionString = "-verbose:jni"; + vm_args.options[1].optionString = "-Djava.class.path=/home/octo/collectd/bindings/java"; + */ - for (i = 0; i < java_plugins_num; i++) + status = JNI_CreateJavaVM (&jvm, (void **) &jvm_env, (void **) &vm_args); + if (status != 0) { - sfree (java_plugins[i].class_name); - oconfig_free (java_plugins[i].ci); + ERROR ("cjni_init: JNI_CreateJavaVM failed with status %i.", + status); + return (-1); } - sfree (java_plugins); - java_plugins_num = 0; + 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."); + return (-1); + } + + cjni_init_plugins (jvm_env); return (0); -} /* }}} int cjni_shutdown */ +} /* }}} int cjni_init */ void module_register (void) { plugin_register_complex_config ("java", cjni_config); plugin_register_init ("java", cjni_init); - plugin_register_read ("java", cjni_read); - plugin_register_write ("java", cjni_write); - plugin_register_shutdown ("java", cjni_shutdown); } /* void module_register (void) */ /* vim: set sw=2 sts=2 et fdm=marker : */