View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements. See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache license, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License. You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the license for the specific language governing permissions and
    15   * limitations under the license.
    16   */
    17
    18  package org.apache.logging.log4j.core.config.plugins.util;
    19
    20  import org.apache.logging.log4j.Logger;
    21  import org.apache.logging.log4j.status.StatusLogger;
    22  import org.apache.logging.log4j.util.Strings;
    23
    24  import java.util.Collection;
    25  import java.util.HashMap;
    26  import java.util.LinkedHashMap;
    27  import java.util.List;
    28  import java.util.Map;
    29  import java.util.concurrent.CopyOnWriteArrayList;
    30
    31  /**
    32   * Loads and manages all the plugins.
    33   */
    34  public class PluginManager {
    35
    36      private static final CopyOnWriteArrayList<String> PACKAGES = new CopyOnWriteArrayList<String>();
    37      private static final String LOG4J_PACKAGES = "org.apache.logging.log4j.core";
    38
    39      private static final Logger LOGGER = StatusLogger.getLogger();
    40
    41      private Map<String, PluginType<?>> plugins = new HashMap<String, PluginType<?>>();
    42      private final String category;
    43
    44      /**
    45       * Constructs a PluginManager for the plugin category name given.
    46       *
    47       * @param category The plugin category name.
    48       */
    49      public PluginManager(final String category) {
    50          this.category = category;
    51      }
    52
    53      /**
    54       * Process annotated plugins.
    55       *
    56       * @deprecated Use {@link org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor} instead. To do so,
    57       *             simply include {@code log4j-core} in your dependencies and make sure annotation processing is not
    58       *             disabled. By default, supported Java compilers will automatically use that plugin processor provided
    59       *             {@code log4j-core} is on the classpath.
    60       */
    61      @Deprecated
    62      // use PluginProcessor instead
    63      public static void main(final String[] args) {
    64          System.err.println("ERROR: this tool is superseded by the annotation processor included in log4j-core.");
    65          System.err.println("If the annotation processor does not work for you, please see the manual page:");
    66          System.err.println("http://logging.apache.org/log4j/2.x/manual/configuration.html#ConfigurationSyntax");
    67          System.exit(-1);
    68      }
    69
    70      /**
    71       * Adds a package name to be scanned for plugins. Must be invoked prior to plugins being collected.
    72       *
    73       * @param p The package name. Ignored if {@code null} or empty.
    74       */
    75      public static void addPackage(final String p) {
    76          if (Strings.isBlank(p)) {
    77              return;
    78          }
    79          PACKAGES.addIfAbsent(p);
    80      }
    81
    82      /**
    83       * Adds a list of package names to be scanned for plugins. Convenience method for {@link #addPackage(String)}.
    84       *
    85       * @param packages collection of package names to add. Empty and null package names are ignored.
    86       */
    87      public static void addPackages(final Collection<String> packages) {
    88          for (final String pkg : packages) {
    89              if (Strings.isNotBlank(pkg)) {
    90                  PACKAGES.addIfAbsent(pkg);
    91              }
    92          }
    93      }
    94
    95      /**
    96       * Returns the type of a specified plugin.
    97       *
    98       * @param name The name of the plugin.
    99       * @return The plugin's type.
    100      */
    101     public PluginType<?> getPluginType(final String name) {
    102         return plugins.get(name.toLowerCase());
    103     }
    104
    105     /**
    106      * Returns all the matching plugins.
    107      *
    108      * @return A Map containing the name of the plugin and its type.
    109      */
    110     public Map<String, PluginType<?>> getPlugins() {
    111         return plugins;
    112     }
    113
    114     /**
    115      * Locates all the plugins.
    116      */
    117     public void collectPlugins() {
    118         collectPlugins(null);
    119     }
    120
    121     /**
    122      * Locates all the plugins including search of specific packages. Warns about name collisions.
    123      *
    124      * @param packages the list of packages to scan for plugins
    125      * @since 2.1
    126      */
    127     public void collectPlugins(final List<String> packages) {
    128         final String categoryLowerCase = category.toLowerCase();
    129         final Map<String, PluginType<?>> newPlugins = new LinkedHashMap<String, PluginType<?>>();
    130
    131         // First, iterate the Log4j2Plugin.dat files found in the main CLASSPATH
    132         Map<String, List<PluginType<?>>> builtInPlugins = PluginRegistry.getInstance().loadFromMainClassLoader();
    133         if (builtInPlugins.isEmpty()) {
    134             // If we didn't find any plugins above, someone must have messed with the log4j-core.jar.
    135             // Search the standard package in the hopes we can find our core plugins.
    136             builtInPlugins = PluginRegistry.getInstance().loadFromPackage(LOG4J_PACKAGES);
    137         }
    138         mergeByName(newPlugins, builtInPlugins.get(categoryLowerCase));
    139
    140         // Next, iterate any Log4j2Plugin.dat files from OSGi Bundles
    141         for (final Map<String, List<PluginType<?>>> pluginsByCategory : PluginRegistry.getInstance().getPluginsByCategoryByBundleId().values()) {
    142             mergeByName(newPlugins, pluginsByCategory.get(categoryLowerCase));
    143         }
    144
    145         // Next iterate any packages passed to the static addPackage method.
    146         for (final String pkg : PACKAGES) {
    147             mergeByName(newPlugins, PluginRegistry.getInstance().loadFromPackage(pkg).get(categoryLowerCase));
    148         }
    149         // Finally iterate any packages provided in the configuration (note these can be changed at runtime).
    150         if (packages != null) {
    151             for (final String pkg : packages) {
    152                 mergeByName(newPlugins, PluginRegistry.getInstance().loadFromPackage(pkg).get(categoryLowerCase));
    153             }
    154         }
    155
    156         LOGGER.debug("PluginManager '{}' found {} plugins", category, newPlugins.size());
    157
    158         plugins = newPlugins;
    159     }
    160
    161     private static void mergeByName(final Map<String, PluginType<?>> newPlugins, final List<PluginType<?>> plugins) {
    162         if (plugins == null) {
    163             return;
    164         }
    165         for (final PluginType<?> pluginType : plugins) {
    166             final String key = pluginType.getKey();
    167             final PluginType<?> existing = newPlugins.get(key);
    168             if (existing == null) {
    169                 newPlugins.put(key, pluginType);
    170             } else if (!existing.getPluginClass().equals(pluginType.getPluginClass())) {
    171                 LOGGER.warn("Plugin [{}] is already mapped to {}, ignoring {}",
    172                     key, existing.getPluginClass(), pluginType.getPluginClass());
    173             }
    174         }
    175     }
    176 }