com.stumbleupon.hbaseadmin.JMXQuery.java Source code

Java tutorial

Introduction

Here is the source code for com.stumbleupon.hbaseadmin.JMXQuery.java

Source

/**
 * This file is part of hbaseadmin.
 * Copyright (C) 2011 StumbleUpon, Inc.
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version. This program is distributed in the hope that it
 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
 * General Public License for more details. You should have received a copy
 * of the GNU Lesser General Public License along with this program. If not,
 * see <http: *www.gnu.org/licenses/>.
 */

/*
 *
 * This file is mostly stolen straight out of http://jmxcmd.svn.sourceforge.net,
 * which in turn has been adapted from http://crawler.archive.org/cmdline-jmxclient/
 *
 */

package com.stumbleupon.hbaseadmin;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.management.*;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.TabularData;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.io.*;
import java.lang.reflect.Constructor;
import java.text.ParseException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JMXQuery {
    private static final Logger logger = LoggerFactory.getLogger(JMXQuery.class.getName());
    protected static final Pattern CMD_LINE_ARGS_PATTERN = Pattern.compile("^([^=]+)(?:(?:\\=)(.+))?$");

    private final String beanName;
    private final String command;
    private final String password_file;

    public JMXQuery(String mbean, String jmx_command, String password_file) {
        this.beanName = StringUtils.defaultString(mbean);
        this.command = StringUtils.defaultString(jmx_command);
        this.password_file = StringUtils.defaultString(password_file);
    }

    public static void main(String[] args) throws Exception {
        JMXQuery client = new JMXQuery("hadoop:name=RegionServerStatistics,service=RegionServer",
                "compactionQueueSize", "/home/hadoop/hbase_conf/jmxremote.password");
        logger.info("Output: " + client.execute(args[0]));
    }

    protected Map<String, ?> getCredentials(String filename) throws IOException {

        Map<String, String[]> env = null;
        final StringBuilder contents = new StringBuilder();
        final BufferedReader input = new BufferedReader(new FileReader(new File(filename)));

        try {
            String line = null; //not declared within while loop
            if ((line = input.readLine()) != null) {
                contents.append(line);
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            input.close();
        }

        final String userpass = contents.toString();
        // split on ascii space (32)
        final int index = userpass.indexOf(32);
        if (index <= 0) {
            throw new RuntimeException("Unable to parse: " + userpass);
        }

        final String[] creds = { userpass.substring(0, index), userpass.substring(index + 1) };

        env = new HashMap<String, String[]>(1);
        env.put("jmx.remote.credentials", creds);
        return env;
    }

    public String execute(String hostport) throws Exception {
        Iterator i;
        String result = "";
        final JMXServiceURL rmiurl = new JMXServiceURL(
                "service:jmx:rmi://" + hostport + "/jndi/rmi://" + hostport + "/jmxrmi");
        final JMXConnector jmxc = JMXConnectorFactory.connect(rmiurl, getCredentials(password_file));
        try {
            final MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();

            final ObjectName objName = new ObjectName(beanName);
            final Set beans = mbsc.queryMBeans(objName, null);

            if (beans.size() == 0) {
                logger.warn(objName.getCanonicalName() + " is not a registered bean");
            } else if (beans.size() == 1) {
                final ObjectInstance instance = (ObjectInstance) beans.iterator().next();
                result = doBean(mbsc, instance, command);
            } else {

                for (i = beans.iterator(); i.hasNext();) {
                    final Object obj = i.next();

                    if (obj instanceof ObjectName)
                        System.out.println(((ObjectName) obj).getCanonicalName());
                    else if (obj instanceof ObjectInstance) {
                        System.out.println(((ObjectInstance) obj).getObjectName().getCanonicalName());
                    } else
                        logger.error("Unexpected object type: " + obj);
                }
            }
        } finally {
            jmxc.close();
        }
        return result;
    }

    public String doBean(MBeanServerConnection mbsc, ObjectInstance instance, String command) throws Exception {
        if (command == null) {
            listOptions(mbsc, instance);
            return "";
        }

        return doSubCommand(mbsc, instance, command);
    }

    protected String doSubCommand(MBeanServerConnection mbsc, ObjectInstance instance, String subCommand)
            throws Exception {
        final MBeanAttributeInfo[] attributeInfo = mbsc.getMBeanInfo(instance.getObjectName()).getAttributes();

        final MBeanOperationInfo[] operationInfo = mbsc.getMBeanInfo(instance.getObjectName()).getOperations();

        Object result = null;

        if (Character.isUpperCase(subCommand.charAt(0))) {
            if ((!(isFeatureInfo(attributeInfo, subCommand))) && (isFeatureInfo(operationInfo, subCommand))) {
                result = doBeanOperation(mbsc, instance, subCommand, operationInfo);
            } else {
                result = doAttributeOperation(mbsc, instance, subCommand, attributeInfo);
            }
        } else if ((!(isFeatureInfo(operationInfo, subCommand))) && (isFeatureInfo(attributeInfo, subCommand))) {
            result = doAttributeOperation(mbsc, instance, subCommand, attributeInfo);
        } else {
            result = doBeanOperation(mbsc, instance, subCommand, operationInfo);
        }

        if (result instanceof CompositeData) {
            result = recurseCompositeData(new StringBuffer("\n"), "", "", (CompositeData) result);
        } else if (result instanceof TabularData) {
            result = recurseTabularData(new StringBuffer("\n"), "", "", (TabularData) result);
        } else if (result instanceof String[]) {
            String[] strs = (String[]) (String[]) result;
            StringBuffer buffer = new StringBuffer("\n");

            for (int i = 0; i < strs.length; ++i) {
                buffer.append(strs[i]);
                buffer.append("\n");
            }

            result = buffer;
        }

        return result.toString();
    }

    protected boolean isFeatureInfo(MBeanFeatureInfo[] infos, String cmd) {
        return (getFeatureInfo(infos, cmd) != null);
    }

    protected MBeanFeatureInfo getFeatureInfo(MBeanFeatureInfo[] infos, String cmd) {
        final int index = cmd.indexOf(61);
        final String name = (index > 0) ? cmd.substring(0, index) : cmd;

        for (int i = 0; i < infos.length; ++i) {
            if (infos[i].getName().equals(name)) {
                return infos[i];
            }
        }
        return null;
    }

    protected StringBuffer recurseTabularData(StringBuffer buffer, String indent, String name, TabularData data) {
        addNameToBuffer(buffer, indent, name);
        final Collection c = data.values();
        for (Iterator i = c.iterator(); i.hasNext();) {
            final Object obj = i.next();
            if (obj instanceof CompositeData) {
                recurseCompositeData(buffer, indent + " ", "", (CompositeData) obj);
            } else if (obj instanceof TabularData) {
                recurseTabularData(buffer, indent, "", (TabularData) obj);
            } else {
                buffer.append(obj);
            }
        }
        return buffer;
    }

    protected StringBuffer recurseCompositeData(StringBuffer buffer, String indent, String name,
            CompositeData data) {
        indent = addNameToBuffer(buffer, indent, name);
        Iterator i = data.getCompositeType().keySet().iterator();
        while (i.hasNext()) {
            String key = (String) i.next();
            Object o = data.get(key);
            if (o instanceof CompositeData) {
                recurseCompositeData(buffer, indent + " ", key, (CompositeData) o);
            } else if (o instanceof TabularData) {
                recurseTabularData(buffer, indent, key, (TabularData) o);
            } else {
                buffer.append(indent);
                buffer.append(key);
                buffer.append(": ");
                buffer.append(o);
                buffer.append("\n");
            }
        }
        return buffer;
    }

    protected String addNameToBuffer(StringBuffer buffer, String indent, String name) {
        if ((name == null) || (name.length() == 0)) {
            return indent;
        }

        buffer.append(indent);
        buffer.append(name);
        buffer.append(":\n");

        return indent + " ";
    }

    protected Object doAttributeOperation(MBeanServerConnection mbsc, ObjectInstance instance, String command,
            MBeanAttributeInfo[] infos) throws Exception {
        final CommandParse parse = new CommandParse(command);

        if ((parse.getArgs() == null) || (parse.getArgs().length == 0)) {
            return mbsc.getAttribute(instance.getObjectName(), parse.getCmd());
        }

        if (parse.getArgs().length != 1) {
            throw new IllegalArgumentException("One only argument setting attribute values: " + parse.getArgs());
        }

        final MBeanAttributeInfo info = (MBeanAttributeInfo) getFeatureInfo(infos, parse.getCmd());

        final Constructor c = getResolvedClass(info.getType()).getConstructor(new Class[] { String.class });

        final Attribute a = new Attribute(parse.getCmd(), c.newInstance(new Object[] { parse.getArgs()[0] }));

        mbsc.setAttribute(instance.getObjectName(), a);
        return null;
    }

    protected Object doBeanOperation(MBeanServerConnection mbsc, ObjectInstance instance, String command,
            MBeanOperationInfo[] infos) throws Exception {

        final CommandParse parse = new CommandParse(command);

        final MBeanOperationInfo op = (MBeanOperationInfo) getFeatureInfo(infos, parse.getCmd());

        Object result = null;

        if (op == null) {
            result = "Operation " + parse.getCmd() + " not found.";
        } else {
            final MBeanParameterInfo[] paraminfos = op.getSignature();
            final int paraminfosLength = (paraminfos == null) ? 0 : paraminfos.length;
            int objsLength = (parse.getArgs() == null) ? 0 : parse.getArgs().length;

            // FIXME: bad solution for comma containing parameter
            if (paraminfosLength == 1) {
                // concat all to one string
                String realParameter = parse.getArgs()[0];
                for (int j = 1; j < objsLength; j++) {
                    realParameter = realParameter + "," + parse.getArgs()[j];
                }
                objsLength = 1;
                parse.setArgs(new String[] { realParameter });
            }

            if (paraminfosLength != objsLength) {
                result = "Passed param count does not match signature count";
            } else {
                final String[] signature = new String[paraminfosLength];
                final Object[] params = (paraminfosLength == 0) ? null : new Object[paraminfosLength];

                for (int i = 0; i < paraminfosLength; ++i) {
                    final MBeanParameterInfo paraminfo = paraminfos[i];
                    // System.out.println( "paraminfo.getType() = " + paraminfo.getType());
                    final String classType = paraminfo.getType();
                    // Constructor c = Class.forName(classType).getConstructor(new Class[] { String.class });
                    final Constructor c = getResolvedClass(paraminfo.getType())
                            .getConstructor(new Class[] { String.class });

                    params[i] = c.newInstance(new Object[] { parse.getArgs()[i] });
                    signature[i] = classType;
                }

                result = mbsc.invoke(instance.getObjectName(), parse.getCmd(), params, signature);
            }
        }

        return result;
    }

    private static Class getResolvedClass(String className) throws ClassNotFoundException {
        // Check if the className is the name of a primitive. If this is the case, use their
        // corresponding class.
        if ("boolean".equals(className)) {
            return Boolean.class;
        } else if ("byte".equals(className)) {
            return Byte.class;
        } else if ("char".equals(className)) {
            return Character.class;
        } else if ("double".equals(className)) {
            return Double.class;
        } else if ("float".equals(className)) {
            return Float.class;
        } else if ("int".equals(className)) {
            return Integer.class;
        } else if ("long".equals(className)) {
            return Long.class;
        } else if ("short".equals(className)) {
            return Short.class;
        } else {
            return Class.forName(className);
        }
    }

    protected void listOptions(MBeanServerConnection mbsc, ObjectInstance instance)
            throws InstanceNotFoundException, IntrospectionException, ReflectionException, IOException {
        final MBeanInfo info = mbsc.getMBeanInfo(instance.getObjectName());
        final MBeanAttributeInfo[] attributes = info.getAttributes();

        if (attributes.length > 0) {
            System.out.println("Attributes:");

            for (int i = 0; i < attributes.length; ++i) {
                System.out.println(' ' + attributes[i].getName() + ": " + attributes[i].getDescription() + " (type="
                        + attributes[i].getType() + ")");
            }
        }

        MBeanOperationInfo[] operations = info.getOperations();

        if (operations.length > 0) {
            System.out.println("Operations:");

            for (int i = 0; i < operations.length; ++i) {
                final MBeanParameterInfo[] params = operations[i].getSignature();
                final StringBuffer paramsStrBuffer = new StringBuffer();

                if (params != null) {
                    for (int j = 0; j < params.length; ++j) {
                        paramsStrBuffer.append("\n   name=");
                        paramsStrBuffer.append(params[j].getName());
                        paramsStrBuffer.append(" type=");
                        paramsStrBuffer.append(params[j].getType());
                        paramsStrBuffer.append(" ");
                        paramsStrBuffer.append(params[j].getDescription());
                    }
                }
                System.out.println(' ' + operations[i].getName() + ": " + operations[i].getDescription()
                        + "\n  Parameters " + params.length + ", return type=" + operations[i].getReturnType()
                        + paramsStrBuffer.toString());
            }
        }
    }

    protected class CommandParse {
        private String cmd;
        private String[] args;

        protected CommandParse(String paramString) throws ParseException {
            parse(paramString);
        }

        private void parse(String command) throws ParseException {
            final Matcher m = JMXQuery.CMD_LINE_ARGS_PATTERN.matcher(command);
            if ((m == null) || (!(m.matches()))) {
                throw new ParseException("Failed parse of " + command, 0);
            }

            this.cmd = m.group(1);
            if ((m.group(2) != null) && (m.group(2).length() > 0))
                this.args = m.group(2).split(",");
            else
                this.args = null;
        }

        protected String getCmd() {
            return this.cmd;
        }

        protected String[] getArgs() {
            return this.args;
        }

        public void setArgs(String[] args) {
            this.args = args;
        }
    }

}