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 (double.class.equals(ctorParamTypes[i]) && Double.class.equals(paramType)) ||
89 (char.class.equals(ctorParamTypes[i]) && Character.class.equals(paramType)) ||
90 (short.class.equals(ctorParamTypes[i]) && Short.class.equals(paramType)) ||
91 (boolean.class.equals(ctorParamTypes[i]) && Boolean.class.equals(paramType)) ||
92 (byte.class.equals(ctorParamTypes[i]) && Byte.class.equals(paramType)));
93 }
94
95 if (match) {
96 return ctor;
97 }
98 }
99 throw new UnsupportedOperationException(
100 "Unable to find suitable constructor for class " + type.getName());
101 }
102
103
104 private static long previousLogTime = 0;
105 private static final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
106
107
108
109
110
111
112
113 public static void logThreadInfo(Log log,
114 String title,
115 long minInterval) {
116 boolean dumpStack = false;
117 if (log.isInfoEnabled()) {
118 synchronized (ReflectionUtils.class) {
119 long now = System.currentTimeMillis();
120 if (now - previousLogTime >= minInterval * 1000) {
121 previousLogTime = now;
122 dumpStack = true;
123 }
124 }
125 if (dumpStack) {
126 try {
127 ByteArrayOutputStream buffer = new ByteArrayOutputStream();
128 printThreadInfo(new PrintStream(buffer, false, "UTF-8"), title);
129 log.info(buffer.toString(Charset.defaultCharset().name()));
130 } catch (UnsupportedEncodingException ignored) {
131 log.warn("Could not write thread info about '" + title +
132 "' due to a string encoding issue.");
133 }
134 }
135 }
136 }
137
138
139
140
141
142
143
144 private static void printThreadInfo(PrintStream stream,
145 String title) {
146 final int STACK_DEPTH = 20;
147 boolean contention = threadBean.isThreadContentionMonitoringEnabled();
148 long[] threadIds = threadBean.getAllThreadIds();
149 stream.println("Process Thread Dump: " + title);
150 stream.println(threadIds.length + " active threads");
151 for (long tid: threadIds) {
152 ThreadInfo info = threadBean.getThreadInfo(tid, STACK_DEPTH);
153 if (info == null) {
154 stream.println(" Inactive");
155 continue;
156 }
157 stream.println("Thread " +
158 getTaskName(info.getThreadId(),
159 info.getThreadName()) + ":");
160 Thread.State state = info.getThreadState();
161 stream.println(" State: " + state);
162 stream.println(" Blocked count: " + info.getBlockedCount());
163 stream.println(" Waited count: " + info.getWaitedCount());
164 if (contention) {
165 stream.println(" Blocked time: " + info.getBlockedTime());
166 stream.println(" Waited time: " + info.getWaitedTime());
167 }
168 if (state == Thread.State.WAITING) {
169 stream.println(" Waiting on " + info.getLockName());
170 } else if (state == Thread.State.BLOCKED) {
171 stream.println(" Blocked on " + info.getLockName());
172 stream.println(" Blocked by " +
173 getTaskName(info.getLockOwnerId(),
174 info.getLockOwnerName()));
175 }
176 stream.println(" Stack:");
177 for (StackTraceElement frame: info.getStackTrace()) {
178 stream.println(" " + frame.toString());
179 }
180 }
181 stream.flush();
182 }
183
184 private static String getTaskName(long id, String name) {
185 if (name == null) {
186 return Long.toString(id);
187 }
188 return id + " (" + name + ")";
189 }
190
191 }