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