package com.javamonitor;
import static com.javamonitor.mbeans.Server.serverObjectName;
import static java.lang.Integer.parseInt;
import static java.lang.Long.parseLong;
import static java.lang.management.ManagementFactory.getPlatformMBeanServer;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
import com.javamonitor.mbeans.DNSCachePolicy;
import com.javamonitor.mbeans.Server;
import com.javamonitor.mbeans.Threading;
/**
* The JMX facade, making JMX easy. Apart from making the JMX interface easier
* to use, this helper also does its best to find mbeans. The reason for doing
* this is that there may be more than one mbean server and we'd like to give
* Java-monitor a single view over all of those.
*
* @author Kees Jan Koster <kjkoster@kjkoster.org>
*/
public class JmxHelper {
/**
* The base of all the helper object names.
*/
public static final String objectNameBase = "com.javamonitor:type=";
private static MBeanServer findMBeanServer(final ObjectName objectName) {
final List<MBeanServer> servers = MBeanServerFactory
.findMBeanServer(null);
for (int i = 0; i < servers.size(); i++) {
try {
if (servers.get(i).getObjectInstance(objectName) != null) {
return servers.get(i);
}
} catch (InstanceNotFoundException e) {
// woops, not registered here...
}
}
// oh well, most likely it is here then...
return getPlatformMBeanServer();
}
/**
* Check that an mbean exists.
*
* @param objectName
* The bean to check for.
* @return <code>true</code> if the bean exists, or <code>false</code>
* otherwise.
*/
public static boolean mbeanExists(final String objectName) {
try {
final ObjectName name = new ObjectName(objectName);
return findMBeanServer(name).isRegistered(name);
} catch (Exception e) {
return false;
}
}
/**
* Register a new mbean in the platform mbean server.
*
* @param mbean
* The mbean to register.
* @param objectName
* The object name to register it under.
* @throws Exception
* When there was a problem registering MBeans.
*/
public static void register(final Object mbean, final String objectName)
throws Exception {
unregister(objectName);
getPlatformMBeanServer().registerMBean(mbean,
new ObjectName(objectName));
}
/**
* Query for a string, based on the object name as string. Convenience
* method that does the casts.
*
* @param objectName
* The object name to query.
* @param attribute
* The attribute to query.
* @return The value of the attribute, as string.
* @throws Exception
* When there was a problem querying.
*/
public static String queryString(final String objectName,
final String attribute) throws Exception {
final Object value = query(objectName, attribute);
return value == null ? null : value.toString();
}
/**
* Query for a string, based on the object name. Convenience method that
* does the casts.
*
* @param objectName
* The object name to query.
* @param attribute
* The attribute to query.
* @return The value of the attribute, as string.
* @throws Exception
* When there was a problem querying.
*/
public static String queryString(final ObjectName objectName,
final String attribute) throws Exception {
final Object value = query(objectName, attribute);
return value == null ? null : value.toString();
}
/**
* Query for an integer, based on the object name. Convenience method that
* does the casts.
*
* @param objectName
* The object name to query.
* @param attribute
* The attribute to query.
* @return The value of the attribute, as string.
* @throws Exception
* When there was a problem querying.
*/
public static Integer queryInt(final String objectName,
final String attribute) throws Exception {
final Object value = query(objectName, attribute);
return value == null ? null : parseInt(value.toString());
}
/**
* Query for an integer, based on the object name. Convenience method that
* does the casts.
*
* @param objectName
* The object name to query.
* @param attribute
* The attribute to query.
* @return The value of the attribute, as string.
* @throws Exception
* When there was a problem querying.
*/
public static Integer queryInt(final ObjectName objectName,
final String attribute) throws Exception {
final Object value = query(objectName, attribute);
return value == null ? null : parseInt(value.toString());
}
/**
* Query for a long, based on the object name. Convenience method that does
* the casts.
*
* @param objectName
* The object name to query.
* @param attribute
* The attribute to query.
* @return The value of the attribute, as string.
* @throws Exception
* When there was a problem querying.
*/
public static Long queryLong(final ObjectName objectName,
final String attribute) throws Exception {
final Object value = query(objectName, attribute);
return value == null ? null : parseLong(value.toString());
}
/**
* Query for a value, based on the object name as string. Convenience method
* that does the casts.
*
* @param objectName
* The object name to query.
* @param attribute
* The attribute to query.
* @return The value of the attribute, as string.
* @throws Exception
* When there was a problem querying.
*/
public static Object query(final String objectName, final String attribute)
throws Exception {
return query(new ObjectName(objectName), attribute);
}
/**
* Query a JMX attribute.
*
* @param objectName
* The name of the mbean to query.
* @param attribute
* The attribute to query on that mbean.
* @return The value of the attribute on the named object.
* @throws Exception
* When there was a problem querying.
*/
public static Object query(final ObjectName objectName,
final String attribute) throws Exception {
final int dot = attribute.indexOf('.');
if (dot < 0) {
return findMBeanServer(objectName).getAttribute(objectName,
attribute);
}
return resolveFields((CompositeData) findMBeanServer(objectName)
.getAttribute(objectName, attribute.substring(0, dot)),
attribute.substring(dot + 1));
}
private static Object resolveFields(final CompositeData attribute,
final String field) {
final int dot = field.indexOf('.');
if (dot < 0) {
final Object ret = attribute.get(field);
return ret == null ? null : ret;
}
return resolveFields((CompositeData) attribute.get(field.substring(0,
dot)), field.substring(dot + 1));
}
/**
* Find a list of object names.
*
* @param query
* The wildcarded object name to list.
* @return A list of matching object names.
* @throws MalformedObjectNameException
* When the query could not be parsed.
*/
public static Set<ObjectName> queryNames(final String query)
throws MalformedObjectNameException {
final ObjectName objectNameQuery = new ObjectName(query);
Set<ObjectName> names = new HashSet<ObjectName>();
final List<MBeanServer> servers = MBeanServerFactory
.findMBeanServer(null);
for (int i = 0; names.size() == 0 && i < servers.size(); i++) {
names = servers.get(i).queryNames(objectNameQuery, null);
}
if (names.size() == 0) {
names = getPlatformMBeanServer().queryNames(objectNameQuery, null);
}
return names;
}
/**
* Register the cool beans we need to find our way in the JMX jungle.
*
* @param server
* The server mbean to register.
* @throws Exception
* When one of the MBeans could not be registered.
*/
public static void registerCoolMBeans(final Server server) throws Exception {
register(server, serverObjectName);
register(new Threading(), Threading.objectName);
register(new DNSCachePolicy(), DNSCachePolicy.objectName);
}
/**
* Unregister all the useful mbeans from the JMX registry. We assume that
* the registered beans were registered in the platform mbean server.
*/
public static void unregisterCoolMBeans() {
unregister(serverObjectName);
unregister(Threading.objectName);
unregister(DNSCachePolicy.objectName);
}
/**
* Unregister an MBean, suppressing all errors that may arise. Good for
* making sure a bean really is not there. We assume that the registered
* bean was registered in the platform mbean server.
*
* @param objectName
* The object name of the MBean to unregister.
*/
public static void unregister(final String objectName) {
try {
getPlatformMBeanServer()
.unregisterMBean(new ObjectName(objectName));
} catch (Exception e) {
// ignore, this was just to clean up
}
}
}