X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=bindings%2Fjava%2Forg%2Fcollectd%2Fjava%2FGenericJMXConfValue.java;h=4b42c91171036ca70d213d0f1131373f79b7f572;hp=dcbe6480470eb70ed29502abd390becd572fe3da;hb=633c3966f770e4d46651a2fe219a18d8a9907a9f;hpb=bd931500189953f6995dc0cda30a35d98a824c3d diff --git a/bindings/java/org/collectd/java/GenericJMXConfValue.java b/bindings/java/org/collectd/java/GenericJMXConfValue.java index dcbe6480..4b42c911 100644 --- a/bindings/java/org/collectd/java/GenericJMXConfValue.java +++ b/bindings/java/org/collectd/java/GenericJMXConfValue.java @@ -1,32 +1,45 @@ -/* - * collectd/java - org/collectd/java/GenericJMXConfValue.java - * Copyright (C) 2009 Florian octo Forster +/** + * collectd - bindings/java/org/collectd/java/GenericJMXConfValue.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. + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: * - * 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. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * 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 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. * * Authors: - * Florian octo Forster + * Florian octo Forster */ 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 java.math.BigDecimal; +import java.math.BigInteger; + import javax.management.MBeanServerConnection; import javax.management.ObjectName; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.InvalidKeyException; import org.collectd.api.Collectd; import org.collectd.api.DataSet; @@ -36,13 +49,32 @@ 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 String _ds_name; + private DataSet _ds; private List _attributes; - private String instance_prefix; + private String _instance_prefix; + private List _instance_from; + private boolean _is_table; + /** + * Converts a generic (OpenType) object to a number. + * + * Returns null if a conversion is not possible or not implemented. + */ private Number genericObjectToNumber (Object obj, int ds_type) /* {{{ */ { if (obj instanceof String) @@ -61,6 +93,14 @@ class GenericJMXConfValue return (null); } } + else if (obj instanceof Byte) + { + return (new Byte ((Byte) obj)); + } + else if (obj instanceof Short) + { + return (new Short ((Short) obj)); + } else if (obj instanceof Integer) { return (new Integer ((Integer) obj)); @@ -69,23 +109,222 @@ class GenericJMXConfValue { return (new Long ((Long) obj)); } + else if (obj instanceof Float) + { + return (new Float ((Float) obj)); + } else if (obj instanceof Double) { return (new Double ((Double) obj)); } + else if (obj instanceof BigDecimal) + { + return (BigDecimal.ZERO.add ((BigDecimal) obj)); + } + else if (obj instanceof BigInteger) + { + return (BigInteger.ZERO.add ((BigInteger) obj)); + } return (null); } /* }}} Number genericObjectToNumber */ - private Number queryAttribute (MBeanServerConnection conn, /* {{{ */ - ObjectName objName, String attrName, - DataSource dsrc) + /** + * Converts a generic list to a list of numbers. + * + * Returns null if one or more objects could not be converted. + */ + 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 */ + + /** + * Converts a list of CompositeData to a list of numbers. + * + * From each CompositeData the key key is received and all + * those values are converted to a number. If one of the + * CompositeData doesn't have the specified key or one returned + * object cannot converted to a number then the function will return null. + */ + 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, /* {{{ */ + String instancePrefix) + { + 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 (instancePrefix == null) + vl.setTypeInstance (key); + else + vl.setTypeInstance (instancePrefix + key); + vl.setValues (values); + + Collectd.dispatchValues (vl); + } + } /* }}} void submitTable */ + + private void submitScalar (List objects, ValueList vl, /* {{{ */ + String instancePrefix) + { + List values; + + values = genericListToNumber (objects); + if (values == null) + { + Collectd.logError ("GenericJMXConfValue: Cannot convert list of " + + "objects to numbers."); + return; + } + + if (instancePrefix == null) + vl.setTypeInstance (""); + else + vl.setTypeInstance (instancePrefix); + 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); + try + { + value = conn.getAttribute (objName, key); + } + catch (javax.management.AttributeNotFoundException e) + { + value = conn.invoke (objName, key, /* args = */ null, /* types = */ null); + } } catch (Exception e) { @@ -94,8 +333,45 @@ 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 if (value instanceof OpenType) + { + OpenType ot = (OpenType) value; + Collectd.logNotice ("GenericJMXConfValue: Handling of OpenType \"" + + ot.getTypeName () + "\" is not yet implemented."); + return (null); + } + else + { + Collectd.logError ("GenericJMXConfValue: Received object of " + + "unknown class."); + return (null); + } + } + } /* }}} Object queryAttribute */ + + private String join (String separator, List list) /* {{{ */ + { + StringBuffer sb; + + sb = new StringBuffer (); + + for (int i = 0; i < list.size (); i++) + { + if (i > 0) + sb.append ("-"); + sb.append (list.get (i)); + } + + return (sb.toString ()); + } /* }}} String join */ private String getConfigString (OConfigItem ci) /* {{{ */ { @@ -121,26 +397,58 @@ 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 { List children; Iterator iter; - this.ds_name = null; - this.ds = null; + this._ds_name = null; + this._ds = null; this._attributes = new ArrayList (); - this.instance_prefix = null; - + this._instance_prefix = null; + this._instance_from = new ArrayList (); + 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 ()) @@ -151,7 +459,13 @@ class GenericJMXConfValue { String tmp = getConfigString (child); if (tmp != null) - this.ds_name = tmp; + 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")) { @@ -163,70 +477,123 @@ class GenericJMXConfValue { String tmp = getConfigString (child); if (tmp != null) - this.instance_prefix = tmp; + this._instance_prefix = tmp; + } + else if (child.getKey ().equalsIgnoreCase ("InstanceFrom")) + { + String tmp = getConfigString (child); + if (tmp != null) + this._instance_from.add (tmp); } else throw (new IllegalArgumentException ("Unknown option: " + child.getKey ())); } - if (this.ds_name == null) + if (this._ds_name == null) throw (new IllegalArgumentException ("No data set was defined.")); else if (this._attributes.size () == 0) 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; + List instanceList; + String instancePrefix; - 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); + + this._ds_name); return; } } - 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 () + + this._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.setType (this._ds_name); + /* + * Build the instnace prefix from the fixed string prefix and the + * properties of the objName. + */ + instanceList = new ArrayList (); + for (int i = 0; i < this._instance_from.size (); i++) + { + String propertyName; + String propertyValue; + + propertyName = this._instance_from.get (i); + propertyValue = objName.getKeyProperty (propertyName); + if (propertyValue == null) + { + Collectd.logError ("GenericJMXConfMBean: " + + "No such property in object name: " + propertyName); + } + else + { + instanceList.add (propertyValue); + } + } + + if (this._instance_prefix != null) + instancePrefix = new String (this._instance_prefix + + join ("-", instanceList)); + else + instancePrefix = join ("-", instanceList); + + /* + * Build a list of `Object's which is then passed to `submitTable' and + * `submitScalar'. + */ + 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, instancePrefix); + else + submitScalar (values, vl, instancePrefix); } /* }}} void query */ -} +} /* class GenericJMXConfValue */ /* vim: set sw=2 sts=2 et fdm=marker : */