1 /*
   2  * Copyright (c) 2004, 2018, 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 8198253
  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/sun.management
  33  * @build ThreadInfoCompositeData OpenTypeConverter
  34  * @run testng/othervm ThreadInfoCompositeData
  35  */
  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.Arrays;
  43 import java.util.Objects;
  44 import java.util.stream.Stream;
  45 
  46 import org.testng.annotations.Test;
  47 import static org.testng.Assert.*;
  48 
  49 public class ThreadInfoCompositeData {
  50     private static String lockClassName = "myClass";
  51     private static int lockIdentityHashCode = 123456;
  52     private static String lockName = lockClassName + '@' +
  53         Integer.toHexString(lockIdentityHashCode);
  54     private static LockInfo lockInfo =
  55         new LockInfo(lockClassName, lockIdentityHashCode);
  56 
  57     @Test
  58     public static void createGoodCompositeData() throws Exception {
  59         CompositeData cd = Factory.makeThreadInfoCompositeData();
  60         ThreadInfo info = ThreadInfo.from(cd);
  61         checkThreadInfo(info);
  62     }
  63 
  64     /*
  65      * An invalid CompositeData with JDK 9 attributes but missing JDK 6 attributes
  66      */
  67     @Test
  68     public static void badMissingCompositeData() throws Exception {
  69         CompositeData cd = Factory.makeCompositeDataMissingV6();
  70         try {
  71             ThreadInfo info = ThreadInfo.from(cd);
  72             throw new RuntimeException("IllegalArgumentException not thrown");
  73         } catch (IllegalArgumentException e) {}
  74     }
  75 
  76     static final StackTraceElement STE =
  77         new StackTraceElement("FooClass", "getFoo", "Foo.java", 100);
  78 
  79 
  80     /*
  81      * Current version of ThreadInfo but an older version of StackTraceElement
  82      */
  83     @Test
  84     public static void withV5StackTraceCompositeData() throws Exception {
  85         CompositeData cd = Factory.makeThreadInfoWithV5StackTrace();
  86         try {
  87             ThreadInfo info = ThreadInfo.from(cd);
  88             throw new RuntimeException("IllegalArgumentException not thrown");
  89         } catch (IllegalArgumentException e) {}
  90     }
  91 
  92     /*
  93      * Current version of ThreadInfo but an older version of MonitorInfo
  94      * and the value of "lockedStackFrame" attribute is null.
  95      */
  96     @Test
  97     public static void withInvalidMonitorInfoCompositeData() throws Exception {
  98         CompositeData cd = Factory.makeThreadInfoWithIncompatibleMonitorInfo();
  99 
 100         // verify MonitorInfo is valid
 101         CompositeData[] monitors = (CompositeData[])cd.get("lockedMonitors");
 102         CompositeData ste = (CompositeData)monitors[0].get("lockedStackFrame");
 103         if (((Integer)monitors[0].get("lockedStackDepth")) >= 0 || ste != null) {
 104             throw new RuntimeException("Expected negative stack depth and null stack frame");
 105         }
 106         MonitorInfo minfo = MonitorInfo.from(monitors[0]);
 107         checkLockInfo(minfo);
 108         if (minfo.getLockedStackFrame() != null) {
 109             throw new RuntimeException("Expected null stack frame");
 110         }
 111 
 112         try {
 113             ThreadInfo info = ThreadInfo.from(cd);
 114             throw new RuntimeException("IllegalArgumentException not thrown");
 115         } catch (IllegalArgumentException e) {}
 116     }
 117 
 118     /*
 119      * ThreadInfo of version N can accept lockedMonitors of version >= N
 120      */
 121     @Test
 122     public static void withNewMonitorInfoCompositeData() throws Exception {
 123         CompositeData cd = Factory.makeThreadInfoWithNewMonitorInfo();
 124         ThreadInfo info = ThreadInfo.from(cd);
 125         checkThreadInfo(info);
 126     }
 127 
 128     /*
 129      * Test CompositeData representing JDK 5 ThreadInfo
 130      */
 131     @Test
 132     public static void createV5ThreadInfo() throws Exception {
 133         CompositeData cd = Factory.makeThreadInfoV5CompositeData();
 134         ThreadInfo info = ThreadInfo.from(cd);
 135         checkThreadInfoV5(info);
 136     }
 137 
 138     /*
 139      * Test ThreadInfoCompositeData.toCompositeData
 140      */
 141     @Test
 142     public static void internalToCompositeData() throws Exception {
 143         CompositeData cd = Factory.makeThreadInfoCompositeData();
 144         ThreadInfo info = ThreadInfo.from(cd);
 145         cd = sun.management.ThreadInfoCompositeData.toCompositeData(info);
 146         info = ThreadInfo.from(cd);
 147         checkThreadInfo(info);
 148     }
 149 
 150    static void checkThreadInfoV5(ThreadInfo info) {
 151        Object[] values = Factory.VALUES;
 152 
 153        if (info.getThreadId() != ((Long) values[THREAD_ID]).longValue()) {
 154             throw new RuntimeException("Thread Id = " + info.getThreadId() +
 155                " expected = " + values[THREAD_ID]);
 156         }
 157         if (!info.getThreadName().equals(values[THREAD_NAME])) {
 158             throw new RuntimeException("Thread Name = " +
 159                info.getThreadName() + " expected = " + values[THREAD_NAME]);
 160         }
 161         if (info.getThreadState() != Thread.State.RUNNABLE) {
 162             throw new RuntimeException("Thread Name = " +
 163                info.getThreadName() + " expected = " + Thread.State.RUNNABLE);
 164         }
 165         if (info.getBlockedTime() != ((Long) values[BLOCKED_TIME]).longValue()) {
 166             throw new RuntimeException("blocked time = " +
 167                info.getBlockedTime() +
 168                " expected = " + values[BLOCKED_TIME]);
 169         }
 170         if (info.getBlockedCount() != ((Long) values[BLOCKED_COUNT]).longValue()) {
 171             throw new RuntimeException("blocked count = " +
 172                info.getBlockedCount() +
 173                " expected = " + values[BLOCKED_COUNT]);
 174         }
 175         if (info.getWaitedTime() != ((Long) values[WAITED_TIME]).longValue()) {
 176             throw new RuntimeException("waited time = " +
 177                info.getWaitedTime() +
 178                " expected = " + values[WAITED_TIME]);
 179         }
 180         if (info.getWaitedCount() != ((Long) values[WAITED_COUNT]).longValue()) {
 181             throw new RuntimeException("waited count = " +
 182                info.getWaitedCount() +
 183                " expected = " + values[WAITED_COUNT]);
 184         }
 185         if (!info.getLockName().equals(values[LOCK_NAME])) {
 186             throw new RuntimeException("Lock Name = " +
 187                info.getLockName() + " expected = " + values[LOCK_NAME]);
 188         }
 189         if (info.getLockOwnerId() !=
 190                 ((Long) values[LOCK_OWNER_ID]).longValue()) {
 191             throw new RuntimeException(
 192                "LockOwner Id = " + info.getLockOwnerId() +
 193                " expected = " + values[LOCK_OWNER_ID]);
 194         }
 195         if (!info.getLockOwnerName().equals(values[LOCK_OWNER_NAME])) {
 196             throw new RuntimeException("LockOwner Name = " +
 197                info.getLockOwnerName() + " expected = " +
 198                values[LOCK_OWNER_NAME]);
 199         }
 200 
 201         checkStackTrace(info.getStackTrace());
 202         checkLockInfo(info.getLockInfo());
 203    }
 204 
 205     static void checkThreadInfo(ThreadInfo info) {
 206         Object[] values = Factory.VALUES;
 207 
 208         checkThreadInfoV5(info);
 209 
 210         if (!values[DAEMON].equals(info.isDaemon())) {
 211             throw new RuntimeException("Daemon = " +
 212                info.isDaemon() + " expected = " + values[DAEMON]);
 213         }
 214     }
 215 
 216     private static void checkStackTrace(StackTraceElement[] s) {
 217         if (s.length != 1) {
 218             throw new RuntimeException("Stack Trace length = " +
 219                 s.length + " expected = 1");
 220         }
 221 
 222         StackTraceElement s1 = STE;
 223         StackTraceElement s2 = s[0];
 224 
 225         // these attributes may be null
 226         if (!Objects.equals(s1.getClassLoaderName(), s2.getClassLoaderName())) {
 227             throw new RuntimeException("Class loader name = " +
 228                 s2.getClassLoaderName() + " expected = " + s1.getClassLoaderName());
 229         }
 230         if (!Objects.equals(s1.getModuleName(), s2.getModuleName())) {
 231             throw new RuntimeException("Module name = " +
 232                 s2.getModuleName() + " expected = " + s1.getModuleName());
 233         }
 234         if (!Objects.equals(s1.getModuleVersion(), s2.getModuleVersion())) {
 235             throw new RuntimeException("Module version = " +
 236                 s2.getModuleVersion() + " expected = " + s1.getModuleVersion());
 237         }
 238 
 239         if (!s1.getClassName().equals(s2.getClassName())) {
 240             throw new RuntimeException("Class name = " +
 241                 s2.getClassName() + " expected = " + s1.getClassName());
 242         }
 243         if (!s1.getMethodName().equals(s2.getMethodName())) {
 244             throw new RuntimeException("Method name = " +
 245                 s2.getMethodName() + " expected = " + s1.getMethodName());
 246         }
 247         if (!s1.getFileName().equals(s2.getFileName())) {
 248             throw new RuntimeException("File name = " +
 249                 s2.getFileName() + " expected = " + s1.getFileName());
 250         }
 251         if (s1.getLineNumber() != s2.getLineNumber()) {
 252             throw new RuntimeException("Line number = " +
 253                 s2.getLineNumber() + " expected = " + s1.getLineNumber());
 254         }
 255     }
 256 
 257     private static void checkLockInfo(LockInfo li) {
 258         if (!li.getClassName().equals(lockInfo.getClassName())) {
 259             throw new RuntimeException("Class Name = " +
 260                 li.getClassName() + " expected = " + lockInfo.getClassName());
 261         }
 262         if (li.getIdentityHashCode() != lockInfo.getIdentityHashCode()) {
 263             throw new RuntimeException("Class Name = " +
 264                 li.getIdentityHashCode() + " expected = " +
 265                 lockInfo.getIdentityHashCode());
 266         }
 267     }
 268 
 269     @Test
 270     public static void badNameCompositeData() throws Exception {
 271         CompositeData cd = Factory.makeCompositeDataWithBadNames();
 272         try {
 273             ThreadInfo info = ThreadInfo.from(cd);
 274             throw new RuntimeException("IllegalArgumentException not thrown");
 275         } catch (IllegalArgumentException e) { }
 276     }
 277 
 278     @Test
 279     public static void badTypeCompositeData() throws Exception {
 280         CompositeData cd = Factory.makeCompositeDataWithBadTypes();
 281 
 282         try {
 283             ThreadInfo info = ThreadInfo.from(cd);
 284             throw new RuntimeException("IllegalArgumentException not thrown");
 285         } catch (IllegalArgumentException e) { }
 286     }
 287 
 288     private static final int THREAD_ID = 0;
 289     private static final int THREAD_NAME = 1;
 290     private static final int THREAD_STATE = 2;
 291     private static final int BLOCKED_TIME = 3;
 292     private static final int BLOCKED_COUNT = 4;
 293     private static final int WAITED_TIME = 5;
 294     private static final int WAITED_COUNT = 6;
 295     private static final int LOCK_NAME = 7;
 296     private static final int LOCK_OWNER_ID = 8;
 297     private static final int LOCK_OWNER_NAME = 9;
 298     private static final int STACK_TRACE = 10;
 299     private static final int SUSPENDED = 11;
 300     private static final int IN_NATIVE = 12;
 301     // JDK 6 ThreadInfo attributes
 302     private static final int LOCK_INFO = 13;
 303     private static final int LOCKED_MONITORS = 14;
 304     private static final int LOCKED_SYNCS = 15;
 305     // JDK 9 ThreadInfo attributes
 306     private static final int DAEMON = 16;
 307     private static final int PRIORITY = 17;
 308 
 309     private static class Factory {
 310 
 311         static final CompositeType STE_COMPOSITE_TYPE;
 312         static final CompositeType LOCK_INFO_COMPOSITE_TYPE;
 313         static final CompositeType MONITOR_INFO_COMPOSITE_TYPE;
 314         static final ArrayType STE_ARRAY_COMPOSITE_TYPE;
 315         static final ArrayType LOCK_INFO_ARRAY_COMPOSITE_TYPE;
 316         static final ArrayType MONITOR_INFO_ARRAY_COMPOSITE_TYPE;
 317 
 318         static {
 319             CompositeType steCType = null;
 320             CompositeType lockInfoCType = null;
 321             CompositeType monitorInfoCType = null;
 322             ArrayType steArrayType = null;
 323             ArrayType lockInfoArrayType = null;
 324             ArrayType monitorInfoArrayType = null;
 325 
 326             try {
 327                 steCType = (CompositeType) OpenTypeConverter.toOpenType(StackTraceElement.class);
 328                 lockInfoCType = (CompositeType) OpenTypeConverter.toOpenType(LockInfo.class);
 329                 monitorInfoCType = (CompositeType) OpenTypeConverter.toOpenType(MonitorInfo.class);
 330                 steArrayType = new ArrayType(1, steCType);
 331                 lockInfoArrayType = new ArrayType(1, lockInfoCType);
 332                 monitorInfoArrayType = new ArrayType(1, monitorInfoCType);
 333             } catch (Exception e) {
 334                 throw new RuntimeException(e);
 335             }
 336             STE_COMPOSITE_TYPE = steCType;
 337             LOCK_INFO_COMPOSITE_TYPE = lockInfoCType;
 338             MONITOR_INFO_COMPOSITE_TYPE = monitorInfoCType;
 339             STE_ARRAY_COMPOSITE_TYPE = steArrayType;
 340             LOCK_INFO_ARRAY_COMPOSITE_TYPE = lockInfoArrayType;
 341             MONITOR_INFO_ARRAY_COMPOSITE_TYPE = monitorInfoArrayType;
 342         }
 343 
 344         static CompositeData makeThreadInfoCompositeData() throws OpenDataException {
 345             CompositeType ct = new CompositeType("MyCompositeType",
 346                 "CompositeType for ThreadInfo",
 347                 ITEM_NAMES,
 348                 ITEM_NAMES,
 349                 ITEM_TYPES);
 350             return new CompositeDataSupport(ct, ITEM_NAMES, VALUES);
 351         }
 352 
 353         static CompositeData makeThreadInfoV5CompositeData() throws OpenDataException {
 354             CompositeType ct = new CompositeType("MyCompositeType",
 355                 "CompositeType for JDK 5 ThreadInfo",
 356                 V5_ITEM_NAMES,
 357                 V5_ITEM_NAMES,
 358                 V5_ITEM_TYPES);
 359             return new CompositeDataSupport(ct, V5_ITEM_NAMES, V5_VALUES);
 360         }
 361 
 362         static CompositeData makeCompositeDataWithBadTypes() throws OpenDataException {
 363             OpenType[] badItemTypes = {
 364                 SimpleType.LONG,
 365                 SimpleType.STRING,
 366                 SimpleType.STRING,
 367                 SimpleType.LONG,
 368                 SimpleType.LONG,
 369                 SimpleType.LONG,
 370                 SimpleType.LONG,
 371                 SimpleType.STRING,
 372                 SimpleType.LONG,
 373                 SimpleType.STRING,
 374                 SimpleType.LONG,  // bad type
 375                 SimpleType.BOOLEAN,
 376                 SimpleType.BOOLEAN,
 377                 SimpleType.LONG,  // bad type
 378                 SimpleType.LONG,  // bad type
 379                 SimpleType.LONG,  // bad type
 380                 SimpleType.BOOLEAN,
 381                 SimpleType.INTEGER,
 382             };
 383 
 384             CompositeType ct =
 385                 new CompositeType("Bad item types",
 386                     "CompositeType for ThreadInfo",
 387                     ITEM_NAMES,
 388                     ITEM_NAMES,
 389                     badItemTypes);
 390 
 391             // Copy before mutating to avoid affecting other tests.
 392             Object[] localValues = VALUES.clone();
 393 
 394             // patch values[STACK_TRACE] to Long
 395             localValues[STACK_TRACE] = Long.valueOf(1000);
 396             localValues[LOCK_INFO] = Long.valueOf(1000);
 397             localValues[LOCKED_MONITORS] = Long.valueOf(1000);
 398             localValues[LOCKED_SYNCS] = Long.valueOf(1000);
 399             return new CompositeDataSupport(ct, ITEM_NAMES, localValues);
 400         }
 401 
 402         static CompositeData makeCompositeDataWithBadNames() throws OpenDataException {
 403             String[] badItemNames = ITEM_NAMES.clone();
 404             badItemNames[STACK_TRACE] = "BadStackTrace"; // bad item name
 405 
 406             CompositeType ct = new CompositeType("Bad item names",
 407                 "CompositeType for ThreadInfo",
 408                 badItemNames,
 409                 badItemNames,
 410                 ITEM_TYPES);
 411             return new CompositeDataSupport(ct,
 412                 badItemNames,
 413                 VALUES);
 414         }
 415 
 416         /*
 417          * Create a CompositeData of ThreadInfo without JDK 6 attributes
 418          */
 419         static CompositeData makeCompositeDataMissingV6() throws OpenDataException {
 420             String[] itemNames = concat(V5_ITEM_NAMES, V9_ITEM_NAMES).toArray(String[]::new);
 421             OpenType[] itemTypes = concat(V5_ITEM_TYPES, V9_ITEM_TYPES).toArray(OpenType[]::new);
 422             Object[] values = concat(V5_VALUES, V9_VALUES).toArray(Object[]::new);
 423 
 424             CompositeType ct =
 425                 new CompositeType("InvalidCompositeType",
 426                     "CompositeType for ThreadInfo",
 427                     itemNames,
 428                     itemNames,
 429                     itemTypes);
 430             return new CompositeDataSupport(ct, itemNames, values);
 431         }
 432 
 433         static CompositeData makeStackTraceElement() {
 434             Object[] steValue = {
 435                 STE.getClassLoaderName(),
 436                 STE.getModuleName(),
 437                 STE.getModuleVersion(),
 438                 STE.getClassName(),
 439                 STE.getMethodName(),
 440                 STE.getFileName(),
 441                 Integer.valueOf(STE.getLineNumber()),
 442                 Boolean.valueOf(STE.isNativeMethod()),
 443             };
 444 
 445             try {
 446                 return new CompositeDataSupport(STE_COMPOSITE_TYPE,
 447                                                 STE_ITEM_NAMES,
 448                                                 steValue);
 449             } catch (OpenDataException e) {
 450                 throw new RuntimeException(e);
 451             }
 452         }
 453 
 454         static CompositeData makeStackTraceElementV5() throws OpenDataException {
 455             CompositeType steV5CType =
 456                 new CompositeType("JDK 5 StackTraceElement",
 457                     "CompositeType for JDK 5 StackTraceElement",
 458                     STE_V5_ITEM_NAMES,
 459                     STE_V5_ITEM_NAMES,
 460                     STE_V5_ITEM_TYPES);
 461 
 462             Object[] steV5Value = {
 463                 STE.getClassName(),
 464                 STE.getMethodName(),
 465                 STE.getFileName(),
 466                 Integer.valueOf(STE.getLineNumber()),
 467                 Boolean.valueOf(STE.isNativeMethod()),
 468             };
 469 
 470             return new CompositeDataSupport(steV5CType, STE_V5_ITEM_NAMES, steV5Value);
 471         }
 472 
 473         /*
 474          * Create a CompositeData of ThreadInfo without JDK 5 StackTraceElement
 475          */
 476         static CompositeData makeThreadInfoWithV5StackTrace() throws OpenDataException {
 477             OpenType[] badTypes = ITEM_TYPES.clone();
 478             Object[] badValues = VALUES.clone();
 479 
 480             CompositeData[] stackTrace = new CompositeData[1];
 481             stackTrace[0] = makeStackTraceElementV5();
 482             badTypes[STACK_TRACE] = new ArrayType(1, stackTrace[0].getCompositeType());
 483             badValues[STACK_TRACE] = stackTrace;
 484             CompositeType ct = new CompositeType("CompositeType",
 485                 "ThreadInfo with JDK 5 StackTraceElement",
 486                 ITEM_NAMES,
 487                 ITEM_NAMES,
 488                 badTypes);
 489             return new CompositeDataSupport(ct, ITEM_NAMES, badValues);
 490         }
 491 
 492         /*
 493          * Create MonitorInfo with JDK 5 StackTraceElement (i.e. JDK 6 MonitorInfo)
 494          * The value of "lockedStackFrame" attribute is null to ensure that
 495          * the validation is done.
 496          */
 497         static CompositeData makeV6MonitorInfo() throws OpenDataException {
 498             CompositeData steV5 = makeStackTraceElementV5();
 499 
 500             String[] names = MONITOR_INFO_COMPOSITE_TYPE.keySet().toArray(new String[0]);
 501             OpenType[] types = new OpenType[names.length];
 502             for (int i=0; i < names.length; i++) {
 503                 String n = names[i];
 504                 types[i] = "lockedStackFrame".equals(n)
 505                                 ? steV5.getCompositeType()
 506                                 : MONITOR_INFO_COMPOSITE_TYPE.getType(n);
 507             }
 508 
 509             CompositeType ctype =
 510                 new CompositeType("JDK 6 MonitorInfo",
 511                     "CompositeType for JDK 6 MonitorInfo",
 512                     names,
 513                     names,
 514                     types);
 515 
 516             Object[] values = {
 517                 lockClassName,
 518                 lockIdentityHashCode,
 519                 -1,
 520                 null
 521             };
 522 
 523             return new CompositeDataSupport(ctype, names, values);
 524         }
 525 
 526         /*
 527          * Create a CompositeData of ThreadInfo with incompatible MonitorInfo
 528          */
 529         static CompositeData makeThreadInfoWithIncompatibleMonitorInfo() throws OpenDataException {
 530             OpenType[] badTypes = ITEM_TYPES.clone();
 531             Object[] badValues = VALUES.clone();
 532 
 533             CompositeData[] lockedMonitors = new CompositeData[1];
 534             lockedMonitors[0] = makeV6MonitorInfo();
 535             badTypes[LOCKED_MONITORS] = new ArrayType(1, lockedMonitors[0].getCompositeType());
 536             badValues[LOCKED_MONITORS] = lockedMonitors;
 537             CompositeType ct = new CompositeType("CompositeType",
 538                 "ThreadInfo with incompatible MonitorInfo",
 539                 ITEM_NAMES,
 540                 ITEM_NAMES,
 541                 badTypes);
 542             return new CompositeDataSupport(ct, ITEM_NAMES, badValues);
 543         }
 544 
 545         static CompositeData makeNewMonitorInfo() throws OpenDataException {
 546             String[] names = Stream.concat(MONITOR_INFO_COMPOSITE_TYPE.keySet().stream(),
 547                                            Stream.of("extra")).toArray(String[]::new);
 548             OpenType[] types = new OpenType[names.length];
 549             for (int i=0; i < names.length; i++) {
 550                 String n = names[i];
 551                 types[i] = "extra".equals(n)
 552                                 ? SimpleType.STRING
 553                                 : MONITOR_INFO_COMPOSITE_TYPE.getType(n);
 554             }
 555 
 556             CompositeType compositeType =
 557                 new CompositeType("JDK X MonitorInfo",
 558                     "CompositeType for JDK X MonitorInfo",
 559                     names,
 560                     names,
 561                     types);
 562 
 563             Object[] values = {
 564                 lockClassName,
 565                 lockIdentityHashCode,
 566                 Integer.valueOf(1),
 567                 makeStackTraceElement(),
 568                 "extra"
 569             };
 570 
 571             return new CompositeDataSupport(compositeType, names, values);
 572         }
 573 
 574         /*
 575          * Create a CompositeData of ThreadInfo with a newer version of MonitorInfo
 576          */
 577         static CompositeData makeThreadInfoWithNewMonitorInfo() throws OpenDataException {
 578             OpenType[] types = ITEM_TYPES.clone();
 579             Object[] badValues = VALUES.clone();
 580 
 581             CompositeData[] lockedMonitors = new CompositeData[1];
 582             lockedMonitors[0] = makeNewMonitorInfo();
 583             types[LOCKED_MONITORS] = new ArrayType(1, lockedMonitors[0].getCompositeType());
 584             badValues[LOCKED_MONITORS] = lockedMonitors;
 585             CompositeType ct = new CompositeType("CompositeType",
 586                             "ThreadInfo with JDK 5 MonitorInfo",
 587                             ITEM_NAMES,
 588                             ITEM_NAMES,
 589                             types);
 590             return new CompositeDataSupport(ct, ITEM_NAMES, badValues);
 591         }
 592 
 593         static CompositeData makeLockInfo() {
 594             Object[] lockInfoValue = {
 595                 lockInfo.getClassName(),
 596                 lockInfo.getIdentityHashCode(),
 597             };
 598 
 599             try {
 600                 return new CompositeDataSupport(LOCK_INFO_COMPOSITE_TYPE,
 601                     LOCK_INFO_ITEM_NAMES,
 602                     lockInfoValue);
 603             } catch (OpenDataException e) {
 604                 throw new RuntimeException(e);
 605             }
 606         }
 607 
 608         static CompositeData[] makeLockedSynchronizers() {
 609             CompositeData[] lockedSyncs = new CompositeData[1];
 610             lockedSyncs[0] = makeLockInfo();
 611             return lockedSyncs;
 612         }
 613 
 614         static CompositeData[] makeLockedMonitors() {
 615             CompositeData[] lockedMonitorsCD = new CompositeData[1];
 616 
 617             Object[] lockedMonitorsValue = {
 618                 lockInfo.getClassName(),
 619                 lockInfo.getIdentityHashCode(),
 620                 makeStackTraceElement(),
 621                 Integer.valueOf(1),
 622             };
 623             try {
 624                 lockedMonitorsCD[0] =
 625                     new CompositeDataSupport(MONITOR_INFO_COMPOSITE_TYPE,
 626                         LOCKED_MONITORS_ITEM_NAMES,
 627                         lockedMonitorsValue);
 628             } catch (OpenDataException e) {
 629                 throw new RuntimeException(e);
 630             }
 631             return lockedMonitorsCD;
 632         }
 633 
 634         static final String[] V5_ITEM_NAMES = {
 635             "threadId",
 636             "threadName",
 637             "threadState",
 638             "blockedTime",
 639             "blockedCount",
 640             "waitedTime",
 641             "waitedCount",
 642             "lockName",
 643             "lockOwnerId",
 644             "lockOwnerName",
 645             "stackTrace",
 646             "suspended",
 647             "inNative",
 648         };
 649 
 650         static final String[] V6_ITEM_NAMES = {
 651             "lockInfo",
 652             "lockedMonitors",
 653             "lockedSynchronizers",
 654         };
 655 
 656         static final String[] V9_ITEM_NAMES = {
 657             "daemon",
 658             "priority",
 659         };
 660 
 661         static final OpenType[] V5_ITEM_TYPES = {
 662             SimpleType.LONG,
 663             SimpleType.STRING,
 664             SimpleType.STRING,
 665             SimpleType.LONG,
 666             SimpleType.LONG,
 667             SimpleType.LONG,
 668             SimpleType.LONG,
 669             SimpleType.STRING,
 670             SimpleType.LONG,
 671             SimpleType.STRING,
 672             STE_ARRAY_COMPOSITE_TYPE,
 673             SimpleType.BOOLEAN,
 674             SimpleType.BOOLEAN,
 675         };
 676 
 677         static final OpenType[] V6_ITEM_TYPES = {
 678             LOCK_INFO_COMPOSITE_TYPE,
 679             MONITOR_INFO_ARRAY_COMPOSITE_TYPE,
 680             LOCK_INFO_ARRAY_COMPOSITE_TYPE,
 681         };
 682 
 683         static final OpenType[] V9_ITEM_TYPES = {
 684             SimpleType.BOOLEAN,
 685             SimpleType.INTEGER,
 686         };
 687 
 688         static final String[] STE_ITEM_NAMES = {
 689             "classLoaderName",
 690             "moduleName",
 691             "moduleVersion",
 692             "className",
 693             "methodName",
 694             "fileName",
 695             "lineNumber",
 696             "nativeMethod",
 697         };
 698 
 699         static final String[] STE_V5_ITEM_NAMES = Arrays.copyOfRange(STE_ITEM_NAMES, 3, 8);
 700 
 701         static final OpenType[] STE_V5_ITEM_TYPES = {
 702             SimpleType.STRING,
 703             SimpleType.STRING,
 704             SimpleType.STRING,
 705             SimpleType.INTEGER,
 706             SimpleType.BOOLEAN
 707         };
 708 
 709         static final String[] LOCK_INFO_ITEM_NAMES = {
 710             "className",
 711             "identityHashCode",
 712         };
 713 
 714         static final String[] LOCKED_MONITORS_ITEM_NAMES = {
 715             LOCK_INFO_ITEM_NAMES[0],
 716             LOCK_INFO_ITEM_NAMES[1],
 717             "lockedStackFrame",
 718             "lockedStackDepth",
 719         };
 720 
 721         static final Object[] V5_VALUES = {
 722             Long.valueOf(100),
 723             "FooThread",
 724             "RUNNABLE",
 725             Long.valueOf(200),
 726             Long.valueOf(10),
 727             Long.valueOf(300),
 728             Long.valueOf(20),
 729             lockName,
 730             Long.valueOf(99),
 731             "BarThread",
 732             new CompositeData[] { makeStackTraceElement() },
 733             Boolean.valueOf(false),
 734             Boolean.valueOf(false),
 735         };
 736 
 737         static final Object[] V6_VALUES = {
 738             makeLockInfo(),
 739             makeLockedMonitors(),
 740             makeLockedSynchronizers(),
 741         };
 742 
 743         static final Object[] V9_VALUES = {
 744             Boolean.valueOf(true),
 745             Thread.NORM_PRIORITY,
 746         };
 747 
 748         static final String[] ITEM_NAMES =
 749             concat(V5_ITEM_NAMES, V6_ITEM_NAMES, V9_ITEM_NAMES).toArray(String[]::new);
 750 
 751         static final OpenType[] ITEM_TYPES =
 752             concat(V5_ITEM_TYPES, V6_ITEM_TYPES, V9_ITEM_TYPES).toArray(OpenType[]::new);
 753 
 754         static final Object[] VALUES =
 755             concat(V5_VALUES, V6_VALUES, V9_VALUES).toArray(Object[]::new);
 756 
 757         static <T> Stream<T> concat(T[]... streams) {
 758             return Stream.of(streams).flatMap(a -> Arrays.stream(a));
 759         }
 760     }
 761 }