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

import java.io.BufferedInputStream;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAliases;
import org.apache.logging.log4j.core.util.ClassLoaderResourceLoader;
import org.apache.logging.log4j.core.util.Closer;
import org.apache.logging.log4j.core.util.Loader;
import org.apache.logging.log4j.core.util.ResourceLoader;
import org.apache.logging.log4j.status.StatusLogger;

public class PluginManager {
   private static final PluginRegistry<PluginType<?>> REGISTRY = new PluginRegistry();
   private static final CopyOnWriteArrayList<String> PACKAGES = new CopyOnWriteArrayList();
   private static final String LOG4J_PACKAGES = "org.apache.logging.log4j.core";
   private static final Logger LOGGER = StatusLogger.getLogger();
   private Map<String, PluginType<?>> plugins = new HashMap();
   private final String category;

   public PluginManager(String category) {
      this.category = category;
   }

   /** @deprecated */
   @Deprecated
   public static void main(String[] args) {
      System.err.println("WARNING: this tool is superseded by the annotation processor included in log4j-core.");
      System.exit(-1);
   }

   public static void addPackage(String p) {
      if (PACKAGES.addIfAbsent(p)) {
         REGISTRY.clear();
      }

   }

   public PluginType<?> getPluginType(String name) {
      return (PluginType)this.plugins.get(name.toLowerCase());
   }

   public Map<String, PluginType<?>> getPlugins() {
      return this.plugins;
   }

   public void collectPlugins() {
      this.collectPlugins(true);
   }

   public void collectPlugins(boolean preLoad) {
      if (REGISTRY.hasCategory(this.category)) {
         this.plugins = REGISTRY.getCategory(this.category);
         preLoad = false;
      }

      long start = System.nanoTime();
      if (preLoad) {
         ResourceLoader loader = new ClassLoaderResourceLoader(Loader.getClassLoader());
         loadPlugins(loader);
      }

      this.plugins = REGISTRY.getCategory(this.category);
      this.loadFromPackages(start, preLoad);
      long elapsed = System.nanoTime() - start;
      this.reportPluginLoadDuration(preLoad, elapsed);
   }

   private void loadFromPackages(long start, boolean preLoad) {
      if ((this.plugins == null || this.plugins.size() == 0) && !PACKAGES.contains("org.apache.logging.log4j.core")) {
         PACKAGES.add("org.apache.logging.log4j.core");
      }

      ResolverUtil resolver = new ResolverUtil();
      ClassLoader classLoader = Loader.getClassLoader();
      if (classLoader != null) {
         resolver.setClassLoader(classLoader);
      }

      Class<?> cls = null;
      ResolverUtil.Test test = new PluginManager.PluginTest((Class)cls);
      Iterator i$ = PACKAGES.iterator();

      while(i$.hasNext()) {
         String pkg = (String)i$.next();
         resolver.findInPackage(test, pkg);
      }

      i$ = resolver.getClasses().iterator();

      while(true) {
         Plugin plugin;
         ConcurrentMap map;
         String type;
         PluginType pluginType;
         PluginAliases pluginAliases;
         Class clazz;
         do {
            if (!i$.hasNext()) {
               this.plugins = REGISTRY.getCategory(this.category);
               return;
            }

            clazz = (Class)i$.next();
            plugin = (Plugin)clazz.getAnnotation(Plugin.class);
            String pluginCategory = plugin.category();
            map = REGISTRY.getCategory(pluginCategory);
            type = plugin.elementType().equals("") ? plugin.name() : plugin.elementType();
            pluginType = new PluginType(clazz, type, plugin.printObject(), plugin.deferChildren());
            map.put(plugin.name().toLowerCase(), pluginType);
            pluginAliases = (PluginAliases)clazz.getAnnotation(PluginAliases.class);
         } while(pluginAliases == null);

         String[] arr$ = pluginAliases.value();
         int len$ = arr$.length;

         for(int i$ = 0; i$ < len$; ++i$) {
            String alias = arr$[i$];
            type = plugin.elementType().equals("") ? alias : plugin.elementType();
            pluginType = new PluginType(clazz, type, plugin.printObject(), plugin.deferChildren());
            map.put(alias.trim().toLowerCase(), pluginType);
         }
      }
   }

