Source for java.lang.management.ManagementFactory

   1: /* ManagementFactory.java - Factory for obtaining system beans.
   2:    Copyright (C) 2006 Free Software Foundation
   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 java.lang.management;
  39: 
  40: import gnu.classpath.SystemProperties;
  41: 
  42: import gnu.java.lang.management.ClassLoadingMXBeanImpl;
  43: import gnu.java.lang.management.CompilationMXBeanImpl;
  44: import gnu.java.lang.management.GarbageCollectorMXBeanImpl;
  45: import gnu.java.lang.management.OperatingSystemMXBeanImpl;
  46: import gnu.java.lang.management.MemoryMXBeanImpl;
  47: import gnu.java.lang.management.MemoryManagerMXBeanImpl;
  48: import gnu.java.lang.management.MemoryPoolMXBeanImpl;
  49: import gnu.java.lang.management.RuntimeMXBeanImpl;
  50: import gnu.java.lang.management.ThreadMXBeanImpl;
  51: 
  52: import java.io.IOException;
  53: 
  54: import java.lang.reflect.InvocationHandler;
  55: import java.lang.reflect.Method;
  56: import java.lang.reflect.Proxy;
  57: 
  58: import java.util.ArrayList;
  59: import java.util.HashMap;
  60: import java.util.Iterator;
  61: import java.util.List;
  62: import java.util.Map;
  63: 
  64: import java.util.logging.LogManager;
  65: 
  66: import javax.management.Attribute;
  67: import javax.management.InstanceAlreadyExistsException;
  68: import javax.management.MBeanRegistrationException;
  69: import javax.management.MBeanServer;
  70: import javax.management.MBeanServerConnection;
  71: import javax.management.MBeanServerFactory;
  72: import javax.management.MalformedObjectNameException;
  73: import javax.management.NotCompliantMBeanException;
  74: import javax.management.NotificationEmitter;
  75: import javax.management.NotificationFilter;
  76: import javax.management.NotificationListener;
  77: import javax.management.ObjectName;
  78: 
  79: import javax.management.openmbean.CompositeData;
  80: import javax.management.openmbean.TabularData;
  81: 
  82: /**
  83:  * <p>
  84:  * Provides access to the system's management beans via a series
  85:  * of static methods.
  86:  * </p>
  87:  * <p>
  88:  * An instance of a system management bean can be obtained by
  89:  * using one of the following methods:
  90:  * </p>
  91:  * <ol>
  92:  * <li>Calling the appropriate static method of this factory.
  93:  * </li>
  94:  * <li>Using the platform {@link javax.management.MBeanServer}
  95:  * to access the beans locally, or an
  96:  * {@link javax.management.MBeanServerConnection} for remote
  97:  * access.  The attributes and operations use the limited
  98:  * range of data types specified below.</li>
  99:  * </ol>
 100:  * <h2>Open Data Types</h2>
 101:  * <p>
 102:  * The data types used by the management beans are restricted
 103:  * to <emph>open</emph> data types to aid interoperability.  This
 104:  * allows the beans to be accessed remotely, including from non-Java
 105:  * clients.  Below is a table which lists the types used by the beans
 106:  * on the left, and the types they are converted to when returned via
 107:  * a bean server on the right.  Type information is provided for each
 108:  * bean by obtaining its instance of {@link javax.management.MBeanInfo}.
 109:  * </p>
 110:  * <table>
 111:  * <th><td>Data Type Used</td><td>Data Type Returned</td></th>
 112:  * <tr>
 113:  * <td>Primitive types (<code>int</code>, <code>char</code>, etc.)</td>
 114:  * <td>Same</td>
 115:  * </tr><tr>
 116:  * <td>Wrapper classes ({@link{java.lang.Integer},
 117:  * @link{java.lang.Character}, etc.)</td>
 118:  * <td>Same</td>
 119:  * </tr><tr>
 120:  * <td>An {@link java.lang.Enum}</td>
 121:  * <td>The <code>name</code> of the enumeration constant</td>
 122:  * </tr><tr>
 123:  * <td>An array of type <code>E</code></td>
 124:  * <td>An array of the same dimensions with this mapping applied
 125:  * to <code>E</code>.</td>
 126:  * </tr><tr>
 127:  * <td>A class with `getter' methods and a
 128:  * <code>from({@link javax.management.openmbean.CompositeData})</code>
 129:  * method.</td>
 130:  * <td>The equivalent {@link javax.management.openmbean.CompositeData}
 131:  * instance, specified by the <code>from</code> method.</td>
 132:  * </tr><tr>
 133:  * <td>A map with keys of type <code>K</code> and values of
 134:  * type <code>V</code>.</td>
 135:  * <td>A {@link javax.management.openmbean.TabularData} instance,
 136:  * with the row type containing two items, <code>"key"</code> and
 137:  * <code>"value"</code> with the types <code>K</code> and <code>V</code>
 138:  * respectively (with translation applied).</td>
 139:  * </tr><tr>
 140:  * <td>A list of type <code>E</code>.</td>
 141:  * <td>An array with this mapping applied to <code>E</code>.</td>
 142:  * </tr></table>
 143:  *
 144:  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 145:  * @since 1.5
 146:  */
 147: public class ManagementFactory
 148: {
 149: 
 150:   /**
 151:    * The object name for the class loading bean.
 152:    */
 153:   public static final String CLASS_LOADING_MXBEAN_NAME =
 154:     "java.lang:type=ClassLoading";
 155: 
 156:   /**
 157:    * The object name for the compilation bean.
 158:    */
 159:   public static final String COMPILATION_MXBEAN_NAME =
 160:     "java.lang:type=Compilation";
 161: 
 162:   /**
 163:    * The domain for the garbage collecting beans.
 164:    */
 165:   public static final String GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE =
 166:     "java.lang:type=GarbageCollector";
 167: 
 168:   /**
 169:    * The domain for the memory manager beans.
 170:    */
 171:   public static final String MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE =
 172:     "java.lang:type=MemoryManager";
 173: 
 174:   /**
 175:    * The object name for the memory bean.
 176:    */
 177:   public static final String MEMORY_MXBEAN_NAME =
 178:     "java.lang:type=Memory";
 179: 
 180:   /**
 181:    * The domain for the memory pool beans.
 182:    */
 183:   public static final String MEMORY_POOL_MXBEAN_DOMAIN_TYPE =
 184:     "java.lang:type=MemoryPool";
 185: 
 186:   /**
 187:    * The object name for the operating system bean.
 188:    */
 189:   public static final String OPERATING_SYSTEM_MXBEAN_NAME =
 190:     "java.lang:type=OperatingSystem";
 191: 
 192:   /**
 193:    * The object name for the runtime bean.
 194:    */
 195:   public static final String RUNTIME_MXBEAN_NAME =
 196:     "java.lang:type=Runtime";
 197: 
 198:   /**
 199:    * The object name for the threading bean.
 200:    */
 201:   public static final String THREAD_MXBEAN_NAME =
 202:     "java.lang:type=Threading";
 203: 
 204:   /**
 205:    * The operating system management bean.
 206:    */
 207:   private static OperatingSystemMXBean osBean;
 208: 
 209:   /**
 210:    * The runtime management bean.
 211:    */
 212:   private static RuntimeMXBean runtimeBean;
 213: 
 214:   /**
 215:    * The class loading management bean.
 216:    */
 217:   private static ClassLoadingMXBean classLoadingBean;
 218: 
 219:   /**
 220:    * The thread bean.
 221:    */
 222:   private static ThreadMXBean threadBean;
 223: 
 224:   /**
 225:    * The memory bean.
 226:    */
 227:   private static MemoryMXBean memoryBean;
 228: 
 229:   /**
 230:    * The compilation bean (may remain null).
 231:    */
 232:   private static CompilationMXBean compilationBean;
 233: 
 234:   /**
 235:    * The platform server.
 236:    */
 237:   private static MBeanServer platformServer;
 238: 
 239:   /**
 240:    * Private constructor to prevent instance creation.
 241:    */
 242:   private ManagementFactory() {}
 243: 
 244:   /**
 245:    * Returns the operating system management bean for the
 246:    * operating system on which the virtual machine is running.
 247:    *
 248:    * @return an instance of {@link OperatingSystemMXBean} for
 249:    *         the underlying operating system.
 250:    */
 251:   public static OperatingSystemMXBean getOperatingSystemMXBean()
 252:   {
 253:     if (osBean == null)
 254:       try
 255:         {
 256:           osBean = new OperatingSystemMXBeanImpl();
 257:         }
 258:       catch (NotCompliantMBeanException e)
 259:         {
 260:           throw new InternalError("The GNU implementation of the " +
 261:                                   "operating system bean is not a " +
 262:                                   "compliant management bean.");
 263:         }
 264:     return osBean;
 265:   }
 266: 
 267:   /**
 268:    * Returns the runtime management bean for the
 269:    * running virtual machine.
 270:    *
 271:    * @return an instance of {@link RuntimeMXBean} for
 272:    *         this virtual machine.
 273:    */
 274:   public static RuntimeMXBean getRuntimeMXBean()
 275:   {
 276:     if (runtimeBean == null)
 277:       try
 278:         {
 279:           runtimeBean = new RuntimeMXBeanImpl();
 280:         }
 281:       catch (NotCompliantMBeanException e)
 282:         {
 283:           throw new InternalError("The GNU implementation of the " +
 284:                                   "runtime bean is not a compliant " +
 285:                                   "management bean.");
 286:         }
 287:     return runtimeBean;
 288:   }
 289: 
 290:   /**
 291:    * Returns the class loading management bean for the
 292:    * running virtual machine.
 293:    *
 294:    * @return an instance of {@link ClassLoadingMXBean} for
 295:    *         this virtual machine.
 296:    */
 297:   public static ClassLoadingMXBean getClassLoadingMXBean()
 298:   {
 299:     if (classLoadingBean == null)
 300:       try
 301:         {
 302:           classLoadingBean = new ClassLoadingMXBeanImpl();
 303:         }
 304:       catch (NotCompliantMBeanException e)
 305:         {
 306:           throw new InternalError("The GNU implementation of the " +
 307:                                   "class loading bean is not a " +
 308:                                   "compliant management bean.");
 309:         }
 310:     return classLoadingBean;
 311:   }
 312: 
 313:   /**
 314:    * Returns the thread management bean for the running
 315:    * virtual machine.
 316:    *
 317:    * @return an instance of {@link ThreadMXBean} for
 318:    *         this virtual machine.
 319:    */
 320:   public static ThreadMXBean getThreadMXBean()
 321:   {
 322:     if (threadBean == null)
 323:       try
 324:         {
 325:           threadBean = new ThreadMXBeanImpl();
 326:         }
 327:       catch (NotCompliantMBeanException e)
 328:         {
 329:           throw new InternalError("The GNU implementation of the " +
 330:                                   "thread bean is not a compliant " +
 331:                                   "management bean.");
 332:         }
 333:     return threadBean;
 334:   }
 335: 
 336:   /**
 337:    * Returns the memory management bean for the running
 338:    * virtual machine.
 339:    *
 340:    * @return an instance of {@link MemoryMXBean} for
 341:    *         this virtual machine.
 342:    */
 343:   public static MemoryMXBean getMemoryMXBean()
 344:   {
 345:     if (memoryBean == null)
 346:       try
 347:         {
 348:           memoryBean = new MemoryMXBeanImpl();
 349:         }
 350:       catch (NotCompliantMBeanException e)
 351:         {
 352:           throw new InternalError("The GNU implementation of the " +
 353:                                   "memory bean is not a compliant " +
 354:                                   "management bean.");
 355:         }
 356:     return memoryBean;
 357:   }
 358: 
 359:   /**
 360:    * Returns the compilation bean for the running
 361:    * virtual machine, if supported.  Otherwise,
 362:    * it returns <code>null</code>.
 363:    *
 364:    * @return an instance of {@link CompilationMXBean} for
 365:    *         this virtual machine, or <code>null</code>
 366:    *         if the virtual machine doesn't include
 367:    *         a Just-In-Time (JIT) compiler.
 368:    */
 369:   public static CompilationMXBean getCompilationMXBean()
 370:   {
 371:     if (compilationBean == null &&
 372:         SystemProperties.getProperty("gnu.java.compiler.name") != null)
 373:       try
 374:         {
 375:           compilationBean = new CompilationMXBeanImpl();
 376:         }
 377:       catch (NotCompliantMBeanException e)
 378:         {
 379:           throw new InternalError("The GNU implementation of the " +
 380:                                   "compilation bean is not a compliant " +
 381:                                   "management bean.");
 382:         }
 383:     return compilationBean;
 384:   }
 385: 
 386:   /**
 387:    * Returns the memory pool beans for the running
 388:    * virtual machine.  These may change during the course
 389:    * of execution.
 390:    *
 391:    * @return a list of memory pool beans, one for each pool.
 392:    */
 393:   public static List<MemoryPoolMXBean> getMemoryPoolMXBeans()
 394:   {
 395:     List<MemoryPoolMXBean> poolBeans =
 396:       new ArrayList<MemoryPoolMXBean>();
 397:     String[] names = VMManagementFactory.getMemoryPoolNames();
 398:     for (int a = 0; a < names.length; ++a)
 399:       try
 400:         {
 401:           poolBeans.add(new MemoryPoolMXBeanImpl(names[a]));
 402:         }
 403:       catch (NotCompliantMBeanException e)
 404:         {
 405:           throw new InternalError("The GNU implementation of the " +
 406:                                   "memory pool bean, " + a + ", is " +
 407:                                   "not a compliant management bean.");
 408:         }
 409:     return poolBeans;
 410:   }
 411: 
 412:   /**
 413:    * Returns the memory manager beans for the running
 414:    * virtual machine.  These may change during the course
 415:    * of execution.
 416:    *
 417:    * @return a list of memory manager beans, one for each manager.
 418:    */
 419:   public static List<MemoryManagerMXBean> getMemoryManagerMXBeans()
 420:   {
 421:     List<MemoryManagerMXBean> managerBeans =
 422:       new ArrayList<MemoryManagerMXBean>();
 423:     String[] names = VMManagementFactory.getMemoryManagerNames();
 424:     for (int a = 0; a < names.length; ++a)
 425:       try
 426:         {
 427:           managerBeans.add(new MemoryManagerMXBeanImpl(names[a]));
 428:         }
 429:       catch (NotCompliantMBeanException e)
 430:         {
 431:           throw new InternalError("The GNU implementation of the " +
 432:                                   "memory manager bean, " + a + ", is " +
 433:                                   "not a compliant management bean.");
 434:         }
 435:     managerBeans.addAll(getGarbageCollectorMXBeans());
 436:     return managerBeans;
 437:   }
 438: 
 439:   /**
 440:    * Returns the garbage collector beans for the running
 441:    * virtual machine.  These may change during the course
 442:    * of execution.
 443:    *
 444:    * @return a list of garbage collector beans, one for each pool.
 445:    */
 446:   public static List<GarbageCollectorMXBean> getGarbageCollectorMXBeans()
 447:   {
 448:     List<GarbageCollectorMXBean> gcBeans =
 449:       new ArrayList<GarbageCollectorMXBean>();
 450:     String[] names = VMManagementFactory.getGarbageCollectorNames();
 451:     for (int a = 0; a < names.length; ++a)
 452:       try
 453:         {
 454:           gcBeans.add(new GarbageCollectorMXBeanImpl(names[a]));
 455:         }
 456:       catch (NotCompliantMBeanException e)
 457:         {
 458:           throw new InternalError("The GNU implementation of the " +
 459:                                   "garbage collector bean, " + a +
 460:                                   ", is not a compliant management " +
 461:                                   "bean.");
 462:         }
 463:     return gcBeans;
 464:   }
 465: 
 466:   /**
 467:    * <p>
 468:    * Returns the platform {@link javax.management.MBeanServer}.  On the
 469:    * first call to this method, a server instance is retrieved from
 470:    * the {@link javax.management.MBeanServerFactory} and each of the
 471:    * beans are registered with it.  Subsequent calls return the existing
 472:    * instance.  If the property <code>javax.management.builder.initial</code>
 473:    * is set, its value will be used as the name of the class which is used
 474:    * to provide the server instance.
 475:    * </p>
 476:    * <p>
 477:    * It is recommended that the platform server is used for other beans as
 478:    * well, in order to simplify their discovery and publication.  Name conflicts
 479:    * should be avoided.
 480:    * </p>
 481:    *
 482:    * @return the platform {@link javax.management.MBeanServer}
 483:    * @throws SecurityException if a security manager exists and the
 484:    *                           caller's permissions don't imply {@link
 485:    *                           MBeanServerPermission(String)}("createMBeanServer")
 486:    * @see javax.management.MBeanServerFactory
 487:    * @see javax.management.MBeanServerFactory#createMBeanServer()
 488:    */
 489:   public static MBeanServer getPlatformMBeanServer()
 490:   {
 491:     if (platformServer == null)
 492:       {
 493:         platformServer = MBeanServerFactory.createMBeanServer();
 494:         try
 495:           {
 496:             platformServer.registerMBean(getOperatingSystemMXBean(),
 497:                                          new ObjectName(OPERATING_SYSTEM_MXBEAN_NAME));
 498:             platformServer.registerMBean(getRuntimeMXBean(),
 499:                                          new ObjectName(RUNTIME_MXBEAN_NAME));
 500:             platformServer.registerMBean(getClassLoadingMXBean(),
 501:                                          new ObjectName(CLASS_LOADING_MXBEAN_NAME));
 502:             platformServer.registerMBean(getThreadMXBean(),
 503:                                          new ObjectName(THREAD_MXBEAN_NAME));
 504:             platformServer.registerMBean(getMemoryMXBean(),
 505:                                          new ObjectName(MEMORY_MXBEAN_NAME));
 506:             CompilationMXBean compBean = getCompilationMXBean();
 507:             if (compBean != null)
 508:               platformServer.registerMBean(compBean,
 509:                                            new ObjectName(COMPILATION_MXBEAN_NAME));
 510:             Iterator beans = getMemoryPoolMXBeans().iterator();
 511:             while (beans.hasNext())
 512:               {
 513:                 MemoryPoolMXBean bean = (MemoryPoolMXBean) beans.next();
 514:                 platformServer.registerMBean(bean,
 515:                                              new ObjectName(MEMORY_POOL_MXBEAN_DOMAIN_TYPE +
 516:                                                             ",name=" +
 517:                                                             bean.getName()));
 518:               }
 519:             beans = getMemoryManagerMXBeans().iterator();
 520:             while (beans.hasNext())
 521:               {
 522:                 MemoryManagerMXBean bean = (MemoryManagerMXBean) beans.next();
 523:                 platformServer.registerMBean(bean,
 524:                                              new ObjectName(MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE +
 525:                                                             ",name=" +
 526:                                                             bean.getName()));
 527:               }
 528:             beans = getGarbageCollectorMXBeans().iterator();
 529:             while (beans.hasNext())
 530:               {
 531:                 GarbageCollectorMXBean bean = (GarbageCollectorMXBean) beans.next();
 532:                 platformServer.registerMBean(bean,
 533:                                              new ObjectName(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE +
 534:                                                             ",name=" +
 535:                                                             bean.getName()));
 536:               }
 537:             platformServer.registerMBean(LogManager.getLoggingMXBean(),
 538:                                          new ObjectName(LogManager.LOGGING_MXBEAN_NAME));
 539:           }
 540:         catch (InstanceAlreadyExistsException e)
 541:           {
 542:             throw (Error)
 543:               (new InternalError("One of the management beans is " +
 544:                                  "already registered.").initCause(e));
 545:           }
 546:         catch (MBeanRegistrationException e)
 547:           {
 548:             throw (Error)
 549:               (new InternalError("One of the management beans' preRegister " +
 550:                                  "methods threw an exception.").initCause(e));
 551:           }
 552:         catch (NotCompliantMBeanException e)
 553:           {
 554:             throw (Error)
 555:               (new InternalError("One of the management beans is " +
 556:                                  "not compliant.").initCause(e));
 557:           }
 558:         catch (MalformedObjectNameException e)
 559:           {
 560:             throw (Error)
 561:               (new InternalError("The object name of a management bean is " +
 562:                                  "not compliant.").initCause(e));
 563:           }
 564:       }
 565:     return platformServer;
 566:   }
 567: 
 568:   /**
 569:    * <p>
 570:    * Returns a proxy for the specified platform bean.  A proxy object is created
 571:    * using <code>Proxy.newProxyInstance(mxbeanInterface.getClassLoader(),
 572:    * new Class[] { mxbeanInterface }, handler)</code>.  The
 573:    * {@link javax.management.NotificationEmitter} class is also added to the
 574:    * array if the bean provides notifications.  <code>handler</code> refers
 575:    * to the invocation handler which forwards calls to the connection, and
 576:    * also provides translation between the Java data types used in the
 577:    * bean interfaces and the open data types, as specified in the description
 578:    * of this class.  It is this translation that makes the
 579:    * usual {@link javax.management.MBeanServerInvocationHandler} inappropriate
 580:    * for providing such a proxy.
 581:    * </p>
 582:    * <p>
 583:    * <strong>Note</strong>: use of the proxy may result in
 584:    * {@link java.io.IOException}s from the underlying {@link MBeanServerConnection}
 585:    * and a {@link java.io.InvalidObjectException} if enum constants
 586:    * used on the client and the server don't match.
 587:    * </p>
 588:    *
 589:    * @param connection the server connection to use to access the bean.
 590:    * @param mxbeanName the {@link javax.management.ObjectName} of the
 591:    *                   bean to provide a proxy for.
 592:    * @param mxbeanInterface the interface for the bean being proxied.
 593:    * @return a proxy for the specified bean.
 594:    * @throws IllegalArgumentException if <code>mxbeanName</code> is not a valid
 595:    *                                  {@link javax.management.ObjectName},
 596:    *                                  the interface and name do not match the
 597:    *                                  same bean, the name does not refer to a
 598:    *                                  platform bean or the bean is not registered
 599:    *                                  with the server accessed by <code>connection</code>.
 600:    * @throws IOException if the connection throws one.
 601:    */
 602:   public static <T> T newPlatformMXBeanProxy(MBeanServerConnection connection,
 603:                                              String mxbeanName,
 604:                                              Class<T> mxbeanInterface)
 605:     throws IOException
 606:   {
 607:     if (!(mxbeanName.equals(CLASS_LOADING_MXBEAN_NAME) ||
 608:           mxbeanName.equals(COMPILATION_MXBEAN_NAME) ||
 609:           mxbeanName.startsWith(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE) ||
 610:           mxbeanName.startsWith(MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE) ||
 611:           mxbeanName.equals(MEMORY_MXBEAN_NAME) ||
 612:           mxbeanName.startsWith(MEMORY_POOL_MXBEAN_DOMAIN_TYPE) ||
 613:           mxbeanName.equals(OPERATING_SYSTEM_MXBEAN_NAME) ||
 614:           mxbeanName.equals(RUNTIME_MXBEAN_NAME) ||
 615:           mxbeanName.equals(THREAD_MXBEAN_NAME)))
 616:       {
 617:         throw new IllegalArgumentException("The named bean, " + mxbeanName +
 618:                                            ", is not a platform name.");
 619:       }
 620:     if ((mxbeanName.equals(CLASS_LOADING_MXBEAN_NAME) &&
 621:          mxbeanInterface != ClassLoadingMXBean.class) ||
 622:         (mxbeanName.equals(COMPILATION_MXBEAN_NAME) &&
 623:          mxbeanInterface != CompilationMXBean.class) ||
 624:         (mxbeanName.startsWith(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE) &&
 625:          mxbeanInterface != GarbageCollectorMXBean.class) ||
 626:         (mxbeanName.startsWith(MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE) &&
 627:          mxbeanInterface != MemoryManagerMXBean.class) ||
 628:         (mxbeanName.equals(MEMORY_MXBEAN_NAME) &&
 629:          mxbeanInterface != MemoryMXBean.class) ||
 630:         (mxbeanName.startsWith(MEMORY_POOL_MXBEAN_DOMAIN_TYPE) &&
 631:          mxbeanInterface != MemoryPoolMXBean.class) ||
 632:         (mxbeanName.equals(OPERATING_SYSTEM_MXBEAN_NAME) &&
 633:          mxbeanInterface != OperatingSystemMXBean.class) ||
 634:         (mxbeanName.equals(RUNTIME_MXBEAN_NAME) &&
 635:          mxbeanInterface != RuntimeMXBean.class) ||
 636:         (mxbeanName.equals(THREAD_MXBEAN_NAME) &&
 637:          mxbeanInterface != ThreadMXBean.class))
 638:       throw new IllegalArgumentException("The interface, " + mxbeanInterface +
 639:                                          ", does not match the bean, " + mxbeanName);
 640:     ObjectName bean;
 641:     try
 642:       {
 643:         bean = new ObjectName(mxbeanName);
 644:       }
 645:     catch (MalformedObjectNameException e)
 646:       {
 647:         throw new IllegalArgumentException("The named bean is invalid.");
 648:       }
 649:     if (!(connection.isRegistered(bean)))
 650:       throw new IllegalArgumentException("The bean is not registered on this connection.");
 651:     Class[] interfaces;
 652:     if (mxbeanName.equals(MEMORY_MXBEAN_NAME))
 653:       interfaces = new Class[] { mxbeanInterface, NotificationEmitter.class };
 654:     else
 655:       interfaces = new Class[] { mxbeanInterface };
 656:     return (T) Proxy.newProxyInstance(mxbeanInterface.getClassLoader(),
 657:                                       interfaces,
 658:                                       new ManagementInvocationHandler(connection, bean));
 659:   }
 660: 
 661:   /**
 662:    * This invocation handler provides method calls for a platform bean
 663:    * by forwarding them to a {@link MBeanServerConnection}.  Translation from
 664:    * Java data types to open data types is performed as specified above.
 665:    *
 666:    * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 667:    * @since 1.5
 668:    */
 669:   private static class ManagementInvocationHandler
 670:     implements InvocationHandler
 671:   {
 672: 
 673:     /**
 674:      * The encapsulated connection.
 675:      */
 676:     private MBeanServerConnection conn;
 677: 
 678:     /**
 679:      * The bean being proxied.
 680:      */
 681:     private ObjectName bean;
 682: 
 683:     /**
 684:      * Constructs a new {@link InvocationHandler} which proxies
 685:      * for the specified bean using the supplied connection.
 686:      *
 687:      * @param conn the connection on which to forward method calls.
 688:      * @param bean the bean to proxy.
 689:      */
 690:     public ManagementInvocationHandler(MBeanServerConnection conn,
 691:                                        ObjectName bean)
 692:       throws IOException
 693:     {
 694:       this.conn = conn;
 695:       this.bean = bean;
 696:     }
 697: 
 698:     /**
 699:      * Called by the proxy class whenever a method is called.  The method
 700:      * is emulated by retrieving an attribute from, setting an attribute on
 701:      * or invoking a method on the server connection as required.  Translation
 702:      * between the Java data types supplied as arguments to the open types used
 703:      * by the bean is provided, as well as translation of the return value back
 704:      * in to the appropriate Java type.
 705:      *
 706:      * @param proxy the proxy on which the method was called.
 707:      * @param method the method which was called.
 708:      * @param args the arguments supplied to the method.
 709:      * @return the return value from the method.
 710:      * @throws Throwable if an exception is thrown in performing the
 711:      *                   method emulation.
 712:      */
 713:     public Object invoke(Object proxy, Method method, Object[] args)
 714:       throws Throwable
 715:     {
 716:       String name = method.getName();
 717:       if (name.equals("toString"))
 718:         return "Proxy for " + bean + " using " + conn;
 719:       if (name.equals("addNotificationListener"))
 720:         {
 721:           conn.addNotificationListener(bean,
 722:                                        (NotificationListener) args[0],
 723:                                        (NotificationFilter) args[1],
 724:                                        args[2]);
 725:           return null;
 726:         }
 727:       if (name.equals("getNotificationInfo"))
 728:         return conn.getMBeanInfo(bean).getNotifications();
 729:       if (name.equals("removeNotificationListener"))
 730:         {
 731:           if (args.length == 1)
 732:             conn.removeNotificationListener(bean,
 733:                                             (NotificationListener)
 734:                                             args[0]);
 735:           else
 736:             conn.removeNotificationListener(bean,
 737:                                             (NotificationListener)
 738:                                             args[0],
 739:                                             (NotificationFilter)
 740:                                             args[1], args[2]);
 741:           return null;
 742:         }
 743:       String attrib = null;
 744:       if (name.startsWith("get"))
 745:         attrib = name.substring(3);
 746:       else if (name.startsWith("is"))
 747:         attrib = name.substring(2);
 748:       if (attrib != null)
 749:         return translate(conn.getAttribute(bean, attrib), method);
 750:       else if (name.startsWith("set"))
 751:         {
 752:           conn.setAttribute(bean, new Attribute(name.substring(3),
 753:                                                 args[0]));
 754:           return null;
 755:         }
 756:       else
 757:         return translate(conn.invoke(bean, name, args, null), method);
 758:     }
 759: 
 760:     /**
 761:      * Translates the returned open data type to the value
 762:      * required by the interface.
 763:      *
 764:      * @param otype the open type returned by the method call.
 765:      * @param method the method that was called.
 766:      * @return the equivalent return type required by the interface.
 767:      * @throws Throwable if an exception is thrown in performing the
 768:      *                   conversion.
 769:      */
 770:     private final Object translate(Object otype, Method method)
 771:       throws Throwable
 772:     {
 773:       Class<?> returnType = method.getReturnType();
 774:       if (returnType.isEnum())
 775:         {
 776:           String ename = (String) otype;
 777:           Enum[] constants = (Enum[]) returnType.getEnumConstants();
 778:           for (Enum c : constants)
 779:             if (c.name().equals(ename))
 780:               return c;
 781:         }
 782:       if (List.class.isAssignableFrom(returnType))
 783:         {
 784:           Object[] elems = (Object[]) otype;
 785:           List l = new ArrayList(elems.length);
 786:           for (Object elem : elems)
 787:             l.add(elem);
 788:           return l;
 789:         }
 790:       if (Map.class.isAssignableFrom(returnType))
 791:         {
 792:           TabularData data = (TabularData) otype;
 793:           Map m = new HashMap(data.size());
 794:           for (Object val : data.values())
 795:             {
 796:               CompositeData vals = (CompositeData) val;
 797:               m.put(vals.get("key"), vals.get("value"));
 798:             }
 799:           return m;
 800:         }
 801:       try
 802:         {
 803:           Method m = returnType.getMethod("from",
 804:                                           new Class[]
 805:             { CompositeData.class });
 806:           return m.invoke(null, (CompositeData) otype);
 807:         }
 808:       catch (NoSuchMethodException e)
 809:         {
 810:           /* Ignored; we expect this if this
 811:              isn't a from(CompositeData) class */
 812:         }
 813:       return otype;
 814:     }
 815: 
 816:   }
 817: }