View Javadoc
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             new Boolean(threadInfo.isSuspended()),
124             new Boolean(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 }