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  * @compile OpenTypeConverter.java
  33  * @build ThreadInfoCompositeData
  34  * @run main ThreadInfoCompositeData
  35  */
  36 
  37 import javax.management.openmbean.*;
  38 import java.lang.management.LockInfo;
  39 import java.lang.management.MonitorInfo;
  40 import java.lang.management.ThreadInfo;
  41 import java.util.Objects;
  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 (!Objects.equals(s1.getModuleName(), s2.getModuleName())) {
 177             throw new RuntimeException("Module name = " +
 178                 s2.getModuleName() + " expected = " + s1.getModuleName());
 179         }
 180         if (!Objects.equals(s1.getModuleVersion(), s2.getModuleVersion())) {
 181             throw new RuntimeException("Module version = " +
 182                 s2.getModuleVersion() + " expected = " + s1.getModuleVersion());
 183         }
 184         if (!s1.getMethodName().equals(s2.getMethodName())) {
 185             throw new RuntimeException("Method name = " +
 186                 s2.getMethodName() + " expected = " + s1.getMethodName());
 187         }
 188         if (!s1.getFileName().equals(s2.getFileName())) {
 189             throw new RuntimeException("File name = " +
 190                 s2.getFileName() + " expected = " + s1.getFileName());
 191         }
 192         if (s1.getLineNumber() != s2.getLineNumber()) {
 193             throw new RuntimeException("Line number = " +
 194                 s2.getLineNumber() + " expected = " + s1.getLineNumber());
 195         }
 196     }
 197 
 198     private static void checkLockInfo(LockInfo li)
 199         throws Exception {
 200         if (!li.getClassName().equals(lockInfo.getClassName())) {
 201             throw new RuntimeException("Class Name = " +
 202                 li.getClassName() + " expected = " + lockInfo.getClassName());
 203         }
 204         if (li.getIdentityHashCode() != lockInfo.getIdentityHashCode()) {
 205             throw new RuntimeException("Class Name = " +
 206                 li.getIdentityHashCode() + " expected = " +
 207                 lockInfo.getIdentityHashCode());
 208         }
 209     }
 210 
 211     public static void badNameCompositeData() throws Exception {
 212         CompositeType ct =
 213             new CompositeType("MyCompositeType",
 214                               "CompositeType for ThreadInfo",
 215                               badItemNames,
 216                               badItemNames,
 217                               validItemTypes);
 218         CompositeData cd =
 219             new CompositeDataSupport(ct,
 220                                      badItemNames,
 221                                      values);
 222 
 223         try {
 224             ThreadInfo info = ThreadInfo.from(cd);
 225         } catch (IllegalArgumentException e) {
 226             System.out.println("Expected exception: " +
 227                 e.getMessage());
 228             return;
 229         }
 230         throw new RuntimeException(
 231             "IllegalArgumentException not thrown");
 232     }
 233 
 234     public static void badTypeCompositeData() throws Exception {
 235         CompositeType ct =
 236             new CompositeType("MyCompositeType",
 237                               "CompositeType for ThreadInfo",
 238                               validItemNames,
 239                               validItemNames,
 240                               badItemTypes);
 241 
 242         // patch values[STACK_TRACE] to Long
 243         values[STACK_TRACE] = new Long(1000);
 244         values[LOCK_INFO] = new Long(1000);
 245         CompositeData cd =
 246             new CompositeDataSupport(ct,
 247                                      validItemNames,
 248                                      values);
 249 
 250         try {
 251             ThreadInfo info = ThreadInfo.from(cd);
 252         } catch (IllegalArgumentException e) {
 253             System.out.println("Expected exception: " +
 254                 e.getMessage());
 255             return;
 256         }
 257         throw new RuntimeException(
 258             "IllegalArgumentException not thrown");
 259     }
 260 
 261     private static final int THREAD_ID       = 0;
 262     private static final int THREAD_NAME     = 1;
 263     private static final int THREAD_STATE    = 2;
 264     private static final int BLOCKED_TIME    = 3;
 265     private static final int BLOCKED_COUNT   = 4;
 266     private static final int WAITED_TIME     = 5;
 267     private static final int WAITED_COUNT    = 6;
 268     private static final int LOCK_NAME       = 7;
 269     private static final int LOCK_OWNER_ID   = 8;
 270     private static final int LOCK_OWNER_NAME = 9;
 271     private static final int STACK_TRACE     = 10;
 272     private static final int SUSPENDED       = 11;
 273     private static final int IN_NATIVE       = 12;
 274     private static final int NUM_V5_ATTS     = 13;
 275     // JDK 6.0 ThreadInfo attributes
 276     private static final int LOCK_INFO       = 13;
 277     // JDK 9.0 ThreadInfo attributes
 278     private static final int DAEMON          = 14;
 279     private static final int PRIORITY        = 15;
 280 
 281     private static final String[] validItemNames = {
 282         "threadId",
 283         "threadName",
 284         "threadState",
 285         "blockedTime",
 286         "blockedCount",
 287         "waitedTime",
 288         "waitedCount",
 289         "lockName",
 290         "lockOwnerId",
 291         "lockOwnerName",
 292         "stackTrace",
 293         "suspended",
 294         "inNative",
 295         "lockInfo",
 296         "daemon",
 297         "priority",
 298     };
 299 
 300     private static OpenType[] validItemTypes = {
 301         SimpleType.LONG,
 302         SimpleType.STRING,
 303         SimpleType.STRING,
 304         SimpleType.LONG,
 305         SimpleType.LONG,
 306         SimpleType.LONG,
 307         SimpleType.LONG,
 308         SimpleType.STRING,
 309         SimpleType.LONG,
 310         SimpleType.STRING,
 311         null,  // ArrayType for StackTraceElement[]
 312         SimpleType.BOOLEAN,
 313         SimpleType.BOOLEAN,
 314         null,  // CompositeType for LockInfo
 315         SimpleType.BOOLEAN,
 316         SimpleType.INTEGER,
 317     };
 318 
 319     private static Object[] values = {
 320         new Long(100),
 321         "FooThread",
 322         "RUNNABLE",
 323         new Long(200),
 324         new Long(10),
 325         new Long(300),
 326         new Long(20),
 327         lockName,
 328         new Long(99),
 329         "BarThread",
 330         steCD,
 331         new Boolean(false),
 332         new Boolean(false),
 333         null, // To be initialized to lockInfoCD
 334         new Boolean(false),
 335         Thread.NORM_PRIORITY,
 336     };
 337 
 338     private static final String[] steItemNames = {
 339         "classLoaderName",
 340         "moduleName",
 341         "moduleVersion",
 342         "className",
 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].getClassLoaderName(),
 366                 ste[0].getModuleName(),
 367                 ste[0].getModuleVersion(),
 368                 ste[0].getClassName(),
 369                 ste[0].getMethodName(),
 370                 ste[0].getFileName(),
 371                 new Integer(ste[0].getLineNumber()),
 372                 new Boolean(ste[0].isNativeMethod()),
 373             };
 374 
 375             steCD[0] =
 376                 new CompositeDataSupport(steCType,
 377                                          steItemNames,
 378                                          steValue);
 379 
 380             CompositeType lockInfoCType = (CompositeType)
 381                 OpenTypeConverter.toOpenType(LockInfo.class);
 382             validItemTypes[LOCK_INFO] = lockInfoCType;
 383 
 384             final Object[] lockInfoValue = {
 385                 lockInfo.getClassName(),
 386                 lockInfo.getIdentityHashCode(),
 387             };
 388 
 389             values[LOCK_INFO] =
 390                 new CompositeDataSupport(lockInfoCType,
 391                                          lockInfoItemNames,
 392                                          lockInfoValue);
 393         } catch (Exception e) {
 394             throw new RuntimeException(e);
 395         }
 396     }
 397 
 398     private static final String[] badItemNames = {
 399         "threadId",
 400         "threadName",
 401         "threadState",
 402         "blockedTime",
 403         "blockedCount",
 404         "waitedTime",
 405         "waitedCount",
 406         "lockName",
 407         "lockOwnerId",
 408         "lockOwnerName",
 409         "BadStackTrace", // bad item name
 410         "suspended",
 411         "inNative",
 412         "lockInfo",
 413         "daemon",
 414         "priority",
 415     };
 416     private static final OpenType[] badItemTypes = {
 417         SimpleType.LONG,
 418         SimpleType.STRING,
 419         SimpleType.STRING,
 420         SimpleType.LONG,
 421         SimpleType.LONG,
 422         SimpleType.LONG,
 423         SimpleType.LONG,
 424         SimpleType.STRING,
 425         SimpleType.LONG,
 426         SimpleType.STRING,
 427         SimpleType.LONG,  // bad type
 428         SimpleType.BOOLEAN,
 429         SimpleType.BOOLEAN,
 430         SimpleType.LONG,  // bad type
 431         SimpleType.BOOLEAN,
 432         SimpleType.INTEGER,
 433     };
 434 
 435 }