1 /**
2 * collectd - src/java.c
3 * Copyright (C) 2009 Florian octo Forster
4 * Copyright (C) 2008 Justo Alonso Achaques
5 *
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.
9 *
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.
14 *
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
18 *
19 * Authors:
20 * Florian octo Forster <octo at verplant.org>
21 * Justo Alonso Achaques <justo.alonso at gmail.com>
22 **/
24 #include "collectd.h"
25 #include "plugin.h"
26 #include "common.h"
28 #include <pthread.h>
29 #include <jni.h>
31 #if !defined(JNI_VERSION_1_2)
32 # error "Need JNI 1.2 compatible interface!"
33 #endif
35 /*
36 * Types
37 */
38 struct java_plugin_s /* {{{ */
39 {
40 char *class_name;
41 jclass class_ptr;
42 jobject object_ptr;
44 oconfig_item_t *ci;
46 #define CJNI_FLAG_ENABLED 0x0001
47 int flags;
49 jmethodID m_config;
50 jmethodID m_init;
51 jmethodID m_shutdown;
52 };
53 typedef struct java_plugin_s java_plugin_t;
54 /* }}} */
56 struct cjni_jvm_env_s /* {{{ */
57 {
58 JNIEnv *jvm_env;
59 int reference_counter;
60 };
61 typedef struct cjni_jvm_env_s cjni_jvm_env_t;
62 /* }}} */
64 struct cjni_callback_info_s /* {{{ */
65 {
66 jclass class;
67 jobject object;
68 jmethodID method;
69 };
70 typedef struct cjni_callback_info_s cjni_callback_info_t;
71 /* }}} */
73 /*
74 * Global variables
75 */
76 static JavaVM *jvm = NULL;
77 static pthread_key_t jvm_env_key;
79 static char **jvm_argv = NULL;
80 static size_t jvm_argc = 0;
82 static java_plugin_t *java_plugins = NULL;
83 static size_t java_plugins_num = 0;
85 /*
86 * Prototypes
87 *
88 * Mostly functions that are needed by the Java interface functions.
89 */
90 static void cjni_callback_info_destroy (void *arg);
91 static int cjni_read (user_data_t *user_data);
92 static int cjni_write (const data_set_t *ds, const value_list_t *vl,
93 user_data_t *ud);
95 /*
96 * C to Java conversion functions
97 */
98 static int ctoj_string (JNIEnv *jvm_env, /* {{{ */
99 const char *string,
100 jclass class_ptr, jobject object_ptr, const char *method_name)
101 {
102 jmethodID m_set;
103 jstring o_string;
105 /* Create a java.lang.String */
106 o_string = (*jvm_env)->NewStringUTF (jvm_env,
107 (string != NULL) ? string : "");
108 if (o_string == NULL)
109 {
110 ERROR ("java plugin: ctoj_string: NewStringUTF failed.");
111 return (-1);
112 }
114 /* Search for the `void setFoo (String s)' method. */
115 m_set = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
116 method_name, "(Ljava/lang/String;)V");
117 if (m_set == NULL)
118 {
119 ERROR ("java plugin: ctoj_string: Cannot find method `void %s (String)'.",
120 method_name);
121 (*jvm_env)->DeleteLocalRef (jvm_env, o_string);
122 return (-1);
123 }
125 /* Call the method. */
126 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, o_string);
128 /* Decrease reference counter on the java.lang.String object. */
129 (*jvm_env)->DeleteLocalRef (jvm_env, o_string);
131 return (0);
132 } /* }}} int ctoj_string */
134 static int ctoj_int (JNIEnv *jvm_env, /* {{{ */
135 jint value,
136 jclass class_ptr, jobject object_ptr, const char *method_name)
137 {
138 jmethodID m_set;
140 /* Search for the `void setFoo (int i)' method. */
141 m_set = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
142 method_name, "(I)V");
143 if (m_set == NULL)
144 {
145 ERROR ("java plugin: ctoj_int: Cannot find method `void %s (int)'.",
146 method_name);
147 return (-1);
148 }
150 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, value);
152 return (0);
153 } /* }}} int ctoj_int */
155 static int ctoj_long (JNIEnv *jvm_env, /* {{{ */
156 jlong value,
157 jclass class_ptr, jobject object_ptr, const char *method_name)
158 {
159 jmethodID m_set;
161 /* Search for the `void setFoo (long l)' method. */
162 m_set = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
163 method_name, "(J)V");
164 if (m_set == NULL)
165 {
166 ERROR ("java plugin: ctoj_long: Cannot find method `void %s (long)'.",
167 method_name);
168 return (-1);
169 }
171 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, value);
173 return (0);
174 } /* }}} int ctoj_long */
176 static int ctoj_double (JNIEnv *jvm_env, /* {{{ */
177 jdouble value,
178 jclass class_ptr, jobject object_ptr, const char *method_name)
179 {
180 jmethodID m_set;
182 /* Search for the `void setFoo (double d)' method. */
183 m_set = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
184 method_name, "(D)V");
185 if (m_set == NULL)
186 {
187 ERROR ("java plugin: ctoj_double: Cannot find method `void %s (double)'.",
188 method_name);
189 return (-1);
190 }
192 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, value);
194 return (0);
195 } /* }}} int ctoj_double */
197 /* Convert a jlong to a java.lang.Number */
198 static jobject ctoj_jlong_to_number (JNIEnv *jvm_env, jlong value) /* {{{ */
199 {
200 jclass c_long;
201 jmethodID m_long_constructor;
203 /* Look up the java.lang.Long class */
204 c_long = (*jvm_env)->FindClass (jvm_env, "java.lang.Long");
205 if (c_long == NULL)
206 {
207 ERROR ("java plugin: ctoj_jlong_to_number: Looking up the "
208 "java.lang.Long class failed.");
209 return (NULL);
210 }
212 m_long_constructor = (*jvm_env)->GetMethodID (jvm_env,
213 c_long, "<init>", "(J)V");
214 if (m_long_constructor == NULL)
215 {
216 ERROR ("java plugin: ctoj_jlong_to_number: Looking up the "
217 "`Long (long)' constructor failed.");
218 return (NULL);
219 }
221 return ((*jvm_env)->NewObject (jvm_env,
222 c_long, m_long_constructor, value));
223 } /* }}} jobject ctoj_jlong_to_number */
225 /* Convert a jdouble to a java.lang.Number */
226 static jobject ctoj_jdouble_to_number (JNIEnv *jvm_env, jdouble value) /* {{{ */
227 {
228 jclass c_double;
229 jmethodID m_double_constructor;
231 /* Look up the java.lang.Long class */
232 c_double = (*jvm_env)->FindClass (jvm_env, "java.lang.Double");
233 if (c_double == NULL)
234 {
235 ERROR ("java plugin: ctoj_jdouble_to_number: Looking up the "
236 "java.lang.Double class failed.");
237 return (NULL);
238 }
240 m_double_constructor = (*jvm_env)->GetMethodID (jvm_env,
241 c_double, "<init>", "(D)V");
242 if (m_double_constructor == NULL)
243 {
244 ERROR ("java plugin: ctoj_jdouble_to_number: Looking up the "
245 "`Double (double)' constructor failed.");
246 return (NULL);
247 }
249 return ((*jvm_env)->NewObject (jvm_env,
250 c_double, m_double_constructor, value));
251 } /* }}} jobject ctoj_jdouble_to_number */
253 /* Convert a value_t to a java.lang.Number */
254 static jobject ctoj_value_to_number (JNIEnv *jvm_env, /* {{{ */
255 value_t value, int ds_type)
256 {
257 if (ds_type == DS_TYPE_COUNTER)
258 return (ctoj_jlong_to_number (jvm_env, (jlong) value.counter));
259 else if (ds_type == DS_TYPE_GAUGE)
260 return (ctoj_jdouble_to_number (jvm_env, (jdouble) value.gauge));
261 else
262 return (NULL);
263 } /* }}} jobject ctoj_value_to_number */
265 /* Convert a data_source_t to a org.collectd.api.DataSource */
266 static jobject ctoj_data_source (JNIEnv *jvm_env, /* {{{ */
267 const data_source_t *dsrc)
268 {
269 jclass c_datasource;
270 jmethodID m_datasource_constructor;
271 jobject o_datasource;
272 int status;
274 /* Look up the DataSource class */
275 c_datasource = (*jvm_env)->FindClass (jvm_env,
276 "org.collectd.api.DataSource");
277 if (c_datasource == NULL)
278 {
279 ERROR ("java plugin: ctoj_data_source: "
280 "FindClass (org.collectd.api.DataSource) failed.");
281 return (NULL);
282 }
284 /* Lookup the `ValueList ()' constructor. */
285 m_datasource_constructor = (*jvm_env)->GetMethodID (jvm_env, c_datasource,
286 "<init>", "()V");
287 if (m_datasource_constructor == NULL)
288 {
289 ERROR ("java plugin: ctoj_data_source: Cannot find the "
290 "`DataSource ()' constructor.");
291 return (NULL);
292 }
294 /* Create a new instance. */
295 o_datasource = (*jvm_env)->NewObject (jvm_env, c_datasource,
296 m_datasource_constructor);
297 if (o_datasource == NULL)
298 {
299 ERROR ("java plugin: ctoj_data_source: "
300 "Creating a new DataSource instance failed.");
301 return (NULL);
302 }
304 /* Set name via `void setName (String name)' */
305 status = ctoj_string (jvm_env, dsrc->name,
306 c_datasource, o_datasource, "setName");
307 if (status != 0)
308 {
309 ERROR ("java plugin: ctoj_data_source: "
310 "ctoj_string (setName) failed.");
311 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
312 return (NULL);
313 }
315 /* Set type via `void setType (int type)' */
316 status = ctoj_int (jvm_env, dsrc->type,
317 c_datasource, o_datasource, "setType");
318 if (status != 0)
319 {
320 ERROR ("java plugin: ctoj_data_source: "
321 "ctoj_int (setType) failed.");
322 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
323 return (NULL);
324 }
326 /* Set min via `void setMin (double min)' */
327 status = ctoj_double (jvm_env, dsrc->min,
328 c_datasource, o_datasource, "setMin");
329 if (status != 0)
330 {
331 ERROR ("java plugin: ctoj_data_source: "
332 "ctoj_double (setMin) failed.");
333 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
334 return (NULL);
335 }
337 /* Set max via `void setMax (double max)' */
338 status = ctoj_double (jvm_env, dsrc->max,
339 c_datasource, o_datasource, "setMax");
340 if (status != 0)
341 {
342 ERROR ("java plugin: ctoj_data_source: "
343 "ctoj_double (setMax) failed.");
344 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
345 return (NULL);
346 }
348 return (o_datasource);
349 } /* }}} jobject ctoj_data_source */
351 /* Convert a oconfig_value_t to a org.collectd.api.OConfigValue */
352 static jobject ctoj_oconfig_value (JNIEnv *jvm_env, /* {{{ */
353 oconfig_value_t ocvalue)
354 {
355 jclass c_ocvalue;
356 jmethodID m_ocvalue_constructor;
357 jobject o_argument;
358 jobject o_ocvalue;
360 m_ocvalue_constructor = NULL;
361 o_argument = NULL;
363 c_ocvalue = (*jvm_env)->FindClass (jvm_env,
364 "org.collectd.api.OConfigValue");
365 if (c_ocvalue == NULL)
366 {
367 ERROR ("java plugin: ctoj_oconfig_value: "
368 "FindClass (org.collectd.api.OConfigValue) failed.");
369 return (NULL);
370 }
372 if (ocvalue.type == OCONFIG_TYPE_BOOLEAN)
373 {
374 jboolean tmp_boolean;
376 tmp_boolean = (ocvalue.value.boolean == 0) ? JNI_FALSE : JNI_TRUE;
378 m_ocvalue_constructor = (*jvm_env)->GetMethodID (jvm_env, c_ocvalue,
379 "<init>", "(Z)V");
380 if (m_ocvalue_constructor == NULL)
381 {
382 ERROR ("java plugin: ctoj_oconfig_value: Cannot find the "
383 "`OConfigValue (boolean)' constructor.");
384 return (NULL);
385 }
387 return ((*jvm_env)->NewObject (jvm_env,
388 c_ocvalue, m_ocvalue_constructor, tmp_boolean));
389 } /* if (ocvalue.type == OCONFIG_TYPE_BOOLEAN) */
390 else if (ocvalue.type == OCONFIG_TYPE_STRING)
391 {
392 m_ocvalue_constructor = (*jvm_env)->GetMethodID (jvm_env, c_ocvalue,
393 "<init>", "(Ljava/lang/String;)V");
394 if (m_ocvalue_constructor == NULL)
395 {
396 ERROR ("java plugin: ctoj_oconfig_value: Cannot find the "
397 "`OConfigValue (String)' constructor.");
398 return (NULL);
399 }
401 o_argument = (*jvm_env)->NewStringUTF (jvm_env, ocvalue.value.string);
402 if (o_argument == NULL)
403 {
404 ERROR ("java plugin: ctoj_oconfig_value: "
405 "Creating a String object failed.");
406 return (NULL);
407 }
408 }
409 else if (ocvalue.type == OCONFIG_TYPE_NUMBER)
410 {
411 m_ocvalue_constructor = (*jvm_env)->GetMethodID (jvm_env, c_ocvalue,
412 "<init>", "(Ljava/lang/Number;)V");
413 if (m_ocvalue_constructor == NULL)
414 {
415 ERROR ("java plugin: ctoj_oconfig_value: Cannot find the "
416 "`OConfigValue (Number)' constructor.");
417 return (NULL);
418 }
420 o_argument = ctoj_jdouble_to_number (jvm_env,
421 (jdouble) ocvalue.value.number);
422 if (o_argument == NULL)
423 {
424 ERROR ("java plugin: ctoj_oconfig_value: "
425 "Creating a Number object failed.");
426 return (NULL);
427 }
428 }
429 else
430 {
431 return (NULL);
432 }
434 assert (m_ocvalue_constructor != NULL);
435 assert (o_argument != NULL);
437 o_ocvalue = (*jvm_env)->NewObject (jvm_env,
438 c_ocvalue, m_ocvalue_constructor, o_argument);
439 if (o_ocvalue == NULL)
440 {
441 ERROR ("java plugin: ctoj_oconfig_value: "
442 "Creating an OConfigValue object failed.");
443 (*jvm_env)->DeleteLocalRef (jvm_env, o_argument);
444 return (NULL);
445 }
447 (*jvm_env)->DeleteLocalRef (jvm_env, o_argument);
448 return (o_ocvalue);
449 } /* }}} jobject ctoj_oconfig_value */
451 /* Convert a oconfig_item_t to a org.collectd.api.OConfigItem */
452 static jobject ctoj_oconfig_item (JNIEnv *jvm_env, /* {{{ */
453 const oconfig_item_t *ci)
454 {
455 jclass c_ocitem;
456 jmethodID m_ocitem_constructor;
457 jmethodID m_addvalue;
458 jmethodID m_addchild;
459 jobject o_key;
460 jobject o_ocitem;
461 int i;
463 c_ocitem = (*jvm_env)->FindClass (jvm_env, "org.collectd.api.OConfigItem");
464 if (c_ocitem == NULL)
465 {
466 ERROR ("java plugin: ctoj_oconfig_item: "
467 "FindClass (org.collectd.api.OConfigItem) failed.");
468 return (NULL);
469 }
471 /* Get the required methods: m_ocitem_constructor, m_addvalue, and m_addchild
472 * {{{ */
473 m_ocitem_constructor = (*jvm_env)->GetMethodID (jvm_env, c_ocitem,
474 "<init>", "(Ljava/lang/String;)V");
475 if (m_ocitem_constructor == NULL)
476 {
477 ERROR ("java plugin: ctoj_oconfig_item: Cannot find the "
478 "`OConfigItem (String)' constructor.");
479 return (NULL);
480 }
482 m_addvalue = (*jvm_env)->GetMethodID (jvm_env, c_ocitem,
483 "addValue", "(Lorg/collectd/api/OConfigValue;)V");
484 if (m_addvalue == NULL)
485 {
486 ERROR ("java plugin: ctoj_oconfig_item: Cannot find the "
487 "`addValue (OConfigValue)' method.");
488 return (NULL);
489 }
491 m_addchild = (*jvm_env)->GetMethodID (jvm_env, c_ocitem,
492 "addChild", "(Lorg/collectd/api/OConfigItem;)V");
493 if (m_addchild == NULL)
494 {
495 ERROR ("java plugin: ctoj_oconfig_item: Cannot find the "
496 "`addChild (OConfigItem)' method.");
497 return (NULL);
498 }
499 /* }}} */
501 /* Create a String object with the key.
502 * Needed for calling the constructor. */
503 o_key = (*jvm_env)->NewStringUTF (jvm_env, ci->key);
504 if (o_key == NULL)
505 {
506 ERROR ("java plugin: ctoj_oconfig_item: "
507 "Creating String object failed.");
508 return (NULL);
509 }
511 /* Create an OConfigItem object */
512 o_ocitem = (*jvm_env)->NewObject (jvm_env,
513 c_ocitem, m_ocitem_constructor, o_key);
514 if (o_ocitem == NULL)
515 {
516 ERROR ("java plugin: ctoj_oconfig_item: "
517 "Creating an OConfigItem object failed.");
518 (*jvm_env)->DeleteLocalRef (jvm_env, o_key);
519 return (NULL);
520 }
522 /* We don't need the String object any longer.. */
523 (*jvm_env)->DeleteLocalRef (jvm_env, o_key);
525 /* Call OConfigItem.addValue for each value */
526 for (i = 0; i < ci->values_num; i++) /* {{{ */
527 {
528 jobject o_value;
530 o_value = ctoj_oconfig_value (jvm_env, ci->values[i]);
531 if (o_value == NULL)
532 {
533 ERROR ("java plugin: ctoj_oconfig_item: "
534 "Creating an OConfigValue object failed.");
535 (*jvm_env)->DeleteLocalRef (jvm_env, o_ocitem);
536 return (NULL);
537 }
539 (*jvm_env)->CallVoidMethod (jvm_env, o_ocitem, m_addvalue, o_value);
540 (*jvm_env)->DeleteLocalRef (jvm_env, o_value);
541 } /* }}} for (i = 0; i < ci->values_num; i++) */
543 /* Call OConfigItem.addChild for each child */
544 for (i = 0; i < ci->children_num; i++) /* {{{ */
545 {
546 jobject o_child;
548 o_child = ctoj_oconfig_item (jvm_env, ci->children + i);
549 if (o_child == NULL)
550 {
551 ERROR ("java plugin: ctoj_oconfig_item: "
552 "Creating an OConfigItem object failed.");
553 (*jvm_env)->DeleteLocalRef (jvm_env, o_ocitem);
554 return (NULL);
555 }
557 (*jvm_env)->CallVoidMethod (jvm_env, o_ocitem, m_addvalue, o_child);
558 (*jvm_env)->DeleteLocalRef (jvm_env, o_child);
559 } /* }}} for (i = 0; i < ci->children_num; i++) */
561 return (o_ocitem);
562 } /* }}} jobject ctoj_oconfig_item */
564 /* Convert a data_set_t to a org.collectd.api.DataSet */
565 static jobject ctoj_data_set (JNIEnv *jvm_env, const data_set_t *ds) /* {{{ */
566 {
567 jclass c_dataset;
568 jmethodID m_constructor;
569 jmethodID m_add;
570 jobject o_type;
571 jobject o_dataset;
572 int i;
574 /* Look up the org.collectd.api.DataSet class */
575 c_dataset = (*jvm_env)->FindClass (jvm_env, "org.collectd.api.DataSet");
576 if (c_dataset == NULL)
577 {
578 ERROR ("java plugin: ctoj_data_set: Looking up the "
579 "org.collectd.api.DataSet class failed.");
580 return (NULL);
581 }
583 /* Search for the `DataSet (String type)' constructor. */
584 m_constructor = (*jvm_env)->GetMethodID (jvm_env,
585 c_dataset, "<init>", "(Ljava.lang.String;)V");
586 if (m_constructor == NULL)
587 {
588 ERROR ("java plugin: ctoj_data_set: Looking up the "
589 "`DataSet (String)' constructor failed.");
590 return (NULL);
591 }
593 /* Search for the `void addDataSource (DataSource)' method. */
594 m_add = (*jvm_env)->GetMethodID (jvm_env,
595 c_dataset, "addDataSource", "(Lorg.collectd.api.DataSource;)V");
596 if (m_add == NULL)
597 {
598 ERROR ("java plugin: ctoj_data_set: Looking up the "
599 "`addDataSource (DataSource)' method failed.");
600 return (NULL);
601 }
603 o_type = (*jvm_env)->NewStringUTF (jvm_env, ds->type);
604 if (o_type == NULL)
605 {
606 ERROR ("java plugin: ctoj_data_set: Creating a String object failed.");
607 return (NULL);
608 }
610 o_dataset = (*jvm_env)->NewObject (jvm_env,
611 c_dataset, m_constructor, o_type);
612 if (o_dataset == NULL)
613 {
614 ERROR ("java plugin: ctoj_data_set: Creating a DataSet object failed.");
615 (*jvm_env)->DeleteLocalRef (jvm_env, o_type);
616 return (NULL);
617 }
619 /* Decrease reference counter on the java.lang.String object. */
620 (*jvm_env)->DeleteLocalRef (jvm_env, o_type);
622 for (i = 0; i < ds->ds_num; i++)
623 {
624 jobject o_datasource;
626 o_datasource = ctoj_data_source (jvm_env, ds->ds + i);
627 if (o_datasource == NULL)
628 {
629 ERROR ("java plugin: ctoj_data_set: ctoj_data_source (%s.%s) failed",
630 ds->type, ds->ds[i].name);
631 (*jvm_env)->DeleteLocalRef (jvm_env, o_dataset);
632 return (NULL);
633 }
635 (*jvm_env)->CallVoidMethod (jvm_env, o_dataset, m_add, o_datasource);
637 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
638 } /* for (i = 0; i < ds->ds_num; i++) */
640 return (o_dataset);
641 } /* }}} jobject ctoj_data_set */
643 static int ctoj_value_list_add_value (JNIEnv *jvm_env, /* {{{ */
644 value_t value, int ds_type,
645 jclass class_ptr, jobject object_ptr)
646 {
647 jmethodID m_addvalue;
648 jobject o_number;
650 m_addvalue = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
651 "addValue", "(Ljava/lang/Number;)V");
652 if (m_addvalue == NULL)
653 {
654 ERROR ("java plugin: ctoj_value_list_add_value: "
655 "Cannot find method `void addValue (Number)'.");
656 return (-1);
657 }
659 o_number = ctoj_value_to_number (jvm_env, value, ds_type);
660 if (o_number == NULL)
661 {
662 ERROR ("java plugin: ctoj_value_list_add_value: "
663 "ctoj_value_to_number failed.");
664 return (-1);
665 }
667 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_addvalue, o_number);
669 (*jvm_env)->DeleteLocalRef (jvm_env, o_number);
671 return (0);
672 } /* }}} int ctoj_value_list_add_value */
674 static int ctoj_value_list_add_data_set (JNIEnv *jvm_env, /* {{{ */
675 jclass c_valuelist, jobject o_valuelist, const data_set_t *ds)
676 {
677 jmethodID m_setdataset;
678 jobject o_dataset;
680 /* Look for the `void setDataSource (List<DataSource> ds)' method. */
681 m_setdataset = (*jvm_env)->GetMethodID (jvm_env, c_valuelist,
682 "setDataSet", "(Lorg.collectd.api.DataSet;)V");
683 if (m_setdataset == NULL)
684 {
685 ERROR ("java plugin: ctoj_value_list_add_data_set: "
686 "Cannot find the `void setDataSet (DataSet)' method.");
687 return (-1);
688 }
690 /* Create a DataSet object. */
691 o_dataset = ctoj_data_set (jvm_env, ds);
692 if (o_dataset == NULL)
693 {
694 ERROR ("java plugin: ctoj_value_list_add_data_set: "
695 "ctoj_data_set (%s) failed.", ds->type);
696 return (-1);
697 }
699 /* Actually call the method. */
700 (*jvm_env)->CallVoidMethod (jvm_env,
701 o_valuelist, m_setdataset, o_dataset);
703 /* Decrease reference counter on the List<DataSource> object. */
704 (*jvm_env)->DeleteLocalRef (jvm_env, o_dataset);
706 return (0);
707 } /* }}} int ctoj_value_list_add_data_set */
709 static jobject ctoj_value_list (JNIEnv *jvm_env, /* {{{ */
710 const data_set_t *ds, const value_list_t *vl)
711 {
712 jclass c_valuelist;
713 jmethodID m_valuelist_constructor;
714 jobject o_valuelist;
715 int status;
716 int i;
718 /* First, create a new ValueList instance..
719 * Look up the class.. */
720 c_valuelist = (*jvm_env)->FindClass (jvm_env,
721 "org.collectd.api.ValueList");
722 if (c_valuelist == NULL)
723 {
724 ERROR ("java plugin: ctoj_value_list: "
725 "FindClass (org.collectd.api.ValueList) failed.");
726 return (NULL);
727 }
729 /* Lookup the `ValueList ()' constructor. */
730 m_valuelist_constructor = (*jvm_env)->GetMethodID (jvm_env, c_valuelist,
731 "<init>", "()V");
732 if (m_valuelist_constructor == NULL)
733 {
734 ERROR ("java plugin: ctoj_value_list: Cannot find the "
735 "`ValueList ()' constructor.");
736 return (NULL);
737 }
739 /* Create a new instance. */
740 o_valuelist = (*jvm_env)->NewObject (jvm_env, c_valuelist,
741 m_valuelist_constructor);
742 if (o_valuelist == NULL)
743 {
744 ERROR ("java plugin: ctoj_value_list: Creating a new ValueList instance "
745 "failed.");
746 return (NULL);
747 }
749 status = ctoj_value_list_add_data_set (jvm_env,
750 c_valuelist, o_valuelist, ds);
751 if (status != 0)
752 {
753 ERROR ("java plugin: ctoj_value_list: "
754 "ctoj_value_list_add_data_set failed.");
755 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist);
756 return (NULL);
757 }
759 /* Set the strings.. */
760 #define SET_STRING(str,method_name) do { \
761 status = ctoj_string (jvm_env, str, \
762 c_valuelist, o_valuelist, method_name); \
763 if (status != 0) { \
764 ERROR ("java plugin: ctoj_value_list: jtoc_string (%s) failed.", \
765 method_name); \
766 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist); \
767 return (NULL); \
768 } } while (0)
770 SET_STRING (vl->host, "setHost");
771 SET_STRING (vl->plugin, "setPlugin");
772 SET_STRING (vl->plugin_instance, "setPluginInstance");
773 SET_STRING (vl->type, "setType");
774 SET_STRING (vl->type_instance, "setTypeInstance");
776 #undef SET_STRING
778 /* Set the `time' member. Java stores time in milliseconds. */
779 status = ctoj_long (jvm_env, ((jlong) vl->time) * ((jlong) 1000),
780 c_valuelist, o_valuelist, "setTime");
781 if (status != 0)
782 {
783 ERROR ("java plugin: ctoj_value_list: ctoj_long (setTime) failed.");
784 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist);
785 return (NULL);
786 }
788 /* Set the `interval' member.. */
789 status = ctoj_long (jvm_env, (jlong) vl->interval,
790 c_valuelist, o_valuelist, "setInterval");
791 if (status != 0)
792 {
793 ERROR ("java plugin: ctoj_value_list: ctoj_long (setInterval) failed.");
794 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist);
795 return (NULL);
796 }
798 for (i = 0; i < vl->values_len; i++)
799 {
800 status = ctoj_value_list_add_value (jvm_env, vl->values[i], ds->ds[i].type,
801 c_valuelist, o_valuelist);
802 if (status != 0)
803 {
804 ERROR ("java plugin: ctoj_value_list: "
805 "ctoj_value_list_add_value failed.");
806 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist);
807 return (NULL);
808 }
809 }
811 return (o_valuelist);
812 } /* }}} int ctoj_value_list */
814 /*
815 * Java to C conversion functions
816 */
817 static int jtoc_string (JNIEnv *jvm_env, /* {{{ */
818 char *buffer, size_t buffer_size,
819 jclass class_ptr, jobject object_ptr, const char *method_name)
820 {
821 jmethodID method_id;
822 jobject string_obj;
823 const char *c_str;
825 method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
826 method_name, "()Ljava/lang/String;");
827 if (method_id == NULL)
828 {
829 ERROR ("java plugin: jtoc_string: Cannot find method `String %s ()'.",
830 method_name);
831 return (-1);
832 }
834 string_obj = (*jvm_env)->CallObjectMethod (jvm_env, object_ptr, method_id);
835 if (string_obj == NULL)
836 {
837 ERROR ("java plugin: jtoc_string: CallObjectMethod (%s) failed.",
838 method_name);
839 return (-1);
840 }
842 c_str = (*jvm_env)->GetStringUTFChars (jvm_env, string_obj, 0);
843 if (c_str == NULL)
844 {
845 ERROR ("java plugin: jtoc_string: GetStringUTFChars failed.");
846 (*jvm_env)->DeleteLocalRef (jvm_env, string_obj);
847 return (-1);
848 }
850 sstrncpy (buffer, c_str, buffer_size);
852 (*jvm_env)->ReleaseStringUTFChars (jvm_env, string_obj, c_str);
853 (*jvm_env)->DeleteLocalRef (jvm_env, string_obj);
855 return (0);
856 } /* }}} int jtoc_string */
858 static int jtoc_long (JNIEnv *jvm_env, /* {{{ */
859 jlong *ret_value,
860 jclass class_ptr, jobject object_ptr, const char *method_name)
861 {
862 jmethodID method_id;
864 method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
865 method_name, "()J");
866 if (method_id == NULL)
867 {
868 ERROR ("java plugin: jtoc_long: Cannot find method `long %s ()'.",
869 method_name);
870 return (-1);
871 }
873 *ret_value = (*jvm_env)->CallLongMethod (jvm_env, object_ptr, method_id);
875 return (0);
876 } /* }}} int jtoc_long */
878 static int jtoc_double (JNIEnv *jvm_env, /* {{{ */
879 jdouble *ret_value,
880 jclass class_ptr, jobject object_ptr, const char *method_name)
881 {
882 jmethodID method_id;
884 method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
885 method_name, "()D");
886 if (method_id == NULL)
887 {
888 ERROR ("java plugin: jtoc_string: Cannot find method `double %s ()'.",
889 method_name);
890 return (-1);
891 }
893 *ret_value = (*jvm_env)->CallDoubleMethod (jvm_env, object_ptr, method_id);
895 return (0);
896 } /* }}} int jtoc_double */
898 static int jtoc_value (JNIEnv *jvm_env, /* {{{ */
899 value_t *ret_value, int ds_type, jobject object_ptr)
900 {
901 jclass class_ptr;
902 int status;
904 class_ptr = (*jvm_env)->GetObjectClass (jvm_env, object_ptr);
906 if (ds_type == DS_TYPE_COUNTER)
907 {
908 jlong tmp_long;
910 status = jtoc_long (jvm_env, &tmp_long,
911 class_ptr, object_ptr, "longValue");
912 if (status != 0)
913 {
914 ERROR ("java plugin: jtoc_value: "
915 "jtoc_long failed.");
916 return (-1);
917 }
918 (*ret_value).counter = (counter_t) tmp_long;
919 }
920 else
921 {
922 jdouble tmp_double;
924 status = jtoc_double (jvm_env, &tmp_double,
925 class_ptr, object_ptr, "doubleValue");
926 if (status != 0)
927 {
928 ERROR ("java plugin: jtoc_value: "
929 "jtoc_double failed.");
930 return (-1);
931 }
932 (*ret_value).gauge = (gauge_t) tmp_double;
933 }
935 return (0);
936 } /* }}} int jtoc_value */
938 static int jtoc_values_array (JNIEnv *jvm_env, /* {{{ */
939 const data_set_t *ds, value_list_t *vl,
940 jclass class_ptr, jobject object_ptr)
941 {
942 jmethodID m_getvalues;
943 jmethodID m_toarray;
944 jobject o_list;
945 jobjectArray o_number_array;
947 value_t *values;
948 int values_num;
949 int i;
951 values_num = ds->ds_num;
953 values = NULL;
954 o_number_array = NULL;
955 o_list = NULL;
957 #define BAIL_OUT(status) \
958 free (values); \
959 if (o_number_array != NULL) \
960 (*jvm_env)->DeleteLocalRef (jvm_env, o_number_array); \
961 if (o_list != NULL) \
962 (*jvm_env)->DeleteLocalRef (jvm_env, o_list); \
963 return (status);
965 /* Call: List<Number> ValueList.getValues () */
966 m_getvalues = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
967 "getValues", "()Ljava/util/List;");
968 if (m_getvalues == NULL)
969 {
970 ERROR ("java plugin: jtoc_values_array: "
971 "Cannot find method `List getValues ()'.");
972 BAIL_OUT (-1);
973 }
975 o_list = (*jvm_env)->CallObjectMethod (jvm_env, object_ptr, m_getvalues);
976 if (o_list == NULL)
977 {
978 ERROR ("java plugin: jtoc_values_array: "
979 "CallObjectMethod (getValues) failed.");
980 BAIL_OUT (-1);
981 }
983 /* Call: Number[] List.toArray () */
984 m_toarray = (*jvm_env)->GetMethodID (jvm_env,
985 (*jvm_env)->GetObjectClass (jvm_env, o_list),
986 "toArray", "()[Ljava/lang/Object;");
987 if (m_toarray == NULL)
988 {
989 ERROR ("java plugin: jtoc_values_array: "
990 "Cannot find method `Object[] toArray ()'.");
991 BAIL_OUT (-1);
992 }
994 o_number_array = (*jvm_env)->CallObjectMethod (jvm_env, o_list, m_toarray);
995 if (o_number_array == NULL)
996 {
997 ERROR ("java plugin: jtoc_values_array: "
998 "CallObjectMethod (toArray) failed.");
999 BAIL_OUT (-1);
1000 }
1002 values = calloc (values_num, sizeof (value_t));
1003 if (values == NULL)
1004 {
1005 ERROR ("java plugin: jtoc_values_array: calloc failed.");
1006 BAIL_OUT (-1);
1007 }
1009 for (i = 0; i < values_num; i++)
1010 {
1011 jobject o_number;
1012 int status;
1014 o_number = (*jvm_env)->GetObjectArrayElement (jvm_env,
1015 o_number_array, (jsize) i);
1016 if (o_number == NULL)
1017 {
1018 ERROR ("java plugin: jtoc_values_array: "
1019 "GetObjectArrayElement (%i) failed.", i);
1020 BAIL_OUT (-1);
1021 }
1023 status = jtoc_value (jvm_env, values + i, ds->ds[i].type, o_number);
1024 if (status != 0)
1025 {
1026 ERROR ("java plugin: jtoc_values_array: "
1027 "jtoc_value (%i) failed.", i);
1028 BAIL_OUT (-1);
1029 }
1030 } /* for (i = 0; i < values_num; i++) */
1032 vl->values = values;
1033 vl->values_len = values_num;
1035 #undef BAIL_OUT
1036 (*jvm_env)->DeleteLocalRef (jvm_env, o_number_array);
1037 (*jvm_env)->DeleteLocalRef (jvm_env, o_list);
1038 return (0);
1039 } /* }}} int jtoc_values_array */
1041 /* Convert a org.collectd.api.ValueList to a value_list_t. */
1042 static int jtoc_value_list (JNIEnv *jvm_env, value_list_t *vl, /* {{{ */
1043 jobject object_ptr)
1044 {
1045 jclass class_ptr;
1046 int status;
1047 jlong tmp_long;
1048 const data_set_t *ds;
1050 class_ptr = (*jvm_env)->GetObjectClass (jvm_env, object_ptr);
1051 if (class_ptr == NULL)
1052 {
1053 ERROR ("java plugin: jtoc_value_list: GetObjectClass failed.");
1054 return (-1);
1055 }
1057 #define SET_STRING(buffer,method) do { \
1058 status = jtoc_string (jvm_env, buffer, sizeof (buffer), \
1059 class_ptr, object_ptr, method); \
1060 if (status != 0) { \
1061 ERROR ("java plugin: jtoc_value_list: jtoc_string (%s) failed.", \
1062 method); \
1063 return (-1); \
1064 } } while (0)
1066 SET_STRING(vl->type, "getType");
1068 ds = plugin_get_ds (vl->type);
1069 if (ds == NULL)
1070 {
1071 ERROR ("java plugin: jtoc_value_list: Data-set `%s' is not defined. "
1072 "Please consult the types.db(5) manpage for mor information.",
1073 vl->type);
1074 return (-1);
1075 }
1077 SET_STRING(vl->host, "getHost");
1078 SET_STRING(vl->plugin, "getPlugin");
1079 SET_STRING(vl->plugin_instance, "getPluginInstance");
1080 SET_STRING(vl->type_instance, "getTypeInstance");
1082 #undef SET_STRING
1084 status = jtoc_long (jvm_env, &tmp_long, class_ptr, object_ptr, "getTime");
1085 if (status != 0)
1086 {
1087 ERROR ("java plugin: jtoc_value_list: jtoc_long (getTime) failed.");
1088 return (-1);
1089 }
1090 /* Java measures time in milliseconds. */
1091 vl->time = (time_t) (tmp_long / ((jlong) 1000));
1093 status = jtoc_long (jvm_env, &tmp_long,
1094 class_ptr, object_ptr, "getInterval");
1095 if (status != 0)
1096 {
1097 ERROR ("java plugin: jtoc_value_list: jtoc_long (getInterval) failed.");
1098 return (-1);
1099 }
1100 vl->interval = (int) tmp_long;
1102 status = jtoc_values_array (jvm_env, ds, vl, class_ptr, object_ptr);
1103 if (status != 0)
1104 {
1105 ERROR ("java plugin: jtoc_value_list: jtoc_values_array failed.");
1106 return (-1);
1107 }
1109 return (0);
1110 } /* }}} int jtoc_value_list */
1112 static cjni_callback_info_t *cjni_callback_info_create (JNIEnv *jvm_env, /* {{{ */
1113 jobject obj, const char *method_name, const char *signature)
1114 {
1115 cjni_callback_info_t *cbi;
1117 cbi = (cjni_callback_info_t *) malloc (sizeof (*cbi));
1118 if (cbi == NULL)
1119 {
1120 ERROR ("java plugin: cjni_callback_info_create: malloc failed.");
1121 return (NULL);
1122 }
1123 memset (cbi, 0, sizeof (*cbi));
1125 cbi->class = (*jvm_env)->GetObjectClass (jvm_env, obj);
1126 if (cbi->class == NULL)
1127 {
1128 ERROR ("java plugin: cjni_callback_info_create: GetObjectClass failed.");
1129 free (cbi);
1130 return (NULL);
1131 }
1133 cbi->object = obj;
1135 cbi->method = (*jvm_env)->GetMethodID (jvm_env, cbi->class,
1136 method_name, signature);
1137 if (cbi->method == NULL)
1138 {
1139 ERROR ("java plugin: cjni_callback_info_create: "
1140 "Cannot find the `%s' method with signature `%s'.",
1141 method_name, signature);
1142 free (cbi);
1143 return (NULL);
1144 }
1146 (*jvm_env)->NewGlobalRef (jvm_env, obj);
1148 return (cbi);
1149 } /* }}} cjni_callback_info_t cjni_callback_info_create */
1151 /*
1152 * Functions accessible from Java
1153 */
1154 static jint JNICALL cjni_api_dispatch_values (JNIEnv *jvm_env, /* {{{ */
1155 jobject this, jobject java_vl)
1156 {
1157 value_list_t vl = VALUE_LIST_INIT;
1158 int status;
1160 DEBUG ("cjni_api_dispatch_values: java_vl = %p;", (void *) java_vl);
1162 status = jtoc_value_list (jvm_env, &vl, java_vl);
1163 if (status != 0)
1164 {
1165 ERROR ("java plugin: cjni_api_dispatch_values: jtoc_value_list failed.");
1166 return (-1);
1167 }
1169 status = plugin_dispatch_values (&vl);
1171 sfree (vl.values);
1173 return (status);
1174 } /* }}} jint cjni_api_dispatch_values */
1176 static jobject JNICALL cjni_api_get_ds (JNIEnv *jvm_env, /* {{{ */
1177 jobject this, jobject o_string_type)
1178 {
1179 const char *ds_name;
1180 const data_set_t *ds;
1181 jobject o_dataset;
1183 ds_name = (*jvm_env)->GetStringUTFChars (jvm_env, o_string_type, 0);
1184 if (ds_name == NULL)
1185 {
1186 ERROR ("java plugin: cjni_api_get_ds: GetStringUTFChars failed.");
1187 return (NULL);
1188 }
1190 ds = plugin_get_ds (ds_name);
1191 DEBUG ("java plugin: cjni_api_get_ds: "
1192 "plugin_get_ds (%s) = %p;", ds_name, (void *) ds);
1194 (*jvm_env)->ReleaseStringUTFChars (jvm_env, o_string_type, ds_name);
1196 if (ds == NULL)
1197 return (NULL);
1199 o_dataset = ctoj_data_set (jvm_env, ds);
1200 return (o_dataset);
1201 } /* }}} jint cjni_api_get_ds */
1203 static jint JNICALL cjni_api_register_read (JNIEnv *jvm_env, /* {{{ */
1204 jobject this, jobject o_name, jobject o_read)
1205 {
1206 const char *c_name;
1207 user_data_t ud;
1208 cjni_callback_info_t *cbi;
1210 c_name = (*jvm_env)->GetStringUTFChars (jvm_env, o_name, 0);
1211 if (c_name == NULL)
1212 {
1213 ERROR ("java plugin: cjni_api_register_read: GetStringUTFChars failed.");
1214 return (-1);
1215 }
1217 cbi = cjni_callback_info_create (jvm_env, o_read, "Read", "()I");
1218 if (cbi == NULL)
1219 return (-1);
1221 memset (&ud, 0, sizeof (ud));
1222 ud.data = (void *) cbi;
1223 ud.free_func = cjni_callback_info_destroy;
1225 plugin_register_complex_read (c_name, cjni_read, &ud);
1227 DEBUG ("java plugin: New read callback registered: %s", c_name);
1229 (*jvm_env)->ReleaseStringUTFChars (jvm_env, o_name, c_name);
1230 (*jvm_env)->DeleteLocalRef (jvm_env, o_read);
1232 return (0);
1233 } /* }}} jint cjni_api_register_read */
1235 static jint JNICALL cjni_api_register_write (JNIEnv *jvm_env, /* {{{ */
1236 jobject this, jobject o_name, jobject o_read)
1237 {
1238 const char *c_name;
1239 user_data_t ud;
1240 cjni_callback_info_t *cbi;
1242 c_name = (*jvm_env)->GetStringUTFChars (jvm_env, o_name, 0);
1243 if (c_name == NULL)
1244 {
1245 ERROR ("java plugin: cjni_api_register_write: GetStringUTFChars failed.");
1246 return (-1);
1247 }
1249 cbi = cjni_callback_info_create (jvm_env, o_read,
1250 "Write", "(Lorg/collectd/api/ValueList;)I");
1251 if (cbi == NULL)
1252 return (-1);
1254 memset (&ud, 0, sizeof (ud));
1255 ud.data = (void *) cbi;
1256 ud.free_func = cjni_callback_info_destroy;
1258 plugin_register_write (c_name, cjni_write, &ud);
1260 DEBUG ("java plugin: New write callback registered: %s", c_name);
1262 (*jvm_env)->ReleaseStringUTFChars (jvm_env, o_name, c_name);
1263 (*jvm_env)->DeleteLocalRef (jvm_env, o_read);
1265 return (0);
1266 } /* }}} jint cjni_api_register_write */
1268 static JNINativeMethod jni_api_functions[] =
1269 {
1270 { "DispatchValues",
1271 "(Lorg/collectd/api/ValueList;)I",
1272 cjni_api_dispatch_values },
1274 { "GetDS",
1275 "(Ljava/lang/String;)Lorg/collectd/api/DataSet;",
1276 cjni_api_get_ds },
1278 { "RegisterRead",
1279 "(Ljava/lang/String;Lorg/collectd/api/CollectdReadInterface;)I",
1280 cjni_api_register_read },
1282 { "RegisterWrite",
1283 "(Ljava/lang/String;Lorg/collectd/api/CollectdWriteInterface;)I",
1284 cjni_api_register_write }
1285 };
1286 static size_t jni_api_functions_num = sizeof (jni_api_functions)
1287 / sizeof (jni_api_functions[0]);
1289 /*
1290 * Functions
1291 */
1292 static JNIEnv *cjni_thread_attach (void) /* {{{ */
1293 {
1294 cjni_jvm_env_t *cjni_env;
1295 JNIEnv *jvm_env;
1297 cjni_env = pthread_getspecific (jvm_env_key);
1298 if (cjni_env == NULL)
1299 {
1300 /* This pointer is free'd in `cjni_jvm_env_destroy'. */
1301 cjni_env = (cjni_jvm_env_t *) malloc (sizeof (*cjni_env));
1302 if (cjni_env == NULL)
1303 {
1304 ERROR ("java plugin: cjni_thread_attach: malloc failed.");
1305 return (NULL);
1306 }
1307 memset (cjni_env, 0, sizeof (*cjni_env));
1308 cjni_env->reference_counter = 0;
1309 cjni_env->jvm_env = NULL;
1311 pthread_setspecific (jvm_env_key, cjni_env);
1312 }
1314 if (cjni_env->reference_counter > 0)
1315 {
1316 cjni_env->reference_counter++;
1317 jvm_env = cjni_env->jvm_env;
1318 }
1319 else
1320 {
1321 int status;
1322 JavaVMAttachArgs args;
1324 assert (cjni_env->jvm_env == NULL);
1326 memset (&args, 0, sizeof (args));
1327 args.version = JNI_VERSION_1_2;
1329 status = (*jvm)->AttachCurrentThread (jvm, (void *) &jvm_env, (void *) &args);
1330 if (status != 0)
1331 {
1332 ERROR ("java plugin: cjni_thread_attach: AttachCurrentThread failed "
1333 "with status %i.", status);
1334 return (NULL);
1335 }
1337 cjni_env->reference_counter = 1;
1338 cjni_env->jvm_env = jvm_env;
1339 }
1341 DEBUG ("java plugin: cjni_thread_attach: cjni_env->reference_counter = %i",
1342 cjni_env->reference_counter);
1343 assert (jvm_env != NULL);
1344 return (jvm_env);
1345 } /* }}} JNIEnv *cjni_thread_attach */
1347 static int cjni_thread_detach (void) /* {{{ */
1348 {
1349 cjni_jvm_env_t *cjni_env;
1350 int status;
1352 cjni_env = pthread_getspecific (jvm_env_key);
1353 if (cjni_env == NULL)
1354 {
1355 ERROR ("java plugin: cjni_thread_detach: pthread_getspecific failed.");
1356 return (-1);
1357 }
1359 assert (cjni_env->reference_counter > 0);
1360 assert (cjni_env->jvm_env != NULL);
1362 cjni_env->reference_counter--;
1363 DEBUG ("java plugin: cjni_thread_detach: cjni_env->reference_counter = %i",
1364 cjni_env->reference_counter);
1366 if (cjni_env->reference_counter > 0)
1367 return (0);
1369 status = (*jvm)->DetachCurrentThread (jvm);
1370 if (status != 0)
1371 {
1372 ERROR ("java plugin: cjni_thread_detach: DetachCurrentThread failed "
1373 "with status %i.", status);
1374 }
1376 cjni_env->reference_counter = 0;
1377 cjni_env->jvm_env = NULL;
1379 return (0);
1380 } /* }}} JNIEnv *cjni_thread_attach */
1382 static void cjni_jvm_env_destroy (void *args) /* {{{ */
1383 {
1384 cjni_jvm_env_t *cjni_env;
1386 if (args == NULL)
1387 return;
1389 cjni_env = (cjni_jvm_env_t *) args;
1391 if (cjni_env->reference_counter > 0)
1392 {
1393 ERROR ("java plugin: cjni_jvm_env_destroy: "
1394 "cjni_env->reference_counter = %i;", cjni_env->reference_counter);
1395 }
1397 if (cjni_env->jvm_env != NULL)
1398 {
1399 ERROR ("java plugin: cjni_jvm_env_destroy: cjni_env->jvm_env = %p;",
1400 (void *) cjni_env->jvm_env);
1401 }
1403 /* The pointer is allocated in `cjni_thread_attach' */
1404 free (cjni_env);
1405 } /* }}} void cjni_jvm_env_destroy */
1407 /*
1408 * Delete a global reference, set by the various `Register*' functions.
1409 */
1410 static void cjni_callback_info_destroy (void *arg) /* {{{ */
1411 {
1412 JNIEnv *jni_env;
1413 cjni_callback_info_t *cbi;
1415 DEBUG ("java plugin: cjni_callback_info_destroy (arg = %p);", arg);
1417 if (arg == NULL)
1418 return;
1420 jni_env = cjni_thread_attach ();
1421 if (jni_env == NULL)
1422 {
1423 ERROR ("java plugin: cjni_callback_info_destroy: cjni_thread_attach failed.");
1424 return;
1425 }
1427 cbi = (cjni_callback_info_t *) arg;
1429 (*jni_env)->DeleteGlobalRef (jni_env, cbi->object);
1431 cbi->method = NULL;
1432 cbi->object = NULL;
1433 cbi->class = NULL;
1434 free (cbi);
1436 cjni_thread_detach ();
1437 } /* }}} void cjni_callback_info_destroy */
1439 static int cjni_config_add_jvm_arg (oconfig_item_t *ci) /* {{{ */
1440 {
1441 char **tmp;
1443 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
1444 {
1445 WARNING ("java plugin: `JVMArg' needs exactly one string argument.");
1446 return (-1);
1447 }
1449 tmp = (char **) realloc (jvm_argv, sizeof (char *) * (jvm_argc + 1));
1450 if (tmp == NULL)
1451 {
1452 ERROR ("java plugin: realloc failed.");
1453 return (-1);
1454 }
1455 jvm_argv = tmp;
1457 jvm_argv[jvm_argc] = strdup (ci->values[0].value.string);
1458 if (jvm_argv[jvm_argc] == NULL)
1459 {
1460 ERROR ("java plugin: strdup failed.");
1461 return (-1);
1462 }
1463 jvm_argc++;
1465 return (0);
1466 } /* }}} int cjni_config_add_jvm_arg */
1468 static int cjni_config_load_plugin (oconfig_item_t *ci) /* {{{ */
1469 {
1470 java_plugin_t *jp;
1472 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
1473 {
1474 WARNING ("java plugin: `LoadPlugin' needs exactly one string argument.");
1475 return (-1);
1476 }
1478 jp = (java_plugin_t *) realloc (java_plugins,
1479 sizeof (*java_plugins) * (java_plugins_num + 1));
1480 if (jp == NULL)
1481 {
1482 ERROR ("java plugin: realloc failed.");
1483 return (-1);
1484 }
1485 java_plugins = jp;
1486 jp = java_plugins + java_plugins_num;
1488 memset (jp, 0, sizeof (*jp));
1489 jp->class_name = strdup (ci->values[0].value.string);
1490 if (jp->class_name == NULL)
1491 {
1492 ERROR ("java plugin: strdup failed.");
1493 return (-1);
1494 }
1496 jp->class_ptr = NULL;
1497 jp->object_ptr = NULL;
1498 jp->ci = NULL;
1499 jp->flags = 0;
1500 jp->m_config = NULL;
1501 jp->m_init = NULL;
1502 jp->m_shutdown = NULL;
1504 java_plugins_num++;
1506 return (0);
1507 } /* }}} int cjni_config_load_plugin */
1509 static int cjni_config_plugin_block (oconfig_item_t *ci) /* {{{ */
1510 {
1511 size_t i;
1512 const char *class_name;
1514 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
1515 {
1516 WARNING ("java plugin: `Plugin' blocks "
1517 "need exactly one string argument.");
1518 return (-1);
1519 }
1521 class_name = ci->values[0].value.string;
1522 for (i = 0; i < java_plugins_num; i++)
1523 if (strcmp (java_plugins[i].class_name, class_name) == 0)
1524 break;
1526 if (i >= java_plugins_num)
1527 {
1528 WARNING ("java plugin: Configuration block for the `%s' plugin found, "
1529 "but the plugin has not been loaded. Please note, that the class "
1530 "name is case-sensitive!",
1531 class_name);
1532 return (0);
1533 }
1535 if (java_plugins[i].ci != NULL)
1536 {
1537 WARNING ("java plugin: There are more than one <Plugin> blocks for the "
1538 "`%s' plugin. This is currently not supported - only the first block "
1539 "will be used!",
1540 class_name);
1541 return (0);
1542 }
1544 java_plugins[i].ci = oconfig_clone (ci);
1545 if (java_plugins[i].ci == NULL)
1546 {
1547 ERROR ("java plugin: cjni_config_plugin_block: "
1548 "oconfig_clone failed for `%s'.",
1549 class_name);
1550 return (-1);
1551 }
1553 DEBUG ("java plugin: cjni_config_plugin_block: "
1554 "Successfully copied config for `%s'.",
1555 class_name);
1557 return (0);
1558 } /* }}} int cjni_config_plugin_block */
1560 static int cjni_config (oconfig_item_t *ci) /* {{{ */
1561 {
1562 int success;
1563 int errors;
1564 int status;
1565 int i;
1567 success = 0;
1568 errors = 0;
1570 for (i = 0; i < ci->children_num; i++)
1571 {
1572 oconfig_item_t *child = ci->children + i;
1574 if (strcasecmp ("JVMArg", child->key) == 0)
1575 {
1576 status = cjni_config_add_jvm_arg (child);
1577 if (status == 0)
1578 success++;
1579 else
1580 errors++;
1581 }
1582 else if (strcasecmp ("LoadPlugin", child->key) == 0)
1583 {
1584 status = cjni_config_load_plugin (child);
1585 if (status == 0)
1586 success++;
1587 else
1588 errors++;
1589 }
1590 else if (strcasecmp ("Plugin", child->key) == 0)
1591 {
1592 status = cjni_config_plugin_block (child);
1593 if (status == 0)
1594 success++;
1595 else
1596 errors++;
1597 }
1598 else
1599 {
1600 WARNING ("java plugin: Option `%s' not allowed here.", child->key);
1601 errors++;
1602 }
1603 }
1605 if ((success == 0) && (errors > 0))
1606 {
1607 ERROR ("java plugin: All statements failed.");
1608 return (-1);
1609 }
1611 return (0);
1612 } /* }}} int cjni_config */
1614 static int cjni_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */
1615 user_data_t *ud)
1616 {
1617 JNIEnv *jvm_env;
1618 cjni_callback_info_t *cbi;
1619 jobject vl_java;
1620 int status;
1622 if (jvm == NULL)
1623 {
1624 ERROR ("java plugin: cjni_write: jvm == NULL");
1625 return (-1);
1626 }
1628 if ((ud == NULL) || (ud->data == NULL))
1629 {
1630 ERROR ("java plugin: cjni_write: Invalid user data.");
1631 return (-1);
1632 }
1634 jvm_env = cjni_thread_attach ();
1635 if (jvm_env == NULL)
1636 return (-1);
1638 cbi = (cjni_callback_info_t *) ud->data;
1640 vl_java = ctoj_value_list (jvm_env, ds, vl);
1641 if (vl_java == NULL)
1642 {
1643 ERROR ("java plugin: cjni_write: ctoj_value_list failed.");
1644 return (-1);
1645 }
1647 status = (*jvm_env)->CallIntMethod (jvm_env,
1648 cbi->object, cbi->method, vl_java);
1650 (*jvm_env)->DeleteLocalRef (jvm_env, vl_java);
1652 status = cjni_thread_detach ();
1653 if (status != 0)
1654 {
1655 ERROR ("java plugin: cjni_write: cjni_thread_detach failed.");
1656 return (-1);
1657 }
1659 return (status);
1660 } /* }}} int cjni_write */
1662 static int cjni_shutdown_one_plugin (JNIEnv *jvm_env, /* {{{ */
1663 java_plugin_t *jp)
1664 {
1665 int status;
1667 if ((jp == NULL)
1668 || ((jp->flags & CJNI_FLAG_ENABLED) == 0)
1669 || (jp->m_shutdown == NULL))
1670 return (0);
1672 status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
1673 jp->m_shutdown);
1674 if (status != 0)
1675 {
1676 ERROR ("cjni_shutdown_one_plugin: Destroying an `%s' object failed "
1677 "with status %i.", jp->class_name, status);
1678 return (-1);
1679 }
1680 jp->flags &= ~CJNI_FLAG_ENABLED;
1682 return (0);
1683 } /* }}} int cjni_shutdown_one_plugin */
1685 static int cjni_shutdown_plugins (JNIEnv *jvm_env) /* {{{ */
1686 {
1687 size_t j;
1689 for (j = 0; j < java_plugins_num; j++)
1690 cjni_shutdown_one_plugin (jvm_env, &java_plugins[j]);
1692 return (0);
1693 } /* }}} int cjni_shutdown_plugins */
1695 static int cjni_shutdown (void) /* {{{ */
1696 {
1697 JNIEnv *jvm_env;
1698 JavaVMAttachArgs args;
1699 int status;
1700 size_t i;
1702 if (jvm == NULL)
1703 return (0);
1705 jvm_env = NULL;
1706 memset (&args, 0, sizeof (args));
1707 args.version = JNI_VERSION_1_2;
1709 status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args);
1710 if (status != 0)
1711 {
1712 ERROR ("java plugin: cjni_shutdown: AttachCurrentThread failed with status %i.",
1713 status);
1714 return (-1);
1715 }
1717 cjni_shutdown_plugins (jvm_env);
1719 (*jvm)->DestroyJavaVM (jvm);
1720 jvm = NULL;
1721 jvm_env = NULL;
1723 pthread_key_delete (jvm_env_key);
1725 for (i = 0; i < jvm_argc; i++)
1726 {
1727 sfree (jvm_argv[i]);
1728 }
1729 sfree (jvm_argv);
1730 jvm_argc = 0;
1732 for (i = 0; i < java_plugins_num; i++)
1733 {
1734 sfree (java_plugins[i].class_name);
1735 oconfig_free (java_plugins[i].ci);
1736 }
1737 sfree (java_plugins);
1738 java_plugins_num = 0;
1740 return (0);
1741 } /* }}} int cjni_shutdown */
1743 static int cjni_read (user_data_t *ud) /* {{{ */
1744 {
1745 JNIEnv *jvm_env;
1746 cjni_callback_info_t *cbi;
1747 int status;
1749 if (jvm == NULL)
1750 {
1751 ERROR ("java plugin: cjni_read: jvm == NULL");
1752 return (-1);
1753 }
1755 if ((ud == NULL) || (ud->data == NULL))
1756 {
1757 ERROR ("java plugin: cjni_read: Invalid user data.");
1758 return (-1);
1759 }
1761 jvm_env = cjni_thread_attach ();
1762 if (jvm_env == NULL)
1763 return (-1);
1765 cbi = (cjni_callback_info_t *) ud->data;
1767 status = (*jvm_env)->CallIntMethod (jvm_env, cbi->object,
1768 cbi->method);
1770 status = cjni_thread_detach ();
1771 if (status != 0)
1772 {
1773 ERROR ("java plugin: cjni_read: cjni_thread_detach failed.");
1774 return (-1);
1775 }
1777 return (status);
1778 } /* }}} int cjni_read */
1780 static int cjni_init_one_plugin (JNIEnv *jvm_env, java_plugin_t *jp) /* {{{ */
1781 {
1782 jmethodID constructor_id;
1783 int status;
1785 jp->class_ptr = (*jvm_env)->FindClass (jvm_env, jp->class_name);
1786 if (jp->class_ptr == NULL)
1787 {
1788 ERROR ("cjni_init_one_plugin: FindClass (%s) failed.",
1789 jp->class_name);
1790 return (-1);
1791 }
1793 constructor_id = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1794 "<init>", "()V");
1795 if (constructor_id == NULL)
1796 {
1797 ERROR ("cjni_init_one_plugin: Could not find the constructor for `%s'.",
1798 jp->class_name);
1799 return (-1);
1800 }
1802 jp->object_ptr = (*jvm_env)->NewObject (jvm_env, jp->class_ptr,
1803 constructor_id);
1804 if (jp->object_ptr == NULL)
1805 {
1806 ERROR ("cjni_init_one_plugin: Could create a new `%s' object.",
1807 jp->class_name);
1808 return (-1);
1809 }
1811 jp->m_config = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1812 "Config", "(Lorg/collectd/api/OConfigItem;)I");
1813 DEBUG ("java plugin: cjni_init_one_plugin: "
1814 "jp->class_name = %s; jp->m_config = %p;",
1815 jp->class_name, (void *) jp->m_config);
1817 jp->m_init = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1818 "Init", "()I");
1819 DEBUG ("java plugin: cjni_init_one_plugin: "
1820 "jp->class_name = %s; jp->m_init = %p;",
1821 jp->class_name, (void *) jp->m_init);
1823 jp->m_shutdown = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1824 "Shutdown", "()I");
1825 DEBUG ("java plugin: cjni_init_one_plugin: "
1826 "jp->class_name = %s; jp->m_shutdown = %p;",
1827 jp->class_name, (void *) jp->m_shutdown);
1829 if (jp->ci != NULL)
1830 {
1831 if (jp->m_config == NULL)
1832 {
1833 WARNING ("java plugin: Configuration for the `%s' plugin is present, "
1834 "but plugin doesn't provide a configuration method.",
1835 jp->class_name);
1836 }
1837 else /* if (jp->m_config != NULL) */
1838 {
1839 jobject o_ocitem;
1841 o_ocitem = ctoj_oconfig_item (jvm_env, jp->ci);
1842 if (o_ocitem == NULL)
1843 {
1844 ERROR ("java plugin: Creating an OConfigItem object failed. "
1845 "Can't pass configuration information to the `%s' plugin!",
1846 jp->class_name);
1847 }
1848 else /* if (o_ocitem != NULL) */
1849 {
1850 status = (*jvm_env)->CallIntMethod (jvm_env,
1851 jp->object_ptr, jp->m_config, o_ocitem);
1852 if (status != 0)
1853 {
1854 ERROR ("java plugin: cjni_init_one_plugin: "
1855 "Configuring the `%s' object failed with status %i.",
1856 jp->class_name, status);
1857 (*jvm_env)->DeleteLocalRef (jvm_env, o_ocitem);
1858 return (-1);
1859 }
1860 (*jvm_env)->DeleteLocalRef (jvm_env, o_ocitem);
1861 } /* if (o_ocitem != NULL) */
1862 } /* if (jp->m_config != NULL) */
1863 } /* if (jp->ci != NULL) */
1865 if (jp->m_init != NULL)
1866 {
1867 status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
1868 jp->m_init);
1869 if (status != 0)
1870 {
1871 ERROR ("java plugin: cjni_init_one_plugin: "
1872 "Initializing `%s' object failed with status %i.",
1873 jp->class_name, status);
1874 return (-1);
1875 }
1876 }
1877 jp->flags |= CJNI_FLAG_ENABLED;
1879 return (0);
1880 } /* }}} int cjni_init_one_plugin */
1882 static int cjni_init_plugins (JNIEnv *jvm_env) /* {{{ */
1883 {
1884 int have_shutdown;
1885 size_t j;
1887 have_shutdown = 0;
1889 for (j = 0; j < java_plugins_num; j++)
1890 {
1891 cjni_init_one_plugin (jvm_env, &java_plugins[j]);
1893 if (java_plugins[j].m_shutdown != NULL)
1894 have_shutdown++;
1895 }
1897 if (have_shutdown > 0)
1898 plugin_register_shutdown ("java", cjni_shutdown);
1900 return (0);
1901 } /* }}} int cjni_init_plugins */
1903 static int cjni_init_native (JNIEnv *jvm_env) /* {{{ */
1904 {
1905 jclass api_class_ptr;
1906 int status;
1908 api_class_ptr = (*jvm_env)->FindClass (jvm_env, "org.collectd.api.CollectdAPI");
1909 if (api_class_ptr == NULL)
1910 {
1911 ERROR ("cjni_init_native: Cannot find API class `org.collectd.api.CollectdAPI'.");
1912 return (-1);
1913 }
1915 status = (*jvm_env)->RegisterNatives (jvm_env, api_class_ptr,
1916 jni_api_functions, (jint) jni_api_functions_num);
1917 if (status != 0)
1918 {
1919 ERROR ("cjni_init_native: RegisterNatives failed with status %i.", status);
1920 return (-1);
1921 }
1923 return (0);
1924 } /* }}} int cjni_init_native */
1926 static int cjni_init (void) /* {{{ */
1927 {
1928 JNIEnv *jvm_env;
1929 JavaVMInitArgs vm_args;
1930 JavaVMOption vm_options[jvm_argc];
1932 int status;
1933 size_t i;
1935 if (jvm != NULL)
1936 return (0);
1938 status = pthread_key_create (&jvm_env_key, cjni_jvm_env_destroy);
1939 if (status != 0)
1940 {
1941 ERROR ("java plugin: cjni_init: pthread_key_create failed "
1942 "with status %i.", status);
1943 return (-1);
1944 }
1946 jvm_env = NULL;
1948 memset (&vm_args, 0, sizeof (vm_args));
1949 vm_args.version = JNI_VERSION_1_2;
1950 vm_args.options = vm_options;
1951 vm_args.nOptions = (jint) jvm_argc;
1953 for (i = 0; i < jvm_argc; i++)
1954 {
1955 DEBUG ("java plugin: cjni_init: jvm_argv[%zu] = %s", i, jvm_argv[i]);
1956 vm_args.options[i].optionString = jvm_argv[i];
1957 }
1958 /*
1959 vm_args.options[0].optionString = "-verbose:jni";
1960 vm_args.options[1].optionString = "-Djava.class.path=/home/octo/collectd/bindings/java";
1961 */
1963 status = JNI_CreateJavaVM (&jvm, (void **) &jvm_env, (void **) &vm_args);
1964 if (status != 0)
1965 {
1966 ERROR ("cjni_init: JNI_CreateJavaVM failed with status %i.",
1967 status);
1968 return (-1);
1969 }
1970 assert (jvm != NULL);
1971 assert (jvm_env != NULL);
1973 /* Call RegisterNatives */
1974 status = cjni_init_native (jvm_env);
1975 if (status != 0)
1976 {
1977 ERROR ("cjni_init: cjni_init_native failed.");
1978 return (-1);
1979 }
1981 cjni_init_plugins (jvm_env);
1983 return (0);
1984 } /* }}} int cjni_init */
1986 void module_register (void)
1987 {
1988 plugin_register_complex_config ("java", cjni_config);
1989 plugin_register_init ("java", cjni_init);
1990 } /* void module_register (void) */
1992 /* vim: set sw=2 sts=2 et fdm=marker : */