/* * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004, 2005, 2006], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.hq.plugin.jboss; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.management.MBeanAttributeInfo; import javax.management.MBeanInfo; import javax.management.MBeanOperationInfo; import javax.management.MBeanParameterInfo; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import org.hyperic.hq.product.PluginException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; //XXX avoid any JBoss specific stuff here, want to make it //a shared class at some point. public class MBeanUtil { private static Log log = LogFactory.getLog(MBeanUtil.class); private static Map converters = new HashMap(); static { initConverters(); } //convert a String to common types public interface Converter { public Object convert(String param); } public interface ListConverter { public Object convert(String[] params); } public static void addConverter(Class type, Converter converter) { converters.put(type.getName(), converter); } public static void addConverter(Class type, ListConverter converter) { converters.put(type.getName(), converter); } private static void addConverter(Class addType, Class fromType) { converters.put(addType.getName(), converters.get(fromType.getName())); } private static IllegalArgumentException invalid(String param, Exception e) { return new IllegalArgumentException("'" + param + "': " + e.getMessage()); } private static void initConverters() { addConverter(Object.class, new Converter() { public Object convert(String param) { return param; } }); addConverter(Short.class, new Converter() { public Object convert(String param) { return Short.valueOf(param); } }); addConverter(Integer.class, new Converter() { public Object convert(String param) { return Integer.valueOf(param); } }); addConverter(Long.class, new Converter() { public Object convert(String param) { return Long.valueOf(param); } }); addConverter(Double.class, new Converter() { public Object convert(String param) { return Double.valueOf(param); } }); addConverter(Boolean.class, new Converter() { public Object convert(String param) { return Boolean.valueOf(param); } }); addConverter(File.class, new Converter() { public Object convert(String param) { return new File(param); } }); addConverter(URL.class, new Converter() { public Object convert(String param) { try { return new URL(param); } catch (MalformedURLException e) { throw invalid(param, e); } } }); addConverter(ObjectName.class, new Converter() { public Object convert(String param) { try { return new ObjectName(param); } catch (MalformedObjectNameException e) { throw invalid(param, e); } } }); addConverter(List.class, new ListConverter() { public Object convert(String[] params) { return Arrays.asList(params); } }); addConverter(String[].class, new ListConverter() { public Object convert(String[] params) { return params; } }); Class[][] aliases = { { String.class, Object.class }, { Short.TYPE, Short.class }, { Integer.TYPE, Integer.class }, { Long.TYPE, Long.class }, { Double.TYPE, Double.class }, { Boolean.TYPE, Boolean.class }, }; for (int i=0; i<aliases.length; i++) { addConverter(aliases[i][0], aliases[i][1]); } } private static Object getConverter(String type) { Object converter = converters.get(type); if (converter == null) { converter = converters.get(Object.class.getName()); } return (Object)converter; } private static boolean hasConverter(String type) { return converters.get(type) != null; } private static Object convert(String type, String param) { return ((Converter)getConverter(type)).convert(param); } private static Object convert(String type, String[] params) { return ((ListConverter)getConverter(type)).convert(params); } private static boolean isListType(String type) { return getConverter(type) instanceof ListConverter; } public static class OperationParams { public Object[] arguments; public String[] signature; public boolean isAttribute = false; } private static PluginException invalidParams(String method, HashMap sigs, Object[]args) { String msg = "operation '" + method + "' takes " + sigs.keySet() + " arguments, [" + args.length + "] given"; return new PluginException(msg); } public static OperationParams getAttributeParams(MBeanInfo info, String method, Object args[]) throws PluginException { if (method.startsWith("set")) { method = method.substring(3); } MBeanAttributeInfo[] attrs = info.getAttributes(); for (int i=0; i<attrs.length; i++) { MBeanAttributeInfo attr = attrs[i]; if (!attr.getName().equals(method)) { continue; } if (!attr.isWritable()) { throw new PluginException("Attribute '" + method + "' is not writable"); } String sig = attr.getType(); if (!hasConverter(sig)) { String msg = "Cannot convert String argument to " + sig; throw new PluginException(msg); } if (args.length != 1) { String msg = "setAttribute(" + method + ") takes [1] argument, [" + args.length + "] given"; throw new PluginException(msg); } OperationParams params = new OperationParams(); Object value; try { value = convert(sig, (String)args[0]); } catch (Exception e) { String msg = "Exception converting param '" + args[0] + "' to type '" + sig + "'"; throw new PluginException(msg + ": " + e); } params.arguments = new Object[] { value }; params.isAttribute = true; return params; } return null; } public static OperationParams getOperationParams(MBeanInfo info, String method, Object args[]) throws PluginException { boolean isDebug = log.isDebugEnabled(); MBeanOperationInfo[] ops = info.getOperations(); MBeanParameterInfo[] pinfo = null; HashMap sigs = new HashMap(); if (isDebug) { log.debug("Converting params for: " + method + Arrays.asList(args)); } for (int i=0; i<ops.length; i++) { if (ops[i].getName().equals(method)) { pinfo = ops[i].getSignature(); sigs.put(new Integer(pinfo.length), pinfo); //XXX might have more than 1 method w/ same //number of args but different signature } } if (sigs.size() == 0) { OperationParams op = getAttributeParams(info, method, args); if (op != null) { return op; } String msg = "No MBean Operation or Attribute Info found for: " + method; throw new PluginException(msg); } else if (sigs.size() > 1) { //try exact match, else last one wins. Object o = sigs.get(new Integer(args.length)); if (o != null) { pinfo = (MBeanParameterInfo[])o; } } int len = pinfo.length; int nargs = args.length; String[] signature = new String[len]; List arguments = new ArrayList(); for (int i=0; i<len; i++) { String sig = pinfo[i].getType(); signature[i] = sig; if (!hasConverter(sig)) { String msg = "Cannot convert String argument to " + sig; throw new PluginException(msg); } if (i >= args.length) { throw invalidParams(method, sigs, args); } if (isListType(sig)) { String[] listArgs; if (i != 0) { int diff = args.length - i; listArgs = new String[diff]; System.arraycopy(args, i, listArgs, 0, diff); } else { listArgs = (String[])args; } nargs -= listArgs.length; arguments.add(convert(sig, listArgs)); if (i != (len-1)) { String msg = sig + " must be the last argument"; throw new PluginException(msg); } } else { nargs--; try { arguments.add(convert(sig, (String)args[i])); } catch (Exception e) { String msg = "Exception converting param[" + i + "] '" + args[i] + "' to type '" + sig + "'"; throw new PluginException(msg + ": " + e); } } if (isDebug) { log.debug(method + "() arg " + i + "=" + arguments.get(i) + ", type=" + sig); } } if (nargs != 0) { throw invalidParams(method, sigs, args); } OperationParams params = new OperationParams(); params.signature = signature; params.arguments = arguments.toArray(); return params; } }