1 /* 2 * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.management; 27 28 import java.lang.management.ThreadInfo; 29 import java.lang.management.MonitorInfo; 30 import java.lang.management.LockInfo; 31 import javax.management.openmbean.CompositeType; 32 import javax.management.openmbean.CompositeData; 33 import javax.management.openmbean.CompositeDataSupport; 34 import javax.management.openmbean.OpenDataException; 35 import javax.management.openmbean.OpenType; 36 37 /** 38 * A CompositeData for ThreadInfo for the local management support. 39 * This class avoids the performance penalty paid to the 40 * construction of a CompositeData use in the local case. 41 */ 42 public class ThreadInfoCompositeData extends LazyCompositeData { 43 private final ThreadInfo threadInfo; 44 private final CompositeData cdata; 45 private final boolean currentVersion; 46 47 private ThreadInfoCompositeData(ThreadInfo ti) { 48 this.threadInfo = ti; 49 this.currentVersion = true; 50 this.cdata = null; 51 } 52 53 private ThreadInfoCompositeData(CompositeData cd) { 54 this.threadInfo = null; 55 this.currentVersion = ThreadInfoCompositeData.isCurrentVersion(cd); 56 this.cdata = cd; 57 } 58 59 public ThreadInfo getThreadInfo() { 60 return threadInfo; 61 } 62 63 public boolean isCurrentVersion() { 64 return currentVersion; 65 } 66 67 public static ThreadInfoCompositeData getInstance(CompositeData cd) { 68 validateCompositeData(cd); 69 return new ThreadInfoCompositeData(cd); 70 } 71 72 public static CompositeData toCompositeData(ThreadInfo ti) { 73 ThreadInfoCompositeData ticd = new ThreadInfoCompositeData(ti); 74 return ticd.getCompositeData(); 75 } 76 77 protected CompositeData getCompositeData() { 78 // Convert StackTraceElement[] to CompositeData[] 79 StackTraceElement[] stackTrace = threadInfo.getStackTrace(); 80 CompositeData[] stackTraceData = 81 new CompositeData[stackTrace.length]; 82 for (int i = 0; i < stackTrace.length; i++) { 83 StackTraceElement ste = stackTrace[i]; 84 stackTraceData[i] = StackTraceElementCompositeData.toCompositeData(ste); 85 } 86 87 // Convert MonitorInfo[] and LockInfo[] to CompositeData[] 88 CompositeData lockInfoData = 89 LockInfoCompositeData.toCompositeData(threadInfo.getLockInfo()); 90 91 // Convert LockInfo[] and MonitorInfo[] to CompositeData[] 92 LockInfo[] lockedSyncs = threadInfo.getLockedSynchronizers(); 93 CompositeData[] lockedSyncsData = 94 new CompositeData[lockedSyncs.length]; 95 for (int i = 0; i < lockedSyncs.length; i++) { 96 LockInfo li = lockedSyncs[i]; 97 lockedSyncsData[i] = LockInfoCompositeData.toCompositeData(li); 98 } 99 100 MonitorInfo[] lockedMonitors = threadInfo.getLockedMonitors(); 101 CompositeData[] lockedMonitorsData = 102 new CompositeData[lockedMonitors.length]; 103 for (int i = 0; i < lockedMonitors.length; i++) { 104 MonitorInfo mi = lockedMonitors[i]; 105 lockedMonitorsData[i] = MonitorInfoCompositeData.toCompositeData(mi); 106 } 107 108 // CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH 109 // threadInfoItemNames! 110 final Object[] threadInfoItemValues = { 111 new Long(threadInfo.getThreadId()), 112 threadInfo.getThreadName(), 113 threadInfo.getThreadState().name(), 114 new Long(threadInfo.getBlockedTime()), 115 new Long(threadInfo.getBlockedCount()), 116 new Long(threadInfo.getWaitedTime()), 117 new Long(threadInfo.getWaitedCount()), 118 lockInfoData, 119 threadInfo.getLockName(), 120 new Long(threadInfo.getLockOwnerId()), 121 threadInfo.getLockOwnerName(), 122 stackTraceData, 123 threadInfo.isSuspended(), 124 threadInfo.isInNative(), 125 lockedMonitorsData, 126 lockedSyncsData, 127 }; 128 129 try { 130 return new CompositeDataSupport(threadInfoCompositeType, 131 threadInfoItemNames, 132 threadInfoItemValues); 133 } catch (OpenDataException e) { 134 // Should never reach here 135 throw new AssertionError(e); 136 } 137 } 138 139 // Attribute names 140 private static final String THREAD_ID = "threadId"; 141 private static final String THREAD_NAME = "threadName"; 142 private static final String THREAD_STATE = "threadState"; 143 private static final String BLOCKED_TIME = "blockedTime"; 144 private static final String BLOCKED_COUNT = "blockedCount"; 145 private static final String WAITED_TIME = "waitedTime"; 146 private static final String WAITED_COUNT = "waitedCount"; 147 private static final String LOCK_INFO = "lockInfo"; 148 private static final String LOCK_NAME = "lockName"; 149 private static final String LOCK_OWNER_ID = "lockOwnerId"; 150 private static final String LOCK_OWNER_NAME = "lockOwnerName"; 151 private static final String STACK_TRACE = "stackTrace"; 152 private static final String SUSPENDED = "suspended"; 153 private static final String IN_NATIVE = "inNative"; 154 private static final String LOCKED_MONITORS = "lockedMonitors"; 155 private static final String LOCKED_SYNCS = "lockedSynchronizers"; 156 157 private static final String[] threadInfoItemNames = { 158 THREAD_ID, 159 THREAD_NAME, 160 THREAD_STATE, 161 BLOCKED_TIME, 162 BLOCKED_COUNT, 163 WAITED_TIME, 164 WAITED_COUNT, 165 LOCK_INFO, 166 LOCK_NAME, 167 LOCK_OWNER_ID, 168 LOCK_OWNER_NAME, 169 STACK_TRACE, 170 SUSPENDED, 171 IN_NATIVE, 172 LOCKED_MONITORS, 173 LOCKED_SYNCS, 174 }; 175 176 // New attributes added in 6.0 ThreadInfo 177 private static final String[] threadInfoV6Attributes = { 178 LOCK_INFO, 179 LOCKED_MONITORS, 180 LOCKED_SYNCS, 181 }; 182 183 // Current version of ThreadInfo 184 private static final CompositeType threadInfoCompositeType; 185 // Previous version of ThreadInfo 186 private static final CompositeType threadInfoV5CompositeType; 187 private static final CompositeType lockInfoCompositeType; 188 static { 189 try { 190 threadInfoCompositeType = (CompositeType) 191 MappedMXBeanType.toOpenType(ThreadInfo.class); 192 // Form a CompositeType for JDK 5.0 ThreadInfo version 193 String[] itemNames = 194 threadInfoCompositeType.keySet().toArray(new String[0]); 195 int numV5Attributes = threadInfoItemNames.length - 196 threadInfoV6Attributes.length; 197 String[] v5ItemNames = new String[numV5Attributes]; 198 String[] v5ItemDescs = new String[numV5Attributes]; 199 OpenType<?>[] v5ItemTypes = new OpenType<?>[numV5Attributes]; 200 int i = 0; 201 for (String n : itemNames) { 202 if (isV5Attribute(n)) { 203 v5ItemNames[i] = n; 204 v5ItemDescs[i] = threadInfoCompositeType.getDescription(n); 205 v5ItemTypes[i] = threadInfoCompositeType.getType(n); 206 i++; 207 } 208 } 209 210 threadInfoV5CompositeType = 211 new CompositeType("java.lang.management.ThreadInfo", 212 "J2SE 5.0 java.lang.management.ThreadInfo", 213 v5ItemNames, 214 v5ItemDescs, 215 v5ItemTypes); 216 } catch (OpenDataException e) { 217 // Should never reach here 218 throw new AssertionError(e); 219 } 220 221 // Each CompositeData object has its CompositeType associated 222 // with it. So we can get the CompositeType representing LockInfo 223 // from a mapped CompositeData for any LockInfo object. 224 // Thus we construct a random LockInfo object and pass it 225 // to LockInfoCompositeData to do the conversion. 226 Object o = new Object(); 227 LockInfo li = new LockInfo(o.getClass().getName(), 228 System.identityHashCode(o)); 229 CompositeData cd = LockInfoCompositeData.toCompositeData(li); 230 lockInfoCompositeType = cd.getCompositeType(); 231 } 232 233 private static boolean isV5Attribute(String itemName) { 234 for (String n : threadInfoV6Attributes) { 235 if (itemName.equals(n)) { 236 return false; 237 } 238 } 239 return true; 240 } 241 242 public static boolean isCurrentVersion(CompositeData cd) { 243 if (cd == null) { 244 throw new NullPointerException("Null CompositeData"); 245 } 246 247 return isTypeMatched(threadInfoCompositeType, cd.getCompositeType()); 248 } 249 250 public long threadId() { 251 return getLong(cdata, THREAD_ID); 252 } 253 254 public String threadName() { 255 // The ThreadName item cannot be null so we check that 256 // it is present with a non-null value. 257 String name = getString(cdata, THREAD_NAME); 258 if (name == null) { 259 throw new IllegalArgumentException("Invalid composite data: " + 260 "Attribute " + THREAD_NAME + " has null value"); 261 } 262 return name; 263 } 264 265 public Thread.State threadState() { 266 return Thread.State.valueOf(getString(cdata, THREAD_STATE)); 267 } 268 269 public long blockedTime() { 270 return getLong(cdata, BLOCKED_TIME); 271 } 272 273 public long blockedCount() { 274 return getLong(cdata, BLOCKED_COUNT); 275 } 276 277 public long waitedTime() { 278 return getLong(cdata, WAITED_TIME); 279 } 280 281 public long waitedCount() { 282 return getLong(cdata, WAITED_COUNT); 283 } 284 285 public String lockName() { 286 // The LockName and LockOwnerName can legitimately be null, 287 // we don't bother to check the value 288 return getString(cdata, LOCK_NAME); 289 } 290 291 public long lockOwnerId() { 292 return getLong(cdata, LOCK_OWNER_ID); 293 } 294 295 public String lockOwnerName() { 296 return getString(cdata, LOCK_OWNER_NAME); 297 } 298 299 public boolean suspended() { 300 return getBoolean(cdata, SUSPENDED); 301 } 302 303 public boolean inNative() { 304 return getBoolean(cdata, IN_NATIVE); 305 } 306 307 public StackTraceElement[] stackTrace() { 308 CompositeData[] stackTraceData = 309 (CompositeData[]) cdata.get(STACK_TRACE); 310 311 // The StackTrace item cannot be null, but if it is we will get 312 // a NullPointerException when we ask for its length. 313 StackTraceElement[] stackTrace = 314 new StackTraceElement[stackTraceData.length]; 315 for (int i = 0; i < stackTraceData.length; i++) { 316 CompositeData cdi = stackTraceData[i]; 317 stackTrace[i] = StackTraceElementCompositeData.from(cdi); 318 } 319 return stackTrace; 320 } 321 322 // 6.0 new attributes 323 public LockInfo lockInfo() { 324 CompositeData lockInfoData = (CompositeData) cdata.get(LOCK_INFO); 325 return LockInfo.from(lockInfoData); 326 } 327 328 public MonitorInfo[] lockedMonitors() { 329 CompositeData[] lockedMonitorsData = 330 (CompositeData[]) cdata.get(LOCKED_MONITORS); 331 332 // The LockedMonitors item cannot be null, but if it is we will get 333 // a NullPointerException when we ask for its length. 334 MonitorInfo[] monitors = 335 new MonitorInfo[lockedMonitorsData.length]; 336 for (int i = 0; i < lockedMonitorsData.length; i++) { 337 CompositeData cdi = lockedMonitorsData[i]; 338 monitors[i] = MonitorInfo.from(cdi); 339 } 340 return monitors; 341 } 342 343 public LockInfo[] lockedSynchronizers() { 344 CompositeData[] lockedSyncsData = 345 (CompositeData[]) cdata.get(LOCKED_SYNCS); 346 347 // The LockedSynchronizers item cannot be null, but if it is we will 348 // get a NullPointerException when we ask for its length. 349 LockInfo[] locks = new LockInfo[lockedSyncsData.length]; 350 for (int i = 0; i < lockedSyncsData.length; i++) { 351 CompositeData cdi = lockedSyncsData[i]; 352 locks[i] = LockInfo.from(cdi); 353 } 354 return locks; 355 } 356 357 /** Validate if the input CompositeData has the expected 358 * CompositeType (i.e. contain all attributes with expected 359 * names and types). 360 */ 361 public static void validateCompositeData(CompositeData cd) { 362 if (cd == null) { 363 throw new NullPointerException("Null CompositeData"); 364 } 365 366 CompositeType type = cd.getCompositeType(); 367 boolean currentVersion = true; 368 if (!isTypeMatched(threadInfoCompositeType, type)) { 369 currentVersion = false; 370 // check if cd is an older version 371 if (!isTypeMatched(threadInfoV5CompositeType, type)) { 372 throw new IllegalArgumentException( 373 "Unexpected composite type for ThreadInfo"); 374 } 375 } 376 377 CompositeData[] stackTraceData = 378 (CompositeData[]) cd.get(STACK_TRACE); 379 if (stackTraceData == null) { 380 throw new IllegalArgumentException( 381 "StackTraceElement[] is missing"); 382 } 383 if (stackTraceData.length > 0) { 384 StackTraceElementCompositeData.validateCompositeData(stackTraceData[0]); 385 } 386 387 // validate v6 attributes 388 if (currentVersion) { 389 CompositeData li = (CompositeData) cd.get(LOCK_INFO); 390 if (li != null) { 391 if (!isTypeMatched(lockInfoCompositeType, 392 li.getCompositeType())) { 393 throw new IllegalArgumentException( 394 "Unexpected composite type for \"" + 395 LOCK_INFO + "\" attribute."); 396 } 397 } 398 399 CompositeData[] lms = (CompositeData[]) cd.get(LOCKED_MONITORS); 400 if (lms == null) { 401 throw new IllegalArgumentException("MonitorInfo[] is null"); 402 } 403 if (lms.length > 0) { 404 MonitorInfoCompositeData.validateCompositeData(lms[0]); 405 } 406 407 CompositeData[] lsyncs = (CompositeData[]) cd.get(LOCKED_SYNCS); 408 if (lsyncs == null) { 409 throw new IllegalArgumentException("LockInfo[] is null"); 410 } 411 if (lsyncs.length > 0) { 412 if (!isTypeMatched(lockInfoCompositeType, 413 lsyncs[0].getCompositeType())) { 414 throw new IllegalArgumentException( 415 "Unexpected composite type for \"" + 416 LOCKED_SYNCS + "\" attribute."); 417 } 418 } 419 420 } 421 } 422 423 private static final long serialVersionUID = 2464378539119753175L; 424 }