2 * collectd - src/java.c
3 * Copyright (C) 2009 Florian octo Forster
4 * Copyright (C) 2008 Justo Alonso Achaques
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; only version 2 of the License is applicable.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * Florian octo Forster <octo at verplant.org>
21 * Justo Alonso Achaques <justo.alonso at gmail.com>
31 #if !defined(JNI_VERSION_1_2)
32 # error "Need JNI 1.2 compatible interface!"
38 struct java_plugin_s /* {{{ */
44 #define CJNI_FLAG_ENABLED 0x0001
47 jmethodID method_init;
48 jmethodID method_read;
49 jmethodID method_shutdown;
51 typedef struct java_plugin_s java_plugin_t;
57 static JavaVM *jvm = NULL;
59 static java_plugin_t java_plugins[] =
61 { "org.collectd.java.Foobar", NULL, NULL, 0, NULL, NULL, NULL }
63 static size_t java_plugins_num = sizeof (java_plugins) / sizeof (java_plugins[0]);
68 * - jtoc_*: From Java to C
69 * - ctoj_*: From C to Java
71 static int jtoc_string (JNIEnv *jvm_env, /* {{{ */
72 char *buffer, size_t buffer_size,
73 jclass class_ptr, jobject object_ptr, const char *method_name)
79 method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
80 method_name, "()Ljava/lang/String;");
81 if (method_id == NULL)
83 ERROR ("java plugin: jtoc_string: Cannot find method `String %s ()'.",
88 string_obj = (*jvm_env)->CallObjectMethod (jvm_env, object_ptr, method_id);
89 if (string_obj == NULL)
91 ERROR ("java plugin: jtoc_string: CallObjectMethod (%s) failed.",
96 c_str = (*jvm_env)->GetStringUTFChars (jvm_env, string_obj, 0);
99 ERROR ("java plugin: jtoc_string: GetStringUTFChars failed.");
100 (*jvm_env)->DeleteLocalRef (jvm_env, string_obj);
104 DEBUG ("java plugin: jtoc_string: ->%s() = %s", method_name, c_str);
106 sstrncpy (buffer, c_str, buffer_size);
108 (*jvm_env)->ReleaseStringUTFChars (jvm_env, string_obj, c_str);
109 (*jvm_env)->DeleteLocalRef (jvm_env, string_obj);
112 } /* }}} int jtoc_string */
114 static int jtoc_long (JNIEnv *jvm_env, /* {{{ */
116 jclass class_ptr, jobject object_ptr, const char *method_name)
120 method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
122 if (method_id == NULL)
124 ERROR ("java plugin: jtoc_string: Cannot find method `long %s ()'.",
129 *ret_value = (*jvm_env)->CallLongMethod (jvm_env, object_ptr, method_id);
131 DEBUG ("java plugin: jtoc_long: ->%s() = %li",
132 method_name, (long int) *ret_value);
135 } /* }}} int jtoc_long */
137 static int jtoc_double (JNIEnv *jvm_env, /* {{{ */
139 jclass class_ptr, jobject object_ptr, const char *method_name)
143 method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
145 if (method_id == NULL)
147 ERROR ("java plugin: jtoc_string: Cannot find method `double %s ()'.",
152 *ret_value = (*jvm_env)->CallDoubleMethod (jvm_env, object_ptr, method_id);
154 DEBUG ("java plugin: jtoc_double: ->%s() = %g",
155 method_name, (double) *ret_value);
158 } /* }}} int jtoc_double */
160 static int jtoc_value (JNIEnv *jvm_env, /* {{{ */
161 value_t *ret_value, int ds_type, jobject object_ptr)
166 class_ptr = (*jvm_env)->GetObjectClass (jvm_env, object_ptr);
168 if (ds_type == DS_TYPE_COUNTER)
172 status = jtoc_long (jvm_env, &tmp_long,
173 class_ptr, object_ptr, "longValue");
176 ERROR ("java plugin: jtoc_value: "
177 "jtoc_long failed.");
180 (*ret_value).counter = (counter_t) tmp_long;
186 status = jtoc_double (jvm_env, &tmp_double,
187 class_ptr, object_ptr, "doubleValue");
190 ERROR ("java plugin: jtoc_value: "
191 "jtoc_double failed.");
194 (*ret_value).gauge = (gauge_t) tmp_double;
198 } /* }}} int jtoc_value */
200 static int jtoc_values_array (JNIEnv *jvm_env, /* {{{ */
201 const data_set_t *ds, value_list_t *vl,
202 jclass class_ptr, jobject object_ptr)
204 jmethodID m_getvalues;
207 jobjectArray o_number_array;
213 values_num = ds->ds_num;
216 o_number_array = NULL;
219 #define BAIL_OUT(status) \
221 if (o_number_array != NULL) \
222 (*jvm_env)->DeleteLocalRef (jvm_env, o_number_array); \
223 if (o_list != NULL) \
224 (*jvm_env)->DeleteLocalRef (jvm_env, o_list); \
227 /* Call: List<Number> ValueList.getValues () */
228 m_getvalues = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
229 "getValues", "()Ljava/util/List;");
230 if (m_getvalues == NULL)
232 ERROR ("java plugin: jtoc_values_array: "
233 "Cannot find method `List getValues ()'.");
237 o_list = (*jvm_env)->CallObjectMethod (jvm_env, object_ptr, m_getvalues);
240 ERROR ("java plugin: jtoc_values_array: "
241 "CallObjectMethod (getValues) failed.");
245 /* Call: Number[] List.toArray () */
246 m_toarray = (*jvm_env)->GetMethodID (jvm_env,
247 (*jvm_env)->GetObjectClass (jvm_env, o_list),
248 "toArray", "()[Ljava/lang/Object;");
249 if (m_toarray == NULL)
251 ERROR ("java plugin: jtoc_values_array: "
252 "Cannot find method `Object[] toArray ()'.");
256 o_number_array = (*jvm_env)->CallObjectMethod (jvm_env, o_list, m_toarray);
257 if (o_number_array == NULL)
259 ERROR ("java plugin: jtoc_values_array: "
260 "CallObjectMethod (toArray) failed.");
264 values = calloc (values_num, sizeof (value_t));
267 ERROR ("java plugin: jtoc_values_array: calloc failed.");
271 for (i = 0; i < values_num; i++)
276 o_number = (*jvm_env)->GetObjectArrayElement (jvm_env,
277 o_number_array, (jsize) i);
278 if (o_number == NULL)
280 ERROR ("java plugin: jtoc_values_array: "
281 "GetObjectArrayElement (%i) failed.", i);
285 status = jtoc_value (jvm_env, values + i, ds->ds[i].type, o_number);
288 ERROR ("java plugin: jtoc_values_array: "
289 "jtoc_value (%i) failed.", i);
292 } /* for (i = 0; i < values_num; i++) */
295 vl->values_len = values_num;
298 (*jvm_env)->DeleteLocalRef (jvm_env, o_number_array);
299 (*jvm_env)->DeleteLocalRef (jvm_env, o_list);
301 } /* }}} int jtoc_values_array */
303 static int jtoc_value_list (JNIEnv *jvm_env, value_list_t *vl, /* {{{ */
309 const data_set_t *ds;
311 class_ptr = (*jvm_env)->GetObjectClass (jvm_env, object_ptr);
312 if (class_ptr == NULL)
314 ERROR ("java plugin: jtoc_value_list: GetObjectClass failed.");
318 #define SET_STRING(buffer,method) do { \
319 status = jtoc_string (jvm_env, buffer, sizeof (buffer), \
320 class_ptr, object_ptr, method); \
322 ERROR ("java plugin: jtoc_value_list: jtoc_string (%s) failed.", \
327 SET_STRING(vl->type, "getType");
329 ds = plugin_get_ds (vl->type);
332 ERROR ("java plugin: jtoc_value_list: Data-set `%s' is not defined. "
333 "Please consult the types.db(5) manpage for mor information.",
338 SET_STRING(vl->host, "getHost");
339 SET_STRING(vl->plugin, "getPlugin");
340 SET_STRING(vl->plugin_instance, "getPluginInstance");
341 SET_STRING(vl->type_instance, "getTypeInstance");
345 status = jtoc_long (jvm_env, &tmp_long, class_ptr, object_ptr, "getTime");
348 ERROR ("java plugin: jtoc_value_list: jtoc_string (getTime) failed.");
351 vl->time = (time_t) tmp_long;
353 status = jtoc_long (jvm_env, &tmp_long,
354 class_ptr, object_ptr, "getInterval");
357 ERROR ("java plugin: jtoc_value_list: jtoc_string (getInterval) failed.");
360 vl->interval = (int) tmp_long;
362 status = jtoc_values_array (jvm_env, ds, vl, class_ptr, object_ptr);
365 ERROR ("java plugin: jtoc_value_list: jtoc_values_array failed.");
370 } /* }}} int jtoc_value_list */
373 * Functions accessible from Java
375 static jint JNICALL cjni_api_dispatch_values (JNIEnv *jvm_env, /* {{{ */
376 jobject this, jobject java_vl)
378 value_list_t vl = VALUE_LIST_INIT;
381 DEBUG ("cjni_api_dispatch_values: java_vl = %p;", (void *) java_vl);
383 status = jtoc_value_list (jvm_env, &vl, java_vl);
386 ERROR ("java plugin: cjni_api_dispatch_values: jtoc_value_list failed.");
390 plugin_dispatch_values (&vl);
395 } /* }}} jint cjni_api_dispatch_values */
397 static JNINativeMethod jni_api_functions[] =
399 { "DispatchValues", "(Lorg/collectd/protocol/ValueList;)I", cjni_api_dispatch_values }
401 static size_t jni_api_functions_num = sizeof (jni_api_functions)
402 / sizeof (jni_api_functions[0]);
407 static int cjni_init_one_plugin (JNIEnv *jvm_env, java_plugin_t *jp) /* {{{ */
409 jmethodID constructor_id;
412 jp->class_ptr = (*jvm_env)->FindClass (jvm_env, jp->class_name);
413 if (jp->class_ptr == NULL)
415 ERROR ("cjni_init_one_plugin: FindClass (%s) failed.",
420 constructor_id = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
422 if (constructor_id == NULL)
424 ERROR ("cjni_init_one_plugin: Could not find the constructor for `%s'.",
429 jp->object_ptr = (*jvm_env)->NewObject (jvm_env, jp->class_ptr,
431 if (jp->object_ptr == NULL)
433 ERROR ("cjni_init_one_plugin: Could create a new `%s' object.",
438 jp->method_init = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
440 DEBUG ("jp->method_init = %p;", (void *) jp->method_init);
441 jp->method_read = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
443 DEBUG ("jp->method_read = %p;", (void *) jp->method_read);
444 jp->method_shutdown = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
446 DEBUG ("jp->method_shutdown = %p;", (void *) jp->method_shutdown);
448 status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
452 ERROR ("cjni_init_one_plugin: Initializing `%s' object failed "
453 "with status %i.", jp->class_name, status);
456 jp->flags |= CJNI_FLAG_ENABLED;
459 } /* }}} int cjni_init_one_plugin */
461 static int cjni_init_plugins (JNIEnv *jvm_env) /* {{{ */
465 for (j = 0; j < java_plugins_num; j++)
466 cjni_init_one_plugin (jvm_env, &java_plugins[j]);
469 } /* }}} int cjni_init_plugins */
471 static int cjni_init_native (JNIEnv *jvm_env) /* {{{ */
473 jclass api_class_ptr;
476 api_class_ptr = (*jvm_env)->FindClass (jvm_env, "org.collectd.java.CollectdAPI");
477 if (api_class_ptr == NULL)
479 ERROR ("cjni_init_native: Cannot find API class `org.collectd.java.CollectdAPI'.");
483 status = (*jvm_env)->RegisterNatives (jvm_env, api_class_ptr,
484 jni_api_functions, (jint) jni_api_functions_num);
487 ERROR ("cjni_init_native: RegisterNatives failed with status %i.", status);
492 } /* }}} int cjni_init_native */
494 static int cjni_init (void) /* {{{ */
497 JavaVMInitArgs vm_args;
498 JavaVMOption vm_options[2];
507 memset (&vm_args, 0, sizeof (vm_args));
508 vm_args.version = JNI_VERSION_1_2;
509 vm_args.options = vm_options;
510 vm_args.nOptions = sizeof (vm_options) / sizeof (vm_options[0]);
512 vm_args.options[0].optionString = "-verbose:jni";
513 vm_args.options[1].optionString = "-Djava.class.path=/home/octo/collectd/bindings/java";
515 status = JNI_CreateJavaVM (&jvm, (void **) &jvm_env, (void **) &vm_args);
518 ERROR ("cjni_init: JNI_CreateJavaVM failed with status %i.",
522 assert (jvm != NULL);
523 assert (jvm_env != NULL);
525 /* Call RegisterNatives */
526 status = cjni_init_native (jvm_env);
529 ERROR ("cjni_init: cjni_init_native failed.");
533 cjni_init_plugins (jvm_env);
536 } /* }}} int cjni_init */
538 static int cjni_read_one_plugin (JNIEnv *jvm_env, java_plugin_t *jp) /* {{{ */
543 || ((jp->flags & CJNI_FLAG_ENABLED) == 0)
544 || (jp->method_read == NULL))
547 DEBUG ("java plugin: Calling: %s.Read()", jp->class_name);
549 status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
553 ERROR ("cjni_read_one_plugin: Calling `Read' on an `%s' object failed "
554 "with status %i.", jp->class_name, status);
559 } /* }}} int cjni_read_one_plugin */
561 static int cjni_read_plugins (JNIEnv *jvm_env) /* {{{ */
565 for (j = 0; j < java_plugins_num; j++)
566 cjni_read_one_plugin (jvm_env, &java_plugins[j]);
569 } /* }}} int cjni_read_plugins */
571 static int cjni_read (void) /* {{{ */
574 JavaVMAttachArgs args;
579 ERROR ("java plugin: cjni_read: jvm == NULL");
584 memset (&args, 0, sizeof (args));
585 args.version = JNI_VERSION_1_2;
587 status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args);
590 ERROR ("java plugin: cjni_read: AttachCurrentThread failed with status %i.",
595 cjni_read_plugins (jvm_env);
597 status = (*jvm)->DetachCurrentThread (jvm);
600 ERROR ("java plugin: cjni_read: DetachCurrentThread failed with status %i.",
606 } /* }}} int cjni_read */
608 static int cjni_shutdown_one_plugin (JNIEnv *jvm_env, /* {{{ */
614 || ((jp->flags & CJNI_FLAG_ENABLED) == 0)
615 || (jp->method_shutdown == NULL))
618 status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
619 jp->method_shutdown);
622 ERROR ("cjni_shutdown_one_plugin: Destroying an `%s' object failed "
623 "with status %i.", jp->class_name, status);
626 jp->flags &= ~CJNI_FLAG_ENABLED;
629 } /* }}} int cjni_shutdown_one_plugin */
631 static int cjni_shutdown_plugins (JNIEnv *jvm_env) /* {{{ */
635 for (j = 0; j < java_plugins_num; j++)
636 cjni_shutdown_one_plugin (jvm_env, &java_plugins[j]);
639 } /* }}} int cjni_shutdown_plugins */
641 static int cjni_shutdown (void) /* {{{ */
644 JavaVMAttachArgs args;
651 memset (&args, 0, sizeof (args));
652 args.version = JNI_VERSION_1_2;
654 status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args);
657 ERROR ("java plugin: cjni_read: AttachCurrentThread failed with status %i.",
662 cjni_shutdown_plugins (jvm_env);
664 (*jvm)->DestroyJavaVM (jvm);
669 } /* }}} int cjni_shutdown */
671 void module_register (void)
673 plugin_register_init ("java", cjni_init);
674 plugin_register_read ("java", cjni_read);
675 plugin_register_shutdown ("java", cjni_shutdown);
676 } /* void module_register (void) */
678 /* vim: set sw=2 sts=2 et fdm=marker : */