001: /**
002: *
003: */package clime.messadmin.utils;
004:
005: /**
006: * A set of utilities to inspect current stack frame.
007: * Heavily inspired by, and based on, Apache LogKit's org.apache.log.util.StackIntrospector
008: *
009: * Note: this information is also available since Java 1.4 via
010: * {@link Throwable#getStackTrace()}
011: *
012: * @author Cédrik LIME
013: */
014: public final class StackIntrospector {
015: /* Magic number CALL_CONTEXT_OFFSET identifies our caller */
016: private static final int CALL_CONTEXT_OFFSET = 2; // may need to change if this class is redesigned
017:
018: /**
019: * Hack to get the call stack as an array of classes.
020: * The SecurityManager class provides this information as a protected method,
021: * so all we have to do is violate OO encapsulation principles and
022: * permit its access through a new public method!
023: */
024: private static final class ClassContext extends SecurityManager {
025: /**
026: * @throws SecurityException if an existing SecurityManager disallows construction of another SecurityManager
027: */
028: ClassContext() {
029: super ();
030: }
031:
032: /**
033: * Returns the current execution stack as an array of classes.<br>
034: * The length of the array is the number of methods on the execution
035: * stack. The element at index <code>0</code> is the class of the
036: * currently executing method, the element at index <code>1</code> is
037: * the class of that method's caller, and so on.
038: *
039: * @return the execution stack.
040: * @see @link SecurityManager#getClassContext()
041: */
042: public Class[] get() {
043: return getClassContext();
044: }
045: }
046:
047: /**
048: * Create Hack SecurityManager to get ClassContext
049: * @throws SecurityException if an existing SecurityManager disallows construction of another SecurityManager
050: */
051: private static final ClassContext CLASS_CONTEXT = new ClassContext();
052:
053: /**
054: * Private constructor to block instantiation.
055: */
056: private StackIntrospector() {
057: /* assert false; */
058: }
059:
060: /**
061: * Find our caller's caller.
062: * May return null if caller not found on execution stack.
063: */
064: public static Class getCallerClass() {
065: Class[] stack = CLASS_CONTEXT.get();
066: if (stack.length <= CALL_CONTEXT_OFFSET + 1) {
067: return null;
068: }
069: Class c = stack[CALL_CONTEXT_OFFSET + 1];
070: return c;
071: }
072:
073: /**
074: * Find the caller of the passed in Class.
075: * May return null if caller not found on execution stack.
076: *
077: * @param clazz the Class to search for on stack to find caller of
078: * @return the Class of object that called parrameter class
079: */
080: public static Class getCallerClass(final Class clazz)
081: throws SecurityException {
082: // return getCallerClass(clazz, 0); // can't do that, as this adds a stack frame...
083: final Class[] stack = CLASS_CONTEXT.get();
084:
085: if (stack.length <= CALL_CONTEXT_OFFSET) {
086: return null;
087: }
088: // Traverse the call stack until we find clazz
089: for (int i = CALL_CONTEXT_OFFSET; i < stack.length; ++i) {
090: if (clazz.isAssignableFrom(stack[i])) {
091: // Found: the caller is the previous stack element
092: return i + 1 >= stack.length ? null : stack[i + 1];
093: }
094: }
095:
096: //Unable to locate class in call stack
097: return null;
098: }
099:
100: /**
101: * Find the caller of the passed in Class.
102: * May return null if caller not found on execution stack.
103: *
104: * @param clazz the Class to search for on stack to find caller of
105: * @param stackDepthOffset Offset call-stack depth to find caller
106: * @return the Class of object that called parrameter class
107: */
108: public static Class getCallerClass(final Class clazz,
109: final int stackDepthOffset) {
110: final Class[] stack = CLASS_CONTEXT.get();
111:
112: if (stack.length <= stackDepthOffset + CALL_CONTEXT_OFFSET) {
113: return null;
114: }
115: // Traverse the call stack until we find clazz
116: for (int i = stackDepthOffset + CALL_CONTEXT_OFFSET; i < stack.length; ++i) {
117: if (clazz.isAssignableFrom(stack[i])) {
118: // Found: the caller is the previous stack element
119: return i + 1 >= stack.length ? null : stack[i + 1];
120: }
121: }
122:
123: //Unable to locate class in call stack
124: return null;
125: }
126: }
|