2 * collectd/java - org/collectd/java/GenericJMXConfValue.java
3 * Copyright (C) 2009 Florian octo Forster
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the License is applicable.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Florian octo Forster <octo at verplant.org>
22 package org.collectd.java;
24 import java.util.Arrays;
25 import java.util.List;
27 import java.util.Iterator;
28 import java.util.ArrayList;
30 import javax.management.MBeanServerConnection;
31 import javax.management.ObjectName;
32 import javax.management.openmbean.OpenType;
33 import javax.management.openmbean.CompositeData;
34 import javax.management.openmbean.InvalidKeyException;
36 import org.collectd.api.Collectd;
37 import org.collectd.api.DataSet;
38 import org.collectd.api.DataSource;
39 import org.collectd.api.ValueList;
40 import org.collectd.api.PluginData;
41 import org.collectd.api.OConfigValue;
42 import org.collectd.api.OConfigItem;
45 * Representation of a <value /> block and query functionality.
47 * This class represents a <value /> block in the configuration. As
48 * such, the constructor takes an {@link org.collectd.api.OConfigValue} to
49 * construct an object of this class.
51 * The object can then be asked to query data from JMX and dispatch it to
54 * @see GenericJMXConfMBean
56 class GenericJMXConfValue
58 private String _ds_name;
60 private List<String> _attributes;
61 private String _instance_prefix;
62 private boolean _is_table;
64 private Number genericObjectToNumber (Object obj, int ds_type) /* {{{ */
66 if (obj instanceof String)
68 String str = (String) obj;
72 if (ds_type == DataSource.TYPE_GAUGE)
73 return (new Double (str));
75 return (new Long (str));
77 catch (NumberFormatException e)
82 else if (obj instanceof Integer)
84 return (new Integer ((Integer) obj));
86 else if (obj instanceof Long)
88 return (new Long ((Long) obj));
90 else if (obj instanceof Double)
92 return (new Double ((Double) obj));
96 } /* }}} Number genericObjectToNumber */
98 private List<Number> genericListToNumber (List<Object> objects) /* {{{ */
100 List<Number> ret = new ArrayList<Number> ();
101 List<DataSource> dsrc = this._ds.getDataSources ();
103 assert (objects.size () == dsrc.size ());
105 for (int i = 0; i < objects.size (); i++)
109 n = genericObjectToNumber (objects.get (i), dsrc.get (i).getType ());
116 } /* }}} List<Number> genericListToNumber */
118 private List<Number> genericCompositeToNumber (List<CompositeData> cdlist, /* {{{ */
121 List<Object> objects = new ArrayList<Object> ();
123 for (int i = 0; i < cdlist.size (); i++)
131 value = cd.get (key);
133 catch (InvalidKeyException e)
140 return (genericListToNumber (objects));
141 } /* }}} List<Number> genericCompositeToNumber */
143 private void submitTable (List<Object> objects, ValueList vl) /* {{{ */
145 List<CompositeData> cdlist;
146 Set<String> keySet = null;
147 Iterator<String> keyIter;
149 cdlist = new ArrayList<CompositeData> ();
150 for (int i = 0; i < objects.size (); i++)
154 obj = objects.get (i);
155 if (obj instanceof CompositeData)
159 cd = (CompositeData) obj;
162 keySet = cd.getCompositeType ().keySet ();
168 Collectd.logError ("GenericJMXConfValue: At least one of the "
169 + "attributes was not of type `CompositeData', as required "
170 + "when table is set to `true'.");
175 assert (keySet != null);
177 keyIter = keySet.iterator ();
178 while (keyIter.hasNext ())
183 key = keyIter.next ();
184 values = genericCompositeToNumber (cdlist, key);
187 Collectd.logError ("GenericJMXConfValue: Cannot build a list of "
188 + "numbers for key " + key + ". Most likely not all attributes "
193 if (this._instance_prefix == null)
194 vl.setTypeInstance (key);
196 vl.setTypeInstance (this._instance_prefix + key);
197 vl.setValues (values);
199 Collectd.dispatchValues (vl);
201 } /* }}} void submitTable */
203 private void submitScalar (List<Object> objects, ValueList vl) /* {{{ */
207 values = genericListToNumber (objects);
210 Collectd.logError ("GenericJMXConfValue: Cannot convert list of "
211 + "objects to numbers.");
215 if (this._instance_prefix == null)
216 vl.setTypeInstance ("");
218 vl.setTypeInstance (this._instance_prefix);
219 vl.setValues (values);
221 Collectd.dispatchValues (vl);
222 } /* }}} void submitScalar */
224 private Object queryAttributeRecursive (CompositeData parent, /* {{{ */
225 List<String> attrName)
230 key = attrName.remove (0);
234 value = parent.get (key);
236 catch (InvalidKeyException e)
241 if (attrName.size () == 0)
247 if (value instanceof CompositeData)
248 return (queryAttributeRecursive ((CompositeData) value, attrName));
252 } /* }}} queryAttributeRecursive */
254 private Object queryAttribute (MBeanServerConnection conn, /* {{{ */
255 ObjectName objName, String attrName)
257 List<String> attrNameList;
260 String[] attrNameArray;
262 attrNameList = new ArrayList<String> ();
264 attrNameArray = attrName.split ("\\.");
265 key = attrNameArray[0];
266 for (int i = 1; i < attrNameArray.length; i++)
267 attrNameList.add (attrNameArray[i]);
271 value = conn.getAttribute (objName, key);
275 Collectd.logError ("GenericJMXConfValue.query: getAttribute failed: "
280 if (attrNameList.size () == 0)
286 if (value instanceof CompositeData)
287 return (queryAttributeRecursive((CompositeData) value, attrNameList));
288 else if (value instanceof OpenType)
290 OpenType ot = (OpenType) value;
291 Collectd.logNotice ("GenericJMXConfValue: Handling of OpenType \""
292 + ot.getTypeName () + "\" is not yet implemented.");
297 Collectd.logError ("GenericJMXConfValue: Received object of "
302 } /* }}} Object queryAttribute */
304 private String getConfigString (OConfigItem ci) /* {{{ */
306 List<OConfigValue> values;
309 values = ci.getValues ();
310 if (values.size () != 1)
312 Collectd.logError ("GenericJMXConfValue: The " + ci.getKey ()
313 + " configuration option needs exactly one string argument.");
318 if (v.getType () != OConfigValue.OCONFIG_TYPE_STRING)
320 Collectd.logError ("GenericJMXConfValue: The " + ci.getKey ()
321 + " configuration option needs exactly one string argument.");
325 return (v.getString ());
326 } /* }}} String getConfigString */
328 private Boolean getConfigBoolean (OConfigItem ci) /* {{{ */
330 List<OConfigValue> values;
334 values = ci.getValues ();
335 if (values.size () != 1)
337 Collectd.logError ("GenericJMXConfValue: The " + ci.getKey ()
338 + " configuration option needs exactly one boolean argument.");
343 if (v.getType () != OConfigValue.OCONFIG_TYPE_BOOLEAN)
345 Collectd.logError ("GenericJMXConfValue: The " + ci.getKey ()
346 + " configuration option needs exactly one boolean argument.");
350 return (new Boolean (v.getBoolean ()));
351 } /* }}} String getConfigBoolean */
354 * Constructs a new value with the configured properties.
356 public GenericJMXConfValue (OConfigItem ci) /* {{{ */
357 throws IllegalArgumentException
359 List<OConfigItem> children;
360 Iterator<OConfigItem> iter;
362 this._ds_name = null;
364 this._attributes = new ArrayList<String> ();
365 this._instance_prefix = null;
366 this._is_table = false;
372 * Attribute "HeapMemoryUsage"
376 * InstancePrefix "heap-"
379 children = ci.getChildren ();
380 iter = children.iterator ();
381 while (iter.hasNext ())
383 OConfigItem child = iter.next ();
385 if (child.getKey ().equalsIgnoreCase ("Type"))
387 String tmp = getConfigString (child);
391 else if (child.getKey ().equalsIgnoreCase ("Table"))
393 Boolean tmp = getConfigBoolean (child);
395 this._is_table = tmp.booleanValue ();
397 else if (child.getKey ().equalsIgnoreCase ("Attribute"))
399 String tmp = getConfigString (child);
401 this._attributes.add (tmp);
403 else if (child.getKey ().equalsIgnoreCase ("InstancePrefix"))
405 String tmp = getConfigString (child);
407 this._instance_prefix = tmp;
410 throw (new IllegalArgumentException ("Unknown option: "
414 if (this._ds_name == null)
415 throw (new IllegalArgumentException ("No data set was defined."));
416 else if (this._attributes.size () == 0)
417 throw (new IllegalArgumentException ("No attribute was defined."));
418 } /* }}} GenericJMXConfValue (OConfigItem ci) */
421 * Query values via JMX according to the object's configuration and dispatch
424 * @param conn Connection to the MBeanServer.
425 * @param objName Object name of the MBean to query.
426 * @param pd Preset naming components. The members host, plugin and
427 * plugin instance will be used.
429 public void query (MBeanServerConnection conn, ObjectName objName, /* {{{ */
433 List<DataSource> dsrc;
436 if (this._ds == null)
438 this._ds = Collectd.getDS (this._ds_name);
439 if (this._ds == null)
441 Collectd.logError ("GenericJMXConfValue: Unknown type: "
447 dsrc = this._ds.getDataSources ();
448 if (dsrc.size () != this._attributes.size ())
450 Collectd.logError ("GenericJMXConfValue.query: The data set "
451 + this._ds_name + " has " + this._ds.getDataSources ().size ()
452 + " data sources, but there were " + this._attributes.size ()
453 + " attributes configured. This doesn't match!");
458 vl = new ValueList (pd);
459 vl.setType (this._ds_name);
460 vl.setTypeInstance (this._instance_prefix);
462 values = new ArrayList<Object> ();
464 assert (dsrc.size () == this._attributes.size ());
465 for (int i = 0; i < this._attributes.size (); i++)
469 v = queryAttribute (conn, objName, this._attributes.get (i));
472 Collectd.logError ("GenericJMXConfValue.query: "
473 + "Querying attribute " + this._attributes.get (i) + " failed.");
481 submitTable (values, vl);
483 submitScalar (values, vl);
484 } /* }}} void query */
487 /* vim: set sw=2 sts=2 et fdm=marker : */