1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.util;
18
19 import java.lang.reflect.Method;
20 import java.util.Stack;
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public final class StackLocator {
48
49 private static PrivateSecurityManager SECURITY_MANAGER;
50
51
52
53 static final int JDK_7u25_OFFSET;
54
55
56 private static final Method GET_CALLER_CLASS;
57
58 private static final StackLocator INSTANCE;
59
60 static {
61 Method getCallerClass;
62 int java7u25CompensationOffset = 0;
63 try {
64 final Class<?> sunReflectionClass = LoaderUtil.loadClass("sun.reflect.Reflection");
65 getCallerClass = sunReflectionClass.getDeclaredMethod("getCallerClass", int.class);
66 Object o = getCallerClass.invoke(null, 0);
67 getCallerClass.invoke(null, 0);
68 if (o == null || o != sunReflectionClass) {
69 getCallerClass = null;
70 java7u25CompensationOffset = -1;
71 } else {
72 o = getCallerClass.invoke(null, 1);
73 if (o == sunReflectionClass) {
74 System.out.println("WARNING: Java 1.7.0_25 is in use which has a broken implementation of Reflection.getCallerClass(). " +
75 " Please consider upgrading to Java 1.7.0_40 or later.");
76 java7u25CompensationOffset = 1;
77 }
78 }
79 } catch (final Exception | LinkageError e) {
80 System.out.println("WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance.");
81 getCallerClass = null;
82 java7u25CompensationOffset = -1;
83 }
84
85 GET_CALLER_CLASS = getCallerClass;
86 JDK_7u25_OFFSET = java7u25CompensationOffset;
87
88 INSTANCE = new StackLocator();
89 }
90
91 public static StackLocator getInstance() {
92 return INSTANCE;
93 }
94
95 private StackLocator() {
96 }
97
98
99
100
101
102 @PerformanceSensitive
103 public Class<?> getCallerClass(final int depth) {
104 if (depth < 0) {
105 throw new IndexOutOfBoundsException(Integer.toString(depth));
106 }
107
108
109 try {
110 return (Class<?>) GET_CALLER_CLASS.invoke(null, depth + 1 + JDK_7u25_OFFSET);
111 } catch (final Exception e) {
112
113
114 return null;
115 }
116 }
117
118
119 @PerformanceSensitive
120 public Class<?> getCallerClass(final String fqcn, final String pkg) {
121 boolean next = false;
122 Class<?> clazz;
123 for (int i = 2; null != (clazz = getCallerClass(i)); i++) {
124 if (fqcn.equals(clazz.getName())) {
125 next = true;
126 continue;
127 }
128 if (next && clazz.getName().startsWith(pkg)) {
129 return clazz;
130 }
131 }
132
133 return null;
134 }
135
136
137 @PerformanceSensitive
138 public Class<?> getCallerClass(final Class<?> anchor) {
139 boolean next = false;
140 Class<?> clazz;
141 for (int i = 2; null != (clazz = getCallerClass(i)); i++) {
142 if (anchor.equals(clazz)) {
143 next = true;
144 continue;
145 }
146 if (next) {
147 return clazz;
148 }
149 }
150 return Object.class;
151 }
152
153
154 @PerformanceSensitive
155 public Stack<Class<?>> getCurrentStackTrace() {
156
157 if (getSecurityManager() != null) {
158 final Class<?>[] array = getSecurityManager().getClassContext();
159 final Stack<Class<?>> classes = new Stack<>();
160 classes.ensureCapacity(array.length);
161 for (final Class<?> clazz : array) {
162 classes.push(clazz);
163 }
164 return classes;
165 }
166
167 final Stack<Class<?>> classes = new Stack<>();
168 Class<?> clazz;
169 for (int i = 1; null != (clazz = getCallerClass(i)); i++) {
170 classes.push(clazz);
171 }
172 return classes;
173 }
174
175 public StackTraceElement calcLocation(final String fqcnOfLogger) {
176 if (fqcnOfLogger == null) {
177 return null;
178 }
179
180 final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
181 StackTraceElement last = null;
182 for (int i = stackTrace.length - 1; i > 0; i--) {
183 final String className = stackTrace[i].getClassName();
184 if (fqcnOfLogger.equals(className)) {
185 return last;
186 }
187 last = stackTrace[i];
188 }
189 return null;
190 }
191
192 public StackTraceElement getStackTraceElement(final int depth) {
193
194
195 final StackTraceElement[] elements = new Throwable().getStackTrace();
196 int i = 0;
197 for (final StackTraceElement element : elements) {
198 if (isValid(element)) {
199 if (i == depth) {
200 return element;
201 }
202 ++i;
203 }
204 }
205 throw new IndexOutOfBoundsException(Integer.toString(depth));
206 }
207
208 private boolean isValid(final StackTraceElement element) {
209
210 if (element.isNativeMethod()) {
211 return false;
212 }
213 final String cn = element.getClassName();
214
215 if (cn.startsWith("sun.reflect.")) {
216 return false;
217 }
218 final String mn = element.getMethodName();
219
220
221
222
223 if (cn.startsWith("java.lang.reflect.") && (mn.equals("invoke") || mn.equals("newInstance"))) {
224 return false;
225 }
226
227 if (cn.startsWith("jdk.internal.reflect.")) {
228 return false;
229 }
230
231 if (cn.equals("java.lang.Class") && mn.equals("newInstance")) {
232 return false;
233 }
234
235 if (cn.equals("java.lang.invoke.MethodHandle") && mn.startsWith("invoke")) {
236 return false;
237 }
238
239 return true;
240 }
241
242 protected PrivateSecurityManager getSecurityManager() {
243 return SECURITY_MANAGER;
244 }
245
246 private static final class PrivateSecurityManager extends SecurityManager {
247
248 @Override
249 protected Class<?>[] getClassContext() {
250 return super.getClassContext();
251 }
252
253 }
254 }