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