InfoCommand.java
package org.cyclopsgroup.jmxterm.cmd;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Pattern;
import javax.management.JMException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanFeatureInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.cyclopsgroup.jcli.annotation.Cli;
import org.cyclopsgroup.jcli.annotation.Option;
import org.cyclopsgroup.jmxterm.Command;
import org.cyclopsgroup.jmxterm.Session;
/**
* Command that displays attributes and operations of an MBean
*
* @author <a href="mailto:jiaqi.guo@gmail.com">Jiaqi Guo</a>
*/
@Cli(
name = "info",
description = "Display detail information about an MBean",
note = "If -b option is not specified, current selected MBean is applied")
public class InfoCommand extends Command {
private static final Comparator<MBeanFeatureInfo> INFO_COMPARATOR =
new Comparator<MBeanFeatureInfo>() {
public int compare(MBeanFeatureInfo o1, MBeanFeatureInfo o2) {
return new CompareToBuilder()
.append(o1.getName(), o2.getName())
.append(o1.hashCode(), o2.hashCode())
.toComparison();
}
};
private static final String TEXT_ATTRIBUTES = "# attributes";
private static final String TEXT_NOTIFICATIONS = "# notifications";
private static final String TEXT_OPERATIONS = "# operations";
private String bean;
private String domain;
private boolean showDescription;
private String type = "aon";
private String operation;
private void displayAttributes(MBeanInfo info) {
Session session = getSession();
MBeanAttributeInfo[] attrInfos = info.getAttributes();
if (attrInfos.length == 0) {
session.output.printMessage("there is no attribute");
return;
}
int index = 0;
session.output.println(TEXT_ATTRIBUTES);
List<MBeanAttributeInfo> infos = new ArrayList<MBeanAttributeInfo>(Arrays.asList(attrInfos));
Collections.sort(infos, INFO_COMPARATOR);
for (MBeanAttributeInfo attr : infos) {
String rw = "" + (attr.isReadable() ? "r" : "") + (attr.isWritable() ? "w" : "");
session.output.println(
String.format(
" %%%-3d - %s (%s, %s)" + (showDescription ? ", %s" : ""),
index++,
attr.getName(),
attr.getType(),
rw,
attr.getDescription()));
}
}
private void displayNotifications(MBeanInfo info) {
Session session = getSession();
MBeanNotificationInfo[] notificationInfos = info.getNotifications();
if (notificationInfos.length == 0) {
session.output.printMessage("there's no notifications");
return;
}
int index = 0;
session.output.println(TEXT_NOTIFICATIONS);
for (MBeanNotificationInfo notification : notificationInfos) {
session.output.println(
String.format(
" %%%-3d - %s(%s)" + (showDescription ? ", %s" : ""),
index++,
notification.getName(),
StringUtils.join(notification.getNotifTypes(), ","),
notification.getDescription()));
}
}
private void displayOperations(MBeanInfo info) {
Session session = getSession();
MBeanOperationInfo[] operationInfos = info.getOperations();
if (operationInfos.length == 0) {
session.output.printMessage("there's no operations");
return;
}
List<MBeanOperationInfo> operations =
new ArrayList<MBeanOperationInfo>(Arrays.asList(operationInfos));
Collections.sort(operations, INFO_COMPARATOR);
session.output.println(TEXT_OPERATIONS);
int index = 0;
for (MBeanOperationInfo op : operations) {
MBeanParameterInfo[] paramInfos = op.getSignature();
List<String> paramTypes = new ArrayList<String>(paramInfos.length);
List<String> paramDescriptions = new ArrayList<String>(paramInfos.length);
for (MBeanParameterInfo paramInfo : paramInfos) {
paramTypes.add(paramInfo.getType() + " " + paramInfo.getName());
paramDescriptions.add(" " + paramInfo.getName() + ": " + paramInfo.getDescription());
}
String parameters = StringUtils.join(paramTypes, ',');
String parametersDesc =
paramDescriptions.isEmpty() ? "" : '\n' + StringUtils.join(paramDescriptions, '\n');
session.output.println(
String.format(
" %%%-3d - %s %s(%s)" + (showDescription ? ", %s%s" : ""),
index++,
op.getReturnType(),
op.getName(),
parameters,
op.getDescription(),
parametersDesc));
}
}
private void displaySingleOperation(MBeanInfo info) {
Session session = getSession();
MBeanOperationInfo[] operationInfos = info.getOperations();
if (operationInfos.length == 0) {
session.output.printMessage("there's no operations");
return;
}
session.output.println(TEXT_OPERATIONS);
int index = 0;
boolean found = false;
for (MBeanOperationInfo op : operationInfos) {
String opName = op.getName();
if (StringUtils.equals(opName, operation)) {
found = true;
MBeanParameterInfo[] paramInfos = op.getSignature();
List<String> paramTypes = new ArrayList<String>(paramInfos.length);
StringBuilder paramsDesc =
new StringBuilder(" parameters:" + System.lineSeparator());
for (MBeanParameterInfo paramInfo : paramInfos) {
String parameter = paramInfo.getName();
paramsDesc.append(
String.format(
" + %-20s : %s" + System.lineSeparator(),
parameter,
paramInfo.getDescription()));
paramTypes.add(paramInfo.getType() + " " + parameter);
}
session.output.println(
String.format(
" %%%-3d - %s %s(%s), %s",
index++,
op.getReturnType(),
opName,
StringUtils.join(paramTypes, ','),
op.getDescription()));
session.output.println(paramsDesc.toString());
}
}
if (!found) {
session.output.printMessage(
String.format("The operation '%s' is not found in the bean.", operation));
}
}
@Override
public void execute() throws IOException, JMException {
Session session = getSession();
String beanName = BeanCommand.getBeanName(bean, domain, session);
if (beanName == null) {
throw new IllegalArgumentException(
"Please specify a bean using either -b option or bean command");
}
ObjectName name = new ObjectName(beanName);
MBeanServerConnection con = session.getConnection().getServerConnection();
MBeanInfo info = con.getMBeanInfo(name);
session.output.printMessage("mbean = " + beanName);
session.output.printMessage("class name = " + info.getClassName());
if (this.showDescription) {
session.output.printMessage("description: " + info.getDescription());
}
if (operation == null) {
for (char t : type.toCharArray()) {
switch (t) {
case 'a':
displayAttributes(info);
break;
case 'o':
displayOperations(info);
break;
case 'n':
displayNotifications(info);
break;
default:
throw new IllegalArgumentException(
"Unrecognizable character " + t + " in type option " + type);
}
}
} else {
session.output.printMessage("operation = " + operation);
displaySingleOperation(info);
}
}
/**
* @param bean Bean for which information is displayed
*/
@Option(name = "b", longName = "bean", description = "Name of MBean")
public final void setBean(String bean) {
this.bean = bean;
}
/**
* Given domain
*
* @param domain Domain name
*/
@Option(name = "d", longName = "domain", description = "Domain for bean")
public final void setDomain(String domain) {
this.domain = domain;
}
/**
* @param showDescription True to show detail description
*/
@Option(name = "e", longName = "detail", description = "Show description")
public final void setShowDescription(boolean showDescription) {
this.showDescription = showDescription;
}
/**
* @param type Type of detail to display
*/
@Option(
name = "t",
longName = "type",
description =
"Types(a|o|u) to display, for example aon for all attributes, operations and notifications")
public void setType(String type) {
Validate.isTrue(StringUtils.isNotEmpty(type), "Type can't be NULL");
Validate.isTrue(Pattern.matches("^a?o?n?$", type), "Type must be a?|o?|n?");
this.type = type;
}
@Option(
name = "o",
longName = "op",
description = "Show a single operation with more details (including parameters information)")
public void setOperation(String operation) {
Validate.isTrue(StringUtils.isNotEmpty(operation), "Operation can't be NULL");
this.operation = operation;
}
}