   private void reportPluginLoadDuration(boolean preLoad, long elapsed) {
      StringBuilder sb = new StringBuilder("Generated plugins in ");
      DecimalFormat numFormat = new DecimalFormat("#0.000000");
      double seconds = (double)elapsed / 1.0E9D;
      sb.append(numFormat.format(seconds)).append(" seconds, packages: ");
      sb.append(PACKAGES);
      sb.append(", preload: ");
      sb.append(preLoad);
      sb.append(".");
      LOGGER.debug(sb.toString());
   }

   public static void loadPlugins(ResourceLoader loader) {
      PluginRegistry<PluginType<?>> registry = decode(loader);
      if (registry != null) {
         Iterator i$ = registry.getCategories().iterator();

         while(i$.hasNext()) {
            Entry<String, ConcurrentMap<String, PluginType<?>>> entry = (Entry)i$.next();
            REGISTRY.getCategory((String)entry.getKey()).putAll((Map)entry.getValue());
         }
      } else {
         LOGGER.info("Plugin preloads not available from class loader {}", loader);
      }

   }

   private static PluginRegistry<PluginType<?>> decode(ResourceLoader loader) {
      Enumeration resources;
      try {
         resources = loader.getResources("META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat");
         if (resources == null) {
            return null;
         }
      } catch (IOException var31) {
         LOGGER.warn((String)"Unable to preload plugins", (Throwable)var31);
         return null;
      }

      PluginRegistry map = new PluginRegistry();

      while(resources.hasMoreElements()) {
         URL url = (URL)resources.nextElement();
         LOGGER.debug("Found Plugin Map at {}", url.toExternalForm());

         InputStream is;
         try {
            is = url.openStream();
         } catch (IOException var28) {
            LOGGER.warn("Unable to open {}", url.toExternalForm(), var28);
            continue;
         }

         DataInputStream dis = new DataInputStream(new BufferedInputStream(is));

         try {
            int count = dis.readInt();

            for(int j = 0; j < count; ++j) {
               String category = dis.readUTF();
               int entries = dis.readInt();
               Map<String, PluginType<?>> types = map.getCategory(category);

               for(int i = 0; i < entries; ++i) {
                  String key = dis.readUTF();
                  String className = dis.readUTF();
                  String name = dis.readUTF();
                  boolean printable = dis.readBoolean();
                  boolean defer = dis.readBoolean();

                  try {
                     Class<?> clazz = loader.loadClass(className);
                     PluginType<?> pluginType = new PluginType(clazz, name, printable, defer);
                     types.put(key, pluginType);
                  } catch (ClassNotFoundException var26) {
                     LOGGER.info("Plugin [{}] could not be loaded due to missing classes.", className, var26);
                  } catch (VerifyError var27) {
                     LOGGER.info("Plugin [{}] could not be loaded due to verification error.", className, var27);
                  }
               }
            }
         } catch (IOException var29) {
            LOGGER.warn((String)"Unable to preload plugins", (Throwable)var29);
         } finally {
            Closer.closeSilently((Closeable)dis);
         }
      }

      return map.isEmpty() ? null : map;
   }

   public static class PluginTest implements ResolverUtil.Test {
      private final Class<?> isA;

      public PluginTest(Class<?> isA) {
         this.isA = isA;
      }

      public boolean matches(Class<?> type) {
         return type != null && type.isAnnotationPresent(Plugin.class) && (this.isA == null || this.isA.isAssignableFrom(type));
      }

      public String toString() {
         StringBuilder msg = new StringBuilder("annotated with @" + Plugin.class.getSimpleName());
         if (this.isA != null) {
            msg.append(" is assignable to " + this.isA.getSimpleName());
         }

         return msg.toString();
      }

      public boolean matches(URI resource) {
         throw new UnsupportedOperationException();
      }

      public boolean doesMatchClass() {
         return true;
      }

      public boolean doesMatchResource() {
         return false;
      }
   }
}
