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