package org.apache.logging.log4j.core.util;

import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ReflectPermission;
import java.net.URL;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.LoaderUtil;
import org.apache.logging.log4j.util.PropertiesUtil;

public final class Loader {
   private static boolean ignoreTCL = false;
   private static final Logger LOGGER = StatusLogger.getLogger();
   private static final String TSTR = "Caught Exception while in Loader.getResource. This may be innocuous.";

   public static ClassLoader getClassLoader() {
      return getClassLoader(Loader.class, (Class)null);
   }

   public static ClassLoader getThreadContextClassLoader() {
      return LoaderUtil.getThreadContextClassLoader();
   }

   public static ClassLoader getClassLoader(Class<?> class1, Class<?> class2) {
      ClassLoader threadContextClassLoader = null;

      try {
         threadContextClassLoader = getTcl();
      } catch (Exception var5) {
         LOGGER.warn("Caught exception locating thread ClassLoader {}", var5.getMessage());
      }

      ClassLoader loader1 = class1 == null ? null : class1.getClassLoader();
      ClassLoader loader2 = class2 == null ? null : class2.getClassLoader();
      if (isChild(threadContextClassLoader, loader1)) {
         return isChild(threadContextClassLoader, loader2) ? threadContextClassLoader : loader2;
      } else {
         return isChild(loader1, loader2) ? loader1 : loader2;
      }
   }

   public static URL getResource(String resource, ClassLoader defaultLoader) {
      try {
         ClassLoader classLoader = getTcl();
         URL url;
         if (classLoader != null) {
            LOGGER.trace("Trying to find [{}] using context class loader {}.", resource, classLoader);
            url = classLoader.getResource(resource);
            if (url != null) {
               return url;
            }
         }

         classLoader = Loader.class.getClassLoader();
         if (classLoader != null) {
            LOGGER.trace("Trying to find [{}] using {} class loader.", resource, classLoader);
            url = classLoader.getResource(resource);
            if (url != null) {
               return url;
            }
         }

         if (defaultLoader != null) {
            LOGGER.trace("Trying to find [{}] using {} class loader.", resource, defaultLoader);
            url = defaultLoader.getResource(resource);
            if (url != null) {
               return url;
            }
         }
      } catch (Throwable var4) {
         LOGGER.warn("Caught Exception while in Loader.getResource. This may be innocuous.", var4);
      }

      LOGGER.trace("Trying to find [{}] using ClassLoader.getSystemResource().", resource);
      return ClassLoader.getSystemResource(resource);
   }

   public static InputStream getResourceAsStream(String resource, ClassLoader defaultLoader) {
      try {
         ClassLoader classLoader = getTcl();
         InputStream is;
         if (classLoader != null) {
            LOGGER.trace("Trying to find [{}] using context class loader {}.", resource, classLoader);
            is = classLoader.getResourceAsStream(resource);
            if (is != null) {
               return is;
            }
         }

         classLoader = Loader.class.getClassLoader();
         if (classLoader != null) {
            LOGGER.trace("Trying to find [{}] using {} class loader.", resource, classLoader);
            is = classLoader.getResourceAsStream(resource);
            if (is != null) {
               return is;
            }
         }

         if (defaultLoader != null) {
            LOGGER.trace("Trying to find [{}] using {} class loader.", resource, defaultLoader);
            is = defaultLoader.getResourceAsStream(resource);
            if (is != null) {
               return is;
            }
         }
      } catch (Throwable var4) {
         LOGGER.warn("Caught Exception while in Loader.getResource. This may be innocuous.", var4);
      }

      LOGGER.trace("Trying to find [{}] using ClassLoader.getSystemResource().", resource);
      return ClassLoader.getSystemResourceAsStream(resource);
   }

   private static ClassLoader getTcl() {
      return LoaderUtil.getThreadContextClassLoader();
   }

   private static boolean isChild(ClassLoader loader1, ClassLoader loader2) {
      if (loader1 != null && loader2 != null) {
         ClassLoader parent;
         for(parent = loader1.getParent(); parent != null && parent != loader2; parent = parent.getParent()) {
         }

         return parent != null;
      } else {
         return loader1 != null;
      }
   }

   public static Class<?> loadClass(String className) throws ClassNotFoundException {
      if (ignoreTCL) {
         LOGGER.trace("Ignoring TCCL. Trying Class.forName({}).", className);
         return loadClassWithDefaultClassLoader(className);
      } else {
         try {
            LOGGER.trace("Trying TCCL for class {}.", className);
            return Class.forName(className, true, getTcl());
         } catch (Throwable var2) {
            LOGGER.trace("TCCL didn't work for class {}: {}.", className, var2.toString());
            return loadClassWithDefaultClassLoader(className);
         }
      }
   }

   private static Class<?> loadClassWithDefaultClassLoader(String className) throws ClassNotFoundException {
      return Class.forName(className);
   }

   public static Class<?> initializeClass(String className, ClassLoader loader) throws ClassNotFoundException {
      return Class.forName(className, true, loader);
   }

   public static Class<?> loadSystemClass(String className) throws ClassNotFoundException {
      try {
         return Class.forName(className, true, ClassLoader.getSystemClassLoader());
      } catch (Throwable var2) {
         LOGGER.trace("Couldn't use SystemClassLoader. Trying Class.forName({}).", className, var2);
         return Class.forName(className);
      }
   }

   public static Object newInstanceOf(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
      Class clazz = loadClass(className);

      try {
         return clazz.getConstructor().newInstance();
      } catch (NoSuchMethodException var3) {
         return clazz.newInstance();
      }
   }

   public static <T> T newCheckedInstanceOf(String className, Class<T> clazz) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
      return clazz.cast(newInstanceOf(className));
   }

   public static boolean isClassAvailable(String className) {
      try {
         Class<?> clazz = loadClass(className);
         return clazz != null;
      } catch (ClassNotFoundException var2) {
         return false;
      } catch (Throwable var3) {
         LOGGER.trace("Unknown error checking for existence of class [{}].", className, var3);
         return false;
      }
   }

   private Loader() {
   }

   static {
      String ignoreTCLProp = PropertiesUtil.getProperties().getStringProperty("log4j.ignoreTCL", (String)null);
      if (ignoreTCLProp != null) {
         ignoreTCL = OptionConverter.toBoolean(ignoreTCLProp, true);
      }

      SecurityManager sm = System.getSecurityManager();
      if (sm != null) {
         sm.checkPermission(new RuntimePermission("getStackTrace"));
         sm.checkPermission(new ReflectPermission("suppressAccessChecks"));
      }

   }
}
