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