001 /* ManagementFactory.java - Factory for obtaining system beans. 002 Copyright (C) 2006 Free Software Foundation 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 package java.lang.management; 039 040 import gnu.classpath.SystemProperties; 041 042 import gnu.java.lang.management.ClassLoadingMXBeanImpl; 043 import gnu.java.lang.management.CompilationMXBeanImpl; 044 import gnu.java.lang.management.GarbageCollectorMXBeanImpl; 045 import gnu.java.lang.management.OperatingSystemMXBeanImpl; 046 import gnu.java.lang.management.MemoryMXBeanImpl; 047 import gnu.java.lang.management.MemoryManagerMXBeanImpl; 048 import gnu.java.lang.management.MemoryPoolMXBeanImpl; 049 import gnu.java.lang.management.RuntimeMXBeanImpl; 050 import gnu.java.lang.management.ThreadMXBeanImpl; 051 052 import java.io.IOException; 053 054 import java.lang.reflect.InvocationHandler; 055 import java.lang.reflect.Method; 056 import java.lang.reflect.Proxy; 057 058 import java.util.ArrayList; 059 import java.util.HashMap; 060 import java.util.Iterator; 061 import java.util.List; 062 import java.util.Map; 063 064 import java.util.logging.LogManager; 065 066 import javax.management.Attribute; 067 import javax.management.InstanceAlreadyExistsException; 068 import javax.management.MBeanRegistrationException; 069 import javax.management.MBeanServer; 070 import javax.management.MBeanServerConnection; 071 import javax.management.MBeanServerFactory; 072 import javax.management.MalformedObjectNameException; 073 import javax.management.NotCompliantMBeanException; 074 import javax.management.NotificationEmitter; 075 import javax.management.NotificationFilter; 076 import javax.management.NotificationListener; 077 import javax.management.ObjectName; 078 079 import javax.management.openmbean.CompositeData; 080 import javax.management.openmbean.TabularData; 081 082 /** 083 * <p> 084 * Provides access to the system's management beans via a series 085 * of static methods. 086 * </p> 087 * <p> 088 * An instance of a system management bean can be obtained by 089 * using one of the following methods: 090 * </p> 091 * <ol> 092 * <li>Calling the appropriate static method of this factory. 093 * </li> 094 * <li>Using the platform {@link javax.management.MBeanServer} 095 * to access the beans locally, or an 096 * {@link javax.management.MBeanServerConnection} for remote 097 * access. The attributes and operations use the limited 098 * range of data types specified below.</li> 099 * </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 }