1 /* 2 * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang.management; 27 import java.io.FilePermission; 28 import java.io.IOException; 29 import javax.management.DynamicMBean; 30 import javax.management.MBeanServer; 31 import javax.management.MBeanServerConnection; 32 import javax.management.MBeanServerFactory; 33 import javax.management.MBeanServerPermission; 34 import javax.management.NotificationEmitter; 35 import javax.management.ObjectName; 36 import javax.management.InstanceNotFoundException; 37 import javax.management.MalformedObjectNameException; 38 import javax.management.StandardEmitterMBean; 39 import javax.management.StandardMBean; 40 import java.util.Collections; 41 import java.util.List; 42 import java.util.Set; 43 import java.util.Map; 44 import java.security.AccessController; 45 import java.security.Permission; 46 import java.security.PrivilegedAction; 47 import java.security.PrivilegedActionException; 48 import java.security.PrivilegedExceptionAction; 49 import java.util.ArrayList; 50 import java.util.Collection; 51 import java.util.Optional; 52 import java.util.ServiceLoader; 53 import java.util.function.Function; 54 import java.util.stream.Collectors; 55 import static java.util.stream.Collectors.toMap; 56 import java.util.stream.Stream; 57 import javax.management.JMX; 58 import sun.management.Util; 59 import sun.management.spi.PlatformMBeanProvider; 60 import sun.management.spi.PlatformMBeanProvider.PlatformComponent; 61 62 /** 63 * The {@code ManagementFactory} class is a factory class for getting 64 * managed beans for the Java platform. 65 * This class consists of static methods each of which returns 66 * one or more <i>platform MXBeans</i> representing 67 * the management interface of a component of the Java virtual 68 * machine. 69 * 70 * <h3><a name="MXBean">Platform MXBeans</a></h3> 71 * <p> 72 * A platform MXBean is a <i>managed bean</i> that 73 * conforms to the <a href="../../../javax/management/package-summary.html">JMX</a> 74 * Instrumentation Specification and only uses a set of basic data types. 75 * A JMX management application and the {@linkplain 76 * #getPlatformMBeanServer platform MBeanServer} 77 * can interoperate without requiring classes for MXBean specific 78 * data types. 79 * The data types being transmitted between the JMX connector 80 * server and the connector client are 81 * {@linkplain javax.management.openmbean.OpenType open types} 82 * and this allows interoperation across versions. 83 * See <a href="../../../javax/management/MXBean.html#MXBean-spec"> 84 * the specification of MXBeans</a> for details. 85 * 86 * <a name="MXBeanNames"></a> 87 * <p>Each platform MXBean is a {@link PlatformManagedObject} 88 * and it has a unique 89 * {@link javax.management.ObjectName ObjectName} for 90 * registration in the platform {@code MBeanServer} as returned by 91 * by the {@link PlatformManagedObject#getObjectName getObjectName} 92 * method. 93 * 94 * <p> 95 * An application can access a platform MXBean in the following ways: 96 * <h4>1. Direct access to an MXBean interface</h4> 97 * <blockquote> 98 * <ul> 99 * <li>Get an MXBean instance by calling the 100 * {@link #getPlatformMXBean(Class) getPlatformMXBean} or 101 * {@link #getPlatformMXBeans(Class) getPlatformMXBeans} method 102 * and access the MXBean locally in the running 103 * virtual machine. 104 * </li> 105 * <li>Construct an MXBean proxy instance that forwards the 106 * method calls to a given {@link MBeanServer MBeanServer} by calling 107 * the {@link #getPlatformMXBean(MBeanServerConnection, Class)} or 108 * {@link #getPlatformMXBeans(MBeanServerConnection, Class)} method. 109 * The {@link #newPlatformMXBeanProxy newPlatformMXBeanProxy} method 110 * can also be used to construct an MXBean proxy instance of 111 * a given {@code ObjectName}. 112 * A proxy is typically constructed to remotely access 113 * an MXBean of another running virtual machine. 114 * </li> 115 * </ul> 116 * <h4>2. Indirect access to an MXBean interface via MBeanServer</h4> 117 * <ul> 118 * <li>Go through the platform {@code MBeanServer} to access MXBeans 119 * locally or a specific {@code MBeanServerConnection} to access 120 * MXBeans remotely. 121 * The attributes and operations of an MXBean use only 122 * <em>JMX open types</em> which include basic data types, 123 * {@link javax.management.openmbean.CompositeData CompositeData}, 124 * and {@link javax.management.openmbean.TabularData TabularData} 125 * defined in 126 * {@link javax.management.openmbean.OpenType OpenType}. 127 * The mapping is specified in 128 * the {@linkplain javax.management.MXBean MXBean} specification 129 * for details. 130 * </li> 131 * </ul> 132 * </blockquote> 133 * 134 * <p> 135 * The {@link #getPlatformManagementInterfaces getPlatformManagementInterfaces} 136 * method returns all management interfaces supported in the Java virtual machine 137 * including the standard management interfaces listed in the tables 138 * below as well as the management interfaces extended by the JDK implementation. 139 * <p> 140 * A Java virtual machine has a single instance of the following management 141 * interfaces: 142 * 143 * <blockquote> 144 * <table border summary="The list of Management Interfaces and their single instances"> 145 * <tr> 146 * <th>Management Interface</th> 147 * <th>ObjectName</th> 148 * </tr> 149 * <tr> 150 * <td> {@link ClassLoadingMXBean} </td> 151 * <td> {@link #CLASS_LOADING_MXBEAN_NAME 152 * java.lang:type=ClassLoading}</td> 153 * </tr> 154 * <tr> 155 * <td> {@link MemoryMXBean} </td> 156 * <td> {@link #MEMORY_MXBEAN_NAME 157 * java.lang:type=Memory}</td> 158 * </tr> 159 * <tr> 160 * <td> {@link ThreadMXBean} </td> 161 * <td> {@link #THREAD_MXBEAN_NAME 162 * java.lang:type=Threading}</td> 163 * </tr> 164 * <tr> 165 * <td> {@link RuntimeMXBean} </td> 166 * <td> {@link #RUNTIME_MXBEAN_NAME 167 * java.lang:type=Runtime}</td> 168 * </tr> 169 * <tr> 170 * <td> {@link OperatingSystemMXBean} </td> 171 * <td> {@link #OPERATING_SYSTEM_MXBEAN_NAME 172 * java.lang:type=OperatingSystem}</td> 173 * </tr> 174 * <tr> 175 * <td> {@link PlatformLoggingMXBean} </td> 176 * <td> {@link java.util.logging.LogManager#LOGGING_MXBEAN_NAME 177 * java.util.logging:type=Logging}</td> 178 * </tr> 179 * </table> 180 * </blockquote> 181 * 182 * <p> 183 * A Java virtual machine has zero or a single instance of 184 * the following management interfaces. 185 * 186 * <blockquote> 187 * <table border summary="The list of Management Interfaces and their single instances"> 188 * <tr> 189 * <th>Management Interface</th> 190 * <th>ObjectName</th> 191 * </tr> 192 * <tr> 193 * <td> {@link CompilationMXBean} </td> 194 * <td> {@link #COMPILATION_MXBEAN_NAME 195 * java.lang:type=Compilation}</td> 196 * </tr> 197 * </table> 198 * </blockquote> 199 * 200 * <p> 201 * A Java virtual machine may have one or more instances of the following 202 * management interfaces. 203 * <blockquote> 204 * <table border summary="The list of Management Interfaces and their single instances"> 205 * <tr> 206 * <th>Management Interface</th> 207 * <th>ObjectName</th> 208 * </tr> 209 * <tr> 210 * <td> {@link GarbageCollectorMXBean} </td> 211 * <td> {@link #GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE 212 * java.lang:type=GarbageCollector}{@code ,name=}<i>collector's name</i></td> 213 * </tr> 214 * <tr> 215 * <td> {@link MemoryManagerMXBean} </td> 216 * <td> {@link #MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE 217 * java.lang:type=MemoryManager}{@code ,name=}<i>manager's name</i></td> 218 * </tr> 219 * <tr> 220 * <td> {@link MemoryPoolMXBean} </td> 221 * <td> {@link #MEMORY_POOL_MXBEAN_DOMAIN_TYPE 222 * java.lang:type=MemoryPool}{@code ,name=}<i>pool's name</i></td> 223 * </tr> 224 * <tr> 225 * <td> {@link BufferPoolMXBean} </td> 226 * <td> {@code java.nio:type=BufferPool,name=}<i>pool name</i></td> 227 * </tr> 228 * </table> 229 * </blockquote> 230 * 231 * @see <a href="../../../javax/management/package-summary.html"> 232 * JMX Specification</a> 233 * @see <a href="package-summary.html#examples"> 234 * Ways to Access Management Metrics</a> 235 * @see javax.management.MXBean 236 * 237 * @author Mandy Chung 238 * @since 1.5 239 */ 240 public class ManagementFactory { 241 // A class with only static fields and methods. 242 private ManagementFactory() {}; 243 244 /** 245 * String representation of the 246 * {@code ObjectName} for the {@link ClassLoadingMXBean}. 247 */ 248 public final static String CLASS_LOADING_MXBEAN_NAME = 249 "java.lang:type=ClassLoading"; 250 251 /** 252 * String representation of the 253 * {@code ObjectName} for the {@link CompilationMXBean}. 254 */ 255 public final static String COMPILATION_MXBEAN_NAME = 256 "java.lang:type=Compilation"; 257 258 /** 259 * String representation of the 260 * {@code ObjectName} for the {@link MemoryMXBean}. 261 */ 262 public final static String MEMORY_MXBEAN_NAME = 263 "java.lang:type=Memory"; 264 265 /** 266 * String representation of the 267 * {@code ObjectName} for the {@link OperatingSystemMXBean}. 268 */ 269 public final static String OPERATING_SYSTEM_MXBEAN_NAME = 270 "java.lang:type=OperatingSystem"; 271 272 /** 273 * String representation of the 274 * {@code ObjectName} for the {@link RuntimeMXBean}. 275 */ 276 public final static String RUNTIME_MXBEAN_NAME = 277 "java.lang:type=Runtime"; 278 279 /** 280 * String representation of the 281 * {@code ObjectName} for the {@link ThreadMXBean}. 282 */ 283 public final static String THREAD_MXBEAN_NAME = 284 "java.lang:type=Threading"; 285 286 /** 287 * The domain name and the type key property in 288 * the {@code ObjectName} for a {@link GarbageCollectorMXBean}. 289 * The unique {@code ObjectName} for a {@code GarbageCollectorMXBean} 290 * can be formed by appending this string with 291 * "{@code ,name=}<i>collector's name</i>". 292 */ 293 public final static String GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE = 294 "java.lang:type=GarbageCollector"; 295 296 /** 297 * The domain name and the type key property in 298 * the {@code ObjectName} for a {@link MemoryManagerMXBean}. 299 * The unique {@code ObjectName} for a {@code MemoryManagerMXBean} 300 * can be formed by appending this string with 301 * "{@code ,name=}<i>manager's name</i>". 302 */ 303 public final static String MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE= 304 "java.lang:type=MemoryManager"; 305 306 /** 307 * The domain name and the type key property in 308 * the {@code ObjectName} for a {@link MemoryPoolMXBean}. 309 * The unique {@code ObjectName} for a {@code MemoryPoolMXBean} 310 * can be formed by appending this string with 311 * {@code ,name=}<i>pool's name</i>. 312 */ 313 public final static String MEMORY_POOL_MXBEAN_DOMAIN_TYPE= 314 "java.lang:type=MemoryPool"; 315 316 /** 317 * Returns the managed bean for the class loading system of 318 * the Java virtual machine. 319 * 320 * @return a {@link ClassLoadingMXBean} object for 321 * the Java virtual machine. 322 */ 323 public static ClassLoadingMXBean getClassLoadingMXBean() { 324 return getPlatformMXBean(ClassLoadingMXBean.class); 325 } 326 327 /** 328 * Returns the managed bean for the memory system of 329 * the Java virtual machine. 330 * 331 * @return a {@link MemoryMXBean} object for the Java virtual machine. 332 */ 333 public static MemoryMXBean getMemoryMXBean() { 334 return getPlatformMXBean(MemoryMXBean.class); 335 } 336 337 /** 338 * Returns the managed bean for the thread system of 339 * the Java virtual machine. 340 * 341 * @return a {@link ThreadMXBean} object for the Java virtual machine. 342 */ 343 public static ThreadMXBean getThreadMXBean() { 344 return getPlatformMXBean(ThreadMXBean.class); 345 } 346 347 /** 348 * Returns the managed bean for the runtime system of 349 * the Java virtual machine. 350 * 351 * @return a {@link RuntimeMXBean} object for the Java virtual machine. 352 353 */ 354 public static RuntimeMXBean getRuntimeMXBean() { 355 return getPlatformMXBean(RuntimeMXBean.class); 356 } 357 358 /** 359 * Returns the managed bean for the compilation system of 360 * the Java virtual machine. This method returns {@code null} 361 * if the Java virtual machine has no compilation system. 362 * 363 * @return a {@link CompilationMXBean} object for the Java virtual 364 * machine or {@code null} if the Java virtual machine has 365 * no compilation system. 366 */ 367 public static CompilationMXBean getCompilationMXBean() { 368 return getPlatformMXBean(CompilationMXBean.class); 369 } 370 371 /** 372 * Returns the managed bean for the operating system on which 373 * the Java virtual machine is running. 374 * 375 * @return an {@link OperatingSystemMXBean} object for 376 * the Java virtual machine. 377 */ 378 public static OperatingSystemMXBean getOperatingSystemMXBean() { 379 return getPlatformMXBean(OperatingSystemMXBean.class); 380 } 381 382 /** 383 * Returns a list of {@link MemoryPoolMXBean} objects in the 384 * Java virtual machine. 385 * The Java virtual machine can have one or more memory pools. 386 * It may add or remove memory pools during execution. 387 * 388 * @return a list of {@code MemoryPoolMXBean} objects. 389 * 390 */ 391 public static List<MemoryPoolMXBean> getMemoryPoolMXBeans() { 392 return getPlatformMXBeans(MemoryPoolMXBean.class); 393 } 394 395 /** 396 * Returns a list of {@link MemoryManagerMXBean} objects 397 * in the Java virtual machine. 398 * The Java virtual machine can have one or more memory managers. 399 * It may add or remove memory managers during execution. 400 * 401 * @return a list of {@code MemoryManagerMXBean} objects. 402 * 403 */ 404 public static List<MemoryManagerMXBean> getMemoryManagerMXBeans() { 405 return getPlatformMXBeans(MemoryManagerMXBean.class); 406 } 407 408 409 /** 410 * Returns a list of {@link GarbageCollectorMXBean} objects 411 * in the Java virtual machine. 412 * The Java virtual machine may have one or more 413 * {@code GarbageCollectorMXBean} objects. 414 * It may add or remove {@code GarbageCollectorMXBean} 415 * during execution. 416 * 417 * @return a list of {@code GarbageCollectorMXBean} objects. 418 * 419 */ 420 public static List<GarbageCollectorMXBean> getGarbageCollectorMXBeans() { 421 return getPlatformMXBeans(GarbageCollectorMXBean.class); 422 } 423 424 private static MBeanServer platformMBeanServer; 425 /** 426 * Returns the platform {@link javax.management.MBeanServer MBeanServer}. 427 * On the first call to this method, it first creates the platform 428 * {@code MBeanServer} by calling the 429 * {@link javax.management.MBeanServerFactory#createMBeanServer 430 * MBeanServerFactory.createMBeanServer} 431 * method and registers each platform MXBean in this platform 432 * {@code MBeanServer} with its 433 * {@link PlatformManagedObject#getObjectName ObjectName}. 434 * This method, in subsequent calls, will simply return the 435 * initially created platform {@code MBeanServer}. 436 * <p> 437 * MXBeans that get created and destroyed dynamically, for example, 438 * memory {@link MemoryPoolMXBean pools} and 439 * {@link MemoryManagerMXBean managers}, 440 * will automatically be registered and deregistered into the platform 441 * {@code MBeanServer}. 442 * <p> 443 * If the system property {@code javax.management.builder.initial} 444 * is set, the platform {@code MBeanServer} creation will be done 445 * by the specified {@link javax.management.MBeanServerBuilder}. 446 * <p> 447 * It is recommended that this platform MBeanServer also be used 448 * to register other application managed beans 449 * besides the platform MXBeans. 450 * This will allow all MBeans to be published through the same 451 * {@code MBeanServer} and hence allow for easier network publishing 452 * and discovery. 453 * Name conflicts with the platform MXBeans should be avoided. 454 * 455 * @return the platform {@code MBeanServer}; the platform 456 * MXBeans are registered into the platform {@code MBeanServer} 457 * at the first time this method is called. 458 * 459 * @exception SecurityException if there is a security manager 460 * and the caller does not have the permission required by 461 * {@link javax.management.MBeanServerFactory#createMBeanServer}. 462 * 463 * @see javax.management.MBeanServerFactory 464 * @see javax.management.MBeanServerFactory#createMBeanServer 465 */ 466 public static synchronized MBeanServer getPlatformMBeanServer() { 467 SecurityManager sm = System.getSecurityManager(); 468 if (sm != null) { 469 Permission perm = new MBeanServerPermission("createMBeanServer"); 470 sm.checkPermission(perm); 471 } 472 473 if (platformMBeanServer == null) { 474 platformMBeanServer = MBeanServerFactory.createMBeanServer(); 475 platformComponents() 476 .stream() 477 .filter(PlatformComponent::shouldRegister) 478 .flatMap(pc -> pc.nameToMBeanMap().entrySet().stream()) 479 .forEach(entry -> addMXBean(platformMBeanServer, entry.getKey(), entry.getValue())); 480 } 481 return platformMBeanServer; 482 } 483 484 /** 485 * Returns a proxy for a platform MXBean interface of a 486 * given <a href="#MXBeanNames">MXBean name</a> 487 * that forwards its method calls through the given 488 * {@code MBeanServerConnection}. 489 * 490 * <p>This method is equivalent to: 491 * <blockquote> 492 * {@link java.lang.reflect.Proxy#newProxyInstance 493 * Proxy.newProxyInstance}{@code (mxbeanInterface.getClassLoader(), 494 * new Class[] { mxbeanInterface }, handler)} 495 * </blockquote> 496 * 497 * where {@code handler} is an {@link java.lang.reflect.InvocationHandler 498 * InvocationHandler} to which method invocations to the MXBean interface 499 * are dispatched. This {@code handler} converts an input parameter 500 * from an MXBean data type to its mapped open type before forwarding 501 * to the {@code MBeanServer} and converts a return value from 502 * an MXBean method call through the {@code MBeanServer} 503 * from an open type to the corresponding return type declared in 504 * the MXBean interface. 505 * 506 * <p> 507 * If the MXBean is a notification emitter (i.e., 508 * it implements 509 * {@link javax.management.NotificationEmitter NotificationEmitter}), 510 * both the {@code mxbeanInterface} and {@code NotificationEmitter} 511 * will be implemented by this proxy. 512 * 513 * <p> 514 * <b>Notes:</b> 515 * <ol> 516 * <li>Using an MXBean proxy is a convenience remote access to 517 * a platform MXBean of a running virtual machine. All method 518 * calls to the MXBean proxy are forwarded to an 519 * {@code MBeanServerConnection} where 520 * {@link java.io.IOException IOException} may be thrown 521 * when the communication problem occurs with the connector server. 522 * If thrown, {@link java.io.IOException IOException} will be wrappped in 523 * {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}. 524 * An application remotely accessing the platform MXBeans using 525 * proxy should prepare to catch {@code UndeclaredThrowableException} and 526 * handle its {@linkplain java.lang.reflect.UndeclaredThrowableException#getCause() cause} 527 * as if that cause had been thrown by the {@code MBeanServerConnection} 528 * interface.</li> 529 * 530 * <li>When a client application is designed to remotely access MXBeans 531 * for a running virtual machine whose version is different than 532 * the version on which the application is running, 533 * it should prepare to catch 534 * {@link java.io.InvalidObjectException InvalidObjectException} 535 * which is thrown when an MXBean proxy receives a name of an 536 * enum constant which is missing in the enum class loaded in 537 * the client application. If thrown, 538 * {@link java.io.InvalidObjectException InvalidObjectException} will be 539 * wrappped in 540 * {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}. 541 * </li> 542 * 543 * <li>{@link javax.management.MBeanServerInvocationHandler 544 * MBeanServerInvocationHandler} or its 545 * {@link javax.management.MBeanServerInvocationHandler#newProxyInstance 546 * newProxyInstance} method cannot be used to create 547 * a proxy for a platform MXBean. The proxy object created 548 * by {@code MBeanServerInvocationHandler} does not handle 549 * the properties of the platform MXBeans described in 550 * the <a href="#MXBean">class specification</a>. 551 *</li> 552 * </ol> 553 * 554 * @param connection the {@code MBeanServerConnection} to forward to. 555 * @param mxbeanName the name of a platform MXBean within 556 * {@code connection} to forward to. {@code mxbeanName} must be 557 * in the format of {@link ObjectName ObjectName}. 558 * @param mxbeanInterface the MXBean interface to be implemented 559 * by the proxy. 560 * @param <T> an {@code mxbeanInterface} type parameter 561 * 562 * @return a proxy for a platform MXBean interface of a 563 * given <a href="#MXBeanNames">MXBean name</a> 564 * that forwards its method calls through the given 565 * {@code MBeanServerConnection}, or {@code null} if not exist. 566 * 567 * @throws IllegalArgumentException if 568 * <ul> 569 * <li>{@code mxbeanName} is not with a valid 570 * {@link ObjectName ObjectName} format, or</li> 571 * <li>the named MXBean in the {@code connection} is 572 * not a MXBean provided by the platform, or</li> 573 * <li>the named MXBean is not registered in the 574 * {@code MBeanServerConnection}, or</li> 575 * <li>the named MXBean is not an instance of the given 576 * {@code mxbeanInterface}</li> 577 * </ul> 578 * 579 * @throws java.io.IOException if a communication problem 580 * occurred when accessing the {@code MBeanServerConnection}. 581 */ 582 public static <T> T 583 newPlatformMXBeanProxy(MBeanServerConnection connection, 584 String mxbeanName, 585 Class<T> mxbeanInterface) 586 throws java.io.IOException { 587 588 // Only allow MXBean interfaces from rt.jar loaded by the 589 // bootstrap class loader 590 final Class<?> cls = mxbeanInterface; 591 ClassLoader loader = 592 AccessController.doPrivileged( 593 (PrivilegedAction<ClassLoader>) () -> cls.getClassLoader()); 594 if (!jdk.internal.misc.VM.isSystemDomainLoader(loader)) { 595 throw new IllegalArgumentException(mxbeanName + 596 " is not a platform MXBean"); 597 } 598 599 try { 600 final ObjectName objName = new ObjectName(mxbeanName); 601 // skip the isInstanceOf check for LoggingMXBean 602 String intfName = mxbeanInterface.getName(); 603 if (!connection.isInstanceOf(objName, intfName)) { 604 throw new IllegalArgumentException(mxbeanName + 605 " is not an instance of " + mxbeanInterface); 606 } 607 608 // check if the registered MBean is a notification emitter 609 boolean emitter = connection.isInstanceOf(objName, NOTIF_EMITTER); 610 611 // create an MXBean proxy 612 return JMX.newMXBeanProxy(connection, objName, mxbeanInterface, 613 emitter); 614 } catch (InstanceNotFoundException|MalformedObjectNameException e) { 615 throw new IllegalArgumentException(e); 616 } 617 } 618 619 /** 620 * Returns the platform MXBean implementing 621 * the given {@code mxbeanInterface} which is specified 622 * to have one single instance in the Java virtual machine. 623 * This method may return {@code null} if the management interface 624 * is not implemented in the Java virtual machine (for example, 625 * a Java virtual machine with no compilation system does not 626 * implement {@link CompilationMXBean}); 627 * otherwise, this method is equivalent to calling: 628 * <pre> 629 * {@link #getPlatformMXBeans(Class) 630 * getPlatformMXBeans(mxbeanInterface)}.get(0); 631 * </pre> 632 * 633 * @param mxbeanInterface a management interface for a platform 634 * MXBean with one single instance in the Java virtual machine 635 * if implemented. 636 * @param <T> an {@code mxbeanInterface} type parameter 637 * 638 * @return the platform MXBean that implements 639 * {@code mxbeanInterface}, or {@code null} if not exist. 640 * 641 * @throws IllegalArgumentException if {@code mxbeanInterface} 642 * is not a platform management interface or 643 * not a singleton platform MXBean. 644 * 645 * @since 1.7 646 */ 647 public static <T extends PlatformManagedObject> 648 T getPlatformMXBean(Class<T> mxbeanInterface) { 649 PlatformComponent<?> pc = PlatformMBeanFinder.findSingleton(mxbeanInterface); 650 651 List<? extends T> mbeans = pc.getMBeans(mxbeanInterface); 652 assert mbeans.isEmpty() || mbeans.size() == 1; 653 return mbeans.isEmpty() ? null : mbeans.get(0); 654 } 655 656 /** 657 * Returns the list of platform MXBeans implementing 658 * the given {@code mxbeanInterface} in the Java 659 * virtual machine. 660 * The returned list may contain zero, one, or more instances. 661 * The number of instances in the returned list is defined 662 * in the specification of the given management interface. 663 * The order is undefined and there is no guarantee that 664 * the list returned is in the same order as previous invocations. 665 * 666 * @param mxbeanInterface a management interface for a platform 667 * MXBean 668 * @param <T> an {@code mxbeanInterface} type parameter 669 * 670 * @return the list of platform MXBeans that implement 671 * {@code mxbeanInterface}. 672 * 673 * @throws IllegalArgumentException if {@code mxbeanInterface} 674 * is not a platform management interface. 675 * 676 * @since 1.7 677 */ 678 public static <T extends PlatformManagedObject> List<T> 679 getPlatformMXBeans(Class<T> mxbeanInterface) { 680 // Validates at first the specified interface by finding at least one 681 // PlatformComponent whose MXBean implements this interface. 682 // An interface can be implemented by different MBeans, provided by 683 // different platform components. 684 PlatformComponent<?> pc = PlatformMBeanFinder.findFirst(mxbeanInterface); 685 if (pc == null) { 686 throw new IllegalArgumentException(mxbeanInterface.getName() 687 + " is not a platform management interface"); 688 } 689 690 return platformComponents().stream() 691 .flatMap(p -> p.getMBeans(mxbeanInterface).stream()) 692 .collect(Collectors.toList()); 693 } 694 695 /** 696 * Returns the platform MXBean proxy for 697 * {@code mxbeanInterface} which is specified to have one single 698 * instance in a Java virtual machine and the proxy will 699 * forward the method calls through the given {@code MBeanServerConnection}. 700 * This method may return {@code null} if the management interface 701 * is not implemented in the Java virtual machine being monitored 702 * (for example, a Java virtual machine with no compilation system 703 * does not implement {@link CompilationMXBean}); 704 * otherwise, this method is equivalent to calling: 705 * <pre> 706 * {@link #getPlatformMXBeans(MBeanServerConnection, Class) 707 * getPlatformMXBeans(connection, mxbeanInterface)}.get(0); 708 * </pre> 709 * 710 * @param connection the {@code MBeanServerConnection} to forward to. 711 * @param mxbeanInterface a management interface for a platform 712 * MXBean with one single instance in the Java virtual machine 713 * being monitored, if implemented. 714 * @param <T> an {@code mxbeanInterface} type parameter 715 * 716 * @return the platform MXBean proxy for 717 * forwarding the method calls of the {@code mxbeanInterface} 718 * through the given {@code MBeanServerConnection}, 719 * or {@code null} if not exist. 720 * 721 * @throws IllegalArgumentException if {@code mxbeanInterface} 722 * is not a platform management interface or 723 * not a singleton platform MXBean. 724 * @throws java.io.IOException if a communication problem 725 * occurred when accessing the {@code MBeanServerConnection}. 726 * 727 * @see #newPlatformMXBeanProxy 728 * @since 1.7 729 */ 730 public static <T extends PlatformManagedObject> 731 T getPlatformMXBean(MBeanServerConnection connection, 732 Class<T> mxbeanInterface) 733 throws java.io.IOException 734 { 735 PlatformComponent<?> pc = PlatformMBeanFinder.findSingleton(mxbeanInterface); 736 return newPlatformMXBeanProxy(connection, pc.getObjectNamePattern(), mxbeanInterface); 737 } 738 739 /** 740 * Returns the list of the platform MXBean proxies for 741 * forwarding the method calls of the {@code mxbeanInterface} 742 * through the given {@code MBeanServerConnection}. 743 * The returned list may contain zero, one, or more instances. 744 * The number of instances in the returned list is defined 745 * in the specification of the given management interface. 746 * The order is undefined and there is no guarantee that 747 * the list returned is in the same order as previous invocations. 748 * 749 * @param connection the {@code MBeanServerConnection} to forward to. 750 * @param mxbeanInterface a management interface for a platform 751 * MXBean 752 * @param <T> an {@code mxbeanInterface} type parameter 753 * 754 * @return the list of platform MXBean proxies for 755 * forwarding the method calls of the {@code mxbeanInterface} 756 * through the given {@code MBeanServerConnection}. 757 * 758 * @throws IllegalArgumentException if {@code mxbeanInterface} 759 * is not a platform management interface. 760 * 761 * @throws java.io.IOException if a communication problem 762 * occurred when accessing the {@code MBeanServerConnection}. 763 * 764 * @see #newPlatformMXBeanProxy 765 * @since 1.7 766 */ 767 public static <T extends PlatformManagedObject> 768 List<T> getPlatformMXBeans(MBeanServerConnection connection, 769 Class<T> mxbeanInterface) 770 throws java.io.IOException 771 { 772 // Validates at first the specified interface by finding at least one 773 // PlatformComponent whose MXBean implements this interface. 774 // An interface can be implemented by different MBeans, provided by 775 // different platform components. 776 PlatformComponent<?> pc = PlatformMBeanFinder.findFirst(mxbeanInterface); 777 if (pc == null) { 778 throw new IllegalArgumentException(mxbeanInterface.getName() 779 + " is not a platform management interface"); 780 } 781 782 // Collect all names, eliminate duplicates. 783 Stream<String> names = Stream.empty(); 784 for (PlatformComponent<?> p : platformComponents()) { 785 names = Stream.concat(names, getProxyNames(p, connection, mxbeanInterface)); 786 } 787 Set<String> objectNames = names.collect(Collectors.toSet()); 788 if (objectNames.isEmpty()) return Collections.emptyList(); 789 790 // Map names on proxies. 791 List<T> proxies = new ArrayList<>(); 792 for (String name : objectNames) { 793 proxies.add(newPlatformMXBeanProxy(connection, name, mxbeanInterface)); 794 } 795 return proxies; 796 } 797 798 // Returns a stream containing all ObjectNames of the MBeans represented by 799 // the specified PlatformComponent and implementing the specified interface. 800 // If the PlatformComponent is a singleton, the name returned by 801 // PlatformComponent.getObjectNamePattern() will be used, otherwise 802 // we will query the specified MBeanServerConnection (conn.queryNames) 803 // with the pattern returned by PlatformComponent.getObjectNamePattern() 804 // in order to find the names of matching MBeans. 805 // In case of singleton, we do not check whether the MBean is registered 806 // in the connection because the caller "getPlatformMXBeans" will do the check 807 // when creating a proxy. 808 private static Stream<String> getProxyNames(PlatformComponent<?> pc, 809 MBeanServerConnection conn, 810 Class<?> intf) 811 throws IOException 812 { 813 if (pc.mbeanInterfaceNames().contains(intf.getName())) { 814 if (pc.isSingleton()) { 815 return Stream.of(pc.getObjectNamePattern()); 816 } else { 817 return conn.queryNames(Util.newObjectName(pc.getObjectNamePattern()), null) 818 .stream().map(ObjectName::getCanonicalName); 819 } 820 } 821 return Stream.empty(); 822 } 823 824 /** 825 * Returns the set of {@code Class} objects, subinterface of 826 * {@link PlatformManagedObject}, representing 827 * all management interfaces for 828 * monitoring and managing the Java platform. 829 * 830 * @return the set of {@code Class} objects, subinterface of 831 * {@link PlatformManagedObject} representing 832 * the management interfaces for 833 * monitoring and managing the Java platform. 834 * 835 * @since 1.7 836 */ 837 public static Set<Class<? extends PlatformManagedObject>> 838 getPlatformManagementInterfaces() 839 { 840 return platformComponents() 841 .stream() 842 .flatMap(pc -> pc.mbeanInterfaces().stream()) 843 .filter(clazz -> PlatformManagedObject.class.isAssignableFrom(clazz)) 844 .map(clazz -> clazz.asSubclass(PlatformManagedObject.class)) 845 .collect(Collectors.toSet()); 846 } 847 848 private static final String NOTIF_EMITTER = 849 "javax.management.NotificationEmitter"; 850 851 private static void addMXBean(final MBeanServer mbs, String name, final Object pmo) 852 { 853 try { 854 ObjectName oname = ObjectName.getInstance(name); 855 // Make DynamicMBean out of MXBean by wrapping it with a StandardMBean 856 AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> { 857 final DynamicMBean dmbean; 858 if (pmo instanceof DynamicMBean) { 859 dmbean = DynamicMBean.class.cast(pmo); 860 } else if (pmo instanceof NotificationEmitter) { 861 dmbean = new StandardEmitterMBean(pmo, null, true, (NotificationEmitter) pmo); 862 } else { 863 dmbean = new StandardMBean(pmo, null, true); 864 } 865 866 mbs.registerMBean(dmbean, oname); 867 return null; 868 }); 869 } catch (MalformedObjectNameException mone) { 870 throw new IllegalArgumentException(mone); 871 } catch (PrivilegedActionException e) { 872 throw new RuntimeException(e.getException()); 873 } 874 } 875 876 private static Collection<PlatformComponent<?>> platformComponents() 877 { 878 return PlatformMBeanFinder.getMap().values(); 879 } 880 881 private static class PlatformMBeanFinder 882 { 883 private static final Map<String, PlatformComponent<?>> componentMap; 884 static { 885 // get all providers 886 List<PlatformMBeanProvider> providers = AccessController.doPrivileged( 887 (PrivilegedAction<List<PlatformMBeanProvider>>) () -> { 888 List<PlatformMBeanProvider> all = new ArrayList<>(); 889 ServiceLoader.loadInstalled(PlatformMBeanProvider.class) 890 .forEach(all::add); 891 all.add(new DefaultPlatformMBeanProvider()); 892 return all; 893 }, null, new FilePermission("<<ALL FILES>>", "read"), 894 new RuntimePermission("sun.management.spi.PlatformMBeanProvider.subclass")); 895 896 // load all platform components into a map 897 componentMap = providers.stream() 898 .flatMap(p -> toPlatformComponentStream(p)) 899 // The first one wins if multiple PlatformComponents 900 // with same ObjectName pattern, 901 .collect(toMap(PlatformComponent::getObjectNamePattern, 902 Function.identity(), 903 (p1, p2) -> p1)); 904 } 905 906 static Map<String, PlatformComponent<?>> getMap() { 907 return componentMap; 908 } 909 910 // Loads all platform components from a provider into a stream 911 // Ensures that two different components are not declared with the same 912 // object name pattern. Throws InternalError if the provider incorrectly 913 // declares two platform components with the same pattern. 914 private static Stream<PlatformComponent<?>> 915 toPlatformComponentStream(PlatformMBeanProvider provider) 916 { 917 return provider.getPlatformComponentList() 918 .stream() 919 .collect(toMap(PlatformComponent::getObjectNamePattern, 920 Function.identity(), 921 (p1, p2) -> { 922 throw new InternalError( 923 p1.getObjectNamePattern() + 924 " has been used as key for " + p1 + 925 ", it cannot be reused for " + p2); 926 })) 927 .values().stream(); 928 } 929 930 // Finds the first PlatformComponent whose mbeanInterfaceNames() list 931 // contains the specified class name. An MBean interface can be implemented 932 // by different MBeans, provided by different platform components. 933 // For instance the MemoryManagerMXBean interface is implemented both by 934 // regular memory managers, and garbage collector MXBeans. This method is 935 // mainly used to verify that there is at least one PlatformComponent 936 // which provides an implementation of the desired interface. 937 static PlatformComponent<?> findFirst(Class<?> mbeanIntf) 938 { 939 String name = mbeanIntf.getName(); 940 Optional<PlatformComponent<?>> op = getMap().values() 941 .stream() 942 .filter(pc -> pc.mbeanInterfaceNames().contains(name)) 943 .findFirst(); 944 945 if (op.isPresent()) { 946 return op.getWhenPresent(); 947 } else { 948 return null; 949 } 950 } 951 952 // Finds a PlatformComponent whose mbeanInterface name list contains 953 // the specified class name, and make sure that one and only one exists. 954 static PlatformComponent<?> findSingleton(Class<?> mbeanIntf) 955 { 956 String name = mbeanIntf.getName(); 957 Optional<PlatformComponent<?>> op = getMap().values() 958 .stream() 959 .filter(pc -> pc.mbeanInterfaceNames().contains(name)) 960 .reduce((p1, p2) -> { 961 if (p2 != null) { 962 throw new IllegalArgumentException(mbeanIntf.getName() + 963 " can have more than one instance"); 964 } else { 965 return p1; 966 } 967 }); 968 969 PlatformComponent<?> singleton = op.isPresent() ? op.getWhenPresent() : null; 970 if (singleton == null) { 971 throw new IllegalArgumentException(mbeanIntf.getName() + 972 " is not a platform management interface"); 973 } 974 if (!singleton.isSingleton()) { 975 throw new IllegalArgumentException(mbeanIntf.getName() + 976 " can have more than one instance"); 977 } 978 return singleton; 979 } 980 } 981 982 static { 983 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 984 System.loadLibrary("management"); 985 return null; 986 }); 987 } 988 }