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 }