6b0c2e1798816a90f0ef7613d46feb71800dc14d
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_read;
52 jmethodID m_write;
53 jmethodID m_shutdown;
54 };
55 typedef struct java_plugin_s java_plugin_t;
56 /* }}} */
58 struct cjni_jvm_env_s /* {{{ */
59 {
60 JNIEnv *jvm_env;
61 int reference_counter;
62 };
63 typedef struct cjni_jvm_env_s cjni_jvm_env_t;
64 /* }}} */
66 /*
67 * Global variables
68 */
69 static JavaVM *jvm = NULL;
70 static pthread_key_t jvm_env_key;
72 static char **jvm_argv = NULL;
73 static size_t jvm_argc = 0;
75 static java_plugin_t *java_plugins = NULL;
76 static size_t java_plugins_num = 0;
78 /*
79 * C to Java conversion functions
80 */
81 static int ctoj_string (JNIEnv *jvm_env, /* {{{ */
82 const char *string,
83 jclass class_ptr, jobject object_ptr, const char *method_name)
84 {
85 jmethodID m_set;
86 jstring o_string;
88 /* Create a java.lang.String */
89 o_string = (*jvm_env)->NewStringUTF (jvm_env,
90 (string != NULL) ? string : "");
91 if (o_string == NULL)
92 {
93 ERROR ("java plugin: ctoj_string: NewStringUTF failed.");
94 return (-1);
95 }
97 /* Search for the `void setFoo (String s)' method. */
98 m_set = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
99 method_name, "(Ljava/lang/String;)V");
100 if (m_set == NULL)
101 {
102 ERROR ("java plugin: ctoj_string: Cannot find method `void %s (String)'.",
103 method_name);
104 (*jvm_env)->DeleteLocalRef (jvm_env, o_string);
105 return (-1);
106 }
108 /* Call the method. */
109 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, o_string);
111 /* Decrease reference counter on the java.lang.String object. */
112 (*jvm_env)->DeleteLocalRef (jvm_env, o_string);
114 DEBUG ("java plugin: ctoj_string: ->%s (%s);",
115 method_name, (string != NULL) ? string : "");
117 return (0);
118 } /* }}} int ctoj_string */
120 static int ctoj_int (JNIEnv *jvm_env, /* {{{ */
121 jint value,
122 jclass class_ptr, jobject object_ptr, const char *method_name)
123 {
124 jmethodID m_set;
126 /* Search for the `void setFoo (int i)' method. */
127 m_set = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
128 method_name, "(I)V");
129 if (m_set == NULL)
130 {
131 ERROR ("java plugin: ctoj_int: Cannot find method `void %s (int)'.",
132 method_name);
133 return (-1);
134 }
136 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, value);
138 DEBUG ("java plugin: ctoj_int: ->%s (%i);",
139 method_name, (int) value);
141 return (0);
142 } /* }}} int ctoj_int */
144 static int ctoj_long (JNIEnv *jvm_env, /* {{{ */
145 jlong value,
146 jclass class_ptr, jobject object_ptr, const char *method_name)
147 {
148 jmethodID m_set;
150 /* Search for the `void setFoo (long l)' method. */
151 m_set = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
152 method_name, "(J)V");
153 if (m_set == NULL)
154 {
155 ERROR ("java plugin: ctoj_long: Cannot find method `void %s (long)'.",
156 method_name);
157 return (-1);
158 }
160 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, value);
162 DEBUG ("java plugin: ctoj_long: ->%s (%"PRIi64");",
163 method_name, (int64_t) value);
165 return (0);
166 } /* }}} int ctoj_long */
168 static int ctoj_double (JNIEnv *jvm_env, /* {{{ */
169 jdouble value,
170 jclass class_ptr, jobject object_ptr, const char *method_name)
171 {
172 jmethodID m_set;
174 /* Search for the `void setFoo (double d)' method. */
175 m_set = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
176 method_name, "(D)V");
177 if (m_set == NULL)
178 {
179 ERROR ("java plugin: ctoj_double: Cannot find method `void %s (double)'.",
180 method_name);
181 return (-1);
182 }
184 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, value);
186 DEBUG ("java plugin: ctoj_double: ->%s (%g);",
187 method_name, (double) value);
189 return (0);
190 } /* }}} int ctoj_double */
192 /* Convert a jlong to a java.lang.Number */
193 static jobject ctoj_jlong_to_number (JNIEnv *jvm_env, jlong value) /* {{{ */
194 {
195 jclass c_long;
196 jmethodID m_long_constructor;
198 /* Look up the java.lang.Long class */
199 c_long = (*jvm_env)->FindClass (jvm_env, "java.lang.Long");
200 if (c_long == NULL)
201 {
202 ERROR ("java plugin: ctoj_jlong_to_number: Looking up the "
203 "java.lang.Long class failed.");
204 return (NULL);
205 }
207 m_long_constructor = (*jvm_env)->GetMethodID (jvm_env,
208 c_long, "<init>", "(J)V");
209 if (m_long_constructor == NULL)
210 {
211 ERROR ("java plugin: ctoj_jlong_to_number: Looking up the "
212 "`Long (long)' constructor failed.");
213 return (NULL);
214 }
216 return ((*jvm_env)->NewObject (jvm_env,
217 c_long, m_long_constructor, value));
218 } /* }}} jobject ctoj_jlong_to_number */
220 /* Convert a jdouble to a java.lang.Number */
221 static jobject ctoj_jdouble_to_number (JNIEnv *jvm_env, jdouble value) /* {{{ */
222 {
223 jclass c_double;
224 jmethodID m_double_constructor;
226 /* Look up the java.lang.Long class */
227 c_double = (*jvm_env)->FindClass (jvm_env, "java.lang.Double");
228 if (c_double == NULL)
229 {
230 ERROR ("java plugin: ctoj_jdouble_to_number: Looking up the "
231 "java.lang.Double class failed.");
232 return (NULL);
233 }
235 m_double_constructor = (*jvm_env)->GetMethodID (jvm_env,
236 c_double, "<init>", "(D)V");
237 if (m_double_constructor == NULL)
238 {
239 ERROR ("java plugin: ctoj_jdouble_to_number: Looking up the "
240 "`Double (double)' constructor failed.");
241 return (NULL);
242 }
244 return ((*jvm_env)->NewObject (jvm_env,
245 c_double, m_double_constructor, value));
246 } /* }}} jobject ctoj_jdouble_to_number */
248 /* Convert a value_t to a java.lang.Number */
249 static jobject ctoj_value_to_number (JNIEnv *jvm_env, /* {{{ */
250 value_t value, int ds_type)
251 {
252 if (ds_type == DS_TYPE_COUNTER)
253 return (ctoj_jlong_to_number (jvm_env, (jlong) value.counter));
254 else if (ds_type == DS_TYPE_GAUGE)
255 return (ctoj_jdouble_to_number (jvm_env, (jdouble) value.gauge));
256 else
257 return (NULL);
258 } /* }}} jobject ctoj_value_to_number */
260 /* Convert a data_source_t to a org.collectd.protocol.DataSource */
261 static jobject ctoj_data_source (JNIEnv *jvm_env, /* {{{ */
262 const data_source_t *dsrc)
263 {
264 jclass c_datasource;
265 jmethodID m_datasource_constructor;
266 jobject o_datasource;
267 int status;
269 /* Look up the DataSource class */
270 c_datasource = (*jvm_env)->FindClass (jvm_env,
271 "org.collectd.protocol.DataSource");
272 if (c_datasource == NULL)
273 {
274 ERROR ("java plugin: ctoj_data_source: "
275 "FindClass (org.collectd.protocol.DataSource) failed.");
276 return (NULL);
277 }
279 /* Lookup the `ValueList ()' constructor. */
280 m_datasource_constructor = (*jvm_env)->GetMethodID (jvm_env, c_datasource,
281 "<init>", "()V");
282 if (m_datasource_constructor == NULL)
283 {
284 ERROR ("java plugin: ctoj_data_source: Cannot find the "
285 "`DataSource ()' constructor.");
286 return (NULL);
287 }
289 /* Create a new instance. */
290 o_datasource = (*jvm_env)->NewObject (jvm_env, c_datasource,
291 m_datasource_constructor);
292 if (o_datasource == NULL)
293 {
294 ERROR ("java plugin: ctoj_data_source: "
295 "Creating a new DataSource instance failed.");
296 return (NULL);
297 }
299 /* Set name via `void setName (String name)' */
300 status = ctoj_string (jvm_env, dsrc->name,
301 c_datasource, o_datasource, "setName");
302 if (status != 0)
303 {
304 ERROR ("java plugin: ctoj_data_source: "
305 "ctoj_string (setName) failed.");
306 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
307 return (NULL);
308 }
310 /* Set type via `void setType (int type)' */
311 status = ctoj_int (jvm_env, dsrc->type,
312 c_datasource, o_datasource, "setType");
313 if (status != 0)
314 {
315 ERROR ("java plugin: ctoj_data_source: "
316 "ctoj_int (setType) failed.");
317 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
318 return (NULL);
319 }
321 /* Set min via `void setMin (double min)' */
322 status = ctoj_double (jvm_env, dsrc->min,
323 c_datasource, o_datasource, "setMin");
324 if (status != 0)
325 {
326 ERROR ("java plugin: ctoj_data_source: "
327 "ctoj_double (setMin) failed.");
328 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
329 return (NULL);
330 }
332 /* Set max via `void setMax (double max)' */
333 status = ctoj_double (jvm_env, dsrc->max,
334 c_datasource, o_datasource, "setMax");
335 if (status != 0)
336 {
337 ERROR ("java plugin: ctoj_data_source: "
338 "ctoj_double (setMax) failed.");
339 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
340 return (NULL);
341 }
343 return (o_datasource);
344 } /* }}} jobject ctoj_data_source */
346 /* Convert a oconfig_value_t to a org.collectd.api.OConfigValue */
347 static jobject ctoj_oconfig_value (JNIEnv *jvm_env, /* {{{ */
348 oconfig_value_t ocvalue)
349 {
350 jclass c_ocvalue;
351 jmethodID m_ocvalue_constructor;
352 jobject o_argument;
353 jobject o_ocvalue;
355 m_ocvalue_constructor = NULL;
356 o_argument = NULL;
358 c_ocvalue = (*jvm_env)->FindClass (jvm_env,
359 "org.collectd.api.OConfigValue");
360 if (c_ocvalue == NULL)
361 {
362 ERROR ("java plugin: ctoj_oconfig_value: "
363 "FindClass (org.collectd.api.OConfigValue) failed.");
364 return (NULL);
365 }
367 if (ocvalue.type == OCONFIG_TYPE_BOOLEAN)
368 {
369 jboolean tmp_boolean;
371 tmp_boolean = (ocvalue.value.boolean == 0) ? JNI_FALSE : JNI_TRUE;
373 m_ocvalue_constructor = (*jvm_env)->GetMethodID (jvm_env, c_ocvalue,
374 "<init>", "(Z)V");
375 if (m_ocvalue_constructor == NULL)
376 {
377 ERROR ("java plugin: ctoj_oconfig_value: Cannot find the "
378 "`OConfigValue (boolean)' constructor.");
379 return (NULL);
380 }
382 return ((*jvm_env)->NewObject (jvm_env,
383 c_ocvalue, m_ocvalue_constructor, tmp_boolean));
384 } /* if (ocvalue.type == OCONFIG_TYPE_BOOLEAN) */
385 else if (ocvalue.type == OCONFIG_TYPE_STRING)
386 {
387 m_ocvalue_constructor = (*jvm_env)->GetMethodID (jvm_env, c_ocvalue,
388 "<init>", "(Ljava/lang/String;)V");
389 if (m_ocvalue_constructor == NULL)
390 {
391 ERROR ("java plugin: ctoj_oconfig_value: Cannot find the "
392 "`OConfigValue (String)' constructor.");
393 return (NULL);
394 }
396 o_argument = (*jvm_env)->NewStringUTF (jvm_env, ocvalue.value.string);
397 if (o_argument == NULL)
398 {
399 ERROR ("java plugin: ctoj_oconfig_value: "
400 "Creating a String object failed.");
401 return (NULL);
402 }
403 }
404 else if (ocvalue.type == OCONFIG_TYPE_NUMBER)
405 {
406 m_ocvalue_constructor = (*jvm_env)->GetMethodID (jvm_env, c_ocvalue,
407 "<init>", "(Ljava/lang/Number;)V");
408 if (m_ocvalue_constructor == NULL)
409 {
410 ERROR ("java plugin: ctoj_oconfig_value: Cannot find the "
411 "`OConfigValue (Number)' constructor.");
412 return (NULL);
413 }
415 o_argument = ctoj_jdouble_to_number (jvm_env,
416 (jdouble) ocvalue.value.number);
417 if (o_argument == NULL)
418 {
419 ERROR ("java plugin: ctoj_oconfig_value: "
420 "Creating a Number object failed.");
421 return (NULL);
422 }
423 }
424 else
425 {
426 return (NULL);
427 }
429 assert (m_ocvalue_constructor != NULL);
430 assert (o_argument != NULL);
432 o_ocvalue = (*jvm_env)->NewObject (jvm_env,
433 c_ocvalue, m_ocvalue_constructor, o_argument);
434 if (o_ocvalue == NULL)
435 {
436 ERROR ("java plugin: ctoj_oconfig_value: "
437 "Creating an OConfigValue object failed.");
438 (*jvm_env)->DeleteLocalRef (jvm_env, o_argument);
439 return (NULL);
440 }
442 (*jvm_env)->DeleteLocalRef (jvm_env, o_argument);
443 return (o_ocvalue);
444 } /* }}} jobject ctoj_oconfig_value */
446 /* Convert a oconfig_item_t to a org.collectd.api.OConfigItem */
447 static jobject ctoj_oconfig_item (JNIEnv *jvm_env, /* {{{ */
448 const oconfig_item_t *ci)
449 {
450 jclass c_ocitem;
451 jmethodID m_ocitem_constructor;
452 jmethodID m_addvalue;
453 jmethodID m_addchild;
454 jobject o_key;
455 jobject o_ocitem;
456 int i;
458 c_ocitem = (*jvm_env)->FindClass (jvm_env, "org.collectd.api.OConfigItem");
459 if (c_ocitem == NULL)
460 {
461 ERROR ("java plugin: ctoj_oconfig_item: "
462 "FindClass (org.collectd.api.OConfigItem) failed.");
463 return (NULL);
464 }
466 /* Get the required methods: m_ocitem_constructor, m_addvalue, and m_addchild
467 * {{{ */
468 m_ocitem_constructor = (*jvm_env)->GetMethodID (jvm_env, c_ocitem,
469 "<init>", "(Ljava/lang/String;)V");
470 if (m_ocitem_constructor == NULL)
471 {
472 ERROR ("java plugin: ctoj_oconfig_item: Cannot find the "
473 "`OConfigItem (String)' constructor.");
474 return (NULL);
475 }
477 m_addvalue = (*jvm_env)->GetMethodID (jvm_env, c_ocitem,
478 "addValue", "(Lorg/collectd/api/OConfigValue;)V");
479 if (m_addvalue == NULL)
480 {
481 ERROR ("java plugin: ctoj_oconfig_item: Cannot find the "
482 "`addValue (OConfigValue)' method.");
483 return (NULL);
484 }
486 m_addchild = (*jvm_env)->GetMethodID (jvm_env, c_ocitem,
487 "addChild", "(Lorg/collectd/api/OConfigItem;)V");
488 if (m_addchild == NULL)
489 {
490 ERROR ("java plugin: ctoj_oconfig_item: Cannot find the "
491 "`addChild (OConfigItem)' method.");
492 return (NULL);
493 }
494 /* }}} */
496 /* Create a String object with the key.
497 * Needed for calling the constructor. */
498 o_key = (*jvm_env)->NewStringUTF (jvm_env, ci->key);
499 if (o_key == NULL)
500 {
501 ERROR ("java plugin: ctoj_oconfig_item: "
502 "Creating String object failed.");
503 return (NULL);
504 }
506 /* Create an OConfigItem object */
507 o_ocitem = (*jvm_env)->NewObject (jvm_env,
508 c_ocitem, m_ocitem_constructor, o_key);
509 if (o_ocitem == NULL)
510 {
511 ERROR ("java plugin: ctoj_oconfig_item: "
512 "Creating an OConfigItem object failed.");
513 (*jvm_env)->DeleteLocalRef (jvm_env, o_key);
514 return (NULL);
515 }
517 /* We don't need the String object any longer.. */
518 (*jvm_env)->DeleteLocalRef (jvm_env, o_key);
520 /* Call OConfigItem.addValue for each value */
521 for (i = 0; i < ci->values_num; i++) /* {{{ */
522 {
523 jobject o_value;
525 o_value = ctoj_oconfig_value (jvm_env, ci->values[i]);
526 if (o_value == NULL)
527 {
528 ERROR ("java plugin: ctoj_oconfig_item: "
529 "Creating an OConfigValue object failed.");
530 (*jvm_env)->DeleteLocalRef (jvm_env, o_ocitem);
531 return (NULL);
532 }
534 (*jvm_env)->CallVoidMethod (jvm_env, o_ocitem, m_addvalue, o_value);
535 (*jvm_env)->DeleteLocalRef (jvm_env, o_value);
536 } /* }}} for (i = 0; i < ci->values_num; i++) */
538 /* Call OConfigItem.addChild for each child */
539 for (i = 0; i < ci->children_num; i++) /* {{{ */
540 {
541 jobject o_child;
543 o_child = ctoj_oconfig_item (jvm_env, ci->children + i);
544 if (o_child == NULL)
545 {
546 ERROR ("java plugin: ctoj_oconfig_item: "
547 "Creating an OConfigItem object failed.");
548 (*jvm_env)->DeleteLocalRef (jvm_env, o_ocitem);
549 return (NULL);
550 }
552 (*jvm_env)->CallVoidMethod (jvm_env, o_ocitem, m_addvalue, o_child);
553 (*jvm_env)->DeleteLocalRef (jvm_env, o_child);
554 } /* }}} for (i = 0; i < ci->children_num; i++) */
556 return (o_ocitem);
557 } /* }}} jobject ctoj_oconfig_item */
559 /* Convert a data_set_t to a java.util.List<DataSource> */
560 static jobject ctoj_data_set (JNIEnv *jvm_env, const data_set_t *ds) /* {{{ */
561 {
562 jclass c_arraylist;
563 jmethodID m_constructor;
564 jmethodID m_add;
565 jobject o_dataset;
566 int i;
568 /* Look up the java.util.ArrayList class */
569 c_arraylist = (*jvm_env)->FindClass (jvm_env, "java.util.ArrayList");
570 if (c_arraylist == NULL)
571 {
572 ERROR ("java plugin: ctoj_data_set: Looking up the "
573 "java.util.ArrayList class failed.");
574 return (NULL);
575 }
577 /* Search for the `ArrayList (int capacity)' constructor. */
578 m_constructor = (*jvm_env)->GetMethodID (jvm_env,
579 c_arraylist, "<init>", "()V");
580 if (m_constructor == NULL)
581 {
582 ERROR ("java plugin: ctoj_data_set: Looking up the "
583 "`ArrayList (void)' constructor failed.");
584 return (NULL);
585 }
587 /* Search for the `boolean add (Object element)' method. */
588 m_add = (*jvm_env)->GetMethodID (jvm_env,
589 c_arraylist, "add", "(Ljava/lang/Object;)Z");
590 if (m_add == NULL)
591 {
592 ERROR ("java plugin: ctoj_data_set: Looking up the "
593 "`add (Object)' method failed.");
594 return (NULL);
595 }
597 o_dataset = (*jvm_env)->NewObject (jvm_env, c_arraylist, m_constructor);
598 if (o_dataset == NULL)
599 {
600 ERROR ("java plugin: ctoj_data_set: "
601 "Creating an ArrayList object failed.");
602 return (NULL);
603 }
605 for (i = 0; i < ds->ds_num; i++)
606 {
607 jobject o_datasource;
608 jboolean status;
610 o_datasource = ctoj_data_source (jvm_env, ds->ds + i);
611 if (o_datasource == NULL)
612 {
613 ERROR ("java plugin: ctoj_data_set: ctoj_data_source (%s.%s) failed",
614 ds->type, ds->ds[i].name);
615 (*jvm_env)->DeleteLocalRef (jvm_env, o_dataset);
616 return (NULL);
617 }
619 status = (*jvm_env)->CallBooleanMethod (jvm_env,
620 o_dataset, m_add, o_datasource);
621 if (!status)
622 {
623 ERROR ("java plugin: ctoj_data_set: ArrayList.add returned FALSE.");
624 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
625 (*jvm_env)->DeleteLocalRef (jvm_env, o_dataset);
626 return (NULL);
627 }
629 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
630 } /* for (i = 0; i < ds->ds_num; i++) */
632 return (o_dataset);
633 } /* }}} jobject ctoj_data_set */
635 static int ctoj_value_list_add_value (JNIEnv *jvm_env, /* {{{ */
636 value_t value, int ds_type,
637 jclass class_ptr, jobject object_ptr)
638 {
639 jmethodID m_addvalue;
640 jobject o_number;
642 m_addvalue = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
643 "addValue", "(Ljava/lang/Number;)V");
644 if (m_addvalue == NULL)
645 {
646 ERROR ("java plugin: ctoj_value_list_add_value: "
647 "Cannot find method `void addValue (Number)'.");
648 return (-1);
649 }
651 o_number = ctoj_value_to_number (jvm_env, value, ds_type);
652 if (o_number == NULL)
653 {
654 ERROR ("java plugin: ctoj_value_list_add_value: "
655 "ctoj_value_to_number failed.");
656 return (-1);
657 }
659 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_addvalue, o_number);
661 (*jvm_env)->DeleteLocalRef (jvm_env, o_number);
663 return (0);
664 } /* }}} int ctoj_value_list_add_value */
666 static int ctoj_value_list_add_data_set (JNIEnv *jvm_env, /* {{{ */
667 jclass c_valuelist, jobject o_valuelist, const data_set_t *ds)
668 {
669 jmethodID m_setdatasource;
670 jobject o_dataset;
672 /* Look for the `void setDataSource (List<DataSource> ds)' method. */
673 m_setdatasource = (*jvm_env)->GetMethodID (jvm_env, c_valuelist,
674 "setDataSource", "(Ljava/util/List;)V");
675 if (m_setdatasource == NULL)
676 {
677 ERROR ("java plugin: ctoj_value_list_add_data_set: "
678 "Cannot find the `void setDataSource (List<DataSource> ds)' method.");
679 return (-1);
680 }
682 /* Create a List<DataSource> object. */
683 o_dataset = ctoj_data_set (jvm_env, ds);
684 if (o_dataset == NULL)
685 {
686 ERROR ("java plugin: ctoj_value_list_add_data_set: "
687 "ctoj_data_set (%s) failed.", ds->type);
688 return (-1);
689 }
691 /* Actually call the method. */
692 (*jvm_env)->CallVoidMethod (jvm_env,
693 o_valuelist, m_setdatasource, o_dataset);
695 /* Decrease reference counter on the List<DataSource> object. */
696 (*jvm_env)->DeleteLocalRef (jvm_env, o_dataset);
698 return (0);
699 } /* }}} int ctoj_value_list_add_data_set */
701 static jobject ctoj_value_list (JNIEnv *jvm_env, /* {{{ */
702 const data_set_t *ds, const value_list_t *vl)
703 {
704 jclass c_valuelist;
705 jmethodID m_valuelist_constructor;
706 jobject o_valuelist;
707 int status;
708 int i;
710 /* First, create a new ValueList instance..
711 * Look up the class.. */
712 c_valuelist = (*jvm_env)->FindClass (jvm_env,
713 "org.collectd.protocol.ValueList");
714 if (c_valuelist == NULL)
715 {
716 ERROR ("java plugin: ctoj_value_list: "
717 "FindClass (org.collectd.protocol.ValueList) failed.");
718 return (NULL);
719 }
721 /* Lookup the `ValueList ()' constructor. */
722 m_valuelist_constructor = (*jvm_env)->GetMethodID (jvm_env, c_valuelist,
723 "<init>", "()V");
724 if (m_valuelist_constructor == NULL)
725 {
726 ERROR ("java plugin: ctoj_value_list: Cannot find the "
727 "`ValueList ()' constructor.");
728 return (NULL);
729 }
731 /* Create a new instance. */
732 o_valuelist = (*jvm_env)->NewObject (jvm_env, c_valuelist,
733 m_valuelist_constructor);
734 if (o_valuelist == NULL)
735 {
736 ERROR ("java plugin: ctoj_value_list: Creating a new ValueList instance "
737 "failed.");
738 return (NULL);
739 }
741 status = ctoj_value_list_add_data_set (jvm_env,
742 c_valuelist, o_valuelist, ds);
743 if (status != 0)
744 {
745 ERROR ("java plugin: ctoj_value_list: "
746 "ctoj_value_list_add_data_set failed.");
747 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist);
748 return (NULL);
749 }
751 /* Set the strings.. */
752 #define SET_STRING(str,method_name) do { \
753 status = ctoj_string (jvm_env, str, \
754 c_valuelist, o_valuelist, method_name); \
755 if (status != 0) { \
756 ERROR ("java plugin: ctoj_value_list: jtoc_string (%s) failed.", \
757 method_name); \
758 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist); \
759 return (NULL); \
760 } } while (0)
762 SET_STRING (vl->host, "setHost");
763 SET_STRING (vl->plugin, "setPlugin");
764 SET_STRING (vl->plugin_instance, "setPluginInstance");
765 SET_STRING (vl->type, "setType");
766 SET_STRING (vl->type_instance, "setTypeInstance");
768 #undef SET_STRING
770 /* Set the `time' member. Java stores time in milliseconds. */
771 status = ctoj_long (jvm_env, ((jlong) vl->time) * ((jlong) 1000),
772 c_valuelist, o_valuelist, "setTime");
773 if (status != 0)
774 {
775 ERROR ("java plugin: ctoj_value_list: ctoj_long (setTime) failed.");
776 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist);
777 return (NULL);
778 }
780 /* Set the `interval' member.. */
781 status = ctoj_long (jvm_env, (jlong) vl->interval,
782 c_valuelist, o_valuelist, "setInterval");
783 if (status != 0)
784 {
785 ERROR ("java plugin: ctoj_value_list: ctoj_long (setInterval) failed.");
786 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist);
787 return (NULL);
788 }
790 for (i = 0; i < vl->values_len; i++)
791 {
792 status = ctoj_value_list_add_value (jvm_env, vl->values[i], ds->ds[i].type,
793 c_valuelist, o_valuelist);
794 if (status != 0)
795 {
796 ERROR ("java plugin: ctoj_value_list: "
797 "ctoj_value_list_add_value failed.");
798 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist);
799 return (NULL);
800 }
801 }
803 return (o_valuelist);
804 } /* }}} int ctoj_value_list */
806 /*
807 * Java to C conversion functions
808 */
809 static int jtoc_string (JNIEnv *jvm_env, /* {{{ */
810 char *buffer, size_t buffer_size,
811 jclass class_ptr, jobject object_ptr, const char *method_name)
812 {
813 jmethodID method_id;
814 jobject string_obj;
815 const char *c_str;
817 method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
818 method_name, "()Ljava/lang/String;");
819 if (method_id == NULL)
820 {
821 ERROR ("java plugin: jtoc_string: Cannot find method `String %s ()'.",
822 method_name);
823 return (-1);
824 }
826 string_obj = (*jvm_env)->CallObjectMethod (jvm_env, object_ptr, method_id);
827 if (string_obj == NULL)
828 {
829 ERROR ("java plugin: jtoc_string: CallObjectMethod (%s) failed.",
830 method_name);
831 return (-1);
832 }
834 c_str = (*jvm_env)->GetStringUTFChars (jvm_env, string_obj, 0);
835 if (c_str == NULL)
836 {
837 ERROR ("java plugin: jtoc_string: GetStringUTFChars failed.");
838 (*jvm_env)->DeleteLocalRef (jvm_env, string_obj);
839 return (-1);
840 }
842 DEBUG ("java plugin: jtoc_string: ->%s() = %s", method_name, c_str);
844 sstrncpy (buffer, c_str, buffer_size);
846 (*jvm_env)->ReleaseStringUTFChars (jvm_env, string_obj, c_str);
847 (*jvm_env)->DeleteLocalRef (jvm_env, string_obj);
849 return (0);
850 } /* }}} int jtoc_string */
852 static int jtoc_long (JNIEnv *jvm_env, /* {{{ */
853 jlong *ret_value,
854 jclass class_ptr, jobject object_ptr, const char *method_name)
855 {
856 jmethodID method_id;
858 method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
859 method_name, "()J");
860 if (method_id == NULL)
861 {
862 ERROR ("java plugin: jtoc_long: Cannot find method `long %s ()'.",
863 method_name);
864 return (-1);
865 }
867 *ret_value = (*jvm_env)->CallLongMethod (jvm_env, object_ptr, method_id);
869 DEBUG ("java plugin: jtoc_long: ->%s() = %li",
870 method_name, (long int) *ret_value);
872 return (0);
873 } /* }}} int jtoc_long */
875 static int jtoc_double (JNIEnv *jvm_env, /* {{{ */
876 jdouble *ret_value,
877 jclass class_ptr, jobject object_ptr, const char *method_name)
878 {
879 jmethodID method_id;
881 method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
882 method_name, "()D");
883 if (method_id == NULL)
884 {
885 ERROR ("java plugin: jtoc_string: Cannot find method `double %s ()'.",
886 method_name);
887 return (-1);
888 }
890 *ret_value = (*jvm_env)->CallDoubleMethod (jvm_env, object_ptr, method_id);
892 DEBUG ("java plugin: jtoc_double: ->%s() = %g",
893 method_name, (double) *ret_value);
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.protocol.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 /*
1113 * Functions accessible from Java
1114 */
1115 static jint JNICALL cjni_api_dispatch_values (JNIEnv *jvm_env, /* {{{ */
1116 jobject this, jobject java_vl)
1117 {
1118 value_list_t vl = VALUE_LIST_INIT;
1119 int status;
1121 DEBUG ("cjni_api_dispatch_values: java_vl = %p;", (void *) java_vl);
1123 status = jtoc_value_list (jvm_env, &vl, java_vl);
1124 if (status != 0)
1125 {
1126 ERROR ("java plugin: cjni_api_dispatch_values: jtoc_value_list failed.");
1127 return (-1);
1128 }
1130 status = plugin_dispatch_values (&vl);
1132 sfree (vl.values);
1134 return (status);
1135 } /* }}} jint cjni_api_dispatch_values */
1137 static jobject JNICALL cjni_api_get_ds (JNIEnv *jvm_env, /* {{{ */
1138 jobject this, jobject o_string_type)
1139 {
1140 const char *ds_name;
1141 const data_set_t *ds;
1142 jobject o_dataset;
1144 ds_name = (*jvm_env)->GetStringUTFChars (jvm_env, o_string_type, 0);
1145 if (ds_name == NULL)
1146 {
1147 ERROR ("java plugin: cjni_api_get_ds: GetStringUTFChars failed.");
1148 return (NULL);
1149 }
1151 ds = plugin_get_ds (ds_name);
1152 DEBUG ("java plugin: cjni_api_get_ds: "
1153 "plugin_get_ds (%s) = %p;", ds_name, (void *) ds);
1155 (*jvm_env)->ReleaseStringUTFChars (jvm_env, o_string_type, ds_name);
1157 if (ds == NULL)
1158 return (NULL);
1160 o_dataset = ctoj_data_set (jvm_env, ds);
1161 return (o_dataset);
1162 } /* }}} jint cjni_api_get_ds */
1164 static JNINativeMethod jni_api_functions[] =
1165 {
1166 { "DispatchValues", "(Lorg/collectd/protocol/ValueList;)I", cjni_api_dispatch_values },
1167 { "GetDS", "(Ljava/lang/String;)Ljava/util/List;", cjni_api_get_ds }
1168 };
1169 static size_t jni_api_functions_num = sizeof (jni_api_functions)
1170 / sizeof (jni_api_functions[0]);
1172 /*
1173 * Functions
1174 */
1175 static JNIEnv *cjni_thread_attach (void) /* {{{ */
1176 {
1177 cjni_jvm_env_t *cjni_env;
1178 JNIEnv *jvm_env;
1180 cjni_env = pthread_getspecific (jvm_env_key);
1181 if (cjni_env == NULL)
1182 {
1183 /* This pointer is free'd in `cjni_jvm_env_destroy'. */
1184 cjni_env = (cjni_jvm_env_t *) malloc (sizeof (*cjni_env));
1185 if (cjni_env == NULL)
1186 {
1187 ERROR ("java plugin: cjni_thread_attach: malloc failed.");
1188 return (NULL);
1189 }
1190 memset (cjni_env, 0, sizeof (*cjni_env));
1191 cjni_env->reference_counter = 0;
1192 cjni_env->jvm_env = NULL;
1194 pthread_setspecific (jvm_env_key, cjni_env);
1195 }
1197 if (cjni_env->reference_counter > 0)
1198 {
1199 cjni_env->reference_counter++;
1200 jvm_env = cjni_env->jvm_env;
1201 }
1202 else
1203 {
1204 int status;
1205 JavaVMAttachArgs args;
1207 assert (cjni_env->jvm_env == NULL);
1209 memset (&args, 0, sizeof (args));
1210 args.version = JNI_VERSION_1_2;
1212 status = (*jvm)->AttachCurrentThread (jvm, (void *) &jvm_env, (void *) &args);
1213 if (status != 0)
1214 {
1215 ERROR ("java plugin: cjni_thread_attach: AttachCurrentThread failed "
1216 "with status %i.", status);
1217 return (NULL);
1218 }
1220 cjni_env->reference_counter = 1;
1221 cjni_env->jvm_env = jvm_env;
1222 }
1224 DEBUG ("java plugin: cjni_thread_attach: cjni_env->reference_counter = %i",
1225 cjni_env->reference_counter);
1226 assert (jvm_env != NULL);
1227 return (jvm_env);
1228 } /* }}} JNIEnv *cjni_thread_attach */
1230 static int cjni_thread_detach (void) /* {{{ */
1231 {
1232 cjni_jvm_env_t *cjni_env;
1233 int status;
1235 cjni_env = pthread_getspecific (jvm_env_key);
1236 if (cjni_env == NULL)
1237 {
1238 ERROR ("java plugin: cjni_thread_detach: pthread_getspecific failed.");
1239 return (-1);
1240 }
1242 assert (cjni_env->reference_counter > 0);
1243 assert (cjni_env->jvm_env != NULL);
1245 cjni_env->reference_counter--;
1246 DEBUG ("java plugin: cjni_thread_detach: cjni_env->reference_counter = %i",
1247 cjni_env->reference_counter);
1249 if (cjni_env->reference_counter > 0)
1250 return (0);
1252 status = (*jvm)->DetachCurrentThread (jvm);
1253 if (status != 0)
1254 {
1255 ERROR ("java plugin: cjni_thread_detach: DetachCurrentThread failed "
1256 "with status %i.", status);
1257 }
1259 cjni_env->reference_counter = 0;
1260 cjni_env->jvm_env = NULL;
1262 return (0);
1263 } /* }}} JNIEnv *cjni_thread_attach */
1265 static void cjni_jvm_env_destroy (void *args) /* {{{ */
1266 {
1267 cjni_jvm_env_t *cjni_env;
1269 if (args == NULL)
1270 return;
1272 cjni_env = (cjni_jvm_env_t *) args;
1274 if (cjni_env->reference_counter > 0)
1275 {
1276 ERROR ("java plugin: cjni_jvm_env_destroy: "
1277 "cjni_env->reference_counter = %i;", cjni_env->reference_counter);
1278 }
1280 if (cjni_env->jvm_env != NULL)
1281 {
1282 ERROR ("java plugin: cjni_jvm_env_destroy: cjni_env->jvm_env = %p;",
1283 (void *) cjni_env->jvm_env);
1284 }
1286 /* The pointer is allocated in `cjni_thread_attach' */
1287 free (cjni_env);
1288 } /* }}} void cjni_jvm_env_destroy */
1290 static int cjni_config_add_jvm_arg (oconfig_item_t *ci) /* {{{ */
1291 {
1292 char **tmp;
1294 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
1295 {
1296 WARNING ("java plugin: `JVMArg' needs exactly one string argument.");
1297 return (-1);
1298 }
1300 tmp = (char **) realloc (jvm_argv, sizeof (char *) * (jvm_argc + 1));
1301 if (tmp == NULL)
1302 {
1303 ERROR ("java plugin: realloc failed.");
1304 return (-1);
1305 }
1306 jvm_argv = tmp;
1308 jvm_argv[jvm_argc] = strdup (ci->values[0].value.string);
1309 if (jvm_argv[jvm_argc] == NULL)
1310 {
1311 ERROR ("java plugin: strdup failed.");
1312 return (-1);
1313 }
1314 jvm_argc++;
1316 return (0);
1317 } /* }}} int cjni_config_add_jvm_arg */
1319 static int cjni_config_load_plugin (oconfig_item_t *ci) /* {{{ */
1320 {
1321 java_plugin_t *jp;
1323 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
1324 {
1325 WARNING ("java plugin: `LoadPlugin' needs exactly one string argument.");
1326 return (-1);
1327 }
1329 jp = (java_plugin_t *) realloc (java_plugins,
1330 sizeof (*java_plugins) * (java_plugins_num + 1));
1331 if (jp == NULL)
1332 {
1333 ERROR ("java plugin: realloc failed.");
1334 return (-1);
1335 }
1336 java_plugins = jp;
1337 jp = java_plugins + java_plugins_num;
1339 memset (jp, 0, sizeof (*jp));
1340 jp->class_name = strdup (ci->values[0].value.string);
1341 if (jp->class_name == NULL)
1342 {
1343 ERROR ("java plugin: strdup failed.");
1344 return (-1);
1345 }
1347 jp->class_ptr = NULL;
1348 jp->object_ptr = NULL;
1349 jp->ci = NULL;
1350 jp->flags = 0;
1351 jp->m_config = NULL;
1352 jp->m_init = NULL;
1353 jp->m_read = NULL;
1354 jp->m_write = NULL;
1355 jp->m_shutdown = NULL;
1357 java_plugins_num++;
1359 return (0);
1360 } /* }}} int cjni_config_load_plugin */
1362 static int cjni_config_plugin_block (oconfig_item_t *ci) /* {{{ */
1363 {
1364 size_t i;
1365 const char *class_name;
1367 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
1368 {
1369 WARNING ("java plugin: `Plugin' blocks "
1370 "need exactly one string argument.");
1371 return (-1);
1372 }
1374 class_name = ci->values[0].value.string;
1375 for (i = 0; i < java_plugins_num; i++)
1376 if (strcmp (java_plugins[i].class_name, class_name) == 0)
1377 break;
1379 if (i >= java_plugins_num)
1380 {
1381 WARNING ("java plugin: Configuration block for the `%s' plugin found, "
1382 "but the plugin has not been loaded. Please note, that the class "
1383 "name is case-sensitive!",
1384 class_name);
1385 return (0);
1386 }
1388 if (java_plugins[i].ci != NULL)
1389 {
1390 WARNING ("java plugin: There are more than one <Plugin> blocks for the "
1391 "`%s' plugin. This is currently not supported - only the first block "
1392 "will be used!",
1393 class_name);
1394 return (0);
1395 }
1397 java_plugins[i].ci = oconfig_clone (ci);
1398 if (java_plugins[i].ci == NULL)
1399 {
1400 ERROR ("java plugin: cjni_config_plugin_block: "
1401 "oconfig_clone failed for `%s'.",
1402 class_name);
1403 return (-1);
1404 }
1406 DEBUG ("java plugin: cjni_config_plugin_block: "
1407 "Successfully copied config for `%s'.",
1408 class_name);
1410 return (0);
1411 } /* }}} int cjni_config_plugin_block */
1413 static int cjni_config (oconfig_item_t *ci) /* {{{ */
1414 {
1415 int success;
1416 int errors;
1417 int status;
1418 int i;
1420 success = 0;
1421 errors = 0;
1423 for (i = 0; i < ci->children_num; i++)
1424 {
1425 oconfig_item_t *child = ci->children + i;
1427 if (strcasecmp ("JVMArg", child->key) == 0)
1428 {
1429 status = cjni_config_add_jvm_arg (child);
1430 if (status == 0)
1431 success++;
1432 else
1433 errors++;
1434 }
1435 else if (strcasecmp ("LoadPlugin", child->key) == 0)
1436 {
1437 status = cjni_config_load_plugin (child);
1438 if (status == 0)
1439 success++;
1440 else
1441 errors++;
1442 }
1443 else if (strcasecmp ("Plugin", child->key) == 0)
1444 {
1445 status = cjni_config_plugin_block (child);
1446 if (status == 0)
1447 success++;
1448 else
1449 errors++;
1450 }
1451 else
1452 {
1453 WARNING ("java plugin: Option `%s' not allowed here.", child->key);
1454 errors++;
1455 }
1456 }
1458 if ((success == 0) && (errors > 0))
1459 {
1460 ERROR ("java plugin: All statements failed.");
1461 return (-1);
1462 }
1464 return (0);
1465 } /* }}} int cjni_config */
1467 static int cjni_read_one_plugin (JNIEnv *jvm_env, java_plugin_t *jp) /* {{{ */
1468 {
1469 int status;
1471 if ((jp == NULL)
1472 || ((jp->flags & CJNI_FLAG_ENABLED) == 0)
1473 || (jp->m_read == NULL))
1474 return (0);
1476 DEBUG ("java plugin: Calling: %s.Read()", jp->class_name);
1478 status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
1479 jp->m_read);
1480 if (status != 0)
1481 {
1482 ERROR ("java plugin: cjni_read_one_plugin: "
1483 "Calling `Read' on an `%s' object failed with status %i.",
1484 jp->class_name, status);
1485 return (-1);
1486 }
1488 return (0);
1489 } /* }}} int cjni_read_one_plugin */
1491 static int cjni_read_plugins (JNIEnv *jvm_env) /* {{{ */
1492 {
1493 size_t j;
1495 for (j = 0; j < java_plugins_num; j++)
1496 cjni_read_one_plugin (jvm_env, &java_plugins[j]);
1498 return (0);
1499 } /* }}} int cjni_read_plugins */
1501 static int cjni_read (void) /* {{{ */
1502 {
1503 JNIEnv *jvm_env;
1504 int status;
1506 if (jvm == NULL)
1507 {
1508 ERROR ("java plugin: cjni_read: jvm == NULL");
1509 return (-1);
1510 }
1512 jvm_env = cjni_thread_attach ();
1513 if (jvm_env == NULL)
1514 return (-1);
1516 cjni_read_plugins (jvm_env);
1518 status = cjni_thread_detach ();
1519 if (status != 0)
1520 return (-1);
1522 return (0);
1523 } /* }}} int cjni_read */
1525 static int cjni_write_one_plugin (JNIEnv *jvm_env, /* {{{ */
1526 java_plugin_t *jp, jobject vl_java)
1527 {
1528 int status;
1530 if ((jp == NULL)
1531 || ((jp->flags & CJNI_FLAG_ENABLED) == 0)
1532 || (jp->m_write == NULL))
1533 return (0);
1535 DEBUG ("java plugin: Calling: %s.Write(ValueList)", jp->class_name);
1537 status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
1538 jp->m_write, vl_java);
1539 if (status != 0)
1540 {
1541 ERROR ("java plugin: cjni_write_one_plugin: "
1542 "Calling `Write' on an `%s' object failed with status %i.",
1543 jp->class_name, status);
1544 return (-1);
1545 }
1547 return (0);
1548 } /* }}} int cjni_write_one_plugin */
1550 static int cjni_write_plugins (JNIEnv *jvm_env, /* {{{ */
1551 const data_set_t *ds, const value_list_t *vl)
1552 {
1553 size_t j;
1555 jobject vl_java;
1557 vl_java = ctoj_value_list (jvm_env, ds, vl);
1558 if (vl_java == NULL)
1559 {
1560 ERROR ("java plugin: cjni_write_plugins: ctoj_value_list failed.");
1561 return (-1);
1562 }
1564 for (j = 0; j < java_plugins_num; j++)
1565 cjni_write_one_plugin (jvm_env, &java_plugins[j], vl_java);
1567 (*jvm_env)->DeleteLocalRef (jvm_env, vl_java);
1569 return (0);
1570 } /* }}} int cjni_write_plugins */
1572 static int cjni_write (const data_set_t *ds, const value_list_t *vl) /* {{{ */
1573 {
1574 JNIEnv *jvm_env;
1575 int status;
1577 if (jvm == NULL)
1578 {
1579 ERROR ("java plugin: cjni_write: jvm == NULL");
1580 return (-1);
1581 }
1583 jvm_env = cjni_thread_attach ();
1584 if (jvm_env == NULL)
1585 return (-1);
1587 cjni_write_plugins (jvm_env, ds, vl);
1589 status = cjni_thread_detach ();
1590 if (status != 0)
1591 return (-1);
1593 return (0);
1594 } /* }}} int cjni_write */
1596 static int cjni_shutdown_one_plugin (JNIEnv *jvm_env, /* {{{ */
1597 java_plugin_t *jp)
1598 {
1599 int status;
1601 if ((jp == NULL)
1602 || ((jp->flags & CJNI_FLAG_ENABLED) == 0)
1603 || (jp->m_shutdown == NULL))
1604 return (0);
1606 status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
1607 jp->m_shutdown);
1608 if (status != 0)
1609 {
1610 ERROR ("cjni_shutdown_one_plugin: Destroying an `%s' object failed "
1611 "with status %i.", jp->class_name, status);
1612 return (-1);
1613 }
1614 jp->flags &= ~CJNI_FLAG_ENABLED;
1616 return (0);
1617 } /* }}} int cjni_shutdown_one_plugin */
1619 static int cjni_shutdown_plugins (JNIEnv *jvm_env) /* {{{ */
1620 {
1621 size_t j;
1623 for (j = 0; j < java_plugins_num; j++)
1624 cjni_shutdown_one_plugin (jvm_env, &java_plugins[j]);
1626 return (0);
1627 } /* }}} int cjni_shutdown_plugins */
1629 static int cjni_shutdown (void) /* {{{ */
1630 {
1631 JNIEnv *jvm_env;
1632 JavaVMAttachArgs args;
1633 int status;
1634 size_t i;
1636 if (jvm == NULL)
1637 return (0);
1639 jvm_env = NULL;
1640 memset (&args, 0, sizeof (args));
1641 args.version = JNI_VERSION_1_2;
1643 status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args);
1644 if (status != 0)
1645 {
1646 ERROR ("java plugin: cjni_read: AttachCurrentThread failed with status %i.",
1647 status);
1648 return (-1);
1649 }
1651 cjni_shutdown_plugins (jvm_env);
1653 (*jvm)->DestroyJavaVM (jvm);
1654 jvm = NULL;
1655 jvm_env = NULL;
1657 pthread_key_delete (jvm_env_key);
1659 for (i = 0; i < jvm_argc; i++)
1660 {
1661 sfree (jvm_argv[i]);
1662 }
1663 sfree (jvm_argv);
1664 jvm_argc = 0;
1666 for (i = 0; i < java_plugins_num; i++)
1667 {
1668 sfree (java_plugins[i].class_name);
1669 oconfig_free (java_plugins[i].ci);
1670 }
1671 sfree (java_plugins);
1672 java_plugins_num = 0;
1674 return (0);
1675 } /* }}} int cjni_shutdown */
1677 static int cjni_init_one_plugin (JNIEnv *jvm_env, java_plugin_t *jp) /* {{{ */
1678 {
1679 jmethodID constructor_id;
1680 int status;
1682 jp->class_ptr = (*jvm_env)->FindClass (jvm_env, jp->class_name);
1683 if (jp->class_ptr == NULL)
1684 {
1685 ERROR ("cjni_init_one_plugin: FindClass (%s) failed.",
1686 jp->class_name);
1687 return (-1);
1688 }
1690 constructor_id = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1691 "<init>", "()V");
1692 if (constructor_id == NULL)
1693 {
1694 ERROR ("cjni_init_one_plugin: Could not find the constructor for `%s'.",
1695 jp->class_name);
1696 return (-1);
1697 }
1699 jp->object_ptr = (*jvm_env)->NewObject (jvm_env, jp->class_ptr,
1700 constructor_id);
1701 if (jp->object_ptr == NULL)
1702 {
1703 ERROR ("cjni_init_one_plugin: Could create a new `%s' object.",
1704 jp->class_name);
1705 return (-1);
1706 }
1708 jp->m_config = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1709 "Config", "(Lorg/collectd/api/OConfigItem;)I");
1710 DEBUG ("java plugin: cjni_init_one_plugin: "
1711 "jp->class_name = %s; jp->m_config = %p;",
1712 jp->class_name, (void *) jp->m_config);
1714 jp->m_init = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1715 "Init", "()I");
1716 DEBUG ("java plugin: cjni_init_one_plugin: "
1717 "jp->class_name = %s; jp->m_init = %p;",
1718 jp->class_name, (void *) jp->m_init);
1720 jp->m_read = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1721 "Read", "()I");
1722 DEBUG ("java plugin: cjni_init_one_plugin: "
1723 "jp->class_name = %s; jp->m_read = %p;",
1724 jp->class_name, (void *) jp->m_read);
1726 jp->m_write = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1727 "Write", "(Lorg/collectd/protocol/ValueList;)I");
1728 DEBUG ("java plugin: cjni_init_one_plugin: "
1729 "jp->class_name = %s; jp->m_write = %p;",
1730 jp->class_name, (void *) jp->m_write);
1732 jp->m_shutdown = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1733 "Shutdown", "()I");
1734 DEBUG ("java plugin: cjni_init_one_plugin: "
1735 "jp->class_name = %s; jp->m_shutdown = %p;",
1736 jp->class_name, (void *) jp->m_shutdown);
1738 if (jp->ci != NULL)
1739 {
1740 if (jp->m_config == NULL)
1741 {
1742 WARNING ("java plugin: Configuration for the `%s' plugin is present, "
1743 "but plugin doesn't provide a configuration method.",
1744 jp->class_name);
1745 }
1746 else /* if (jp->m_config != NULL) */
1747 {
1748 jobject o_ocitem;
1750 o_ocitem = ctoj_oconfig_item (jvm_env, jp->ci);
1751 if (o_ocitem == NULL)
1752 {
1753 ERROR ("java plugin: Creating an OConfigItem object failed. "
1754 "Can't pass configuration information to the `%s' plugin!",
1755 jp->class_name);
1756 }
1757 else /* if (o_ocitem != NULL) */
1758 {
1759 status = (*jvm_env)->CallIntMethod (jvm_env,
1760 jp->object_ptr, jp->m_config, o_ocitem);
1761 if (status != 0)
1762 {
1763 ERROR ("java plugin: cjni_init_one_plugin: "
1764 "Configuring the `%s' object failed with status %i.",
1765 jp->class_name, status);
1766 (*jvm_env)->DeleteLocalRef (jvm_env, o_ocitem);
1767 return (-1);
1768 }
1769 (*jvm_env)->DeleteLocalRef (jvm_env, o_ocitem);
1770 } /* if (o_ocitem != NULL) */
1771 } /* if (jp->m_config != NULL) */
1772 } /* if (jp->ci != NULL) */
1774 if (jp->m_init != NULL)
1775 {
1776 status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
1777 jp->m_init);
1778 if (status != 0)
1779 {
1780 ERROR ("java plugin: cjni_init_one_plugin: "
1781 "Initializing `%s' object failed with status %i.",
1782 jp->class_name, status);
1783 return (-1);
1784 }
1785 }
1786 jp->flags |= CJNI_FLAG_ENABLED;
1788 return (0);
1789 } /* }}} int cjni_init_one_plugin */
1791 static int cjni_init_plugins (JNIEnv *jvm_env) /* {{{ */
1792 {
1793 size_t j;
1795 int have_read;
1796 int have_write;
1797 int have_shutdown;
1799 have_read = 0;
1800 have_write = 0;
1801 have_shutdown = 0;
1803 for (j = 0; j < java_plugins_num; j++)
1804 {
1805 cjni_init_one_plugin (jvm_env, &java_plugins[j]);
1807 if (java_plugins[j].m_read != NULL)
1808 have_read++;
1809 if (java_plugins[j].m_write != NULL)
1810 have_write++;
1811 if (java_plugins[j].m_shutdown != NULL)
1812 have_shutdown++;
1813 }
1815 if (have_read > 0)
1816 plugin_register_read ("java", cjni_read);
1817 if (have_write > 0)
1818 plugin_register_write ("java", cjni_write);
1819 if (have_shutdown > 0)
1820 plugin_register_shutdown ("java", cjni_shutdown);
1823 return (0);
1824 } /* }}} int cjni_init_plugins */
1826 static int cjni_init_native (JNIEnv *jvm_env) /* {{{ */
1827 {
1828 jclass api_class_ptr;
1829 int status;
1831 api_class_ptr = (*jvm_env)->FindClass (jvm_env, "org.collectd.api.CollectdAPI");
1832 if (api_class_ptr == NULL)
1833 {
1834 ERROR ("cjni_init_native: Cannot find API class `org.collectd.api.CollectdAPI'.");
1835 return (-1);
1836 }
1838 status = (*jvm_env)->RegisterNatives (jvm_env, api_class_ptr,
1839 jni_api_functions, (jint) jni_api_functions_num);
1840 if (status != 0)
1841 {
1842 ERROR ("cjni_init_native: RegisterNatives failed with status %i.", status);
1843 return (-1);
1844 }
1846 return (0);
1847 } /* }}} int cjni_init_native */
1849 static int cjni_init (void) /* {{{ */
1850 {
1851 JNIEnv *jvm_env;
1852 JavaVMInitArgs vm_args;
1853 JavaVMOption vm_options[jvm_argc];
1855 int status;
1856 size_t i;
1858 if (jvm != NULL)
1859 return (0);
1861 status = pthread_key_create (&jvm_env_key, cjni_jvm_env_destroy);
1862 if (status != 0)
1863 {
1864 ERROR ("java plugin: cjni_init: pthread_key_create failed "
1865 "with status %i.", status);
1866 return (-1);
1867 }
1869 jvm_env = NULL;
1871 memset (&vm_args, 0, sizeof (vm_args));
1872 vm_args.version = JNI_VERSION_1_2;
1873 vm_args.options = vm_options;
1874 vm_args.nOptions = (jint) jvm_argc;
1876 for (i = 0; i < jvm_argc; i++)
1877 {
1878 DEBUG ("java plugin: cjni_init: jvm_argv[%zu] = %s", i, jvm_argv[i]);
1879 vm_args.options[i].optionString = jvm_argv[i];
1880 }
1881 /*
1882 vm_args.options[0].optionString = "-verbose:jni";
1883 vm_args.options[1].optionString = "-Djava.class.path=/home/octo/collectd/bindings/java";
1884 */
1886 status = JNI_CreateJavaVM (&jvm, (void **) &jvm_env, (void **) &vm_args);
1887 if (status != 0)
1888 {
1889 ERROR ("cjni_init: JNI_CreateJavaVM failed with status %i.",
1890 status);
1891 return (-1);
1892 }
1893 assert (jvm != NULL);
1894 assert (jvm_env != NULL);
1896 /* Call RegisterNatives */
1897 status = cjni_init_native (jvm_env);
1898 if (status != 0)
1899 {
1900 ERROR ("cjni_init: cjni_init_native failed.");
1901 return (-1);
1902 }
1904 cjni_init_plugins (jvm_env);
1906 return (0);
1907 } /* }}} int cjni_init */
1909 void module_register (void)
1910 {
1911 plugin_register_complex_config ("java", cjni_config);
1912 plugin_register_init ("java", cjni_init);
1913 } /* void module_register (void) */
1915 /* vim: set sw=2 sts=2 et fdm=marker : */