diff -r fd16c54261b3 -r 90ce3da70b43 jdk/src/share/classes/sun/management/ThreadInfoCompositeData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/management/ThreadInfoCompositeData.java Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,413 @@ +/* + * Copyright 2004-2005 Sun Microsystems, Inc. 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. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +package sun.management; + +import java.lang.management.ThreadInfo; +import java.lang.management.MonitorInfo; +import java.lang.management.LockInfo; +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. + * This class avoids the performance penalty paid to the + * construction of a CompositeData use in the local case. + */ +public class ThreadInfoCompositeData extends LazyCompositeData { + private final ThreadInfo threadInfo; + private final CompositeData cdata; + private final boolean currentVersion; + + private ThreadInfoCompositeData(ThreadInfo ti) { + this.threadInfo = ti; + this.currentVersion = true; + this.cdata = null; + } + + private ThreadInfoCompositeData(CompositeData cd) { + this.threadInfo = null; + this.currentVersion = ThreadInfoCompositeData.isCurrentVersion(cd); + this.cdata = cd; + } + + public ThreadInfo getThreadInfo() { + return threadInfo; + } + + public boolean isCurrentVersion() { + return currentVersion; + } + + public static ThreadInfoCompositeData getInstance(CompositeData cd) { + validateCompositeData(cd); + return new ThreadInfoCompositeData(cd); + } + + public static CompositeData toCompositeData(ThreadInfo ti) { + ThreadInfoCompositeData ticd = new ThreadInfoCompositeData(ti); + return ticd.getCompositeData(); + } + + protected CompositeData getCompositeData() { + // Convert StackTraceElement[] to CompositeData[] + StackTraceElement[] stackTrace = threadInfo.getStackTrace(); + CompositeData[] stackTraceData = + new CompositeData[stackTrace.length]; + for (int i = 0; i < stackTrace.length; i++) { + StackTraceElement ste = stackTrace[i]; + stackTraceData[i] = StackTraceElementCompositeData.toCompositeData(ste); + } + + // Convert MonitorInfo[] and LockInfo[] to CompositeData[] + LockDataConverter converter = new LockDataConverter(threadInfo); + CompositeData lockInfoData = converter.toLockInfoCompositeData(); + CompositeData[] lockedSyncsData = converter.toLockedSynchronizersCompositeData(); + + // Convert MonitorInfo[] to CompositeData[] + MonitorInfo[] lockedMonitors = threadInfo.getLockedMonitors(); + CompositeData[] lockedMonitorsData = + new CompositeData[lockedMonitors.length]; + for (int i = 0; i < lockedMonitors.length; i++) { + MonitorInfo mi = lockedMonitors[i]; + lockedMonitorsData[i] = MonitorInfoCompositeData.toCompositeData(mi); + } + + + // CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH + // threadInfoItemNames! + final Object[] threadInfoItemValues = { + new Long(threadInfo.getThreadId()), + threadInfo.getThreadName(), + threadInfo.getThreadState().name(), + new Long(threadInfo.getBlockedTime()), + new Long(threadInfo.getBlockedCount()), + new Long(threadInfo.getWaitedTime()), + new Long(threadInfo.getWaitedCount()), + lockInfoData, + threadInfo.getLockName(), + new Long(threadInfo.getLockOwnerId()), + threadInfo.getLockOwnerName(), + stackTraceData, + new Boolean(threadInfo.isSuspended()), + new Boolean(threadInfo.isInNative()), + lockedMonitorsData, + lockedSyncsData, + }; + + try { + return new CompositeDataSupport(threadInfoCompositeType, + threadInfoItemNames, + threadInfoItemValues); + } catch (OpenDataException e) { + // Should never reach here + throw Util.newInternalError(e); + } + } + + // Attribute names + private static final String THREAD_ID = "threadId"; + private static final String THREAD_NAME = "threadName"; + private static final String THREAD_STATE = "threadState"; + private static final String BLOCKED_TIME = "blockedTime"; + private static final String BLOCKED_COUNT = "blockedCount"; + private static final String WAITED_TIME = "waitedTime"; + private static final String WAITED_COUNT = "waitedCount"; + private static final String LOCK_INFO = "lockInfo"; + private static final String LOCK_NAME = "lockName"; + private static final String LOCK_OWNER_ID = "lockOwnerId"; + private static final String LOCK_OWNER_NAME = "lockOwnerName"; + private static final String STACK_TRACE = "stackTrace"; + private static final String SUSPENDED = "suspended"; + private static final String IN_NATIVE = "inNative"; + private static final String LOCKED_MONITORS = "lockedMonitors"; + private static final String LOCKED_SYNCS = "lockedSynchronizers"; + + private static final String[] threadInfoItemNames = { + THREAD_ID, + THREAD_NAME, + THREAD_STATE, + BLOCKED_TIME, + 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, + }; + + // New attributes added in 6.0 ThreadInfo + private static final String[] threadInfoV6Attributes = { + LOCK_INFO, + LOCKED_MONITORS, + LOCKED_SYNCS, + }; + + // Current version of ThreadInfo + private static final CompositeType threadInfoCompositeType; + // 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 + String[] itemNames = + threadInfoCompositeType.keySet().toArray(new String[0]); + int numV5Attributes = threadInfoItemNames.length - + threadInfoV6Attributes.length; + String[] v5ItemNames = new String[numV5Attributes]; + String[] v5ItemDescs = new String[numV5Attributes]; + OpenType[] v5ItemTypes = new OpenType[numV5Attributes]; + int i = 0; + for (String n : itemNames) { + if (isV5Attribute(n)) { + v5ItemNames[i] = n; + v5ItemDescs[i] = threadInfoCompositeType.getDescription(n); + v5ItemTypes[i] = threadInfoCompositeType.getType(n); + i++; + } + } + + threadInfoV5CompositeType = + new CompositeType("java.lang.management.ThreadInfo", + "J2SE 5.0 java.lang.management.ThreadInfo", + v5ItemNames, + v5ItemDescs, + v5ItemTypes); + } catch (OpenDataException e) { + // Should never reach here + throw Util.newInternalError(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 LockDataConverter to do the conversion. + Object o = new Object(); + LockInfo li = new LockInfo(o.getClass().getName(), + System.identityHashCode(o)); + CompositeData cd = LockDataConverter.toLockInfoCompositeData(li); + lockInfoCompositeType = cd.getCompositeType(); + } + + private static boolean isV5Attribute(String itemName) { + for (String n : threadInfoV6Attributes) { + 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()); + } + + public long threadId() { + return getLong(cdata, THREAD_ID); + } + + public String threadName() { + // The ThreadName item cannot be null so we check that + // it is present with a non-null value. + String name = getString(cdata, THREAD_NAME); + if (name == null) { + throw new IllegalArgumentException("Invalid composite data: " + + "Attribute " + THREAD_NAME + " has null value"); + } + return name; + } + + public Thread.State threadState() { + return Thread.State.valueOf(getString(cdata, THREAD_STATE)); + } + + public long blockedTime() { + return getLong(cdata, BLOCKED_TIME); + } + + public long blockedCount() { + return getLong(cdata, BLOCKED_COUNT); + } + + public long waitedTime() { + return getLong(cdata, WAITED_TIME); + } + + public long waitedCount() { + return getLong(cdata, WAITED_COUNT); + } + + public String lockName() { + // The LockName and LockOwnerName can legitimately be null, + // we don't bother to check the value + return getString(cdata, LOCK_NAME); + } + + public long lockOwnerId() { + return getLong(cdata, LOCK_OWNER_ID); + } + + public String lockOwnerName() { + return getString(cdata, LOCK_OWNER_NAME); + } + + public boolean suspended() { + return getBoolean(cdata, SUSPENDED); + } + + public boolean inNative() { + return getBoolean(cdata, IN_NATIVE); + } + + public StackTraceElement[] stackTrace() { + CompositeData[] stackTraceData = + (CompositeData[]) cdata.get(STACK_TRACE); + + // The StackTrace item cannot be null, but if it is we will get + // a NullPointerException when we ask for its length. + StackTraceElement[] stackTrace = + new StackTraceElement[stackTraceData.length]; + for (int i = 0; i < stackTraceData.length; i++) { + CompositeData cdi = stackTraceData[i]; + stackTrace[i] = StackTraceElementCompositeData.from(cdi); + } + return stackTrace; + } + + // 6.0 new attributes + public LockInfo lockInfo() { + LockDataConverter converter = new LockDataConverter(); + CompositeData lockInfoData = (CompositeData) cdata.get(LOCK_INFO); + return converter.toLockInfo(lockInfoData); + } + + public MonitorInfo[] lockedMonitors() { + CompositeData[] lockedMonitorsData = + (CompositeData[]) cdata.get(LOCKED_MONITORS); + + // The LockedMonitors item cannot be null, but if it is we will get + // a NullPointerException when we ask for its length. + MonitorInfo[] monitors = + new MonitorInfo[lockedMonitorsData.length]; + for (int i = 0; i < lockedMonitorsData.length; i++) { + CompositeData cdi = lockedMonitorsData[i]; + monitors[i] = MonitorInfo.from(cdi); + } + return monitors; + } + + public LockInfo[] lockedSynchronizers() { + LockDataConverter converter = new LockDataConverter(); + CompositeData[] lockedSyncsData = + (CompositeData[]) cdata.get(LOCKED_SYNCS); + + // The LockedSynchronizers item cannot be null, but if it is we will + // get a NullPointerException when we ask for its length. + return converter.toLockedSynchronizers(lockedSyncsData); + } + + /** Validate if the input CompositeData has the expected + * CompositeType (i.e. contain all attributes with expected + * names and types). + */ + public static void validateCompositeData(CompositeData cd) { + if (cd == null) { + throw new NullPointerException("Null CompositeData"); + } + + CompositeType type = cd.getCompositeType(); + boolean currentVersion = true; + if (!isTypeMatched(threadInfoCompositeType, type)) { + currentVersion = false; + // check if cd is an older version + if (!isTypeMatched(threadInfoV5CompositeType, type)) { + throw new IllegalArgumentException( + "Unexpected composite type for ThreadInfo"); + } + } + + CompositeData[] stackTraceData = + (CompositeData[]) cd.get(STACK_TRACE); + if (stackTraceData == null) { + 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."); + } + } + + } + } +}