001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.fusesource.hawtdispatch.jmx; 018 019import javax.management.*; 020import java.lang.annotation.Annotation; 021import java.lang.reflect.Method; 022import java.util.HashMap; 023import java.util.Map; 024 025/** 026 * MBean that looks for method/parameter descriptions in the Info annotation. 027 */ 028public class AnnotatedMBean extends StandardMBean { 029 030 private static final Map<String, Class<?>> primitives = new HashMap<String, Class<?>>(); 031 032 static { 033 Class<?>[] p = { byte.class, short.class, int.class, long.class, float.class, double.class, char.class, boolean.class, }; 034 for (Class<?> c : p) { 035 primitives.put(c.getName(), c); 036 } 037 } 038 039 @SuppressWarnings({ "unchecked", "rawtypes" }) 040 public static AnnotatedMBean create(Object object) throws Exception { 041 String mbeanName = object.getClass().getName() + "MBean"; 042 for (Class c : object.getClass().getInterfaces()) { 043 if (mbeanName.equals(c.getName())) { 044 return new AnnotatedMBean(object, c); 045 } 046 } 047 throw new IllegalArgumentException(object.getClass().getName()+" does not implement a "+object.getClass().getName()+"MBean interface"); 048 } 049 050 /** Instance where the MBean interface is implemented by another object. */ 051 public <T> AnnotatedMBean(T impl, Class<T> mbeanInterface) throws NotCompliantMBeanException { 052 super(impl, mbeanInterface); 053 } 054 055 /** Instance where the MBean interface is implemented by this object. */ 056 protected AnnotatedMBean(Class<?> mbeanInterface) throws NotCompliantMBeanException { 057 super(mbeanInterface); 058 } 059 060 /** {@inheritDoc} */ 061 @Override 062 protected String getDescription(MBeanAttributeInfo info) { 063 064 String descr = info.getDescription(); 065 Method m = getMethod(getMBeanInterface(), "get" + info.getName().substring(0, 1).toUpperCase() + info.getName().substring(1)); 066 if (m == null) 067 m = getMethod(getMBeanInterface(), "is" + info.getName().substring(0, 1).toUpperCase() + info.getName().substring(1)); 068 if (m == null) 069 m = getMethod(getMBeanInterface(), "does" + info.getName().substring(0, 1).toUpperCase() + info.getName().substring(1)); 070 071 if (m != null) { 072 MBeanInfo d = m.getAnnotation(MBeanInfo.class); 073 if (d != null) 074 descr = d.value(); 075 } 076 return descr; 077 } 078 079 /** {@inheritDoc} */ 080 @Override 081 protected String getDescription(MBeanOperationInfo op) { 082 083 String descr = op.getDescription(); 084 Method m = getMethod(op); 085 if (m != null) { 086 MBeanInfo d = m.getAnnotation(MBeanInfo.class); 087 if (d != null) 088 descr = d.value(); 089 } 090 return descr; 091 } 092 093 /** {@inheritDoc} */ 094 @Override 095 protected String getParameterName(MBeanOperationInfo op, MBeanParameterInfo param, int paramNo) { 096 String name = param.getName(); 097 Method m = getMethod(op); 098 if (m != null) { 099 for (Annotation a : m.getParameterAnnotations()[paramNo]) { 100 if (MBeanInfo.class.isInstance(a)) 101 name = MBeanInfo.class.cast(a).value(); 102 } 103 } 104 return name; 105 } 106 107 /** 108 * Extracts the Method from the MBeanOperationInfo 109 * 110 * @param op 111 * @return 112 */ 113 private Method getMethod(MBeanOperationInfo op) { 114 final MBeanParameterInfo[] params = op.getSignature(); 115 final String[] paramTypes = new String[params.length]; 116 for (int i = 0; i < params.length; i++) 117 paramTypes[i] = params[i].getType(); 118 119 return getMethod(getMBeanInterface(), op.getName(), paramTypes); 120 } 121 122 /** 123 * Returns the Method with the specified name and parameter types for the 124 * given class, null if it doesn't exist. 125 * 126 * @param mbean 127 * @param method 128 * @param params 129 * @return 130 */ 131 private static Method getMethod(Class<?> mbean, String method, String... params) { 132 try { 133 final ClassLoader loader = mbean.getClassLoader(); 134 final Class<?>[] paramClasses = new Class<?>[params.length]; 135 for (int i = 0; i < params.length; i++) { 136 paramClasses[i] = primitives.get(params[i]); 137 if (paramClasses[i] == null) 138 paramClasses[i] = Class.forName(params[i], false, loader); 139 } 140 return mbean.getMethod(method, paramClasses); 141 } catch (RuntimeException e) { 142 throw e; 143 } catch (Exception e) { 144 return null; 145 } 146 } 147}