io.pcp.parfait.jmx.MonitoredMBeanAttributeFactory Maven / Gradle / Ivy
Show all versions of parfait-jmx Show documentation
/*
* Copyright 2009-2017 Aconex
*
* Licensed under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package io.pcp.parfait.jmx;
import static tec.uom.se.AbstractUnit.ONE;
import java.io.IOException;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.openmbean.CompositeData;
import javax.measure.Unit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.jmx.support.JmxUtils;
import io.pcp.parfait.Monitorable;
import io.pcp.parfait.MonitorableRegistry;
import io.pcp.parfait.MonitoredConstant;
import io.pcp.parfait.MonitoredValue;
import io.pcp.parfait.PollingMonitoredValue;
import io.pcp.parfait.ValueSemantics;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.base.Supplier;
/**
* Factory bean that generates a monitor which tracks the value of the provided MBean attribute.
*
* Support is provided for monitoring simple attributes and also the data items of attributes that
* are of type {@link CompositeData}.
*/
public class MonitoredMBeanAttributeFactory implements FactoryBean> {
public static final Logger LOG = LoggerFactory.getLogger(MonitoredMBeanAttributeFactory.class.getName());
/**
* May be passed as the update interval to indicate that no updates are required. This is useful
* for tracking attributes which will never change in value.
*/
public static final int DO_NOT_UPDATE_VALUE = -1;
private final String name;
private final String description;
private final ObjectName mBeanName;
private final String attributeName;
private final String compositeDataItem;
private MBeanServerConnection server;
private int updateInterval = DO_NOT_UPDATE_VALUE;
private Unit> unit = ONE;
private ValueSemantics semantics = ValueSemantics.FREE_RUNNING;
private MonitorableRegistry monitorableRegistry = MonitorableRegistry.DEFAULT_REGISTRY;
public MonitoredMBeanAttributeFactory(String name, String description,
String mBeanName, String attributeName) {
this(name, description, mBeanName, attributeName, null,
JmxUtils.locateMBeanServer());
}
public MonitoredMBeanAttributeFactory(String name, String description,
String mBeanName, String attributeName, String compositeDataItem) {
this(name, description, mBeanName, attributeName, compositeDataItem,
JmxUtils.locateMBeanServer());
}
public MonitoredMBeanAttributeFactory(String name, String description,
String mBeanName, String attributeName, String compositeDataItem,
MBeanServerConnection server) {
this.name = name;
this.server = server;
this.description = description;
this.attributeName = attributeName;
this.compositeDataItem = compositeDataItem;
String beanName = registerBeanName(server, mBeanName);
try {
this.mBeanName = new ObjectName(beanName);
} catch (Exception e) {
throw new RuntimeException("Unexpected exception mBeanName name [" + mBeanName
+ "]", e);
}
}
public void setMonitorableRegistry(MonitorableRegistry registry) {
this.monitorableRegistry = Preconditions.checkNotNull(registry);
}
public void setUpdateInterval(int updateInterval) {
this.updateInterval = updateInterval;
}
public void setValueSemantics(ValueSemantics semantics) {
this.semantics = Preconditions.checkNotNull(semantics);
}
public void setUnit(Unit> unit) {
this.unit = unit;
}
public Monitorable getObject() throws InstanceNotFoundException, IntrospectionException,
ReflectionException, AttributeNotFoundException, MBeanException, IOException {
MBeanInfo beanInfo = server.getMBeanInfo(mBeanName);
MBeanAttributeInfo monitoredAttribute = null;
MBeanAttributeInfo[] attributes = beanInfo.getAttributes();
for (MBeanAttributeInfo attribute : attributes) {
if (attribute.getName().equals(attributeName)) {
monitoredAttribute = attribute;
break;
}
}
if (monitoredAttribute == null) {
throw new UnsupportedOperationException("MBean [" + mBeanName
+ "] does not have an attribute named [" + attributeName + "]");
}
if (!Strings.isNullOrEmpty(compositeDataItem)) {
Preconditions
.checkState(
CompositeData.class.getName().equals(
monitoredAttribute.getType()),
"MBean [%s] attribute [%s] must be of type CompositeData if compositeDataItem is provided",
mBeanName, attributeName);
CompositeData data = (CompositeData) server.getAttribute(mBeanName, attributeName);
Preconditions
.checkState(
data.getCompositeType().getType(compositeDataItem) != null,
"MBean [%s] attribute [%s] does not have a data item called [%s]",
mBeanName, attributeName, compositeDataItem);
}
if (isConstant()) {
return new MonitoredConstant(name, description, getAttributeValue());
} else {
return new PollingMonitoredValue(name, description, monitorableRegistry, updateInterval, new Supplier() {
public T get() {
return getAttributeValue();
}
}, semantics, unit);
}
}
public Class> getObjectType() {
return isConstant() ? MonitoredConstant.class : MonitoredValue.class;
}
private boolean isConstant() {
return updateInterval == DO_NOT_UPDATE_VALUE;
}
public boolean isSingleton() {
return true;
}
@SuppressWarnings("unchecked")
protected T getAttributeValue() {
try {
if (!Strings.isNullOrEmpty(compositeDataItem)) {
CompositeData data = (CompositeData) server.getAttribute(mBeanName, attributeName);
return (T) data.get(compositeDataItem);
} else {
return (T) server.getAttribute(mBeanName, attributeName);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private String registerBeanName(MBeanServerConnection server, String beanName) {
int pos = beanName.lastIndexOf(",name=");
if (pos > 0) {
String baseString = beanName.substring(0, pos);
Iterable namesString = Splitter.on('|').split(beanName.substring(beanName.lastIndexOf("=")+1));
for (String name : namesString) {
try {
String returnValue = baseString+",name="+name;
ObjectName objectName = new ObjectName(returnValue);
if (server.isRegistered(objectName)) {
LOG.trace(this.name + " registered as " + returnValue);
return returnValue;
}
}
catch (MalformedObjectNameException mone) {
throw new RuntimeException("Unexpected exception mBeanName name [" + beanName
+ "]", mone);
} catch (IOException ioe) {
throw new RuntimeException("Unexpected IO error, mBeanName name [" + beanName
+ "]", ioe);
}
}
}
return beanName;
}
}