# HG changeset patch # User ihse # Date 1519899751 -3600 # Node ID d8ea550b907af9f38d7e28075f352c675f277eb3 # Parent 1c5a3127046f921c96c08932b7e6beaddb1113b4# Parent b1c42b3cd19b6a5c43275ef67f0636f0f3f155b0 Merge with default diff -r 1c5a3127046f -r d8ea550b907a src/java.management/share/classes/java/lang/management/MonitorInfo.java --- a/src/java.management/share/classes/java/lang/management/MonitorInfo.java Thu Mar 01 11:02:40 2018 +0100 +++ b/src/java.management/share/classes/java/lang/management/MonitorInfo.java Thu Mar 01 11:22:31 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -116,11 +116,10 @@ * * * lockedStackFrame - * CompositeData as specified in the - * stackTrace - * attribute defined in the {@link ThreadInfo#from - * ThreadInfo.from} method. - * + * + * {@code CompositeData} for {@code StackTraceElement} as specified + * in {@link ThreadInfo#from(CompositeData)} method. + * * * * lockedStackDepth @@ -134,7 +133,7 @@ * @throws IllegalArgumentException if {@code cd} does not * represent a {@code MonitorInfo} with the attributes described * above. - + * * @return a {@code MonitorInfo} object represented * by {@code cd} if {@code cd} is not {@code null}; * {@code null} otherwise. diff -r 1c5a3127046f -r d8ea550b907a src/java.management/share/classes/java/lang/management/ThreadInfo.java --- a/src/java.management/share/classes/java/lang/management/ThreadInfo.java Thu Mar 01 11:02:40 2018 +0100 +++ b/src/java.management/share/classes/java/lang/management/ThreadInfo.java Thu Mar 01 11:22:31 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package java.lang.management; +import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeData; import sun.management.ManagementFactoryHelper; import sun.management.ThreadInfoCompositeData; @@ -110,7 +111,6 @@ private StackTraceElement[] stackTrace; private MonitorInfo[] lockedMonitors; private LockInfo[] lockedSynchronizers; - private static MonitorInfo[] EMPTY_MONITORS = new MonitorInfo[0]; private static LockInfo[] EMPTY_SYNCS = new LockInfo[0]; @@ -264,6 +264,11 @@ /* * Constructs a {@code ThreadInfo} object from a * {@link CompositeData CompositeData}. + * + * @throws IllegalArgumentException if the given CompositeData does not + * contain all of the attributes defined for ThreadInfo of version <= N. + * + * @see ThreadInfo#from */ private ThreadInfo(CompositeData cd) { ThreadInfoCompositeData ticd = ThreadInfoCompositeData.getInstance(cd); @@ -281,41 +286,11 @@ suspended = ticd.suspended(); inNative = ticd.inNative(); stackTrace = ticd.stackTrace(); - - // 6.0 attributes - if (ticd.hasV6()) { - lock = ticd.lockInfo(); - lockedMonitors = ticd.lockedMonitors(); - lockedSynchronizers = ticd.lockedSynchronizers(); - } else { - // lockInfo is a new attribute added in 1.6 ThreadInfo - // If cd is a 5.0 version, construct the LockInfo object - // from the lockName value. - if (lockName != null) { - String result[] = lockName.split("@"); - if (result.length == 2) { - int identityHashCode = Integer.parseInt(result[1], 16); - lock = new LockInfo(result[0], identityHashCode); - } else { - assert result.length == 2; - lock = null; - } - } else { - lock = null; - } - lockedMonitors = EMPTY_MONITORS; - lockedSynchronizers = EMPTY_SYNCS; - } - - // 9.0 attributes - if (ticd.isCurrentVersion()) { - daemon = ticd.isDaemon(); - priority = ticd.getPriority(); - } else { - // Not ideal, but unclear what else we can do. - daemon = false; - priority = Thread.NORM_PRIORITY; - } + lock = ticd.lockInfo(); + lockedMonitors = ticd.lockedMonitors(); + lockedSynchronizers = ticd.lockedSynchronizers(); + daemon = ticd.isDaemon(); + priority = ticd.getPriority(); } /** @@ -692,52 +667,105 @@ /** * Returns a {@code ThreadInfo} object represented by the * given {@code CompositeData}. - * The given {@code CompositeData} must contain the following attributes - * unless otherwise specified below: + * + * + * A {@code CompositeData} representing a {@code ThreadInfo} of + * version N must contain all of the attributes defined + * in version ≤ N unless specified otherwise. + * The same rule applies the composite type of the given + * {@code CompositeData} and transitively to attributes whose + * {@linkplain CompositeData#getCompositeType() type} or + * {@linkplain ArrayType#getElementOpenType() component type} is + * {@code CompositeType}. + *

