KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > avalon > excalibur > util > StackIntrospector


1 /*
2  * Copyright (C) The Apache Software Foundation. All rights reserved.
3  *
4  * This software is published under the terms of the Apache Software License
5  * version 1.1, a copy of which has been included with this distribution in
6  * the LICENSE.txt file.
7  */

8 package org.apache.avalon.excalibur.util;
9
10 import java.io.PrintWriter JavaDoc;
11 import java.io.StringWriter JavaDoc;
12 import java.util.ArrayList JavaDoc;
13
14 /**
15  * A set of utilities to inspect current stack frame.
16  *
17  * @author <a HREF="mailto:sylvain@apache.org">Sylvain Wallez</a>
18  * @author <a HREF="mailto:stuart.roebuck@adolos.com">Stuart Roebuck</a>
19  * @author <a HREF="mailto:peter@apache.org">Peter Donald</a>
20  * @version CVS $Revision: 1.4 $ $Date: 2001/12/11 09:53:37 $
21  */

22 public final class StackIntrospector
23 {
24     /**
25      * Hack to get the call stack as an array of classes. The
26      * SecurityManager class provides it as a protected method, so
27      * change it to public through a new method !
28      */

29     private final static class CallStack
30         extends SecurityManager JavaDoc
31     {
32         /**
33          * Returns the current execution stack as an array of classes.
34          * The length of the array is the number of methods on the execution
35          * stack. The element at index 0 is the class of the currently executing
36          * method, the element at index 1 is the class of that method's caller,
37          * and so on.
38          */

39         public Class JavaDoc[] get()
40         {
41             return getClassContext();
42         }
43     }
44
45     ///Method to cache CallStack hack as needed
46
private static CallStack c_callStack;
47
48     /**
49      * Private constructor to block instantiation.
50      *
51      */

52     private StackIntrospector()
53     {
54     }
55
56     /**
57      * Hack a CallStack object to get access to Classes in callStack.
58      *
59      * @return the Class array for call stack
60      * @exception SecurityException if an existing SecurityManager disallows construction
61      * of another SecurityManager
62      */

63     private synchronized static Class JavaDoc[] getCallStackAsClassArray()
64         throws SecurityException JavaDoc
65     {
66         //TODO: Check permission even if not created...
67
if( null == c_callStack )
68         {
69             //Lazily create CallStack accessor as appropriate
70
c_callStack = new CallStack();
71         }
72         
73         return c_callStack.get();
74     }
75
76     /**
77      * Find the caller of the passed in Class.
78      * May return null if caller not found on execution stack
79      *
80      * @param clazz the Class to search for on stack to find caller of
81      * @return the Class of object that called parrameter class
82      * @exception SecurityException if an existing SecurityManager disallows construction
83      * of another SecurityManager and thus blocks method results
84      */

85     public final static Class JavaDoc getCallerClass( final int index )
86         throws SecurityException JavaDoc
87     {
88         final Class JavaDoc[] stack = getCallStackAsClassArray();
89         if( index < stack.length ) return stack[ index ];
90         else return null;
91     }
92
93     /**
94      * Find the caller of the passed in Class.
95      * May return null if caller not found on execution stack
96      *
97      * @param clazz the Class to search for on stack to find caller of
98      * @return the Class of object that called parrameter class
99      * @exception SecurityException if an existing SecurityManager disallows construction
100      * of another SecurityManager and thus blocks method results
101      */

102     public final static Class JavaDoc getCallerClass( final Class JavaDoc clazz )
103         throws SecurityException JavaDoc
104     {
105         final Class JavaDoc[] stack = getCallStackAsClassArray();
106
107         // Traverse the call stack in reverse order until we find clazz
108
for( int i = stack.length - 1; i >= 0; i-- )
109         {
110             if( clazz.isAssignableFrom( stack[ i ] ) )
111             {
112                 // Found : the caller is the previous stack element
113
return stack[ i + 1 ];
114             }
115         }
116
117         //Unable to locate class in call stack
118
return null;
119     }
120
121     /**
122      * Get the name of the method is at specified index in call stack.
123      *
124      * @return The method path name in the form
125      * "the.package.MyClass.method(MyClass:121)"
126      */

127     public final static String JavaDoc getCallerMethod( final int index )
128     {
129         final String JavaDoc[] callStack = getCallStackAsStringArray();
130
131         //increment callStack index as added method call with above
132
int actualIndex = index + 1;
133         if( actualIndex < callStack.length ) return callStack[ actualIndex ];
134         else return null;
135     }
136
137     /**
138      * Get the name of the method that called specified class.
139      *
140      * @return The method path name in the form "the.package.MyClass.method(MyClass:121)"
141      * or null if unable to determine caller.
142      */

143     public final static String JavaDoc getCallerMethod( final Class JavaDoc clazz )
144     {
145         final String JavaDoc[] callStack = getCallStackAsStringArray();
146         final int index = getCallerIndex( clazz.getName(), callStack );
147
148         if( -1 == index ) return null;
149         else
150         {
151             return callStack[ index ];
152         }
153     }
154
155     /**
156      * Return the call stack that called specified Class as an array of Strings.
157      * The maximum size of call-stack is specified by count parameter.
158      *
159      * <p>This can be useful for debugging code to determine where calls to a
160      * method are coming from.</p>
161      *
162      * @param clazz the last class on the stack you are <i>not</i> interested in!
163      * @param count the number of stack entries to return.
164      *
165      * @return An array of method names in the form
166      * "the.package.MyClass.method(MyClass:121)"
167      */

168     public final static String JavaDoc[] getCallerStack( final Class JavaDoc clazz, int count )
169     {
170         final String JavaDoc[] callStack = getCallStackAsStringArray();
171         final int start = getCallerIndex( clazz.getName(), callStack );
172         if( -1 == start ) return null;
173
174         final int size = Math.min( count, callStack.length - start );
175
176         final String JavaDoc[] result = new String JavaDoc[ size ];
177         for( int i = 0; i < size; i++ )
178         {
179             result[ i ] = callStack[ start + i ];
180         }
181
182         return result;
183     }
184
185     /**
186      * Return the current call stack as a String array.
187      *
188      * <p>This can be useful for debugging code to determine where calls to a
189      * method are coming from.</p>
190      *
191      * @return The array of strings containing methods in the form
192      * "the.package.MyClass.method(MyClass:121)"
193      */

194     public final static String JavaDoc[] getCallStackAsStringArray()
195     {
196         //Extract stack into a StringBuffer
197
final StringWriter JavaDoc sw = new StringWriter JavaDoc();
198         final Throwable JavaDoc throwable = new Throwable JavaDoc();
199         throwable.printStackTrace( new PrintWriter JavaDoc( sw, true ) );
200         final StringBuffer JavaDoc buffer = sw.getBuffer();
201
202         //Resulting stack
203
final ArrayList JavaDoc stack = new ArrayList JavaDoc();
204
205         //Cache vars used in loop
206
final StringBuffer JavaDoc line = new StringBuffer JavaDoc();
207         final int length = buffer.length();
208
209         //setup state
210
boolean found = false;
211         int state = 0;
212
213         //parse line
214
for( int i = 0; i < length; i++ )
215         {
216             final char ch = buffer.charAt( i );
217
218             switch( state )
219             {
220             case 0:
221                 //Strip the first line from input
222
if( '\n' == ch ) state = 1;
223                 break;
224
225             case 1:
226                 //strip 't' from 'at'
227
if( 't' == ch ) state = 2;
228                 break;
229
230             case 2:
231                 //Strip space after 'at'
232
line.setLength( 0 );
233                 state = 3;
234                 break;
235
236             case 3:
237                 //accumulate all characters to end of line
238
if( '\n' != ch ) line.append( ch );
239                 else
240                 {
241                     //At this stage you have the line that looks like
242
//com.biz.SomeClass.someMethod(SomeClass.java:22)
243
final String JavaDoc method = line.toString();
244                     stack.add( method );
245
246                     //start parsing from start of line again
247
state = 1;
248                 }
249             }
250         }
251
252         return (String JavaDoc[])stack.toArray( new String JavaDoc[ 0 ] );
253     }
254
255     /**
256      * Return the index into specified stack, that
257      * has a caller that starts with prefix.
258      *
259      * @param prefix the prefix.
260      * @param callStack the call stack
261      * @return index into array
262      */

263     private static int getCallerIndex( final String JavaDoc prefix, final String JavaDoc[] callStack )
264     {
265         boolean found = false;
266         for( int i = 0; i < callStack.length; i++ )
267         {
268             ///Determine if line is a match for class
269
final boolean match = callStack[ i ].startsWith( prefix );
270             if( !match ) continue;
271
272             //If this is the first time we cound class then
273
//set found to true and look for caller into class
274
if( !found ) found = true;
275             else
276             {
277                 //We have now located caller of Clazz
278
return i;
279             }
280         }
281
282         return -1;
283     }
284 }
285
Popular Tags