KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > log > util > StackIntrospector


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12  * implied.
13  *
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17 package org.apache.log.util;
18
19 import java.io.PrintWriter JavaDoc;
20 import java.io.StringWriter JavaDoc;
21
22 /**
23  * A set of utilities to inspect current stack frame.
24  *
25  * @author <a HREF="mailto:dev@avalon.apache.org">Avalon Development Team</a>
26  * @author <a HREF="mailto:sylvain@apache.org">Sylvain Wallez</a>
27  * @author <a HREF="mailto:stuart.roebuck@adolos.com">Stuart Roebuck</a>
28  * @version CVS $Revision: 1.16 $ $Date: 2004/02/28 11:31:25 $
29  */

30 public final class StackIntrospector
31 {
32     /**
33      * Hack to get the call stack as an array of classes. The
34      * SecurityManager class provides it as a protected method, so
35      * change it to public through a new method !
36      */

37     private static final class CallStack
38         extends SecurityManager JavaDoc
39     {
40         /**
41          * Returns the current execution stack as an array of classes.
42          * The length of the array is the number of methods on the execution
43          * stack. The element at index 0 is the class of the currently executing
44          * method, the element at index 1 is the class of that method's caller,
45          * and so on.
46          */

47         public Class JavaDoc[] get()
48         {
49             return getClassContext();
50         }
51     }
52
53     ///Method to cache CallStack hack as needed
54
private static CallStack c_callStack;
55
56     /**
57      * Private constructor to block instantiation.
58      *
59      */

60     private StackIntrospector()
61     {
62     }
63
64     /**
65      * Create Hack SecurityManager to get CallStack.
66      *
67      * @return the CallStack object
68      * @exception SecurityException if an existing SecurityManager disallows construction
69      * of another SecurityManager
70      */

71     private static synchronized CallStack getCallStack()
72         throws SecurityException JavaDoc
73     {
74         if( null == c_callStack )
75         {
76             //Lazily create CallStack accessor as appropriate
77
c_callStack = new CallStack();
78         }
79
80         return c_callStack;
81     }
82
83     /**
84      * Find the caller of the passed in Class.
85      * May return null if caller not found on execution stack
86      *
87      * @param clazz the Class to search for on stack to find caller of
88      * @return the Class of object that called parrameter class
89      * @exception SecurityException if an existing SecurityManager disallows construction
90      * of another SecurityManager and thus blocks method results
91      */

92     public static final Class JavaDoc getCallerClass( final Class JavaDoc clazz )
93         throws SecurityException JavaDoc
94     {
95         return getCallerClass( clazz, 0 );
96     }
97
98     /**
99      * Find the caller of the passed in Class.
100      * May return null if caller not found on execution stack
101      *
102      * @param clazz the Class to search for on stack to find caller of
103      * @param stackDepthOffset Offset call-stack depth to find caller
104      * @return the Class of object that called parrameter class
105      * @exception SecurityException if an existing SecurityManager disallows construction
106      * of another SecurityManager and thus blocks method results
107      */

108     public static final Class JavaDoc getCallerClass( final Class JavaDoc clazz, int stackDepthOffset )
109     {
110         final Class JavaDoc[] stack = getCallStack().get();
111
112         // Traverse the call stack in reverse order until we find clazz
113
for( int i = stack.length - 1; i >= 0; i-- )
114         {
115             if( clazz.isAssignableFrom( stack[ i ] ) )
116             {
117                 // Found : the caller is the previous stack element
118
return stack[ i + 1 + stackDepthOffset ];
119             }
120         }
121
122         //Unable to locate class in call stack
123
return null;
124     }
125
126     /**
127      * Get the method path name for the method from which the LogEvent was
128      * created, this includes the path name and the source filename and line
129      * number if the source was compiled with debugging on.
130      *
131      * @param clazz the Class to search for on stack to find caller of
132      * @return The method path name in the form "the.package.path.Method"
133      */

134     public static final String JavaDoc getCallerMethod( final Class JavaDoc clazz )
135     {
136         final String JavaDoc className = clazz.getName();
137
138         //Extract stack into a StringBuffer
139
final StringWriter JavaDoc sw = new StringWriter JavaDoc();
140         final Throwable JavaDoc throwable = new Throwable JavaDoc();
141         throwable.printStackTrace( new PrintWriter JavaDoc( sw, true ) );
142         final StringBuffer JavaDoc buffer = sw.getBuffer();
143
144         //Cache vars used in loop
145
final StringBuffer JavaDoc line = new StringBuffer JavaDoc();
146         final int length = buffer.length();
147
148         //setup state
149
boolean found = false;
150         int state = 0;
151
152         //parse line
153
for( int i = 0; i < length; i++ )
154         {
155             final char ch = buffer.charAt( i );
156
157             switch( state )
158             {
159                 case 0:
160                     //Strip the first line from input
161
if( '\n' == ch )
162                     {
163                         state = 1;
164                     }
165                     break;
166
167                 case 1:
168                     //strip 't' from 'at'
169
if( 't' == ch )
170                     {
171                         state = 2;
172                     }
173                     break;
174
175                 case 2:
176                     //Strip space after 'at'
177
line.setLength( 0 );
178                     state = 3;
179                     break;
180
181                 case 3:
182                     //accumulate all characters to end of line
183
if( '\n' != ch )
184                     {
185                         line.append( ch );
186                     }
187                     else
188                     {
189                         //At this stage you have the line that looks like
190
//com.biz.SomeClass.someMethod(SomeClass.java:22)
191
final String JavaDoc method = line.toString();
192
193                         ///Determine if line is a match for class
194
final boolean match = method.startsWith( className );
195                         if( !found && match )
196                         {
197                             //If this is the first time we cound class then
198
//set found to true and look for caller into class
199
found = true;
200                         }
201                         else if( found && !match )
202                         {
203                             //We have now located caller of Clazz
204
return method;
205                         }
206
207                         //start parsing from start of line again
208
state = 1;
209                     }
210             }
211         }
212
213         return "";
214     }
215
216     /**
217      * Return the current call stack as a String, starting with the first call
218      * in the stack after a reference to the <code>clazz</code> class, and then
219      * display <code>entries</code> entries.
220      *
221      * <p>This can be useful for debugging code to determine where calls to a
222      * method are coming from.</p>
223      *
224      * @param clazz the last class on the stack you are <i>not</i> interested in!
225      * @param entries the number of stack lines to return.
226      *
227      * @return The method path name in the form "the.package.path.Method"
228      */

229     public static final String JavaDoc getRecentStack( final Class JavaDoc clazz, int entries )
230     {
231         final String JavaDoc className = clazz.getName();
232
233         //Extract stack into a StringBuffer
234
final StringWriter JavaDoc sw = new StringWriter JavaDoc();
235         final Throwable JavaDoc throwable = new Throwable JavaDoc();
236         throwable.printStackTrace( new PrintWriter JavaDoc( sw, true ) );
237         final StringBuffer JavaDoc buffer = sw.getBuffer();
238
239         //Cache vars used in loop
240
final StringBuffer JavaDoc line = new StringBuffer JavaDoc();
241         final StringBuffer JavaDoc stack = new StringBuffer JavaDoc();
242         final int length = buffer.length();
243
244         //setup state
245
boolean found = false;
246         int state = 0;
247
248         //parse line
249
for( int i = 0; i < length; i++ )
250         {
251             final char ch = buffer.charAt( i );
252
253             switch( state )
254             {
255                 case 0:
256                     //Strip the first line from input
257
if( '\n' == ch )
258                     {
259                         state = 1;
260                     }
261                     break;
262
263                 case 1:
264                     //strip 't' from 'at'
265
if( 't' == ch )
266                     {
267                         state = 2;
268                     }
269                     break;
270
271                 case 2:
272                     //Strip space after 'at'
273
line.setLength( 0 );
274                     state = 3;
275                     break;
276
277                 case 3:
278                     //accumulate all characters to end of line
279
if( '\n' != ch )
280                     {
281                         line.append( ch );
282                     }
283                     else
284                     {
285                         //At this stage you have the line that looks like
286
//com.biz.SomeClass.someMethod(SomeClass.java:22)
287
final String JavaDoc method = line.toString();
288
289                         ///Determine if line is a match for class
290
final boolean match = method.startsWith( className );
291                         if( !found && match )
292                         {
293                             //If this is the first time we cound class then
294
//set found to true and look for caller into class
295
found = true;
296                         }
297                         else if( found && !match )
298                         {
299                             //We are looking at the callers of Clazz
300
stack.append( method );
301                             entries--;
302                             if( entries == 0 )
303                             {
304                                 return stack.toString();
305                             }
306                             stack.append( "\n" );
307                         }
308
309                         //start parsing from start of line again
310
state = 1;
311                     }
312             }
313         }
314
315         return "";
316     }
317 }
318
319
Popular Tags