8198253: ThreadInfo.from(CompositeData) incorrectly accepts CompositeData with missing JDK 6 attributes

Reviewed-by: dfuchs, jmanson
This commit is contained in:
Mandy Chung 2018-02-28 17:11:57 -08:00
parent dc42a2bab5
commit 3414903aba
9 changed files with 1075 additions and 794 deletions
src/java.management/share/classes
test/jdk
java/lang/management/CompositeData
sun/management/StackTraceElementCompositeData

@ -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 @@ public class MonitorInfo extends LockInfo {
* <tbody style="text-align:left">
* <tr>
* <th scope="row">lockedStackFrame</th>
* <td><code>CompositeData as specified in the
* <a href="ThreadInfo.html#StackTrace">stackTrace</a>
* attribute defined in the {@link ThreadInfo#from
* ThreadInfo.from} method.
* </code></td>
* <td><a href="ThreadInfo.html#stackTraceElement">
* {@code CompositeData} for {@code StackTraceElement}</a> as specified
* in {@link ThreadInfo#from(CompositeData)} method.
* </td>
* </tr>
* <tr>
* <th scope="row">lockedStackDepth</th>
@ -134,7 +133,7 @@ public class MonitorInfo extends LockInfo {
* @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.

@ -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 @@ public class ThreadInfo {
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 @@ public class ThreadInfo {
/*
* 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 @@ public class ThreadInfo {
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 @@ public class ThreadInfo {
/**
* 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 id="attributes"></a>
* A {@code CompositeData} representing a {@code ThreadInfo} of
* version <em>N</em> must contain all of the attributes defined
* in version &le; <em>N</em> 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}.
* <p>
* A {@code CompositeData} representing {@code ThreadInfo} of
* version <em>N</em> 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 <em>N</em>.
* The {@code "lockedStackFrame"} attribute in
* {@link MonitorInfo#from(CompositeData) MonitorInfo}'s composite type
* must represent {@code StackTraceElement} of the same version <em>N</em>.
* Otherwise, this method will throw {@code IllegalArgumentException}.
*
* <table class="striped" style="margin-left:2em">
* <caption style="display:none">The attributes and their types the given CompositeData contains</caption>
* <caption style="display:none">The attributes and their types for ThreadInfo's composite data</caption>
* <thead>
* <tr>
* <th scope="col">Attribute Name</th>
* <th scope="col">Type</th>
* <th scope="col">Since</th>
* </tr>
* </thead>
* <tbody style="text-align:left">
* <tr>
* <th scope="row">threadId</th>
* <td>{@code java.lang.Long}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">threadName</th>
* <td>{@code java.lang.String}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">threadState</th>
* <td>{@code java.lang.String}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">suspended</th>
* <td>{@code java.lang.Boolean}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">inNative</th>
* <td>{@code java.lang.Boolean}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">blockedCount</th>
* <td>{@code java.lang.Long}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">blockedTime</th>
* <td>{@code java.lang.Long}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">waitedCount</th>
* <td>{@code java.lang.Long}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">waitedTime</th>
* <td>{@code java.lang.Long}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">lockName</th>
* <td>{@code java.lang.String}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">lockOwnerId</th>
* <td>{@code java.lang.Long}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">lockOwnerName</th>
* <td>{@code java.lang.String}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row"><a id="StackTrace">stackTrace</a></th>
* <td>{@code javax.management.openmbean.CompositeData[]}, each element
* is a {@code CompositeData} representing {@code StackTraceElement}
* as specified <a href="#stackTraceElement">below</a>.
* </td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">lockInfo</th>
@ -745,78 +773,21 @@ public class ThreadInfo {
* - the mapped type for {@link LockInfo} as specified in the
* {@link LockInfo#from} method.
* <p>
* 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. </td>
* </tr>
* <tr>
* <th scope="row">lockName</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">lockOwnerId</th>
* <td>{@code java.lang.Long}</td>
* </tr>
* <tr>
* <th scope="row">lockOwnerName</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row"><a id="StackTrace">stackTrace</a></th>
* <td>{@code javax.management.openmbean.CompositeData[]}
* <p>
* Each element is a {@code CompositeData} representing
* StackTraceElement containing the following attributes:
* <table class="striped" style="margin-left:2em">
* <caption style="display:none">The attributes and their types the given CompositeData contains</caption>
* <thead style="text-align:center">
* <tr>
* <th scope="col">Attribute Name</th>
* <th scope="col">Type</th>
* </tr>
* </thead>
* <tbody style="text-align:left">
* <tr>
* <th scope="row">moduleName</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">moduleVersion</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">className</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">methodName</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">fileName</th>
* <td>{@code java.lang.String}</td>
* </tr>
* <tr>
* <th scope="row">lineNumber</th>
* <td>{@code java.lang.Integer}</td>
* </tr>
* <tr>
* <th scope="row">nativeMethod</th>
* <td>{@code java.lang.Boolean}</td>
* </tr>
* </tbody>
* </table>
* </td>
* the value of the {@code lockName} attribute.</td>
* <td>6</td>
* </tr>
* <tr>
* <th scope="row">lockedMonitors</th>
* <td>{@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.
* <p>
* If {@code cd} does not contain this attribute,
* this attribute will be set to an empty array. </td>
* If the given {@code CompositeData} does not contain this attribute,
* this attribute will be set to an empty array.</td>
* <td>6</td>
* </tr>
* <tr>
* <th scope="row">lockedSynchronizers</th>
@ -824,25 +795,93 @@ public class ThreadInfo {
* whose element type is the mapped type for
* {@link LockInfo} as specified in the {@link LockInfo#from} method.
* <p>
* If {@code cd} does not contain this attribute,
* this attribute will be set to an empty array. </td>
* If the given {@code CompositeData} does not contain this attribute,
* this attribute will be set to an empty array.</td>
* <td>6</td>
* </tr>
* <tr>
* <th scope="row">daemon</th>
* <td>{@code java.lang.Boolean}</td>
* <td>{@code java.lang.Boolean}
* <p>
* If the given {@code CompositeData} does not contain this attribute,
* this attribute will be set to {@code false}.</td>
* <td>9</td>
* </tr>
* <tr>
* <th scope="row">priority</th>
* <td>{@code java.lang.Integer}
* <p>
* If the given {@code CompositeData} does not contain this attribute,
* This attribute will be set to {@link Thread#NORM_PRIORITY}.</td>
* <td>9</td>
* </tr>
* </tbody>
* </table>
*
* <a id="stackTraceElement">A {@code CompositeData} representing
* {@code StackTraceElement}</a> of version <em>N</em> must contain
* all of the attributes defined in version &le; <em>N</em>
* unless specified otherwise.
*
* <table class="striped" style="margin-left:2em">
* <caption style="display:none">The attributes and their types for StackTraceElement's composite data</caption>
* <thead style="text-align:center">
* <tr>
* <th scope="col">Attribute Name</th>
* <th scope="col">Type</th>
* <th scope="col">Since</th>
* </tr>
* </thead>
* <tbody style="text-align:left">
* <tr>
* <th scope="row">classLoaderName</th>
* <td>{@code java.lang.String}</td>
* <td>9</td>
* </tr>
* <tr>
* <th scope="row">moduleName</th>
* <td>{@code java.lang.String}</td>
* <td>9</td>
* </tr>
* <tr>
* <th scope="row">moduleVersion</th>
* <td>{@code java.lang.String}</td>
* <td>9</td>
* </tr>
* <tr>
* <th scope="row">className</th>
* <td>{@code java.lang.String}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">methodName</th>
* <td>{@code java.lang.String}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">fileName</th>
* <td>{@code java.lang.String}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">lineNumber</th>
* <td>{@code java.lang.Integer}</td>
* <td>5</td>
* </tr>
* <tr>
* <th scope="row">nativeMethod</th>
* <td>{@code java.lang.Boolean}</td>
* <td>5</td>
* </tr>
* </tbody>
* </table>
*
* @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
* <a href="#attributes">the attributes</a> 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};

@ -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 @@ public class LockInfoCompositeData extends LazyCompositeData {
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 @@ public class LockInfoCompositeData extends LazyCompositeData {
}
}
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 @@ public class LockInfoCompositeData extends LazyCompositeData {
}
}
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 @@ public class LockInfoCompositeData extends LazyCompositeData {
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");
}

@ -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.CompositeType;
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 @@ public class MonitorInfoCompositeData extends LazyCompositeData {
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 @@ public class MonitorInfoCompositeData extends LazyCompositeData {
}
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 @@ public class MonitorInfoCompositeData extends LazyCompositeData {
}
}
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<String> 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 @@ public class MonitorInfoCompositeData extends LazyCompositeData {
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");
}

@ -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 class StackTraceElementCompositeData extends LazyCompositeData {
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 @@ public class StackTraceElementCompositeData extends LazyCompositeData {
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 @@ public class StackTraceElementCompositeData extends LazyCompositeData {
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 @@ public class StackTraceElementCompositeData extends LazyCompositeData {
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 @@ public class StackTraceElementCompositeData extends LazyCompositeData {
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 @@ public class StackTraceElementCompositeData extends LazyCompositeData {
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 @@ public class StackTraceElementCompositeData extends LazyCompositeData {
}
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;
}

@ -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 @@ package sun.management;
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 @@ import javax.management.openmbean.OpenDataException;
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 @@ public class ThreadInfoCompositeData extends LazyCompositeData {
}
// CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH
// threadInfoItemNames!
// THREAD_INFO_ATTRIBUTES!
final Object[] threadInfoItemValues = {
threadInfo.getThreadId(),
threadInfo.getThreadName(),
@ -126,8 +118,8 @@ public class ThreadInfoCompositeData extends LazyCompositeData {
threadInfo.getLockOwnerId(),
threadInfo.getLockOwnerName(),
stackTraceData,
threadInfo.isSuspended(),
threadInfo.isInNative(),
threadInfo.isSuspended(),
threadInfo.isInNative(),
lockedMonitorsData,
lockedSyncsData,
threadInfo.isDaemon(),
@ -135,8 +127,8 @@ public class ThreadInfoCompositeData extends LazyCompositeData {
};
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 @@ public class ThreadInfoCompositeData extends LazyCompositeData {
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 @@ public class ThreadInfoCompositeData extends LazyCompositeData {
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 @@ public class ThreadInfoCompositeData extends LazyCompositeData {
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 @@ public class ThreadInfoCompositeData extends LazyCompositeData {
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 @@ public class ThreadInfoCompositeData extends LazyCompositeData {
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 @@ public class ThreadInfoCompositeData extends LazyCompositeData {
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 @@ public class ThreadInfoCompositeData extends LazyCompositeData {
}
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;
}
CompositeData[] stackTraceData =
(CompositeData[]) cd.get(STACK_TRACE);
if (stackTraceData == null) {
if (!isTypeMatched(ThreadInfoCompositeTypes.ofVersion(version), type)) {
throw new IllegalArgumentException(
"StackTraceElement[] is missing");
}
if (stackTraceData.length > 0) {
StackTraceElementCompositeData.validateCompositeData(stackTraceData[0]);
}
// 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.");
}
}
CompositeData[] lms = (CompositeData[]) cd.get(LOCKED_MONITORS);
if (lms == null) {
throw new IllegalArgumentException("MonitorInfo[] is null");
}
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.");
}
}
"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<Integer, CompositeType> compositeTypes = initCompositeTypes();
/*
* Returns CompositeType of the given runtime version
*/
static CompositeType ofVersion(int version) {
return compositeTypes.get(version);
}
static Map<Integer, CompositeType> initCompositeTypes() {
Map<Integer, CompositeType> 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);
}
}
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);
}
}
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;
}
return new CompositeType("ThreadInfo",
"JDK 6 ThreadInfo",
v6Names,
v6Names,
v6Types);
} catch (OpenDataException e) {
// Should never reach here
throw new AssertionError(e);
}
}
}
private static final long serialVersionUID = 2464378539119753175L;
}

