public static void main(String[] args) throws Exception {

    long timeBeforeInMillis = System.currentTimeMillis();

    JmxInvokerArguments arguments = new JmxInvokerArguments();
    CmdLineParser parser = new CmdLineParser(arguments);
    try {
      parser.parseArgument(args);
      arguments.cmdLineParser = parser;
      if (Strings2.isEmpty(arguments.pid) && arguments.pidFile == null) {
        throw new CmdLineException(parser, "Options --pid and --pid-file can NOT be both null");
      } else if (!Strings2.isEmpty(arguments.pid) && arguments.pidFile != null) {
        throw new CmdLineException(parser, "Options --pid and --pid-file can NOT be both defined");
      } else if ((arguments.attribute == null || arguments.attribute.length == 0)
          && (arguments.operation == null || arguments.operation.length == 0)
          && arguments.listMbeans == false
          && arguments.describeMbeans == false) {
        throw new CmdLineException(
            parser,
            "Option --attribute or --operation or --list-mbeans or --describe-mbeans must be defined");
      } else if ((arguments.attribute != null && arguments.attribute.length > 0)
          && (arguments.operation != null && arguments.operation.length > 0)) {
        throw new CmdLineException(
            parser, "Options --attribute and --operation can NOT be both defined");
      }

      String logLevel;
      if (arguments.superVerbose) {
        logLevel = "TRACE";
      } else if (arguments.verbose) {
        logLevel = "DEBUG";
      } else {
        logLevel = "WARN";
      }
      System.setProperty(SimpleLogger.DEFAULT_LOG_LEVEL_KEY, logLevel);

      Map<ObjectName, Result> results = new JmxInvoker().process(arguments);
      for (Map.Entry<ObjectName, Result> entry : results.entrySet()) {
        System.out.println(entry.getValue().description);
      }
    } catch (CmdLineException e) {
      System.err.println("INVALID INVOCATION: " + e.getMessage());
      System.err.println("Arguments: " + Strings2.join(args, " "));
      System.err.println("Usage:");
      parser.printUsage(System.err);
      throw e;
    } catch (Exception e) {
      System.err.println("INVALID INVOCATION: " + e.getMessage());
      System.err.println("Arguments: " + Strings2.join(args, " "));
      e.printStackTrace();
      throw e;
    } finally {
      if (arguments.verbose || arguments.superVerbose) {
        System.out.println("Duration: " + (System.currentTimeMillis() - timeBeforeInMillis) + "ms");
      }
    }
  }
  @Nullable
  public Result invokeOperation(
      @Nonnull MBeanServerConnection mBeanServer,
      @Nonnull ObjectName on,
      @Nonnull String operationName,
      @Nonnull String... arguments)
      throws JMException, IOException {

    logger.debug("invokeOperation({},{}, {}, {})...", on, operationName, Arrays.asList(arguments));
    MBeanInfo mbeanInfo = mBeanServer.getMBeanInfo(on);

    List<MBeanOperationInfo> candidates = new ArrayList<MBeanOperationInfo>();
    for (MBeanOperationInfo mbeanOperationInfo : mbeanInfo.getOperations()) {
      if (mbeanOperationInfo.getName().equals(operationName)
          && mbeanOperationInfo.getSignature().length == arguments.length) {
        candidates.add(mbeanOperationInfo);
        logger.debug("Select matching operation {}", mbeanOperationInfo);
      } else {
        logger.trace("Ignore non matching operation {}", mbeanOperationInfo);
      }
    }
    if (candidates.isEmpty()) {
      throw new IllegalArgumentException(
          "Operation '"
              + operationName
              + "("
              + Strings2.join(arguments, ", ")
              + ")' NOT found on "
              + on);
    } else if (candidates.size() > 1) {
      throw new IllegalArgumentException(
          "More than 1 ("
              + candidates.size()
              + ") operation '"
              + operationName
              + "("
              + Strings2.join(arguments, ", ")
              + ")' found on '"
              + on
              + "': "
              + candidates);
    }
    MBeanOperationInfo beanOperationInfo = candidates.get(0);

    MBeanParameterInfo[] mbeanParameterInfos = beanOperationInfo.getSignature();

    List<String> signature = new ArrayList<String>();
    for (MBeanParameterInfo mbeanParameterInfo : mbeanParameterInfos) {
      signature.add(mbeanParameterInfo.getType());
    }

    Object[] convertedArguments = convertValues(arguments, signature);

    logger.debug("Invoke {}:{}({}) ...", on, operationName, Arrays.asList(convertedArguments));

    Object result =
        mBeanServer.invoke(on, operationName, convertedArguments, signature.toArray(new String[0]));

    if ("void".equals(beanOperationInfo.getReturnType()) && result == null) {
      result = "void";
    }

    logger.info(
        "Invoke {}:{}({}): {}", on, operationName, Arrays.asList(convertedArguments), result);

    String description =
        "Invoke operation "
            + on
            + ":"
            + operationName
            + "("
            + Strings2.join(convertedArguments, ", ")
            + "): "
            + Strings2.toString(result);
    return new Result(on, result, description);
  }