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.processor;
    19
    20  import org.apache.logging.log4j.core.config.plugins.Plugin;
    21  import org.apache.logging.log4j.core.config.plugins.PluginAliases;
    22  import org.apache.logging.log4j.util.Strings;
    23
    24  import javax.annotation.processing.AbstractProcessor;
    25  import javax.annotation.processing.RoundEnvironment;
    26  import javax.annotation.processing.SupportedAnnotationTypes;
    27  import javax.lang.model.SourceVersion;
    28  import javax.lang.model.element.Element;
    29  import javax.lang.model.element.ElementVisitor;
    30  import javax.lang.model.element.TypeElement;
    31  import javax.lang.model.util.Elements;
    32  import javax.lang.model.util.SimpleElementVisitor6;
    33  import javax.tools.Diagnostic.Kind;
    34  import javax.tools.FileObject;
    35  import javax.tools.StandardLocation;
    36  import java.io.IOException;
    37  import java.io.OutputStream;
    38  import java.util.ArrayList;
    39  import java.util.Collection;
    40  import java.util.Collections;
    41  import java.util.Map;
    42  import java.util.Set;
    43
    44  /**
    45   * Annotation processor for pre-scanning Log4j 2 plugins.
    46   */
    47  @SupportedAnnotationTypes("org.apache.logging.log4j.core.config.plugins.*")
    48  public class PluginProcessor extends AbstractProcessor {
    49
    50      // TODO: this could be made more abstract to allow for compile-time and run-time plugin processing
    51
    52      /**
    53       * The location of the plugin cache data file. This file is written to by this processor, and read from by
    54       * {@link org.apache.logging.log4j.core.config.plugins.util.PluginManager}.
    55       */
    56      public static final String PLUGIN_CACHE_FILE = "META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat";
    57
    58      private final PluginCache pluginCache = new PluginCache();
    59
    60      @Override
    61      public SourceVersion getSupportedSourceVersion() {
    62          return SourceVersion.latest();
    63      }
    64
    65      @Override
    66      public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
    67          try {
    68              final Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(Plugin.class);
    69              if (elements.isEmpty()) {
    70                  return false;
    71              }
    72              collectPlugins(elements);
    73              writeCacheFile(elements.toArray(new Element[elements.size()]));
    74              return true;
    75          } catch (final IOException e) {
    76              error(e.getMessage());
    77              return false;
    78          }
    79      }
    80
    81      private void error(final CharSequence message) {
    82          processingEnv.getMessager().printMessage(Kind.ERROR, message);
    83      }
    84
    85      private void collectPlugins(final Iterable<? extends Element> elements) {
    86          final Elements elementUtils = processingEnv.getElementUtils();
    87          final ElementVisitor<PluginEntry, Plugin> pluginVisitor =
    88                  new PluginElementVisitor(elementUtils);
    89          final ElementVisitor<Collection<PluginEntry>, Plugin> pluginAliasesVisitor =
    90                  new PluginAliasesElementVisitor(elementUtils);
    91          for (final Element element : elements) {
    92              final Plugin plugin = element.getAnnotation(Plugin.class);
    93              final PluginEntry entry = element.accept(pluginVisitor, plugin);
    94              final Map<String, PluginEntry> category = pluginCache.getCategory(entry.getCategory());
    95              category.put(entry.getKey(), entry);
    96              final Collection<PluginEntry> entries = element.accept(pluginAliasesVisitor, plugin);
    97              for (final PluginEntry pluginEntry : entries) {
    98                  category.put(pluginEntry.getKey(), pluginEntry);
    99              }
    100         }
    101     }
    102
    103     private void writeCacheFile(final Element... elements) throws IOException {
    104         final FileObject fo = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT,
    105             Strings.EMPTY, PLUGIN_CACHE_FILE, elements);
    106         final OutputStream out = fo.openOutputStream();
    107         try {
    108             pluginCache.writeCache(out);
    109         } finally {
    110             out.close();
    111         }
    112     }
    113
    114     /**
    115      * ElementVisitor to scan the Plugin annotation.
    116      */
    117     private static class PluginElementVisitor extends SimpleElementVisitor6<PluginEntry, Plugin> {
    118
    119         private final Elements elements;
    120
    121         private PluginElementVisitor(final Elements elements) {
    122             this.elements = elements;
    123         }
    124
    125         @Override
    126         public PluginEntry visitType(final TypeElement e, final Plugin plugin) {
    127             if (plugin == null) {
    128                 throw new NullPointerException("Plugin annotation is null.");
    129             }
    130             final PluginEntry entry = new PluginEntry();
    131             entry.setKey(plugin.name().toLowerCase());
    132             entry.setClassName(elements.getBinaryName(e).toString());
    133             entry.setName(Plugin.EMPTY.equals(plugin.elementType()) ? plugin.name() : plugin.elementType());
    134             entry.setPrintable(plugin.printObject());
    135             entry.setDefer(plugin.deferChildren());
    136             entry.setCategory(plugin.category());
    137             return entry;
    138         }
    139     }
    140
    141     /**
    142      * ElementVisitor to scan the PluginAliases annotation.
    143      */
    144     private static class PluginAliasesElementVisitor extends SimpleElementVisitor6<Collection<PluginEntry>, Plugin> {
    145
    146         private final Elements elements;
    147
    148         private PluginAliasesElementVisitor(final Elements elements) {
    149             super(Collections.<PluginEntry>emptyList());
    150             this.elements = elements;
    151         }
    152
    153         @Override
    154         public Collection<PluginEntry> visitType(final TypeElement e, final Plugin plugin) {
    155             final PluginAliases aliases = e.getAnnotation(PluginAliases.class);
    156             if (aliases == null) {
    157                 return DEFAULT_VALUE;
    158             }
    159             final Collection<PluginEntry> entries = new ArrayList<PluginEntry>(aliases.value().length);
    160             for (final String alias : aliases.value()) {
    161                 final PluginEntry entry = new PluginEntry();
    162                 entry.setKey(alias.toLowerCase());
    163                 entry.setClassName(elements.getBinaryName(e).toString());
    164                 entry.setName(Plugin.EMPTY.equals(plugin.elementType()) ? alias : plugin.elementType());
    165                 entry.setPrintable(plugin.printObject());
    166                 entry.setDefer(plugin.deferChildren());
    167                 entry.setCategory(plugin.category());
    168                 entries.add(entry);
    169             }
    170             return entries;
    171         }
    172     }
    173 }