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