1 /*
   2  * Copyright (c) 2008, 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 
  28 import java.util.ArrayList;
  29 import java.util.Collections;
  30 import java.util.List;
  31 import java.util.HashSet;
  32 import java.util.HashMap;
  33 import java.util.Map;
  34 import java.util.Set;
  35 import javax.management.MBeanServerConnection;
  36 import javax.management.ObjectName;
  37 
  38 import com.sun.management.HotSpotDiagnosticMXBean;
  39 import com.sun.management.UnixOperatingSystemMXBean;
  40 import com.sun.management.VMOption;
  41 
  42 import sun.management.ManagementFactoryHelper;
  43 import sun.management.Util;
  44 
  45 import jdk.management.jfr.FlightRecorderMXBean;
  46 
  47 /**
  48  * This enum class defines the list of platform components
  49  * that provides monitoring and management support.
  50  * Each enum represents one MXBean interface. A MXBean
  51  * instance could implement one or more MXBean interfaces.
  52  *
  53  * For example, com.sun.management.GarbageCollectorMXBean
  54  * extends java.lang.management.GarbageCollectorMXBean
  55  * and there is one set of garbage collection MXBean instances,
  56  * each of which implements both c.s.m. and j.l.m. interfaces.
  57  * There are two separate enums GARBAGE_COLLECTOR
  58  * and SUN_GARBAGE_COLLECTOR so that ManagementFactory.getPlatformMXBeans(Class)
  59  * will return the list of MXBeans of the specified type.
  60  *
  61  * To add a new MXBean interface for the Java platform,
  62  * add a new enum constant and implement the MXBeanFetcher.
  63  */
  64 enum PlatformComponent {
  65 
  66     /**
  67      * Class loading system of the Java virtual machine.
  68      */
  69     CLASS_LOADING(
  70         "java.lang.management.ClassLoadingMXBean",
  71         "java.lang", "ClassLoading", defaultKeyProperties(),
  72         true, // singleton
  73         new MXBeanFetcher<ClassLoadingMXBean>() {
  74             public List<ClassLoadingMXBean> getMXBeans() {
  75                 return Collections.singletonList(ManagementFactoryHelper.getClassLoadingMXBean());
  76             }
  77         }),
  78 
  79     /**
  80      * Compilation system of the Java virtual machine.
  81      */
  82     COMPILATION(
  83         "java.lang.management.CompilationMXBean",
  84         "java.lang", "Compilation", defaultKeyProperties(),
  85         true, // singleton
  86         new MXBeanFetcher<CompilationMXBean>() {
  87             public List<CompilationMXBean> getMXBeans() {
  88                 CompilationMXBean m = ManagementFactoryHelper.getCompilationMXBean();
  89                 if (m == null) {
  90                    return Collections.emptyList();
  91                 } else {
  92                    return Collections.singletonList(m);
  93                 }
  94             }
  95         }),
  96 
  97     /**
  98      * Memory system of the Java virtual machine.
  99      */
 100     MEMORY(
 101         "java.lang.management.MemoryMXBean",
 102         "java.lang", "Memory", defaultKeyProperties(),
 103         true, // singleton
 104         new MXBeanFetcher<MemoryMXBean>() {
 105             public List<MemoryMXBean> getMXBeans() {
 106                 return Collections.singletonList(ManagementFactoryHelper.getMemoryMXBean());
 107             }
 108         }),
 109 
 110     /**
 111      * Garbage Collector in the Java virtual machine.
 112      */
 113     GARBAGE_COLLECTOR(
 114         "java.lang.management.GarbageCollectorMXBean",
 115         "java.lang", "GarbageCollector", keyProperties("name"),
 116         false, // zero or more instances
 117         new MXBeanFetcher<GarbageCollectorMXBean>() {
 118             public List<GarbageCollectorMXBean> getMXBeans() {
 119                 return ManagementFactoryHelper.
 120                            getGarbageCollectorMXBeans();
 121             }
 122         }),
 123 
 124     /**
 125      * Memory manager in the Java virtual machine.
 126      */
 127     MEMORY_MANAGER(
 128         "java.lang.management.MemoryManagerMXBean",
 129         "java.lang", "MemoryManager", keyProperties("name"),
 130         false, // zero or more instances
 131         new MXBeanFetcher<MemoryManagerMXBean>() {
 132             public List<MemoryManagerMXBean> getMXBeans() {
 133                 return ManagementFactoryHelper.getMemoryManagerMXBeans();
 134             }
 135         },
 136         GARBAGE_COLLECTOR),
 137 
 138     /**
 139      * Memory pool in the Java virtual machine.
 140      */
 141     MEMORY_POOL(
 142         "java.lang.management.MemoryPoolMXBean",
 143         "java.lang", "MemoryPool", keyProperties("name"),
 144         false, // zero or more instances
 145         new MXBeanFetcher<MemoryPoolMXBean>() {
 146             public List<MemoryPoolMXBean> getMXBeans() {
 147                 return ManagementFactoryHelper.getMemoryPoolMXBeans();
 148             }
 149         }),
 150 
 151     /**
 152      * Operating system on which the Java virtual machine is running
 153      */
 154     OPERATING_SYSTEM(
 155         "java.lang.management.OperatingSystemMXBean",
 156         "java.lang", "OperatingSystem", defaultKeyProperties(),
 157         true, // singleton
 158         new MXBeanFetcher<OperatingSystemMXBean>() {
 159             public List<OperatingSystemMXBean> getMXBeans() {
 160                 return Collections.singletonList(ManagementFactoryHelper.getOperatingSystemMXBean());
 161             }
 162         }),
 163 
 164     /**
 165      * Runtime system of the Java virtual machine.
 166      */
 167     RUNTIME(
 168         "java.lang.management.RuntimeMXBean",
 169         "java.lang", "Runtime", defaultKeyProperties(),
 170         true, // singleton
 171         new MXBeanFetcher<RuntimeMXBean>() {
 172             public List<RuntimeMXBean> getMXBeans() {
 173                 return Collections.singletonList(ManagementFactoryHelper.getRuntimeMXBean());
 174             }
 175         }),
 176 
 177     /**
 178      * Threading system of the Java virtual machine.
 179      */
 180     THREADING(
 181         "java.lang.management.ThreadMXBean",
 182         "java.lang", "Threading", defaultKeyProperties(),
 183         true, // singleton
 184         new MXBeanFetcher<ThreadMXBean>() {
 185             public List<ThreadMXBean> getMXBeans() {
 186                 return Collections.singletonList(ManagementFactoryHelper.getThreadMXBean());
 187             }
 188         }),
 189 
 190 
 191     /**
 192      * Logging facility.
 193      */
 194     LOGGING(
 195         "java.lang.management.PlatformLoggingMXBean",
 196         "java.util.logging", "Logging", defaultKeyProperties(),
 197         true, // singleton
 198         new MXBeanFetcher<PlatformLoggingMXBean>() {
 199             public List<PlatformLoggingMXBean> getMXBeans() {
 200                 PlatformLoggingMXBean m = ManagementFactoryHelper.getPlatformLoggingMXBean();
 201                 if (m == null) {
 202                    return Collections.emptyList();
 203                 } else {
 204                    return Collections.singletonList(m);
 205                 }
 206             }
 207         }),
 208 
 209     /**
 210      * Buffer pools.
 211      */
 212     BUFFER_POOL(
 213         "java.lang.management.BufferPoolMXBean",
 214         "java.nio", "BufferPool", keyProperties("name"),
 215         false, // zero or more instances
 216         new MXBeanFetcher<BufferPoolMXBean>() {
 217             public List<BufferPoolMXBean> getMXBeans() {
 218                 return ManagementFactoryHelper.getBufferPoolMXBeans();
 219             }
 220         }),
 221 
 222 
 223     // Sun Platform Extension
 224 
 225     /**
 226      * Sun extension garbage collector that performs collections in cycles.
 227      */
 228     SUN_GARBAGE_COLLECTOR(
 229         "com.sun.management.GarbageCollectorMXBean",
 230         "java.lang", "GarbageCollector", keyProperties("name"),
 231         false, // zero or more instances
 232         new MXBeanFetcher<com.sun.management.GarbageCollectorMXBean>() {
 233             public List<com.sun.management.GarbageCollectorMXBean> getMXBeans() {
 234                 return getGcMXBeanList(com.sun.management.GarbageCollectorMXBean.class);
 235             }
 236         }),
 237 
 238     /**
 239      * Sun extension operating system on which the Java virtual machine
 240      * is running.
 241      */
 242     SUN_OPERATING_SYSTEM(
 243         "com.sun.management.OperatingSystemMXBean",
 244         "java.lang", "OperatingSystem", defaultKeyProperties(),
 245         true, // singleton
 246         new MXBeanFetcher<com.sun.management.OperatingSystemMXBean>() {
 247             public List<com.sun.management.OperatingSystemMXBean> getMXBeans() {
 248                 return getOSMXBeanList(com.sun.management.OperatingSystemMXBean.class);
 249             }
 250         }),
 251 
 252     /**
 253      * Unix operating system.
 254      */
 255     SUN_UNIX_OPERATING_SYSTEM(
 256         "com.sun.management.UnixOperatingSystemMXBean",
 257         "java.lang", "OperatingSystem", defaultKeyProperties(),
 258         true, // singleton
 259         new MXBeanFetcher<UnixOperatingSystemMXBean>() {
 260             public List<UnixOperatingSystemMXBean> getMXBeans() {
 261                 return getOSMXBeanList(com.sun.management.UnixOperatingSystemMXBean.class);
 262             }
 263         }),
 264 
 265     /**
 266      * Diagnostic support for the HotSpot Virtual Machine.
 267      */
 268     HOTSPOT_DIAGNOSTIC(
 269         "com.sun.management.HotSpotDiagnosticMXBean",
 270         "com.sun.management", "HotSpotDiagnostic", defaultKeyProperties(),
 271         true, // singleton
 272         new MXBeanFetcher<HotSpotDiagnosticMXBean>() {
 273             public List<HotSpotDiagnosticMXBean> getMXBeans() {
 274                 return Collections.singletonList(ManagementFactoryHelper.getDiagnosticMXBean());
 275             }
 276         }),
 277 
 278     /**
 279      * Flight Recorder.
 280      */
 281     FLIGHT_RECORDER(
 282         "jdk.management.jfr.FlightRecorderMXBean",
 283         "jdk.management.jfr", "FlightRecorder", defaultKeyProperties(),
 284         true,
 285         new MXBeanFetcher<FlightRecorderMXBean>() {
 286             public List<FlightRecorderMXBean> getMXBeans() {
 287                 HotSpotDiagnosticMXBean hsDiagMBean = ManagementFactoryHelper.getDiagnosticMXBean();
 288                 VMOption opt = hsDiagMBean.getVMOption("EnableJFR");
 289                 if (Boolean.valueOf(opt.getValue())) {
 290                     FlightRecorderMXBean m = ManagementFactoryHelper.getFlightRecorderMXBean();
 291                     if (m != null) {
 292                         return Collections.singletonList(m);
 293                     }
 294                 }
 295                 return Collections.emptyList();
 296             }
 297         });
 298 
 299     /**
 300      * A task that returns the MXBeans for a component.
 301      */
 302     interface MXBeanFetcher<T extends PlatformManagedObject> {
 303         public List<T> getMXBeans();
 304     }
 305 
 306     /*
 307      * Returns a list of the GC MXBeans of the given type.
 308      */
 309     private static <T extends GarbageCollectorMXBean>
 310             List<T> getGcMXBeanList(Class<T> gcMXBeanIntf) {
 311         List<GarbageCollectorMXBean> list =
 312             ManagementFactoryHelper.getGarbageCollectorMXBeans();
 313         List<T> result = new ArrayList<>(list.size());
 314         for (GarbageCollectorMXBean m : list) {
 315             if (gcMXBeanIntf.isInstance(m)) {
 316                 result.add(gcMXBeanIntf.cast(m));
 317             }
 318         }
 319         return result;
 320     }
 321 
 322     /*
 323      * Returns the OS mxbean instance of the given type.
 324      */
 325     private static <T extends OperatingSystemMXBean>
 326             List<T> getOSMXBeanList(Class<T> osMXBeanIntf) {
 327         OperatingSystemMXBean m =
 328             ManagementFactoryHelper.getOperatingSystemMXBean();
 329         if (osMXBeanIntf.isInstance(m)) {
 330             return Collections.singletonList(osMXBeanIntf.cast(m));
 331         } else {
 332             return Collections.emptyList();
 333         }
 334     }
 335 
 336     private final String mxbeanInterfaceName;
 337     private final String domain;
 338     private final String type;
 339     private final Set<String> keyProperties;
 340     private final MXBeanFetcher<?> fetcher;
 341     private final PlatformComponent[] subComponents;
 342     private final boolean singleton;
 343 
 344     private PlatformComponent(String intfName,
 345                               String domain, String type,
 346                               Set<String> keyProperties,
 347                               boolean singleton,
 348                               MXBeanFetcher<?> fetcher,
 349                               PlatformComponent... subComponents) {
 350         this.mxbeanInterfaceName = intfName;
 351         this.domain = domain;
 352         this.type = type;
 353         this.keyProperties = keyProperties;
 354         this.singleton = singleton;
 355         this.fetcher = fetcher;
 356         this.subComponents = subComponents;
 357     }
 358 
 359     private static Set<String> defaultKeyProps;
 360     private static Set<String> defaultKeyProperties() {
 361         if (defaultKeyProps == null) {
 362             defaultKeyProps = Collections.singleton("type");
 363         }
 364         return defaultKeyProps;
 365     }
 366 
 367     private static Set<String> keyProperties(String... keyNames) {
 368         Set<String> set = new HashSet<>();
 369         set.add("type");
 370         for (String s : keyNames) {
 371             set.add(s);
 372         }
 373         return set;
 374     }
 375 
 376     boolean isSingleton() {
 377         return singleton;
 378     }
 379 
 380     String getMXBeanInterfaceName() {
 381         return mxbeanInterfaceName;
 382     }
 383 
 384     @SuppressWarnings("unchecked")
 385     Class<? extends PlatformManagedObject> getMXBeanInterface() {
 386         try {
 387             // Lazy loading the MXBean interface only when it is needed
 388             return (Class<? extends PlatformManagedObject>)
 389                        Class.forName(mxbeanInterfaceName, false,
 390                                      PlatformManagedObject.class.getClassLoader());
 391         } catch (ClassNotFoundException x) {
 392             throw new AssertionError(x);
 393         }
 394     }
 395 
 396     @SuppressWarnings("unchecked")
 397     <T extends PlatformManagedObject>
 398         List<T> getMXBeans(Class<T> mxbeanInterface)
 399     {
 400         return (List<T>) fetcher.getMXBeans();
 401     }
 402 
 403     <T extends PlatformManagedObject> T getSingletonMXBean(Class<T> mxbeanInterface)
 404     {
 405         if (!singleton) {
 406             throw new IllegalArgumentException(mxbeanInterfaceName +
 407                 " can have zero or more than one instances");
 408         }
 409 
 410         List<T> list = getMXBeans(mxbeanInterface);
 411         assert list.size() == 1;
 412         return list.isEmpty() ? null : list.get(0);
 413     }
 414 
 415     <T extends PlatformManagedObject>
 416             T getSingletonMXBean(MBeanServerConnection mbs, Class<T> mxbeanInterface)
 417         throws java.io.IOException
 418     {
 419         if (!singleton) {
 420             throw new IllegalArgumentException(mxbeanInterfaceName +
 421                 " can have zero or more than one instances");
 422         }
 423 
 424         // ObjectName of a singleton MXBean contains only domain and type
 425         assert keyProperties.size() == 1;
 426         String on = domain + ":type=" + type;
 427         return ManagementFactory.newPlatformMXBeanProxy(mbs,
 428                                                         on,
 429                                                         mxbeanInterface);
 430     }
 431 
 432     <T extends PlatformManagedObject>
 433             List<T> getMXBeans(MBeanServerConnection mbs, Class<T> mxbeanInterface)
 434         throws java.io.IOException
 435     {
 436         List<T> result = new ArrayList<>();
 437         for (ObjectName on : getObjectNames(mbs)) {
 438             result.add(ManagementFactory.
 439                 newPlatformMXBeanProxy(mbs,
 440                                        on.getCanonicalName(),
 441                                        mxbeanInterface)
 442             );
 443         }
 444         return result;
 445     }
 446 
 447     private Set<ObjectName> getObjectNames(MBeanServerConnection mbs)
 448         throws java.io.IOException
 449     {
 450         String domainAndType = domain + ":type=" + type;
 451         if (keyProperties.size() > 1) {
 452             // if there are more than 1 key properties (i.e. other than "type")
 453             domainAndType += ",*";
 454         }
 455         ObjectName on = Util.newObjectName(domainAndType);
 456         Set<ObjectName> set =  mbs.queryNames(on, null);
 457         for (PlatformComponent pc : subComponents) {
 458             set.addAll(pc.getObjectNames(mbs));
 459         }
 460         return set;
 461     }
 462 
 463     // a map from MXBean interface name to PlatformComponent
 464     private static Map<String, PlatformComponent> enumMap;
 465     private static synchronized void ensureInitialized() {
 466         if (enumMap == null) {
 467             enumMap = new HashMap<>();
 468             for (PlatformComponent pc: PlatformComponent.values()) {
 469                 // Use String as the key rather than Class<?> to avoid
 470                 // causing unnecessary class loading of management interface
 471                 enumMap.put(pc.getMXBeanInterfaceName(), pc);
 472             }
 473         }
 474     }
 475 
 476     static boolean isPlatformMXBean(String cn) {
 477         ensureInitialized();
 478         return enumMap.containsKey(cn);
 479     }
 480 
 481     static <T extends PlatformManagedObject>
 482         PlatformComponent getPlatformComponent(Class<T> mxbeanInterface)
 483     {
 484         ensureInitialized();
 485         String cn = mxbeanInterface.getName();
 486         PlatformComponent pc = enumMap.get(cn);
 487         if (pc != null && pc.getMXBeanInterface() == mxbeanInterface) {
 488             return pc;
 489         }
 490         return null;
 491     }
 492 
 493     private static final long serialVersionUID = 6992337162326171013L;
 494 }