java plugin: Add support for `notification' callbacks.
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Mon, 23 Feb 2009 13:57:56 +0000 (14:57 +0100)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Mon, 23 Feb 2009 13:57:56 +0000 (14:57 +0100)
bindings/java/org/collectd/api/Collectd.java
bindings/java/org/collectd/api/CollectdNotificationInterface.java [new file with mode: 0644]
src/collectd-java.pod
src/java.c

index eb96969..92ddec0 100644 (file)
@@ -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 (file)
index 0000000..4a18975
--- /dev/null
@@ -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 <octo at verplant.org>
+ */
+
+package org.collectd.api;
+
+/**
+ * Interface for objects implementing a notification function.
+ *
+ * @author Florian Forster &lt;octo at verplant.org&gt;
+ * @see Collectd#registerNotification
+ */
+public interface CollectdNotificationInterface
+{
+       public int notification (Notification n);
+}
index 72ce0b6..773130a 100644 (file)
@@ -61,6 +61,10 @@ Corresponds to C<data_set_t>, defined in F<src/plugin.h>.
 
 Corresponds to C<value_list_t>, defined in F<src/plugin.h>.
 
+=item B<org.collectd.api.Notification>
+
+Corresponds to C<notification_t>, defined in F<src/plugin.h>.
+
 =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<org.collectd.api.CollectdNotificationInterface>
+
+Signature: I<int> B<notification> (I<Notification> 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<log> function of I<object> with the daemon.
 
 Returns zero upon success and non-zero when an error occurred.
 
+=head2 registerNotification
+
+Signature: I<int> B<registerNotification> (I<String> name,
+I<CollectdNotificationInterface> object);
+
+Registers the B<notification> function of I<object> with the daemon.
+
+Returns zero upon success and non-zero when an error occurred.
+
 =head2 dispatchValues
 
 Signature: I<int> B<dispatchValues> (I<ValueList>)
index fc332e5..2d310c6 100644 (file)
@@ -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,
+      "<init>", "()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;