001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017package org.apache.logging.log4j.util;
018
019import java.util.NoSuchElementException;
020import java.util.Stack;
021import java.util.function.Predicate;
022
023import org.apache.logging.log4j.status.StatusLogger;
024
025/**
026 * <em>Consider this class private.</em> Provides various methods to determine the caller class. <h3>Background</h3>
027 */
028public final class StackLocatorUtil {
029    private static StackLocator stackLocator = null;
030    private static volatile boolean errorLogged;
031
032    static {
033        stackLocator = StackLocator.getInstance();
034    }
035
036    private StackLocatorUtil() {
037    }
038
039    // TODO: return Object.class instead of null (though it will have a null ClassLoader)
040    // (MS) I believe this would work without any modifications elsewhere, but I could be wrong
041
042    // migrated from ReflectiveCallerClassUtility
043    @PerformanceSensitive
044    public static Class<?> getCallerClass(final int depth) {
045        return stackLocator.getCallerClass(depth + 1);
046    }
047
048    public static StackTraceElement getStackTraceElement(final int depth) {
049        return stackLocator.getStackTraceElement(depth + 1);
050    }
051
052    /**
053     * Equivalent to {@link #getCallerClass(String, String)} with an empty {@code pkg}.
054     */
055    // migrated from ClassLoaderContextSelector
056    @PerformanceSensitive
057    public static Class<?> getCallerClass(final String fqcn) {
058        return getCallerClass(fqcn, Strings.EMPTY);
059    }
060
061    /**
062     * Search for a calling class.
063     *
064     * @param fqcn Root class name whose caller to search for.
065     * @param pkg Package name prefix that must be matched after the {@code fqcn} has been found.
066     * @return The caller class that was matched, or null if one could not be located.
067     */
068    @PerformanceSensitive
069    public static Class<?> getCallerClass(final String fqcn, final String pkg) {
070        return stackLocator.getCallerClass(fqcn, pkg);
071    }
072
073    /**
074     * Search for a calling class.
075     *
076     * @param sentinelClass Sentinel class at which to begin searching
077     * @param callerPredicate Predicate checked after the sentinelClass is found
078     * @return the first matching class after <code>sentinelClass</code> is found.
079     */
080    @PerformanceSensitive
081    public static Class<?> getCallerClass(final Class<?> sentinelClass, final Predicate<Class<?>> callerPredicate) {
082        return stackLocator.getCallerClass(sentinelClass, callerPredicate);
083    }
084
085    // added for use in LoggerAdapter implementations mainly
086    @PerformanceSensitive
087    public static Class<?> getCallerClass(final Class<?> anchor) {
088        return stackLocator.getCallerClass(anchor);
089    }
090
091    // migrated from ThrowableProxy
092    @PerformanceSensitive
093    public static Stack<Class<?>> getCurrentStackTrace() {
094        return stackLocator.getCurrentStackTrace();
095    }
096
097    public static StackTraceElement calcLocation(final String fqcnOfLogger) {
098        try {
099            return stackLocator.calcLocation(fqcnOfLogger);
100        } catch (NoSuchElementException ex) {
101            if (!errorLogged) {
102                errorLogged = true;
103                StatusLogger.getLogger().warn("Unable to locate stack trace element for {}", fqcnOfLogger, ex);
104            }
105            return null;
106        }
107    }
108}