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 */
34import java.lang.management.*;
35import javax.management.*;
36import javax.management.openmbean.CompositeData;
37import javax.management.openmbean.TabularData;
38import static java.lang.management.ManagementFactory.*;
39import java.util.List;
40import java.util.Map;
41import com.sun.management.GcInfo;
42
43public 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}
304