From fb9f56e5af1a63d94c80a2ea6f067aeb7787f397 Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Mon, 23 Feb 2009 14:57:56 +0100 Subject: [PATCH] java plugin: Add support for `notification' callbacks. --- bindings/java/org/collectd/api/Collectd.java | 6 + .../api/CollectdNotificationInterface.java | 33 ++++ src/collectd-java.pod | 24 +++ src/java.c | 214 +++++++++++++++++++-- 4 files changed, 260 insertions(+), 17 deletions(-) create mode 100644 bindings/java/org/collectd/api/CollectdNotificationInterface.java diff --git a/bindings/java/org/collectd/api/Collectd.java b/bindings/java/org/collectd/api/Collectd.java index eb96969a..92ddec02 100644 --- a/bindings/java/org/collectd/api/Collectd.java +++ b/bindings/java/org/collectd/api/Collectd.java @@ -77,6 +77,12 @@ public class Collectd CollectdLogInterface object); /** + * Java representation of collectd/src/plugin.h:plugin_register_notification + */ + native public static int registerNotification (String name, + CollectdNotificationInterface object); + + /** * Java representation of collectd/src/plugin.h:plugin_dispatch_values */ native public static int dispatchValues (ValueList vl); diff --git a/bindings/java/org/collectd/api/CollectdNotificationInterface.java b/bindings/java/org/collectd/api/CollectdNotificationInterface.java new file mode 100644 index 00000000..4a18975d --- /dev/null +++ b/bindings/java/org/collectd/api/CollectdNotificationInterface.java @@ -0,0 +1,33 @@ +/* + * collectd/java - org/collectd/api/CollectdNotificationInterface.java + * Copyright (C) 2009 Florian octo Forster + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; only version 2 of the License is applicable. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + */ + +package org.collectd.api; + +/** + * Interface for objects implementing a notification function. + * + * @author Florian Forster <octo at verplant.org> + * @see Collectd#registerNotification + */ +public interface CollectdNotificationInterface +{ + public int notification (Notification n); +} diff --git a/src/collectd-java.pod b/src/collectd-java.pod index 72ce0b69..773130ac 100644 --- a/src/collectd-java.pod +++ b/src/collectd-java.pod @@ -61,6 +61,10 @@ Corresponds to C, defined in F. Corresponds to C, defined in F. +=item B + +Corresponds to C, defined in F. + =back In the remainder of this document, we'll use the short form of these names, for @@ -217,6 +221,17 @@ org.collectd.api.Collectd.LOG_DEBUG The function does not return any value. +=head2 notification callback + +Interface: B + +Signature: I B (I n) + +This callback can be used to receive notifications from the daemon. + +To signal success, this method has to return zero. Anything else will be +considered an error condition and cause an appropriate message to be logged. + =head2 Example This short example demonstrates how to register a read callback with the @@ -316,6 +331,15 @@ Registers the B function of I with the daemon. Returns zero upon success and non-zero when an error occurred. +=head2 registerNotification + +Signature: I B (I name, +I object); + +Registers the B function of I with the daemon. + +Returns zero upon success and non-zero when an error occurred. + =head2 dispatchValues Signature: I B (I) diff --git a/src/java.c b/src/java.c index fc332e50..2d310c6f 100644 --- a/src/java.c +++ b/src/java.c @@ -60,13 +60,14 @@ struct java_plugin_config_s /* {{{ */ typedef struct java_plugin_config_s java_plugin_config_t; /* }}} */ -#define CB_TYPE_CONFIG 1 -#define CB_TYPE_INIT 2 -#define CB_TYPE_READ 3 -#define CB_TYPE_WRITE 4 -#define CB_TYPE_FLUSH 5 -#define CB_TYPE_SHUTDOWN 6 -#define CB_TYPE_LOG 7 +#define CB_TYPE_CONFIG 1 +#define CB_TYPE_INIT 2 +#define CB_TYPE_READ 3 +#define CB_TYPE_WRITE 4 +#define CB_TYPE_FLUSH 5 +#define CB_TYPE_SHUTDOWN 6 +#define CB_TYPE_LOG 7 +#define CB_TYPE_NOTIFICATION 8 struct cjni_callback_info_s /* {{{ */ { char *name; @@ -117,6 +118,7 @@ static int cjni_write (const data_set_t *ds, const value_list_t *vl, user_data_t *ud); static int cjni_flush (int timeout, const char *identifier, user_data_t *ud); static void cjni_log (int severity, const char *message, user_data_t *ud); +static int cjni_notification (const notification_t *n, user_data_t *ud); /* * C to Java conversion functions @@ -836,7 +838,90 @@ static jobject ctoj_value_list (JNIEnv *jvm_env, /* {{{ */ } return (o_valuelist); -} /* }}} int ctoj_value_list */ +} /* }}} jobject ctoj_value_list */ + +/* Convert a notification_t to a org.collectd.api.Notification */ +static jobject ctoj_notification (JNIEnv *jvm_env, /* {{{ */ + const notification_t *n) +{ + jclass c_notification; + jmethodID m_constructor; + jobject o_notification; + int status; + + /* First, create a new Notification instance.. + * Look up the class.. */ + c_notification = (*jvm_env)->FindClass (jvm_env, + "org.collectd.api.Notification"); + if (c_notification == NULL) + { + ERROR ("java plugin: ctoj_notification: " + "FindClass (org.collectd.api.Notification) failed."); + return (NULL); + } + + /* Lookup the `Notification ()' constructor. */ + m_constructor = (*jvm_env)->GetMethodID (jvm_env, c_notification, + "", "()V"); + if (m_constructor == NULL) + { + ERROR ("java plugin: ctoj_notification: Cannot find the " + "`Notification ()' constructor."); + return (NULL); + } + + /* Create a new instance. */ + o_notification = (*jvm_env)->NewObject (jvm_env, c_notification, + m_constructor); + if (o_notification == NULL) + { + ERROR ("java plugin: ctoj_notification: Creating a new Notification " + "instance failed."); + return (NULL); + } + + /* Set the strings.. */ +#define SET_STRING(str,method_name) do { \ + status = ctoj_string (jvm_env, str, \ + c_notification, o_notification, method_name); \ + if (status != 0) { \ + ERROR ("java plugin: ctoj_notification: jtoc_string (%s) failed.", \ + method_name); \ + (*jvm_env)->DeleteLocalRef (jvm_env, o_notification); \ + return (NULL); \ + } } while (0) + + SET_STRING (n->host, "setHost"); + SET_STRING (n->plugin, "setPlugin"); + SET_STRING (n->plugin_instance, "setPluginInstance"); + SET_STRING (n->type, "setType"); + SET_STRING (n->type_instance, "setTypeInstance"); + SET_STRING (n->message, "setMessage"); + +#undef SET_STRING + + /* Set the `time' member. Java stores time in milliseconds. */ + status = ctoj_long (jvm_env, ((jlong) n->time) * ((jlong) 1000), + c_notification, o_notification, "setTime"); + if (status != 0) + { + ERROR ("java plugin: ctoj_notification: ctoj_long (setTime) failed."); + (*jvm_env)->DeleteLocalRef (jvm_env, o_notification); + return (NULL); + } + + /* Set the `interval' member.. */ + status = ctoj_int (jvm_env, (jint) n->severity, + c_notification, o_notification, "setSeverity"); + if (status != 0) + { + ERROR ("java plugin: ctoj_notification: ctoj_int (setSeverity) failed."); + (*jvm_env)->DeleteLocalRef (jvm_env, o_notification); + return (NULL); + } + + return (o_notification); +} /* }}} jobject ctoj_notification */ /* * Java to C conversion functions @@ -1304,6 +1389,30 @@ static jint JNICALL cjni_api_register_log (JNIEnv *jvm_env, /* {{{ */ return (0); } /* }}} jint cjni_api_register_log */ +static jint JNICALL cjni_api_register_notification (JNIEnv *jvm_env, /* {{{ */ + jobject this, jobject o_name, jobject o_notification) +{ + user_data_t ud; + cjni_callback_info_t *cbi; + + cbi = cjni_callback_info_create (jvm_env, o_name, o_notification, + CB_TYPE_NOTIFICATION); + if (cbi == NULL) + return (-1); + + DEBUG ("java plugin: Registering new notification callback: %s", cbi->name); + + memset (&ud, 0, sizeof (ud)); + ud.data = (void *) cbi; + ud.free_func = cjni_callback_info_destroy; + + plugin_register_notification (cbi->name, cjni_notification, &ud); + + (*jvm_env)->DeleteLocalRef (jvm_env, o_notification); + + return (0); +} /* }}} jint cjni_api_register_notification */ + static void JNICALL cjni_api_log (JNIEnv *jvm_env, /* {{{ */ jobject this, jint severity, jobject o_message) { @@ -1366,6 +1475,10 @@ static JNINativeMethod jni_api_functions[] = /* {{{ */ "(Ljava/lang/String;Lorg/collectd/api/CollectdLogInterface;)I", cjni_api_register_log }, + { "registerNotification", + "(Ljava/lang/String;Lorg/collectd/api/CollectdNotificationInterface;)I", + cjni_api_register_notification }, + { "log", "(ILjava/lang/String;)V", cjni_api_log }, @@ -1424,6 +1537,11 @@ static cjni_callback_info_t *cjni_callback_info_create (JNIEnv *jvm_env, /* {{{ method_signature = "(ILjava/lang/String;)V"; break; + case CB_TYPE_NOTIFICATION: + method_name = "notification"; + method_signature = "(LLorg/collectd/api/Notification;)I"; + break; + default: ERROR ("java plugin: cjni_callback_info_create: Unknown type: %#x", type); @@ -1866,6 +1984,15 @@ static void cjni_callback_info_destroy (void *arg) /* {{{ */ DEBUG ("java plugin: cjni_callback_info_destroy (arg = %p);", arg); + cbi = (cjni_callback_info_t *) arg; + + /* This condition can occurr when shutting down. */ + if (jvm == NULL) + { + sfree (cbi); + return; + } + if (arg == NULL) return; @@ -1876,8 +2003,6 @@ static void cjni_callback_info_destroy (void *arg) /* {{{ */ return; } - cbi = (cjni_callback_info_t *) arg; - (*jvm_env)->DeleteGlobalRef (jvm_env, cbi->object); cbi->method = NULL; @@ -1894,6 +2019,7 @@ static int cjni_read (user_data_t *ud) /* {{{ */ JNIEnv *jvm_env; cjni_callback_info_t *cbi; int status; + int ret_status; if (jvm == NULL) { @@ -1913,7 +2039,7 @@ static int cjni_read (user_data_t *ud) /* {{{ */ cbi = (cjni_callback_info_t *) ud->data; - status = (*jvm_env)->CallIntMethod (jvm_env, cbi->object, + ret_status = (*jvm_env)->CallIntMethod (jvm_env, cbi->object, cbi->method); status = cjni_thread_detach (); @@ -1923,7 +2049,7 @@ static int cjni_read (user_data_t *ud) /* {{{ */ return (-1); } - return (status); + return (ret_status); } /* }}} int cjni_read */ /* Call the CB_TYPE_WRITE callback pointed to by the `user_data_t' pointer. */ @@ -1934,6 +2060,7 @@ static int cjni_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */ cjni_callback_info_t *cbi; jobject vl_java; int status; + int ret_status; if (jvm == NULL) { @@ -1960,7 +2087,7 @@ static int cjni_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */ return (-1); } - status = (*jvm_env)->CallIntMethod (jvm_env, + ret_status = (*jvm_env)->CallIntMethod (jvm_env, cbi->object, cbi->method, vl_java); (*jvm_env)->DeleteLocalRef (jvm_env, vl_java); @@ -1972,7 +2099,7 @@ static int cjni_write (const data_set_t *ds, const value_list_t *vl, /* {{{ */ return (-1); } - return (status); + return (ret_status); } /* }}} int cjni_write */ /* Call the CB_TYPE_FLUSH callback pointed to by the `user_data_t' pointer. */ @@ -1983,6 +2110,7 @@ static int cjni_flush (int timeout, const char *identifier, /* {{{ */ cjni_callback_info_t *cbi; jobject o_identifier; int status; + int ret_status; if (jvm == NULL) { @@ -2013,7 +2141,7 @@ static int cjni_flush (int timeout, const char *identifier, /* {{{ */ } } - status = (*jvm_env)->CallIntMethod (jvm_env, + ret_status = (*jvm_env)->CallIntMethod (jvm_env, cbi->object, cbi->method, (jint) timeout, o_identifier); (*jvm_env)->DeleteLocalRef (jvm_env, o_identifier); @@ -2025,7 +2153,7 @@ static int cjni_flush (int timeout, const char *identifier, /* {{{ */ return (-1); } - return (status); + return (ret_status); } /* }}} int cjni_flush */ /* Call the CB_TYPE_LOG callback pointed to by the `user_data_t' pointer. */ @@ -2058,7 +2186,58 @@ static void cjni_log (int severity, const char *message, /* {{{ */ (*jvm_env)->DeleteLocalRef (jvm_env, o_message); cjni_thread_detach (); -} /* }}} int cjni_log */ +} /* }}} void cjni_log */ + +/* Call the CB_TYPE_NOTIFICATION callback pointed to by the `user_data_t' + * pointer. */ +static int cjni_notification (const notification_t *n, /* {{{ */ + user_data_t *ud) +{ + JNIEnv *jvm_env; + cjni_callback_info_t *cbi; + jobject o_notification; + int status; + int ret_status; + + if (jvm == NULL) + { + ERROR ("java plugin: cjni_read: jvm == NULL"); + return (-1); + } + + if ((ud == NULL) || (ud->data == NULL)) + { + ERROR ("java plugin: cjni_read: Invalid user data."); + return (-1); + } + + jvm_env = cjni_thread_attach (); + if (jvm_env == NULL) + return (-1); + + cbi = (cjni_callback_info_t *) ud->data; + + o_notification = ctoj_notification (jvm_env, n); + if (o_notification == NULL) + { + ERROR ("java plugin: cjni_notification: ctoj_notification failed."); + return (-1); + } + + ret_status = (*jvm_env)->CallIntMethod (jvm_env, + cbi->object, cbi->method, o_notification); + + (*jvm_env)->DeleteLocalRef (jvm_env, o_notification); + + status = cjni_thread_detach (); + if (status != 0) + { + ERROR ("java plugin: cjni_read: cjni_thread_detach failed."); + return (-1); + } + + return (ret_status); +} /* }}} int cjni_notification */ /* Iterate over `java_classes_list' and create one object of each class. This * will trigger the object's constructors, to the objects can register callback @@ -2263,6 +2442,7 @@ static int cjni_shutdown (void) /* {{{ */ sfree (java_classes_list); /* Destroy the JVM */ + DEBUG ("java plugin: Destroying the JVM."); (*jvm)->DestroyJavaVM (jvm); jvm = NULL; jvm_env = NULL; -- 2.11.0