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: throw (NotCompliantMBeanException) 110: (new NotCompliantMBeanException("An interface for the class " + 111: className + " was not found.").initCause(e)); 112: } 113: } 114: if (!(iface.isInstance(this))) 115: throw new NotCompliantMBeanException("The instance, " + impl + 116: ", is not an instance of " + iface); 117: impl = this; 118: this.iface = iface; 119: } 120: 121: /** 122: * Constructs a new {@link StandardMBean} using the specified 123: * interface and the supplied instance as the implementation. 124: * 125: * @param impl the implementation. 126: * @param iface the interface the bean implements, or <code>null</code> 127: * if the interface should be determined using the naming 128: * convention (class X has interface XMBean). 129: * @throws IllegalArgumentException if <code>impl</code> is <code>null</code>. 130: * @throws NotCompliantMBeanException if <code>impl</code> doesn't implement 131: * the interface or a method appears 132: * in the interface that doesn't comply 133: * with the naming conventions. 134: */ 135: public StandardMBean(Object impl, Class iface) 136: throws NotCompliantMBeanException 137: { 138: if (impl == null) 139: throw new IllegalArgumentException("The specified implementation is null."); 140: if (iface == null) 141: { 142: String className = impl.getClass().getName(); 143: try 144: { 145: iface = Class.forName(className + "MBean"); 146: } 147: catch (ClassNotFoundException e) 148: { 149: throw (NotCompliantMBeanException) 150: (new NotCompliantMBeanException("An interface for the class " + 151: className + " was not found.").initCause(e)); 152: } 153: } 154: if (!(iface.isInstance(impl))) 155: throw new NotCompliantMBeanException("The instance, " + impl + 156: ", is not an instance of " + iface); 157: this.impl = impl; 158: this.iface = iface; 159: } 160: 161: /** 162: * Caches the {@link MBeanInfo} instance for this object. This is a 163: * customization hook, so that subclasses can choose the caching policy 164: * used. The default implementation caches the value in the instance 165: * itself. Subclasses may override this so as to not cache the data 166: * at all, or so as to use a cache shared between multiple beans. 167: * 168: * @param info the {@link MBeanInfo} instance to cache, or <code>null</code> 169: * if there is no new value to cache. When the value is not 170: * <code>null</code>, the cache should replace the current value 171: * with the value supplied here. 172: * @see #getCachedMBeanInfo() 173: */ 174: protected void cacheMBeanInfo(MBeanInfo info) 175: { 176: if (info != null) 177: this.info = info; 178: } 179: 180: /** 181: * Obtains the value of the specified attribute of the 182: * management bean. The management bean should perform 183: * a lookup for the named attribute, and return its value 184: * by calling the appropriate getter method, if possible. 185: * 186: * @param name the name of the attribute to retrieve. 187: * @return the value of the specified attribute. 188: * @throws AttributeNotFoundException if the name does not 189: * correspond to an attribute 190: * of the bean. 191: * @throws MBeanException if retrieving the attribute causes 192: * the bean to throw an exception (which 193: * becomes the cause of this exception). 194: * @throws ReflectionException if an exception occurred in trying 195: * to use the reflection interface 196: * to lookup the attribute. The 197: * thrown exception is the cause of 198: * this exception. 199: * @see #setAttribute(String) 200: */ 201: public Object getAttribute(String name) 202: throws AttributeNotFoundException, MBeanException, 203: ReflectionException 204: { 205: Method getter; 206: try 207: { 208: getter = iface.getMethod("get" + 209: name.substring(0, 1).toUpperCase() + 210: name.substring(1), null); 211: } 212: catch (NoSuchMethodException e) 213: { 214: try 215: { 216: getter = iface.getMethod("is" + 217: name.substring(0, 1).toUpperCase() + 218: name.substring(1), null); 219: } 220: catch (NoSuchMethodException ex) 221: { 222: throw ((AttributeNotFoundException) 223: new AttributeNotFoundException("The attribute, " + name + 224: ", was not found.").initCause(ex)); 225: } 226: } 227: Object result; 228: try 229: { 230: result = getter.invoke(impl, null); 231: } 232: catch (IllegalAccessException e) 233: { 234: throw new ReflectionException(e, "Failed to retrieve " + name); 235: } 236: catch (IllegalArgumentException e) 237: { 238: throw new ReflectionException(e, "Failed to retrieve " + name); 239: } 240: catch (InvocationTargetException e) 241: { 242: throw new MBeanException((Exception) e.getCause(), 243: "The getter of " + name + 244: " threw an exception"); 245: } 246: return result; 247: } 248: 249: /** 250: * Obtains the values of each of the specified attributes 251: * of the management bean. The returned list includes 252: * those attributes that were retrieved and their 253: * corresponding values. 254: * 255: * @param names the names of the attributes to retrieve. 256: * @return a list of the retrieved attributes. 257: * @see #setAttributes(AttributeList) 258: */ 259: public AttributeList getAttributes(String[] names) 260: { 261: AttributeList list = new AttributeList(names.length); 262: for (int a = 0; a < names.length; ++a) 263: { 264: try 265: { 266: Object value = getAttribute(names[a]); 267: list.add(new Attribute(names[a], value)); 268: } 269: catch (AttributeNotFoundException e) 270: { 271: /* Ignored */ 272: } 273: catch (ReflectionException e) 274: { 275: /* Ignored */ 276: } 277: catch (MBeanException e) 278: { 279: /* Ignored */ 280: } 281: } 282: return list; 283: } 284: 285: /** 286: * Returns the cached {@link MBeanInfo} instance for this object. This is a 287: * customization hook, so that subclasses can choose the caching policy 288: * used. The default implementation caches the value in the instance 289: * itself, and returns this value on calls to this method. 290: * 291: * @return the cached {@link MBeanInfo} instance, or <code>null</code> 292: * if no value is cached. 293: * @see #cacheMBeanInfo(javax.management.MBeanInfo) 294: */ 295: protected MBeanInfo getCachedMBeanInfo() 296: { 297: return info; 298: } 299: 300: /** 301: * Returns the class name that will be used in the {@link MBeanInfo} 302: * instance. This is a customization hook, so that subclasses can 303: * provide a custom class name. By default, this returns the class 304: * name from the supplied {@link MBeanInfo} instance. 305: * 306: * @param info the {@link MBeanInfo} instance constructed via 307: * reflection. 308: * @return the class name to use in the instance. 309: */ 310: protected String getClassName(MBeanInfo info) 311: { 312: return info.getClassName(); 313: } 314: 315: /** 316: * Returns information on the constructors that will be used in 317: * the {@link MBeanInfo} instance. This is a customization hook, 318: * so that subclasses can provide their own information on the 319: * bean's constructors, if necessary. By default, this method 320: * returns <code>null</code> unless the implementation supplied 321: * is either <code>null</code> or <code>this</code>. This default 322: * implementation prevents the use of 323: * {@link MBeanServer#createMBean} in cases where the bean is 324: * not created as a subclass of {@link StandardMBean}. 325: * 326: * @param constructors the constructor information created via 327: * reflection. 328: * @param impl the implementation, or <code>null</code> if this 329: * should be ignored. 330: * @return the constructor information to use. 331: */ 332: protected MBeanConstructorInfo[] getConstructors(MBeanConstructorInfo[] 333: constructors, Object impl) 334: { 335: if (impl == null || impl == this) 336: return constructors; 337: return null; 338: } 339: 340: /** 341: * Returns the description of the attribute that will be used in 342: * the supplied {@link MBeanAttributeInfo} instance. This is a 343: * customization hook, so that subclasses can provide a custom 344: * description. By default, this calls 345: * {@link #getDescription(MBeanFeatureInfo)} with the supplied 346: * {@link MBeanAttributeInfo} instance. 347: * 348: * @param info the {@link MBeanAttributeInfo} instance constructed 349: * via reflection. 350: * @return the description to use in the instance. 351: */ 352: protected String getDescription(MBeanAttributeInfo info) 353: { 354: return getDescription((MBeanFeatureInfo) info); 355: } 356: 357: /** 358: * Returns the description of the constructor that will be used in 359: * the supplied {@link MBeanConstructorInfo} instance. This is a 360: * customization hook, so that subclasses can provide a custom 361: * description. By default, this calls 362: * {@link #getDescription(MBeanFeatureInfo)} with the supplied 363: * {@link MBeanConstructorInfo} instance. 364: * 365: * @param info the {@link MBeanConstructorInfo} instance constructed 366: * via reflection. 367: * @return the description to use in the instance. 368: */ 369: protected String getDescription(MBeanConstructorInfo info) 370: { 371: return getDescription((MBeanFeatureInfo) info); 372: } 373: 374: /** 375: * Returns the description of the nth parameter of the constructor 376: * that will be used in the supplied {@link MBeanParameterInfo} 377: * instance. This is a customization hook, so that subclasses 378: * can provide a custom description. By default, this calls 379: * <code>param.getDescription()</code>. 380: * 381: * @param info the {@link MBeanConstructorInfo} instance constructed 382: * via reflection. 383: * @param param the {@link MBeanParameterInfo} instance constructed 384: * via reflection. 385: * @param n the number of the parameter, in order to link it to the 386: * information on the constructor. 387: * @return the description to use in the instance. 388: */ 389: protected String getDescription(MBeanConstructorInfo info, 390: MBeanParameterInfo param, int n) 391: { 392: return param.getDescription(); 393: } 394: 395: /** 396: * Returns the description of the supplied feature that 397: * will be used in the supplied {@link MBeanFeatureInfo} 398: * instance. This is a customization hook, so that subclasses 399: * can provide a custom description. By default, this calls 400: * <code>info.getDescription()</code>. This method is also called 401: * by default for the more specific description methods for attributes, 402: * constructors and operations. 403: * 404: * @param info the {@link MBeanFeatureInfo} instance constructed 405: * via reflection. 406: * @return the description to use in the instance. 407: */ 408: protected String getDescription(MBeanFeatureInfo info) 409: { 410: return info.getDescription(); 411: } 412: 413: /** 414: * Returns the description of the bean that will be used in the 415: * supplied {@link MBeanInfo} instance. This is a customization 416: * hook, so that subclasses can provide a custom description. By 417: * default, this calls <code>info.getDescription()</code>. 418: * 419: * @param info the {@link MBeanInfo} instance constructed 420: * via reflection. 421: * @return the description to use in the instance. 422: */ 423: protected String getDescription(MBeanInfo info) 424: { 425: return info.getDescription(); 426: } 427: 428: /** 429: * Returns the description of the operation that will be used in 430: * the supplied {@link MBeanOperationInfo} instance. This is a 431: * customization hook, so that subclasses can provide a custom 432: * description. By default, this calls 433: * {@link #getDescription(MBeanFeatureInfo)} with the supplied 434: * {@link MBeanOperationInfo} instance. 435: * 436: * @param info the {@link MBeanOperationInfo} instance constructed 437: * via reflection. 438: * @return the description to use in the instance. 439: */ 440: protected String getDescription(MBeanOperationInfo info) 441: { 442: return getDescription((MBeanFeatureInfo) info); 443: } 444: 445: /** 446: * Returns the description of the nth parameter of the operation 447: * that will be used in the supplied {@link MBeanParameterInfo} 448: * instance. This is a customization hook, so that subclasses 449: * can provide a custom description. By default, this calls 450: * <code>param.getDescription()</code>. 451: * 452: * @param info the {@link MBeanOperationInfo} instance constructed 453: * via reflection. 454: * @param param the {@link MBeanParameterInfo} instance constructed 455: * via reflection. 456: * @param n the number of the parameter, in order to link it to the 457: * information on the operation. 458: * @return the description to use in the instance. 459: */ 460: protected String getDescription(MBeanOperationInfo info, 461: MBeanParameterInfo param, int n) 462: { 463: return param.getDescription(); 464: } 465: 466: /** 467: * Returns the impact of the operation that will be used in the 468: * supplied {@link MBeanOperationInfo} instance. This is a 469: * customization hook, so that subclasses can provide a custom 470: * impact flag. By default, this returns 471: * <code>info.getImpact()</code>. 472: * 473: * @param info the {@link MBeanOperationInfo} instance constructed 474: * via reflection. 475: * @return the impact flag to use in the instance. 476: */ 477: protected int getImpact(MBeanOperationInfo info) 478: { 479: return info.getImpact(); 480: } 481: 482: /** 483: * Returns the instance that implements this bean. 484: * 485: * @return the implementation. 486: */ 487: public Object getImplementation() 488: { 489: return impl; 490: } 491: 492: /** 493: * Returns the class of the instance that implements this bean. 494: * 495: * @return the implementation class. 496: */ 497: public Class getImplementationClass() 498: { 499: return impl.getClass(); 500: } 501: 502: /** 503: * <p> 504: * Returns an information object which lists the attributes 505: * and actions associated with the management bean. This 506: * implementation proceeds as follows: 507: * </p> 508: * <ol> 509: * <li>{@link #getCachedMBeanInfo()} is called to obtain 510: * the cached instance. If this returns a non-null value, 511: * this value is returned.</li> 512: * <li>If there is no cached value, then the method proceeds 513: * to create one. During this process, the customization hooks 514: * detailed in this class are called to allow the values used 515: * to be overrided: 516: * <ul> 517: * <li>For each attribute, 518: * {@link #getDescription(MBeanAttributeInfo)} is called.</li> 519: * <li>For each constructor, 520: * {@link #getDescription(MBeanConstructorInfo)} is called, 521: * along with {@link #getDescription(MBeanConstructorInfo, 522: * MBeanParameterInfo, int)} and 523: * {@link #getParameterName(MBeanConstructorInfo, 524: * MBeanParameterInfo, int)} for each parameter.</li> 525: * <li>The constructors may be replaced as a whole by 526: * a call to 527: * {@link #getConstructors(MBeanConstructorInfo[], Object)}.</li> 528: * <li>For each operation, 529: * {@link #getDescription(MBeanOperationInfo)} and 530: * {@link #getImpact(MBeanOperationInfo)} are called, 531: * along with {@link #getDescription(MBeanOperationInfo, 532: * MBeanParameterInfo, int)} and 533: * {@link #getParameterName(MBeanOperationInfo, 534: * MBeanParameterInfo, int)} for each parameter.</li> 535: * <li>{@link #getClassName(MBeanInfo)} and 536: * {@link #getDescription(MBeanInfo)} are called to customise 537: * the basic information about the class.</li> 538: * </ul> 539: * </li> 540: * <li>Finally, {@link #cacheMBeanInfo(MBeanInfo)} is called 541: * with the created instance before it is returned.</li> 542: * </ol> 543: * 544: * @return a description of the management bean, including 545: * all exposed attributes and actions. 546: */ 547: public MBeanInfo getMBeanInfo() 548: { 549: MBeanInfo info = getCachedMBeanInfo(); 550: if (info != null) 551: return info; 552: Method[] methods = iface.getMethods(); 553: Map attributes = new HashMap(); 554: List operations = new ArrayList(); 555: for (int a = 0; a < methods.length; ++a) 556: { 557: String name = methods[a].getName(); 558: if (((name.startsWith("get") && 559: methods[a].getReturnType() != Void.TYPE) || 560: (name.startsWith("is") && 561: methods[a].getReturnType() == Boolean.TYPE)) && 562: methods[a].getParameterTypes().length == 0) 563: { 564: Method[] amethods; 565: String attrib; 566: if (name.startsWith("is")) 567: attrib = name.substring(2,3).toLowerCase() 568: + name.substring(3); 569: else 570: attrib = name.substring(3,4).toLowerCase() 571: + name.substring(4); 572: if (attributes.containsKey(attrib)) 573: amethods = (Method[]) attributes.get(attrib); 574: else 575: { 576: amethods = new Method[2]; 577: attributes.put(attrib, amethods); 578: } 579: amethods[0] = methods[a]; 580: } 581: else if (name.startsWith("set") && 582: methods[a].getReturnType() == Void.TYPE && 583: methods[a].getParameterTypes().length == 1) 584: { 585: Method[] amethods; 586: String attrib = name.substring(3,4).toLowerCase() 587: + name.substring(4); 588: if (attributes.containsKey(attrib)) 589: amethods = (Method[]) attributes.get(attrib); 590: else 591: { 592: amethods = new Method[2]; 593: attributes.put(attrib, amethods); 594: } 595: amethods[1] = methods[a]; 596: } 597: else 598: operations.add(new MBeanOperationInfo("", methods[a])); 599: } 600: List attribs = new ArrayList(attributes.size()); 601: Iterator it = attributes.entrySet().iterator(); 602: while (it.hasNext()) 603: { 604: Map.Entry entry = (Map.Entry) it.next(); 605: Method[] amethods = (Method[]) entry.getValue(); 606: try 607: { 608: attribs.add(new MBeanAttributeInfo((String) entry.getKey(), "", 609: amethods[0], amethods[1])); 610: } 611: catch (IntrospectionException e) 612: { 613: /* Shouldn't happen; both shouldn't be null */ 614: throw new IllegalStateException("The two methods passed to " + 615: "the MBeanAttributeInfo " + 616: "constructor for " + entry + 617: "were null.", e); 618: } 619: } 620: MBeanAttributeInfo[] ainfo = new MBeanAttributeInfo[attribs.size()]; 621: for (int a = 0; a < ainfo.length; ++a) 622: { 623: MBeanAttributeInfo oldInfo = (MBeanAttributeInfo) attribs.get(a); 624: String desc = getDescription(oldInfo); 625: ainfo[a] = new MBeanAttributeInfo(oldInfo.getName(), 626: oldInfo.getType(), desc, 627: oldInfo.isReadable(), 628: oldInfo.isWritable(), 629: oldInfo.isIs()); 630: } 631: Constructor[] cons = impl.getClass().getConstructors(); 632: MBeanConstructorInfo[] cinfo = new MBeanConstructorInfo[cons.length]; 633: for (int a = 0; a < cinfo.length; ++a) 634: { 635: MBeanConstructorInfo oldInfo = new MBeanConstructorInfo("", cons[a]); 636: String desc = getDescription(oldInfo); 637: MBeanParameterInfo[] params = oldInfo.getSignature(); 638: MBeanParameterInfo[] pinfo = new MBeanParameterInfo[params.length]; 639: for (int b = 0; b < pinfo.length; ++b) 640: { 641: String pdesc = getDescription(oldInfo, params[b], b); 642: String pname = getParameterName(oldInfo, params[b], b); 643: pinfo[b] = new MBeanParameterInfo(pname, params[b].getType(), 644: pdesc); 645: } 646: cinfo[a] = new MBeanConstructorInfo(oldInfo.getName(), desc, 647: pinfo); 648: } 649: cinfo = getConstructors(cinfo, impl); 650: MBeanOperationInfo[] oinfo = new MBeanOperationInfo[operations.size()]; 651: for (int a = 0; a < oinfo.length; ++a) 652: { 653: MBeanOperationInfo oldInfo = (MBeanOperationInfo) operations.get(a); 654: String desc = getDescription(oldInfo); 655: int impact = getImpact(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: oinfo[a] = new MBeanOperationInfo(oldInfo.getName(), desc, pinfo, 666: oldInfo.getReturnType(), impact); 667: } 668: info = new MBeanInfo(impl.getClass().getName(), "", ainfo, cinfo, 669: oinfo, null); 670: String cname = getClassName(info); 671: String desc = getDescription(info); 672: info = new MBeanInfo(cname, desc, ainfo, cinfo, oinfo, null); 673: cacheMBeanInfo(info); 674: return info; 675: } 676: 677: /** 678: * Returns the interface for this management bean. 679: * 680: * @return the management interface. 681: */ 682: public Class getMBeanInterface() 683: { 684: return iface; 685: } 686: 687: /** 688: * Returns the name of the nth parameter of the constructor 689: * that will be used in the supplied {@link MBeanParameterInfo} 690: * instance. This is a customization hook, so that subclasses 691: * can provide a custom name. By default, this calls 692: * <code>param.getName()</code>. 693: * 694: * @param info the {@link MBeanConstructorInfo} instance constructed 695: * via reflection. 696: * @param param the {@link MBeanParameterInfo} instance constructed 697: * via reflection. 698: * @param n the number of the parameter, in order to link it to the 699: * information on the constructor. 700: * @return the name to use in the instance. 701: */ 702: protected String getParameterName(MBeanConstructorInfo info, 703: MBeanParameterInfo param, int n) 704: { 705: return param.getName(); 706: } 707: 708: /** 709: * Returns the name of the nth parameter of the operation 710: * that will be used in the supplied {@link MBeanParameterInfo} 711: * instance. This is a customization hook, so that subclasses 712: * can provide a custom name. By default, this calls 713: * <code>param.getName()</code>. 714: * 715: * @param info the {@link MBeanOperationInfo} instance constructed 716: * via reflection. 717: * @param param the {@link MBeanParameterInfo} instance constructed 718: * via reflection. 719: * @param n the number of the parameter, in order to link it to the 720: * information on the operation. 721: * @return the name to use in the instance. 722: */ 723: protected String getParameterName(MBeanOperationInfo info, 724: MBeanParameterInfo param, int n) 725: { 726: return param.getName(); 727: } 728: 729: /** 730: * Invokes the specified action on the management bean using 731: * the supplied parameters. The signature of the action is 732: * specified by a {@link String} array, which lists the classes 733: * corresponding to each parameter. The class loader used to 734: * load these classes is the same as that used for loading the 735: * management bean itself. 736: * 737: * @param name the name of the action to invoke. 738: * @param params the parameters used to call the action. 739: * @param signature the signature of the action. 740: * @return the return value of the action. 741: * @throws MBeanException if the action throws an exception. The 742: * thrown exception is the cause of this 743: * exception. 744: * @throws ReflectionException if an exception occurred in trying 745: * to use the reflection interface 746: * to invoke the action. The 747: * thrown exception is the cause of 748: * this exception. 749: */ 750: public Object invoke(String name, Object[] params, String[] signature) 751: throws MBeanException, ReflectionException 752: { 753: Class[] sigTypes = new Class[signature.length]; 754: ClassLoader loader = getClass().getClassLoader(); 755: for (int a = 0; a < signature.length; ++a) 756: try 757: { 758: sigTypes[a] = Class.forName(signature[a], true, loader); 759: } 760: catch (ClassNotFoundException e) 761: { 762: throw new ReflectionException(e, "The class, " + signature[a] + 763: ", in the method signature " + 764: "could not be loaded."); 765: } 766: Method method; 767: try 768: { 769: method = iface.getMethod(name, sigTypes); 770: } 771: catch (NoSuchMethodException e) 772: { 773: throw new ReflectionException(e, "The method, " + name + 774: ", could not be found."); 775: } 776: Object result; 777: try 778: { 779: result = method.invoke(impl, params); 780: } 781: catch (IllegalAccessException e) 782: { 783: throw new ReflectionException(e, "Failed to call " + name); 784: } 785: catch (IllegalArgumentException e) 786: { 787: throw new ReflectionException(e, "Failed to call " + name); 788: } 789: catch (InvocationTargetException e) 790: { 791: throw new MBeanException((Exception) e.getCause(), "The method " 792: + name + " threw an exception"); 793: } 794: return result; 795: } 796: 797: /** 798: * Sets the value of the specified attribute of the 799: * management bean. The management bean should perform 800: * a lookup for the named attribute, and sets its value 801: * using the associated setter method, if possible. 802: * 803: * @param attribute the attribute to set. 804: * @throws AttributeNotFoundException if the attribute does not 805: * correspond to an attribute 806: * of the bean. 807: * @throws InvalidAttributeValueException if the value is invalid 808: * for this particular 809: * attribute of the bean. 810: * @throws MBeanException if setting the attribute causes 811: * the bean to throw an exception (which 812: * becomes the cause of this exception). 813: * @throws ReflectionException if an exception occurred in trying 814: * to use the reflection interface 815: * to lookup the attribute. The 816: * thrown exception is the cause of 817: * this exception. 818: * @see #getAttribute(String) 819: */ 820: public void setAttribute(Attribute attribute) 821: throws AttributeNotFoundException, InvalidAttributeValueException, 822: MBeanException, ReflectionException 823: { 824: Method setter; 825: String name = attribute.getName(); 826: try 827: { 828: setter = iface.getMethod("set" + 829: name.substring(0, 1).toUpperCase() + 830: name.substring(1), null); 831: } 832: catch (NoSuchMethodException e) 833: { 834: throw ((AttributeNotFoundException) 835: new AttributeNotFoundException("The attribute, " + name + 836: ", was not found.").initCause(e)); 837: } 838: try 839: { 840: setter.invoke(impl, new Object[] { attribute.getValue() }); 841: } 842: catch (IllegalAccessException e) 843: { 844: throw new ReflectionException(e, "Failed to set " + name); 845: } 846: catch (IllegalArgumentException e) 847: { 848: throw ((InvalidAttributeValueException) 849: new InvalidAttributeValueException(attribute.getValue() + 850: " is an invalid value for " + 851: name).initCause(e)); 852: } 853: catch (InvocationTargetException e) 854: { 855: throw new MBeanException((Exception) e.getCause(), "The getter of " 856: + name + " threw an exception"); 857: } 858: } 859: 860: /** 861: * Sets the value of each of the specified attributes 862: * to that supplied by the {@link Attribute} object. 863: * The returned list contains the attributes that were 864: * set and their new values. 865: * 866: * @param attributes the attributes to set. 867: * @return a list of the changed attributes. 868: * @see #getAttributes(AttributeList) 869: */ 870: public AttributeList setAttributes(AttributeList attributes) 871: { 872: AttributeList list = new AttributeList(attributes.size()); 873: Iterator it = attributes.iterator(); 874: while (it.hasNext()) 875: { 876: try 877: { 878: Attribute attrib = (Attribute) it.next(); 879: setAttribute(attrib); 880: list.add(attrib); 881: } 882: catch (AttributeNotFoundException e) 883: { 884: /* Ignored */ 885: } 886: catch (InvalidAttributeValueException e) 887: { 888: /* Ignored */ 889: } 890: catch (ReflectionException e) 891: { 892: /* Ignored */ 893: } 894: catch (MBeanException e) 895: { 896: /* Ignored */ 897: } 898: } 899: return list; 900: } 901: 902: /** 903: * Replaces the implementation of the interface used by this 904: * instance with the one specified. The new implementation 905: * must be non-null and implement the interface specified on 906: * construction of this instance. 907: * 908: * @throws IllegalArgumentException if <code>impl</code> is <code>null</code>. 909: * @throws NotCompliantMBeanException if <code>impl</code> doesn't implement 910: * the interface or a method appears 911: * in the interface that doesn't comply 912: * with the naming conventions. 913: */ 914: public void setImplementation(Object impl) 915: throws NotCompliantMBeanException 916: { 917: if (impl == null) 918: throw new IllegalArgumentException("The specified implementation is null."); 919: if (!(iface.isInstance(impl))) 920: throw new NotCompliantMBeanException("The instance, " + impl + 921: ", is not an instance of " + iface); 922: this.impl = impl; 923: } 924: 925: }