diff --git a/log4j-core/pom.xml b/log4j-core/pom.xml index 5cda105..bcb8236 100644 --- a/log4j-core/pom.xml +++ b/log4j-core/pom.xml @@ -15,7 +15,8 @@ ~ See the license for the specific language governing permissions and ~ limitations under the license. --> - + 4.0.0 org.apache.logging.log4j @@ -333,30 +334,6 @@ maven-compiler-plugin ${compiler.plugin.version} - - - - default-compile - - compile - - compile - - none - - - - - process-plugins - - compile - - process-classes - - only - - - maven-surefire-plugin diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java index 2fd4160..f18bd1e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java @@ -24,8 +24,8 @@ import java.io.IOException; import java.io.OutputStream; import java.net.URL; -import java.util.Enumeration; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; /** @@ -34,6 +34,13 @@ public class PluginCache { private final Map> categories = new LinkedHashMap<>(); + + /** + * Clears this cache. + */ + public void clear() { + categories.clear(); + } /** * Returns all categories of plugins in this cache. @@ -86,6 +93,35 @@ } } } + /** + * Loads and merges a Log4j plugin cache file. Usually, this is obtained via a ClassLoader. + * + * @param url URL to the desired plugin cache file to load. + * @throws IOException if an I/O exception occurs. + */ + public void loadCacheFile(final URL url) throws IOException { + try (final DataInputStream in = new DataInputStream(new BufferedInputStream(url.openStream()))) { + final int count = in.readInt(); + for (int i = 0; i < count; i++) { + final String category = in.readUTF(); + final Map m = getCategory(category); + final int entries = in.readInt(); + for (int j = 0; j < entries; j++) { + final PluginEntry entry = new PluginEntry(); + entry.setKey(in.readUTF()); + entry.setClassName(in.readUTF()); + entry.setName(in.readUTF()); + entry.setPrintable(in.readBoolean()); + entry.setDefer(in.readBoolean()); + entry.setCategory(category); + if (!m.containsKey(entry.getKey())) { + m.put(entry.getKey(), entry); + } + } + } + } + } + /** * Loads and merges all the Log4j plugin cache files specified. Usually, this is obtained via a ClassLoader. @@ -93,30 +129,10 @@ * @param resources URLs to all the desired plugin cache files to load. * @throws IOException if an I/O exception occurs. */ - public void loadCacheFiles(final Enumeration resources) throws IOException { - categories.clear(); - while (resources.hasMoreElements()) { - final URL url = resources.nextElement(); - try (final DataInputStream in = new DataInputStream(new BufferedInputStream(url.openStream()))) { - final int count = in.readInt(); - for (int i = 0; i < count; i++) { - final String category = in.readUTF(); - final Map m = getCategory(category); - final int entries = in.readInt(); - for (int j = 0; j < entries; j++) { - final PluginEntry entry = new PluginEntry(); - entry.setKey(in.readUTF()); - entry.setClassName(in.readUTF()); - entry.setName(in.readUTF()); - entry.setPrintable(in.readBoolean()); - entry.setDefer(in.readBoolean()); - entry.setCategory(category); - if (!m.containsKey(entry.getKey())) { - m.put(entry.getKey(), entry); - } - } - } - } + public void loadCacheFiles(final List resources) throws IOException { + clear(); + for (URL url : resources) { + loadCacheFile(url); } } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java index b0e7570..53acf4b 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java @@ -51,11 +51,17 @@ // TODO: this could be made more abstract to allow for compile-time and run-time plugin processing /** + * The location of the plugin cache data directory. + */ + public static final String PLUGIN_CACHE_DIR = "META-INF/org/apache/logging/log4j/core/config/plugins/"; + + public static final String PLUGIN_CACHE_EXT = ".dat"; + + /** * The location of the plugin cache data file. This file is written to by this processor, and read from by * {@link org.apache.logging.log4j.core.config.plugins.util.PluginManager}. */ - public static final String PLUGIN_CACHE_FILE = - "META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat"; + public static final String PLUGIN_CACHE_FILE = PLUGIN_CACHE_DIR + "Log4j2Plugins" + PLUGIN_CACHE_EXT; private final PluginCache pluginCache = new PluginCache(); @@ -105,8 +111,10 @@ } private void writeCacheFile(final Element... elements) throws IOException { + final String pluginCacheFileOption = processingEnv.getOptions().get("pluginCacheFile"); + final String pluginCacheFile = pluginCacheFileOption != null ? pluginCacheFileOption : PLUGIN_CACHE_FILE; final FileObject fo = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, Strings.EMPTY, - PLUGIN_CACHE_FILE, elements); + pluginCacheFile, elements); try (final OutputStream out = fo.openOutputStream()) { pluginCache.writeCache(out); } diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java index a657f1a..e18f58b 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java @@ -17,9 +17,19 @@ package org.apache.logging.log4j.core.config.plugins.util; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; @@ -159,13 +169,13 @@ final long startTime = System.nanoTime(); final PluginCache cache = new PluginCache(); try { - final Enumeration resources = loader.getResources(PluginProcessor.PLUGIN_CACHE_FILE); + final List resources = getResources(loader); if (resources == null) { LOGGER.info("Plugin preloads not available from class loader {}", loader); } else { cache.loadCacheFiles(resources); } - } catch (final IOException ioe) { + } catch (final IOException | URISyntaxException ioe) { LOGGER.warn("Unable to preload plugins", ioe); } final Map>> newPluginsByCategory = new HashMap<>(); @@ -198,6 +208,47 @@ return newPluginsByCategory; } + private List getResources(final ClassLoader classLoader) throws IOException, URISyntaxException { + final List resources = new ArrayList<>(); + final Enumeration foldersEnum = classLoader.getResources(PluginProcessor.PLUGIN_CACHE_DIR); + if (foldersEnum != null) { + while (foldersEnum.hasMoreElements()) { + final URL url = foldersEnum.nextElement(); + URI uri = url.toURI(); + if ("file".equals(uri.getScheme())) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) { + String resource; + while ((resource = reader.readLine()) != null) { + if (resource.endsWith(PluginProcessor.PLUGIN_CACHE_EXT)) { + resources.add(new URL(url + resource)); + } + } + } + } else { + // jar and zip + try (final FileSystem fileSystem = FileSystems.newFileSystem(uri, new HashMap())) { + try (final DirectoryStream directoryStream = Files.newDirectoryStream(Paths.get(uri), + "*" + PluginProcessor.PLUGIN_CACHE_EXT)) { + for (Path path : directoryStream) { + resources.add(path.toUri().toURL()); + } + } + } + } + } + } + // For backward compatibility + final Enumeration oldResources = classLoader.getResources(PluginProcessor.PLUGIN_CACHE_FILE); + while (oldResources.hasMoreElements()) { + final URL url = oldResources.nextElement(); + // Work with a list, not a set to maintain classpath order. + if (!resources.contains(url)) { + resources.add(url); + } + } + return resources; + } + /** * @since 2.1 */ diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java index 9c37af4..bc207da 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java @@ -41,7 +41,11 @@ public static void setUpClass() throws Exception { final Enumeration resources = PluginProcessor.class.getClassLoader().getResources(PluginProcessor.PLUGIN_CACHE_FILE); - pluginCache.loadCacheFiles(resources); + pluginCache.clear(); + while (resources.hasMoreElements()) { + URL url = resources.nextElement(); + pluginCache.loadCacheFile(url); + } } @Test