+ * A {@code CompositeData} representing {@code ThreadInfo} of + * version N contains {@code "stackTrace"} attribute and + * {@code "lockedMonitors"} attribute representing + * an array of {@code StackTraceElement} and + * an array of {@link MonitorInfo} respectively + * and their types are of version N. + * The {@code "lockedStackFrame"} attribute in + * {@link MonitorInfo#from(CompositeData) MonitorInfo}'s composite type + * must represent {@code StackTraceElement} of the same version N. + * Otherwise, this method will throw {@code IllegalArgumentException}. + * * - * + * * * * * + * * * * * * * + * * * * * + * * * * * + * * * * * + * * * * * + * * * * * + * * * * * + * * * * * + * * * * * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * * * * @@ -745,78 +773,21 @@ * - the mapped type for {@link LockInfo} as specified in the * {@link LockInfo#from} method. *

- * If {@code cd} does not contain this attribute, + * If the given {@code CompositeData} does not contain this attribute, * the {@code LockInfo} object will be constructed from - * the value of the {@code lockName} attribute. - *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * + * the value of the {@code lockName} attribute. + * * * * * + * If the given {@code CompositeData} does not contain this attribute, + * this attribute will be set to an empty array. + * * * * @@ -824,25 +795,93 @@ * whose element type is the mapped type for * {@link LockInfo} as specified in the {@link LockInfo#from} method. *

- * If {@code cd} does not contain this attribute, - * this attribute will be set to an empty array. + * If the given {@code CompositeData} does not contain this attribute, + * this attribute will be set to an empty array. + *

* * * - * + * + * * * * + * + * + * + * + *
The attributes and their types the given CompositeData containsThe attributes and their types for ThreadInfo's composite data
Attribute NameTypeSince
threadId{@code java.lang.Long}5
threadName{@code java.lang.String}5
threadState{@code java.lang.String}5
suspended{@code java.lang.Boolean}5
inNative{@code java.lang.Boolean}5
blockedCount{@code java.lang.Long}5
blockedTime{@code java.lang.Long}5
waitedCount{@code java.lang.Long}5
waitedTime{@code java.lang.Long}5
lockName{@code java.lang.String}5
lockOwnerId{@code java.lang.Long}5
lockOwnerName{@code java.lang.String}5
stackTrace{@code javax.management.openmbean.CompositeData[]}, each element + * is a {@code CompositeData} representing {@code StackTraceElement} + * as specified below. + * 5
lockInfo
lockName{@code java.lang.String}
lockOwnerId{@code java.lang.Long}
lockOwnerName{@code java.lang.String}
stackTrace{@code javax.management.openmbean.CompositeData[]} - *

- * Each element is a {@code CompositeData} representing - * StackTraceElement containing the following attributes: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
The attributes and their types the given CompositeData contains
Attribute NameType
moduleName{@code java.lang.String}
moduleVersion{@code java.lang.String}
className{@code java.lang.String}
methodName{@code java.lang.String}
fileName{@code java.lang.String}
lineNumber{@code java.lang.Integer}
nativeMethod{@code java.lang.Boolean}
- *

6
lockedMonitors{@code javax.management.openmbean.CompositeData[]} * whose element type is the mapped type for * {@link MonitorInfo} as specified in the - * {@link MonitorInfo#from Monitor.from} method. + * {@link MonitorInfo#from MonitorInfo.from} method. *

- * If {@code cd} does not contain this attribute, - * this attribute will be set to an empty array.

6
lockedSynchronizers6
daemon{@code java.lang.Boolean}{@code java.lang.Boolean} + *

+ * If the given {@code CompositeData} does not contain this attribute, + * this attribute will be set to {@code false}.

9
priority{@code java.lang.Integer} + *

+ * If the given {@code CompositeData} does not contain this attribute, + * This attribute will be set to {@link Thread#NORM_PRIORITY}.

9
+ * + * A {@code CompositeData} representing + * {@code StackTraceElement} of version N must contain + * all of the attributes defined in version ≤ N + * unless specified otherwise. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * * + * + * + * + * + * + * * * *
The attributes and their types for StackTraceElement's composite data
Attribute NameTypeSince
classLoaderName{@code java.lang.String}9
moduleName{@code java.lang.String}9
moduleVersion{@code java.lang.String}9
className{@code java.lang.String}5
methodName{@code java.lang.String}5
fileName{@code java.lang.String}5
lineNumber{@code java.lang.Integer}5
nativeMethod{@code java.lang.Boolean}5
* * @param cd {@code CompositeData} representing a {@code ThreadInfo} * - * @throws IllegalArgumentException if {@code cd} does not - * represent a {@code ThreadInfo} with the attributes described - * above. + * @throws IllegalArgumentException if the given {@code cd} and + * its composite type does not contain all of + * the attributes defined for a + * {@code ThreadInfo} of a specific runtime version. * * @return a {@code ThreadInfo} object represented * by {@code cd} if {@code cd} is not {@code null}; diff -r 1c5a3127046f -r d8ea550b907a src/java.management/share/classes/sun/management/LockInfoCompositeData.java --- a/src/java.management/share/classes/sun/management/LockInfoCompositeData.java Thu Mar 01 11:02:40 2018 +0100 +++ b/src/java.management/share/classes/sun/management/LockInfoCompositeData.java Thu Mar 01 11:22:31 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,15 +58,15 @@ protected CompositeData getCompositeData() { // CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH - // lockInfoItemNames! + // LOCK_INFO_ATTRIBUTES! final Object[] lockInfoItemValues = { new String(lock.getClassName()), lock.getIdentityHashCode(), }; try { - return new CompositeDataSupport(lockInfoCompositeType, - lockInfoItemNames, + return new CompositeDataSupport(LOCK_INFO_COMPOSITE_TYPE, + LOCK_INFO_ATTRIBUTES, lockInfoItemValues); } catch (OpenDataException e) { // Should never reach here @@ -74,10 +74,10 @@ } } - private static final CompositeType lockInfoCompositeType; + private static final CompositeType LOCK_INFO_COMPOSITE_TYPE; static { try { - lockInfoCompositeType = (CompositeType) + LOCK_INFO_COMPOSITE_TYPE = (CompositeType) MappedMXBeanType.toOpenType(LockInfo.class); } catch (OpenDataException e) { // Should never reach here @@ -85,13 +85,13 @@ } } - static CompositeType getLockInfoCompositeType() { - return lockInfoCompositeType; + static CompositeType compositeType() { + return LOCK_INFO_COMPOSITE_TYPE; } private static final String CLASS_NAME = "className"; private static final String IDENTITY_HASH_CODE = "identityHashCode"; - private static final String[] lockInfoItemNames = { + private static final String[] LOCK_INFO_ATTRIBUTES = { CLASS_NAME, IDENTITY_HASH_CODE, }; @@ -104,7 +104,7 @@ throw new NullPointerException("Null CompositeData"); } - if (!isTypeMatched(lockInfoCompositeType, cd.getCompositeType())) { + if (!isTypeMatched(LOCK_INFO_COMPOSITE_TYPE, cd.getCompositeType())) { throw new IllegalArgumentException( "Unexpected composite type for LockInfo"); } diff -r 1c5a3127046f -r d8ea550b907a src/java.management/share/classes/sun/management/MonitorInfoCompositeData.java --- a/src/java.management/share/classes/sun/management/MonitorInfoCompositeData.java Thu Mar 01 11:02:40 2018 +0100 +++ b/src/java.management/share/classes/sun/management/MonitorInfoCompositeData.java Thu Mar 01 11:22:31 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; import javax.management.openmbean.OpenDataException; -import java.util.Set; +import javax.management.openmbean.OpenType; /** * A CompositeData for MonitorInfo for the local management support. @@ -55,14 +55,14 @@ protected CompositeData getCompositeData() { // CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH - // monitorInfoItemNames! + // MONITOR_INFO_ATTRIBUTES! - int len = monitorInfoItemNames.length; + int len = MONITOR_INFO_ATTRIBUTES.length; Object[] values = new Object[len]; CompositeData li = LockInfoCompositeData.toCompositeData(lock); for (int i = 0; i < len; i++) { - String item = monitorInfoItemNames[i]; + String item = MONITOR_INFO_ATTRIBUTES[i]; if (item.equals(LOCKED_STACK_FRAME)) { StackTraceElement ste = lock.getLockedStackFrame(); values[i] = (ste != null ? StackTraceElementCompositeData. @@ -76,8 +76,8 @@ } try { - return new CompositeDataSupport(monitorInfoCompositeType, - monitorInfoItemNames, + return new CompositeDataSupport(MONITOR_INFO_COMPOSITE_TYPE, + MONITOR_INFO_ATTRIBUTES, values); } catch (OpenDataException e) { // Should never reach here @@ -85,28 +85,50 @@ } } - private static final CompositeType monitorInfoCompositeType; - private static final String[] monitorInfoItemNames; + private static final String CLASS_NAME = "className"; + private static final String IDENTITY_HASH_CODE = "identityHashCode"; + private static final String LOCKED_STACK_FRAME = "lockedStackFrame"; + private static final String LOCKED_STACK_DEPTH = "lockedStackDepth"; + + private static final String[] MONITOR_INFO_ATTRIBUTES = { + CLASS_NAME, + IDENTITY_HASH_CODE, + LOCKED_STACK_FRAME, + LOCKED_STACK_DEPTH + }; + + private static final CompositeType MONITOR_INFO_COMPOSITE_TYPE; + private static final CompositeType V6_COMPOSITE_TYPE; static { try { - monitorInfoCompositeType = (CompositeType) + MONITOR_INFO_COMPOSITE_TYPE = (CompositeType) MappedMXBeanType.toOpenType(MonitorInfo.class); - Set s = monitorInfoCompositeType.keySet(); - monitorInfoItemNames = s.toArray(new String[0]); + + OpenType[] types = new OpenType[MONITOR_INFO_ATTRIBUTES.length]; + for (int i = 0; i < MONITOR_INFO_ATTRIBUTES.length; i++) { + String name = MONITOR_INFO_ATTRIBUTES[i]; + types[i] = name.equals(LOCKED_STACK_FRAME) + ? StackTraceElementCompositeData.v5CompositeType() + : MONITOR_INFO_COMPOSITE_TYPE.getType(name); + } + V6_COMPOSITE_TYPE = new CompositeType("MonitorInfo", + "JDK 6 MonitorInfo", + MONITOR_INFO_ATTRIBUTES, + MONITOR_INFO_ATTRIBUTES, + types); } catch (OpenDataException e) { // Should never reach here throw new AssertionError(e); } } - static CompositeType getMonitorInfoCompositeType() { - return monitorInfoCompositeType; + static CompositeType v6CompositeType() { + return V6_COMPOSITE_TYPE; } - private static final String CLASS_NAME = "className"; - private static final String IDENTITY_HASH_CODE = "identityHashCode"; - private static final String LOCKED_STACK_FRAME = "lockedStackFrame"; - private static final String LOCKED_STACK_DEPTH = "lockedStackDepth"; + static CompositeType compositeType() { + return MONITOR_INFO_COMPOSITE_TYPE; + } public static String getClassName(CompositeData cd) { return getString(cd, CLASS_NAME); @@ -138,7 +160,8 @@ throw new NullPointerException("Null CompositeData"); } - if (!isTypeMatched(monitorInfoCompositeType, cd.getCompositeType())) { + if (!isTypeMatched(MONITOR_INFO_COMPOSITE_TYPE, cd.getCompositeType()) && + !isTypeMatched(V6_COMPOSITE_TYPE, cd.getCompositeType())) { throw new IllegalArgumentException( "Unexpected composite type for MonitorInfo"); } diff -r 1c5a3127046f -r d8ea550b907a src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java --- a/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java Thu Mar 01 11:02:40 2018 +0100 +++ b/src/java.management/share/classes/sun/management/StackTraceElementCompositeData.java Thu Mar 01 11:22:31 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,13 @@ package sun.management; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Predicate; import javax.management.openmbean.CompositeType; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import java.util.Arrays; +import java.util.stream.Stream; /** * A CompositeData for StackTraceElement for the local management support. @@ -52,12 +52,7 @@ public static StackTraceElement from(CompositeData cd) { validateCompositeData(cd); - if (stackTraceElementV6CompositeType.equals(cd.getCompositeType())) { - return new StackTraceElement(getString(cd, CLASS_NAME), - getString(cd, METHOD_NAME), - getString(cd, FILE_NAME), - getInt(cd, LINE_NUMBER)); - } else { + if (STACK_TRACE_ELEMENT_COMPOSITE_TYPE.equals(cd.getCompositeType())) { return new StackTraceElement(getString(cd, CLASS_LOADER_NAME), getString(cd, MODULE_NAME), getString(cd, MODULE_VERSION), @@ -65,6 +60,12 @@ getString(cd, METHOD_NAME), getString(cd, FILE_NAME), getInt(cd, LINE_NUMBER)); + } else { + return new StackTraceElement(getString(cd, CLASS_NAME), + getString(cd, METHOD_NAME), + getString(cd, FILE_NAME), + getInt(cd, LINE_NUMBER)); + } } @@ -75,7 +76,7 @@ protected CompositeData getCompositeData() { // CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH - // stackTraceElementItemNames! + // STACK_TRACE_ELEMENT_ATTRIBUTES! final Object[] stackTraceElementItemValues = { ste.getClassLoaderName(), ste.getModuleName(), @@ -87,8 +88,8 @@ ste.isNativeMethod(), }; try { - return new CompositeDataSupport(stackTraceElementCompositeType, - stackTraceElementItemNames, + return new CompositeDataSupport(STACK_TRACE_ELEMENT_COMPOSITE_TYPE, + STACK_TRACE_ELEMENT_ATTRIBUTES, stackTraceElementItemValues); } catch (OpenDataException e) { // Should never reach here @@ -106,11 +107,7 @@ private static final String LINE_NUMBER = "lineNumber"; private static final String NATIVE_METHOD = "nativeMethod"; - - private static final String[] stackTraceElementItemNames = { - CLASS_LOADER_NAME, - MODULE_NAME, - MODULE_VERSION, + private static final String[] V5_ATTRIBUTES = { CLASS_NAME, METHOD_NAME, FILE_NAME, @@ -118,30 +115,48 @@ NATIVE_METHOD, }; - private static final String[] stackTraceElementV9ItemNames = { + private static final String[] V9_ATTRIBUTES = { CLASS_LOADER_NAME, MODULE_NAME, MODULE_VERSION, }; - private static final CompositeType stackTraceElementCompositeType; - private static final CompositeType stackTraceElementV6CompositeType; + private static final String[] STACK_TRACE_ELEMENT_ATTRIBUTES = + Stream.of(V5_ATTRIBUTES, V9_ATTRIBUTES).flatMap(Arrays::stream) + .toArray(String[]::new); + + private static final CompositeType STACK_TRACE_ELEMENT_COMPOSITE_TYPE; + private static final CompositeType V5_COMPOSITE_TYPE; static { try { - stackTraceElementCompositeType = (CompositeType) + STACK_TRACE_ELEMENT_COMPOSITE_TYPE = (CompositeType) MappedMXBeanType.toOpenType(StackTraceElement.class); - stackTraceElementV6CompositeType = - TypeVersionMapper.getInstance().getVersionedCompositeType( - stackTraceElementCompositeType, - TypeVersionMapper.V6 - ); + + OpenType[] types = new OpenType[V5_ATTRIBUTES.length]; + for (int i=0; i < V5_ATTRIBUTES.length; i++) { + String name = V5_ATTRIBUTES[i]; + types[i] = STACK_TRACE_ELEMENT_COMPOSITE_TYPE.getType(name); + } + V5_COMPOSITE_TYPE = new CompositeType("StackTraceElement", + "JDK 5 StackTraceElement", + V5_ATTRIBUTES, + V5_ATTRIBUTES, + types); } catch (OpenDataException e) { // Should never reach here throw new AssertionError(e); } } - /** Validate if the input CompositeData has the expected + static CompositeType v5CompositeType() { + return V5_COMPOSITE_TYPE; + } + static CompositeType compositeType() { + return STACK_TRACE_ELEMENT_COMPOSITE_TYPE; + } + + /** + * Validate if the input CompositeData has the expected * CompositeType (i.e. contain all attributes with expected * names and types). */ @@ -151,22 +166,11 @@ } CompositeType ct = cd.getCompositeType(); - if (!isTypeMatched(stackTraceElementCompositeType, ct)) { - if (!isTypeMatched(stackTraceElementV6CompositeType, ct)) { - throw new IllegalArgumentException( - "Unexpected composite type for StackTraceElement"); - } + if (!isTypeMatched(STACK_TRACE_ELEMENT_COMPOSITE_TYPE, ct) && + !isTypeMatched(V5_COMPOSITE_TYPE, ct)) { + throw new IllegalArgumentException( + "Unexpected composite type for StackTraceElement"); } } - - static boolean isV6Attribute(String name) { - for(String attrName : stackTraceElementV9ItemNames) { - if (name.equals(attrName)) { - return false; - } - } - return true; - } - private static final long serialVersionUID = -2704607706598396827L; } diff -r 1c5a3127046f -r d8ea550b907a src/java.management/share/classes/sun/management/ThreadInfoCompositeData.java --- a/src/java.management/share/classes/sun/management/ThreadInfoCompositeData.java Thu Mar 01 11:02:40 2018 +0100 +++ b/src/java.management/share/classes/sun/management/ThreadInfoCompositeData.java Thu Mar 01 11:22:31 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,10 +28,16 @@ import java.lang.management.ThreadInfo; import java.lang.management.MonitorInfo; import java.lang.management.LockInfo; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; +import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeType; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataSupport; import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; /** * A CompositeData for ThreadInfo for the local management support. @@ -41,35 +47,21 @@ public class ThreadInfoCompositeData extends LazyCompositeData { private final ThreadInfo threadInfo; private final CompositeData cdata; - private final boolean currentVersion; - private final boolean hasV6; private ThreadInfoCompositeData(ThreadInfo ti) { this.threadInfo = ti; - this.currentVersion = true; this.cdata = null; - this.hasV6 = true; } private ThreadInfoCompositeData(CompositeData cd) { this.threadInfo = null; - this.currentVersion = ThreadInfoCompositeData.isCurrentVersion(cd); this.cdata = cd; - this.hasV6 = ThreadInfoCompositeData.hasV6(cd); } public ThreadInfo getThreadInfo() { return threadInfo; } - public boolean hasV6() { - return hasV6; - } - - public boolean isCurrentVersion() { - return currentVersion; - } - public static ThreadInfoCompositeData getInstance(CompositeData cd) { validateCompositeData(cd); return new ThreadInfoCompositeData(cd); @@ -112,7 +104,7 @@ } // CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH - // threadInfoItemNames! + // THREAD_INFO_ATTRIBUTES! final Object[] threadInfoItemValues = { threadInfo.getThreadId(), threadInfo.getThreadName(), @@ -126,8 +118,8 @@ threadInfo.getLockOwnerId(), threadInfo.getLockOwnerName(), stackTraceData, - threadInfo.isSuspended(), - threadInfo.isInNative(), + threadInfo.isSuspended(), + threadInfo.isInNative(), lockedMonitorsData, lockedSyncsData, threadInfo.isDaemon(), @@ -135,8 +127,8 @@ }; try { - return new CompositeDataSupport(threadInfoCompositeType, - threadInfoItemNames, + return new CompositeDataSupport(compositeType(), + THREAD_INFO_ATTRIBTUES, threadInfoItemValues); } catch (OpenDataException e) { // Should never reach here @@ -164,7 +156,7 @@ private static final String LOCKED_MONITORS = "lockedMonitors"; private static final String LOCKED_SYNCS = "lockedSynchronizers"; - private static final String[] threadInfoItemNames = { + private static final String[] V5_ATTRIBUTES = { THREAD_ID, THREAD_NAME, THREAD_STATE, @@ -172,109 +164,28 @@ BLOCKED_COUNT, WAITED_TIME, WAITED_COUNT, - LOCK_INFO, LOCK_NAME, LOCK_OWNER_ID, LOCK_OWNER_NAME, STACK_TRACE, SUSPENDED, - IN_NATIVE, - LOCKED_MONITORS, - LOCKED_SYNCS, - DAEMON, - PRIORITY, + IN_NATIVE }; - // New attributes added in 6.0 ThreadInfo - private static final String[] threadInfoV6Attributes = { + private static final String[] V6_ATTRIBUTES = { LOCK_INFO, LOCKED_MONITORS, LOCKED_SYNCS, }; - private static final String[] threadInfoV9Attributes = { + private static final String[] V9_ATTRIBUTES = { DAEMON, PRIORITY, }; - // Current version of ThreadInfo - private static final CompositeType threadInfoCompositeType; - // Previous version of ThreadInfo - private static final CompositeType threadInfoV6CompositeType; - // Previous-previous version of ThreadInfo - private static final CompositeType threadInfoV5CompositeType; - private static final CompositeType lockInfoCompositeType; - static { - try { - threadInfoCompositeType = (CompositeType) - MappedMXBeanType.toOpenType(ThreadInfo.class); - // Form a CompositeType for JDK 5.0 ThreadInfo version - - threadInfoV5CompositeType = - TypeVersionMapper.getInstance().getVersionedCompositeType( - threadInfoCompositeType, TypeVersionMapper.V5 - ); - - threadInfoV6CompositeType = - TypeVersionMapper.getInstance().getVersionedCompositeType( - threadInfoCompositeType, TypeVersionMapper.V6 - ); - } catch (OpenDataException e) { - // Should never reach here - throw new AssertionError(e); - } - - // Each CompositeData object has its CompositeType associated - // with it. So we can get the CompositeType representing LockInfo - // from a mapped CompositeData for any LockInfo object. - // Thus we construct a random LockInfo object and pass it - // to LockInfoCompositeData to do the conversion. - Object o = new Object(); - LockInfo li = new LockInfo(o.getClass().getName(), - System.identityHashCode(o)); - CompositeData cd = LockInfoCompositeData.toCompositeData(li); - lockInfoCompositeType = cd.getCompositeType(); - } - - static boolean isV5Attribute(String itemName) { - for (String n : threadInfoV6Attributes) { - if (itemName.equals(n)) { - return false; - } - } - for (String n : threadInfoV9Attributes) { - if (itemName.equals(n)) { - return false; - } - } - return true; - } - - static boolean isV6Attribute(String itemName) { - for (String n : threadInfoV9Attributes) { - if (itemName.equals(n)) { - return false; - } - } - return true; - } - - public static boolean isCurrentVersion(CompositeData cd) { - if (cd == null) { - throw new NullPointerException("Null CompositeData"); - } - - return isTypeMatched(threadInfoCompositeType, cd.getCompositeType()); - } - - private static boolean hasV6(CompositeData cd) { - if (cd == null) { - throw new NullPointerException("Null CompositeData"); - } - - return isTypeMatched(threadInfoCompositeType, cd.getCompositeType()) || - isTypeMatched(threadInfoV6CompositeType, cd.getCompositeType()); - } + private static final String[] THREAD_INFO_ATTRIBTUES = + Stream.of(V5_ATTRIBUTES, V6_ATTRIBUTES, V9_ATTRIBUTES) + .flatMap(Arrays::stream).toArray(String[]::new); public long threadId() { return getLong(cdata, THREAD_ID); @@ -333,12 +244,18 @@ return getBoolean(cdata, IN_NATIVE); } + /* + * if daemon attribute is not present, default to false. + */ public boolean isDaemon() { - return getBoolean(cdata, DAEMON); + return cdata.containsKey(DAEMON) ? getBoolean(cdata, DAEMON) : false; } + /* + * if priority attribute is not present, default to norm priority. + */ public int getPriority(){ - return getInt(cdata, PRIORITY); + return cdata.containsKey(PRIORITY) ? getInt(cdata, PRIORITY) : Thread.NORM_PRIORITY; } public StackTraceElement[] stackTrace() { @@ -356,13 +273,37 @@ return stackTrace; } - // 6.0 new attributes + /* + * lockInfo is a new attribute added in JDK 6 ThreadInfo + * If cd is a 5.0 version, construct the LockInfo object + * from the lockName value. + */ public LockInfo lockInfo() { - CompositeData lockInfoData = (CompositeData) cdata.get(LOCK_INFO); - return LockInfo.from(lockInfoData); + if (cdata.containsKey(LOCK_INFO)) { + CompositeData lockInfoData = (CompositeData) cdata.get(LOCK_INFO); + return LockInfo.from(lockInfoData); + } else { + String lockName = lockName(); + LockInfo lock = null; + if (lockName != null) { + String result[] = lockName.split("@"); + if (result.length == 2) { + int identityHashCode = Integer.parseInt(result[1], 16); + lock = new LockInfo(result[0], identityHashCode); + } + } + return lock; + } } + /** + * Returns an empty array if locked_monitors attribute is not present. + */ public MonitorInfo[] lockedMonitors() { + if (!cdata.containsKey(LOCKED_MONITORS)) { + return new MonitorInfo[0]; + } + CompositeData[] lockedMonitorsData = (CompositeData[]) cdata.get(LOCKED_MONITORS); @@ -377,7 +318,14 @@ return monitors; } + /** + * Returns an empty array if locked_monitors attribute is not present. + */ public LockInfo[] lockedSynchronizers() { + if (!cdata.containsKey(LOCKED_SYNCS)) { + return new LockInfo[0]; + } + CompositeData[] lockedSyncsData = (CompositeData[]) cdata.get(LOCKED_SYNCS); @@ -391,7 +339,8 @@ return locks; } - /** Validate if the input CompositeData has the expected + /** + * Validate if the input CompositeData has the expected * CompositeType (i.e. contain all attributes with expected * names and types). */ @@ -401,62 +350,98 @@ } CompositeType type = cd.getCompositeType(); - boolean currentVersion = true; - if (!isTypeMatched(threadInfoCompositeType, type)) { - currentVersion = false; - // check if cd is an older version - if (!isTypeMatched(threadInfoV5CompositeType, type) && - !isTypeMatched(threadInfoV6CompositeType, type)) { - throw new IllegalArgumentException( - "Unexpected composite type for ThreadInfo"); + int version; + if (Arrays.stream(V9_ATTRIBUTES).anyMatch(type::containsKey)) { + version = Runtime.version().feature(); + } else if (Arrays.stream(V6_ATTRIBUTES).anyMatch(type::containsKey)) { + version = 6; + } else { + version = 5; + } + + if (!isTypeMatched(ThreadInfoCompositeTypes.ofVersion(version), type)) { + throw new IllegalArgumentException( + "Unexpected composite type for ThreadInfo of version " + version); + } + } + + public static CompositeType compositeType() { + return ThreadInfoCompositeTypes.compositeTypes.get(0); + } + + static class ThreadInfoCompositeTypes { + static final int CURRENT = Runtime.version().feature(); + static final Map compositeTypes = initCompositeTypes(); + /* + * Returns CompositeType of the given runtime version + */ + static CompositeType ofVersion(int version) { + return compositeTypes.get(version); + } + + static Map initCompositeTypes() { + Map types = new HashMap<>(); + CompositeType ctype = initCompositeType(); + types.put(CURRENT, ctype); + types.put(5, initV5CompositeType(ctype)); + types.put(6, initV6CompositeType(ctype)); + return types; + } + + static CompositeType initCompositeType() { + try { + return (CompositeType)MappedMXBeanType.toOpenType(ThreadInfo.class); + } catch (OpenDataException e) { + // Should never reach here + throw new AssertionError(e); } } - CompositeData[] stackTraceData = - (CompositeData[]) cd.get(STACK_TRACE); - if (stackTraceData == null) { - throw new IllegalArgumentException( - "StackTraceElement[] is missing"); - } - if (stackTraceData.length > 0) { - StackTraceElementCompositeData.validateCompositeData(stackTraceData[0]); + static CompositeType initV5CompositeType(CompositeType threadInfoCompositeType) { + try { + OpenType[] v5Types = new OpenType[V5_ATTRIBUTES.length]; + for (int i = 0; i < v5Types.length; i++) { + String name = V5_ATTRIBUTES[i]; + v5Types[i] = name.equals(STACK_TRACE) + ? new ArrayType<>(1, StackTraceElementCompositeData.v5CompositeType()) + : threadInfoCompositeType.getType(name); + } + return new CompositeType("ThreadInfo", + "JDK 5 ThreadInfo", + V5_ATTRIBUTES, + V5_ATTRIBUTES, + v5Types); + } catch (OpenDataException e) { + // Should never reach here + throw new AssertionError(e); + } } - // validate v6 attributes - if (currentVersion) { - CompositeData li = (CompositeData) cd.get(LOCK_INFO); - if (li != null) { - if (!isTypeMatched(lockInfoCompositeType, - li.getCompositeType())) { - throw new IllegalArgumentException( - "Unexpected composite type for \"" + - LOCK_INFO + "\" attribute."); + static CompositeType initV6CompositeType(CompositeType threadInfoCompositeType) { + try { + String[] v6Names = Stream.of(V5_ATTRIBUTES, V6_ATTRIBUTES) + .flatMap(Arrays::stream).toArray(String[]::new); + OpenType[] v6Types = new OpenType[v6Names.length]; + for (int i = 0; i < v6Names.length; i++) { + String name = v6Names[i]; + OpenType ot = threadInfoCompositeType.getType(name); + if (name.equals(STACK_TRACE)) { + ot = new ArrayType<>(1, StackTraceElementCompositeData.v5CompositeType()); + } else if (name.equals(LOCKED_MONITORS)) { + ot = new ArrayType<>(1, MonitorInfoCompositeData.v6CompositeType()); + } + v6Types[i] = ot; } - } - - CompositeData[] lms = (CompositeData[]) cd.get(LOCKED_MONITORS); - if (lms == null) { - throw new IllegalArgumentException("MonitorInfo[] is null"); + return new CompositeType("ThreadInfo", + "JDK 6 ThreadInfo", + v6Names, + v6Names, + v6Types); + } catch (OpenDataException e) { + // Should never reach here + throw new AssertionError(e); } - if (lms.length > 0) { - MonitorInfoCompositeData.validateCompositeData(lms[0]); - } - - CompositeData[] lsyncs = (CompositeData[]) cd.get(LOCKED_SYNCS); - if (lsyncs == null) { - throw new IllegalArgumentException("LockInfo[] is null"); - } - if (lsyncs.length > 0) { - if (!isTypeMatched(lockInfoCompositeType, - lsyncs[0].getCompositeType())) { - throw new IllegalArgumentException( - "Unexpected composite type for \"" + - LOCKED_SYNCS + "\" attribute."); - } - } - } } - private static final long serialVersionUID = 2464378539119753175L; } diff -r 1c5a3127046f -r d8ea550b907a src/java.management/share/classes/sun/management/TypeVersionMapper.java --- a/src/java.management/share/classes/sun/management/TypeVersionMapper.java Thu Mar 01 11:02:40 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,174 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package sun.management; - -import java.lang.management.ThreadInfo; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import javax.management.openmbean.ArrayType; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenDataException; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularType; -import static sun.management.Util.toStringArray; - -/** - * Provides simplistic support for versioning of {@linkplain CompositeType} instances - * based on the latest version and filtering out certain items. - */ -final class TypeVersionMapper { - private static final class Singleton { - private final static TypeVersionMapper INSTANCE = new TypeVersionMapper(); - } - - final static String V5 = "J2SE 5.0"; - final static String V6 = "Java SE 6"; - - private final Map>> filterMap; - - private TypeVersionMapper() { - filterMap = new HashMap<>(); - setupStackTraceElement(); - setupThreadInfo(); - } - - public static TypeVersionMapper getInstance() { - return Singleton.INSTANCE; - } - - private void setupStackTraceElement() { - Map> filter = new HashMap<>(); - filterMap.put(StackTraceElement.class.getName(), filter); - filter.put(V5, StackTraceElementCompositeData::isV6Attribute); - filter.put(V6, StackTraceElementCompositeData::isV6Attribute); - } - - private void setupThreadInfo() { - Map> filter = new HashMap<>(); - filterMap.put(ThreadInfo.class.getName(), filter); - filter.put(V5, ThreadInfoCompositeData::isV5Attribute); - filter.put(V6, ThreadInfoCompositeData::isV6Attribute); - } - - /** - * Retrieves the specified version of a {@linkplain CompositeType} instance. - * @param type The current (latest) version of {@linkplain CompositeType} - * @param version The version identifier (eg. {@linkplain TypeVersionMapper#V5}) - * @return Returns the {@linkplain CompositeType} corresponding to the requested - * version. - * @throws OpenDataException - */ - CompositeType getVersionedCompositeType(CompositeType type, String version) - throws OpenDataException - { - Predicate filter = getFilter(type.getTypeName(), version); - if (filter == null) { - return type; - } - - List itemNames = new ArrayList<>(); - List itemDesc = new ArrayList<>(); - List> itemTypes = new ArrayList<>(); - - for(String item : type.keySet()) { - if (filter.test(item)) { - itemNames.add(item); - itemDesc.add(type.getDescription(item)); - itemTypes.add(getVersionedType( - type.getType(item), - version - )); - } - } - return new CompositeType( - type.getTypeName(), - version != null ? version + " " + type.getDescription() : type.getDescription(), - itemNames.toArray(new String[itemNames.size()]), - itemDesc.toArray(new String[itemDesc.size()]), - itemTypes.toArray(new OpenType[itemTypes.size()]) - ); - } - - private OpenType getVersionedType(OpenType type, String version) - throws OpenDataException - { - if (type instanceof ArrayType) { - return getVersionedArrayType((ArrayType)type, version); - } - if (type instanceof CompositeType) { - return getVersionedCompositeType((CompositeType)type, version); - } - if (type instanceof TabularType) { - return getVersionedTabularType((TabularType)type, version); - } - return type; - } - - private ArrayType getVersionedArrayType(ArrayType type, String version) - throws OpenDataException - { - if (type.isPrimitiveArray()) { - return type; - } - OpenType ot = getVersionedType( - type.getElementOpenType(), - version - ); - if (ot instanceof SimpleType) { - return new ArrayType<>((SimpleType)ot, type.isPrimitiveArray()); - } else { - return new ArrayType<>(type.getDimension(), ot); - } - } - - private TabularType getVersionedTabularType(TabularType type, String version) - throws OpenDataException - { - CompositeType ct = getVersionedCompositeType( - type.getRowType(), - version - ); - - if (ct != null) { - return new TabularType( - type.getTypeName(), type.getDescription(), ct, - toStringArray(type.getIndexNames())); - } - return null; - } - - private Predicate getFilter(String type, String version) { - Map> versionMap = filterMap.get(type); - if (versionMap == null) { - return null; - } - - return versionMap.get(version); - } -} diff -r 1c5a3127046f -r d8ea550b907a test/jdk/java/lang/management/CompositeData/ThreadInfoCompositeData.java --- a/test/jdk/java/lang/management/CompositeData/ThreadInfoCompositeData.java Thu Mar 01 11:02:40 2018 +0100 +++ b/test/jdk/java/lang/management/CompositeData/ThreadInfoCompositeData.java Thu Mar 01 11:22:31 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,26 +23,26 @@ /* * @test - * @bug 4982289 + * @bug 4982289 8198253 * @summary Test ThreadInfo.from to return a valid * ThreadInfo object. Or throw exception if * the input CompositeData is invalid. * @author Mandy Chung * - * @compile OpenTypeConverter.java - * @build ThreadInfoCompositeData + * @build ThreadInfoCompositeData OpenTypeConverter * @run main ThreadInfoCompositeData */ + import javax.management.openmbean.*; import java.lang.management.LockInfo; import java.lang.management.MonitorInfo; import java.lang.management.ThreadInfo; +import java.util.Arrays; import java.util.Objects; +import java.util.stream.Stream; public class ThreadInfoCompositeData { - private static StackTraceElement[] ste = new StackTraceElement[1]; - private static CompositeData[] steCD = new CompositeData[1]; private static String lockClassName = "myClass"; private static int lockIdentityHashCode = 123456; private static String lockName = lockClassName + '@' + @@ -53,55 +53,100 @@ public static void main(String[] argv) throws Exception { // A valid CompositeData is passed to ThreadInfo createGoodCompositeData(); - // A valid CompositeData for JDK 5.0 ThreadInfo + // A valid CompositeData for JDK 5 ThreadInfo // is passed to ThreadInfo createV5ThreadInfo(); + // ThreadInfo of version N can accept lockedMonitors of version >= N + withNewMonitorInfoCompositeData(); + // An invalid CompositeData is passed to ThreadInfo.from() badNameCompositeData(); badTypeCompositeData(); + badMissingCompositeData(); + withV5StackTraceCompositeData(); + withInvalidMonitorInfoCompositeData(); System.out.println("Test passed"); } public static void createGoodCompositeData() throws Exception { - CompositeType ct = - new CompositeType("MyCompositeType", - "CompositeType for ThreadInfo", - validItemNames, - validItemNames, - validItemTypes); - CompositeData cd = - new CompositeDataSupport(ct, - validItemNames, - values); + CompositeData cd = Factory.makeThreadInfoCompositeData(); ThreadInfo info = ThreadInfo.from(cd); checkThreadInfo(info); + } + + /* + * An invalid CompositeData with JDK 9 attributes but missing JDK 6 attributes + */ + public static void badMissingCompositeData() throws Exception { + CompositeData cd = Factory.makeCompositeDataMissingV6(); + try { + ThreadInfo info = ThreadInfo.from(cd); + throw new RuntimeException("IllegalArgumentException not thrown"); + } catch (IllegalArgumentException e) {} + } + + static final StackTraceElement STE = + new StackTraceElement("FooClass", "getFoo", "Foo.java", 100); + + + /* + * Current version of ThreadInfo but an older version of StackTraceElement + */ + public static void withV5StackTraceCompositeData() throws Exception { + CompositeData cd = Factory.makeThreadInfoWithV5StackTrace(); + try { + ThreadInfo info = ThreadInfo.from(cd); + throw new RuntimeException("IllegalArgumentException not thrown"); + } catch (IllegalArgumentException e) {} + } + + /* + * Current version of ThreadInfo but an older version of MonitorInfo + * and the value of "lockedStackFrame" attribute is null. + */ + public static void withInvalidMonitorInfoCompositeData() throws Exception { + CompositeData cd = Factory.makeThreadInfoWithIncompatibleMonitorInfo(); + + // verify MonitorInfo is valid + CompositeData[] monitors = (CompositeData[])cd.get("lockedMonitors"); + CompositeData ste = (CompositeData)monitors[0].get("lockedStackFrame"); + if (((Integer)monitors[0].get("lockedStackDepth")) >= 0 || ste != null) { + throw new RuntimeException("Expected negative stack depth and null stack frame"); + } + MonitorInfo minfo = MonitorInfo.from(monitors[0]); + checkLockInfo(minfo); + if (minfo.getLockedStackFrame() != null) { + throw new RuntimeException("Expected null stack frame"); + } + + try { + ThreadInfo info = ThreadInfo.from(cd); + throw new RuntimeException("IllegalArgumentException not thrown"); + } catch (IllegalArgumentException e) {} + } + + /* + * ThreadInfo of version N can accept lockedMonitors of version >= N + */ + public static void withNewMonitorInfoCompositeData() throws Exception { + CompositeData cd = Factory.makeThreadInfoWithNewMonitorInfo(); + ThreadInfo info = ThreadInfo.from(cd); + checkThreadInfo(info); + } + + /* + * Test CompositeData representing JDK 5 ThreadInfo + */ + public static void createV5ThreadInfo() throws Exception { + CompositeData cd = Factory.makeThreadInfoV5CompositeData(); + ThreadInfo info = ThreadInfo.from(cd); + checkThreadInfoV5(info); } - public static void createV5ThreadInfo() throws Exception { - String[] v5ItemNames = new String[NUM_V5_ATTS]; - OpenType[] v5ItemTypes = new OpenType[NUM_V5_ATTS]; - Object[] v5ItemValues = new Object[NUM_V5_ATTS]; - for (int i = 0; i < NUM_V5_ATTS; i++) { - v5ItemNames[i] = validItemNames[i]; - v5ItemTypes[i] = validItemTypes[i]; - v5ItemValues[i] = values[i]; - } - CompositeType ct = - new CompositeType("MyCompositeType", - "CompositeType for JDK 5.0 ThreadInfo", - v5ItemNames, - v5ItemNames, - v5ItemTypes); - CompositeData cd = - new CompositeDataSupport(ct, - v5ItemNames, - v5ItemValues); - ThreadInfo info = ThreadInfo.from(cd); - checkThreadInfo(info); - } + static void checkThreadInfoV5(ThreadInfo info) { + Object[] values = Factory.VALUES; - static void checkThreadInfo(ThreadInfo info) throws Exception { - if (info.getThreadId() != ((Long) values[THREAD_ID]).longValue()) { + if (info.getThreadId() != ((Long) values[THREAD_ID]).longValue()) { throw new RuntimeException("Thread Id = " + info.getThreadId() + " expected = " + values[THREAD_ID]); } @@ -148,30 +193,35 @@ info.getLockOwnerName() + " expected = " + values[LOCK_OWNER_NAME]); } + + checkStackTrace(info.getStackTrace()); + checkLockInfo(info.getLockInfo()); + } + + static void checkThreadInfo(ThreadInfo info) { + Object[] values = Factory.VALUES; + + checkThreadInfoV5(info); + if (!values[DAEMON].equals(info.isDaemon())) { throw new RuntimeException("Daemon = " + - info.isDaemon() + " expected = " + - values[DAEMON]); + info.isDaemon() + " expected = " + values[DAEMON]); } - - checkStackTrace(info.getStackTrace()); - - checkLockInfo(info.getLockInfo()); } - private static void checkStackTrace(StackTraceElement[] s) - throws Exception { - if (ste.length != s.length) { + private static void checkStackTrace(StackTraceElement[] s) { + if (s.length != 1) { throw new RuntimeException("Stack Trace length = " + - s.length + " expected = " + ste.length); + s.length + " expected = 1"); } - StackTraceElement s1 = ste[0]; + StackTraceElement s1 = STE; StackTraceElement s2 = s[0]; - if (!s1.getClassName().equals(s2.getClassName())) { - throw new RuntimeException("Class name = " + - s2.getClassName() + " expected = " + s1.getClassName()); + // these attributes may be null + if (!Objects.equals(s1.getClassLoaderName(), s2.getClassLoaderName())) { + throw new RuntimeException("Class loader name = " + + s2.getClassLoaderName() + " expected = " + s1.getClassLoaderName()); } if (!Objects.equals(s1.getModuleName(), s2.getModuleName())) { throw new RuntimeException("Module name = " + @@ -181,6 +231,11 @@ throw new RuntimeException("Module version = " + s2.getModuleVersion() + " expected = " + s1.getModuleVersion()); } + + if (!s1.getClassName().equals(s2.getClassName())) { + throw new RuntimeException("Class name = " + + s2.getClassName() + " expected = " + s1.getClassName()); + } if (!s1.getMethodName().equals(s2.getMethodName())) { throw new RuntimeException("Method name = " + s2.getMethodName() + " expected = " + s1.getMethodName()); @@ -195,8 +250,7 @@ } } - private static void checkLockInfo(LockInfo li) - throws Exception { + private static void checkLockInfo(LockInfo li) { if (!li.getClassName().equals(lockInfo.getClassName())) { throw new RuntimeException("Class Name = " + li.getClassName() + " expected = " + lockInfo.getClassName()); @@ -209,227 +263,493 @@ } public static void badNameCompositeData() throws Exception { - CompositeType ct = - new CompositeType("MyCompositeType", - "CompositeType for ThreadInfo", - badItemNames, - badItemNames, - validItemTypes); - CompositeData cd = - new CompositeDataSupport(ct, - badItemNames, - values); - + CompositeData cd = Factory.makeCompositeDataWithBadNames(); try { ThreadInfo info = ThreadInfo.from(cd); - } catch (IllegalArgumentException e) { - System.out.println("Expected exception: " + - e.getMessage()); - return; - } - throw new RuntimeException( - "IllegalArgumentException not thrown"); + throw new RuntimeException("IllegalArgumentException not thrown"); + } catch (IllegalArgumentException e) { } } public static void badTypeCompositeData() throws Exception { - CompositeType ct = - new CompositeType("MyCompositeType", - "CompositeType for ThreadInfo", - validItemNames, - validItemNames, - badItemTypes); - - // patch values[STACK_TRACE] to Long - values[STACK_TRACE] = new Long(1000); - values[LOCK_INFO] = new Long(1000); - CompositeData cd = - new CompositeDataSupport(ct, - validItemNames, - values); + CompositeData cd = Factory.makeCompositeDataWithBadTypes(); try { ThreadInfo info = ThreadInfo.from(cd); - } catch (IllegalArgumentException e) { - System.out.println("Expected exception: " + - e.getMessage()); - return; - } - throw new RuntimeException( - "IllegalArgumentException not thrown"); + throw new RuntimeException("IllegalArgumentException not thrown"); + } catch (IllegalArgumentException e) { } } - private static final int THREAD_ID = 0; - private static final int THREAD_NAME = 1; - private static final int THREAD_STATE = 2; - private static final int BLOCKED_TIME = 3; - private static final int BLOCKED_COUNT = 4; - private static final int WAITED_TIME = 5; - private static final int WAITED_COUNT = 6; - private static final int LOCK_NAME = 7; - private static final int LOCK_OWNER_ID = 8; + private static final int THREAD_ID = 0; + private static final int THREAD_NAME = 1; + private static final int THREAD_STATE = 2; + private static final int BLOCKED_TIME = 3; + private static final int BLOCKED_COUNT = 4; + private static final int WAITED_TIME = 5; + private static final int WAITED_COUNT = 6; + private static final int LOCK_NAME = 7; + private static final int LOCK_OWNER_ID = 8; private static final int LOCK_OWNER_NAME = 9; - private static final int STACK_TRACE = 10; - private static final int SUSPENDED = 11; - private static final int IN_NATIVE = 12; - private static final int NUM_V5_ATTS = 13; - // JDK 6.0 ThreadInfo attributes - private static final int LOCK_INFO = 13; - // JDK 9.0 ThreadInfo attributes - private static final int DAEMON = 14; - private static final int PRIORITY = 15; + private static final int STACK_TRACE = 10; + private static final int SUSPENDED = 11; + private static final int IN_NATIVE = 12; + // JDK 6 ThreadInfo attributes + private static final int LOCK_INFO = 13; + private static final int LOCKED_MONITORS = 14; + private static final int LOCKED_SYNCS = 15; + // JDK 9 ThreadInfo attributes + private static final int DAEMON = 16; + private static final int PRIORITY = 17; + + static class Factory { - private static final String[] validItemNames = { - "threadId", - "threadName", - "threadState", - "blockedTime", - "blockedCount", - "waitedTime", - "waitedCount", - "lockName", - "lockOwnerId", - "lockOwnerName", - "stackTrace", - "suspended", - "inNative", - "lockInfo", - "daemon", - "priority", - }; + static final CompositeType STE_COMPOSITE_TYPE; + static final CompositeType LOCK_INFO_COMPOSITE_TYPE; + static final CompositeType MONITOR_INFO_COMPOSITE_TYPE; + static final ArrayType STE_ARRAY_COMPOSITE_TYPE; + static final ArrayType LOCK_INFO_ARRAY_COMPOSITE_TYPE; + static final ArrayType MONITOR_INFO_ARRAY_COMPOSITE_TYPE; + + static { + CompositeType steCType = null; + CompositeType lockInfoCType = null; + CompositeType monitorInfoCType = null; + ArrayType steArrayType = null; + ArrayType lockInfoArrayType = null; + ArrayType monitorInfoArrayType = null; - private static OpenType[] validItemTypes = { - SimpleType.LONG, - SimpleType.STRING, - SimpleType.STRING, - SimpleType.LONG, - SimpleType.LONG, - SimpleType.LONG, - SimpleType.LONG, - SimpleType.STRING, - SimpleType.LONG, - SimpleType.STRING, - null, // ArrayType for StackTraceElement[] - SimpleType.BOOLEAN, - SimpleType.BOOLEAN, - null, // CompositeType for LockInfo - SimpleType.BOOLEAN, - SimpleType.INTEGER, - }; + try { + steCType = (CompositeType) OpenTypeConverter.toOpenType(StackTraceElement.class); + lockInfoCType = (CompositeType) OpenTypeConverter.toOpenType(LockInfo.class); + monitorInfoCType = (CompositeType) OpenTypeConverter.toOpenType(MonitorInfo.class); + steArrayType = new ArrayType(1, steCType); + lockInfoArrayType = new ArrayType(1, lockInfoCType); + monitorInfoArrayType = new ArrayType(1, monitorInfoCType); + } catch (Exception e) { + throw new RuntimeException(e); + } + STE_COMPOSITE_TYPE = steCType; + LOCK_INFO_COMPOSITE_TYPE = lockInfoCType; + MONITOR_INFO_COMPOSITE_TYPE = monitorInfoCType; + STE_ARRAY_COMPOSITE_TYPE = steArrayType; + LOCK_INFO_ARRAY_COMPOSITE_TYPE = lockInfoArrayType; + MONITOR_INFO_ARRAY_COMPOSITE_TYPE = monitorInfoArrayType; + } + + static CompositeData makeThreadInfoCompositeData() throws OpenDataException { + CompositeType ct = new CompositeType("MyCompositeType", + "CompositeType for ThreadInfo", + ITEM_NAMES, + ITEM_NAMES, + ITEM_TYPES); + return new CompositeDataSupport(ct, ITEM_NAMES, VALUES); + } - private static Object[] values = { - new Long(100), - "FooThread", - "RUNNABLE", - new Long(200), - new Long(10), - new Long(300), - new Long(20), - lockName, - new Long(99), - "BarThread", - steCD, - new Boolean(false), - new Boolean(false), - null, // To be initialized to lockInfoCD - new Boolean(false), - Thread.NORM_PRIORITY, - }; + static CompositeData makeThreadInfoV5CompositeData() throws OpenDataException { + CompositeType ct = new CompositeType("MyCompositeType", + "CompositeType for JDK 5 ThreadInfo", + V5_ITEM_NAMES, + V5_ITEM_NAMES, + V5_ITEM_TYPES); + return new CompositeDataSupport(ct, V5_ITEM_NAMES, V5_VALUES); + } - private static final String[] steItemNames = { - "classLoaderName", - "moduleName", - "moduleVersion", - "className", - "methodName", - "fileName", - "lineNumber", - "nativeMethod", - }; - - private static final String[] lockInfoItemNames = { - "className", - "identityHashCode", - }; - - static { - // create stack trace element - ste[0] = new StackTraceElement("FooClass", "getFoo", "Foo.java", 100); - - // initialize the ste[0] and values and validItemTypes - try { - CompositeType steCType = (CompositeType) - OpenTypeConverter.toOpenType(StackTraceElement.class); - validItemTypes[STACK_TRACE] = new ArrayType(1, steCType); - - final Object[] steValue = { - ste[0].getClassLoaderName(), - ste[0].getModuleName(), - ste[0].getModuleVersion(), - ste[0].getClassName(), - ste[0].getMethodName(), - ste[0].getFileName(), - new Integer(ste[0].getLineNumber()), - new Boolean(ste[0].isNativeMethod()), + static CompositeData makeCompositeDataWithBadTypes() throws OpenDataException { + OpenType[] badItemTypes = { + SimpleType.LONG, + SimpleType.STRING, + SimpleType.STRING, + SimpleType.LONG, + SimpleType.LONG, + SimpleType.LONG, + SimpleType.LONG, + SimpleType.STRING, + SimpleType.LONG, + SimpleType.STRING, + SimpleType.LONG, // bad type + SimpleType.BOOLEAN, + SimpleType.BOOLEAN, + SimpleType.LONG, // bad type + SimpleType.LONG, // bad type + SimpleType.LONG, // bad type + SimpleType.BOOLEAN, + SimpleType.INTEGER, }; - steCD[0] = - new CompositeDataSupport(steCType, - steItemNames, - steValue); + CompositeType ct = + new CompositeType("Bad item types", + "CompositeType for ThreadInfo", + ITEM_NAMES, + ITEM_NAMES, + badItemTypes); + + // Copy before mutating to avoid affecting other tests. + Object[] localValues = VALUES.clone(); + + // patch values[STACK_TRACE] to Long + localValues[STACK_TRACE] = Long.valueOf(1000); + localValues[LOCK_INFO] = Long.valueOf(1000); + localValues[LOCKED_MONITORS] = Long.valueOf(1000); + localValues[LOCKED_SYNCS] = Long.valueOf(1000); + return new CompositeDataSupport(ct, ITEM_NAMES, localValues); + } + + static CompositeData makeCompositeDataWithBadNames() throws OpenDataException { + String[] badItemNames = ITEM_NAMES.clone(); + badItemNames[STACK_TRACE] = "BadStackTrace"; // bad item name + + CompositeType ct = new CompositeType("Bad item names", + "CompositeType for ThreadInfo", + badItemNames, + badItemNames, + ITEM_TYPES); + return new CompositeDataSupport(ct, + badItemNames, + VALUES); + } + + /* + * Create a CompositeData of ThreadInfo without JDK 6 attributes + */ + static CompositeData makeCompositeDataMissingV6() throws OpenDataException { + String[] itemNames = concat(V5_ITEM_NAMES, V9_ITEM_NAMES).toArray(String[]::new); + OpenType[] itemTypes = concat(V5_ITEM_TYPES, V9_ITEM_TYPES).toArray(OpenType[]::new); + Object[] values = concat(V5_VALUES, V9_VALUES).toArray(Object[]::new); + + CompositeType ct = + new CompositeType("InvalidCompositeType", + "CompositeType for ThreadInfo", + itemNames, + itemNames, + itemTypes); + return new CompositeDataSupport(ct, itemNames, values); + } + + static CompositeData makeStackTraceElement() { + Object[] steValue = { + STE.getClassLoaderName(), + STE.getModuleName(), + STE.getModuleVersion(), + STE.getClassName(), + STE.getMethodName(), + STE.getFileName(), + Integer.valueOf(STE.getLineNumber()), + Boolean.valueOf(STE.isNativeMethod()), + }; + + try { + return new CompositeDataSupport(STE_COMPOSITE_TYPE, + STE_ITEM_NAMES, + steValue); + } catch (OpenDataException e) { + throw new RuntimeException(e); + } + } + + static CompositeData makeStackTraceElementV5() throws OpenDataException { + CompositeType steV5CType = + new CompositeType("JDK 5 StackTraceElement", + "CompositeType for JDK 5 StackTraceElement", + STE_V5_ITEM_NAMES, + STE_V5_ITEM_NAMES, + STE_V5_ITEM_TYPES); + + Object[] steV5Value = { + STE.getClassName(), + STE.getMethodName(), + STE.getFileName(), + Integer.valueOf(STE.getLineNumber()), + Boolean.valueOf(STE.isNativeMethod()), + }; + + return new CompositeDataSupport(steV5CType, STE_V5_ITEM_NAMES, steV5Value); + } + + /* + * Create a CompositeData of ThreadInfo without JDK 5 StackTraceElement + */ + static CompositeData makeThreadInfoWithV5StackTrace() throws OpenDataException { + OpenType[] badTypes = ITEM_TYPES.clone(); + Object[] badValues = VALUES.clone(); - CompositeType lockInfoCType = (CompositeType) - OpenTypeConverter.toOpenType(LockInfo.class); - validItemTypes[LOCK_INFO] = lockInfoCType; + CompositeData[] stackTrace = new CompositeData[1]; + stackTrace[0] = makeStackTraceElementV5(); + badTypes[STACK_TRACE] = new ArrayType(1, stackTrace[0].getCompositeType()); + badValues[STACK_TRACE] = stackTrace; + CompositeType ct = new CompositeType("CompositeType", + "ThreadInfo with JDK 5 StackTraceElement", + ITEM_NAMES, + ITEM_NAMES, + badTypes); + return new CompositeDataSupport(ct, ITEM_NAMES, badValues); + } + + /* + * Create MonitorInfo with JDK 5 StackTraceElement (i.e. JDK 6 MonitorInfo) + * The value of "lockedStackFrame" attribute is null to ensure that + * the validation is done. + */ + static CompositeData makeV6MonitorInfo() throws OpenDataException { + CompositeData steV5 = makeStackTraceElementV5(); + + String[] names = MONITOR_INFO_COMPOSITE_TYPE.keySet().toArray(new String[0]); + OpenType[] types = new OpenType[names.length]; + for (int i=0; i < names.length; i++) { + String n = names[i]; + types[i] = "lockedStackFrame".equals(n) + ? steV5.getCompositeType() + : MONITOR_INFO_COMPOSITE_TYPE.getType(n); + } + + CompositeType ctype = + new CompositeType("JDK 6 MonitorInfo", + "CompositeType for JDK 6 MonitorInfo", + names, + names, + types); + + Object[] values = { + lockClassName, + lockIdentityHashCode, + -1, + null + }; + + return new CompositeDataSupport(ctype, names, values); + } + + /* + * Create a CompositeData of ThreadInfo with incompatible MonitorInfo + */ + static CompositeData makeThreadInfoWithIncompatibleMonitorInfo() throws OpenDataException { + OpenType[] badTypes = ITEM_TYPES.clone(); + Object[] badValues = VALUES.clone(); - final Object[] lockInfoValue = { + CompositeData[] lockedMonitors = new CompositeData[1]; + lockedMonitors[0] = makeV6MonitorInfo(); + badTypes[LOCKED_MONITORS] = new ArrayType(1, lockedMonitors[0].getCompositeType()); + badValues[LOCKED_MONITORS] = lockedMonitors; + CompositeType ct = new CompositeType("CompositeType", + "ThreadInfo with incompatible MonitorInfo", + ITEM_NAMES, + ITEM_NAMES, + badTypes); + return new CompositeDataSupport(ct, ITEM_NAMES, badValues); + } + + static CompositeData makeNewMonitorInfo() throws OpenDataException { + String[] names = Stream.concat(MONITOR_INFO_COMPOSITE_TYPE.keySet().stream(), + Stream.of("extra")).toArray(String[]::new); + OpenType[] types = new OpenType[names.length]; + for (int i=0; i < names.length; i++) { + String n = names[i]; + types[i] = "extra".equals(n) + ? SimpleType.STRING + : MONITOR_INFO_COMPOSITE_TYPE.getType(n); + } + + CompositeType compositeType = + new CompositeType("JDK X MonitorInfo", + "CompositeType for JDK X MonitorInfo", + names, + names, + types); + + Object[] values = { + lockClassName, + lockIdentityHashCode, + Integer.valueOf(1), + makeStackTraceElement(), + "extra" + }; + + return new CompositeDataSupport(compositeType, names, values); + } + + /* + * Create a CompositeData of ThreadInfo with a newer version of MonitorInfo + */ + static CompositeData makeThreadInfoWithNewMonitorInfo() throws OpenDataException { + OpenType[] types = ITEM_TYPES.clone(); + Object[] badValues = VALUES.clone(); + + CompositeData[] lockedMonitors = new CompositeData[1]; + lockedMonitors[0] = makeNewMonitorInfo(); + types[LOCKED_MONITORS] = new ArrayType(1, lockedMonitors[0].getCompositeType()); + badValues[LOCKED_MONITORS] = lockedMonitors; + CompositeType ct = new CompositeType("CompositeType", + "ThreadInfo with JDK 5 MonitorInfo", + ITEM_NAMES, + ITEM_NAMES, + types); + return new CompositeDataSupport(ct, ITEM_NAMES, badValues); + } + + static CompositeData makeLockInfo() { + Object[] lockInfoValue = { lockInfo.getClassName(), lockInfo.getIdentityHashCode(), }; - values[LOCK_INFO] = - new CompositeDataSupport(lockInfoCType, - lockInfoItemNames, - lockInfoValue); - } catch (Exception e) { - throw new RuntimeException(e); + try { + return new CompositeDataSupport(LOCK_INFO_COMPOSITE_TYPE, + LOCK_INFO_ITEM_NAMES, + lockInfoValue); + } catch (OpenDataException e) { + throw new RuntimeException(e); + } + } + + static CompositeData[] makeLockedSynchronizers() { + CompositeData[] lockedSyncs = new CompositeData[1]; + lockedSyncs[0] = makeLockInfo(); + return lockedSyncs; + } + + static CompositeData[] makeLockedMonitors() { + CompositeData[] lockedMonitorsCD = new CompositeData[1]; + + Object[] lockedMonitorsValue = { + lockInfo.getClassName(), + lockInfo.getIdentityHashCode(), + makeStackTraceElement(), + Integer.valueOf(1), + }; + try { + lockedMonitorsCD[0] = + new CompositeDataSupport(MONITOR_INFO_COMPOSITE_TYPE, + LOCKED_MONITORS_ITEM_NAMES, + lockedMonitorsValue); + } catch (OpenDataException e) { + throw new RuntimeException(e); + } + return lockedMonitorsCD; + } + + static final String[] V5_ITEM_NAMES = { + "threadId", + "threadName", + "threadState", + "blockedTime", + "blockedCount", + "waitedTime", + "waitedCount", + "lockName", + "lockOwnerId", + "lockOwnerName", + "stackTrace", + "suspended", + "inNative", + }; + + static final String[] V6_ITEM_NAMES = { + "lockInfo", + "lockedMonitors", + "lockedSynchronizers", + }; + + static final String[] V9_ITEM_NAMES = { + "daemon", + "priority", + }; + + static final OpenType[] V5_ITEM_TYPES = { + SimpleType.LONG, + SimpleType.STRING, + SimpleType.STRING, + SimpleType.LONG, + SimpleType.LONG, + SimpleType.LONG, + SimpleType.LONG, + SimpleType.STRING, + SimpleType.LONG, + SimpleType.STRING, + STE_ARRAY_COMPOSITE_TYPE, + SimpleType.BOOLEAN, + SimpleType.BOOLEAN, + }; + + static final OpenType[] V6_ITEM_TYPES = { + LOCK_INFO_COMPOSITE_TYPE, + MONITOR_INFO_ARRAY_COMPOSITE_TYPE, + LOCK_INFO_ARRAY_COMPOSITE_TYPE, + }; + + static final OpenType[] V9_ITEM_TYPES = { + SimpleType.BOOLEAN, + SimpleType.INTEGER, + }; + + static final String[] STE_ITEM_NAMES = { + "classLoaderName", + "moduleName", + "moduleVersion", + "className", + "methodName", + "fileName", + "lineNumber", + "nativeMethod", + }; + + static final String[] STE_V5_ITEM_NAMES = Arrays.copyOfRange(STE_ITEM_NAMES, 3, 8); + + static final OpenType[] STE_V5_ITEM_TYPES = { + SimpleType.STRING, + SimpleType.STRING, + SimpleType.STRING, + SimpleType.INTEGER, + SimpleType.BOOLEAN + }; + + static final String[] LOCK_INFO_ITEM_NAMES = { + "className", + "identityHashCode", + }; + + static final String[] LOCKED_MONITORS_ITEM_NAMES = { + LOCK_INFO_ITEM_NAMES[0], + LOCK_INFO_ITEM_NAMES[1], + "lockedStackFrame", + "lockedStackDepth", + }; + + static final Object[] V5_VALUES = { + Long.valueOf(100), + "FooThread", + "RUNNABLE", + Long.valueOf(200), + Long.valueOf(10), + Long.valueOf(300), + Long.valueOf(20), + lockName, + Long.valueOf(99), + "BarThread", + new CompositeData[] { makeStackTraceElement() }, + Boolean.valueOf(false), + Boolean.valueOf(false), + }; + + static final Object[] V6_VALUES = { + makeLockInfo(), + makeLockedMonitors(), + makeLockedSynchronizers(), + }; + + static final Object[] V9_VALUES = { + Boolean.valueOf(true), + Thread.NORM_PRIORITY, + }; + + static final String[] ITEM_NAMES = + concat(V5_ITEM_NAMES, V6_ITEM_NAMES, V9_ITEM_NAMES).toArray(String[]::new); + + static final OpenType[] ITEM_TYPES = + concat(V5_ITEM_TYPES, V6_ITEM_TYPES, V9_ITEM_TYPES).toArray(OpenType[]::new); + + static final Object[] VALUES = + concat(V5_VALUES, V6_VALUES, V9_VALUES).toArray(Object[]::new); + + static Stream concat(T[]... streams) { + return Stream.of(streams).flatMap(a -> Arrays.stream(a)); } } - - private static final String[] badItemNames = { - "threadId", - "threadName", - "threadState", - "blockedTime", - "blockedCount", - "waitedTime", - "waitedCount", - "lockName", - "lockOwnerId", - "lockOwnerName", - "BadStackTrace", // bad item name - "suspended", - "inNative", - "lockInfo", - "daemon", - "priority", - }; - private static final OpenType[] badItemTypes = { - SimpleType.LONG, - SimpleType.STRING, - SimpleType.STRING, - SimpleType.LONG, - SimpleType.LONG, - SimpleType.LONG, - SimpleType.LONG, - SimpleType.STRING, - SimpleType.LONG, - SimpleType.STRING, - SimpleType.LONG, // bad type - SimpleType.BOOLEAN, - SimpleType.BOOLEAN, - SimpleType.LONG, // bad type - SimpleType.BOOLEAN, - SimpleType.INTEGER, - }; - } diff -r 1c5a3127046f -r d8ea550b907a test/jdk/sun/management/StackTraceElementCompositeData/CompatibilityTest.java --- a/test/jdk/sun/management/StackTraceElementCompositeData/CompatibilityTest.java Thu Mar 01 11:02:40 2018 +0100 +++ b/test/jdk/sun/management/StackTraceElementCompositeData/CompatibilityTest.java Thu Mar 01 11:22:31 2018 +0100 @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ import java.util.HashMap; import java.util.Map; @@ -6,6 +28,7 @@ import javax.management.openmbean.CompositeType; import javax.management.openmbean.OpenType; import javax.management.openmbean.SimpleType; + import sun.management.StackTraceElementCompositeData; import org.testng.annotations.*; @@ -14,6 +37,7 @@ /* * @test * @bug 8139587 + * @modules java.management/sun.management * @summary Check backward compatibility of StackTraceElementCompositeData * @author Jaroslav Bachorik * @@ -22,21 +46,33 @@ public class CompatibilityTest { private static CompositeType compositeTypeV6; - private static Map itemsV6; - private static CompositeData compositeDataV6; + private static CompositeType compositeType; + + // Attribute names + private static final String CLASS_LOADER_NAME = "classLoaderName"; + private static final String MODULE_NAME = "moduleName"; + private static final String MODULE_VERSION = "moduleVersion"; + private static final String CLASS_NAME = "className"; + private static final String METHOD_NAME = "methodName"; + private static final String FILE_NAME = "fileName"; + private static final String LINE_NUMBER = "lineNumber"; + private static final String NATIVE_METHOD = "nativeMethod"; @BeforeClass public static void setup() throws Exception { + String[] v6Names = { + CLASS_NAME, METHOD_NAME, FILE_NAME, NATIVE_METHOD, LINE_NUMBER + }; + String[] names = { + CLASS_LOADER_NAME, MODULE_NAME, MODULE_VERSION, + CLASS_NAME, METHOD_NAME, FILE_NAME, NATIVE_METHOD, LINE_NUMBER + }; compositeTypeV6 = new CompositeType( StackTraceElement.class.getName(), "StackTraceElement", - new String[]{ - "className", "methodName", "fileName", "nativeMethod", "lineNumber" - }, - new String[]{ - "className", "methodName", "fileName", "nativeMethod", "lineNumber" - }, - new OpenType[]{ + v6Names, + v6Names, + new OpenType[] { SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, @@ -44,20 +80,52 @@ SimpleType.INTEGER } ); + compositeType = new CompositeType( + StackTraceElement.class.getName(), + "StackTraceElement", + names, + names, + new OpenType[] { + SimpleType.STRING, + SimpleType.STRING, + SimpleType.STRING, + SimpleType.STRING, + SimpleType.STRING, + SimpleType.STRING, + SimpleType.BOOLEAN, + SimpleType.INTEGER + } + ); + } - itemsV6 = new HashMap<>(); - itemsV6.put("className", "MyClass"); - itemsV6.put("methodName", "myMethod"); - itemsV6.put("fileName", "MyClass.java"); - itemsV6.put("nativeMethod", false); - itemsV6.put("lineNumber", 123); + private static CompositeData makeCompositeDataV6() throws Exception { + Map itemsV6 = new HashMap<>(); + itemsV6.put(CLASS_NAME, "MyClass"); + itemsV6.put(METHOD_NAME, "myMethod"); + itemsV6.put(FILE_NAME, "MyClass.java"); + itemsV6.put(NATIVE_METHOD, false); + itemsV6.put(LINE_NUMBER, 123); + + return new CompositeDataSupport(compositeTypeV6, itemsV6); + } - compositeDataV6 = new CompositeDataSupport(compositeTypeV6, itemsV6); + private static CompositeData makeCompositeData() throws Exception { + Map items = new HashMap<>(); + items.put(CLASS_LOADER_NAME, "app"); + items.put(MODULE_NAME, "m"); + items.put(MODULE_VERSION, "1.0"); + items.put(CLASS_NAME, "MyClass"); + items.put(METHOD_NAME, "myMethod"); + items.put(FILE_NAME, "MyClass.java"); + items.put(NATIVE_METHOD, false); + items.put(LINE_NUMBER, 123); + + return new CompositeDataSupport(compositeType, items); } @Test public void testV6Compatibility() throws Exception { - StackTraceElement ste = StackTraceElementCompositeData.from(compositeDataV6); + StackTraceElement ste = StackTraceElementCompositeData.from(makeCompositeDataV6()); assertNotNull(ste); assertEquals(ste.getClassName(), "MyClass"); @@ -69,5 +137,22 @@ assertNull(ste.getModuleName()); assertNull(ste.getModuleVersion()); } + + @Test + public void test() throws Exception { + StackTraceElement ste = StackTraceElementCompositeData.from(makeCompositeData()); + + assertNotNull(ste); + + assertEquals(ste.getModuleName(), "m"); + assertEquals(ste.getModuleVersion(), "1.0"); + assertEquals(ste.getClassLoaderName(), "app"); + + assertEquals(ste.getClassName(), "MyClass"); + assertEquals(ste.getMethodName(), "myMethod"); + assertEquals(ste.getFileName(), "MyClass.java"); + assertEquals(ste.isNativeMethod(), false); + assertEquals(ste.getLineNumber(), 123); + } }