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