GNU Classpath (0.95) | |
Frames | No Frames |
1: /* StandardMBean.java -- A standard reflection-based management bean. 2: Copyright (C) 2006 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package javax.management; 39: 40: import java.lang.reflect.Constructor; 41: import java.lang.reflect.InvocationTargetException; 42: import java.lang.reflect.Method; 43: 44: import java.util.ArrayList; 45: import java.util.HashMap; 46: import java.util.Iterator; 47: import java.util.List; 48: import java.util.Map; 49: 50: /** 51: * Provides a dynamic management bean by using reflection on an 52: * interface and an implementing class. By default, a bean instance 53: * is paired up with its interface based on specific naming 54: * conventions (if the implementation is called X, the interface must 55: * be XMBean). Using this class removes the need to use a specific 56: * naming system to match up the two. Instead, an instance of this 57: * bean is created either via explicit construction or subclassing, 58: * and this provides access to the attributes, constructors and 59: * operations of the implementation via reflection. Various hooks are 60: * provided in order to allow customization of this process. 61: * 62: * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 63: * @since 1.5 64: */ 65: public class StandardMBean 66: implements DynamicMBean 67: { 68: 69: /** 70: * The interface for this bean. 71: */ 72: private Class<?> iface; 73: 74: /** 75: * The implementation of the interface. 76: */ 77: private Object impl; 78: 79: /** 80: * Cached bean information. 81: */ 82: private MBeanInfo info; 83: 84: /** 85: * Constructs a new {@link StandardMBean} using the specified 86: * interface and <code>this</code> as the instance. This should 87: * be used to create an instance via subclassing. 88: * 89: * @param iface the interface this bean implements, or <code>null</code> 90: * if the interface should be determined using the naming 91: * convention (class X has interface XMBean). 92: * @throws NotCompliantMBeanException if this class doesn't implement 93: * the interface or a method appears 94: * in the interface that doesn't comply 95: * with the naming conventions. 96: */ 97: protected StandardMBean(Class<?> iface) 98: throws NotCompliantMBeanException 99: { 100: if (iface == null) 101: { 102: String className = getClass().getName(); 103: try 104: { 105: iface = Class.forName(className + "MBean"); 106: } 107: catch (ClassNotFoundException e) 108: { 109: for (Class<?> nextIface : getClass().getInterfaces()) 110: { 111: if (JMX.isMXBeanInterface(nextIface)) 112: { 113: iface = nextIface; 114: break; 115: } 116: } 117: if (iface == null) 118: throw (NotCompliantMBeanException) 119: (new NotCompliantMBeanException("An interface for the class " 120: + className + 121: " was not found.").initCause(e)); 122: } 123: } 124: if (!(iface.isInstance(this))) 125: throw new NotCompliantMBeanException("The instance, " + impl + 126: ", is not an instance of " + iface); 127: impl = this; 128: this.iface = iface; 129: } 130: 131: /** 132: * Constructs a new {@link StandardMBean} using the specified 133: * interface and the supplied instance as the implementation. 134: * 135: * @param impl the implementation. 136: * @param iface the interface the bean implements, or <code>null</code> 137: * if the interface should be determined using the naming 138: * convention (class X has interface XMBean). 139: * @throws IllegalArgumentException if <code>impl</code> is <code>null</code>. 140: * @throws NotCompliantMBeanException if <code>impl</code> doesn't implement 141: * the interface or a method appears 142: * in the interface that doesn't comply 143: * with the naming conventions. 144: */ 145: public <T> StandardMBean(T impl, Class<T> iface) 146: throws NotCompliantMBeanException 147: { 148: if (impl == null) 149: throw new IllegalArgumentException("The specified implementation is null."); 150: if (iface == null) 151: { 152: Class<?> implClass = impl.getClass(); 153: String className = implClass.getName(); 154: try 155: { 156: this.iface = Class.forName(className + "MBean", true, 157: implClass.getClassLoader()); 158: } 159: catch (ClassNotFoundException e) 160: { 161: for (Class<?> nextIface : implClass.getInterfaces()) 162: { 163: if (JMX.isMXBeanInterface(nextIface)) 164: { 165: this.iface = nextIface; 166: break; 167: } 168: } 169: if (this.iface == null) 170: throw (NotCompliantMBeanException) 171: (new NotCompliantMBeanException("An interface for the class " + 172: className + 173: " was not found.").initCause(e)); 174: } 175: } 176: else 177: this.iface = iface; 178: if (!(this.iface.isInstance(impl))) 179: throw new NotCompliantMBeanException("The instance, " + impl + 180: ", is not an instance of " + iface); 181: this.impl = impl; 182: } 183: 184: /** 185: * Caches the {@link MBeanInfo} instance for this object. This is a 186: * customization hook, so that subclasses can choose the caching policy 187: * used. The default implementation caches the value in the instance 188: * itself. Subclasses may override this so as to not cache the data 189: * at all, or so as to use a cache shared between multiple beans. 190: * 191: * @param info the {@link MBeanInfo} instance to cache, or <code>null</code> 192: * if there is no new value to cache. When the value is not 193: * <code>null</code>, the cache should replace the current value 194: * with the value supplied here. 195: * @see #getCachedMBeanInfo() 196: */ 197: protected void cacheMBeanInfo(MBeanInfo info) 198: { 199: if (info != null) 200: this.info = info; 201: } 202: 203: /** 204: * Obtains the value of the specified attribute of the 205: * management bean. The management bean should perform 206: * a lookup for the named attribute, and return its value 207: * by calling the appropriate getter method, if possible. 208: * 209: * @param name the name of the attribute to retrieve. 210: * @return the value of the specified attribute. 211: * @throws AttributeNotFoundException if the name does not 212: * correspond to an attribute 213: * of the bean. 214: * @throws MBeanException if retrieving the attribute causes 215: * the bean to throw an exception (which 216: * becomes the cause of this exception). 217: * @throws ReflectionException if an exception occurred in trying 218: * to use the reflection interface 219: * to lookup the attribute. The 220: * thrown exception is the cause of 221: * this exception. 222: * @see #setAttribute(String) 223: */ 224: public Object getAttribute(String name) 225: throws AttributeNotFoundException, MBeanException, 226: ReflectionException 227: { 228: Method getter; 229: try 230: { 231: getter = iface.getMethod("get" + name, null); 232: } 233: catch (NoSuchMethodException e) 234: { 235: try 236: { 237: getter = iface.getMethod("is" + name, null); 238: } 239: catch (NoSuchMethodException ex) 240: { 241: throw ((AttributeNotFoundException) 242: new AttributeNotFoundException("The attribute, " + name + 243: ", was not found.").initCause(ex)); 244: } 245: } 246: Object result; 247: try 248: { 249: result = getter.invoke(impl, null); 250: } 251: catch (IllegalAccessException e) 252: { 253: throw new ReflectionException(e, "Failed to retrieve " + name); 254: } 255: catch (IllegalArgumentException e) 256: { 257: throw new ReflectionException(e, "Failed to retrieve " + name); 258: } 259: catch (InvocationTargetException e) 260: { 261: throw new MBeanException((Exception) e.getCause(), 262: "The getter of " + name + 263: " threw an exception"); 264: } 265: return result; 266: } 267: 268: /** 269: * Obtains the values of each of the specified attributes 270: * of the management bean. The returned list includes 271: * those attributes that were retrieved and their 272: * corresponding values. 273: * 274: * @param names the names of the attributes to retrieve. 275: * @return a list of the retrieved attributes. 276: * @see #setAttributes(AttributeList) 277: */ 278: public AttributeList getAttributes(String[] names) 279: { 280: AttributeList list = new AttributeList(names.length); 281: for (int a = 0; a < names.length; ++a) 282: { 283: try 284: { 285: Object value = getAttribute(names[a]); 286: list.add(new Attribute(names[a], value)); 287: } 288: catch (AttributeNotFoundException e) 289: { 290: /* Ignored */ 291: } 292: catch (ReflectionException e) 293: { 294: /* Ignored */ 295: } 296: catch (MBeanException e) 297: { 298: /* Ignored */ 299: } 300: } 301: return list; 302: } 303: 304: /** 305: * Returns the cached {@link MBeanInfo} instance for this object. This is a 306: * customization hook, so that subclasses can choose the caching policy 307: * used. The default implementation caches the value in the instance 308: * itself, and returns this value on calls to this method. 309: * 310: * @return the cached {@link MBeanInfo} instance, or <code>null</code> 311: * if no value is cached. 312: * @see #cacheMBeanInfo(javax.management.MBeanInfo) 313: */ 314: protected MBeanInfo getCachedMBeanInfo() 315: { 316: return info; 317: } 318: 319: /** 320: * Returns the class name that will be used in the {@link MBeanInfo} 321: * instance. This is a customization hook, so that subclasses can 322: * provide a custom class name. By default, this returns the class 323: * name from the supplied {@link MBeanInfo} instance. 324: * 325: * @param info the {@link MBeanInfo} instance constructed via 326: * reflection. 327: * @return the class name to use in the instance. 328: */ 329: protected String getClassName(MBeanInfo info) 330: { 331: return info.getClassName(); 332: } 333: 334: /** 335: * Returns information on the constructors that will be used in 336: * the {@link MBeanInfo} instance. This is a customization hook, 337: * so that subclasses can provide their own information on the 338: * bean's constructors, if necessary. By default, this method 339: * returns <code>null</code> unless the implementation supplied 340: * is either <code>null</code> or <code>this</code>. This default 341: * implementation prevents the use of 342: * {@link MBeanServer#createMBean} in cases where the bean is 343: * not created as a subclass of {@link StandardMBean}. 344: * 345: * @param constructors the constructor information created via 346: * reflection. 347: * @param impl the implementation, or <code>null</code> if this 348: * should be ignored. 349: * @return the constructor information to use. 350: */ 351: protected MBeanConstructorInfo[] getConstructors(MBeanConstructorInfo[] 352: constructors, Object impl) 353: { 354: if (impl == null || impl == this) 355: return constructors; 356: return null; 357: } 358: 359: /** 360: * Returns the description of the attribute that will be used in 361: * the supplied {@link MBeanAttributeInfo} instance. This is a 362: * customization hook, so that subclasses can provide a custom 363: * description. By default, this calls 364: * {@link #getDescription(MBeanFeatureInfo)} with the supplied 365: * {@link MBeanAttributeInfo} instance. 366: * 367: * @param info the {@link MBeanAttributeInfo} instance constructed 368: * via reflection. 369: * @return the description to use in the instance. 370: */ 371: protected String getDescription(MBeanAttributeInfo info) 372: { 373: return getDescription((MBeanFeatureInfo) info); 374: } 375: 376: /** 377: * Returns the description of the constructor that will be used in 378: * the supplied {@link MBeanConstructorInfo} instance. This is a 379: * customization hook, so that subclasses can provide a custom 380: * description. By default, this calls 381: * {@link #getDescription(MBeanFeatureInfo)} with the supplied 382: * {@link MBeanConstructorInfo} instance. 383: * 384: * @param info the {@link MBeanConstructorInfo} instance constructed 385: * via reflection. 386: * @return the description to use in the instance. 387: */ 388: protected String getDescription(MBeanConstructorInfo info) 389: { 390: return getDescription((MBeanFeatureInfo) info); 391: } 392: 393: /** 394: * Returns the description of the nth parameter of the constructor 395: * that will be used in the supplied {@link MBeanParameterInfo} 396: * instance. This is a customization hook, so that subclasses 397: * can provide a custom description. By default, this calls 398: * <code>param.getDescription()</code>. 399: * 400: * @param info the {@link MBeanConstructorInfo} instance constructed 401: * via reflection. 402: * @param param the {@link MBeanParameterInfo} instance constructed 403: * via reflection. 404: * @param n the number of the parameter, in order to link it to the 405: * information on the constructor. 406: * @return the description to use in the instance. 407: */ 408: protected String getDescription(MBeanConstructorInfo info, 409: MBeanParameterInfo param, int n) 410: { 411: return param.getDescription(); 412: } 413: 414: /** 415: * Returns the description of the supplied feature that 416: * will be used in the supplied {@link MBeanFeatureInfo} 417: * instance. This is a customization hook, so that subclasses 418: * can provide a custom description. By default, this calls 419: * <code>info.getDescription()</code>. This method is also called 420: * by default for the more specific description methods for attributes, 421: * constructors and operations. 422: * 423: * @param info the {@link MBeanFeatureInfo} instance constructed 424: * via reflection. 425: * @return the description to use in the instance. 426: */ 427: protected String getDescription(MBeanFeatureInfo info) 428: { 429: return info.getDescription(); 430: } 431: 432: /** 433: * Returns the description of the bean that will be used in the 434: * supplied {@link MBeanInfo} instance. This is a customization 435: * hook, so that subclasses can provide a custom description. By 436: * default, this calls <code>info.getDescription()</code>. 437: * 438: * @param info the {@link MBeanInfo} instance constructed 439: * via reflection. 440: * @return the description to use in the instance. 441: */ 442: protected String getDescription(MBeanInfo info) 443: { 444: return info.getDescription(); 445: } 446: 447: /** 448: * Returns the description of the operation that will be used in 449: * the supplied {@link MBeanOperationInfo} instance. This is a 450: * customization hook, so that subclasses can provide a custom 451: * description. By default, this calls 452: * {@link #getDescription(MBeanFeatureInfo)} with the supplied 453: * {@link MBeanOperationInfo} instance. 454: * 455: * @param info the {@link MBeanOperationInfo} instance constructed 456: * via reflection. 457: * @return the description to use in the instance. 458: */ 459: protected String getDescription(MBeanOperationInfo info) 460: { 461: return getDescription((MBeanFeatureInfo) info); 462: } 463: 464: /** 465: * Returns the description of the nth parameter of the operation 466: * that will be used in the supplied {@link MBeanParameterInfo} 467: * instance. This is a customization hook, so that subclasses 468: * can provide a custom description. By default, this calls 469: * <code>param.getDescription()</code>. 470: * 471: * @param info the {@link MBeanOperationInfo} instance constructed 472: * via reflection. 473: * @param param the {@link MBeanParameterInfo} instance constructed 474: * via reflection. 475: * @param n the number of the parameter, in order to link it to the 476: * information on the operation. 477: * @return the description to use in the instance. 478: */ 479: protected String getDescription(MBeanOperationInfo info, 480: MBeanParameterInfo param, int n) 481: { 482: return param.getDescription(); 483: } 484: 485: /** 486: * Returns the impact of the operation that will be used in the 487: * supplied {@link MBeanOperationInfo} instance. This is a 488: * customization hook, so that subclasses can provide a custom 489: * impact flag. By default, this returns 490: * <code>info.getImpact()</code>. 491: * 492: * @param info the {@link MBeanOperationInfo} instance constructed 493: * via reflection. 494: * @return the impact flag to use in the instance. 495: */ 496: protected int getImpact(MBeanOperationInfo info) 497: { 498: return info.getImpact(); 499: } 500: 501: /** 502: * Returns the instance that implements this bean. 503: * 504: * @return the implementation. 505: */ 506: public Object getImplementation() 507: { 508: return impl; 509: } 510: 511: /** 512: * Returns the class of the instance that implements this bean. 513: * 514: * @return the implementation class. 515: */ 516: public Class<?> getImplementationClass() 517: { 518: return impl.getClass(); 519: } 520: 521: /** 522: * <p> 523: * Returns an information object which lists the attributes 524: * and actions associated with the management bean. This 525: * implementation proceeds as follows: 526: * </p> 527: * <ol> 528: * <li>{@link #getCachedMBeanInfo()} is called to obtain 529: * the cached instance. If this returns a non-null value, 530: * this value is returned.</li> 531: * <li>If there is no cached value, then the method proceeds 532: * to create one. During this process, the customization hooks 533: * detailed in this class are called to allow the values used 534: * to be overrided: 535: * <ul> 536: * <li>For each attribute, 537: * {@link #getDescription(MBeanAttributeInfo)} is called.</li> 538: * <li>For each constructor, 539: * {@link #getDescription(MBeanConstructorInfo)} is called, 540: * along with {@link #getDescription(MBeanConstructorInfo, 541: * MBeanParameterInfo, int)} and 542: * {@link #getParameterName(MBeanConstructorInfo, 543: * MBeanParameterInfo, int)} for each parameter.</li> 544: * <li>The constructors may be replaced as a whole by 545: * a call to 546: * {@link #getConstructors(MBeanConstructorInfo[], Object)}.</li> 547: * <li>For each operation, 548: * {@link #getDescription(MBeanOperationInfo)} and 549: * {@link #getImpact(MBeanOperationInfo)} are called, 550: * along with {@link #getDescription(MBeanOperationInfo, 551: * MBeanParameterInfo, int)} and 552: * {@link #getParameterName(MBeanOperationInfo, 553: * MBeanParameterInfo, int)} for each parameter.</li> 554: * <li>{@link #getClassName(MBeanInfo)} and 555: * {@link #getDescription(MBeanInfo)} are called to customise 556: * the basic information about the class.</li> 557: * </ul> 558: * </li> 559: * <li>Finally, {@link #cacheMBeanInfo(MBeanInfo)} is called 560: * with the created instance before it is returned.</li> 561: * </ol> 562: * 563: * @return a description of the management bean, including 564: * all exposed attributes and actions. 565: */ 566: public MBeanInfo getMBeanInfo() 567: { 568: MBeanInfo info = getCachedMBeanInfo(); 569: if (info != null) 570: return info; 571: Method[] methods = iface.getMethods(); 572: Map attributes = new HashMap(); 573: List operations = new ArrayList(); 574: for (int a = 0; a < methods.length; ++a) 575: { 576: String name = methods[a].getName(); 577: if (((name.startsWith("get") && 578: methods[a].getReturnType() != Void.TYPE) || 579: (name.startsWith("is") && 580: methods[a].getReturnType() == Boolean.TYPE)) && 581: methods[a].getParameterTypes().length == 0) 582: { 583: Method[] amethods; 584: String attrib; 585: if (name.startsWith("is")) 586: attrib = name.substring(2); 587: else 588: attrib = name.substring(3); 589: if (attributes.containsKey(attrib)) 590: amethods = (Method[]) attributes.get(attrib); 591: else 592: { 593: amethods = new Method[2]; 594: attributes.put(attrib, amethods); 595: } 596: amethods[0] = methods[a]; 597: } 598: else if (name.startsWith("set") && 599: methods[a].getReturnType() == Void.TYPE && 600: methods[a].getParameterTypes().length == 1) 601: { 602: Method[] amethods; 603: String attrib = name.substring(3); 604: if (attributes.containsKey(attrib)) 605: amethods = (Method[]) attributes.get(attrib); 606: else 607: { 608: amethods = new Method[2]; 609: attributes.put(attrib, amethods); 610: } 611: amethods[1] = methods[a]; 612: } 613: else 614: operations.add(new MBeanOperationInfo(methods[a].getName(), 615: methods[a])); 616: } 617: List attribs = new ArrayList(attributes.size()); 618: Iterator it = attributes.entrySet().iterator(); 619: while (it.hasNext()) 620: { 621: Map.Entry entry = (Map.Entry) it.next(); 622: Method[] amethods = (Method[]) entry.getValue(); 623: try 624: { 625: attribs.add(new MBeanAttributeInfo((String) entry.getKey(), 626: (String) entry.getKey(), 627: amethods[0], amethods[1])); 628: } 629: catch (IntrospectionException e) 630: { 631: /* Shouldn't happen; both shouldn't be null */ 632: throw new IllegalStateException("The two methods passed to " + 633: "the MBeanAttributeInfo " + 634: "constructor for " + entry + 635: "were null.", e); 636: } 637: } 638: MBeanAttributeInfo[] ainfo = new MBeanAttributeInfo[attribs.size()]; 639: for (int a = 0; a < ainfo.length; ++a) 640: { 641: MBeanAttributeInfo oldInfo = (MBeanAttributeInfo) attribs.get(a); 642: String desc = getDescription(oldInfo); 643: ainfo[a] = new MBeanAttributeInfo(oldInfo.getName(), 644: oldInfo.getType(), desc, 645: oldInfo.isReadable(), 646: oldInfo.isWritable(), 647: oldInfo.isIs()); 648: } 649: Constructor[] cons = impl.getClass().getConstructors(); 650: MBeanConstructorInfo[] cinfo = new MBeanConstructorInfo[cons.length]; 651: for (int a = 0; a < cinfo.length; ++a) 652: { 653: MBeanConstructorInfo oldInfo = new MBeanConstructorInfo(cons[a].getName(), 654: cons[a]); 655: String desc = getDescription(oldInfo); 656: MBeanParameterInfo[] params = oldInfo.getSignature(); 657: MBeanParameterInfo[] pinfo = new MBeanParameterInfo[params.length]; 658: for (int b = 0; b < pinfo.length; ++b) 659: { 660: String pdesc = getDescription(oldInfo, params[b], b); 661: String pname = getParameterName(oldInfo, params[b], b); 662: pinfo[b] = new MBeanParameterInfo(pname, params[b].getType(), 663: pdesc); 664: } 665: cinfo[a] = new MBeanConstructorInfo(oldInfo.getName(), desc, 666: pinfo); 667: } 668: cinfo = getConstructors(cinfo, impl); 669: MBeanOperationInfo[] oinfo = new MBeanOperationInfo[operations.size()]; 670: for (int a = 0; a < oinfo.length; ++a) 671: { 672: MBeanOperationInfo oldInfo = (MBeanOperationInfo) operations.get(a); 673: String desc = getDescription(oldInfo); 674: int impact = getImpact(oldInfo); 675: MBeanParameterInfo[] params = oldInfo.getSignature(); 676: MBeanParameterInfo[] pinfo = new MBeanParameterInfo[params.length]; 677: for (int b = 0; b < pinfo.length; ++b) 678: { 679: String pdesc = getDescription(oldInfo, params[b], b); 680: String pname = getParameterName(oldInfo, params[b], b); 681: pinfo[b] = new MBeanParameterInfo(pname, params[b].getType(), 682: pdesc); 683: } 684: oinfo[a] = new MBeanOperationInfo(oldInfo.getName(), desc, pinfo, 685: oldInfo.getReturnType(), impact); 686: } 687: info = new MBeanInfo(impl.getClass().getName(), impl.getClass().getName(), 688: ainfo, cinfo, oinfo, null); 689: String cname = getClassName(info); 690: String desc = getDescription(info); 691: MBeanNotificationInfo[] ninfo = null; 692: if (impl instanceof NotificationBroadcaster) 693: ninfo = ((NotificationBroadcaster) impl).getNotificationInfo(); 694: info = new MBeanInfo(cname, desc, ainfo, cinfo, oinfo, ninfo); 695: cacheMBeanInfo(info); 696: return info; 697: } 698: 699: /** 700: * Returns the interface for this management bean. 701: * 702: * @return the management interface. 703: */ 704: public final Class<?> getMBeanInterface() 705: { 706: return iface; 707: } 708: 709: /** 710: * Returns the name of the nth parameter of the constructor 711: * that will be used in the supplied {@link MBeanParameterInfo} 712: * instance. This is a customization hook, so that subclasses 713: * can provide a custom name. By default, this calls 714: * <code>param.getName()</code>. 715: * 716: * @param info the {@link MBeanConstructorInfo} instance constructed 717: * via reflection. 718: * @param param the {@link MBeanParameterInfo} instance constructed 719: * via reflection. 720: * @param n the number of the parameter, in order to link it to the 721: * information on the constructor. 722: * @return the name to use in the instance. 723: */ 724: protected String getParameterName(MBeanConstructorInfo info, 725: MBeanParameterInfo param, int n) 726: { 727: return param.getName(); 728: } 729: 730: /** 731: * Returns the name of the nth parameter of the operation 732: * that will be used in the supplied {@link MBeanParameterInfo} 733: * instance. This is a customization hook, so that subclasses 734: * can provide a custom name. By default, this calls 735: * <code>param.getName()</code>. 736: * 737: * @param info the {@link MBeanOperationInfo} instance constructed 738: * via reflection. 739: * @param param the {@link MBeanParameterInfo} instance constructed 740: * via reflection. 741: * @param n the number of the parameter, in order to link it to the 742: * information on the operation. 743: * @return the name to use in the instance. 744: */ 745: protected String getParameterName(MBeanOperationInfo info, 746: MBeanParameterInfo param, int n) 747: { 748: return param.getName(); 749: } 750: 751: /** 752: * Invokes the specified action on the management bean using 753: * the supplied parameters. The signature of the action is 754: * specified by a {@link String} array, which lists the classes 755: * corresponding to each parameter. The class loader used to 756: * load these classes is the same as that used for loading the 757: * management bean itself. 758: * 759: * @param name the name of the action to invoke. 760: * @param params the parameters used to call the action. 761: * @param signature the signature of the action. 762: * @return the return value of the action. 763: * @throws MBeanException if the action throws an exception. The 764: * thrown exception is the cause of this 765: * exception. 766: * @throws ReflectionException if an exception occurred in trying 767: * to use the reflection interface 768: * to invoke the action. The 769: * thrown exception is the cause of 770: * this exception. 771: */ 772: public Object invoke(String name, Object[] params, String[] signature) 773: throws MBeanException, ReflectionException 774: { 775: if (name.startsWith("get") || name.startsWith("is") || 776: name.startsWith("set")) 777: throw new ReflectionException(new NoSuchMethodException(), 778: "Invocation of an attribute " + 779: "method is disallowed."); 780: ClassLoader loader = getClass().getClassLoader(); 781: Class[] sigTypes; 782: if (signature != null) 783: { 784: sigTypes = new Class[signature.length]; 785: for (int a = 0; a < signature.length; ++a) 786: try 787: { 788: sigTypes[a] = Class.forName(signature[a], true, loader); 789: } 790: catch (ClassNotFoundException e) 791: { 792: throw new ReflectionException(e, "The class, " + signature[a] + 793: ", in the method signature " + 794: "could not be loaded."); 795: } 796: } 797: else 798: sigTypes = null; 799: Method method; 800: try 801: { 802: method = iface.getMethod(name, sigTypes); 803: } 804: catch (NoSuchMethodException e) 805: { 806: throw new ReflectionException(e, "The method, " + name + 807: ", could not be found."); 808: } 809: Object result; 810: try 811: { 812: result = method.invoke(impl, params); 813: } 814: catch (IllegalAccessException e) 815: { 816: throw new ReflectionException(e, "Failed to call " + name); 817: } 818: catch (IllegalArgumentException e) 819: { 820: throw new ReflectionException(e, "Failed to call " + name); 821: } 822: catch (InvocationTargetException e) 823: { 824: throw new MBeanException((Exception) e.getCause(), "The method " 825: + name + " threw an exception"); 826: } 827: return result; 828: } 829: 830: /** 831: * Sets the value of the specified attribute of the 832: * management bean. The management bean should perform 833: * a lookup for the named attribute, and sets its value 834: * using the associated setter method, if possible. 835: * 836: * @param attribute the attribute to set. 837: * @throws AttributeNotFoundException if the attribute does not 838: * correspond to an attribute 839: * of the bean. 840: * @throws InvalidAttributeValueException if the value is invalid 841: * for this particular 842: * attribute of the bean. 843: * @throws MBeanException if setting the attribute causes 844: * the bean to throw an exception (which 845: * becomes the cause of this exception). 846: * @throws ReflectionException if an exception occurred in trying 847: * to use the reflection interface 848: * to lookup the attribute. The 849: * thrown exception is the cause of 850: * this exception. 851: * @see #getAttribute(String) 852: */ 853: public void setAttribute(Attribute attribute) 854: throws AttributeNotFoundException, InvalidAttributeValueException, 855: MBeanException, ReflectionException 856: { 857: String name = attribute.getName(); 858: String attName = name.substring(0, 1).toUpperCase() + name.substring(1); 859: Object val = attribute.getValue(); 860: try 861: { 862: getMutator(attName, val.getClass()).invoke(impl, new Object[] { val }); 863: } 864: catch (IllegalAccessException e) 865: { 866: throw new ReflectionException(e, "Failed to set " + name); 867: } 868: catch (IllegalArgumentException e) 869: { 870: throw ((InvalidAttributeValueException) 871: new InvalidAttributeValueException(attribute.getValue() + 872: " is an invalid value for " + 873: name).initCause(e)); 874: } 875: catch (InvocationTargetException e) 876: { 877: throw new MBeanException(e, "The getter of " + name + 878: " threw an exception"); 879: } 880: } 881: 882: /** 883: * Sets the value of each of the specified attributes 884: * to that supplied by the {@link Attribute} object. 885: * The returned list contains the attributes that were 886: * set and their new values. 887: * 888: * @param attributes the attributes to set. 889: * @return a list of the changed attributes. 890: * @see #getAttributes(AttributeList) 891: */ 892: public AttributeList setAttributes(AttributeList attributes) 893: { 894: AttributeList list = new AttributeList(attributes.size()); 895: Iterator it = attributes.iterator(); 896: while (it.hasNext()) 897: { 898: try 899: { 900: Attribute attrib = (Attribute) it.next(); 901: setAttribute(attrib); 902: list.add(attrib); 903: } 904: catch (AttributeNotFoundException e) 905: { 906: /* Ignored */ 907: } 908: catch (InvalidAttributeValueException e) 909: { 910: /* Ignored */ 911: } 912: catch (ReflectionException e) 913: { 914: /* Ignored */ 915: } 916: catch (MBeanException e) 917: { 918: /* Ignored */ 919: } 920: } 921: return list; 922: } 923: 924: /** 925: * Replaces the implementation of the interface used by this 926: * instance with the one specified. The new implementation 927: * must be non-null and implement the interface specified on 928: * construction of this instance. 929: * 930: * @throws IllegalArgumentException if <code>impl</code> is <code>null</code>. 931: * @throws NotCompliantMBeanException if <code>impl</code> doesn't implement 932: * the interface or a method appears 933: * in the interface that doesn't comply 934: * with the naming conventions. 935: */ 936: public void setImplementation(Object impl) 937: throws NotCompliantMBeanException 938: { 939: if (impl == null) 940: throw new IllegalArgumentException("The specified implementation is null."); 941: if (!(iface.isInstance(impl))) 942: throw new NotCompliantMBeanException("The instance, " + impl + 943: ", is not an instance of " + iface); 944: this.impl = impl; 945: } 946: 947: /** 948: * Returns the mutator method for a particular attribute name 949: * with a parameter type matching that of the given value. 950: * 951: * @param name the name of the attribute. 952: * @param type the type of the parameter. 953: * @return the appropriate mutator method. 954: * @throws AttributeNotFoundException if a method can't be found. 955: */ 956: private Method getMutator(String name, Class<?> type) 957: throws AttributeNotFoundException 958: { 959: String mutator = "set" + name; 960: Exception ex = null; 961: try 962: { 963: return iface.getMethod(mutator, type); 964: } 965: catch (NoSuchMethodException e) 966: { 967: /* Ignored; we'll try harder instead */ 968: ex = e; 969: } 970: /* Special cases */ 971: if (type == Boolean.class) 972: try 973: { 974: return iface.getMethod(mutator, Boolean.TYPE); 975: } 976: catch (NoSuchMethodException e) 977: { 978: throw ((AttributeNotFoundException) 979: new AttributeNotFoundException("The attribute, " + name + 980: ", was not found.").initCause(e)); 981: } 982: if (type == Byte.class) 983: try 984: { 985: return iface.getMethod(mutator, Byte.TYPE); 986: } 987: catch (NoSuchMethodException e) 988: { 989: throw ((AttributeNotFoundException) 990: new AttributeNotFoundException("The attribute, " + name + 991: ", was not found.").initCause(e)); 992: } 993: if (type == Character.class) 994: try 995: { 996: return iface.getMethod(mutator, Character.TYPE); 997: } 998: catch (NoSuchMethodException e) 999: { 1000: throw ((AttributeNotFoundException) 1001: new AttributeNotFoundException("The attribute, " + name + 1002: ", was not found.").initCause(e)); 1003: } 1004: if (type == Double.class) 1005: try 1006: { 1007: return iface.getMethod(mutator, Double.TYPE); 1008: } 1009: catch (NoSuchMethodException e) 1010: { 1011: throw ((AttributeNotFoundException) 1012: new AttributeNotFoundException("The attribute, " + name + 1013: ", was not found.").initCause(e)); 1014: } 1015: if (type == Float.class) 1016: try 1017: { 1018: return iface.getMethod(mutator, Float.TYPE); 1019: } 1020: catch (NoSuchMethodException e) 1021: { 1022: throw ((AttributeNotFoundException) 1023: new AttributeNotFoundException("The attribute, " + name + 1024: ", was not found.").initCause(e)); 1025: } 1026: if (type == Integer.class) 1027: try 1028: { 1029: return iface.getMethod(mutator, Integer.TYPE); 1030: } 1031: catch (NoSuchMethodException e) 1032: { 1033: throw ((AttributeNotFoundException) 1034: new AttributeNotFoundException("The attribute, " + name + 1035: ", was not found.").initCause(e)); 1036: } 1037: if (type == Long.class) 1038: try 1039: { 1040: return iface.getMethod(mutator, Long.TYPE); 1041: } 1042: catch (NoSuchMethodException e) 1043: { 1044: throw ((AttributeNotFoundException) 1045: new AttributeNotFoundException("The attribute, " + name + 1046: ", was not found.").initCause(e)); 1047: } 1048: if (type == Short.class) 1049: try 1050: { 1051: return iface.getMethod(mutator, Short.TYPE); 1052: } 1053: catch (NoSuchMethodException e) 1054: { 1055: throw ((AttributeNotFoundException) 1056: new AttributeNotFoundException("The attribute, " + name + 1057: ", was not found.").initCause(e)); 1058: } 1059: /* Superclasses and interfaces */ 1060: for (Class<?> i : type.getInterfaces()) 1061: try 1062: { 1063: return getMutator(name, i); 1064: } 1065: catch (AttributeNotFoundException e) 1066: { 1067: ex = e; 1068: } 1069: Class<?> sclass = type.getSuperclass(); 1070: if (sclass != null && sclass != Object.class) 1071: try 1072: { 1073: return getMutator(name, sclass); 1074: } 1075: catch (AttributeNotFoundException e) 1076: { 1077: ex = e; 1078: } 1079: /* If we get this far, give up */ 1080: throw ((AttributeNotFoundException) 1081: new AttributeNotFoundException("The attribute, " + name + 1082: ", was not found.").initCause(ex)); 1083: } 1084: 1085: }
GNU Classpath (0.95) |