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