1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.log4j.spi;
21
22 import org.apache.log4j.Layout;
23 import org.apache.log4j.helpers.LogLog;
24
25 import java.io.PrintWriter;
26 import java.io.StringWriter;
27 import java.io.InterruptedIOException;
28 import java.lang.reflect.Method;
29 import java.lang.reflect.InvocationTargetException;
30
31
32
33
34
35
36 public class LocationInfo implements java.io.Serializable {
37
38
39
40
41 transient String lineNumber;
42
43
44
45 transient String fileName;
46
47
48
49 transient String className;
50
51
52
53 transient String methodName;
54
55
56
57
58 public String fullInfo;
59
60 private static StringWriter sw = new StringWriter();
61 private static PrintWriter pw = new PrintWriter(sw);
62
63 private static Method getStackTraceMethod;
64 private static Method getClassNameMethod;
65 private static Method getMethodNameMethod;
66 private static Method getFileNameMethod;
67 private static Method getLineNumberMethod;
68
69
70
71
72
73
74 public final static String NA = "?";
75
76 static final long serialVersionUID = -1325822038990805636L;
77
78
79
80
81
82 public static final LocationInfo NA_LOCATION_INFO =
83 new LocationInfo(NA, NA, NA, NA);
84
85
86
87
88 static boolean inVisualAge = false;
89 static {
90 try {
91 inVisualAge = Class.forName("com.ibm.uvm.tools.DebugSupport") != null;
92 LogLog.debug("Detected IBM VisualAge environment.");
93 } catch(Throwable e) {
94
95 }
96 try {
97 Class[] noArgs = null;
98 getStackTraceMethod = Throwable.class.getMethod("getStackTrace", noArgs);
99 Class stackTraceElementClass = Class.forName("java.lang.StackTraceElement");
100 getClassNameMethod = stackTraceElementClass.getMethod("getClassName", noArgs);
101 getMethodNameMethod = stackTraceElementClass.getMethod("getMethodName", noArgs);
102 getFileNameMethod = stackTraceElementClass.getMethod("getFileName", noArgs);
103 getLineNumberMethod = stackTraceElementClass.getMethod("getLineNumber", noArgs);
104 } catch(ClassNotFoundException ex) {
105 LogLog.debug("LocationInfo will use pre-JDK 1.4 methods to determine location.");
106 } catch(NoSuchMethodException ex) {
107 LogLog.debug("LocationInfo will use pre-JDK 1.4 methods to determine location.");
108 }
109 }
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 public LocationInfo(Throwable t, String fqnOfCallingClass) {
134 if(t == null || fqnOfCallingClass == null)
135 return;
136 if (getLineNumberMethod != null) {
137 try {
138 Object[] noArgs = null;
139 Object[] elements = (Object[]) getStackTraceMethod.invoke(t, noArgs);
140 String prevClass = NA;
141 for(int i = elements.length - 1; i >= 0; i--) {
142 String thisClass = (String) getClassNameMethod.invoke(elements[i], noArgs);
143 if(fqnOfCallingClass.equals(thisClass)) {
144 int caller = i + 1;
145 if (caller < elements.length) {
146 className = prevClass;
147 methodName = (String) getMethodNameMethod.invoke(elements[caller], noArgs);
148 fileName = (String) getFileNameMethod.invoke(elements[caller], noArgs);
149 if (fileName == null) {
150 fileName = NA;
151 }
152 int line = ((Integer) getLineNumberMethod.invoke(elements[caller], noArgs)).intValue();
153 if (line < 0) {
154 lineNumber = NA;
155 } else {
156 lineNumber = String.valueOf(line);
157 }
158 StringBuffer buf = new StringBuffer();
159 buf.append(className);
160 buf.append(".");
161 buf.append(methodName);
162 buf.append("(");
163 buf.append(fileName);
164 buf.append(":");
165 buf.append(lineNumber);
166 buf.append(")");
167 this.fullInfo = buf.toString();
168 }
169 return;
170 }
171 prevClass = thisClass;
172 }
173 return;
174 } catch(IllegalAccessException ex) {
175 LogLog.debug("LocationInfo failed using JDK 1.4 methods", ex);
176 } catch(InvocationTargetException ex) {
177 if (ex.getTargetException() instanceof InterruptedException
178 || ex.getTargetException() instanceof InterruptedIOException) {
179 Thread.currentThread().interrupt();
180 }
181 LogLog.debug("LocationInfo failed using JDK 1.4 methods", ex);
182 } catch(RuntimeException ex) {
183 LogLog.debug("LocationInfo failed using JDK 1.4 methods", ex);
184 }
185 }
186
187 String s;
188
189 synchronized(sw) {
190 t.printStackTrace(pw);
191 s = sw.toString();
192 sw.getBuffer().setLength(0);
193 }
194
195 int ibegin, iend;
196
197
198
199
200
201
202
203
204 ibegin = s.lastIndexOf(fqnOfCallingClass);
205 if(ibegin == -1)
206 return;
207
208
209
210
211
212
213
214
215 if (ibegin + fqnOfCallingClass.length() < s.length() &&
216 s.charAt(ibegin + fqnOfCallingClass.length()) != '.') {
217 int i = s.lastIndexOf(fqnOfCallingClass + ".");
218 if (i != -1) {
219 ibegin = i;
220 }
221 }
222
223
224 ibegin = s.indexOf(Layout.LINE_SEP, ibegin);
225 if(ibegin == -1)
226 return;
227 ibegin+= Layout.LINE_SEP_LEN;
228
229
230 iend = s.indexOf(Layout.LINE_SEP, ibegin);
231 if(iend == -1)
232 return;
233
234
235
236 if(!inVisualAge) {
237
238 ibegin = s.lastIndexOf("at ", iend);
239 if(ibegin == -1)
240 return;
241
242 ibegin += 3;
243 }
244
245 this.fullInfo = s.substring(ibegin, iend);
246 }
247
248
249
250
251
252
253
254
255
256 private static final void appendFragment(final StringBuffer buf,
257 final String fragment) {
258 if (fragment == null) {
259 buf.append(NA);
260 } else {
261 buf.append(fragment);
262 }
263 }
264
265
266
267
268
269
270
271
272
273
274 public LocationInfo(
275 final String file,
276 final String classname,
277 final String method,
278 final String line) {
279 this.fileName = file;
280 this.className = classname;
281 this.methodName = method;
282 this.lineNumber = line;
283 StringBuffer buf = new StringBuffer();
284 appendFragment(buf, classname);
285 buf.append(".");
286 appendFragment(buf, method);
287 buf.append("(");
288 appendFragment(buf, file);
289 buf.append(":");
290 appendFragment(buf, line);
291 buf.append(")");
292 this.fullInfo = buf.toString();
293 }
294
295
296
297
298
299 public
300 String getClassName() {
301 if(fullInfo == null) return NA;
302 if(className == null) {
303
304
305 int iend = fullInfo.lastIndexOf('(');
306 if(iend == -1)
307 className = NA;
308 else {
309 iend =fullInfo.lastIndexOf('.', iend);
310
311
312
313
314
315
316
317
318
319
320 int ibegin = 0;
321 if (inVisualAge) {
322 ibegin = fullInfo.lastIndexOf(' ', iend)+1;
323 }
324
325 if(iend == -1)
326 className = NA;
327 else
328 className = this.fullInfo.substring(ibegin, iend);
329 }
330 }
331 return className;
332 }
333
334
335
336
337
338
339 public
340 String getFileName() {
341 if(fullInfo == null) return NA;
342
343 if(fileName == null) {
344 int iend = fullInfo.lastIndexOf(':');
345 if(iend == -1)
346 fileName = NA;
347 else {
348 int ibegin = fullInfo.lastIndexOf('(', iend - 1);
349 fileName = this.fullInfo.substring(ibegin + 1, iend);
350 }
351 }
352 return fileName;
353 }
354
355
356
357
358
359
360 public
361 String getLineNumber() {
362 if(fullInfo == null) return NA;
363
364 if(lineNumber == null) {
365 int iend = fullInfo.lastIndexOf(')');
366 int ibegin = fullInfo.lastIndexOf(':', iend -1);
367 if(ibegin == -1)
368 lineNumber = NA;
369 else
370 lineNumber = this.fullInfo.substring(ibegin + 1, iend);
371 }
372 return lineNumber;
373 }
374
375
376
377
378 public
379 String getMethodName() {
380 if(fullInfo == null) return NA;
381 if(methodName == null) {
382 int iend = fullInfo.lastIndexOf('(');
383 int ibegin = fullInfo.lastIndexOf('.', iend);
384 if(ibegin == -1)
385 methodName = NA;
386 else
387 methodName = this.fullInfo.substring(ibegin + 1, iend);
388 }
389 return methodName;
390 }
391 }