summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 2084476)
raw | patch | inline | side by side (parent: 2084476)
author | Florian Forster <octo@leeloo.lan.home.verplant.org> | |
Tue, 17 Feb 2009 22:45:40 +0000 (23:45 +0100) | ||
committer | Florian Forster <octo@leeloo.lan.home.verplant.org> | |
Tue, 17 Feb 2009 22:45:40 +0000 (23:45 +0100) |
It's totally proof-of-concept, but it's possible to dispatch values from
a Java class using the ValueList implementation provided by Doug
MacEachern from Hyperic. The other way around is not yet implemented,
but that's just a matter of time and code. Configuration, notifications,
targets, matches - all that is still missing.
Right now, the code requires JNI version 1.2. Maybe I'll try to
introduce compatibility with JNI 1.1 at a later point, if it's really
useful for somebody.
Signed-off-by: Florian Forster <octo@leeloo.lan.home.verplant.org>
a Java class using the ValueList implementation provided by Doug
MacEachern from Hyperic. The other way around is not yet implemented,
but that's just a matter of time and code. Configuration, notifications,
targets, matches - all that is still missing.
Right now, the code requires JNI version 1.2. Maybe I'll try to
introduce compatibility with JNI 1.1 at a later point, if it's really
useful for somebody.
Signed-off-by: Florian Forster <octo@leeloo.lan.home.verplant.org>
bindings/java/org/collectd/java/CollectdAPI.java | [new file with mode: 0644] | patch | blob |
bindings/java/org/collectd/protocol/PluginData.java | [new file with mode: 0644] | patch | blob |
bindings/java/org/collectd/protocol/ValueList.java | [new file with mode: 0644] | patch | blob |
configure.in | patch | blob | history | |
src/Makefile.am | patch | blob | history | |
src/java.c | [new file with mode: 0644] | patch | blob |
diff --git a/bindings/java/org/collectd/java/CollectdAPI.java b/bindings/java/org/collectd/java/CollectdAPI.java
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * collectd - src/java.c
+ * 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.java;
+
+import org.collectd.protocol.ValueList;
+
+public class CollectdAPI
+{
+ native public static int DispatchValues (ValueList vl);
+} /* class CollectdAPI */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */
diff --git a/bindings/java/org/collectd/protocol/PluginData.java b/bindings/java/org/collectd/protocol/PluginData.java
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * jcollectd
+ * Copyright (C) 2009 Hyperic, Inc.
+ *
+ * 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
+ */
+
+package org.collectd.protocol;
+
+import java.util.Date;
+
+/**
+ * Shared members of value_list_t and notification_t structures.
+ */
+public class PluginData {
+
+ protected long _time;
+ protected String _host;
+ protected String _plugin;
+ protected String _pluginInstance = "";
+ protected String _type = "";
+ protected String _typeInstance = "";
+
+ public PluginData() {
+
+ }
+
+ public PluginData(PluginData pd) {
+ _time = pd._time;
+ _host = pd._host;
+ _plugin = pd._plugin;
+ _pluginInstance = pd._pluginInstance;
+ _type = pd._type;
+ _typeInstance = pd._typeInstance;
+ }
+
+ public long getTime() {
+ return _time;
+ }
+
+ public void setTime(long time) {
+ _time = time;
+ }
+
+ public String getHost() {
+ return _host;
+ }
+
+ public void setHost(String host) {
+ _host = host;
+ }
+
+ public String getPlugin() {
+ return _plugin;
+ }
+
+ public void setPlugin(String plugin) {
+ _plugin = plugin;
+ }
+
+ public String getPluginInstance() {
+ return _pluginInstance;
+ }
+
+ public void setPluginInstance(String pluginInstance) {
+ _pluginInstance = pluginInstance;
+ }
+
+ public String getType() {
+ return _type;
+ }
+
+ public void setType(String type) {
+ _type = type;
+ }
+
+ public String getTypeInstance() {
+ return _typeInstance;
+ }
+
+ public void setTypeInstance(String typeInstance) {
+ _typeInstance = typeInstance;
+ }
+
+ public boolean defined(String val) {
+ return (val != null) && (val.length() > 0);
+ }
+
+ public String getSource() {
+ final char DLM = '/';
+ StringBuffer sb = new StringBuffer();
+ if (defined(_host)) {
+ sb.append(_host);
+ }
+ if (defined(_plugin)) {
+ sb.append(DLM).append(_plugin);
+ }
+ if (defined(_pluginInstance)) {
+ sb.append(DLM).append(_pluginInstance);
+ }
+ if (defined(_type)) {
+ sb.append(DLM).append(_type);
+ }
+ if (defined(_typeInstance)) {
+ sb.append(DLM).append(_typeInstance);
+ }
+ return sb.toString();
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append('[').append(new Date(_time)).append("] ");
+ sb.append(getSource());
+ return sb.toString();
+ }
+}
diff --git a/bindings/java/org/collectd/protocol/ValueList.java b/bindings/java/org/collectd/protocol/ValueList.java
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * jcollectd
+ * Copyright (C) 2009 Hyperic, Inc.
+ *
+ * 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
+ */
+
+package org.collectd.protocol;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Java representation of collectd/src/plugin.h:value_list_t structure.
+ */
+public class ValueList extends PluginData {
+
+ List<Number> _values = new ArrayList<Number>();
+ List<DataSource> _ds = new ArrayList<DataSource>();
+
+ long _interval;
+
+ public ValueList() {
+
+ }
+
+ public ValueList(PluginData pd) {
+ super(pd);
+ }
+
+ public ValueList(ValueList vl) {
+ this((PluginData)vl);
+ _interval = vl._interval;
+ _values.addAll(vl.getValues());
+ _ds.addAll(vl._ds);
+ }
+
+ public List<Number> getValues() {
+ return _values;
+ }
+
+ public void setValues(List<Number> values) {
+ _values = values;
+ }
+
+ public void addValue(Number value) {
+ _values.add(value);
+ }
+
+ public List<DataSource> getDataSource() {
+ if (_ds.size() > 0) {
+ return _ds;
+ }
+ else {
+ TypesDB db = TypesDB.getInstance();
+ return db.getType(_type);
+ }
+ }
+
+ public void setDataSource(List<DataSource> ds) {
+ _ds = ds;
+ }
+
+ public long getInterval() {
+ return _interval;
+ }
+
+ public void setInterval(long interval) {
+ _interval = interval;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer(super.toString());
+ sb.append("=[");
+ List<DataSource> ds = getDataSource();
+ int size = _values.size();
+ for (int i=0; i<size; i++) {
+ Number val = _values.get(i);
+ String name;
+ if (ds == null) {
+ name = "unknown" + i;
+ }
+ else {
+ name = ds.get(i).getName();
+ }
+ sb.append(name).append('=').append(val);
+ if (i < size-1) {
+ sb.append(',');
+ }
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+}
diff --git a/configure.in b/configure.in
index 9a467d8f3d30d37a956d06236eb58eb21db086a5..5ff8fc82c8da7f12d67326f786c26dca0148b6e6 100644 (file)
--- a/configure.in
+++ b/configure.in
fi
# }}}
+# --with-java {{{
+with_java_home="$JAVA_HOME"
+with_java_vmtype="client"
+with_java_cflags=""
+with_java_libs=""
+AC_ARG_WITH(java, [AS_HELP_STRING([--with-java@<:@=PREFIX@:>@], [Path to Java home.])],
+[
+ if test "x$withval" = "xno"
+ then
+ with_java="no"
+ else if test "x$withval" = "xyes"
+ then
+ with_java="yes"
+ else
+ with_java_home="$withval"
+ with_java="yes"
+ fi; fi
+],
+[with_java="yes"])
+if test "x$with_java" = "xyes"
+then
+ if test -d "$with_java_home"
+ then
+ if test -d "$with_java_home/include"
+ then
+ JAVA_CPPFLAGS="$JAVA_CPPFLAGS -I$with_java_home/include"
+ else
+ JAVA_CPPFLAGS="$JAVA_CPPFLAGS -I$with_java_home"
+ fi
+
+ if test -d "$with_java_home/lib"
+ then
+ JAVA_LDFLAGS="$JAVA_LDFLAGS -L$with_java_home/lib"
+ else
+ JAVA_LDFLAGS="$JAVA_LDFLAGS -L$with_java_home"
+ fi
+ else if test "x$with_java_home" != "x"
+ then
+ AC_MSG_WARN([JAVA_HOME: No such directory: $with_java_home])
+ fi; fi
+fi
+
+if test "x$JAVA_CPPFLAGS" != "x"
+then
+ AC_MSG_NOTICE([Building with JAVA_CPPFLAGS set to: $JAVA_CPPFLAGS])
+fi
+if test "x$JAVA_CFLAGS" != "x"
+then
+ AC_MSG_NOTICE([Building with JAVA_CFLAGS set to: $JAVA_CFLAGS])
+fi
+if test "x$JAVA_LDFLAGS" != "x"
+then
+ AC_MSG_NOTICE([Building with JAVA_LDFLAGS set to: $JAVA_LDFLAGS])
+fi
+
+SAVE_CPPFLAGS="$CPPFLAGS"
+SAVE_CFLAGS="$CFLAGS"
+SAVE_LDFLAGS="$LDFLAGS"
+CPPFLAGS="$CPPFLAGS $JAVA_CPPFLAGS"
+CFLAGS="$CFLAGS $JAVA_CFLAGS"
+LDFLAGS="$LDFLAGS $JAVA_LDFLAGS"
+
+if test "x$with_java" = "xyes"
+then
+ AC_CHECK_HEADERS(jni.h, [], [with_java="no (jni.h not found)"])
+fi
+if test "x$with_java" = "xyes"
+then
+ AC_CHECK_LIB(jvm, JNI_CreateJavaVM,
+ [with_java="yes"],
+ [with_java="no (libjvm not found)"],
+ [$JAVA_LIBS])
+fi
+if test "x$with_java" = "xyes"
+then
+ JAVA_LIBS="$JAVA_LIBS -ljvm"
+ AC_MSG_NOTICE([Building with JAVA_LIBS set to: $JAVA_LIBS])
+fi
+
+CPPFLAGS="$SAVE_CPPFLAGS"
+CFLAGS="$SAVE_CFLAGS"
+LDFLAGS="$SAVE_LDFLAGS"
+
+AC_SUBST(JAVA_CPPFLAGS)
+AC_SUBST(JAVA_CFLAGS)
+AC_SUBST(JAVA_LDFLAGS)
+AC_SUBST(JAVA_LIBS)
+AM_CONDITIONAL(BUILD_WITH_JAVA, test "x$with_java" = "xyes")
+# }}}
+
# --with-libmysql {{{
with_mysql_config="mysql_config"
with_mysql_cflags=""
AC_PLUGIN([iptables], [$with_libiptc], [IPTables rule counters])
AC_PLUGIN([ipvs], [$plugin_ipvs], [IPVS connection statistics])
AC_PLUGIN([irq], [$plugin_irq], [IRQ statistics])
+AC_PLUGIN([java], [$with_java], [Embed the Java Virtual Machine])
AC_PLUGIN([libvirt], [$plugin_libvirt], [Virtual machine statistics])
AC_PLUGIN([load], [$plugin_load], [System load])
AC_PLUGIN([logfile], [yes], [File logging plugin])
libesmtp . . . . . . $with_libesmtp
libiokit . . . . . . $with_libiokit
libiptc . . . . . . . $with_libiptc
+ libjvm . . . . . . . $with_java
libkstat . . . . . . $with_kstat
libkvm . . . . . . . $with_libkvm
libmysql . . . . . . $with_libmysql
iptables . . . . . . $enable_iptables
ipvs . . . . . . . . $enable_ipvs
irq . . . . . . . . . $enable_irq
+ java . . . . . . . . $enable_java
libvirt . . . . . . . $enable_libvirt
load . . . . . . . . $enable_load
logfile . . . . . . . $enable_logfile
diff --git a/src/Makefile.am b/src/Makefile.am
index 39e0c416d4db3ccca6613ebb607b85cf8c551e92..ba304fb1fce73f3b142c1e66626164e357f3c5f5 100644 (file)
--- a/src/Makefile.am
+++ b/src/Makefile.am
collectd_DEPENDENCIES += irq.la
endif
+if BUILD_PLUGIN_JAVA
+pkglib_LTLIBRARIES += java.la
+java_la_SOURCES = java.c
+java_la_CPPFLAGS = $(AM_CPPFLAGS) $(JAVA_CPPFLAGS)
+java_la_CFLAGS = $(AM_CFLAGS) $(JAVA_CFLAGS)
+java_la_LDFLAGS = -module -avoid-version $(JAVA_LDFLAGS)
+java_la_LIBADD = $(JAVA_LIBS)
+collectd_LDADD += "-dlopen" java.la
+collectd_DEPENDENCIES += java.la
+endif
+
if BUILD_PLUGIN_LIBVIRT
pkglib_LTLIBRARIES += libvirt.la
libvirt_la_SOURCES = libvirt.c
diff --git a/src/java.c b/src/java.c
--- /dev/null
+++ b/src/java.c
@@ -0,0 +1,678 @@
+/**
+ * collectd - src/java.c
+ * Copyright (C) 2009 Florian octo Forster
+ * Copyright (C) 2008 Justo Alonso Achaques
+ *
+ * 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>
+ * Justo Alonso Achaques <justo.alonso at gmail.com>
+ **/
+
+#include "collectd.h"
+#include "plugin.h"
+#include "common.h"
+
+#include <pthread.h>
+#include <jni.h>
+
+#if !defined(JNI_VERSION_1_2)
+# error "Need JNI 1.2 compatible interface!"
+#endif
+
+/*
+ * Types
+ */
+struct java_plugin_s /* {{{ */
+{
+ char *class_name;
+ jclass class_ptr;
+ jobject object_ptr;
+
+#define CJNI_FLAG_ENABLED 0x0001
+ int flags;
+
+ jmethodID method_init;
+ jmethodID method_read;
+ jmethodID method_shutdown;
+};
+typedef struct java_plugin_s java_plugin_t;
+/* }}} */
+
+/*
+ * Global variables
+ */
+static JavaVM *jvm = NULL;
+
+static java_plugin_t java_plugins[] =
+{
+ { "org.collectd.java.Foobar", NULL, NULL, 0, NULL, NULL, NULL }
+};
+static size_t java_plugins_num = sizeof (java_plugins) / sizeof (java_plugins[0]);
+
+/*
+ * Conversion functons
+ *
+ * - jtoc_*: From Java to C
+ * - ctoj_*: From C to Java
+ */
+static int jtoc_string (JNIEnv *jvm_env, /* {{{ */
+ char *buffer, size_t buffer_size,
+ jclass class_ptr, jobject object_ptr, const char *method_name)
+{
+ jmethodID method_id;
+ jobject string_obj;
+ const char *c_str;
+
+ method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
+ method_name, "()Ljava/lang/String;");
+ if (method_id == NULL)
+ {
+ ERROR ("java plugin: jtoc_string: Cannot find method `String %s ()'.",
+ method_name);
+ return (-1);
+ }
+
+ string_obj = (*jvm_env)->CallObjectMethod (jvm_env, object_ptr, method_id);
+ if (string_obj == NULL)
+ {
+ ERROR ("java plugin: jtoc_string: CallObjectMethod (%s) failed.",
+ method_name);
+ return (-1);
+ }
+
+ c_str = (*jvm_env)->GetStringUTFChars (jvm_env, string_obj, 0);
+ if (c_str == NULL)
+ {
+ ERROR ("java plugin: jtoc_string: GetStringUTFChars failed.");
+ (*jvm_env)->DeleteLocalRef (jvm_env, string_obj);
+ return (-1);
+ }
+
+ DEBUG ("java plugin: jtoc_string: ->%s() = %s", method_name, c_str);
+
+ sstrncpy (buffer, c_str, buffer_size);
+
+ (*jvm_env)->ReleaseStringUTFChars (jvm_env, string_obj, c_str);
+ (*jvm_env)->DeleteLocalRef (jvm_env, string_obj);
+
+ return (0);
+} /* }}} int jtoc_string */
+
+static int jtoc_long (JNIEnv *jvm_env, /* {{{ */
+ jlong *ret_value,
+ jclass class_ptr, jobject object_ptr, const char *method_name)
+{
+ jmethodID method_id;
+
+ method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
+ method_name, "()J");
+ if (method_id == NULL)
+ {
+ ERROR ("java plugin: jtoc_string: Cannot find method `long %s ()'.",
+ method_name);
+ return (-1);
+ }
+
+ *ret_value = (*jvm_env)->CallLongMethod (jvm_env, object_ptr, method_id);
+
+ DEBUG ("java plugin: jtoc_long: ->%s() = %li",
+ method_name, (long int) *ret_value);
+
+ return (0);
+} /* }}} int jtoc_long */
+
+static int jtoc_double (JNIEnv *jvm_env, /* {{{ */
+ jdouble *ret_value,
+ jclass class_ptr, jobject object_ptr, const char *method_name)
+{
+ jmethodID method_id;
+
+ method_id = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
+ method_name, "()D");
+ if (method_id == NULL)
+ {
+ ERROR ("java plugin: jtoc_string: Cannot find method `double %s ()'.",
+ method_name);
+ return (-1);
+ }
+
+ *ret_value = (*jvm_env)->CallDoubleMethod (jvm_env, object_ptr, method_id);
+
+ DEBUG ("java plugin: jtoc_double: ->%s() = %g",
+ method_name, (double) *ret_value);
+
+ return (0);
+} /* }}} int jtoc_double */
+
+static int jtoc_value (JNIEnv *jvm_env, /* {{{ */
+ value_t *ret_value, int ds_type, jobject object_ptr)
+{
+ jclass class_ptr;
+ int status;
+
+ class_ptr = (*jvm_env)->GetObjectClass (jvm_env, object_ptr);
+
+ if (ds_type == DS_TYPE_COUNTER)
+ {
+ jlong tmp_long;
+
+ status = jtoc_long (jvm_env, &tmp_long,
+ class_ptr, object_ptr, "longValue");
+ if (status != 0)
+ {
+ ERROR ("java plugin: jtoc_value: "
+ "jtoc_long failed.");
+ return (-1);
+ }
+ (*ret_value).counter = (counter_t) tmp_long;
+ }
+ else
+ {
+ jdouble tmp_double;
+
+ status = jtoc_double (jvm_env, &tmp_double,
+ class_ptr, object_ptr, "doubleValue");
+ if (status != 0)
+ {
+ ERROR ("java plugin: jtoc_value: "
+ "jtoc_double failed.");
+ return (-1);
+ }
+ (*ret_value).gauge = (gauge_t) tmp_double;
+ }
+
+ return (0);
+} /* }}} int jtoc_value */
+
+static int jtoc_values_array (JNIEnv *jvm_env, /* {{{ */
+ const data_set_t *ds, value_list_t *vl,
+ jclass class_ptr, jobject object_ptr)
+{
+ jmethodID m_getvalues;
+ jmethodID m_toarray;
+ jobject o_list;
+ jobjectArray o_number_array;
+
+ value_t *values;
+ int values_num;
+ int i;
+
+ values_num = ds->ds_num;
+
+ values = NULL;
+ o_number_array = NULL;
+ o_list = NULL;
+
+#define BAIL_OUT(status) \
+ free (values); \
+ if (o_number_array != NULL) \
+ (*jvm_env)->DeleteLocalRef (jvm_env, o_number_array); \
+ if (o_list != NULL) \
+ (*jvm_env)->DeleteLocalRef (jvm_env, o_list); \
+ return (status);
+
+ /* Call: List<Number> ValueList.getValues () */
+ m_getvalues = (*jvm_env)->GetMethodID (jvm_env, class_ptr,
+ "getValues", "()Ljava/util/List;");
+ if (m_getvalues == NULL)
+ {
+ ERROR ("java plugin: jtoc_values_array: "
+ "Cannot find method `List getValues ()'.");
+ BAIL_OUT (-1);
+ }
+
+ o_list = (*jvm_env)->CallObjectMethod (jvm_env, object_ptr, m_getvalues);
+ if (o_list == NULL)
+ {
+ ERROR ("java plugin: jtoc_values_array: "
+ "CallObjectMethod (getValues) failed.");
+ BAIL_OUT (-1);
+ }
+
+ /* Call: Number[] List.toArray () */
+ m_toarray = (*jvm_env)->GetMethodID (jvm_env,
+ (*jvm_env)->GetObjectClass (jvm_env, o_list),
+ "toArray", "()[Ljava/lang/Object;");
+ if (m_toarray == NULL)
+ {
+ ERROR ("java plugin: jtoc_values_array: "
+ "Cannot find method `Object[] toArray ()'.");
+ BAIL_OUT (-1);
+ }
+
+ o_number_array = (*jvm_env)->CallObjectMethod (jvm_env, o_list, m_toarray);
+ if (o_number_array == NULL)
+ {
+ ERROR ("java plugin: jtoc_values_array: "
+ "CallObjectMethod (toArray) failed.");
+ BAIL_OUT (-1);
+ }
+
+ values = calloc (values_num, sizeof (value_t));
+ if (values == NULL)
+ {
+ ERROR ("java plugin: jtoc_values_array: calloc failed.");
+ BAIL_OUT (-1);
+ }
+
+ for (i = 0; i < values_num; i++)
+ {
+ jobject o_number;
+ int status;
+
+ o_number = (*jvm_env)->GetObjectArrayElement (jvm_env,
+ o_number_array, (jsize) i);
+ if (o_number == NULL)
+ {
+ ERROR ("java plugin: jtoc_values_array: "
+ "GetObjectArrayElement (%i) failed.", i);
+ BAIL_OUT (-1);
+ }
+
+ status = jtoc_value (jvm_env, values + i, ds->ds[i].type, o_number);
+ if (status != 0)
+ {
+ ERROR ("java plugin: jtoc_values_array: "
+ "jtoc_value (%i) failed.", i);
+ BAIL_OUT (-1);
+ }
+ } /* for (i = 0; i < values_num; i++) */
+
+ vl->values = values;
+ vl->values_len = values_num;
+
+#undef BAIL_OUT
+ (*jvm_env)->DeleteLocalRef (jvm_env, o_number_array);
+ (*jvm_env)->DeleteLocalRef (jvm_env, o_list);
+ return (0);
+} /* }}} int jtoc_values_array */
+
+static int jtoc_value_list (JNIEnv *jvm_env, value_list_t *vl, /* {{{ */
+ jobject object_ptr)
+{
+ jclass class_ptr;
+ int status;
+ jlong tmp_long;
+ const data_set_t *ds;
+
+ class_ptr = (*jvm_env)->GetObjectClass (jvm_env, object_ptr);
+ if (class_ptr == NULL)
+ {
+ ERROR ("java plugin: jtoc_value_list: GetObjectClass failed.");
+ return (-1);
+ }
+
+#define SET_STRING(buffer,method) do { \
+ status = jtoc_string (jvm_env, buffer, sizeof (buffer), \
+ class_ptr, object_ptr, method); \
+ if (status != 0) { \
+ ERROR ("java plugin: jtoc_value_list: jtoc_string (%s) failed.", \
+ method); \
+ return (-1); \
+ } } while (0)
+
+ SET_STRING(vl->type, "getType");
+
+ ds = plugin_get_ds (vl->type);
+ if (ds == NULL)
+ {
+ ERROR ("java plugin: jtoc_value_list: Data-set `%s' is not defined. "
+ "Please consult the types.db(5) manpage for mor information.",
+ vl->type);
+ return (-1);
+ }
+
+ SET_STRING(vl->host, "getHost");
+ SET_STRING(vl->plugin, "getPlugin");
+ SET_STRING(vl->plugin_instance, "getPluginInstance");
+ SET_STRING(vl->type_instance, "getTypeInstance");
+
+#undef SET_STRING
+
+ status = jtoc_long (jvm_env, &tmp_long, class_ptr, object_ptr, "getTime");
+ if (status != 0)
+ {
+ ERROR ("java plugin: jtoc_value_list: jtoc_string (getTime) failed.");
+ return (-1);
+ }
+ vl->time = (time_t) tmp_long;
+
+ status = jtoc_long (jvm_env, &tmp_long,
+ class_ptr, object_ptr, "getInterval");
+ if (status != 0)
+ {
+ ERROR ("java plugin: jtoc_value_list: jtoc_string (getInterval) failed.");
+ return (-1);
+ }
+ vl->interval = (int) tmp_long;
+
+ status = jtoc_values_array (jvm_env, ds, vl, class_ptr, object_ptr);
+ if (status != 0)
+ {
+ ERROR ("java plugin: jtoc_value_list: jtoc_values_array failed.");
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int jtoc_value_list */
+
+/*
+ * Functions accessible from Java
+ */
+static jint JNICALL cjni_api_dispatch_values (JNIEnv *jvm_env, /* {{{ */
+ jobject this, jobject java_vl)
+{
+ value_list_t vl = VALUE_LIST_INIT;
+ int status;
+
+ DEBUG ("cjni_api_dispatch_values: java_vl = %p;", (void *) java_vl);
+
+ status = jtoc_value_list (jvm_env, &vl, java_vl);
+ if (status != 0)
+ {
+ ERROR ("java plugin: cjni_api_dispatch_values: jtoc_value_list failed.");
+ return (-1);
+ }
+
+ plugin_dispatch_values (&vl);
+
+ sfree (vl.values);
+
+ return (0);
+} /* }}} jint cjni_api_dispatch_values */
+
+static JNINativeMethod jni_api_functions[] =
+{
+ { "DispatchValues", "(Lorg/collectd/protocol/ValueList;)I", cjni_api_dispatch_values }
+};
+static size_t jni_api_functions_num = sizeof (jni_api_functions)
+ / sizeof (jni_api_functions[0]);
+
+/*
+ * Functions
+ */
+static int cjni_init_one_plugin (JNIEnv *jvm_env, java_plugin_t *jp) /* {{{ */
+{
+ jmethodID constructor_id;
+ int status;
+
+ jp->class_ptr = (*jvm_env)->FindClass (jvm_env, jp->class_name);
+ if (jp->class_ptr == NULL)
+ {
+ ERROR ("cjni_init_one_plugin: FindClass (%s) failed.",
+ jp->class_name);
+ return (-1);
+ }
+
+ constructor_id = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
+ "<init>", "()V");
+ if (constructor_id == NULL)
+ {
+ ERROR ("cjni_init_one_plugin: Could not find the constructor for `%s'.",
+ jp->class_name);
+ return (-1);
+ }
+
+ jp->object_ptr = (*jvm_env)->NewObject (jvm_env, jp->class_ptr,
+ constructor_id);
+ if (jp->object_ptr == NULL)
+ {
+ ERROR ("cjni_init_one_plugin: Could create a new `%s' object.",
+ jp->class_name);
+ return (-1);
+ }
+
+ jp->method_init = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
+ "Init", "()I");
+ DEBUG ("jp->method_init = %p;", (void *) jp->method_init);
+ jp->method_read = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
+ "Read", "()I");
+ DEBUG ("jp->method_read = %p;", (void *) jp->method_read);
+ jp->method_shutdown = (*jvm_env)->GetMethodID (jvm_env, jp->class_ptr,
+ "Shutdown", "()I");
+ DEBUG ("jp->method_shutdown = %p;", (void *) jp->method_shutdown);
+
+ status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
+ jp->method_init);
+ if (status != 0)
+ {
+ ERROR ("cjni_init_one_plugin: Initializing `%s' object failed "
+ "with status %i.", jp->class_name, status);
+ return (-1);
+ }
+ jp->flags |= CJNI_FLAG_ENABLED;
+
+ return (0);
+} /* }}} int cjni_init_one_plugin */
+
+static int cjni_init_plugins (JNIEnv *jvm_env) /* {{{ */
+{
+ size_t j;
+
+ for (j = 0; j < java_plugins_num; j++)
+ cjni_init_one_plugin (jvm_env, &java_plugins[j]);
+
+ return (0);
+} /* }}} int cjni_init_plugins */
+
+static int cjni_init_native (JNIEnv *jvm_env) /* {{{ */
+{
+ jclass api_class_ptr;
+ int status;
+
+ api_class_ptr = (*jvm_env)->FindClass (jvm_env, "org.collectd.java.CollectdAPI");
+ if (api_class_ptr == NULL)
+ {
+ ERROR ("cjni_init_native: Cannot find API class `org.collectd.java.CollectdAPI'.");
+ return (-1);
+ }
+
+ status = (*jvm_env)->RegisterNatives (jvm_env, api_class_ptr,
+ jni_api_functions, (jint) jni_api_functions_num);
+ if (status != 0)
+ {
+ ERROR ("cjni_init_native: RegisterNatives failed with status %i.", status);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int cjni_init_native */
+
+static int cjni_init (void) /* {{{ */
+{
+ JNIEnv *jvm_env;
+ JavaVMInitArgs vm_args;
+ JavaVMOption vm_options[2];
+
+ int status;
+
+ if (jvm != NULL)
+ return (0);
+
+ jvm_env = NULL;
+
+ memset (&vm_args, 0, sizeof (vm_args));
+ vm_args.version = JNI_VERSION_1_2;
+ vm_args.options = vm_options;
+ vm_args.nOptions = sizeof (vm_options) / sizeof (vm_options[0]);
+
+ vm_args.options[0].optionString = "-verbose:jni";
+ vm_args.options[1].optionString = "-Djava.class.path=/home/octo/collectd/bindings/java";
+
+ status = JNI_CreateJavaVM (&jvm, (void **) &jvm_env, (void **) &vm_args);
+ if (status != 0)
+ {
+ ERROR ("cjni_init: JNI_CreateJavaVM failed with status %i.",
+ status);
+ return (-1);
+ }
+ assert (jvm != NULL);
+ assert (jvm_env != NULL);
+
+ /* Call RegisterNatives */
+ status = cjni_init_native (jvm_env);
+ if (status != 0)
+ {
+ ERROR ("cjni_init: cjni_init_native failed.");
+ return (-1);
+ }
+
+ cjni_init_plugins (jvm_env);
+
+ return (0);
+} /* }}} int cjni_init */
+
+static int cjni_read_one_plugin (JNIEnv *jvm_env, java_plugin_t *jp) /* {{{ */
+{
+ int status;
+
+ if ((jp == NULL)
+ || ((jp->flags & CJNI_FLAG_ENABLED) == 0)
+ || (jp->method_read == NULL))
+ return (0);
+
+ DEBUG ("java plugin: Calling: %s.Read()", jp->class_name);
+
+ status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
+ jp->method_read);
+ if (status != 0)
+ {
+ ERROR ("cjni_read_one_plugin: Calling `Read' on an `%s' object failed "
+ "with status %i.", jp->class_name, status);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int cjni_read_one_plugin */
+
+static int cjni_read_plugins (JNIEnv *jvm_env) /* {{{ */
+{
+ size_t j;
+
+ for (j = 0; j < java_plugins_num; j++)
+ cjni_read_one_plugin (jvm_env, &java_plugins[j]);
+
+ return (0);
+} /* }}} int cjni_read_plugins */
+
+static int cjni_read (void) /* {{{ */
+{
+ JNIEnv *jvm_env;
+ JavaVMAttachArgs args;
+ int status;
+
+ if (jvm == NULL)
+ {
+ ERROR ("java plugin: cjni_read: jvm == NULL");
+ return (-1);
+ }
+
+ jvm_env = NULL;
+ memset (&args, 0, sizeof (args));
+ args.version = JNI_VERSION_1_2;
+
+ status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args);
+ if (status != 0)
+ {
+ ERROR ("java plugin: cjni_read: AttachCurrentThread failed with status %i.",
+ status);
+ return (-1);
+ }
+
+ cjni_read_plugins (jvm_env);
+
+ status = (*jvm)->DetachCurrentThread (jvm);
+ if (status != 0)
+ {
+ ERROR ("java plugin: cjni_read: DetachCurrentThread failed with status %i.",
+ status);
+ return (-1);
+ }
+
+ return (0);
+} /* }}} int cjni_read */
+
+static int cjni_shutdown_one_plugin (JNIEnv *jvm_env, /* {{{ */
+ java_plugin_t *jp)
+{
+ int status;
+
+ if ((jp == NULL)
+ || ((jp->flags & CJNI_FLAG_ENABLED) == 0)
+ || (jp->method_shutdown == NULL))
+ return (0);
+
+ status = (*jvm_env)->CallIntMethod (jvm_env, jp->object_ptr,
+ jp->method_shutdown);
+ if (status != 0)
+ {
+ ERROR ("cjni_shutdown_one_plugin: Destroying an `%s' object failed "
+ "with status %i.", jp->class_name, status);
+ return (-1);
+ }
+ jp->flags &= ~CJNI_FLAG_ENABLED;
+
+ return (0);
+} /* }}} int cjni_shutdown_one_plugin */
+
+static int cjni_shutdown_plugins (JNIEnv *jvm_env) /* {{{ */
+{
+ size_t j;
+
+ for (j = 0; j < java_plugins_num; j++)
+ cjni_shutdown_one_plugin (jvm_env, &java_plugins[j]);
+
+ return (0);
+} /* }}} int cjni_shutdown_plugins */
+
+static int cjni_shutdown (void) /* {{{ */
+{
+ JNIEnv *jvm_env;
+ JavaVMAttachArgs args;
+ int status;
+
+ if (jvm == NULL)
+ return (0);
+
+ jvm_env = NULL;
+ memset (&args, 0, sizeof (args));
+ args.version = JNI_VERSION_1_2;
+
+ status = (*jvm)->AttachCurrentThread (jvm, (void **) &jvm_env, &args);
+ if (status != 0)
+ {
+ ERROR ("java plugin: cjni_read: AttachCurrentThread failed with status %i.",
+ status);
+ return (-1);
+ }
+
+ cjni_shutdown_plugins (jvm_env);
+
+ (*jvm)->DestroyJavaVM (jvm);
+ jvm = NULL;
+ jvm_env = NULL;
+
+ return (0);
+} /* }}} int cjni_shutdown */
+
+void module_register (void)
+{
+ plugin_register_init ("java", cjni_init);
+ plugin_register_read ("java", cjni_read);
+ plugin_register_shutdown ("java", cjni_shutdown);
+} /* void module_register (void) */
+
+/* vim: set sw=2 sts=2 et fdm=marker : */