package netflix.adminresources.resources.jmx;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.openmbean.CompositeDataSupport;
import java.lang.management.ManagementFactory;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JmxService {
private static final Logger LOG = LoggerFactory.getLogger(JmxService.class);
private static final String CSV_PATTERN = "\"([^\"]+?)\",?|([^,]+),?|,";
private static final String CURRENT_VALUE = "CurrentValue";
private static final String MODE_DOMAIN = "domain";
private static final String MODE_INNER = "inner";
private static final String MODE_LEAF = "leaf";
private static class Holder {
private static final JmxService instance = new JmxService();
}
private final MBeanServer mBeanServer;
private static Pattern csvRE = Pattern.compile(CSV_PATTERN);
private JmxService() {
mBeanServer = ManagementFactory.getPlatformMBeanServer();
}
public static JmxService getInstance() {
return Holder.instance;
}
/**
* Return the list of all domains on this server
* @return
*/
public List<String> getDomainList() {
return Lists.newArrayList(mBeanServer.getDomains());
}
/**
* Return subtree of nodes for a domain
*/
public DynaTreeNode getDomainTree(String domainName) {
DynaTreeNode domainNode = new DynaTreeNode()
.setTitle(domainName)
.setKey(domainName)
.setMode(MODE_DOMAIN);
try {
// List all objects in the domain
ObjectName name = new ObjectName(domainName + ":*");
Set<ObjectName> objs = mBeanServer.queryNames(name, null);
// Convert object naems to a tree
for (ObjectName objName : objs) {
MBeanInfo info = mBeanServer.getMBeanInfo(objName);
Matcher m = csvRE.matcher(objName.getKeyPropertyListString());
DynaTreeNode node = domainNode;
StringBuilder innerKey = new StringBuilder();
innerKey.append(domainName).append(":");
while (m.find()) {
String title = StringUtils.removeEnd(m.group(), ",");
String key = StringUtils.substringBefore(title, "=");
String value = StringUtils.substringAfter(title, "=");
value = StringUtils.removeStart(value, "\"");
value = StringUtils.removeEnd (value, "\"");
innerKey.append(title).append(",");
DynaTreeNode next = node.getChild(value);
if (next == null) {
next = new DynaTreeNode()
.setTitle(value)
.setMode(MODE_INNER)
.setKey(innerKey.toString() + "*")
.setNoLink(false);
node.putChild(next);
}
node = next;
}
node.setKey(objName.getCanonicalName())
.setMode(MODE_LEAF);
if ( info.getAttributes() != null
|| info.getOperations() != null
|| info.getNotifications() != null) {
node.setNoLink(false);
}
}
} catch (MalformedObjectNameException e) {
LOG.error("Exception in getDomainTree ", e);
} catch (IntrospectionException e) {
LOG.error("Exception in getDomainTree ", e);
} catch (ReflectionException e) {
LOG.error("Exception in getDomainTree ", e);
} catch (InstanceNotFoundException e) {
LOG.error("Exception in getDomainTree ", e);
} catch (RuntimeException e) {
LOG.error("Exception in getDomainTree ", e);
}
return domainNode;
}
/**
* Return all keysace in a domain
* @param domainName
* @return
*/
public List<String> getDomainKeys(String domainName) {
return getKeysFromRegex(domainName + ":*");
}
/**
* Return the list of all keys matching a regex
* @param regex
* @return
*/
public List<String> getKeysFromRegex(String regex) {
List<String> keys = Lists.newArrayList();
try {
// List all objects in the domain
ObjectName name = new ObjectName(regex);
Set<ObjectName> objs = mBeanServer.queryNames(name, null);
// Convert object naems to a tree
for (ObjectName objName : objs) {
MBeanInfo info = mBeanServer.getMBeanInfo(objName);
keys.add(objName.getCanonicalName());
}
} catch (Exception e) {
LOG.error("Exception in getKeysFromRegex ", e);
}
return keys;
}
/**
* Return a map of all attributes for objects matching the regex.
* @param regex
* @return
* @throws Exception
*/
public Map<String, Map<String, String>> getMBeanAttributesByRegex(String regex) throws Exception {
Map<String, Map<String, String>> result = Maps.newLinkedHashMap();
ObjectName name = new ObjectName(regex);
Set<ObjectName> objs = mBeanServer.queryNames(name, null);
// Convert object naems to a tree
for (ObjectName objName : objs) {
result.put(objName.getCanonicalName(), getMBeanAttributes(objName));
}
return result;
}
/**
* Get list of all attributes of the specified key
* @param key
* @return
*/
public Map<String, String> getMBeanAttributes(String key) throws Exception {
return getMBeanAttributes(new ObjectName(key));
}
/**
* Get list of all attributes of an object
* @param objName
* @return
* @throws Exception
*/
private Map<String, String> getMBeanAttributes(ObjectName objName) throws Exception {
Map<String, String> response = Maps.newLinkedHashMap();
// Look for the object
MBeanInfo mBeanInfo = mBeanServer.getMBeanInfo(objName);
if (mBeanInfo != null) {
// Does it have attributes?
MBeanAttributeInfo[] attrs = mBeanInfo.getAttributes();
if (attrs != null) {
// List all attributes
List<String> attrNames = Lists.newArrayList();
for (MBeanAttributeInfo attr : attrs) {
attrNames.add(attr.getName());
}
AttributeList attrList = mBeanServer.getAttributes(objName, attrNames.toArray(new String[0]));
// Process each attribute
for (Attribute attr : attrList.asList()) {
String attrName = attr.getName();
Object value = attr.getValue();
String attrValue = null;
// Attribute has data
if (value != null) {
// Special case of CompositeDataSuppert
if (value instanceof CompositeDataSupport) {
CompositeDataSupport compositeValue = (CompositeDataSupport) value;
if (compositeValue != null) {
try {
if (compositeValue.containsKey(CURRENT_VALUE)) {
Object curValue = compositeValue.get(CURRENT_VALUE);
attrValue = (curValue == null ? "null" : curValue.toString());
}
}
catch (Exception e) {
attrValue = compositeValue.toString();
}
}
}
if (attrValue == null) {
attrValue = value.toString();
}
}
else {
value = "none";
}
response.put(attrName, attrValue);
}
}
}
return response;
}
/**
* Return all operations for the specified mbean name
* @param name
* @return
* @throws Exception
*/
public MBeanOperationInfo[] getMBeanOperations(String name) throws Exception {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
MBeanInfo mBeanInfo = mBeanServer.getMBeanInfo(new ObjectName(name));
return mBeanInfo.getOperations();
}
}