@ -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<String, Map<String, Predicate<String>>> filterMap;
private TypeVersionMapper() {
filterMap = new HashMap<>();
setupStackTraceElement();
setupThreadInfo();
}
public static TypeVersionMapper getInstance() {
return Singleton.INSTANCE;
}
private void setupStackTraceElement() {
Map<String, Predicate<String>> filter = new HashMap<>();
filterMap.put(StackTraceElement.class.getName(), filter);
filter.put(V5, StackTraceElementCompositeData::isV6Attribute);
filter.put(V6, StackTraceElementCompositeData::isV6Attribute);
}
private void setupThreadInfo() {
Map<String, Predicate<String>> 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<String> filter = getFilter(type.getTypeName(), version);
if (filter == null) {
return type;
}
List<String> itemNames = new ArrayList<>();
List<String> itemDesc = new ArrayList<>();
List<OpenType<?>> 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<String> getFilter(String type, String version) {
Map<String, Predicate<String>> versionMap = filterMap.get(type);
if (versionMap == null) {
return null;
}
return versionMap.get(version);
}
}

@ -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 class ThreadInfoCompositeData {
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);
}
}
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];
/*
* 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");
}
CompositeType ct =
new CompositeType("MyCompositeType",
"CompositeType for JDK 5.0 ThreadInfo",
v5ItemNames,
v5ItemNames,
v5ItemTypes);
CompositeData cd =
new CompositeDataSupport(ct,
v5ItemNames,
v5ItemValues);
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);
}
static void checkThreadInfo(ThreadInfo info) throws Exception {
if (info.getThreadId() != ((Long) values[THREAD_ID]).longValue()) {
static void checkThreadInfoV5(ThreadInfo info) {
Object[] values = Factory.VALUES;
if (info.getThreadId() != ((Long) values[THREAD_ID]).longValue()) {
throw new RuntimeException("Thread Id = " + info.getThreadId() +
" expected = " + values[THREAD_ID]);
}
@ -148,30 +193,35 @@ public class ThreadInfoCompositeData {
info.getLockOwnerName() + " expected = " +
values[LOCK_OWNER_NAME]);
}
if (!values[DAEMON].equals(info.isDaemon())) {
throw new RuntimeException("Daemon = " +
info.isDaemon() + " expected = " +
values[DAEMON]);
}
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]);
}
}
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 @@ public class ThreadInfoCompositeData {
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 @@ public class ThreadInfoCompositeData {
}
}
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 class ThreadInfoCompositeData {
}
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;
private static final String[] validItemNames = {
"threadId",
"threadName",
"threadState",
"blockedTime",
"blockedCount",
"waitedTime",
"waitedCount",
"lockName",
"lockOwnerId",
"lockOwnerName",
"stackTrace",
"suspended",
"inNative",
"lockInfo",
"daemon",
"priority",
};
static class Factory {
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,
};
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;
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 {
CompositeType steCType = null;
CompositeType lockInfoCType = null;
CompositeType monitorInfoCType = null;
ArrayType steArrayType = null;
ArrayType lockInfoArrayType = null;
ArrayType monitorInfoArrayType = null;
private static final String[] steItemNames = {
"classLoaderName",
"moduleName",
"moduleVersion",
"className",
"methodName",
"fileName",
"lineNumber",
"nativeMethod",
};
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;
}
private static final String[] lockInfoItemNames = {
"className",
"identityHashCode",
};
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);
}
static {
// create stack trace element
ste[0] = new StackTraceElement("FooClass", "getFoo", "Foo.java", 100);
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);
}
// 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);
CompositeType lockInfoCType = (CompositeType)
OpenTypeConverter.toOpenType(LockInfo.class);
validItemTypes[LOCK_INFO] = lockInfoCType;
// Copy before mutating to avoid affecting other tests.
Object[] localValues = VALUES.clone();
final Object[] lockInfoValue = {
// 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();
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();
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 <T> Stream<T> 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,
};
}

@ -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.CompositeDataSupport;
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 @@ import static org.testng.Assert.*;
/*
* @test
* @bug 8139587
* @modules java.management/sun.management
* @summary Check backward compatibility of StackTraceElementCompositeData
* @author Jaroslav Bachorik
*
@ -22,21 +46,33 @@ import static org.testng.Assert.*;
public class CompatibilityTest {
private static CompositeType compositeTypeV6;
private static Map<String, Object> 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 @@ public class CompatibilityTest {
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<String, Object> 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);
compositeDataV6 = new CompositeDataSupport(compositeTypeV6, itemsV6);
return new CompositeDataSupport(compositeTypeV6, itemsV6);
}
private static CompositeData makeCompositeData() throws Exception {
Map<String, Object> 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 @@ public class CompatibilityTest {
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);
}
}