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     4982289
  27  * @summary Test ThreadInfo.from to return a valid
  28  *          ThreadInfo object. Or throw exception if
  29  *          the input CompositeData is invalid.
  30  * @author  Mandy Chung
  31  *
  32  * @modules java.management
  33  * @compile OpenTypeConverter.java
  34  * @build ThreadInfoCompositeData
  35  * @run main ThreadInfoCompositeData
  36  */
  37 
  38 import javax.management.openmbean.*;
  39 import java.lang.management.LockInfo;
  40 import java.lang.management.MonitorInfo;
  41 import java.lang.management.ThreadInfo;
  42 
  43 public class ThreadInfoCompositeData {
  44     private static StackTraceElement[] ste = new StackTraceElement[1];
  45     private static CompositeData[] steCD = new CompositeData[1];
  46     private static String lockClassName = "myClass";
  47     private static int lockIdentityHashCode = 123456;
  48     private static String lockName = lockClassName + '@' +
  49         Integer.toHexString(lockIdentityHashCode);
  50     private static LockInfo lockInfo =
  51         new LockInfo(lockClassName, lockIdentityHashCode);
  52 
  53     public static void main(String[] argv) throws Exception {
  54         // A valid CompositeData is passed to ThreadInfo
  55         createGoodCompositeData();
  56         // A valid CompositeData for JDK 5.0 ThreadInfo
  57         // is passed to ThreadInfo
  58         createV5ThreadInfo();
  59         // An invalid CompositeData is passed to ThreadInfo.from()
  60         badNameCompositeData();
  61         badTypeCompositeData();
  62         System.out.println("Test passed");
  63     }
  64 
  65     public static void createGoodCompositeData() throws Exception {
  66         CompositeType ct =
  67             new CompositeType("MyCompositeType",
  68                               "CompositeType for ThreadInfo",
  69                               validItemNames,
  70                               validItemNames,
  71                               validItemTypes);
  72         CompositeData cd =
  73             new CompositeDataSupport(ct,
  74                                      validItemNames,
  75                                      values);
  76         ThreadInfo info = ThreadInfo.from(cd);
  77         checkThreadInfo(info);
  78    }
  79 
  80     public static void createV5ThreadInfo() throws Exception {
  81         String[] v5ItemNames = new String[NUM_V5_ATTS];
  82         OpenType[] v5ItemTypes = new OpenType[NUM_V5_ATTS];
  83         Object[] v5ItemValues = new Object[NUM_V5_ATTS];
  84         for (int i = 0; i < NUM_V5_ATTS; i++) {
  85             v5ItemNames[i] = validItemNames[i];
  86             v5ItemTypes[i] = validItemTypes[i];
  87             v5ItemValues[i] = values[i];
  88         }
  89         CompositeType ct =
  90             new CompositeType("MyCompositeType",
  91                               "CompositeType for JDK 5.0 ThreadInfo",
  92                               v5ItemNames,
  93                               v5ItemNames,
  94                               v5ItemTypes);
  95         CompositeData cd =
  96             new CompositeDataSupport(ct,
  97                                      v5ItemNames,
  98                                      v5ItemValues);
  99         ThreadInfo info = ThreadInfo.from(cd);
 100         checkThreadInfo(info);
 101    }
 102 
 103    static void checkThreadInfo(ThreadInfo info) throws Exception {
 104         if (info.getThreadId() != ((Long) values[THREAD_ID]).longValue()) {
 105             throw new RuntimeException("Thread Id = " + info.getThreadId() +
 106                " expected = " + values[THREAD_ID]);
 107         }
 108         if (!info.getThreadName().equals(values[THREAD_NAME])) {
 109             throw new RuntimeException("Thread Name = " +
 110                info.getThreadName() + " expected = " + values[THREAD_NAME]);
 111         }
 112         if (info.getThreadState() != Thread.State.RUNNABLE) {
 113             throw new RuntimeException("Thread Name = " +
 114                info.getThreadName() + " expected = " + Thread.State.RUNNABLE);
 115         }
 116         if (info.getBlockedTime() != ((Long) values[BLOCKED_TIME]).longValue()) {
 117             throw new RuntimeException("blocked time = " +
 118                info.getBlockedTime() +
 119                " expected = " + values[BLOCKED_TIME]);
 120         }
 121         if (info.getBlockedCount() != ((Long) values[BLOCKED_COUNT]).longValue()) {
 122             throw new RuntimeException("blocked count = " +
 123                info.getBlockedCount() +
 124                " expected = " + values[BLOCKED_COUNT]);
 125         }
 126         if (info.getWaitedTime() != ((Long) values[WAITED_TIME]).longValue()) {
 127             throw new RuntimeException("waited time = " +
 128                info.getWaitedTime() +
 129                " expected = " + values[WAITED_TIME]);
 130         }
 131         if (info.getWaitedCount() != ((Long) values[WAITED_COUNT]).longValue()) {
 132             throw new RuntimeException("waited count = " +
 133                info.getWaitedCount() +
 134                " expected = " + values[WAITED_COUNT]);
 135         }
 136         if (!info.getLockName().equals(values[LOCK_NAME])) {
 137             throw new RuntimeException("Lock Name = " +
 138                info.getLockName() + " expected = " + values[LOCK_NAME]);
 139         }
 140         if (info.getLockOwnerId() !=
 141                 ((Long) values[LOCK_OWNER_ID]).longValue()) {
 142             throw new RuntimeException(
 143                "LockOwner Id = " + info.getLockOwnerId() +
 144                " expected = " + values[LOCK_OWNER_ID]);
 145         }
 146         if (!info.getLockOwnerName().equals(values[LOCK_OWNER_NAME])) {
 147             throw new RuntimeException("LockOwner Name = " +
 148                info.getLockOwnerName() + " expected = " +
 149                values[LOCK_OWNER_NAME]);
 150         }
 151         if (!values[DAEMON].equals(info.isDaemon())) {
 152             throw new RuntimeException("Daemon = " +
 153                info.isDaemon() + " expected = " +
 154                values[DAEMON]);
 155         }
 156 
 157         checkStackTrace(info.getStackTrace());
 158 
 159         checkLockInfo(info.getLockInfo());
 160     }
 161 
 162     private static void checkStackTrace(StackTraceElement[] s)
 163         throws Exception {
 164         if (ste.length != s.length) {
 165             throw new RuntimeException("Stack Trace length = " +
 166                 s.length + " expected = " + ste.length);
 167         }
 168 
 169         StackTraceElement s1 = ste[0];
 170         StackTraceElement s2 = s[0];
 171 
 172         if (!s1.getClassName().equals(s2.getClassName())) {
 173             throw new RuntimeException("Class name = " +
 174                 s2.getClassName() + " expected = " + s1.getClassName());
 175         }
 176         if (!s1.getMethodName().equals(s2.getMethodName())) {
 177             throw new RuntimeException("Method name = " +
 178                 s2.getMethodName() + " expected = " + s1.getMethodName());
 179         }
 180         if (!s1.getFileName().equals(s2.getFileName())) {
 181             throw new RuntimeException("File name = " +
 182                 s2.getFileName() + " expected = " + s1.getFileName());
 183         }
 184         if (s1.getLineNumber() != s2.getLineNumber()) {
 185             throw new RuntimeException("Line number = " +
 186                 s2.getLineNumber() + " expected = " + s1.getLineNumber());
 187         }
 188     }
 189 
 190     private static void checkLockInfo(LockInfo li)
 191         throws Exception {
 192         if (!li.getClassName().equals(lockInfo.getClassName())) {
 193             throw new RuntimeException("Class Name = " +
 194                 li.getClassName() + " expected = " + lockInfo.getClassName());
 195         }
 196         if (li.getIdentityHashCode() != lockInfo.getIdentityHashCode()) {
 197             throw new RuntimeException("Class Name = " +
 198                 li.getIdentityHashCode() + " expected = " +
 199                 lockInfo.getIdentityHashCode());
 200         }
 201     }
 202 
 203     public static void badNameCompositeData() throws Exception {
 204         CompositeType ct =
 205             new CompositeType("MyCompositeType",
 206                               "CompositeType for ThreadInfo",
 207                               badItemNames,
 208                               badItemNames,
 209                               validItemTypes);
 210         CompositeData cd =
 211             new CompositeDataSupport(ct,
 212                                      badItemNames,
 213                                      values);
 214 
 215         try {
 216             ThreadInfo info = ThreadInfo.from(cd);
 217         } catch (IllegalArgumentException e) {
 218             System.out.println("Expected exception: " +
 219                 e.getMessage());
 220             return;
 221         }
 222         throw new RuntimeException(
 223             "IllegalArgumentException not thrown");
 224     }
 225 
 226     public static void badTypeCompositeData() throws Exception {
 227         CompositeType ct =
 228             new CompositeType("MyCompositeType",
 229                               "CompositeType for ThreadInfo",
 230                               validItemNames,
 231                               validItemNames,
 232                               badItemTypes);
 233 
 234         // patch values[STACK_TRACE] to Long
 235         values[STACK_TRACE] = new Long(1000);
 236         values[LOCK_INFO] = new Long(1000);
 237         CompositeData cd =
 238             new CompositeDataSupport(ct,
 239                                      validItemNames,
 240                                      values);
 241 
 242         try {
 243             ThreadInfo info = ThreadInfo.from(cd);
 244         } catch (IllegalArgumentException e) {
 245             System.out.println("Expected exception: " +
 246                 e.getMessage());
 247             return;
 248         }
 249         throw new RuntimeException(
 250             "IllegalArgumentException not thrown");
 251     }
 252 
 253     private static final int THREAD_ID       = 0;
 254     private static final int THREAD_NAME     = 1;
 255     private static final int THREAD_STATE    = 2;
 256     private static final int BLOCKED_TIME    = 3;
 257     private static final int BLOCKED_COUNT   = 4;
 258     private static final int WAITED_TIME     = 5;
 259     private static final int WAITED_COUNT    = 6;
 260     private static final int LOCK_NAME       = 7;
 261     private static final int LOCK_OWNER_ID   = 8;
 262     private static final int LOCK_OWNER_NAME = 9;
 263     private static final int STACK_TRACE     = 10;
 264     private static final int SUSPENDED       = 11;
 265     private static final int IN_NATIVE       = 12;
 266     private static final int NUM_V5_ATTS     = 13;
 267     // JDK 6.0 ThreadInfo attributes
 268     private static final int LOCK_INFO       = 13;
 269     // JDK 9.0 ThreadInfo attributes
 270     private static final int DAEMON          = 14;
 271     private static final int PRIORITY        = 15;
 272 
 273     private static final String[] validItemNames = {
 274         "threadId",
 275         "threadName",
 276         "threadState",
 277         "blockedTime",
 278         "blockedCount",
 279         "waitedTime",
 280         "waitedCount",
 281         "lockName",
 282         "lockOwnerId",
 283         "lockOwnerName",
 284         "stackTrace",
 285         "suspended",
 286         "inNative",
 287         "lockInfo",
 288         "daemon",
 289         "priority",
 290     };
 291 
 292     private static OpenType[] validItemTypes = {
 293         SimpleType.LONG,
 294         SimpleType.STRING,
 295         SimpleType.STRING,
 296         SimpleType.LONG,
 297         SimpleType.LONG,
 298         SimpleType.LONG,
 299         SimpleType.LONG,
 300         SimpleType.STRING,
 301         SimpleType.LONG,
 302         SimpleType.STRING,
 303         null,  // ArrayType for StackTraceElement[]
 304         SimpleType.BOOLEAN,
 305         SimpleType.BOOLEAN,
 306         null,  // CompositeType for LockInfo
 307         SimpleType.BOOLEAN,
 308         SimpleType.INTEGER,
 309     };
 310 
 311     private static Object[] values = {
 312         new Long(100),
 313         "FooThread",
 314         "RUNNABLE",
 315         new Long(200),
 316         new Long(10),
 317         new Long(300),
 318         new Long(20),
 319         lockName,
 320         new Long(99),
 321         "BarThread",
 322         steCD,
 323         new Boolean(false),
 324         new Boolean(false),
 325         null, // To be initialized to lockInfoCD
 326         new Boolean(false),
 327         Thread.NORM_PRIORITY,
 328     };
 329 
 330     private static final String[] steItemNames = {
 331         "className",
 332         "methodName",
 333         "fileName",
 334         "lineNumber",
 335         "nativeMethod",
 336     };
 337 
 338     private static final String[] lockInfoItemNames = {
 339         "className",
 340         "identityHashCode",
 341     };
 342 
 343     static {
 344         // create stack trace element
 345         ste[0] = new StackTraceElement("FooClass", "getFoo", "Foo.java", 100);
 346 
 347         // initialize the ste[0] and values and validItemTypes
 348         try {
 349             CompositeType steCType = (CompositeType)
 350                 OpenTypeConverter.toOpenType(StackTraceElement.class);
 351             validItemTypes[STACK_TRACE] = new ArrayType(1, steCType);
 352 
 353             final Object[] steValue = {
 354                 ste[0].getClassName(),
 355                 ste[0].getMethodName(),
 356                 ste[0].getFileName(),
 357                 new Integer(ste[0].getLineNumber()),
 358                 new Boolean(ste[0].isNativeMethod()),
 359             };
 360 
 361             steCD[0] =
 362                 new CompositeDataSupport(steCType,
 363                                          steItemNames,
 364                                          steValue);
 365 
 366             CompositeType lockInfoCType = (CompositeType)
 367                 OpenTypeConverter.toOpenType(LockInfo.class);
 368             validItemTypes[LOCK_INFO] = lockInfoCType;
 369 
 370             final Object[] lockInfoValue = {
 371                 lockInfo.getClassName(),
 372                 lockInfo.getIdentityHashCode(),
 373             };
 374 
 375             values[LOCK_INFO] =
 376                 new CompositeDataSupport(lockInfoCType,
 377                                          lockInfoItemNames,
 378                                          lockInfoValue);
 379         } catch (Exception e) {
 380             throw new RuntimeException(e);
 381         }
 382     }
 383 
 384     private static final String[] badItemNames = {
 385         "threadId",
 386         "threadName",
 387         "threadState",
 388         "blockedTime",
 389         "blockedCount",
 390         "waitedTime",
 391         "waitedCount",
 392         "lockName",
 393         "lockOwnerId",
 394         "lockOwnerName",
 395         "BadStackTrace", // bad item name
 396         "suspended",
 397         "inNative",
 398         "lockInfo",
 399         "daemon",
 400         "priority",
 401     };
 402     private static final OpenType[] badItemTypes = {
 403         SimpleType.LONG,
 404         SimpleType.STRING,
 405         SimpleType.STRING,
 406         SimpleType.LONG,
 407         SimpleType.LONG,
 408         SimpleType.LONG,
 409         SimpleType.LONG,
 410         SimpleType.STRING,
 411         SimpleType.LONG,
 412         SimpleType.STRING,
 413         SimpleType.LONG,  // bad type
 414         SimpleType.BOOLEAN,
 415         SimpleType.BOOLEAN,
 416         SimpleType.LONG,  // bad type
 417         SimpleType.BOOLEAN,
 418         SimpleType.INTEGER,
 419     };
 420 
 421 }