View Javadoc

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