Source for javax.management.StandardMBean

   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: }