1 /*
   2  * Copyright (c) 2004, 2016, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug     5024531
  27  * @summary Validate open types mapped for the MXBeans in the platform
  28  *          MBeanServer.
  29  * @author  Mandy Chung
  30  *
  31  * @modules jdk.management
  32  * @compile ValidateOpenTypes.java
  33  * @run main/othervm -verbose:gc ValidateOpenTypes
  34  */
  35 import java.lang.management.*;
  36 import javax.management.*;
  37 import javax.management.openmbean.CompositeData;
  38 import javax.management.openmbean.TabularData;
  39 import static java.lang.management.ManagementFactory.*;
  40 import java.util.List;
  41 import java.util.Map;
  42 import com.sun.management.GcInfo;
  43 
  44 public class ValidateOpenTypes {
  45     private static MBeanServer server =
  46         ManagementFactory.getPlatformMBeanServer();
  47     private static ObjectName memory;
  48     private static ObjectName thread;
  49     private static ObjectName runtime;
  50     private static ObjectName os;
  51     private static ObjectName heapPool = null;
  52     private static ObjectName nonHeapPool = null;
  53 
  54     public static void main(String[] argv) throws Exception {
  55         memory = new ObjectName(MEMORY_MXBEAN_NAME);
  56         runtime = new ObjectName(RUNTIME_MXBEAN_NAME);
  57         thread = new ObjectName(THREAD_MXBEAN_NAME);
  58         os = new ObjectName(OPERATING_SYSTEM_MXBEAN_NAME);
  59 
  60         List<MemoryPoolMXBean> pools = getMemoryPoolMXBeans();
  61         for (MemoryPoolMXBean p : pools) {
  62             if (heapPool == null &&
  63                 p.getType() == MemoryType.HEAP &&
  64                 p.isUsageThresholdSupported() &&
  65                 p.isCollectionUsageThresholdSupported()) {
  66                 heapPool = new ObjectName(MEMORY_POOL_MXBEAN_DOMAIN_TYPE +
  67                                ",name=" + p.getName());
  68             }
  69             if (nonHeapPool == null &&
  70                 p.getType() == MemoryType.NON_HEAP &&
  71                 p.isUsageThresholdSupported()) {
  72                 nonHeapPool = new ObjectName(MEMORY_POOL_MXBEAN_DOMAIN_TYPE +
  73                                ",name=" + p.getName());
  74             }
  75         }
  76 
  77         // Check notification emitters
  78         MyListener listener = new MyListener();
  79         server.addNotificationListener(memory, listener, null, null);
  80         server.removeNotificationListener(memory, listener);
  81 
  82         checkEnum();
  83         checkList();
  84         checkMap();
  85         checkMemoryUsage();
  86         checkThreadInfo();
  87 
  88         checkOS();
  89         checkSunGC();
  90 
  91         System.out.println("Test passed.");
  92     }
  93 
  94     private static void checkEnum() throws Exception {
  95         String type = (String) server.getAttribute(heapPool, "Type");
  96         if (!type.equals("HEAP")) {
  97             throw new RuntimeException("TEST FAILED: " +
  98                 " incorrect memory type for " + heapPool);
  99         }
 100 
 101         type = (String) server.getAttribute(nonHeapPool, "Type");
 102         if (!type.equals("NON_HEAP")) {
 103             throw new RuntimeException("TEST FAILED: " +
 104                 " incorrect memory type for " + nonHeapPool);
 105         }
 106     }
 107 
 108     private static final String OPTION = "-verbose:gc";
 109     private static void checkList() throws Exception {
 110         String[] args = (String[]) server.getAttribute(runtime,
 111                                                        "InputArguments");
 112         if (args.length < 1) {
 113            throw new RuntimeException("TEST FAILED: " +
 114                 " empty input arguments");
 115         }
 116         // check if -verbose:gc exists
 117         boolean found = false;
 118         for (String option : args) {
 119            if (option.equals(OPTION)) {
 120                found = true;
 121                break;
 122            }
 123         }
 124         if (!found) {
 125             throw new RuntimeException("TEST FAILED: " +
 126                 "VM option " + OPTION + " not found");
 127         }
 128     }
 129 
 130     private static final String KEY1   = "test.property.key1";
 131     private static final String VALUE1 = "test.property.value1";
 132     private static final String KEY2   = "test.property.key2";
 133     private static final String VALUE2 = "test.property.value2";
 134     private static final String KEY3   = "test.property.key3";
 135     private static void checkMap() throws Exception {
 136         // Add new system properties
 137         System.setProperty(KEY1, VALUE1);
 138         System.setProperty(KEY2, VALUE2);
 139 
 140         TabularData props1 = (TabularData)
 141             server.getAttribute(runtime, "SystemProperties");
 142 
 143         String value1 = getProperty(props1, KEY1);
 144         if (value1 == null || !value1.equals(VALUE1)) {
 145             throw new RuntimeException("TEST FAILED: " +
 146                  KEY1 + " property found" +
 147                  " with value = " + value1 +
 148                  " but expected to be " + VALUE1);
 149         }
 150 
 151         String value2 = getProperty(props1, KEY2);
 152         if (value2 == null || !value2.equals(VALUE2)) {
 153             throw new RuntimeException("TEST FAILED: " +
 154                  KEY2 + " property found" +
 155                  " with value = " + value2 +
 156                  " but expected to be " + VALUE2);
 157         }
 158 
 159         String value3 = getProperty(props1, KEY3);
 160         if (value3 != null) {
 161             throw new RuntimeException("TEST FAILED: " +
 162                  KEY3 + " property found" +
 163                  " but should not exist" );
 164         }
 165     }
 166     private static String getProperty(TabularData td, String propName) {
 167         CompositeData cd = td.get(new Object[] { propName});
 168         if (cd != null) {
 169             String key = (String) cd.get("key");
 170             if (!propName.equals(key)) {
 171                  throw new RuntimeException("TEST FAILED: " +
 172                      key + " property found" +
 173                      " but expected to be " + propName);
 174             }
 175             return (String) cd.get("value");
 176         }
 177         return null;
 178     }
 179 
 180     private static void checkMemoryUsage() throws Exception {
 181         // sanity check to have non-negative usage
 182         Object u1 = server.getAttribute(memory, "HeapMemoryUsage");
 183         Object u2 = server.getAttribute(memory, "NonHeapMemoryUsage");
 184         Object u3 = server.getAttribute(heapPool, "Usage");
 185         Object u4 = server.getAttribute(nonHeapPool, "Usage");
 186         if (getCommitted(u1) < 0 ||
 187             getCommitted(u2) < 0 ||
 188             getCommitted(u3) < 0 ||
 189             getCommitted(u4) < 0) {
 190             throw new RuntimeException("TEST FAILED: " +
 191                 " expected non-negative committed usage");
 192         }
 193         server.invoke(memory, "gc", new Object[0], new String[0]);
 194         Object u5 = server.getAttribute(heapPool, "CollectionUsage");
 195         if (getCommitted(u5) < 0) {
 196             throw new RuntimeException("TEST FAILED: " +
 197                 " expected non-negative committed collected usage");
 198         }
 199     }
 200 
 201     private static long getCommitted(Object data) {
 202         MemoryUsage u = MemoryUsage.from((CompositeData) data);
 203         return u.getCommitted();
 204     }
 205 
 206     private static void checkThreadInfo() throws Exception {
 207         // assume all threads stay alive
 208         long[] ids = (long[]) server.getAttribute(thread, "AllThreadIds");
 209         Object result = server.invoke(thread,
 210                                       "getThreadInfo",
 211                                       new Object[] { ids },
 212                                       new String[] { "[J" });
 213         for (CompositeData cd : (CompositeData[]) result) {
 214             printThreadInfo(cd);
 215         }
 216 
 217         result = server.invoke(thread,
 218                                "getThreadInfo",
 219                                new Object[] { ids, new Integer(2) },
 220                                new String[] { "[J", "int" });
 221         for (CompositeData cd : (CompositeData[]) result) {
 222             printThreadInfo(cd);
 223         }
 224 
 225         long id = Thread.currentThread().getId();
 226         result = server.invoke(thread,
 227                                "getThreadInfo",
 228                                new Object[] { new Long(id) },
 229                                new String[] { "long" });
 230         printThreadInfo((CompositeData) result);
 231 
 232         result = server.invoke(thread,
 233                                "getThreadInfo",
 234                                new Object[] { new Long(id), new Integer(2) },
 235                                new String[] { "long", "int" });
 236         printThreadInfo((CompositeData) result);
 237     }
 238 
 239     private static void printThreadInfo(CompositeData cd) {
 240         ThreadInfo info = ThreadInfo.from(cd);
 241         if (info == null) {
 242             throw new RuntimeException("TEST FAILED: " +
 243                 " Null ThreadInfo");
 244         }
 245 
 246         System.out.print(info.getThreadName());
 247         System.out.print(" id=" + info.getThreadId());
 248         System.out.println(" " + info.getThreadState());
 249 
 250         for (StackTraceElement s : info.getStackTrace()) {
 251             System.out.println(s);
 252         }
 253     }
 254 
 255     private static void checkOS() throws Exception {
 256         Integer cpus = (Integer) server.getAttribute(os, "AvailableProcessors");
 257         System.out.println("# CPUs = " + cpus);
 258         Long vmem = (Long) server.getAttribute(os, "CommittedVirtualMemorySize");
 259         System.out.println("Committed virtual memory = " + vmem);
 260     }
 261 
 262     private static void checkSunGC() throws Exception {
 263        // Test com.sun.management proxy
 264         List<GarbageCollectorMXBean> gcs = getGarbageCollectorMXBeans();
 265         for (GarbageCollectorMXBean gc : gcs) {
 266             ObjectName sunGc =
 267                 new ObjectName(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE +
 268                                ",name=" + gc.getName());
 269             CompositeData cd = (CompositeData) server.getAttribute(sunGc, "LastGcInfo");
 270             if (cd != null) {
 271                 System.out.println("GC statistic for : " + gc.getName());
 272                 printGcInfo(cd);
 273             }
 274         }
 275     }
 276 
 277     private static void printGcInfo(CompositeData cd) throws Exception {
 278         GcInfo info = GcInfo.from(cd);
 279         System.out.print("GC #" + info.getId());
 280         System.out.print(" start:" + info.getStartTime());
 281         System.out.print(" end:" + info.getEndTime());
 282         System.out.println(" (" + info.getDuration() + "ms)");
 283         Map<String,MemoryUsage> usage = info.getMemoryUsageBeforeGc();
 284 
 285         for (Map.Entry<String,MemoryUsage> entry : usage.entrySet()) {
 286             String poolname = entry.getKey();
 287             MemoryUsage busage = entry.getValue();
 288             MemoryUsage ausage = info.getMemoryUsageAfterGc().get(poolname);
 289             if (ausage == null) {
 290                 throw new RuntimeException("After Gc Memory does not exist" +
 291                     " for " + poolname);
 292             }
 293             System.out.println("Usage for pool " + poolname);
 294             System.out.println("   Before GC: " + busage);
 295             System.out.println("   After GC: " + ausage);
 296         }
 297     }
 298 
 299     static class MyListener implements NotificationListener {
 300         public void handleNotification(Notification notif, Object handback) {
 301             return;
 302         }
 303     }
 304 }