001package org.unix4j.util;
002
003/**
004 * Utility class to evaluate the {@link StackTraceElement} corresponding to a
005 * calling method in the caller stack.
006 */
007public class StackTraceUtil {
008
009        /**
010         * Returns the stack trace element corresponding to the direct caller
011         * method, that is, the method which calls this method.
012         */
013        public static StackTraceElement getCurrentMethodStackTraceElement() {
014                return internalGetCurrentMethodStackTraceElement(1);
015        }
016
017        /**
018         * Returns the stack trace element belonging to the
019         * <code>callerOffset<sup>th</sup></code> caller of the calling method.
020         * <p>
021         * For example, {@code callerOffset=0} returns the stack trace element of
022         * the direct caller of this method; {@code callerOffset=1} corresponds to
023         * the method calling the direct caller method, etc.
024         * 
025         * @param callerOffset
026         *            the index of the stack trace element in the caller stack,
027         *            where {@code callerOffset=0} corresponds to the direct caller
028         *            of this method
029         */
030        public static StackTraceElement getCurrentMethodStackTraceElement(int callerOffset) {
031                return internalGetCurrentMethodStackTraceElement(callerOffset + 1);
032        }
033
034        private static StackTraceElement internalGetCurrentMethodStackTraceElement(int callerOffset) {
035                // trc[0] Thread.dumpThreads(native)
036                // trc[1] Thread.getStackTrace(..)
037                // trc[2] StackTrace.internalGetCurrentMethodStackTraceElement(..)
038                // trc[3] is what we want for offset == 0!
039
040                // NOTE sometimes also
041                // trc[0] Thread.getStackTrace(..)
042                // trc[1] StackTrace.internalGetCurrentMethodStackTraceElement(..)
043                // trc[2] is what we want for offset == 0!
044                StackTraceElement[] trc = Thread.currentThread().getStackTrace();
045                for (int i = 0; i < trc.length; i++) {
046                        if (trc[i].getClassName().equals(StackTraceUtil.class.getName()) && trc[i].getMethodName().equals("internalGetCurrentMethodStackTraceElement")) {
047                                return trc[callerOffset + i + 1];
048                        }
049                }
050                throw new RuntimeException("internal error: current method not found");
051        }
052
053        // no instances
054        private StackTraceUtil() {
055        }
056}