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 */ 017 package org.apache.activemq.broker.jmx; 018 019 import java.lang.annotation.Annotation; 020 import java.lang.reflect.Method; 021 import java.util.HashMap; 022 import java.util.Map; 023 024 import javax.management.InstanceAlreadyExistsException; 025 import javax.management.MBeanAttributeInfo; 026 import javax.management.MBeanOperationInfo; 027 import javax.management.MBeanParameterInfo; 028 import javax.management.MBeanRegistrationException; 029 import javax.management.MBeanServer; 030 import javax.management.NotCompliantMBeanException; 031 import javax.management.ObjectName; 032 import javax.management.StandardMBean; 033 034 /** 035 * MBean that looks for method/parameter descriptions in the Info annotation. 036 */ 037 public class AnnotatedMBean extends StandardMBean { 038 039 private static final Map<String, Class<?>> primitives = new HashMap<String, Class<?>>(); 040 static { 041 Class<?>[] p = { byte.class, short.class, int.class, long.class, float.class, double.class, char.class, boolean.class, }; 042 for (Class<?> c : p) 043 primitives.put(c.getName(), c); 044 } 045 046 @SuppressWarnings("unchecked") 047 public static void registerMBean(ManagementContext context, Object object, ObjectName objectName) 048 throws Exception { 049 050 String mbeanName = object.getClass().getName() + "MBean"; 051 052 for (Class c : object.getClass().getInterfaces()) { 053 if (mbeanName.equals(c.getName())) { 054 context.registerMBean(new AnnotatedMBean(object, c), objectName); 055 return; 056 } 057 } 058 059 context.registerMBean(object, objectName); 060 } 061 062 /** Instance where the MBean interface is implemented by another object. */ 063 public <T> AnnotatedMBean(T impl, Class<T> mbeanInterface) throws NotCompliantMBeanException { 064 super(impl, mbeanInterface); 065 } 066 067 /** Instance where the MBean interface is implemented by this object. */ 068 protected AnnotatedMBean(Class<?> mbeanInterface) throws NotCompliantMBeanException { 069 super(mbeanInterface); 070 } 071 072 /** {@inheritDoc} */ 073 @Override 074 protected String getDescription(MBeanAttributeInfo info) { 075 076 String descr = info.getDescription(); 077 Method m = getMethod(getMBeanInterface(), "get"+info.getName().substring(0, 1).toUpperCase()+info.getName().substring(1)); 078 if (m == null) 079 m = getMethod(getMBeanInterface(), "is"+info.getName().substring(0, 1).toUpperCase()+info.getName().substring(1)); 080 if (m == null) 081 m = getMethod(getMBeanInterface(), "does"+info.getName().substring(0, 1).toUpperCase()+info.getName().substring(1)); 082 083 if (m != null) { 084 MBeanInfo d = m.getAnnotation(MBeanInfo.class); 085 if (d != null) 086 descr = d.value(); 087 } 088 return descr; 089 } 090 091 /** {@inheritDoc} */ 092 @Override 093 protected String getDescription(MBeanOperationInfo op) { 094 095 String descr = op.getDescription(); 096 Method m = getMethod(op); 097 if (m != null) { 098 MBeanInfo d = m.getAnnotation(MBeanInfo.class); 099 if (d != null) 100 descr = d.value(); 101 } 102 return descr; 103 } 104 105 /** {@inheritDoc} */ 106 @Override 107 protected String getParameterName(MBeanOperationInfo op, MBeanParameterInfo param, int paramNo) { 108 String name = param.getName(); 109 Method m = getMethod(op); 110 if (m != null) { 111 for (Annotation a : m.getParameterAnnotations()[paramNo]) { 112 if (MBeanInfo.class.isInstance(a)) 113 name = MBeanInfo.class.cast(a).value(); 114 } 115 } 116 return name; 117 } 118 119 /** 120 * Extracts the Method from the MBeanOperationInfo 121 * @param op 122 * @return 123 */ 124 private Method getMethod(MBeanOperationInfo op) { 125 final MBeanParameterInfo[] params = op.getSignature(); 126 final String[] paramTypes = new String[params.length]; 127 for (int i = 0; i < params.length; i++) 128 paramTypes[i] = params[i].getType(); 129 130 return getMethod(getMBeanInterface(), op.getName(), paramTypes); 131 } 132 133 /** 134 * Returns the Method with the specified name and parameter types for the given class, 135 * null if it doesn't exist. 136 * @param mbean 137 * @param method 138 * @param params 139 * @return 140 */ 141 private static Method getMethod(Class<?> mbean, String method, String... params) { 142 try { 143 final ClassLoader loader = mbean.getClassLoader(); 144 final Class<?>[] paramClasses = new Class<?>[params.length]; 145 for (int i = 0; i < params.length; i++) { 146 paramClasses[i] = primitives.get(params[i]); 147 if (paramClasses[i] == null) 148 paramClasses[i] = Class.forName(params[i], false, loader); 149 } 150 return mbean.getMethod(method, paramClasses); 151 } catch (RuntimeException e) { 152 throw e; 153 } catch (Exception e) { 154 return null; 155 } 156 } 157 }