/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2006-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) 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, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) 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 OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.netmgt.collectd;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
import org.opennms.core.utils.InetAddressUtils;
import org.opennms.core.utils.LogUtils;
import org.opennms.core.utils.ParameterMap;
import org.opennms.netmgt.config.BeanInfo;
import org.opennms.netmgt.config.DataSourceFactory;
import org.opennms.netmgt.config.JMXDataCollectionConfigFactory;
import org.opennms.netmgt.config.collectd.jmx.Attrib;
import org.opennms.netmgt.config.collector.AttributeGroupType;
import org.opennms.netmgt.config.collector.CollectionAttribute;
import org.opennms.netmgt.config.collector.CollectionAttributeType;
import org.opennms.netmgt.config.collector.CollectionResource;
import org.opennms.netmgt.config.collector.CollectionSet;
import org.opennms.netmgt.config.collector.CollectionSetVisitor;
import org.opennms.netmgt.config.collector.Persister;
import org.opennms.netmgt.config.collector.ServiceParameters;
import org.opennms.netmgt.model.RrdRepository;
import org.opennms.netmgt.model.events.EventProxy;
import org.opennms.protocols.jmx.connectors.ConnectionWrapper;
/**
* This class performs the collection and storage of data. The derived class
* manages the connection and configuration. The SNMPCollector class was used
* as the starting point for this class so anyone familiar with it should be
* able to easily understand it.
* <p>
* The jmx-datacollection-config.xml defines a list of MBeans and attributes
* that may be monitored. This class retrieves the list of MBeans for the
* specified service name (currently jboss and jsr160) and queries the remote
* server for the attributes. The values are then stored in RRD files.
* </p>
* <p>
* Two types of MBeans may be specified in the jmx-datacollection-config.xml
* file. Standard MBeans which consist of and ObjectName and their attributes,
* and WildCard MBeans which performs a query to retieve MBeans based on a
* criteria. The current implementation looks like: jboss:a=b,c=d,* Future
* versions may permit enhanced queries. In either case multiple MBeans may be
* returned and these MBeans would then be queried to obtain their attributes.
* There are some important issues then using the wild card appraoch:
* </p>
* <p>
* <ol>
* <li>Since multiple MBeans will have the same attribute name there needs to
* be a way to differentiate them. To handle this situation you need to
* specify which field in the ObjectName should be used. This is defined as
* the key-field.</li>
* <li>The version of RRD that is used is limited to 19 characters. If this
* limit is exceeded then the data will not be saved. The name is defined as:
* keyField_attributeName.rrd Since the keyfield is defined in the Object Name
* and may be too long, you may define an alias for it. The key-alias
* parameter permit you to define a list of names to be substituted. Only
* exact matches are handled. An example is:
* <code>key-alias="this-name-is-long|thisIsNot,name-way-2-long,goodName"</code></li>
* <li>If there are keyfields that you want to exclude (exact matches) you
* may use a comma separated list like:
* <code>exclude="name1,name2,name3"</code></li>
* <li>Unlike the Standard MBeans there is no way (currently) to pre-define
* graphs for them in the snmp-graph.properties file. The only way you can
* create graphs is to create a custom graph in the Report section. The wild
* card approach needs to be carefully considered before using it but it can
* cut down on the amount of work necessary to define what to save.</li>
* </ol>
* </p>
*
* @author <a href="mailto:mike@opennms.org">Mike Jamison</a>
* @author <a href="http://www.opennms.org/">OpenNMS</a>
*/
public abstract class JMXCollector implements ServiceCollector {
/**
* Interface attribute key used to store the map of IfInfo objects which
* hold data about each interface on a particular node.
*/
static String IF_MAP_KEY = "org.opennms.netmgt.collectd.JBossCollector.ifMap";
/**
* RRD data source name max length.
*/
private static final int MAX_DS_NAME_LENGTH = 19;
/**
* In some circumstances there may be many instances of a given service
* but running on different ports. Rather than using the port as the
* identfier users may define a more meaninful name.
*/
private boolean useFriendlyName = false;
/**
* Interface attribute key used to store a JMXNodeInfo object which holds
* data about the node being polled.
*/
static String NODE_INFO_KEY =
"org.opennms.netmgt.collectd.JMXCollector.nodeInfo";
/**
* The service name is provided by the derived class
*/
private String serviceName = null;
/**
* <p>
* Returns the name of the service that the plug-in collects ("JMX").
* </p>
*
* @return The service that the plug-in collects.
*/
public String serviceName() {
return serviceName.toUpperCase();
}
/**
* <p>Setter for the field <code>serviceName</code>.</p>
*
* @param name a {@link java.lang.String} object.
*/
public void setServiceName(String name) {
serviceName = name;
}
/**
* {@inheritDoc}
*
* <p>
* Initialize the service collector.
* </p>
* <p>
* During initialization the JMX collector: - Initializes various
* configuration factories. - Verifies access to the database - Verifies
* access to RRD file repository - Verifies access to JNI RRD shared
* library - Determines if JMX to be stored for only the node'sprimary
* interface or for all interfaces.
* </p>
* @exception RuntimeException
* Thrown if an unrecoverable error occurs that prevents
* the plug-in from functioning.
*/
public void initialize(Map<String, String> parameters) {
// Initialize the JMXDataCollectionConfigFactory
try {
// XXX was reload(), which isn't test-friendly
JMXDataCollectionConfigFactory.init();
} catch (Throwable e) {
LogUtils.errorf(this, e, "initialize: Failed to load data collection configuration");
throw new UndeclaredThrowableException(e);
}
// Make sure we can connect to the database
java.sql.Connection ctest = null;
try {
DataSourceFactory.init();
ctest = DataSourceFactory.getInstance().getConnection();
} catch (final Exception e) {
LogUtils.errorf(this, e, "initialize: failed to get a database connection");
throw new UndeclaredThrowableException(e);
} finally {
if (ctest != null) {
try {
ctest.close();
} catch (final Throwable t) {
LogUtils.debugf(this, "initialize: an exception occured while closing the JDBC connection");
}
}
}
// Save local reference to singleton instance
LogUtils.debugf(this, "initialize: successfully instantiated JNI interface to RRD.");
}
/**
* Responsible for freeing up any resources held by the collector.
*/
public void release() {
// Nothing to release...
}
/**
* {@inheritDoc}
*
* Responsible for performing all necessary initialization for the
* specified interface in preparation for data collection.
*/
public void initialize(CollectionAgent agent, Map<String, Object> parameters) {
InetAddress ipAddr = (InetAddress) agent.getAddress();
int nodeID = agent.getNodeId();
// Retrieve the name of the JMX data collector
String collectionName = ParameterMap.getKeyedString(parameters, "collection", serviceName);
final String hostAddress = InetAddressUtils.str(ipAddr);
LogUtils.debugf(this, "initialize: InetAddress=%s, collectionName=%s", hostAddress, collectionName);
JMXNodeInfo nodeInfo = new JMXNodeInfo(nodeID);
LogUtils.debugf(this, "nodeInfo: %s %d %s", hostAddress, nodeID, agent);
/*
* Retrieve list of MBean objects to be collected from the
* remote agent which are to be stored in the node-level RRD file.
* These objects pertain to the node itself not any individual
* interfaces.
*/
Map<String, List<Attrib>> attrMap = JMXDataCollectionConfigFactory.getInstance().getAttributeMap(collectionName, serviceName, hostAddress);
nodeInfo.setAttributeMap(attrMap);
Map<String, JMXDataSource> dsList = buildDataSourceList(collectionName, attrMap);
nodeInfo.setDsMap(dsList);
nodeInfo.setMBeans(JMXDataCollectionConfigFactory.getInstance().getMBeanInfo(collectionName));
// Add the JMXNodeInfo object as an attribute of the interface
agent.setAttribute(NODE_INFO_KEY, nodeInfo);
agent.setAttribute("collectionName", collectionName);
}
/**
* {@inheritDoc}
*
* Responsible for releasing any resources associated with the specified
* interface.
*/
public void release(CollectionAgent agent) {
// Nothing to release...
}
/**
* <p>getMBeanServerConnection</p>
*
* @param map a {@link java.util.Map} object.
* @param address a {@link java.net.InetAddress} object.
* @return a {@link org.opennms.protocols.jmx.connectors.ConnectionWrapper} object.
*/
public abstract ConnectionWrapper getMBeanServerConnection(Map<String, Object> map, InetAddress address);
/**
* {@inheritDoc}
*
* Perform data collection.
*/
public CollectionSet collect(CollectionAgent agent, EventProxy eproxy, Map<String, Object> map) {
InetAddress ipaddr = (InetAddress) agent.getAddress();
JMXNodeInfo nodeInfo = agent.getAttribute(NODE_INFO_KEY);
Map<String, BeanInfo> mbeans = nodeInfo.getMBeans();
String collDir = serviceName;
String port = ParameterMap.getKeyedString(map, "port", null);
String friendlyName = ParameterMap.getKeyedString(map,"friendly-name", port);
if (useFriendlyName) {
collDir = friendlyName;
}
JMXCollectionSet collectionSet=new JMXCollectionSet(agent,collDir);
collectionSet.setCollectionTimestamp(new Date());
JMXCollectionResource collectionResource=collectionSet.getResource();
ConnectionWrapper connection = null;
LogUtils.debugf(this, "collecting %s on node ID %d", InetAddressUtils.str(ipaddr), nodeInfo.getNodeId());
try {
connection = getMBeanServerConnection(map, ipaddr);
if (connection == null) {
return collectionSet;
}
MBeanServerConnection mbeanServer = connection.getMBeanServer();
int retry = ParameterMap.getKeyedInteger(map, "retry", 3);
for (int attempts = 0; attempts <= retry; attempts++) {
try {
/*
* Iterate over the mbeans, for each object name perform a
* getAttributes, the update the RRD.
*/
for (Iterator<BeanInfo> iter = mbeans.values().iterator(); iter.hasNext();) {
BeanInfo beanInfo = iter.next();
String objectName = beanInfo.getObjectName();
String excludeList = beanInfo.getExcludes();
//All JMX collected values are per node
AttributeGroupType attribGroupType=new AttributeGroupType(fixGroupName(objectName),"all");
List<String> attribNames = beanInfo.getAttributeNames();
List<String> compAttribNames = beanInfo.getCompositeAttributeNames();
for (String compAttribName : compAttribNames) {
if (attribNames.contains(compAttribName) ) {
attribNames.remove(compAttribName);
String[] ac = (String[])compAttribName.split("\\|", -1);
String attrName = ac[0];
if (!attribNames.contains(attrName)) {
attribNames.add(attrName);
}
}
}
//log.debug(" JMXCollector: processed the following attributes: " + attribNames.toString());
//log.debug(" JMXCollector: processed the following Composite Attributes: " + compAttribNames.toString());
String[] attrNames = (String[])attribNames.toArray(new String[attribNames.size()]);
if (objectName.indexOf("*") == -1) {
LogUtils.debugf(this, "%s Collector - getAttributes: %s, # attributes: %d, # composite attribute members: %d", serviceName, objectName, attrNames.length, compAttribNames.size());
try {
ObjectName oName = new ObjectName(objectName);
if (mbeanServer.isRegistered(oName)) {
AttributeList attrList = mbeanServer.getAttributes(oName, attrNames);
Map<String, JMXDataSource> dsMap = nodeInfo.getDsMap();
for(Object attribute : attrList) {
List<String> compositeMemberKeys = new ArrayList<String>();
Boolean isComposite = false;
Attribute attrib=(Attribute)attribute;
for (String compAttrName : compAttribNames ) {
String[] attribKeys = compAttrName.split("\\|", -1);
if (attrib.getName().equals(attribKeys[0])) {
compositeMemberKeys.add(attribKeys[1]);
isComposite = true;
}
}
if (isComposite) {
try {
CompositeData cd = (CompositeData)attrib.getValue();
for (String key : compositeMemberKeys) {
/*
value = cd.get(key);
log.debug(" JMXCollector - got CompositeData: " +
objectName + "|" + attrib.getName() + "|" + key + " |-> " + cd.get(key).toString());
*/
JMXDataSource ds = dsMap.get(objectName + "|" + attrib.getName() + "|" + key);
JMXCollectionAttributeType attribType=new JMXCollectionAttributeType(ds, null, null, attribGroupType);
collectionResource.setAttributeValue(attribType, cd.get(key).toString());
}
} catch (final ClassCastException cce) {
LogUtils.debugf(this, cce, "%s Collection - getAttributes (try CompositeData) - ERROR: Failed to cast attribute value to type CompositeData!", serviceName);
}
}
else {
// this is a normal attribute, so fallback to default handler
JMXDataSource ds = dsMap.get(objectName + "|" + attrib.getName());
JMXCollectionAttributeType attribType=new JMXCollectionAttributeType(ds, null, null, attribGroupType);
collectionResource.setAttributeValue(attribType, attrib.getValue().toString());
}
}
}
} catch (final InstanceNotFoundException e) {
LogUtils.errorf(this, e, "Unable to retrieve attributes from %s", objectName);
}
} else {
/*
* This section is for ObjectNames that use the
* '*' wildcard
*/
Set<ObjectName> mbeanSet = getObjectNames(mbeanServer, objectName);
for (Iterator<ObjectName> objectNameIter = mbeanSet.iterator(); objectNameIter.hasNext(); ) {
ObjectName oName = objectNameIter.next();
LogUtils.debugf(this, "%s Collector - getAttributesWC: %s, # attributes: %d, alias: %s", serviceName, oName, attrNames.length, beanInfo.getKeyAlias());
try {
if (excludeList == null) {
// the exclude list doesn't apply
if (mbeanServer.isRegistered(oName)) {
AttributeList attrList = mbeanServer.getAttributes(oName,
attrNames);
Map<String, JMXDataSource> dsMap = nodeInfo.getDsMap();
for(Object attribute : attrList) {
Attribute attrib=(Attribute)attribute;
JMXDataSource ds = dsMap.get(objectName + "|"
+ attrib.getName());
JMXCollectionAttributeType attribType=
new JMXCollectionAttributeType(ds,
oName.getKeyProperty(beanInfo.getKeyField()),
beanInfo.getKeyAlias(),
attribGroupType);
collectionResource.setAttributeValue(attribType, attrib.getValue().toString());
}
}
} else {
/*
* filter out calls if the key field
* matches an entry in the exclude
* list
*/
String keyName = oName.getKeyProperty(beanInfo.getKeyField());
boolean found = false;
StringTokenizer st = new StringTokenizer(
excludeList,
",");
while (st.hasMoreTokens()) {
if (keyName.equals(st.nextToken())) {
found = true;
break;
}
}
if (!found) {
if (mbeanServer.isRegistered(oName)) {
AttributeList attrList =
(AttributeList)
mbeanServer.getAttributes(oName,
attrNames);
Map<String, JMXDataSource> dsMap = nodeInfo.getDsMap();
for(Object attribute : attrList) {
Attribute attrib=(Attribute)attribute;
JMXDataSource ds = dsMap.get(objectName + "|" + attrib.getName());
JMXCollectionAttributeType attribType = new JMXCollectionAttributeType(ds,
oName.getKeyProperty(beanInfo.getKeyField()),
beanInfo.getKeyAlias(),
attribGroupType);
collectionResource.setAttributeValue(attribType, attrib.getValue().toString());
}
}
}
}
} catch (final InstanceNotFoundException e) {
LogUtils.errorf(this, e, "Error retrieving attributes for %s", oName);
}
}
}
}
break;
} catch (final Exception e) {
LogUtils.debugf(this, e, "%s Collector.collect: IOException while collecting address: %s", serviceName, agent.getAddress());
}
}
} catch (final Exception e) {
LogUtils.errorf(this, e, "Error getting MBeanServer");
} finally {
if (connection != null) {
connection.close();
}
}
collectionSet.setStatus(ServiceCollector.COLLECTION_SUCCEEDED);
return collectionSet;
}
private Set<ObjectName> getObjectNames(MBeanServerConnection mbeanServer, String objectName) throws IOException,
MalformedObjectNameException {
return mbeanServer.queryNames(new ObjectName(objectName), null);
}
/**
* This method removes characters from an object name that are
* potentially illegal in a file or directory name, returning a
* name that is appropriate for use with the storeByGroup persistence
* method.
*
* @param objectName
* @return
*/
private String fixGroupName(String objectName) {
if (objectName == null) {
return "NULL";
}
return objectName.replaceAll("[.:=,]", "_");
}
/*
* This method strips out the illegal character '/' and attempts to keep
* the length of the key plus ds name to 19 or less characters. The slash
* character cannot be in the name since it is an illegal character in
* file names.
*/
private String fixKey(String key, String attrName, String substitutions) {
String newKey = key;
if (key.startsWith(File.separator)) {
newKey = key.substring(1);
}
if (substitutions != null && substitutions.length() > 0) {
StringTokenizer st = new StringTokenizer(substitutions, ",");
while (st.hasMoreTokens()) {
String token = st.nextToken();
int index = token.indexOf("|");
if (newKey.equals(token.substring(0, index))) {
newKey = token.substring(index + 1);
}
}
}
return newKey;
}
/**
* <p>getRRDValue_isthis_used_</p>
*
* @param ds
* @param dsVal
* @param collectorEntry a {@link org.opennms.netmgt.collectd.JMXCollectorEntry} object.
* @throws java.lang.IllegalArgumentException if any.
* @return a {@link java.lang.String} object.
*/
public String getRRDValue_isthis_used_(JMXDataSource ds,
JMXCollectorEntry collectorEntry) throws IllegalArgumentException {
LogUtils.debugf(this, "getRRDValue: %s", ds.getName());
// Make sure we have an actual object id value.
if (ds.getOid() == null) {
return null;
}
return (String) collectorEntry.get(collectorEntry + "|" + ds.getOid());
}
/**
* This method is responsible for building a list of RRDDataSource objects
* from the provided list of MBeanObject objects.
*
* @param collectionName
* Collection name
* @param oidList
* List of MBeanObject objects defining the oid's to be
* collected via JMX.
* @return list of RRDDataSource objects
*/
private Map<String, JMXDataSource> buildDataSourceList(String collectionName, Map<String, List<Attrib>> attributeMap) {
LogUtils.debugf(this, "buildDataSourceList - ***");
/*
* Retrieve the RRD expansion data source list which contains all
* the expansion data source's. Use this list as a basis
* for building a data source list for the current interface.
*/
HashMap<String, JMXDataSource> dsList = new HashMap<String, JMXDataSource>();
/*
* Loop through the MBean object list to be collected for this
* interface and add a corresponding RRD data source object. In this
* manner each interface will have RRD files create which reflect only
* the data sources pertinent to it.
*/
LogUtils.debugf(this, "attributeMap size: %d", attributeMap.size());
Iterator<String> objNameIter = attributeMap.keySet().iterator();
while (objNameIter.hasNext()) {
String objectName = objNameIter.next().toString();
List<Attrib> list = attributeMap.get(objectName);
LogUtils.debugf(this, "ObjectName: %s, Attributes: %d", objectName, list.size());
Iterator<Attrib> iter = list.iterator();
while (iter.hasNext()) {
Attrib attr = iter.next();
JMXDataSource ds = null;
/*
* Verify that this object has an appropriate "integer" data
* type which can be stored in an RRD database file (must map to
* one of the supported RRD data source types: COUNTER or GAUGE).
* */
String ds_type = JMXDataSource.mapType(attr.getType());
if (ds_type != null) {
/*
* Passed!! Create new data source instance for this MBean
* object.
* Assign heartbeat using formula (2 * step) and hard code
* min & max values to "U" ("unknown").
*/
ds = new JMXDataSource();
ds.setHeartbeat(2 * JMXDataCollectionConfigFactory.getInstance().getStep(
collectionName));
// For completeness, adding a minval option to the variable.
String ds_minval = attr.getMinval();
if (ds_minval == null) {
ds_minval = "U";
}
ds.setMax(ds_minval);
/*
* In order to handle counter wraps, we need to set a max
* value for the variable.
*/
String ds_maxval = attr.getMaxval();
if (ds_maxval == null) {
ds_maxval = "U";
}
ds.setMax(ds_maxval);
ds.setInstance(collectionName);
/*
* Truncate MBean object name/alias if it exceeds 19 char
* max for RRD data source names.
*/
String ds_name = attr.getAlias();
if (ds_name.length() > MAX_DS_NAME_LENGTH) {
LogUtils.warnf(this, "buildDataSourceList: alias '%s' exceeds 19 char maximum for RRD data source names, truncating.", attr.getAlias());
char[] temp = ds_name.toCharArray();
ds_name = String.copyValueOf(temp, 0,
MAX_DS_NAME_LENGTH);
}
ds.setName(ds_name);
// Map MBean object data type to RRD data type
ds.setType(ds_type);
/*
* Assign the data source object identifier and instance
* ds.setName(attr.getName());
*/
ds.setOid(attr.getName());
LogUtils.debugf(this, "buildDataSourceList: ds_name: %s ds_oid: %s.%s ds_max: %s ds_min: %s", ds.getName(), ds.getOid(), ds.getInstance(), ds.getMax(), ds.getMin());
// Add the new data source to the list
dsList.put(objectName + "|" + attr.getName(), ds);
} else {
LogUtils.warnf(this, "buildDataSourceList: Data type '%s' not supported. Only integer-type data may be stored in RRD. MBean object '%s' will not be mapped to RRD data source.", attr.getType(), attr.getAlias());
}
}
}
return dsList;
}
/**
* <p>Setter for the field <code>useFriendlyName</code>.</p>
*
* @param useFriendlyName a boolean.
*/
public void setUseFriendlyName(boolean useFriendlyName) {
this.useFriendlyName = useFriendlyName;
}
class JMXCollectionAttributeType implements CollectionAttributeType {
JMXDataSource m_dataSource;
AttributeGroupType m_groupType;
String m_name;
protected JMXCollectionAttributeType(JMXDataSource dataSource, String key, String substitutions, AttributeGroupType groupType) {
m_groupType=groupType;
m_dataSource=dataSource;
m_name=createName(key,substitutions);
}
private String createName(String key, String substitutions) {
String name=m_dataSource.getName();
if(key!=null && !key.equals("")) {
name=fixKey(key, m_dataSource.getName(),substitutions)+"_"+name;
}
return name;
}
public AttributeGroupType getGroupType() {
return m_groupType;
}
public void storeAttribute(CollectionAttribute attribute, Persister persister) {
//Only numeric data comes back from JMX in data collection
persister.persistNumericAttribute(attribute);
}
public String getName() {
return m_name;
}
public String getType() {
return m_dataSource.getType();
}
}
class JMXCollectionAttribute extends AbstractCollectionAttribute implements CollectionAttribute {
String m_alias;
String m_value;
JMXCollectionResource m_resource;
CollectionAttributeType m_attribType;
JMXCollectionAttribute(JMXCollectionResource resource, CollectionAttributeType attribType, String alias, String value) {
super();
m_resource=resource;
m_attribType=attribType;
m_alias = alias;
m_value = value;
}
public CollectionAttributeType getAttributeType() {
return m_attribType;
}
public String getName() {
return m_alias;
}
public String getNumericValue() {
return m_value;
}
public CollectionResource getResource() {
return m_resource;
}
public String getStringValue() {
return m_value;
}
public boolean shouldPersist(ServiceParameters params) {
return true;
}
public String getType() {
return m_attribType.getType();
}
public String toString() {
return "alias " + m_alias + ", value " + m_value + ", resource "
+ m_resource + ", attributeType " + m_attribType;
}
}
class JMXCollectionResource extends AbstractCollectionResource {
String m_resourceName;
private int m_nodeId;
JMXCollectionResource(CollectionAgent agent, String resourceName) {
super(agent);
m_resourceName=resourceName;
m_nodeId = agent.getNodeId();
}
public String toString() {
return "node["+m_nodeId+']';
}
public int getType() {
return -1; //Is this correct?
}
public boolean rescanNeeded() {
return false;
}
public boolean shouldPersist(ServiceParameters params) {
return true;
}
public void setAttributeValue(CollectionAttributeType type, String value) {
JMXCollectionAttribute attr = new JMXCollectionAttribute(this, type, type.getName(), value);
addAttribute(attr);
}
@Override
public File getResourceDir(RrdRepository repository) {
return new File(repository.getRrdBaseDir(), Integer.toString(m_agent.getNodeId())+ File.separator+ m_resourceName);
}
public String getResourceTypeName() {
return "node"; //All node resources for JMX; nothing of interface or "indexed resource" type
}
public String getInstance() {
return null; //For node type resources, use the default instance
}
public String getParent() {
return Integer.toString(m_nodeId);
}
}
class JMXCollectionSet implements CollectionSet {
private int m_status;
private Date m_timestamp;
private JMXCollectionResource m_collectionResource;
JMXCollectionSet(CollectionAgent agent, String resourceName) {
m_status=ServiceCollector.COLLECTION_FAILED;
m_collectionResource=new JMXCollectionResource(agent, resourceName);
}
public JMXCollectionResource getResource() {
return m_collectionResource;
}
public void setStatus(int status) {
m_status=status;
}
public int getStatus() {
return m_status;
}
public void visit(CollectionSetVisitor visitor) {
visitor.visitCollectionSet(this);
m_collectionResource.visit(visitor);
visitor.completeCollectionSet(this);
}
public boolean ignorePersist() {
return false;
}
@Override
public Date getCollectionTimestamp() {
return m_timestamp;
}
public void setCollectionTimestamp(Date timestamp) {
this.m_timestamp = timestamp;
}
}
/** {@inheritDoc} */
public RrdRepository getRrdRepository(String collectionName) {
return JMXDataCollectionConfigFactory.getInstance().getRrdRepository(collectionName);
}
}