/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.openejb.server.cli.command; import java.util.Arrays; import java.util.Iterator; import java.util.Set; import javax.management.Attribute; 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.RuntimeMBeanException; import org.apache.openejb.monitoring.LocalMBeanServer; import org.apache.xbean.propertyeditor.PropertyEditors; // TODO: maybe find a better way to invoker get/set/invoke because currently we limit a bit possible values @Command(name = "jmx", description = "consult/update a jmx information", usage = "jmx <operation> <options>. " + "\n\t\tOperation can be set|get|invoke.\n\t\tLast value is always the object name canonical path." + "\n\t\tSet takes the new value as last value and the name of the attribute as second parameter." + "\n\t\tInvoke takes the method invocation as second parameter." + "\n\t\tSamples:" + "\n\t\t\tjmx get MyAttributeName foo:type=bar" + "\n\t\t\tjmx set MyAttributeName foo:type=bar NewValue" + "\n\t\t\tjmx invoke myMethod(arg1,arg2) foo:type=bar") public class LocalJMXCommand extends AbstractCommand { @Override public void execute(final String cmd) { final String jmxCmd = cmd.trim(); if ("list".equals(jmxCmd)) { listMBeans(); return; } if (!jmxCmd.contains(" ")) { streamManager.writeErr("the command is not correct"); return; } int space = jmxCmd.indexOf(" "); final String command = jmxCmd.substring(0, space); final String value = jmxCmd.substring(command.length()).trim(); if ("get".equals(command)) { get(value); } else if ("set".equals(command)) { set(value); } else if ("invoke".equals(command)) { invoke(value); } else { streamManager.writeOut("unknown command '" + command + "'"); } } private void invoke(final String value) { if (!value.contains("(") || !value.contains(")")) { streamManager.writeErr("method should follow the format: <methoName>(<arg1>,<arg2>,...)"); return; } int open = value.indexOf("("); int close = value.lastIndexOf(")"); final String name = value.substring(0, open).trim(); final String rawArgs = value.substring(open + 1, close).trim(); final ObjectName on; try { on = new ObjectName(value.substring(close + 1).trim()); } catch (MalformedObjectNameException e) { streamManager.writeErr(e); return; } final MBeanServer server = LocalMBeanServer.get(); final String[] args; if (rawArgs == null || rawArgs.isEmpty()) { args = new String[0]; } else { args = rawArgs.split(","); } try { final MBeanInfo minfo = server.getMBeanInfo(on); final MBeanOperationInfo[] methods = minfo.getOperations(); MBeanOperationInfo operation = null; for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equals(name)) { operation = methods[i]; break; } } if (operation == null) { streamManager.writeErr("can't find operation '" + name + "'"); return; } final Object[] passedArgs = new Object[args.length]; final String[] passedArgTypes = new String[args.length]; for (int i = 0; i < passedArgs.length; i++) { final String expected = operation.getSignature()[i].getType(); if (!String.class.getName().equals(expected)) { passedArgs[i] = PropertyEditors.getValue(expected, args[i], Thread.currentThread().getContextClassLoader()); } else { passedArgs[i] = args[i]; } passedArgTypes[i] = expected; } streamManager.writeOut(stringify(server.invoke(on, name, passedArgs, passedArgTypes))); } catch (Exception e) { streamManager.writeErr(e); return; } } private void get(final String cmd) { int space = cmd.indexOf(" "); if (space < 0) { streamManager.writeErr("you need to specify an attribute and an objectname"); return; } final String attr = cmd.substring(0, space); final String on = cmd.substring(space, cmd.length()).trim(); final MBeanServer mBeanServer = LocalMBeanServer.get(); try { final ObjectName oname = new ObjectName(on); final Object value = mBeanServer.getAttribute(oname, attr); streamManager.writeOut("Attribute [" + on + " -> " + attr + "] = " + stringify(value)); } catch (Exception ex) { streamManager.writeErr(ex); } } private void set(final String cmd) { final String[] split = cmd.split(" "); if (split.length < 2) { streamManager.writeErr("you need to specify an attribute, an objectname and a value"); return; } final MBeanServer mBeanServer = LocalMBeanServer.get(); final String newValue = cmd.substring(split[0].length() + split[1].length() + 1).trim(); try { final ObjectName oname = new ObjectName(split[1]); final MBeanInfo minfo = mBeanServer.getMBeanInfo(oname); final MBeanAttributeInfo attrs[] = minfo.getAttributes(); String type = String.class.getName(); for (int i = 0; i < attrs.length; i++) { if (attrs[i].getName().equals(split[0])) { type = attrs[i].getType(); break; } } final Object valueObj = PropertyEditors.getValue(type, newValue, Thread.currentThread().getContextClassLoader()); mBeanServer.setAttribute(oname, new Attribute(split[0], valueObj)); streamManager.writeOut("done"); } catch (Exception ex) { streamManager.writeOut("Error - " + ex.toString()); } } private String stringify(final Object value) { if (value == null) { return "<null>"; } if (value.getClass().isArray()) { return Arrays.asList((Object[]) value).toString(); } return value.toString(); } private void listMBeans() { final MBeanServer mBeanServer = LocalMBeanServer.get(); final Set<ObjectName> names; try { names = mBeanServer.queryNames(null, null); } catch (Exception e) { streamManager.writeErr(e); return; } final Iterator<ObjectName> it = names.iterator(); while (it.hasNext()) { ObjectName oname = it.next(); streamManager.writeOut("Name: " + oname.toString()); try { final MBeanInfo minfo = mBeanServer.getMBeanInfo(oname); String code = minfo.getClassName(); if ("org.apache.commons.modeler.BaseModelMBean".equals(code)) { code = (String) mBeanServer.getAttribute(oname, "modelerType"); } streamManager.writeOut(" + modelerType: " + code); MBeanAttributeInfo attrs[] = minfo.getAttributes(); Object value = null; for (int i = 0; i < attrs.length; i++) { if (!attrs[i].isReadable()) { continue; } final String attName = attrs[i].getName(); if ("modelerType".equals(attName)) { continue; } if (attName.indexOf("=") >= 0 || attName.indexOf(":") >= 0 || attName.indexOf(" ") >= 0) { continue; } try { value = mBeanServer.getAttribute(oname, attName); } catch (RuntimeMBeanException uoe) { // ignored } catch (Throwable t) { streamManager.writeErr(new Exception(t)); continue; } try { String valueString = stringify(value); streamManager.writeOut(" + " + attName + ": " + valueString); } catch (Throwable t) { streamManager.writeErr(new Exception(t)); } } } catch (Throwable t) { streamManager.writeErr(new Exception(t)); } streamManager.writeOut(""); } } }