001/* 002 * HA-JDBC: High-Availability JDBC 003 * Copyright (C) 2012 Paul Ferraro 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Lesser General Public License as published by 007 * the Free Software Foundation, either version 3 of the License, or 008 * (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018package net.sf.hajdbc.management; 019 020import java.beans.BeanInfo; 021import java.beans.Introspector; 022import java.beans.MethodDescriptor; 023import java.beans.PropertyDescriptor; 024import java.lang.reflect.InvocationTargetException; 025import java.lang.reflect.Method; 026import java.util.ArrayList; 027import java.util.HashMap; 028import java.util.List; 029import java.util.Map; 030import javax.management.Attribute; 031import javax.management.AttributeList; 032import javax.management.AttributeNotFoundException; 033import javax.management.DynamicMBean; 034import javax.management.InvalidAttributeValueException; 035import javax.management.MBeanAttributeInfo; 036import javax.management.MBeanException; 037import javax.management.MBeanInfo; 038import javax.management.MBeanOperationInfo; 039import javax.management.ReflectionException; 040 041/** 042 * @author Paul Ferraro 043 */ 044public class AnnotatedMBean implements DynamicMBean 045{ 046 private final MBeanInfo info; 047 private final Object bean; 048 private final Map<String, Method> accessorMap = new HashMap<String, Method>(); 049 private final Map<String, Method> mutatorMap = new HashMap<String, Method>(); 050 051 public AnnotatedMBean(Object bean) 052 { 053 Class<?> beanClass = bean.getClass(); 054 055 MBean mbean = beanClass.getAnnotation(MBean.class); 056 057 if (mbean == null) 058 { 059 throw new IllegalArgumentException(String.format("%s is not an @MBean", beanClass)); 060 } 061 062 this.bean = bean; 063 064 try 065 { 066 BeanInfo beanInfo = Introspector.getBeanInfo(beanClass); 067 PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors(); 068 List<MBeanAttributeInfo> attributeList = new ArrayList<MBeanAttributeInfo>(properties.length); 069 070 for (PropertyDescriptor descriptor: properties) 071 { 072 Method accessor = descriptor.getReadMethod(); 073 ManagedAttribute managedAccessor = (accessor != null) ? accessor.getAnnotation(ManagedAttribute.class) : null; 074 075 Method mutator = descriptor.getWriteMethod(); 076 ManagedAttribute managedMutator = (mutator != null) ? mutator.getAnnotation(ManagedAttribute.class) : null; 077 078 if ((managedAccessor != null) || (managedMutator != null)) 079 { 080 String name = descriptor.getName(); 081 082 Description description = (accessor != null) ? accessor.getAnnotation(Description.class) : null; 083 if ((description == null) && (mutator != null)) 084 { 085 description = mutator.getAnnotation(Description.class); 086 } 087 088 attributeList.add(new MBeanAttributeInfo(name, (description != null) ? description.value() : null, (managedAccessor != null) ? accessor : null, (managedMutator != null) ? mutator : null)); 089 090 if (managedAccessor != null) 091 { 092 this.accessorMap.put(name, accessor); 093 } 094 095 if (managedMutator != null) 096 { 097 this.mutatorMap.put(name, mutator); 098 } 099 } 100 } 101 102 MethodDescriptor[] methods = beanInfo.getMethodDescriptors(); 103 List<MBeanOperationInfo> operationList = new ArrayList<MBeanOperationInfo>(methods.length); 104 105 for (MethodDescriptor descriptor: beanInfo.getMethodDescriptors()) 106 { 107 Method method = descriptor.getMethod(); 108 ManagedOperation managedMethod = method.getAnnotation(ManagedOperation.class); 109 110 if (managedMethod != null) 111 { 112 Description description = method.getAnnotation(Description.class); 113 114 operationList.add(new MBeanOperationInfo((description != null) ? description.value() : null, method)); 115 } 116 } 117 118 Description description = beanClass.getAnnotation(Description.class); 119 120 this.info = new MBeanInfo(beanClass.getName(), (description != null) ? description.value() : null, attributeList.toArray(new MBeanAttributeInfo[attributeList.size()]), null, operationList.toArray(new MBeanOperationInfo[operationList.size()]), null); 121 } 122 catch (java.beans.IntrospectionException e) 123 { 124 throw new IllegalArgumentException(e); 125 } 126 catch (javax.management.IntrospectionException e) 127 { 128 throw new IllegalArgumentException(e); 129 } 130 } 131 132 /** 133 * {@inheritDoc} 134 * @see javax.management.DynamicMBean#getAttribute(java.lang.String) 135 */ 136 @Override 137 public Object getAttribute(String name) throws AttributeNotFoundException, MBeanException, ReflectionException 138 { 139 Method method = this.accessorMap.get(name); 140 141 if (method == null) 142 { 143 throw new AttributeNotFoundException(name); 144 } 145 146 try 147 { 148 return method.invoke(this.bean); 149 } 150 catch (InvocationTargetException e) 151 { 152 throw new ReflectionException(e); 153 } 154 catch (IllegalArgumentException e) 155 { 156 throw new MBeanException(e); 157 } 158 catch (IllegalAccessException e) 159 { 160 throw new MBeanException(e); 161 } 162 } 163 164 /** 165 * {@inheritDoc} 166 * @see javax.management.DynamicMBean#getAttributes(java.lang.String[]) 167 */ 168 @Override 169 public AttributeList getAttributes(String[] names) 170 { 171 AttributeList list = new AttributeList(names.length); 172 173 for (String name: names) 174 { 175 try 176 { 177 list.add(new Attribute(name, this.getAttribute(name))); 178 } 179 catch (Exception e) 180 { 181 // Ignore 182 } 183 } 184 185 return list; 186 } 187 188 /** 189 * {@inheritDoc} 190 * @see javax.management.DynamicMBean#getMBeanInfo() 191 */ 192 @Override 193 public MBeanInfo getMBeanInfo() 194 { 195 return this.info; 196 } 197 198 /** 199 * {@inheritDoc} 200 * @see javax.management.DynamicMBean#invoke(java.lang.String, java.lang.Object[], java.lang.String[]) 201 */ 202 @Override 203 public Object invoke(String method, Object[] args, String[] types) throws MBeanException, ReflectionException 204 { 205 Class<?>[] classes = new Class<?>[types.length]; 206 207 try 208 { 209 for (int i = 0; i < types.length; ++i) 210 { 211 classes[i] = this.bean.getClass().getClassLoader().loadClass(types[i]); 212 } 213 214 return this.bean.getClass().getMethod(method, classes).invoke(this.bean, args); 215 } 216 catch (ClassNotFoundException e) 217 { 218 throw new MBeanException(e); 219 } 220 catch (IllegalArgumentException e) 221 { 222 throw new MBeanException(e); 223 } 224 catch (SecurityException e) 225 { 226 throw new MBeanException(e); 227 } 228 catch (IllegalAccessException e) 229 { 230 throw new MBeanException(e); 231 } 232 catch (InvocationTargetException e) 233 { 234 throw new ReflectionException(e); 235 } 236 catch (NoSuchMethodException e) 237 { 238 throw new MBeanException(e); 239 } 240 } 241 242 /** 243 * {@inheritDoc} 244 * @see javax.management.DynamicMBean#setAttribute(javax.management.Attribute) 245 */ 246 @Override 247 public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException 248 { 249 Method method = this.mutatorMap.get(attribute.getName()); 250 251 if (method == null) 252 { 253 throw new AttributeNotFoundException(attribute.getName()); 254 } 255 256 try 257 { 258 this.mutatorMap.get(attribute.getName()).invoke(this.bean, attribute.getValue()); 259 } 260 catch (IllegalArgumentException e) 261 { 262 throw new InvalidAttributeValueException(e.getMessage()); 263 } 264 catch (IllegalAccessException e) 265 { 266 throw new MBeanException(e); 267 } 268 catch (InvocationTargetException e) 269 { 270 throw new ReflectionException(e); 271 } 272 } 273 274 /** 275 * {@inheritDoc} 276 * @see javax.management.DynamicMBean#setAttributes(javax.management.AttributeList) 277 */ 278 @Override 279 public AttributeList setAttributes(AttributeList attributes) 280 { 281 AttributeList list = new AttributeList(attributes.size()); 282 283 for (Object attribute: attributes) 284 { 285 try 286 { 287 this.setAttribute((Attribute) attribute); 288 289 list.add(attribute); 290 } 291 catch (Exception e) 292 { 293 // Ignore 294 } 295 } 296 297 return list; 298 } 299}