From 658b873e6ac13d387a710fa02d8f85057fd5cae8 Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Sun, 2 Aug 2009 16:50:22 +0200 Subject: [PATCH] java bindings: GenericJMX: This first prototype version seems to do something. Well, at least it's not throwing exceptions like mad.. --- bindings/java/org/collectd/java/GenericJMX.java | 12 +- .../org/collectd/java/GenericJMXConfMBean.java | 46 ++- .../org/collectd/java/GenericJMXConfValue.java | 311 ++++++++++++++++++--- 3 files changed, 327 insertions(+), 42 deletions(-) diff --git a/bindings/java/org/collectd/java/GenericJMX.java b/bindings/java/org/collectd/java/GenericJMX.java index 978e989b..319615c9 100644 --- a/bindings/java/org/collectd/java/GenericJMX.java +++ b/bindings/java/org/collectd/java/GenericJMX.java @@ -105,7 +105,17 @@ public class GenericJMX implements CollectdConfigInterface, public int read () /* {{{ */ { for (int i = 0; i < this._connections.size (); i++) - this._connections.get (i).query (); + { + try + { + this._connections.get (i).query (); + } + catch (Exception e) + { + Collectd.logError ("GenericJMX: Caught unexpected exception: " + e); + e.printStackTrace (); + } + } return (0); } /* }}} int read */ diff --git a/bindings/java/org/collectd/java/GenericJMXConfMBean.java b/bindings/java/org/collectd/java/GenericJMXConfMBean.java index eea2d8ab..1b4d9ccf 100644 --- a/bindings/java/org/collectd/java/GenericJMXConfMBean.java +++ b/bindings/java/org/collectd/java/GenericJMXConfMBean.java @@ -21,15 +21,15 @@ package org.collectd.java; -import java.util.List; import java.util.Iterator; +import java.util.List; +import java.util.Set; import java.util.ArrayList; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.MalformedObjectNameException; - import org.collectd.api.Collectd; import org.collectd.api.PluginData; import org.collectd.api.OConfigValue; @@ -139,17 +139,49 @@ class GenericJMXConfMBean } /* }}} GenericJMXConfMBean (OConfigItem ci) */ - public String getName () + public String getName () /* {{{ */ { return (this._name); - } + } /* }}} */ public void query (MBeanServerConnection conn, PluginData pd) /* {{{ */ { - pd.setPluginInstance ((this._instance != null) ? this._instance : ""); + Set names; + Iterator iter; + + try + { + names = conn.queryNames (this._obj_name, /* query = */ null); + } + catch (Exception e) + { + Collectd.logError ("GenericJMXConfMBean: queryNames failed: " + e); + return; + } + + if (names.size () == 0) + { + Collectd.logWarning ("GenericJMXConfMBean: No MBean matched " + + "the ObjectName " + this._obj_name); + } + + iter = names.iterator (); + while (iter.hasNext ()) + { + ObjectName objName; + PluginData pd_tmp; - for (int i = 0; i < this._values.size (); i++) - this._values.get (i).query (conn, this._obj_name, pd); + objName = iter.next (); + pd_tmp = new PluginData (pd); + + Collectd.logDebug ("GenericJMXConfMBean: objName = " + + objName.toString ()); + + pd_tmp.setPluginInstance ((this._instance != null) ? this._instance : ""); + + for (int i = 0; i < this._values.size (); i++) + this._values.get (i).query (conn, objName, pd_tmp); + } } /* }}} void query */ } diff --git a/bindings/java/org/collectd/java/GenericJMXConfValue.java b/bindings/java/org/collectd/java/GenericJMXConfValue.java index dcbe6480..0fcf31aa 100644 --- a/bindings/java/org/collectd/java/GenericJMXConfValue.java +++ b/bindings/java/org/collectd/java/GenericJMXConfValue.java @@ -21,12 +21,16 @@ package org.collectd.java; +import java.util.Arrays; import java.util.List; +import java.util.Set; import java.util.Iterator; import java.util.ArrayList; import javax.management.MBeanServerConnection; import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.InvalidKeyException; import org.collectd.api.Collectd; import org.collectd.api.DataSet; @@ -36,12 +40,25 @@ import org.collectd.api.PluginData; import org.collectd.api.OConfigValue; import org.collectd.api.OConfigItem; +/** + * Representation of a <value /> block and query functionality. + * + * This class represents a <value /> block in the configuration. As + * such, the constructor takes an {@link org.collectd.api.OConfigValue} to + * construct an object of this class. + * + * The object can then be asked to query data from JMX and dispatch it to + * collectd. + * + * @see GenericJMXConfMBean + */ class GenericJMXConfValue { private String ds_name; - private DataSet ds; + private DataSet _ds; private List _attributes; - private String instance_prefix; + private String _instance_prefix; + private boolean _is_table; private Number genericObjectToNumber (Object obj, int ds_type) /* {{{ */ { @@ -77,15 +94,180 @@ class GenericJMXConfValue return (null); } /* }}} Number genericObjectToNumber */ - private Number queryAttribute (MBeanServerConnection conn, /* {{{ */ - ObjectName objName, String attrName, - DataSource dsrc) + private List genericListToNumber (List objects) /* {{{ */ + { + List ret = new ArrayList (); + List dsrc = this._ds.getDataSources (); + + assert (objects.size () == dsrc.size ()); + + for (int i = 0; i < objects.size (); i++) + { + Number n; + + n = genericObjectToNumber (objects.get (i), dsrc.get (i).getType ()); + if (n == null) + return (null); + ret.add (n); + } + + return (ret); + } /* }}} List genericListToNumber */ + + private List genericCompositeToNumber (List cdlist, /* {{{ */ + String key) + { + List objects = new ArrayList (); + + for (int i = 0; i < cdlist.size (); i++) + { + CompositeData cd; + Object value; + + cd = cdlist.get (i); + try + { + value = cd.get (key); + } + catch (InvalidKeyException e) + { + return (null); + } + objects.add (value); + } + + return (genericListToNumber (objects)); + } /* }}} List genericCompositeToNumber */ + + private void submitTable (List objects, ValueList vl) /* {{{ */ + { + List cdlist; + Set keySet = null; + Iterator keyIter; + + cdlist = new ArrayList (); + for (int i = 0; i < objects.size (); i++) + { + Object obj; + + obj = objects.get (i); + if (obj instanceof CompositeData) + { + CompositeData cd; + + cd = (CompositeData) obj; + + if (i == 0) + keySet = cd.getCompositeType ().keySet (); + + cdlist.add (cd); + } + else + { + Collectd.logError ("GenericJMXConfValue: At least one of the " + + "attributes was not of type `CompositeData', as required " + + "when table is set to `true'."); + return; + } + } + + assert (keySet != null); + + keyIter = keySet.iterator (); + while (keyIter.hasNext ()) + { + String key; + List values; + + key = keyIter.next (); + values = genericCompositeToNumber (cdlist, key); + if (values == null) + { + Collectd.logError ("GenericJMXConfValue: Cannot build a list of " + + "numbers for key " + key + ". Most likely not all attributes " + + "have this key."); + continue; + } + + if (this._instance_prefix == null) + vl.setTypeInstance (key); + else + vl.setTypeInstance (this._instance_prefix + key); + vl.setValues (values); + + Collectd.dispatchValues (vl); + } + } /* }}} void submitTable */ + + private void submitScalar (List objects, ValueList vl) /* {{{ */ + { + List values; + + values = genericListToNumber (objects); + if (values == null) + { + Collectd.logError ("GenericJMXConfValue: Cannot convert list of " + + "objects to numbers."); + return; + } + + if (this._instance_prefix == null) + vl.setTypeInstance (""); + else + vl.setTypeInstance (this._instance_prefix); + vl.setValues (values); + + Collectd.dispatchValues (vl); + } /* }}} void submitScalar */ + + private Object queryAttributeRecursive (CompositeData parent, /* {{{ */ + List attrName) + { + String key; + Object value; + + key = attrName.remove (0); + + try + { + value = parent.get (key); + } + catch (InvalidKeyException e) + { + return (null); + } + + if (attrName.size () == 0) + { + return (value); + } + else + { + if (value instanceof CompositeData) + return (queryAttributeRecursive ((CompositeData) value, attrName)); + else + return (null); + } + } /* }}} queryAttributeRecursive */ + + private Object queryAttribute (MBeanServerConnection conn, /* {{{ */ + ObjectName objName, String attrName) { - Object attrObj; + List attrNameList; + String key; + Object value; + String[] attrNameArray; + + attrNameList = new ArrayList (); + + attrNameArray = attrName.split ("\\."); + key = attrNameArray[0]; + for (int i = 1; i < attrNameArray.length; i++) + attrNameList.add (attrNameArray[i]); try { - attrObj = conn.getAttribute (objName, attrName); + value = conn.getAttribute (objName, key); } catch (Exception e) { @@ -94,8 +276,18 @@ class GenericJMXConfValue return (null); } - return (genericObjectToNumber (attrObj, dsrc.getType ())); - } /* }}} int queryAttribute */ + if (attrNameList.size () == 0) + { + return (value); + } + else + { + if (value instanceof CompositeData) + return (queryAttributeRecursive ((CompositeData) value, attrNameList)); + else + return (null); + } + } /* }}} Object queryAttribute */ private String getConfigString (OConfigItem ci) /* {{{ */ { @@ -121,14 +313,34 @@ class GenericJMXConfValue return (v.getString ()); } /* }}} String getConfigString */ -/* - * - * Type "memory" - * Attribute "HeapMemoryUsage" - * # Type instance: - * InstancePrefix "heap-" - * - */ + private Boolean getConfigBoolean (OConfigItem ci) /* {{{ */ + { + List values; + OConfigValue v; + Boolean b; + + values = ci.getValues (); + if (values.size () != 1) + { + Collectd.logError ("GenericJMXConfValue: The " + ci.getKey () + + " configuration option needs exactly one boolean argument."); + return (null); + } + + v = values.get (0); + if (v.getType () != OConfigValue.OCONFIG_TYPE_BOOLEAN) + { + Collectd.logError ("GenericJMXConfValue: The " + ci.getKey () + + " configuration option needs exactly one boolean argument."); + return (null); + } + + return (new Boolean (v.getBoolean ())); + } /* }}} String getConfigBoolean */ + + /** + * Constructs a new value with the configured properties. + */ public GenericJMXConfValue (OConfigItem ci) /* {{{ */ throws IllegalArgumentException { @@ -136,11 +348,22 @@ class GenericJMXConfValue Iterator iter; this.ds_name = null; - this.ds = null; + this._ds = null; this._attributes = new ArrayList (); - this.instance_prefix = null; - + this._instance_prefix = null; + this._is_table = false; + /* + * + * Type "memory" + * Table true|false + * Attribute "HeapMemoryUsage" + * Attribute "..." + * : + * # Type instance: + * InstancePrefix "heap-" + * + */ children = ci.getChildren (); iter = children.iterator (); while (iter.hasNext ()) @@ -153,6 +376,12 @@ class GenericJMXConfValue if (tmp != null) this.ds_name = tmp; } + else if (child.getKey ().equalsIgnoreCase ("Table")) + { + Boolean tmp = getConfigBoolean (child); + if (tmp != null) + this._is_table = tmp.booleanValue (); + } else if (child.getKey ().equalsIgnoreCase ("Attribute")) { String tmp = getConfigString (child); @@ -163,7 +392,7 @@ class GenericJMXConfValue { String tmp = getConfigString (child); if (tmp != null) - this.instance_prefix = tmp; + this._instance_prefix = tmp; } else throw (new IllegalArgumentException ("Unknown option: " @@ -176,16 +405,26 @@ class GenericJMXConfValue throw (new IllegalArgumentException ("No attribute was defined.")); } /* }}} GenericJMXConfValue (OConfigItem ci) */ + /** + * Query values via JMX according to the object's configuration and dispatch + * them to collectd. + * + * @param conn Connection to the MBeanServer. + * @param objName Object name of the MBean to query. + * @param pd Preset naming components. The members host, plugin and + * plugin instance will be used. + */ public void query (MBeanServerConnection conn, ObjectName objName, /* {{{ */ PluginData pd) { ValueList vl; List dsrc; + List values; - if (this.ds == null) + if (this._ds == null) { - this.ds = Collectd.getDS (this.ds_name); - if (ds == null) + this._ds = Collectd.getDS (this.ds_name); + if (this._ds == null) { Collectd.logError ("GenericJMXConfValue: Unknown type: " + this.ds_name); @@ -193,39 +432,43 @@ class GenericJMXConfValue } } - dsrc = this.ds.getDataSources (); + dsrc = this._ds.getDataSources (); if (dsrc.size () != this._attributes.size ()) { Collectd.logError ("GenericJMXConfValue.query: The data set " - + ds_name + " has " + this.ds.getDataSources ().size () + + ds_name + " has " + this._ds.getDataSources ().size () + " data sources, but there were " + this._attributes.size () + " attributes configured. This doesn't match!"); - this.ds = null; + this._ds = null; return; } vl = new ValueList (pd); vl.setType (this.ds_name); - vl.setTypeInstance (this.instance_prefix); + vl.setTypeInstance (this._instance_prefix); + + values = new ArrayList (); assert (dsrc.size () == this._attributes.size ()); for (int i = 0; i < this._attributes.size (); i++) { - Number v; + Object v; - v = queryAttribute (conn, objName, this._attributes.get (i), - dsrc.get (i)); + v = queryAttribute (conn, objName, this._attributes.get (i)); if (v == null) { Collectd.logError ("GenericJMXConfValue.query: " + "Querying attribute " + this._attributes.get (i) + " failed."); return; } - Collectd.logDebug ("GenericJMXConfValue.query: dsrc[" + i + "]: v = " + v); - vl.addValue (v); + + values.add (v); } - Collectd.dispatchValues (vl); + if (this._is_table) + submitTable (values, vl); + else + submitScalar (values, vl); } /* }}} void query */ } -- 2.11.0