/*_##########################################################################
_##
_## Copyright (C) 2013 Kaito Yamada
_##
_##########################################################################
*/
package com.github.kaitoy.sneo.tools.console;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.rmi.registry.Registry;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.Attribute;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import mx4j.log.Log4JLogger;
import org.snmp4j.util.ArgumentParser;
import com.github.kaitoy.sneo.log.Log4jPropertiesLoader;
public class JmxRemoteOperator {
private final JMXConnector connector;
private final MBeanServerConnection connection;
public JmxRemoteOperator(JMXServiceURL url) throws IOException {
try {
connector = JMXConnectorFactory.connect(url);
connection = connector.getMBeanServerConnection();
} catch (IOException e) {
close();
throw e;
}
}
public static void main(String[] args) {
mx4j.log.Log.redirectTo(new Log4JLogger());
Log4jPropertiesLoader.getInstance().loadPropertyOf(JmxRemoteOperator.class);
Map<?, ?> paramMap = parseArgs(args);
int rmiPort = ((Integer)ArgumentParser.getValue(paramMap, "rmiPort", 0)).intValue();
String host = (String)ArgumentParser.getValue(paramMap, "host", 0);
StringBuffer urlBuff = new StringBuffer();
urlBuff.append("service:jmx:rmi:///jndi/rmi://")
.append(host).append(":").append(rmiPort).append("/JMXConnectorServer");
JMXServiceURL url = null;
try {
url = new JMXServiceURL(urlBuff.toString());
} catch (MalformedURLException e) {
System.err.println("Invalid host and/or port: " + host + ", " + rmiPort);
System.exit(1);
}
JmxRemoteOperator jro = null;
try {
jro = new JmxRemoteOperator(url);
} catch (IOException e) {
System.err.println("Failed to connect the JMX server: " + url);
System.exit(1);
}
try {
String command = (String)ArgumentParser.getValue(paramMap, "command", 0);
if (command.equals("list")) {
try {
jro.list();
} catch (IOException e) {
System.err.println("Lost the connection to the JMX server: " + url);
System.exit(1);
}
return;
}
if (command.equals("query")) {
String query = (String)ArgumentParser.getValue(paramMap, "object_name_or_query", 0);
if (query == null || query.length() == 0) {
System.err.println("Specify a query.");
System.exit(1);
}
try {
jro.query(query);
return;
} catch (MalformedObjectNameException e) {
System.err.println("Invalid query: " + query);
System.exit(1);
} catch (IOException e) {
System.err.println("Lost the connection to the JMX server: " + url);
System.exit(1);
}
}
String objNameStr = (String)ArgumentParser.getValue(paramMap, "object_name_or_query", 0);
if (objNameStr == null || objNameStr.length() == 0) {
System.err.println("Specify a query.");
System.exit(1);
}
ObjectName objName = null;
try {
objName = new ObjectName(objNameStr);
} catch (MalformedObjectNameException e) {
System.err.println("Invalid object name: " + objNameStr);
System.exit(1);
}
if (command.equals("info")) {
try {
jro.printObjectInfo(objName);
} catch (IOException e) {
System.err.println("Lost the connection to the JMX server: " + url);
System.exit(1);
} catch (InstanceNotFoundException e) {
System.err.println("No such mbean: " + objNameStr);
System.exit(1);
} catch (IntrospectionException e) {
System.err.println("Failed to get the info due to an exception: ");
e.printStackTrace();
System.exit(1);
} catch (ReflectionException e) {
System.err.println("Failed to get the info due to an exception: ");
e.printStackTrace();
System.exit(1);
}
return;
}
else if (command.equals("get")) {
String attrName = (String)ArgumentParser.getValue(paramMap, "command_args", 0);
try {
System.out.println(jro.getAttr(objName, attrName));
} catch (AttributeNotFoundException e) {
System.err.println("No such attribute: " + attrName);
System.exit(1);
} catch (InstanceNotFoundException e) {
System.err.println("No such mbean: " + objNameStr);
System.exit(1);
} catch (MBeanException e) {
System.err.println("Failed to get the attribute due to an exception: ");
e.printStackTrace();
System.exit(1);
} catch (ReflectionException e) {
System.err.println("Failed to get the attribute due to an exception: ");
e.printStackTrace();
System.exit(1);
} catch (IOException e) {
System.err.println("Lost the connection to the JMX server: " + url);
System.exit(1);
}
return;
}
else if (command.equals("set")) {
String attrName = (String)ArgumentParser.getValue(paramMap, "command_args", 0);
String value = (String)ArgumentParser.getValue(paramMap, "command_args", 1);
try {
jro.setAttr(objName, attrName, value);
} catch (InstanceNotFoundException e) {
System.err.println("No such mbean: " + objNameStr);
System.exit(1);
} catch (AttributeNotFoundException e) {
System.err.println("No such attribute: " + attrName);
System.exit(1);
} catch (InvalidAttributeValueException e) {
System.err.println("Invalid value: " + value);
System.exit(1);
} catch (MBeanException e) {
System.err.println("Failed to get the info due to an exception: ");
e.printStackTrace();
System.exit(1);
} catch (ReflectionException e) {
System.err.println("Failed to get the info due to an exception: ");
e.printStackTrace();
System.exit(1);
} catch (IOException e) {
System.err.println("Lost the connection to the JMX server: " + url);
System.exit(1);
}
System.out.println("Success!");
return;
}
else if (command.equals("invoke")) {
@SuppressWarnings("unchecked")
List<String> commandArgs = (List<String>)paramMap.get("command_args");
String operName = commandArgs.remove(0);
try {
jro.invoke(objName, operName, commandArgs);
} catch (IOException e) {
System.err.println("Lost the connection to the JMX server: " + url);
System.exit(1);
} catch (InstanceNotFoundException e) {
System.err.println("No such mbean: " + objNameStr);
System.exit(1);
} catch (MBeanException e) {
System.err.println("Failed to get the info due to an exception: ");
e.printStackTrace();
System.exit(1);
} catch (ReflectionException e) {
System.err.println("Failed to get the info due to an exception: ");
e.printStackTrace();
System.exit(1);
}
}
else {
System.err.println("Unknown command: " + command);
System.exit(1);
}
} finally {
try {
jro.close();
} catch (IOException e) {}
}
}
private static Map<?, ?> parseArgs(String[] args) {
Map<?, ?> params = null;
List<String> optList = new ArrayList<String>();
List<String> paramList = new ArrayList<String>();
try {
optList.add("-host[s{=localhost] ");
optList.add("-rmiPort[i{=" + Registry.REGISTRY_PORT + "}] ");
paramList.add("-command[s<list|query|info|get|set|invoke>] ");
paramList.add("+object_name_or_query[s] ");
paramList.add("+command_args[s] ..");
for (String arg: args) {
if (
arg.equals("-h")
|| arg.equals("-help")
|| arg.equals("--help")
|| arg.equals("-?")
) {
prHelp(optList, paramList);
System.exit(0);
}
}
StringBuilder optsBuilder = new StringBuilder();
for (String opt: optList) {
optsBuilder.append(opt);
}
StringBuilder paramsBuilder = new StringBuilder();
for (String param: paramList) {
paramsBuilder.append(param);
}
ArgumentParser parser
= new ArgumentParser(optsBuilder.toString(), paramsBuilder.toString());
params = parser.parse(args);
}
catch (ParseException e) {
prHelp(optList, paramList);
System.exit(1);
}
return params;
}
private static void prHelp(List<String> optList, List<String> paramList) {
System.out.println("Usage: " + JmxRemoteOperator.class.getName() + " <Options> <Params>");
System.out.println("Options: ");
for (String opt: optList) {
System.out.println(" " + opt);
}
System.out.println("Params: ");
for (String param: paramList) {
System.out.println(" " + param);
}
}
private void list() throws IOException {
try {
@SuppressWarnings("unchecked")
Set<ObjectName> objNames = connection.queryNames(new ObjectName("*:*"), null);
for (ObjectName objName: objNames) {
System.out.println(objName);
}
} catch (NullPointerException e) {
throw new AssertionError("Never get here.");
} catch (MalformedObjectNameException e) {
throw new AssertionError("Never get here.");
}
}
private void query(
String query
) throws MalformedObjectNameException, NullPointerException, IOException {
@SuppressWarnings("unchecked")
Set<ObjectName> objNames = connection.queryNames(new ObjectName(query), null);
for (ObjectName objName: objNames) {
System.out.println(objName);
}
}
private void printObjectInfo(
ObjectName objName
) throws IOException, InstanceNotFoundException, IntrospectionException, ReflectionException {
MBeanInfo info = connection.getMBeanInfo(objName);
System.out.println("Attributes:");
for (MBeanAttributeInfo attr: info.getAttributes()) {
StringBuilder sb = new StringBuilder(50);
sb.append(" ")
.append(attr.isReadable() ? "r" : " ")
.append(attr.isWritable() ? "w " : " ")
.append(attr.getType())
.append(" ")
.append(attr.getName());
Object val;
try {
val = connection.getAttribute(objName, attr.getName());
} catch (AttributeNotFoundException e) {
throw new AssertionError("Never get here.");
} catch (MBeanException e) {
val = "Filed to get this attribute due to MBeanException";
} catch (ReflectionException e) {
val = "Filed to get this attribute due to ReflectionException";
}
sb.append(": ")
.append(val);
System.out.println(sb.toString());
}
System.out.println();
System.out.println("Operations:");
for (MBeanOperationInfo oper: info.getOperations()) {
StringBuilder sb = new StringBuilder(50);
sb.append(" ")
.append(oper.getReturnType())
.append(" ")
.append(oper.getName())
.append("(");
MBeanParameterInfo[] params = oper.getSignature();
for (MBeanParameterInfo param: params) {
sb.append(param.getType())
.append(" ")
.append(param.getName())
.append(", ");
}
if (params.length != 0) {
sb.delete(sb.length() - 2, sb.length());
}
sb.append(")");
System.out.println(sb.toString());
}
}
private Object getAttr(ObjectName objName, String attrName)
throws IOException, AttributeNotFoundException,
InstanceNotFoundException, MBeanException, ReflectionException
{
return connection.getAttribute(objName, attrName);
}
private void setAttr(
ObjectName objName, String attrName, Object value
) throws IOException, InstanceNotFoundException, AttributeNotFoundException,
InvalidAttributeValueException, MBeanException, ReflectionException
{
Attribute attr = new Attribute(attrName, value);
connection.setAttribute(objName, attr);
}
private void invoke(
ObjectName objName, String operName, List<String> operArgs
) throws IOException, InstanceNotFoundException, MBeanException, ReflectionException {
List<Object> paramList = new ArrayList<Object>();
List<String> signature = new ArrayList<String>();
for (int i = 0; i < operArgs.size(); i += 2) {
String type = operArgs.get(i);
String value = operArgs.get(i + 1);
if (type.equals("int")) {
signature.add(type);
paramList.add(Integer.valueOf(value));
}
else if (type.equalsIgnoreCase("String") || type.equals(String.class.getName())) {
signature.add(String.class.getName());
paramList.add(value);
}
else {
Class<?> cls = null;
try {
cls = Class.forName(type);
} catch (ClassNotFoundException e1) {
System.err.println("No such type: " + type);
System.exit(1);
}
Method valueOf = null;
try {
valueOf = cls.getMethod("valueOf", String.class);
} catch (SecurityException e) {
System.err.println("Unsupported type: " + type);
System.exit(1);
} catch (NoSuchMethodException e) {
System.err.println("Unsupported type: " + type);
System.exit(1);
}
Object param = null;
try {
param = valueOf.invoke(null, value);
} catch (IllegalArgumentException e) {
System.err.println("Invalid valud and/or type: " + type + ", " + value);
System.exit(1);
} catch (IllegalAccessException e) {
System.err.println("Unsupported type: " + type);
System.exit(1);
} catch (InvocationTargetException e) {
System.err.println("Invalid valud and/or type: " + type + ", " + value);
System.exit(1);
}
signature.add(type);
paramList.add(param);
}
}
Object result
= connection.invoke(
objName, operName,
paramList.toArray(), signature.toArray(new String[signature.size()])
);
System.out.println(result);
}
private void close() throws IOException {
if (connector != null) {
connector.close();
}
}
}