1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.util;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.PrintStream;
23 import java.io.UnsupportedEncodingException;
24 import java.lang.management.ManagementFactory;
25 import java.lang.management.ThreadInfo;
26 import java.lang.management.ThreadMXBean;
27 import java.lang.reflect.Constructor;
28 import java.lang.reflect.InvocationTargetException;
29 import java.nio.charset.Charset;
30
31 import org.apache.commons.logging.Log;
32
33 import org.apache.hadoop.hbase.classification.InterfaceAudience;
34
35 @InterfaceAudience.Private
36 public class ReflectionUtils {
37 @SuppressWarnings("unchecked")
38 public static <T> T instantiateWithCustomCtor(String className,
39 Class<? >[] ctorArgTypes, Object[] ctorArgs) {
40 try {
41 Class<? extends T> resultType = (Class<? extends T>) Class.forName(className);
42 Constructor<? extends T> ctor = resultType.getDeclaredConstructor(ctorArgTypes);
43 return instantiate(className, ctor, ctorArgs);
44 } catch (ClassNotFoundException e) {
45 throw new UnsupportedOperationException(
46 "Unable to find " + className, e);
47 } catch (NoSuchMethodException e) {
48 throw new UnsupportedOperationException(
49 "Unable to find suitable constructor for class " + className, e);
50 }
51 }
52
53 private static <T> T instantiate(final String className, Constructor<T> ctor, Object[] ctorArgs) {
54 try {
55 return ctor.newInstance(ctorArgs);
56 } catch (IllegalAccessException e) {
57 throw new UnsupportedOperationException(
58 "Unable to access specified class " + className, e);
59 } catch (InstantiationException e) {
60 throw new UnsupportedOperationException(
61 "Unable to instantiate specified class " + className, e);
62 } catch (InvocationTargetException e) {
63 throw new UnsupportedOperationException(
64 "Constructor threw an exception for " + className, e);
65 }
66 }
67
68 @SuppressWarnings("unchecked")
69 public static <T> T newInstance(Class<T> type, Object... params) {
70 return instantiate(type.getName(), findConstructor(type, params), params);
71 }
72
73 @SuppressWarnings("unchecked")
74 public static <T> Constructor<T> findConstructor(Class<T> type, Object... paramTypes) {
75 Constructor<T>[] constructors = (Constructor<T>[])type.getConstructors();
76 for (Constructor<T> ctor : constructors) {
77 Class<?>[] ctorParamTypes = ctor.getParameterTypes();
78 if (ctorParamTypes.length != paramTypes.length) {
79 continue;
80 }
81
82 boolean match = true;
83 for (int i = 0; i < ctorParamTypes.length && match; ++i) {
84 Class<?> paramType = paramTypes[i].getClass();
85 match = (!ctorParamTypes[i].isPrimitive()) ? ctorParamTypes[i].isAssignableFrom(paramType) :
86 ((int.class.equals(ctorParamTypes[i]) && Integer.class.equals(paramType)) ||
87 (long.class.equals(ctorParamTypes[i]) && Long.class.equals(paramType)) ||
88 (char.class.equals(ctorParamTypes[i]) && Character.class.equals(paramType)) ||
89 (short.class.equals(ctorParamTypes[i]) && Short.class.equals(paramType)) ||
90 (boolean.class.equals(ctorParamTypes[i]) && Boolean.class.equals(paramType)) ||
91 (byte.class.equals(ctorParamTypes[i]) && Byte.class.equals(paramType)));
92 }
93
94 if (match) {
95 return ctor;
96 }
97 }
98 throw new UnsupportedOperationException(
99 "Unable to find suitable constructor for class " + type.getName());
100 }
101
102
103 private static long previousLogTime = 0;
104 private static final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
105
106
107
108
109
110
111
112 public static void logThreadInfo(Log log,
113 String title,
114 long minInterval) {
115 boolean dumpStack = false;
116 if (log.isInfoEnabled()) {
117 synchronized (ReflectionUtils.class) {
118 long now = System.currentTimeMillis();
119 if (now - previousLogTime >= minInterval * 1000) {
120 previousLogTime = now;
121 dumpStack = true;
122 }
123 }
124 if (dumpStack) {
125 try {
126 ByteArrayOutputStream buffer = new ByteArrayOutputStream();
127 printThreadInfo(new PrintStream(buffer, false, "UTF-8"), title);
128 log.info(buffer.toString(Charset.defaultCharset().name()));
129 } catch (UnsupportedEncodingException ignored) {
130 log.warn("Could not write thread info about '" + title +
131 "' due to a string encoding issue.");
132 }
133 }
134 }
135 }
136
137
138
139
140
141
142
143 private static void printThreadInfo(PrintStream stream,
144 String title) {
145 final int STACK_DEPTH = 20;
146 boolean contention = threadBean.isThreadContentionMonitoringEnabled();
147 long[] threadIds = threadBean.getAllThreadIds();
148 stream.println("Process Thread Dump: " + title);
149 stream.println(threadIds.length + " active threads");
150 for (long tid: threadIds) {
151 ThreadInfo info = threadBean.getThreadInfo(tid, STACK_DEPTH);
152 if (info == null) {
153 stream.println(" Inactive");
154 continue;
155 }
156 stream.println("Thread " +
157 getTaskName(info.getThreadId(),
158 info.getThreadName()) + ":");
159 Thread.State state = info.getThreadState();
160 stream.println(" State: " + state);
161 stream.println(" Blocked count: " + info.getBlockedCount());
162 stream.println(" Waited count: " + info.getWaitedCount());
163 if (contention) {
164 stream.println(" Blocked time: " + info.getBlockedTime());
165 stream.println(" Waited time: " + info.getWaitedTime());
166 }
167 if (state == Thread.State.WAITING) {
168 stream.println(" Waiting on " + info.getLockName());
169 } else if (state == Thread.State.BLOCKED) {
170 stream.println(" Blocked on " + info.getLockName());
171 stream.println(" Blocked by " +
172 getTaskName(info.getLockOwnerId(),
173 info.getLockOwnerName()));
174 }
175 stream.println(" Stack:");
176 for (StackTraceElement frame: info.getStackTrace()) {
177 stream.println(" " + frame.toString());
178 }
179 }
180 stream.flush();
181 }
182
183 private static String getTaskName(long id, String name) {
184 if (name == null) {
185 return Long.toString(id);
186 }
187 return id + " (" + name + ")";
188 }
189
190 }