[LOG4J2-1320] Custom plugins are not loaded, URL protocol vfs is not supported. Another go around with a better set of tests from Pierrick HYMBERT.
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/2d5812b2 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/2d5812b2 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/2d5812b2 Branch: refs/heads/LOG4J2-1528 Commit: 2d5812b2e98c2e1ca8e7acf322ae34aba34429c7 Parents: 33aaf3d Author: Gary Gregory <ggreg...@apache.org> Authored: Thu Aug 25 13:03:58 2016 -0700 Committer: Gary Gregory <ggreg...@apache.org> Committed: Thu Aug 25 13:03:58 2016 -0700 ---------------------------------------------------------------------- .../core/config/plugins/util/ResolverUtil.java | 11 +- .../plugins/util/PluginManagerPackagesTest.java | 2 +- .../util/ResolverUtilCustomProtocolTest.java | 227 +++++++++++++++++++ .../config/plugins/util/ResolverUtilTest.java | 146 +++++++----- 4 files changed, 322 insertions(+), 64 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2d5812b2/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java index 14bf1e8..a353228 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java @@ -199,9 +199,14 @@ public class ResolverUtil { close(stream, newURL); } } else if (VFS.equals(url.getProtocol())) { - final String path = urlPath.substring(1, urlPath.length() - packageName.length() - 2); - final File file = new File(path); - loadImplementationsInJar(test, packageName, file); + final String containerPath = urlPath.substring(1, + urlPath.length() - packageName.length() - 2); + final File containerFile = new File(containerPath); + if (containerFile.isDirectory()) { + loadImplementationsInDirectory(test, packageName, new File(containerFile, packageName)); + } else { + loadImplementationsInJar(test, packageName, containerFile); + } } else if (BUNDLE_RESOURCE.equals(url.getProtocol())) { loadImplementationsInBundle(test, packageName); } else { http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2d5812b2/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/PluginManagerPackagesTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/PluginManagerPackagesTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/PluginManagerPackagesTest.java index 5808b10..c97643f 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/PluginManagerPackagesTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/PluginManagerPackagesTest.java @@ -85,7 +85,7 @@ public class PluginManagerPackagesTest { assertEquals("abc123XYZ", messages.get(0)); } - private void compile(final File f) throws IOException { + static void compile(final File f) throws IOException { // set up compiler final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); final DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>(); http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2d5812b2/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java new file mode 100644 index 0000000..86bc000 --- /dev/null +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java @@ -0,0 +1,227 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ + +package org.apache.logging.log4j.core.config.plugins.util; + +import static org.junit.Assert.assertEquals; +import static org.apache.logging.log4j.core.config.plugins.util.ResolverUtilTest.compileAndCreateClassLoader; +import static org.apache.logging.log4j.core.config.plugins.util.ResolverUtilTest.compileJarAndCreateClassLoader; + +import org.apache.logging.log4j.core.config.plugins.util.PluginRegistry.PluginTest; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.net.URLStreamHandlerFactory; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * Tests the ResolverUtil class for custom protocol like bundleresource, vfs, vfszip. + */ +public class ResolverUtilCustomProtocolTest { + + static class NoopURLStreamHandlerFactory implements URLStreamHandlerFactory { + @Override + public URLStreamHandler createURLStreamHandler(String protocol) { + return new URLStreamHandler() { + @Override + protected URLConnection openConnection(URL url) { + return open(url, null); + } + + private URLConnection open(URL url, Proxy proxy) { + return new URLConnection(url) { + @Override + public void connect() throws IOException { + // do nothing + } + }; + } + + @Override + protected URLConnection openConnection(URL url, Proxy proxy) { + return open(url, proxy); + } + + @Override + protected int getDefaultPort() { + return 1; + } + }; + } + } + + static class SingleURLClassLoader extends ClassLoader { + private URL url; + + public SingleURLClassLoader(URL url) { + this.url = url; + } + + public SingleURLClassLoader(URL url, ClassLoader parent) { + super(parent); + this.url = url; + } + + @Override + protected URL findResource(String name) { + return url; + } + + @Override + public URL getResource(String name) { + return findResource(name); + } + + @Override + public Enumeration<URL> getResources(String name) throws IOException { + return findResources(name); + } + + @Override + protected Enumeration<URL> findResources(String name) throws IOException { + return Collections.enumeration(Arrays.asList(findResource(name))); + } + } + + @BeforeClass + public static void defineURLHandler() { + URL.setURLStreamHandlerFactory(new NoopURLStreamHandlerFactory()); + } + + @AfterClass + public static void removeURLHandler() throws Exception { + // Simulate this - Not the best way, but no other choice welcome ? + // URL.setURLStreamHandlerFactory(null); + Field handlersFields = URL.class.getDeclaredField("handlers"); + if (!handlersFields.isAccessible()) { + handlersFields.setAccessible(true); + } + Field factoryFields = URL.class.getDeclaredField("factory"); + if (!factoryFields.isAccessible()) { + factoryFields.setAccessible(true); + } + + @SuppressWarnings("unchecked") + Hashtable<String, URLStreamHandler> handlers = (Hashtable<String, URLStreamHandler>) handlersFields.get(null); + handlers.clear(); + factoryFields.set(null, null); + } + + @Test + public void testExtractPathFromVfsEarJarWindowsUrl() throws Exception { + final URL url = new URL( + "vfs:/C:/jboss/jboss-eap-6.4/standalone/deployments/com.xxx.yyy.application-ear.ear/lib/com.xxx.yyy.logging.jar/com/xxx/yyy/logging/config/"); + final String expected = "/C:/jboss/jboss-eap-6.4/standalone/deployments/com.xxx.yyy.application-ear.ear/lib/com.xxx.yyy.logging.jar/com/xxx/yyy/logging/config/"; + assertEquals(expected, new ResolverUtil().extractPath(url)); + } + + @Test + public void testExtractPathFromVfsWarClassesWindowsUrl() throws Exception { + final URL url = new URL( + "vfs:/C:/jboss/jboss-eap-6.4/standalone/deployments/test-log4j2-web-standalone.war/WEB-INF/classes/org/hypik/test/jboss/eap7/logging/config/"); + final String expected = "/C:/jboss/jboss-eap-6.4/standalone/deployments/test-log4j2-web-standalone.war/WEB-INF/classes/org/hypik/test/jboss/eap7/logging/config/"; + assertEquals(expected, new ResolverUtil().extractPath(url)); + } + + @Test + public void testExtractPathFromVfsWarClassesLinuxUrl() throws Exception { + final URL url = new URL( + "vfs:/content/mycustomweb.war/WEB-INF/classes/org/hypik/test/jboss/log4j2/logging/pluginweb/"); + final String expected = "/content/mycustomweb.war/WEB-INF/classes/org/hypik/test/jboss/log4j2/logging/pluginweb/"; + assertEquals(expected, new ResolverUtil().extractPath(url)); + } + + @Test + public void testExtractPathFromVfszipUrl() throws Exception { + final URL url = new URL( + "vfszip:/home2/jboss-5.0.1.CR2/jboss-as/server/ais/ais-deploy/myear.ear/mywar.war/WEB-INF/some.xsd"); + final String expected = "/home2/jboss-5.0.1.CR2/jboss-as/server/ais/ais-deploy/myear.ear/mywar.war/WEB-INF/some.xsd"; + assertEquals(expected, new ResolverUtil().extractPath(url)); + } + + @Test + public void testExtractPathFromVfsEarJarLinuxUrl() throws Exception { + final URL url = new URL( + "vfs:/content/test-log4k2-ear.ear/lib/test-log4j2-jar-plugins.jar/org/hypik/test/jboss/log4j2/pluginjar/"); + final String expected = "/content/test-log4k2-ear.ear/lib/test-log4j2-jar-plugins.jar/org/hypik/test/jboss/log4j2/pluginjar/"; + assertEquals(expected, new ResolverUtil().extractPath(url)); + } + + @Test + public void testExtractPathFromVfszipUrlWithPlusCharacters() throws Exception { + final URL url = new URL("vfszip:/path+with+plus/file+name+with+plus.xml"); + final String expected = "/path+with+plus/file+name+with+plus.xml"; + assertEquals(expected, new ResolverUtil().extractPath(url)); + } + + @Test + public void testExtractPathFromVfsUrlWithPlusCharacters() throws Exception { + final URL url = new URL("vfs:/path+with+plus/file+name+with+plus.xml"); + final String expected = "/path+with+plus/file+name+with+plus.xml"; + assertEquals(expected, new ResolverUtil().extractPath(url)); + } + + @Test + public void testExtractPathFromResourceBundleUrl() throws Exception { + final URL url = new URL("bundleresource:/some/path/some/file.properties"); + final String expected = "/some/path/some/file.properties"; + assertEquals(expected, new ResolverUtil().extractPath(url)); + } + + @Test + public void testExtractPathFromResourceBundleUrlWithPlusCharacters() throws Exception { + final URL url = new URL("bundleresource:/some+path/some+file.properties"); + final String expected = "/some+path/some+file.properties"; + assertEquals(expected, new ResolverUtil().extractPath(url)); + } + + @Test + public void testFindInPackageFromVfsDirectoryURL() throws Exception { + ClassLoader cl = compileAndCreateClassLoader("3"); + + ResolverUtil resolverUtil = new ResolverUtil(); + resolverUtil.setClassLoader(new SingleURLClassLoader(new URL("vfs:/target/resolverutil3/customplugin3/"), cl)); + resolverUtil.findInPackage(new PluginTest(), "customplugin3"); + assertEquals("Class not found in packages", 1, resolverUtil.getClasses().size()); + assertEquals("Unexpected class resolved", cl.loadClass("customplugin3.FixedString3Layout"), + resolverUtil.getClasses().iterator().next()); + } + + @Test + public void testFindInPackageFromVfsJarURL() throws Exception { + ClassLoader cl = compileJarAndCreateClassLoader("4"); + + ResolverUtil resolverUtil = new ResolverUtil(); + resolverUtil.setClassLoader( + new SingleURLClassLoader(new URL("vfs:/target/resolverutil4/customplugin4.jar/customplugin4/"), cl)); + resolverUtil.findInPackage(new PluginTest(), "customplugin4"); + assertEquals("Class not found in packages", 1, resolverUtil.getClasses().size()); + assertEquals("Unexpected class resolved", cl.loadClass("customplugin4.FixedString4Layout"), + resolverUtil.getClasses().iterator().next()); + } + +} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2d5812b2/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java index cbcd23c..76ab740 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java @@ -20,12 +20,23 @@ package org.apache.logging.log4j.core.config.plugins.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.io.File; +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; - -import org.junit.Ignore; +import java.net.URLClassLoader; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.HashMap; +import java.util.Map; + +import org.apache.logging.log4j.core.config.plugins.util.PluginRegistry.PluginTest; import org.junit.Test; /** @@ -93,64 +104,6 @@ public class ResolverUtilTest { assertEquals(expected, new ResolverUtil().extractPath(url)); } - @Ignore - @Test - public void testExtractPathFromVfszipUrl() throws Exception { - // need to install URLStreamHandlerFactory to prevent "unknown protocol" MalformedURLException - final URL url = new URL( - "vfszip:/home2/jboss-5.0.1.CR2/jboss-as/server/ais/ais-deploy/myear.ear/mywar.war/WEB-INF/some.xsd"); - final String expected = "/home2/jboss-5.0.1.CR2/jboss-as/server/ais/ais-deploy/myear.ear/mywar.war/WEB-INF/some.xsd"; - assertEquals(expected, new ResolverUtil().extractPath(url)); - } - - @Ignore - @Test - public void testExtractPathFromVfsUrl() throws Exception { - // need to install URLStreamHandlerFactory to prevent "unknown protocol" MalformedURLException - final URL url = new URL( - "vfs:/C:/jboss/jboss-eap-6.4/standalone/deployments/com.xxx.yyy.application-ear.ear/lib/com.xxx.yyy.logging.jar/com/xxx/yyy/logging/config/"); - final String expected = "/jboss/jboss-eap-6.4/standalone/deployments/com.xxx.yyy.application-ear.ear/lib/com.xxx.yyy.logging.jar/com/xxx/yyy/logging/config/"; - assertEquals(expected, new ResolverUtil().extractPath(url)); - } - - @Ignore - @Test - public void testExtractPathFromVfszipUrlWithPlusCharacters() - throws Exception { - // need to install URLStreamHandlerFactory to prevent "unknown protocol" MalformedURLException - final URL url = new URL("vfszip:/path+with+plus/file+name+with+plus.xml"); - final String expected = "/path+with+plus/file+name+with+plus.xml"; - assertEquals(expected, new ResolverUtil().extractPath(url)); - } - - @Ignore - @Test - public void testExtractPathFromVfsUrlWithPlusCharacters() - throws Exception { - // need to install URLStreamHandlerFactory to prevent "unknown protocol" MalformedURLException - final URL url = new URL("vfs:/path+with+plus/file+name+with+plus.xml"); - final String expected = "/path+with+plus/file+name+with+plus.xml"; - assertEquals(expected, new ResolverUtil().extractPath(url)); - } - - @Ignore - @Test - public void testExtractPathFromResourceBundleUrl() throws Exception { - // need to install URLStreamHandlerFactory to prevent "unknown protocol" MalformedURLException - final URL url = new URL("resourcebundle:/some/path/some/file.properties"); - final String expected = "/some/path/some/file.properties"; - assertEquals(expected, new ResolverUtil().extractPath(url)); - } - - @Ignore - @Test - public void testExtractPathFromResourceBundleUrlWithPlusCharacters() throws Exception { - // need to install URLStreamHandlerFactory to prevent "unknown protocol" MalformedURLException - final URL url = new URL("resourcebundle:/some+path/some+file.properties"); - final String expected = "/some+path/some+file.properties"; - assertEquals(expected, new ResolverUtil().extractPath(url)); - } - @Test public void testExtractPathFromHttpUrl() throws Exception { final URL url = new URL("http://java.sun.com/index.html#chapter1"); @@ -186,4 +139,77 @@ public class ResolverUtilTest { assertEquals(expected, new ResolverUtil().extractPath(url)); } + @Test + public void testFindInPackageFromDirectoryPath() throws Exception { + ClassLoader cl = compileAndCreateClassLoader("1"); + + ResolverUtil resolverUtil = new ResolverUtil(); + resolverUtil.setClassLoader(cl); + resolverUtil.findInPackage(new PluginTest(), "customplugin1"); + assertEquals("Class not found in packages", 1, resolverUtil.getClasses().size()); + assertEquals("Unexpected class resolved", + cl.loadClass("customplugin1.FixedString1Layout"), + resolverUtil.getClasses().iterator().next()); + } + + @Test + public void testFindInPackageFromJarPath() throws Exception { + ClassLoader cl = compileJarAndCreateClassLoader("2"); + + ResolverUtil resolverUtil = new ResolverUtil(); + resolverUtil.setClassLoader(cl); + resolverUtil.findInPackage(new PluginTest(), "customplugin2"); + assertEquals("Class not found in packages", 1, resolverUtil.getClasses().size()); + assertEquals("Unexpected class resolved", + cl.loadClass("customplugin2.FixedString2Layout"), + resolverUtil.getClasses().iterator().next()); + } + + static URLClassLoader compileJarAndCreateClassLoader(String suffix) throws IOException, Exception { + File workDir = compile(suffix); + File jarFile = new File(workDir, "customplugin" + suffix + ".jar"); + URI jarURL = jarFile.toURI(); + createJar(jarURL, workDir, new File(workDir, + "customplugin" + suffix + "/FixedString" + suffix + "Layout.class")); + return URLClassLoader.newInstance(new URL[] {jarURL.toURL()}); + } + + static URLClassLoader compileAndCreateClassLoader(String suffix) throws IOException { + final File workDir = compile(suffix); + return URLClassLoader.newInstance(new URL[] {workDir.toURI().toURL()}); + } + + static File compile(String suffix) throws IOException { + final File orig = new File("target/test-classes/customplugin/FixedStringLayout.java.source"); + final File workDir = new File("target/resolverutil" + suffix); + final File javaFile = new File(workDir, "customplugin" + suffix + "/FixedString" + suffix + "Layout.java"); + final File parent = javaFile.getParentFile(); + if (!parent.exists()) { + assertTrue("Create customplugin" + suffix + " folder KO", javaFile.getParentFile().mkdirs()); + } + + String content = new String(Files.readAllBytes(orig.toPath())) + .replaceAll("FixedString", "FixedString" + suffix) + .replaceAll("customplugin", "customplugin" + suffix); + Files.write(javaFile.toPath(), content.getBytes()); + + PluginManagerPackagesTest.compile(javaFile); + return workDir; + } + + static void createJar(URI jarURL, File workDir, File f) throws Exception { + Map<String, String> env = new HashMap<>(); + env.put("create", "true"); + URI uri = URI.create("jar:file://" + jarURL.getPath()); + try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) { + Path path = zipfs.getPath(workDir.toPath().relativize(f.toPath()).toString()); + if (path.getParent() != null) { + Files.createDirectories(path.getParent()); + } + Files.copy(f.toPath(), + path, + StandardCopyOption.REPLACE_EXISTING ); + } + } + }