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 26package sun.management; 27 28import java.lang.management.ThreadInfo; 29import java.lang.management.MonitorInfo; 30import java.lang.management.LockInfo; 31import javax.management.openmbean.CompositeType; 32import javax.management.openmbean.CompositeData; 33import javax.management.openmbean.CompositeDataSupport; 34import javax.management.openmbean.OpenDataException; 35 36/** 37 * A CompositeData for ThreadInfo for the local management support. 38 * This class avoids the performance penalty paid to the 39 * construction of a CompositeData use in the local case. 40 */ 41public class ThreadInfoCompositeData extends LazyCompositeData { 42 private final ThreadInfo threadInfo; 43 private final CompositeData cdata; 44 private final boolean currentVersion; 45 private final boolean hasV6; 46 47 private ThreadInfoCompositeData(ThreadInfo ti) { 48 this.threadInfo = ti; 49 this.currentVersion = true; 50 this.cdata = null; 51 this.hasV6 = true; 52 } 53 54 private ThreadInfoCompositeData(CompositeData cd) { 55 this.threadInfo = null; 56 this.currentVersion = ThreadInfoCompositeData.isCurrentVersion(cd); 57 this.cdata = cd; 58 this.hasV6 = ThreadInfoCompositeData.hasV6(cd); 59 } 60 61 public ThreadInfo getThreadInfo() { 62 return threadInfo; 63 } 64 65 public boolean hasV6() { 66 return hasV6; 67 } 68 69 public boolean isCurrentVersion() { 70 return currentVersion; 71 } 72 73 public static ThreadInfoCompositeData getInstance(CompositeData cd) { 74 validateCompositeData(cd); 75 return new ThreadInfoCompositeData(cd); 76 } 77 78 public static CompositeData toCompositeData(ThreadInfo ti) { 79 ThreadInfoCompositeData ticd = new ThreadInfoCompositeData(ti); 80 return ticd.getCompositeData(); 81 } 82 83 protected CompositeData getCompositeData() { 84 // Convert StackTraceElement[] to CompositeData[] 85 StackTraceElement[] stackTrace = threadInfo.getStackTrace(); 86 CompositeData[] stackTraceData = 87 new CompositeData[stackTrace.length]; 88 for (int i = 0; i < stackTrace.length; i++) { 89 StackTraceElement ste = stackTrace[i]; 90 stackTraceData[i] = StackTraceElementCompositeData.toCompositeData(ste); 91 } 92 93 // Convert MonitorInfo[] and LockInfo[] to CompositeData[] 94 CompositeData lockInfoData = 95 LockInfoCompositeData.toCompositeData(threadInfo.getLockInfo()); 96 97 // Convert LockInfo[] and MonitorInfo[] to CompositeData[] 98 LockInfo[] lockedSyncs = threadInfo.getLockedSynchronizers(); 99 CompositeData[] lockedSyncsData = 100 new CompositeData[lockedSyncs.length]; 101 for (int i = 0; i < lockedSyncs.length; i++) { 102 LockInfo li = lockedSyncs[i]; 103 lockedSyncsData[i] = LockInfoCompositeData.toCompositeData(li); 104 } 105 106 MonitorInfo[] lockedMonitors = threadInfo.getLockedMonitors(); 107 CompositeData[] lockedMonitorsData = 108 new CompositeData[lockedMonitors.length]; 109 for (int i = 0; i < lockedMonitors.length; i++) { 110 MonitorInfo mi = lockedMonitors[i]; 111 lockedMonitorsData[i] = MonitorInfoCompositeData.toCompositeData(mi); 112 } 113 114 // CONTENTS OF THIS ARRAY MUST BE SYNCHRONIZED WITH 115 // threadInfoItemNames! 116 final Object[] threadInfoItemValues = { 117 threadInfo.getThreadId(), 118 threadInfo.getThreadName(), 119 threadInfo.getThreadState().name(), 120 threadInfo.getBlockedTime(), 121 threadInfo.getBlockedCount(), 122 threadInfo.getWaitedTime(), 123 threadInfo.getWaitedCount(), 124 lockInfoData, 125 threadInfo.getLockName(), 126 threadInfo.getLockOwnerId(), 127 threadInfo.getLockOwnerName(), 128 stackTraceData, 129 threadInfo.isSuspended(), 130 threadInfo.isInNative(), 131 lockedMonitorsData, 132 lockedSyncsData, 133 threadInfo.isDaemon(), 134 threadInfo.getPriority(), 135 }; 136 137 try { 138 return new CompositeDataSupport(threadInfoCompositeType, 139 threadInfoItemNames, 140 threadInfoItemValues); 141 } catch (OpenDataException e) { 142 // Should never reach here 143 throw new AssertionError(e); 144 } 145 } 146 147 // Attribute names 148 private static final String THREAD_ID = "threadId"; 149 private static final String THREAD_NAME = "threadName"; 150 private static final String THREAD_STATE = "threadState"; 151 private static final String BLOCKED_TIME = "blockedTime"; 152 private static final String BLOCKED_COUNT = "blockedCount"; 153 private static final String WAITED_TIME = "waitedTime"; 154 private static final String WAITED_COUNT = "waitedCount"; 155 private static final String LOCK_INFO = "lockInfo"; 156 private static final String LOCK_NAME = "lockName"; 157 private static final String LOCK_OWNER_ID = "lockOwnerId"; 158 private static final String LOCK_OWNER_NAME = "lockOwnerName"; 159 private static final String STACK_TRACE = "stackTrace"; 160 private static final String SUSPENDED = "suspended"; 161 private static final String IN_NATIVE = "inNative"; 162 private static final String DAEMON = "daemon"; 163 private static final String PRIORITY = "priority"; 164 private static final String LOCKED_MONITORS = "lockedMonitors"; 165 private static final String LOCKED_SYNCS = "lockedSynchronizers"; 166 167 private static final String[] threadInfoItemNames = { 168 THREAD_ID, 169 THREAD_NAME, 170 THREAD_STATE, 171 BLOCKED_TIME, 172 BLOCKED_COUNT, 173 WAITED_TIME, 174 WAITED_COUNT, 175 LOCK_INFO, 176 LOCK_NAME, 177 LOCK_OWNER_ID, 178 LOCK_OWNER_NAME, 179 STACK_TRACE, 180 SUSPENDED, 181 IN_NATIVE, 182 LOCKED_MONITORS, 183 LOCKED_SYNCS, 184 DAEMON, 185 PRIORITY, 186 }; 187 188 // New attributes added in 6.0 ThreadInfo 189 private static final String[] threadInfoV6Attributes = { 190 LOCK_INFO, 191 LOCKED_MONITORS, 192 LOCKED_SYNCS, 193 }; 194 195 private static final String[] threadInfoV9Attributes = { 196 DAEMON, 197 PRIORITY, 198 }; 199 200 // Current version of ThreadInfo 201 private static final CompositeType threadInfoCompositeType; 202 // Previous version of ThreadInfo 203 private static final CompositeType threadInfoV6CompositeType; 204 // Previous-previous version of ThreadInfo 205 private static final CompositeType threadInfoV5CompositeType; 206 private static final CompositeType lockInfoCompositeType; 207 static { 208 try { 209 threadInfoCompositeType = (CompositeType) 210 MappedMXBeanType.toOpenType(ThreadInfo.class); 211 // Form a CompositeType for JDK 5.0 ThreadInfo version 212 213 threadInfoV5CompositeType = 214 TypeVersionMapper.getInstance().getVersionedCompositeType( 215 threadInfoCompositeType, TypeVersionMapper.V5 216 ); 217 218 threadInfoV6CompositeType = 219 TypeVersionMapper.getInstance().getVersionedCompositeType( 220 threadInfoCompositeType, TypeVersionMapper.V6 221 ); 222 } catch (OpenDataException e) { 223 // Should never reach here 224 throw new AssertionError(e); 225 } 226 227 // Each CompositeData object has its CompositeType associated 228 // with it. So we can get the CompositeType representing LockInfo 229 // from a mapped CompositeData for any LockInfo object. 230 // Thus we construct a random LockInfo object and pass it 231 // to LockInfoCompositeData to do the conversion. 232 Object o = new Object(); 233 LockInfo li = new LockInfo(o.getClass().getName(), 234 System.identityHashCode(o)); 235 CompositeData cd = LockInfoCompositeData.toCompositeData(li); 236 lockInfoCompositeType = cd.getCompositeType(); 237 } 238 239 static boolean isV5Attribute(String itemName) { 240 for (String n : threadInfoV6Attributes) { 241 if (itemName.equals(n)) { 242 return false; 243 } 244 } 245 for (String n : threadInfoV9Attributes) { 246 if (itemName.equals(n)) { 247 return false; 248 } 249 } 250 return true; 251 } 252 253 static boolean isV6Attribute(String itemName) { 254 for (String n : threadInfoV9Attributes) { 255 if (itemName.equals(n)) { 256 return false; 257 } 258 } 259 return true; 260 } 261 262 public static boolean isCurrentVersion(CompositeData cd) { 263 if (cd == null) { 264 throw new NullPointerException("Null CompositeData"); 265 } 266 267 return isTypeMatched(threadInfoCompositeType, cd.getCompositeType()); 268 } 269 270 private static boolean hasV6(CompositeData cd) { 271 if (cd == null) { 272 throw new NullPointerException("Null CompositeData"); 273 } 274 275 return isTypeMatched(threadInfoCompositeType, cd.getCompositeType()) || 276 isTypeMatched(threadInfoV6CompositeType, cd.getCompositeType()); 277 } 278 279 public long threadId() { 280 return getLong(cdata, THREAD_ID); 281 } 282 283 public String threadName() { 284 // The ThreadName item cannot be null so we check that 285 // it is present with a non-null value. 286 String name = getString(cdata, THREAD_NAME); 287 if (name == null) { 288 throw new IllegalArgumentException("Invalid composite data: " + 289 "Attribute " + THREAD_NAME + " has null value"); 290 } 291 return name; 292 } 293 294 public Thread.State threadState() { 295 return Thread.State.valueOf(getString(cdata, THREAD_STATE)); 296 } 297 298 public long blockedTime() { 299 return getLong(cdata, BLOCKED_TIME); 300 } 301 302 public long blockedCount() { 303 return getLong(cdata, BLOCKED_COUNT); 304 } 305 306 public long waitedTime() { 307 return getLong(cdata, WAITED_TIME); 308 } 309 310 public long waitedCount() { 311 return getLong(cdata, WAITED_COUNT); 312 } 313 314 public String lockName() { 315 // The LockName and LockOwnerName can legitimately be null, 316 // we don't bother to check the value 317 return getString(cdata, LOCK_NAME); 318 } 319 320 public long lockOwnerId() { 321 return getLong(cdata, LOCK_OWNER_ID); 322 } 323 324 public String lockOwnerName() { 325 return getString(cdata, LOCK_OWNER_NAME); 326 } 327 328 public boolean suspended() { 329 return getBoolean(cdata, SUSPENDED); 330 } 331 332 public boolean inNative() { 333 return getBoolean(cdata, IN_NATIVE); 334 } 335 336 public boolean isDaemon() { 337 return getBoolean(cdata, DAEMON); 338 } 339 340 public int getPriority(){ 341 return getInt(cdata, PRIORITY); 342 } 343 344 public StackTraceElement[] stackTrace() { 345 CompositeData[] stackTraceData = 346 (CompositeData[]) cdata.get(STACK_TRACE); 347 348 // The StackTrace item cannot be null, but if it is we will get 349 // a NullPointerException when we ask for its length. 350 StackTraceElement[] stackTrace = 351 new StackTraceElement[stackTraceData.length]; 352 for (int i = 0; i < stackTraceData.length; i++) { 353 CompositeData cdi = stackTraceData[i]; 354 stackTrace[i] = StackTraceElementCompositeData.from(cdi); 355 } 356 return stackTrace; 357 } 358 359 // 6.0 new attributes 360 public LockInfo lockInfo() { 361 CompositeData lockInfoData = (CompositeData) cdata.get(LOCK_INFO); 362 return LockInfo.from(lockInfoData); 363 } 364 365 public MonitorInfo[] lockedMonitors() { 366 CompositeData[] lockedMonitorsData = 367 (CompositeData[]) cdata.get(LOCKED_MONITORS); 368 369 // The LockedMonitors item cannot be null, but if it is we will get 370 // a NullPointerException when we ask for its length. 371 MonitorInfo[] monitors = 372 new MonitorInfo[lockedMonitorsData.length]; 373 for (int i = 0; i < lockedMonitorsData.length; i++) { 374 CompositeData cdi = lockedMonitorsData[i]; 375 monitors[i] = MonitorInfo.from(cdi); 376 } 377 return monitors; 378 } 379 380 public LockInfo[] lockedSynchronizers() { 381 CompositeData[] lockedSyncsData = 382 (CompositeData[]) cdata.get(LOCKED_SYNCS); 383 384 // The LockedSynchronizers item cannot be null, but if it is we will 385 // get a NullPointerException when we ask for its length. 386 LockInfo[] locks = new LockInfo[lockedSyncsData.length]; 387 for (int i = 0; i < lockedSyncsData.length; i++) { 388 CompositeData cdi = lockedSyncsData[i]; 389 locks[i] = LockInfo.from(cdi); 390 } 391 return locks; 392 } 393 394 /** Validate if the input CompositeData has the expected 395 * CompositeType (i.e. contain all attributes with expected 396 * names and types). 397 */ 398 public static void validateCompositeData(CompositeData cd) { 399 if (cd == null) { 400 throw new NullPointerException("Null CompositeData"); 401 } 402 403 CompositeType type = cd.getCompositeType(); 404 boolean currentVersion = true; 405 if (!isTypeMatched(threadInfoCompositeType, type)) { 406 currentVersion = false; 407 // check if cd is an older version 408 if (!isTypeMatched(threadInfoV5CompositeType, type) && 409 !isTypeMatched(threadInfoV6CompositeType, type)) { 410 throw new IllegalArgumentException( 411 "Unexpected composite type for ThreadInfo"); 412 } 413 } 414 415 CompositeData[] stackTraceData = 416 (CompositeData[]) cd.get(STACK_TRACE); 417 if (stackTraceData == null) { 418 throw new IllegalArgumentException( 419 "StackTraceElement[] is missing"); 420 } 421 if (stackTraceData.length > 0) { 422 StackTraceElementCompositeData.validateCompositeData(stackTraceData[0]); 423 } 424 425 // validate v6 attributes 426 if (currentVersion) { 427 CompositeData li = (CompositeData) cd.get(LOCK_INFO); 428 if (li != null) { 429 if (!isTypeMatched(lockInfoCompositeType, 430 li.getCompositeType())) { 431 throw new IllegalArgumentException( 432 "Unexpected composite type for \"" + 433 LOCK_INFO + "\" attribute."); 434 } 435 } 436 437 CompositeData[] lms = (CompositeData[]) cd.get(LOCKED_MONITORS); 438 if (lms == null) { 439 throw new IllegalArgumentException("MonitorInfo[] is null"); 440 } 441 if (lms.length > 0) { 442 MonitorInfoCompositeData.validateCompositeData(lms[0]); 443 } 444 445 CompositeData[] lsyncs = (CompositeData[]) cd.get(LOCKED_SYNCS); 446 if (lsyncs == null) { 447 throw new IllegalArgumentException("LockInfo[] is null"); 448 } 449 if (lsyncs.length > 0) { 450 if (!isTypeMatched(lockInfoCompositeType, 451 lsyncs[0].getCompositeType())) { 452 throw new IllegalArgumentException( 453 "Unexpected composite type for \"" + 454 LOCKED_SYNCS + "\" attribute."); 455 } 456 } 457 458 } 459 } 460 461 private static final long serialVersionUID = 2464378539119753175L; 462} 463