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  * <h3><a id="MXBean">Platform MXBeans</a></h3>
71  * <p>
72  * A platform MXBean is a <i>managed bean</i> that
73  * conforms to the <a href="../../../javax/management/package-summary.html">JMX</a>
74  * Instrumentation Specification and only uses a set of basic data types.
75  * A JMX management application and the {@linkplain
76  * #getPlatformMBeanServer platform MBeanServer}
77  * can interoperate without requiring classes for MXBean specific
78  * data types.
79  * The data types being transmitted between the JMX connector
80  * server and the connector client are
81  * {@linkplain javax.management.openmbean.OpenType open types}
82  * and this allows interoperation across versions.
83  * See <a href="../../../javax/management/MXBean.html#MXBean-spec">
84  * the specification of MXBeans</a> for details.
85  *
86  * <a 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  * <h4>1. Direct access to an MXBean interface</h4>
97  * <blockquote>
98  * <ul>
99  *     <li>Get an MXBean instance by calling the
100  *         {@link #getPlatformMXBean(Class) getPlatformMXBean} or
101  *         {@link #getPlatformMXBeans(Class) getPlatformMXBeans} method
102  *         and access the MXBean locally in the running
103  *         virtual machine.
104  *         </li>
105  *     <li>Construct an MXBean proxy instance that forwards the
106  *         method calls to a given {@link MBeanServer MBeanServer} by calling
107  *         the {@link #getPlatformMXBean(MBeanServerConnection, Class)} or
108  *         {@link #getPlatformMXBeans(MBeanServerConnection, Class)} method.
109  *         The {@link #newPlatformMXBeanProxy newPlatformMXBeanProxy} method
110  *         can also be used to construct an MXBean proxy instance of
111  *         a given {@code ObjectName}.
112  *         A proxy is typically constructed to remotely access
113  *         an MXBean of another running virtual machine.
114  *         </li>
115  * </ul>
116  * <h4>2. Indirect access to an MXBean interface via MBeanServer</h4>
117  * <ul>
118  *     <li>Go through the platform {@code MBeanServer} to access MXBeans
119  *         locally or a specific {@code MBeanServerConnection} to access
120  *         MXBeans remotely.
121  *         The attributes and operations of an MXBean use only
122  *         <em>JMX open types</em> which include basic data types,
123  *         {@link javax.management.openmbean.CompositeData CompositeData},
124  *         and {@link javax.management.openmbean.TabularData TabularData}
125  *         defined in
126  *         {@link javax.management.openmbean.OpenType OpenType}.
127  *         The mapping is specified in
128  *         the {@linkplain javax.management.MXBean MXBean} specification
129  *         for details.
130  *        </li>
131  * </ul>
132  * </blockquote>
133  *
134  * <p>
135  * The {@link #getPlatformManagementInterfaces getPlatformManagementInterfaces}
136  * method returns all management interfaces supported in the Java virtual machine
137  * including the standard management interfaces listed in the tables
138  * below as well as the management interfaces extended by the JDK implementation.
139  * <p>
140  * A Java virtual machine has a single instance of the following management
141  * interfaces:
142  *
143  * <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 nullif 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 nullif 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 nullif 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 nullif 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 nullif 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 nullif 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, nulltrue, (NotificationEmitter) pmo);
898                 } else {
899                     dmbean = new StandardMBean(pmo, nulltrue);
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                 }, nullnew 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 }
1025