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