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