f6ce46785ed990cde2f1b8ad9f881dd6c6bd842e
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 #define CJNI_FLAG_ENABLED 0x0001
45 int flags;
47 jmethodID m_init;
48 jmethodID m_read;
49 jmethodID m_write;
50 jmethodID m_shutdown;
51 };
52 typedef struct java_plugin_s java_plugin_t;
53 /* }}} */
55 /*
56 * Global variables
57 */
58 static JavaVM *jvm = NULL;
60 static char **jvm_argv = NULL;
61 static size_t jvm_argc = 0;
63 static java_plugin_t *java_plugins = NULL;
64 static size_t java_plugins_num = 0;
66 /*
67 * C to Java conversion functions
68 */
69 static int ctoj_string (JNIEnv *jvm_env, /* {{{ */
70 const char *string,
71 jclass class_ptr, jobject object_ptr, const char *method_name)
72 {
73 jmethodID m_set;
74 jstring o_string;
76 /* Create a java.lang.String */
77 o_string = (*jvm_env)->NewStringUTF (jvm_env,
78 (string != NULL) ? string : "");
79 if (o_string == NULL)
80 {
81 ERROR ("java plugin: ctoj_string: NewStringUTF failed.");
82 return (-1);
83 }
85 /* Search for the `void setFoo (String s)' method. */
86 m_set = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
87 method_name, "(Ljava/lang/String;)V");
88 if (m_set == NULL)
89 {
90 ERROR ("java plugin: ctoj_string: Cannot find method `void %s (String)'.",
91 method_name);
92 (*jvm_env)->DeleteLocalRef (jvm_env, o_string);
93 return (-1);
94 }
96 /* Call the method. */
97 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, o_string);
99 /* Decrease reference counter on the java.lang.String object. */
100 (*jvm_env)->DeleteLocalRef (jvm_env, o_string);
102 DEBUG ("java plugin: ctoj_string: ->%s (%s);",
103 method_name, (string != NULL) ? string : "");
105 return (0);
106 } /* }}} int ctoj_string */
108 static int ctoj_int (JNIEnv *jvm_env, /* {{{ */
109 jint value,
110 jclass class_ptr, jobject object_ptr, const char *method_name)
111 {
112 jmethodID m_set;
114 /* Search for the `void setFoo (int i)' method. */
115 m_set = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
116 method_name, "(I)V");
117 if (m_set == NULL)
118 {
119 ERROR ("java plugin: ctoj_int: Cannot find method `void %s (int)'.",
120 method_name);
121 return (-1);
122 }
124 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, value);
126 DEBUG ("java plugin: ctoj_int: ->%s (%i);",
127 method_name, (int) value);
129 return (0);
130 } /* }}} int ctoj_int */
132 static int ctoj_long (JNIEnv *jvm_env, /* {{{ */
133 jlong value,
134 jclass class_ptr, jobject object_ptr, const char *method_name)
135 {
136 jmethodID m_set;
138 /* Search for the `void setFoo (long l)' method. */
139 m_set = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
140 method_name, "(J)V");
141 if (m_set == NULL)
142 {
143 ERROR ("java plugin: ctoj_long: Cannot find method `void %s (long)'.",
144 method_name);
145 return (-1);
146 }
148 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, value);
150 DEBUG ("java plugin: ctoj_long: ->%s (%"PRIi64");",
151 method_name, (int64_t) value);
153 return (0);
154 } /* }}} int ctoj_long */
156 static int ctoj_double (JNIEnv *jvm_env, /* {{{ */
157 jdouble value,
158 jclass class_ptr, jobject object_ptr, const char *method_name)
159 {
160 jmethodID m_set;
162 /* Search for the `void setFoo (double d)' method. */
163 m_set = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
164 method_name, "(D)V");
165 if (m_set == NULL)
166 {
167 ERROR ("java plugin: ctoj_double: Cannot find method `void %s (double)'.",
168 method_name);
169 return (-1);
170 }
172 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_set, value);
174 DEBUG ("java plugin: ctoj_double: ->%s (%g);",
175 method_name, (double) value);
177 return (0);
178 } /* }}} int ctoj_double */
180 /* Convert a value_t to a java.lang.Number */
181 static jobject ctoj_value_to_number (JNIEnv *jvm_env, /* {{{ */
182 value_t value, int ds_type)
183 {
184 if (ds_type == DS_TYPE_COUNTER)
185 {
186 jclass c_long;
187 jmethodID m_long_constructor;
189 jlong tmp_long;
191 /* Look up the java.lang.Long class */
192 c_long = (*jvm_env)->FindClass (jvm_env, "java.lang.Long");
193 if (c_long == NULL)
194 {
195 ERROR ("java plugin: ctoj_value_to_number: Looking up the "
196 "java.lang.Long class failed.");
197 return (NULL);
198 }
200 m_long_constructor = (*jvm_env)->GetMethodID (jvm_env,
201 c_long, "<init>", "(J)V");
202 if (m_long_constructor == NULL)
203 {
204 ERROR ("java plugin: ctoj_value_to_number: Looking up the "
205 "`Long (long)' constructor failed.");
206 return (NULL);
207 }
209 tmp_long = (jlong) value.counter;
210 return ((*jvm_env)->NewObject (jvm_env,
211 c_long, m_long_constructor, tmp_long));
212 }
213 else if (ds_type == DS_TYPE_GAUGE)
214 {
215 jclass c_double;
216 jmethodID m_double_constructor;
218 jdouble tmp_double;
220 /* Look up the java.lang.Long class */
221 c_double = (*jvm_env)->FindClass (jvm_env, "java.lang.Double");
222 if (c_double == NULL)
223 {
224 ERROR ("java plugin: ctoj_value_to_number: Looking up the "
225 "java.lang.Double class failed.");
226 return (NULL);
227 }
229 m_double_constructor = (*jvm_env)->GetMethodID (jvm_env,
230 c_double, "<init>", "(D)V");
231 if (m_double_constructor == NULL)
232 {
233 ERROR ("java plugin: ctoj_value_to_number: Looking up the "
234 "`Double (double)' constructor failed.");
235 return (NULL);
236 }
238 tmp_double = (jdouble) value.gauge;
239 return ((*jvm_env)->NewObject (jvm_env,
240 c_double, m_double_constructor, tmp_double));
241 }
242 else
243 {
244 return (NULL);
245 }
246 } /* }}} jobject ctoj_value_to_number */
248 /* Convert a data_source_t to a org.collectd.protocol.DataSource */
249 static jobject ctoj_data_source (JNIEnv *jvm_env, /* {{{ */
250 const data_source_t *dsrc)
251 {
252 jclass c_datasource;
253 jmethodID m_datasource_constructor;
254 jobject o_datasource;
255 int status;
257 /* Look up the DataSource class */
258 c_datasource = (*jvm_env)->FindClass (jvm_env,
259 "org.collectd.protocol.DataSource");
260 if (c_datasource == NULL)
261 {
262 ERROR ("java plugin: ctoj_data_source: "
263 "FindClass (org.collectd.protocol.DataSource) failed.");
264 return (NULL);
265 }
267 /* Lookup the `ValueList ()' constructor. */
268 m_datasource_constructor = (*jvm_env)->GetMethodID (jvm_env, c_datasource,
269 "<init>", "()V");
270 if (m_datasource_constructor == NULL)
271 {
272 ERROR ("java plugin: ctoj_data_source: Cannot find the "
273 "`DataSource ()' constructor.");
274 return (NULL);
275 }
277 /* Create a new instance. */
278 o_datasource = (*jvm_env)->NewObject (jvm_env, c_datasource,
279 m_datasource_constructor);
280 if (o_datasource == NULL)
281 {
282 ERROR ("java plugin: ctoj_data_source: "
283 "Creating a new DataSource instance failed.");
284 return (NULL);
285 }
287 /* Set name via `void setName (String name)' */
288 status = ctoj_string (jvm_env, dsrc->name,
289 c_datasource, o_datasource, "setName");
290 if (status != 0)
291 {
292 ERROR ("java plugin: ctoj_data_source: "
293 "ctoj_string (setName) failed.");
294 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
295 return (NULL);
296 }
298 /* Set type via `void setType (int type)' */
299 status = ctoj_int (jvm_env, dsrc->type,
300 c_datasource, o_datasource, "setType");
301 if (status != 0)
302 {
303 ERROR ("java plugin: ctoj_data_source: "
304 "ctoj_int (setType) failed.");
305 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
306 return (NULL);
307 }
309 /* Set min via `void setMin (double min)' */
310 status = ctoj_double (jvm_env, dsrc->min,
311 c_datasource, o_datasource, "setMin");
312 if (status != 0)
313 {
314 ERROR ("java plugin: ctoj_data_source: "
315 "ctoj_double (setMin) failed.");
316 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
317 return (NULL);
318 }
320 /* Set max via `void setMax (double max)' */
321 status = ctoj_double (jvm_env, dsrc->max,
322 c_datasource, o_datasource, "setMax");
323 if (status != 0)
324 {
325 ERROR ("java plugin: ctoj_data_source: "
326 "ctoj_double (setMax) failed.");
327 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
328 return (NULL);
329 }
331 return (o_datasource);
332 } /* }}} jobject ctoj_data_source */
334 /* Convert a data_set_t to a java.util.List<DataSource> */
335 static jobject ctoj_data_set (JNIEnv *jvm_env, const data_set_t *ds) /* {{{ */
336 {
337 jclass c_arraylist;
338 jmethodID m_constructor;
339 jmethodID m_add;
340 jobject o_dataset;
341 int i;
343 /* Look up the java.util.ArrayList class */
344 c_arraylist = (*jvm_env)->FindClass (jvm_env, "java.util.ArrayList");
345 if (c_arraylist == NULL)
346 {
347 ERROR ("java plugin: ctoj_data_set: Looking up the "
348 "java.util.ArrayList class failed.");
349 return (NULL);
350 }
352 /* Search for the `ArrayList (int capacity)' constructor. */
353 m_constructor = (*jvm_env)->GetMethodID (jvm_env,
354 c_arraylist, "<init>", "()V");
355 if (m_constructor == NULL)
356 {
357 ERROR ("java plugin: ctoj_data_set: Looking up the "
358 "`ArrayList (void)' constructor failed.");
359 return (NULL);
360 }
362 /* Search for the `boolean add (Object element)' method. */
363 m_add = (*jvm_env)->GetMethodID (jvm_env,
364 c_arraylist, "add", "(Ljava/lang/Object;)Z");
365 if (m_add == NULL)
366 {
367 ERROR ("java plugin: ctoj_data_set: Looking up the "
368 "`add (Object)' method failed.");
369 return (NULL);
370 }
372 o_dataset = (*jvm_env)->NewObject (jvm_env, c_arraylist, m_constructor);
373 if (o_dataset == NULL)
374 {
375 ERROR ("java plugin: ctoj_data_set: "
376 "Creating an ArrayList object failed.");
377 return (NULL);
378 }
380 for (i = 0; i < ds->ds_num; i++)
381 {
382 jobject o_datasource;
383 jboolean status;
385 o_datasource = ctoj_data_source (jvm_env, ds->ds + i);
386 if (o_datasource == NULL)
387 {
388 ERROR ("java plugin: ctoj_data_set: ctoj_data_source (%s.%s) failed",
389 ds->type, ds->ds[i].name);
390 (*jvm_env)->DeleteLocalRef (jvm_env, o_dataset);
391 return (NULL);
392 }
394 status = (*jvm_env)->CallBooleanMethod (jvm_env,
395 o_dataset, m_add, o_datasource);
396 if (!status)
397 {
398 ERROR ("java plugin: ctoj_data_set: ArrayList.add returned FALSE.");
399 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
400 (*jvm_env)->DeleteLocalRef (jvm_env, o_dataset);
401 return (NULL);
402 }
404 (*jvm_env)->DeleteLocalRef (jvm_env, o_datasource);
405 } /* for (i = 0; i < ds->ds_num; i++) */
407 return (o_dataset);
408 } /* }}} jobject ctoj_data_set */
410 static int ctoj_value_list_add_value (JNIEnv *jvm_env, /* {{{ */
411 value_t value, int ds_type,
412 jclass class_ptr, jobject object_ptr)
413 {
414 jmethodID m_addvalue;
415 jobject o_number;
417 m_addvalue = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
418 "addValue", "(Ljava/lang/Number;)V");
419 if (m_addvalue == NULL)
420 {
421 ERROR ("java plugin: ctoj_value_list_add_value: "
422 "Cannot find method `void addValue (Number)'.");
423 return (-1);
424 }
426 o_number = ctoj_value_to_number (jvm_env, value, ds_type);
427 if (o_number == NULL)
428 {
429 ERROR ("java plugin: ctoj_value_list_add_value: "
430 "ctoj_value_to_number failed.");
431 return (-1);
432 }
434 (*jvm_env)->CallVoidMethod (jvm_env, object_ptr, m_addvalue, o_number);
436 (*jvm_env)->DeleteLocalRef (jvm_env, o_number);
438 return (0);
439 } /* }}} int ctoj_value_list_add_value */
441 static int ctoj_value_list_add_data_set (JNIEnv *jvm_env, /* {{{ */
442 jclass c_valuelist, jobject o_valuelist, const data_set_t *ds)
443 {
444 jmethodID m_setdatasource;
445 jobject o_dataset;
447 /* Look for the `void setDataSource (List<DataSource> ds)' method. */
448 m_setdatasource = (*jvm_env)->GetMethodID (jvm_env, c_valuelist,
449 "setDataSource", "(Ljava/util/List;)V");
450 if (m_setdatasource == NULL)
451 {
452 ERROR ("java plugin: ctoj_value_list_add_data_set: "
453 "Cannot find the `void setDataSource (List<DataSource> ds)' method.");
454 return (-1);
455 }
457 /* Create a List<DataSource> object. */
458 o_dataset = ctoj_data_set (jvm_env, ds);
459 if (o_dataset == NULL)
460 {
461 ERROR ("java plugin: ctoj_value_list_add_data_set: "
462 "ctoj_data_set (%s) failed.", ds->type);
463 return (-1);
464 }
466 /* Actually call the method. */
467 (*jvm_env)->CallVoidMethod (jvm_env,
468 o_valuelist, m_setdatasource, o_dataset);
470 /* Decrease reference counter on the List<DataSource> object. */
471 (*jvm_env)->DeleteLocalRef (jvm_env, o_dataset);
473 return (0);
474 } /* }}} int ctoj_value_list_add_data_set */
476 static jobject ctoj_value_list (JNIEnv *jvm_env, /* {{{ */
477 const data_set_t *ds, const value_list_t *vl)
478 {
479 jclass c_valuelist;
480 jmethodID m_valuelist_constructor;
481 jobject o_valuelist;
482 int status;
483 int i;
485 /* First, create a new ValueList instance..
486 * Look up the class.. */
487 c_valuelist = (*jvm_env)->FindClass (jvm_env,
488 "org.collectd.protocol.ValueList");
489 if (c_valuelist == NULL)
490 {
491 ERROR ("java plugin: ctoj_value_list: "
492 "FindClass (org.collectd.protocol.ValueList) failed.");
493 return (NULL);
494 }
496 /* Lookup the `ValueList ()' constructor. */
497 m_valuelist_constructor = (*jvm_env)->GetMethodID (jvm_env, c_valuelist,
498 "<init>", "()V");
499 if (m_valuelist_constructor == NULL)
500 {
501 ERROR ("java plugin: ctoj_value_list: Cannot find the "
502 "`ValueList ()' constructor.");
503 return (NULL);
504 }
506 /* Create a new instance. */
507 o_valuelist = (*jvm_env)->NewObject (jvm_env, c_valuelist,
508 m_valuelist_constructor);
509 if (o_valuelist == NULL)
510 {
511 ERROR ("java plugin: ctoj_value_list: Creating a new ValueList instance "
512 "failed.");
513 return (NULL);
514 }
516 status = ctoj_value_list_add_data_set (jvm_env,
517 c_valuelist, o_valuelist, ds);
518 if (status != 0)
519 {
520 ERROR ("java plugin: ctoj_value_list: "
521 "ctoj_value_list_add_data_set failed.");
522 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist);
523 return (NULL);
524 }
526 /* Set the strings.. */
527 #define SET_STRING(str,method_name) do { \
528 status = ctoj_string (jvm_env, str, \
529 c_valuelist, o_valuelist, method_name); \
530 if (status != 0) { \
531 ERROR ("java plugin: ctoj_value_list: jtoc_string (%s) failed.", \
532 method_name); \
533 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist); \
534 return (NULL); \
535 } } while (0)
537 SET_STRING (vl->host, "setHost");
538 SET_STRING (vl->plugin, "setPlugin");
539 SET_STRING (vl->plugin_instance, "setPluginInstance");
540 SET_STRING (vl->type, "setType");
541 SET_STRING (vl->type_instance, "setTypeInstance");
543 #undef SET_STRING
545 /* Set the `time' member. Java stores time in milliseconds. */
546 status = ctoj_long (jvm_env, ((jlong) vl->time) * ((jlong) 1000),
547 c_valuelist, o_valuelist, "setTime");
548 if (status != 0)
549 {
550 ERROR ("java plugin: ctoj_value_list: ctoj_long (setTime) failed.");
551 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist);
552 return (NULL);
553 }
555 /* Set the `interval' member.. */
556 status = ctoj_long (jvm_env, (jlong) vl->interval,
557 c_valuelist, o_valuelist, "setInterval");
558 if (status != 0)
559 {
560 ERROR ("java plugin: ctoj_value_list: ctoj_long (setInterval) failed.");
561 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist);
562 return (NULL);
563 }
565 for (i = 0; i < vl->values_len; i++)
566 {
567 status = ctoj_value_list_add_value (jvm_env, vl->values[i], ds->ds[i].type,
568 c_valuelist, o_valuelist);
569 if (status != 0)
570 {
571 ERROR ("java plugin: ctoj_value_list: "
572 "ctoj_value_list_add_value failed.");
573 (*jvm_env)->DeleteLocalRef (jvm_env, o_valuelist);
574 return (NULL);
575 }
576 }
578 return (o_valuelist);
579 } /* }}} int ctoj_value_list */
581 /*
582 * Java to C conversion functions
583 */
584 static int jtoc_string (JNIEnv *jvm_env, /* {{{ */
585 char *buffer, size_t buffer_size,
586 jclass class_ptr, jobject object_ptr, const char *method_name)
587 {
588 jmethodID method_id;
589 jobject string_obj;
590 const char *c_str;
592 method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
593 method_name, "()Ljava/lang/String;");
594 if (method_id == NULL)
595 {
596 ERROR ("java plugin: jtoc_string: Cannot find method `String %s ()'.",
597 method_name);
598 return (-1);
599 }
601 string_obj = (*jvm_env)->CallObjectMethod (jvm_env, object_ptr, method_id);
602 if (string_obj == NULL)
603 {
604 ERROR ("java plugin: jtoc_string: CallObjectMethod (%s) failed.",
605 method_name);
606 return (-1);
607 }
609 c_str = (*jvm_env)->GetStringUTFChars (jvm_env, string_obj, 0);
610 if (c_str == NULL)
611 {
612 ERROR ("java plugin: jtoc_string: GetStringUTFChars failed.");
613 (*jvm_env)->DeleteLocalRef (jvm_env, string_obj);
614 return (-1);
615 }
617 DEBUG ("java plugin: jtoc_string: ->%s() = %s", method_name, c_str);
619 sstrncpy (buffer, c_str, buffer_size);
621 (*jvm_env)->ReleaseStringUTFChars (jvm_env, string_obj, c_str);
622 (*jvm_env)->DeleteLocalRef (jvm_env, string_obj);
624 return (0);
625 } /* }}} int jtoc_string */
627 static int jtoc_long (JNIEnv *jvm_env, /* {{{ */
628 jlong *ret_value,
629 jclass class_ptr, jobject object_ptr, const char *method_name)
630 {
631 jmethodID method_id;
633 method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
634 method_name, "()J");
635 if (method_id == NULL)
636 {
637 ERROR ("java plugin: jtoc_long: Cannot find method `long %s ()'.",
638 method_name);
639 return (-1);
640 }
642 *ret_value = (*jvm_env)->CallLongMethod (jvm_env, object_ptr, method_id);
644 DEBUG ("java plugin: jtoc_long: ->%s() = %li",
645 method_name, (long int) *ret_value);
647 return (0);
648 } /* }}} int jtoc_long */
650 static int jtoc_double (JNIEnv *jvm_env, /* {{{ */
651 jdouble *ret_value,
652 jclass class_ptr, jobject object_ptr, const char *method_name)
653 {
654 jmethodID method_id;
656 method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
657 method_name, "()D");
658 if (method_id == NULL)
659 {
660 ERROR ("java plugin: jtoc_string: Cannot find method `double %s ()'.",
661 method_name);
662 return (-1);
663 }
665 *ret_value = (*jvm_env)->CallDoubleMethod (jvm_env, object_ptr, method_id);
667 DEBUG ("java plugin: jtoc_double: ->%s() = %g",
668 method_name, (double) *ret_value);
670 return (0);
671 } /* }}} int jtoc_double */
673 static int jtoc_value (JNIEnv *jvm_env, /* {{{ */
674 value_t *ret_value, int ds_type, jobject object_ptr)
675 {
676 jclass class_ptr;
677 int status;
679 class_ptr = (*jvm_env)->GetObjectClass (jvm_env, object_ptr);
681 if (ds_type == DS_TYPE_COUNTER)
682 {
683 jlong tmp_long;
685 status = jtoc_long (jvm_env, &tmp_long,
686 class_ptr, object_ptr, "longValue");
687 if (status != 0)
688 {
689 ERROR ("java plugin: jtoc_value: "
690 "jtoc_long failed.");
691 return (-1);
692 }
693 (*ret_value).counter = (counter_t) tmp_long;
694 }
695 else
696 {
697 jdouble tmp_double;
699 status = jtoc_double (jvm_env, &tmp_double,
700 class_ptr, object_ptr, "doubleValue");
701 if (status != 0)
702 {
703 ERROR ("java plugin: jtoc_value: "
704 "jtoc_double failed.");
705 return (-1);
706 }
707 (*ret_value).gauge = (gauge_t) tmp_double;
708 }
710 return (0);
711 } /* }}} int jtoc_value */
713 static int jtoc_values_array (JNIEnv *jvm_env, /* {{{ */
714 const data_set_t *ds, value_list_t *vl,
715 jclass class_ptr, jobject object_ptr)
716 {
717 jmethodID m_getvalues;
718 jmethodID m_toarray;
719 jobject o_list;
720 jobjectArray o_number_array;
722 value_t *values;
723 int values_num;
724 int i;
726 values_num = ds->ds_num;
728 values = NULL;
729 o_number_array = NULL;
730 o_list = NULL;
732 #define BAIL_OUT(status) \
733 free (values); \
734 if (o_number_array != NULL) \
735 (*jvm_env)->DeleteLocalRef (jvm_env, o_number_array); \
736 if (o_list != NULL) \
737 (*jvm_env)->DeleteLocalRef (jvm_env, o_list); \
738 return (status);
740 /* Call: List<Number> ValueList.getValues () */
741 m_getvalues = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
742 "getValues", "()Ljava/util/List;");
743 if (m_getvalues == NULL)
744 {
745 ERROR ("java plugin: jtoc_values_array: "
746 "Cannot find method `List getValues ()'.");
747 BAIL_OUT (-1);
748 }
750 o_list = (*jvm_env)->CallObjectMethod (jvm_env, object_ptr, m_getvalues);
751 if (o_list == NULL)
752 {
753 ERROR ("java plugin: jtoc_values_array: "
754 "CallObjectMethod (getValues) failed.");
755 BAIL_OUT (-1);
756 }
758 /* Call: Number[] List.toArray () */
759 m_toarray = (*jvm_env)->GetMethodID (jvm_env,
760 (*jvm_env)->GetObjectClass (jvm_env, o_list),
761 "toArray", "()[Ljava/lang/Object;");
762 if (m_toarray == NULL)
763 {
764 ERROR ("java plugin: jtoc_values_array: "
765 "Cannot find method `Object[] toArray ()'.");
766 BAIL_OUT (-1);
767 }
769 o_number_array = (*jvm_env)->CallObjectMethod (jvm_env, o_list, m_toarray);
770 if (o_number_array == NULL)
771 {
772 ERROR ("java plugin: jtoc_values_array: "
773 "CallObjectMethod (toArray) failed.");
774 BAIL_OUT (-1);
775 }
777 values = calloc (values_num, sizeof (value_t));
778 if (values == NULL)
779 {
780 ERROR ("java plugin: jtoc_values_array: calloc failed.");
781 BAIL_OUT (-1);
782 }
784 for (i = 0; i < values_num; i++)
785 {
786 jobject o_number;
787 int status;
789 o_number = (*jvm_env)->GetObjectArrayElement (jvm_env,
790 o_number_array, (jsize) i);
791 if (o_number == NULL)
792 {
793 ERROR ("java plugin: jtoc_values_array: "
794 "GetObjectArrayElement (%i) failed.", i);
795 BAIL_OUT (-1);
796 }
798 status = jtoc_value (jvm_env, values + i, ds->ds[i].type, o_number);
799 if (status != 0)
800 {
801 ERROR ("java plugin: jtoc_values_array: "
802 "jtoc_value (%i) failed.", i);
803 BAIL_OUT (-1);
804 }
805 } /* for (i = 0; i < values_num; i++) */
807 vl->values = values;
808 vl->values_len = values_num;
810 #undef BAIL_OUT
811 (*jvm_env)->DeleteLocalRef (jvm_env, o_number_array);
812 (*jvm_env)->DeleteLocalRef (jvm_env, o_list);
813 return (0);
814 } /* }}} int jtoc_values_array */
816 /* Convert a org.collectd.protocol.ValueList to a value_list_t. */
817 static int jtoc_value_list (JNIEnv *jvm_env, value_list_t *vl, /* {{{ */
818 jobject object_ptr)
819 {
820 jclass class_ptr;
821 int status;
822 jlong tmp_long;
823 const data_set_t *ds;
825 class_ptr = (*jvm_env)->GetObjectClass (jvm_env, object_ptr);
826 if (class_ptr == NULL)
827 {
828 ERROR ("java plugin: jtoc_value_list: GetObjectClass failed.");
829 return (-1);
830 }
832 #define SET_STRING(buffer,method) do { \
833 status = jtoc_string (jvm_env, buffer, sizeof (buffer), \
834 class_ptr, object_ptr, method); \
835 if (status != 0) { \
836 ERROR ("java plugin: jtoc_value_list: jtoc_string (%s) failed.", \
837 method); \
838 return (-1); \
839 } } while (0)
841 SET_STRING(vl->type, "getType");
843 ds = plugin_get_ds (vl->type);
844 if (ds == NULL)
845 {
846 ERROR ("java plugin: jtoc_value_list: Data-set `%s' is not defined. "
847 "Please consult the types.db(5) manpage for mor information.",
848 vl->type);
849 return (-1);
850 }
852 SET_STRING(vl->host, "getHost");
853 SET_STRING(vl->plugin, "getPlugin");
854 SET_STRING(vl->plugin_instance, "getPluginInstance");
855 SET_STRING(vl->type_instance, "getTypeInstance");
857 #undef SET_STRING
859 status = jtoc_long (jvm_env, &tmp_long, class_ptr, object_ptr, "getTime");
860 if (status != 0)
861 {
862 ERROR ("java plugin: jtoc_value_list: jtoc_long (getTime) failed.");
863 return (-1);
864 }
865 vl->time = (time_t) tmp_long;
867 status = jtoc_long (jvm_env, &tmp_long,
868 class_ptr, object_ptr, "getInterval");
869 if (status != 0)
870 {
871 ERROR ("java plugin: jtoc_value_list: jtoc_long (getInterval) failed.");
872 return (-1);
873 }
874 vl->interval = (int) tmp_long;
876 status = jtoc_values_array (jvm_env, ds, vl, class_ptr, object_ptr);
877 if (status != 0)
878 {
879 ERROR ("java plugin: jtoc_value_list: jtoc_values_array failed.");
880 return (-1);
881 }
883 return (0);
884 } /* }}} int jtoc_value_list */
886 /*
887 * Functions accessible from Java
888 */
889 static jint JNICALL cjni_api_dispatch_values (JNIEnv *jvm_env, /* {{{ */
890 jobject this, jobject java_vl)
891 {
892 value_list_t vl = VALUE_LIST_INIT;
893 int status;
895 DEBUG ("cjni_api_dispatch_values: java_vl = %p;", (void *) java_vl);
897 status = jtoc_value_list (jvm_env, &vl, java_vl);
898 if (status != 0)
899 {
900 ERROR ("java plugin: cjni_api_dispatch_values: jtoc_value_list failed.");
901 return (-1);
902 }
904 plugin_dispatch_values (&vl);
906 sfree (vl.values);
908 return (0);
909 } /* }}} jint cjni_api_dispatch_values */
911 static JNINativeMethod jni_api_functions[] =
912 {
913 { "DispatchValues", "(Lorg/collectd/protocol/ValueList;)I", cjni_api_dispatch_values }
914 };
915 static size_t jni_api_functions_num = sizeof (jni_api_functions)
916 / sizeof (jni_api_functions[0]);
918 /*
919 * Functions
920 */
921 static int cjni_config_add_jvm_arg (oconfig_item_t *ci) /* {{{ */
922 {
923 char **tmp;
925 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
926 {
927 WARNING ("java plugin: `JVMArg' needs exactly one string argument.");
928 return (-1);
929 }
931 tmp = (char **) realloc (jvm_argv, sizeof (char *) * (jvm_argc + 1));
932 if (tmp == NULL)
933 {
934 ERROR ("java plugin: realloc failed.");
935 return (-1);
936 }
937 jvm_argv = tmp;
939 jvm_argv[jvm_argc] = strdup (ci->values[0].value.string);
940 if (jvm_argv[jvm_argc] == NULL)
941 {
942 ERROR ("java plugin: strdup failed.");
943 return (-1);
944 }
945 jvm_argc++;
947 return (0);
948 } /* }}} int cjni_config_add_jvm_arg */
950 static int cjni_config_load_plugin (oconfig_item_t *ci) /* {{{ */
951 {
952 java_plugin_t *jp;
954 if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
955 {
956 WARNING ("java plugin: `LoadPlugin' needs exactly one string argument.");
957 return (-1);
958 }
960 jp = (java_plugin_t *) realloc (java_plugins,
961 sizeof (*java_plugins) * (java_plugins_num + 1));
962 if (jp == NULL)
963 {
964 ERROR ("java plugin: realloc failed.");
965 return (-1);
966 }
967 java_plugins = jp;
968 jp = java_plugins + java_plugins_num;
970 memset (jp, 0, sizeof (*jp));
971 jp->class_name = strdup (ci->values[0].value.string);
972 if (jp->class_name == NULL)
973 {
974 ERROR ("java plugin: strdup failed.");
975 return (-1);
976 }
978 jp->class_ptr = NULL;
979 jp->object_ptr = NULL;
980 jp->flags = 0;
981 jp->m_init = NULL;
982 jp->m_read = NULL;
983 jp->m_write = NULL;
984 jp->m_shutdown = NULL;
986 java_plugins_num++;
988 return (0);
989 } /* }}} int cjni_config_load_plugin */
991 static int cjni_config (oconfig_item_t *ci) /* {{{ */
992 {
993 int success;
994 int errors;
995 int status;
996 int i;
998 success = 0;
999 errors = 0;
1001 for (i = 0; i < ci->children_num; i++)
1002 {
1003 oconfig_item_t *child = ci->children + i;
1005 if (strcasecmp ("JVMArg", child->key) == 0)
1006 {
1007 status = cjni_config_add_jvm_arg (child);
1008 if (status == 0)
1009 success++;
1010 else
1011 errors++;
1012 }
1013 else if (strcasecmp ("LoadPlugin", child->key) == 0)
1014 {
1015 status = cjni_config_load_plugin (child);
1016 if (status == 0)
1017 success++;
1018 else
1019 errors++;
1020 }
1021 else
1022 {
1023 WARNING ("java plugin: Option `%s' not allowed here.", child->key);
1024 errors++;
1025 }
1026 }
1028 if ((success == 0) && (errors > 0))
1029 {
1030 ERROR ("java plugin: All statements failed.");
1031 return (-1);
1032 }
1034 return (0);
1035 } /* }}} int cjni_config */
1037 static int cjni_init_one_plugin (JNIEnv *jvm_env, java_plugin_t *jp) /* {{{ */
1038 {
1039 jmethodID constructor_id;
1040 int status;
1042 jp->class_ptr = (*jvm_env)->FindClass (jvm_env, jp->class_name);
1043 if (jp->class_ptr == NULL)
1044 {
1045 ERROR ("cjni_init_one_plugin: FindClass (%s) failed.",
1046 jp->class_name);
1047 return (-1);
1048 }
1050 constructor_id = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1051 "<init>", "()V");
1052 if (constructor_id == NULL)
1053 {
1054 ERROR ("cjni_init_one_plugin: Could not find the constructor for `%s'.",
1055 jp->class_name);
1056 return (-1);
1057 }
1059 jp->object_ptr = (*jvm_env)->NewObject (jvm_env, jp->class_ptr,
1060 constructor_id);
1061 if (jp->object_ptr == NULL)
1062 {
1063 ERROR ("cjni_init_one_plugin: Could create a new `%s' object.",
1064 jp->class_name);
1065 return (-1);
1066 }
1068 jp->m_init = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1069 "Init", "()I");
1070 DEBUG ("java plugin: cjni_init_one_plugin: "
1071 "jp->class_name = %s; jp->m_init = %p;",
1072 jp->class_name, (void *) jp->m_init);
1074 jp->m_read = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1075 "Read", "()I");
1076 DEBUG ("java plugin: cjni_init_one_plugin: "
1077 "jp->class_name = %s; jp->m_read = %p;",
1078 jp->class_name, (void *) jp->m_read);
1080 jp->m_write = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1081 "Write", "(Lorg/collectd/protocol/ValueList;)I");
1082 DEBUG ("java plugin: cjni_init_one_plugin: "
1083 "jp->class_name = %s; jp->m_write = %p;",
1084 jp->class_name, (void *) jp->m_write);
1086 jp->m_shutdown = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
1087 "Shutdown", "()I");
1088 DEBUG ("java plugin: cjni_init_one_plugin: "
1089 "jp->class_name = %s; jp->m_shutdown = %p;",
1090 jp->class_name, (void *) jp->m_shutdown);
1092 if (jp->m_init != NULL)
1093 {
1094 status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
1095 jp->m_init);
1096 if (status != 0)
1097 {
1098 ERROR ("cjni_init_one_plugin: Initializing `%s' object failed "
1099 "with status %i.", jp->class_name, status);
1100 return (-1);
1101 }
1102 }
1103 jp->flags |= CJNI_FLAG_ENABLED;
1105 return (0);
1106 } /* }}} int cjni_init_one_plugin */
1108 static int cjni_init_plugins (JNIEnv *jvm_env) /* {{{ */
1109 {
1110 size_t j;
1112 for (j = 0; j < java_plugins_num; j++)
1113 cjni_init_one_plugin (jvm_env, &java_plugins[j]);
1115 return (0);
1116 } /* }}} int cjni_init_plugins */
1118 static int cjni_init_native (JNIEnv *jvm_env) /* {{{ */
1119 {
1120 jclass api_class_ptr;
1121 int status;
1123 api_class_ptr = (*jvm_env)->FindClass (jvm_env, "org.collectd.api.CollectdAPI");
1124 if (api_class_ptr == NULL)
1125 {
1126 ERROR ("cjni_init_native: Cannot find API class `org.collectd.api.CollectdAPI'.");
1127 return (-1);
1128 }
1130 status = (*jvm_env)->RegisterNatives (jvm_env, api_class_ptr,
1131 jni_api_functions, (jint) jni_api_functions_num);
1132 if (status != 0)
1133 {
1134 ERROR ("cjni_init_native: RegisterNatives failed with status %i.", status);
1135 return (-1);
1136 }
1138 return (0);
1139 } /* }}} int cjni_init_native */
1141 static int cjni_init (void) /* {{{ */
1142 {
1143 JNIEnv *jvm_env;
1144 JavaVMInitArgs vm_args;
1145 JavaVMOption vm_options[jvm_argc];
1147 int status;
1148 size_t i;
1150 if (jvm != NULL)
1151 return (0);
1153 jvm_env = NULL;
1155 memset (&vm_args, 0, sizeof (vm_args));
1156 vm_args.version = JNI_VERSION_1_2;
1157 vm_args.options = vm_options;
1158 vm_args.nOptions = (jint) jvm_argc;
1160 for (i = 0; i < jvm_argc; i++)
1161 {
1162 DEBUG ("java plugin: cjni_init: jvm_argv[%zu] = %s", i, jvm_argv[i]);
1163 vm_args.options[i].optionString = jvm_argv[i];
1164 }
1165 /*
1166 vm_args.options[0].optionString = "-verbose:jni";
1167 vm_args.options[1].optionString = "-Djava.class.path=/home/octo/collectd/bindings/java";
1168 */
1170 status = JNI_CreateJavaVM (&jvm, (void **) &jvm_env, (void **) &vm_args);
1171 if (status != 0)
1172 {
1173 ERROR ("cjni_init: JNI_CreateJavaVM failed with status %i.",
1174 status);
1175 return (-1);
1176 }
1177 assert (jvm != NULL);
1178 assert (jvm_env != NULL);
1180 /* Call RegisterNatives */
1181 status = cjni_init_native (jvm_env);
1182 if (status != 0)
1183 {
1184 ERROR ("cjni_init: cjni_init_native failed.");
1185 return (-1);
1186 }
1188 cjni_init_plugins (jvm_env);
1190 return (0);
1191 } /* }}} int cjni_init */
1193 static int cjni_read_one_plugin (JNIEnv *jvm_env, java_plugin_t *jp) /* {{{ */
1194 {
1195 int status;
1197 if ((jp == NULL)
1198 || ((jp->flags & CJNI_FLAG_ENABLED) == 0)
1199 || (jp->m_read == NULL))
1200 return (0);
1202 DEBUG ("java plugin: Calling: %s.Read()", jp->class_name);
1204 status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
1205 jp->m_read);
1206 if (status != 0)
1207 {
1208 ERROR ("java plugin: cjni_read_one_plugin: "
1209 "Calling `Read' on an `%s' object failed with status %i.",
1210 jp->class_name, status);
1211 return (-1);
1212 }
1214 return (0);
1215 } /* }}} int cjni_read_one_plugin */
1217 static int cjni_read_plugins (JNIEnv *jvm_env) /* {{{ */
1218 {
1219 size_t j;
1221 for (j = 0; j < java_plugins_num; j++)
1222 cjni_read_one_plugin (jvm_env, &java_plugins[j]);
1224 return (0);
1225 } /* }}} int cjni_read_plugins */
1227 static int cjni_read (void) /* {{{ */
1228 {
1229 JNIEnv *jvm_env;
1230 JavaVMAttachArgs args;
1231 int status;
1233 if (jvm == NULL)
1234 {
1235 ERROR ("java plugin: cjni_read: jvm == NULL");
1236 return (-1);
1237 }
1239 jvm_env = NULL;
1240 memset (&args, 0, sizeof (args));
1241 args.version = JNI_VERSION_1_2;
1243 status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args);
1244 if (status != 0)
1245 {
1246 ERROR ("java plugin: cjni_read: AttachCurrentThread failed with status %i.",
1247 status);
1248 return (-1);
1249 }
1251 cjni_read_plugins (jvm_env);
1253 status = (*jvm)->DetachCurrentThread (jvm);
1254 if (status != 0)
1255 {
1256 ERROR ("java plugin: cjni_read: DetachCurrentThread failed with status %i.",
1257 status);
1258 return (-1);
1259 }
1261 return (0);
1262 } /* }}} int cjni_read */
1264 static int cjni_write_one_plugin (JNIEnv *jvm_env, /* {{{ */
1265 java_plugin_t *jp, jobject vl_java)
1266 {
1267 int status;
1269 if ((jp == NULL)
1270 || ((jp->flags & CJNI_FLAG_ENABLED) == 0)
1271 || (jp->m_write == NULL))
1272 return (0);
1274 DEBUG ("java plugin: Calling: %s.Write(ValueList)", jp->class_name);
1276 status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
1277 jp->m_write, vl_java);
1278 if (status != 0)
1279 {
1280 ERROR ("java plugin: cjni_write_one_plugin: "
1281 "Calling `Write' on an `%s' object failed with status %i.",
1282 jp->class_name, status);
1283 return (-1);
1284 }
1286 return (0);
1287 } /* }}} int cjni_write_one_plugin */
1289 static int cjni_write_plugins (JNIEnv *jvm_env, /* {{{ */
1290 const data_set_t *ds, const value_list_t *vl)
1291 {
1292 size_t j;
1294 jobject vl_java;
1296 vl_java = ctoj_value_list (jvm_env, ds, vl);
1297 if (vl_java == NULL)
1298 {
1299 ERROR ("java plugin: cjni_write_plugins: ctoj_value_list failed.");
1300 return (-1);
1301 }
1303 for (j = 0; j < java_plugins_num; j++)
1304 cjni_write_one_plugin (jvm_env, &java_plugins[j], vl_java);
1306 (*jvm_env)->DeleteLocalRef (jvm_env, vl_java);
1308 return (0);
1309 } /* }}} int cjni_write_plugins */
1311 static int cjni_write (const data_set_t *ds, const value_list_t *vl) /* {{{ */
1312 {
1313 JNIEnv *jvm_env;
1314 JavaVMAttachArgs args;
1315 int status;
1317 if (jvm == NULL)
1318 {
1319 ERROR ("java plugin: cjni_write: jvm == NULL");
1320 return (-1);
1321 }
1323 jvm_env = NULL;
1324 memset (&args, 0, sizeof (args));
1325 args.version = JNI_VERSION_1_2;
1327 status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args);
1328 if (status != 0)
1329 {
1330 ERROR ("java plugin: cjni_write: AttachCurrentThread failed with status %i.",
1331 status);
1332 return (-1);
1333 }
1335 cjni_write_plugins (jvm_env, ds, vl);
1337 status = (*jvm)->DetachCurrentThread (jvm);
1338 if (status != 0)
1339 {
1340 ERROR ("java plugin: cjni_write: DetachCurrentThread failed with status %i.",
1341 status);
1342 return (-1);
1343 }
1345 return (0);
1346 } /* }}} int cjni_write */
1348 static int cjni_shutdown_one_plugin (JNIEnv *jvm_env, /* {{{ */
1349 java_plugin_t *jp)
1350 {
1351 int status;
1353 if ((jp == NULL)
1354 || ((jp->flags & CJNI_FLAG_ENABLED) == 0)
1355 || (jp->m_shutdown == NULL))
1356 return (0);
1358 status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
1359 jp->m_shutdown);
1360 if (status != 0)
1361 {
1362 ERROR ("cjni_shutdown_one_plugin: Destroying an `%s' object failed "
1363 "with status %i.", jp->class_name, status);
1364 return (-1);
1365 }
1366 jp->flags &= ~CJNI_FLAG_ENABLED;
1368 return (0);
1369 } /* }}} int cjni_shutdown_one_plugin */
1371 static int cjni_shutdown_plugins (JNIEnv *jvm_env) /* {{{ */
1372 {
1373 size_t j;
1375 for (j = 0; j < java_plugins_num; j++)
1376 cjni_shutdown_one_plugin (jvm_env, &java_plugins[j]);
1378 return (0);
1379 } /* }}} int cjni_shutdown_plugins */
1381 static int cjni_shutdown (void) /* {{{ */
1382 {
1383 JNIEnv *jvm_env;
1384 JavaVMAttachArgs args;
1385 int status;
1386 size_t i;
1388 if (jvm == NULL)
1389 return (0);
1391 jvm_env = NULL;
1392 memset (&args, 0, sizeof (args));
1393 args.version = JNI_VERSION_1_2;
1395 status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args);
1396 if (status != 0)
1397 {
1398 ERROR ("java plugin: cjni_read: AttachCurrentThread failed with status %i.",
1399 status);
1400 return (-1);
1401 }
1403 cjni_shutdown_plugins (jvm_env);
1405 (*jvm)->DestroyJavaVM (jvm);
1406 jvm = NULL;
1407 jvm_env = NULL;
1409 for (i = 0; i < jvm_argc; i++)
1410 {
1411 sfree (jvm_argv[i]);
1412 }
1413 sfree (jvm_argv);
1414 jvm_argc = 0;
1416 for (i = 0; i < java_plugins_num; i++)
1417 {
1418 sfree (java_plugins[i].class_name);
1419 }
1420 sfree (java_plugins);
1421 java_plugins_num = 0;
1423 return (0);
1424 } /* }}} int cjni_shutdown */
1426 void module_register (void)
1427 {
1428 plugin_register_complex_config ("java", cjni_config);
1429 plugin_register_init ("java", cjni_init);
1430 plugin_register_read ("java", cjni_read);
1431 plugin_register_write ("java", cjni_write);
1432 plugin_register_shutdown ("java", cjni_shutdown);
1433 } /* void module_register (void) */
1435 /* vim: set sw=2 sts=2 et fdm=marker : */