View Javadoc

1   // ========================================================================
2   // Copyright (c) Webtide LLC
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.monitor.integration;
15  
16  import java.lang.management.ManagementFactory;
17  import java.lang.management.ThreadInfo;
18  import java.lang.management.ThreadMXBean;
19  import java.lang.reflect.InvocationTargetException;
20  import java.lang.reflect.Method;
21  import java.security.Security;
22  import java.util.HashMap;
23  import java.util.Map;
24  
25  /* ------------------------------------------------------------ */
26  /**
27   * Derived from the JMX bean classes created by Kees Jan Koster for the java-monitor
28   * J2EE probe http://code.google.com/p/java-monitor-probes/source/browse/.
29   * 
30   * @author kjkoster <kjkoster@gmail.com>
31   */
32  public class JavaMonitorTools
33  {
34      private static final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
35  
36      private static Method findDeadlockMethod = null;
37  
38      static
39      {
40          try
41          {
42              findDeadlockMethod = ThreadMXBean.class.getMethod("findDeadlockedThreads");
43          }
44          catch (Exception ignored)
45          {
46              // this is a 1.5 JVM
47              try
48              {
49                  findDeadlockMethod = ThreadMXBean.class.getMethod("findMonitorDeadlockedThreads");
50              }
51              catch (SecurityException e)
52              {
53                  e.printStackTrace();
54              }
55              catch (NoSuchMethodException e)
56              {
57                  e.printStackTrace();
58              }
59          }
60      }
61  
62      private ThreadInfo[] findDeadlock()
63          throws IllegalAccessException, InvocationTargetException
64      {
65          final long[] threadIds = (long[])findDeadlockMethod.invoke(threadMXBean,(Object[])null);
66  
67          if (threadIds == null || threadIds.length < 1)
68          {
69              // no deadlock, we're done
70              return null;
71          }
72  
73          final ThreadInfo[] threads = threadMXBean.getThreadInfo(threadIds,Integer.MAX_VALUE);
74          return threads;
75      }
76  
77      public String getDeadlockStacktraces()
78      {
79          try
80          {
81              final ThreadInfo[] threads = findDeadlock();
82              if (threads == null)
83              {
84                  // no deadlock, we're done
85                  return null;
86              }
87  
88              return stacktraces(threads,0);
89          }
90          catch (Exception e)
91          {
92              return e.getMessage();
93          }
94      }
95  
96      private static final int MAX_STACK = 10;
97  
98      private String stacktraces(final ThreadInfo[] threads, final int i)
99      {
100         if (i >= threads.length)
101         {
102             return "";
103         }
104         final ThreadInfo thread = threads[i];
105 
106         final StringBuilder trace = new StringBuilder();
107         for (int stack_i = 0; stack_i < Math.min(thread.getStackTrace().length,MAX_STACK); stack_i++)
108         {
109             if (stack_i == (MAX_STACK - 1))
110             {
111                 trace.append("    ...");
112             }
113             else
114             {
115                 trace.append("    at ").append(thread.getStackTrace()[stack_i]).append("\n");
116             }
117         }
118 
119         return "\"" + thread.getThreadName() + "\", id " + thread.getThreadId() + " is " + thread.getThreadState() + " on " + thread.getLockName()
120                 + ", owned by " + thread.getLockOwnerName() + ", id " + thread.getLockOwnerId() + "\n" + trace + "\n\n" + stacktraces(threads,i + 1);
121     }
122 
123     /**
124      * We keep track of the last time we sampled the thread states.
125      * It is a crude optimization to avoid having to query for the
126      * threads states very often.
127      */
128     private long lastSampled = 0L;
129 
130     private final Map<Thread.State, Integer> states = new HashMap<Thread.State, Integer>();
131 
132     public int getThreadsBlocked()
133     {
134         sampleThreads();
135 
136         return states.get(Thread.State.BLOCKED);
137     }
138 
139     public int getThreadsNew()
140     {
141         sampleThreads();
142 
143         return states.get(Thread.State.NEW);
144     }
145 
146     public int getThreadsTerminated()
147     {
148         sampleThreads();
149 
150         return states.get(Thread.State.TERMINATED);
151     }
152 
153     public int getThreadsTimedWaiting()
154     {
155         sampleThreads();
156 
157         return states.get(Thread.State.TIMED_WAITING);
158     }
159 
160     public int getThreadsWaiting()
161     {
162         sampleThreads();
163 
164         return states.get(Thread.State.WAITING);
165     }
166 
167     public int getThreadsRunnable()
168     {
169         sampleThreads();
170 
171         return states.get(Thread.State.RUNNABLE);
172     }
173 
174     private synchronized void sampleThreads()
175     {
176         if ((lastSampled + 50L) < System.currentTimeMillis())
177         {
178             lastSampled = System.currentTimeMillis();
179             for (final Thread.State state : Thread.State.values())
180             {
181                 states.put(state,0);
182             }
183 
184             for (final ThreadInfo thread : threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds()))
185             {
186                 if (thread != null)
187                 {
188                     final Thread.State state = thread.getThreadState();
189                     states.put(state,states.get(state) + 1);
190                 }
191                 else
192                 {
193                     states.put(Thread.State.TERMINATED,states.get(Thread.State.TERMINATED) + 1);
194                 }
195             }
196         }
197     }
198 
199     private static final String POLICY = "sun.net.InetAddressCachePolicy";
200 
201     public int getCacheSeconds() throws ClassNotFoundException,
202             IllegalAccessException, InvocationTargetException,
203             NoSuchMethodException {
204         final Class policy = Class.forName(POLICY);
205         final Object returnValue = policy.getMethod("get", (Class[]) null)
206                 .invoke(null, (Object[]) null);
207         Integer seconds = (Integer) returnValue;
208 
209         return seconds.intValue();
210     }
211 
212     public int getCacheNegativeSeconds() throws ClassNotFoundException,
213             IllegalAccessException, InvocationTargetException,
214             NoSuchMethodException {
215         final Class policy = Class.forName(POLICY);
216         final Object returnValue = policy.getMethod("getNegative",
217                 (Class[]) null).invoke(null, (Object[]) null);
218         Integer seconds = (Integer) returnValue;
219 
220         return seconds.intValue();
221     }
222 
223     private static final String DEFAULT = "default";
224 
225     private static final String SECURITY = "security";
226 
227     private static final String SYSTEM = "system";
228 
229     private static final String BOTH = "both";
230 
231     private static final String SECURITY_TTL = "networkaddress.cache.ttl";
232 
233     private static final String SYSTEM_TTL = "sun.net.inetaddr.ttl";
234 
235     private static final String SECURITY_NEGATIVE_TTL = "networkaddress.cache.negative.ttl";
236 
237     private static final String SYSTEM_NEGATIVE_TTL = "sun.net.inetaddr.negative.ttl";
238 
239     public String getCacheTweakedFrom() {
240         if (Security.getProperty(SECURITY_TTL) != null) {
241             if (System.getProperty(SYSTEM_TTL) != null) {
242                 return BOTH;
243             }
244 
245             return SECURITY;
246         }
247 
248         if (System.getProperty(SYSTEM_TTL) != null) {
249             return SYSTEM;
250         }
251 
252         return DEFAULT;
253     }
254 
255     public String getCacheNegativeTweakedFrom() {
256         if (Security.getProperty(SECURITY_NEGATIVE_TTL) != null) {
257             if (System.getProperty(SYSTEM_NEGATIVE_TTL) != null) {
258                 return BOTH;
259             }
260 
261             return SECURITY;
262         }
263 
264         if (System.getProperty(SYSTEM_NEGATIVE_TTL) != null) {
265             return SYSTEM;
266         }
267 
268         return DEFAULT;
269     }
270 }