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 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 }
1025