001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.lang.management;
019:
020: import javax.management.openmbean.CompositeData;
021:
022: import org.apache.harmony.lang.management.ManagementUtils;
023:
024: /**
025: * <p>
026: * Thread information.
027: * </p>
028: *
029: * @since 1.5
030: */
031: public class ThreadInfo {
032:
033: /**
034: * Receives a {@link CompositeData}representing a <code>ThreadInfo</code>
035: * object and attempts to return the root <code>ThreadInfo</code>
036: * instance.
037: *
038: * @param cd
039: * a <code>CompositeDate</code> that represents a
040: * <code>ThreadInfo</code>.
041: * @return if <code>cd</code> is non- <code>null</code>, returns a new
042: * instance of <code>ThreadInfo</code>. If <code>cd</code> is
043: * <code>null</code>, returns <code>null</code>.
044: * @throws IllegalArgumentException
045: * if argument <code>cd</code> does not correspond to a
046: * <code>ThreadInfo</code> with the following attributes:
047: * <ul>
048: * <li><code>threadId</code>(<code>java.lang.Long</code>)
049: * <li><code>threadName</code>(
050: * <code>java.lang.String</code>)
051: * <li><code>threadState</code>(
052: * <code>java.lang.String</code>)
053: * <li><code>suspended</code>(
054: * <code>java.lang.Boolean</code>)
055: * <li><code>inNative</code>(<code>java.lang.Boolean</code>)
056: * <li><code>blockedCount</code>(
057: * <code>java.lang.Long</code>)
058: * <li><code>blockedTime</code>(<code>java.lang.Long</code>)
059: * <li><code>waitedCount</code>(<code>java.lang.Long</code>)
060: * <li><code>waitedTime<code> (<code>java.lang.Long</code>)
061: * <li><code>lockName</code> (<code>java.lang.String</code>)
062: * <li><code>lockOwnerId</code> (<code>java.lang.Long</code>)
063: * <li><code>lockOwnerName</code> (<code>java.lang.String</code>)
064: * <li><code>stackTrace</code> (<code>javax.management.openmbean.CompositeData[]</code>)
065: * </ul>
066: * Each element of the <code>stackTrace</code> array must
067: * correspond to a <code>java.lang.StackTraceElement</code>
068: * and have the following attributes :
069: * <ul>
070: * <li><code>className</code> (<code>java.lang.String</code>)
071: * <li><code>methodName</code> (<code>java.lang.String</code>)
072: * <li><code>fileName</code> (<code>java.lang.String</code>)
073: * <li><code>lineNumber</code> (<code>java.lang.Integer</code>)
074: * <li><code>nativeMethod</code> (<code>java.lang.Boolean</code>)
075: * </ul>
076: */
077: public static ThreadInfo from(CompositeData cd) {
078: ThreadInfo result = null;
079:
080: if (cd != null) {
081: // Does cd meet the necessary criteria to create a new
082: // ThreadInfo ? If not then exit on an IllegalArgumentException
083: ManagementUtils.verifyFieldNumber(cd, 13);
084: String[] attributeNames = { "threadId", "threadName",
085: "threadState", "suspended", "inNative",
086: "blockedCount", "blockedTime", "waitedCount",
087: "waitedTime", "lockName", "lockOwnerId",
088: "lockOwnerName", "stackTrace" };
089: ManagementUtils.verifyFieldNames(cd, attributeNames);
090: String[] attributeTypes = { "java.lang.Long",
091: "java.lang.String", "java.lang.String",
092: "java.lang.Boolean", "java.lang.Boolean",
093: "java.lang.Long", "java.lang.Long",
094: "java.lang.Long", "java.lang.Long",
095: "java.lang.String", "java.lang.Long",
096: "java.lang.String",
097: (new CompositeData[0]).getClass().getName() };
098: ManagementUtils.verifyFieldTypes(cd, attributeNames,
099: attributeTypes);
100:
101: // Extract the values of the attributes and use them to construct
102: // a new ThreadInfo.
103: Object[] attributeVals = cd.getAll(attributeNames);
104: long threadIdVal = ((Long) attributeVals[0]).longValue();
105: String threadNameVal = (String) attributeVals[1];
106: String threadStateStringVal = (String) attributeVals[2];
107:
108: // Verify that threadStateStringVal contains a string that can be
109: // successfully used to create a Thread.State.
110: Thread.State threadStateVal = null;
111: try {
112: threadStateVal = Thread.State
113: .valueOf(threadStateStringVal);
114: } catch (IllegalArgumentException e) {
115: throw new IllegalArgumentException(
116: "CompositeData contains an unexpected threadState value.",
117: e);
118: }
119:
120: boolean suspendedVal = ((Boolean) attributeVals[3])
121: .booleanValue();
122: boolean inNativeVal = ((Boolean) attributeVals[4])
123: .booleanValue();
124: long blockedCountVal = ((Long) attributeVals[5])
125: .longValue();
126: long blockedTimeVal = ((Long) attributeVals[6]).longValue();
127: long waitedCountVal = ((Long) attributeVals[7]).longValue();
128: long waitedTimeVal = ((Long) attributeVals[8]).longValue();
129: String lockNameVal = attributeVals[9] != null ? (String) attributeVals[9]
130: : null;
131: long lockOwnerIdVal = ((Long) attributeVals[10])
132: .longValue();
133: String lockOwnerNameVal = attributeVals[11] != null ? (String) attributeVals[11]
134: : null;
135: CompositeData[] stackTraceDataVal = (CompositeData[]) attributeVals[12];
136: StackTraceElement[] stackTraceVals = getStackTracesFromCompositeData(stackTraceDataVal);
137:
138: result = new ThreadInfo(threadIdVal, threadNameVal,
139: threadStateVal, suspendedVal, inNativeVal,
140: blockedCountVal, blockedTimeVal, waitedCountVal,
141: waitedTimeVal, lockNameVal, lockOwnerIdVal,
142: lockOwnerNameVal, stackTraceVals);
143: }// end if cd is not null
144:
145: return result;
146: }
147:
148: /**
149: * Returns an array of {@link StackTraceElement}whose elements have been
150: * created from the corresponding elements of the
151: * <code>stackTraceDataVal</code> argument.
152: *
153: * @param stackTraceDataVal
154: * an array of {@link CompositeData}objects, each one
155: * representing a <code>StackTraceElement</code>.
156: * @return an array of <code>StackTraceElement</code> objects built using
157: * the data discovered in the corresponding elements of
158: * <code>stackTraceDataVal</code>.
159: * @throws IllegalArgumentException
160: * if any of the elements of <code>stackTraceDataVal</code> do
161: * not correspond to a <code>StackTraceElement</code> with the
162: * following attributes:
163: * <ul>
164: * <li><code>className</code>(<code>java.lang.String</code>)
165: * <li><code>methodName</code>(
166: * <code>java.lang.String</code>)
167: * <li><code>fileName</code>(<code>java.lang.String</code>)
168: * <li><code>lineNumbercode> (<code>java.lang.Integer</code>)
169: * <li><code>nativeMethod</code> (<code>java.lang.Boolean</code>)
170: * </ul>
171: */
172: private static StackTraceElement[] getStackTracesFromCompositeData(
173: CompositeData[] stackTraceDataVal) {
174: StackTraceElement[] result = new StackTraceElement[stackTraceDataVal.length];
175:
176: for (int i = 0; i < stackTraceDataVal.length; i++) {
177: CompositeData data = stackTraceDataVal[i];
178:
179: // Verify the element
180: ManagementUtils.verifyFieldNumber(data, 5);
181: String[] attributeNames = { "className", "methodName",
182: "fileName", "lineNumber", "nativeMethod" };
183: ManagementUtils.verifyFieldNames(data, attributeNames);
184: String[] attributeTypes = { "java.lang.String",
185: "java.lang.String", "java.lang.String",
186: "java.lang.Integer", "java.lang.Boolean" };
187: ManagementUtils.verifyFieldTypes(data, attributeNames,
188: attributeTypes);
189:
190: // Get hold of the values from the data object to use in the
191: // creation of a new StackTraceElement.
192: Object[] attributeVals = data.getAll(attributeNames);
193: String classNameVal = (String) attributeVals[0];
194: String methodNameVal = (String) attributeVals[1];
195: String fileNameVal = (String) attributeVals[2];
196: int lineNumberVal = ((Integer) attributeVals[3]).intValue();
197: boolean nativeMethodVal = ((Boolean) attributeVals[4])
198: .booleanValue();
199: StackTraceElement element = new StackTraceElement(
200: classNameVal, methodNameVal, fileNameVal,
201: lineNumberVal);
202: result[i] = element;
203: }
204:
205: return result;
206: }
207:
208: private long threadId;
209:
210: private String threadName;
211:
212: private Thread.State threadState;
213:
214: private boolean suspended;
215:
216: private boolean inNative;
217:
218: private long blockedCount;
219:
220: private long blockedTime;
221:
222: private long waitedCount;
223:
224: private long waitedTime;
225:
226: private String lockName;
227:
228: private long lockOwnerId;
229:
230: private String lockOwnerName;
231:
232: private StackTraceElement[] stackTraces = new StackTraceElement[0];
233:
234: private String TOSTRING_VALUE;
235:
236: /**
237: * Creates a new <code>ThreadInfo</code> instance.
238: *
239: * @param threadIdVal
240: * @param threadNameVal
241: * @param threadStateVal
242: * @param suspendedVal
243: * @param inNativeVal
244: * @param blockedCountVal
245: * @param blockedTimeVal
246: * @param waitedCountVal
247: * @param waitedTimeVal
248: * @param lockNameVal
249: * @param lockOwnerIdVal
250: * @param lockOwnerNameVal
251: * @param stackTraceVal
252: */
253: private ThreadInfo(long threadIdVal, String threadNameVal,
254: Thread.State threadStateVal, boolean suspendedVal,
255: boolean inNativeVal, long blockedCountVal,
256: long blockedTimeVal, long waitedCountVal,
257: long waitedTimeVal, String lockNameVal,
258: long lockOwnerIdVal, String lockOwnerNameVal,
259: StackTraceElement[] stackTraceVal) {
260: super ();
261: this .threadId = threadIdVal;
262: this .threadName = threadNameVal;
263: this .threadState = threadStateVal;
264: this .suspended = suspendedVal;
265: this .inNative = inNativeVal;
266: this .blockedCount = blockedCountVal;
267: this .blockedTime = blockedTimeVal;
268: this .waitedCount = waitedCountVal;
269: this .waitedTime = waitedTimeVal;
270: this .lockName = lockNameVal;
271: this .lockOwnerId = lockOwnerIdVal;
272: this .lockOwnerName = lockOwnerNameVal;
273: this .stackTraces = stackTraceVal;
274: }
275:
276: /**
277: * Returns the number of times that the thread represented by this
278: * <code>ThreadInfo</code> has been blocked on any monitor objects. The
279: * count is from the start of the thread's life.
280: *
281: * @return the number of times the corresponding thread has been blocked on
282: * a monitor.
283: */
284: public long getBlockedCount() {
285: return this .blockedCount;
286: }
287:
288: /**
289: * If thread contention monitoring is supported and enabled, returns the
290: * total amount of time that the thread represented by this
291: * <code>ThreadInfo</code> has spent blocked on any monitor objects. The
292: * time is measued in milliseconds and will be measured over the time period
293: * since thread contention was most recently enabled.
294: *
295: * @return if thread contention monitoring is currently enabled, the number
296: * of milliseconds that the thread associated with this
297: * <code>ThreadInfo</code> has spent blocked on any monitors. If
298: * thread contention monitoring is supported but currently disabled,
299: * <code>-1</code>.
300: * @throws UnsupportedOperationException
301: * if the virtual machine does not support thread contention
302: * monitoring.
303: * @see ThreadMXBean#isThreadContentionMonitoringSupported()
304: * @see ThreadMXBean#isThreadContentionMonitoringEnabled()
305: */
306: public long getBlockedTime() {
307: return this .blockedTime;
308: }
309:
310: /**
311: * If the thread represented by this <code>ThreadInfo</code> is currently
312: * blocked on or waiting on a monitor object, returns a string
313: * representation of that monitor object.
314: * <p>
315: * The monitor's string representation is comprised of the following
316: * component parts:
317: * <ul>
318: * <li><code>monitor</code> class name
319: * <li><code>@</code>
320: * <li><code>Integer.toHexString(System.identityHashCode(monitor))</code>
321: * </ul>
322: * </p>
323: * @return if blocked or waiting on a monitor, a string representation of
324: * the monitor object. Otherwise, <code>null</code>.
325: * @see Integer#toHexString(int)
326: * @see System#identityHashCode(java.lang.Object)
327: */
328: public String getLockName() {
329: return this .lockName;
330: }
331:
332: /**
333: * If the thread represented by this <code>ThreadInfo</code> is currently
334: * blocked on or waiting on a monitor object, returns the thread identifier
335: * of the thread which owns the monitor.
336: *
337: * @return the thread identifier of the other thread which holds the monitor
338: * that the thread associated with this <code>ThreadInfo</code> is
339: * blocked or waiting on. If this <code>ThreadInfo</code>'s
340: * associated thread is currently not blocked or waiting, or there
341: * is no other thread holding the monitor, returns a <code>-1</code>.
342: */
343: public long getLockOwnerId() {
344: return this .lockOwnerId;
345: }
346:
347: /**
348: * If the thread represented by this <code>ThreadInfo</code> is currently
349: * blocked on or waiting on a monitor object, returns the name of the thread
350: * which owns the monitor.
351: *
352: * @return the name of the other thread which holds the monitor that the
353: * thread associated with this <code>ThreadInfo</code> is blocked
354: * or waiting on. If this <code>ThreadInfo</code>'s associated
355: * thread is currently not blocked or waiting, or there is no other
356: * thread holding the monitor, returns a <code>null</code>
357: * reference.
358: */
359: public String getLockOwnerName() {
360: return lockOwnerName;
361: }
362:
363: /**
364: * If available, returns the stack trace for the thread represented by this
365: * <code>ThreadInfo</code> instance. The stack trace is returned in an
366: * array of {@link StackTraceElement}objects with the "top" of the
367: * stack encapsulated in the first array element and the "bottom"
368: * of the stack in the last array element.
369: * <p>
370: * If this <code>ThreadInfo</code> was created without any stack trace
371: * information (e.g. by a call to {@link ThreadMXBean#getThreadInfo(long)})
372: * then the returned array will have a length of zero.
373: * </p>
374: *
375: * @return the stack trace for the thread represented by this
376: * <code>ThreadInfo</code>.
377: */
378: public StackTraceElement[] getStackTrace() {
379: return this .stackTraces;
380: }
381:
382: /**
383: * Returns the thread identifier of the thread represented by this
384: * <code>ThreadInfo</code>.
385: *
386: * @return the identifer of the thread corresponding to this
387: * <code>ThreadInfo</code>.
388: */
389: public long getThreadId() {
390: return this .threadId;
391: }
392:
393: /**
394: * Returns the name of the thread represented by this
395: * <code>ThreadInfo</code>.
396: *
397: * @return the name of the thread corresponding to this
398: * <code>ThreadInfo</code>.
399: */
400: public String getThreadName() {
401: return this .threadName;
402: }
403:
404: /**
405: * Returns the thread state value of the thread represented by this
406: * <code>ThreadInfo</code>.
407: *
408: * @return the thread state of the thread corresponding to this
409: * <code>ThreadInfo</code>.
410: * @see Thread#getState()
411: */
412: public Thread.State getThreadState() {
413: return this .threadState;
414: }
415:
416: /**
417: * The number of times that the thread represented by this
418: * <code>ThreadInfo</code> has gone to the "wait" or "timed
419: * wait" state.
420: *
421: * @return the numer of times the corresponding thread has been in the
422: * "wait" or "timed wait" state.
423: */
424: public long getWaitedCount() {
425: return this .waitedCount;
426: }
427:
428: /**
429: * If thread contention monitoring is supported and enabled, returns the
430: * total amount of time that the thread represented by this
431: * <code>ThreadInfo</code> has spent waiting for notifications. The time
432: * is measued in milliseconds and will be measured over the time period
433: * since thread contention was most recently enabled.
434: *
435: * @return if thread contention monitoring is currently enabled, the number
436: * of milliseconds that the thread associated with this
437: * <code>ThreadInfo</code> has spent waiting notifications. If
438: * thread contention monitoring is supported but currently disabled,
439: * <code>-1</code>.
440: * @throws UnsupportedOperationException
441: * if the virtual machine does not support thread contention
442: * monitoring.
443: * @see ThreadMXBean#isThreadContentionMonitoringSupported()
444: * @see ThreadMXBean#isThreadContentionMonitoringEnabled()
445: */
446: public long getWaitedTime() {
447: return this .waitedTime;
448: }
449:
450: /**
451: * Returns a <code>boolean</code> indication of whether or not the thread
452: * represented by this <code>ThreadInfo</code> is currently in a native
453: * method.
454: *
455: * @return if the corresponding thread <i>is </i> executing a native method
456: * then <code>true</code>, otherwise <code>false</code>.
457: */
458: public boolean isInNative() {
459: return this .inNative;
460: }
461:
462: /**
463: * Returns a <code>boolean</code> indication of whether or not the thread
464: * represented by this <code>ThreadInfo</code> is currently suspended.
465: *
466: * @return if the corresponding thread <i>is </i> suspened then
467: * <code>true</code>, otherwise <code>false</code>.
468: */
469: public boolean isSuspended() {
470: return this .suspended;
471: }
472:
473: @Override
474: public String toString() {
475: // Since ThreadInfos are immutable the string value need only be
476: // calculated the one time
477: if (TOSTRING_VALUE == null) {
478: StringBuilder buff = new StringBuilder();
479: buff.append("Thread ");
480: buff.append(threadName);
481: buff.append(" (Id = ");
482: buff.append(threadId);
483: buff.append(") ");
484: buff.append(threadState.toString());
485: if (lockName != null) {
486: buff.append(" " + lockName);
487: }
488: TOSTRING_VALUE = buff.toString().trim();
489: }
490: return TOSTRING_VALUE;
491: }
492: }
|