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.
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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
 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     //
 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>
 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>
 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>
 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>
 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.
 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>>
 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 
 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 
 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 
 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<?>>
 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.
 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.
 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 {
1019         AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
1020             System.loadLibrary("management");
1021             return null;
1022         });
1023     }
1024 }