Repository: logging-log4j2 Updated Branches: refs/heads/master d71541572 -> 4ccf5cc41
LOG4J2-920: Fix import-package omission causing CNFE in OSGi Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/4ccf5cc4 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/4ccf5cc4 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/4ccf5cc4 Branch: refs/heads/master Commit: 4ccf5cc41e479ef370ef5e21e99bc0adf1ebd79e Parents: d715415 Author: Matt Sicker <[email protected]> Authored: Mon Feb 8 20:27:09 2016 -0600 Committer: Matt Sicker <[email protected]> Committed: Mon Feb 8 20:27:09 2016 -0600 ---------------------------------------------------------------------- log4j-api/pom.xml | 13 +- .../log4j/osgi/AbstractLoadBundleTest.java | 140 ++++++++++++++++++- .../logging/log4j/osgi/BundleTestInfo.java | 2 +- .../logging/log4j/core/osgi/Activator.java | 3 +- src/changes/changes.xml | 3 + 5 files changed, 148 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4ccf5cc4/log4j-api/pom.xml ---------------------------------------------------------------------- diff --git a/log4j-api/pom.xml b/log4j-api/pom.xml index 0291d96..e4df6f5 100644 --- a/log4j-api/pom.xml +++ b/log4j-api/pom.xml @@ -33,6 +33,12 @@ <projectDir>/api</projectDir> </properties> <dependencies> + <!-- Place Felix before Equinox because Felix is signed. / also place it before org.osgi.core so that its versions of the OSGi classes are used --> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.framework</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>org.osgi</groupId> <artifactId>org.osgi.core</artifactId> @@ -43,12 +49,6 @@ <artifactId>junit</artifactId> <scope>test</scope> </dependency> - <!-- Place Felix before Equinox because Felix is signed. --> - <dependency> - <groupId>org.apache.felix</groupId> - <artifactId>org.apache.felix.framework</artifactId> - <scope>test</scope> - </dependency> <dependency> <groupId>org.eclipse.osgi</groupId> <artifactId>org.eclipse.osgi</artifactId> @@ -121,6 +121,7 @@ <Export-Package>org.apache.logging.log4j.*</Export-Package> <Import-Package> sun.reflect;resolution:=optional, + org.apache.logging.log4j.core.osgi;resolution:=optional, * </Import-Package> <Bundle-Activator>org.apache.logging.log4j.util.Activator</Bundle-Activator> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4ccf5cc4/log4j-api/src/test/java/org/apache/logging/log4j/osgi/AbstractLoadBundleTest.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/osgi/AbstractLoadBundleTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/osgi/AbstractLoadBundleTest.java index 9c6acab..15f0f5b 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/osgi/AbstractLoadBundleTest.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/osgi/AbstractLoadBundleTest.java @@ -16,7 +16,11 @@ */ package org.apache.logging.log4j.osgi; +import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.PrintStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import org.junit.Assert; import org.junit.Assume; @@ -29,7 +33,7 @@ import org.osgi.framework.BundleException; import org.osgi.framework.launch.FrameworkFactory; /** - * Tests loading a bundle into an OSGi container. + * Tests loading a bundle into an OSGi container. Also test a basic Log4J 'setup' in an OSGi container. * <p> * Requires that "mvn package" has been previously run, otherwise test fails its JUnit {@link Assume}. * </p> @@ -62,8 +66,9 @@ public abstract class AbstractLoadBundleTest { final String bundlePath = getBundlePath(); Assume.assumeNotNull(bundlePath); final File file = new File(bundlePath); - Assume.assumeTrue("File does not exist: " + file.getAbsolutePath() + ". Run 'mvn package' before 'mvn test'", - file.exists()); + Assume.assumeTrue( + "File does not exist: " + file.getAbsolutePath() + ". Run 'mvn package -DskipTests' before 'mvn test'", + file.exists()); } protected String getBundlePath() { @@ -76,7 +81,7 @@ public abstract class AbstractLoadBundleTest { * @return the expected bundle symbolic name. */ public String getExpectedBundleSymbolicName() { - return "org.apache.logging." + bundleTestInfo.getArtifactId(); + return "org.apache.logging." + bundleTestInfo.getArtifactId().replace('-', '.'); } /** @@ -90,7 +95,7 @@ public abstract class AbstractLoadBundleTest { final Bundle bundle = bundleContext.installBundle("file:" + getBundlePath()); Assert.assertNotNull("Error loading bundle: null returned", bundle); Assert.assertEquals("Error loading bundle: symbolic name mismatch", getExpectedBundleSymbolicName(), - bundle.getSymbolicName()); + bundle.getSymbolicName()); Assert.assertEquals("Bundle is not in INSTALLED state", Bundle.INSTALLED, bundle.getState()); // sanity check: start and stop bundle @@ -102,6 +107,131 @@ public abstract class AbstractLoadBundleTest { Assert.assertEquals("Bundle is not in ACTIVE state", Bundle.ACTIVE, bundle.getState()); bundle.stop(); Assert.assertEquals("Bundle is not in RESOLVED state", Bundle.RESOLVED, bundle.getState()); + bundle.uninstall(); + Assert.assertEquals("Bundle is not in UNINSTALLED state", Bundle.UNINSTALLED, bundle.getState()); + } + + /** + * Tests the log of a simple message in an OSGi container + */ + @Test + public void testSimpleLogInAnOsgiContext() throws BundleException, ReflectiveOperationException { + + final BundleContext bundleContext = osgi.getFramework().getBundleContext(); + + final Bundle api = bundleContext.installBundle("file:" + getBundlePath()); + final Bundle core = bundleContext.installBundle( + "file:../log4j-core/target/log4j-core-" + bundleTestInfo.getVersion() + ".jar"); + final Bundle dummy = bundleContext.installBundle( + "file:../log4j-samples/configuration/target/log4j-samples-configuration-" + bundleTestInfo.getVersion() + ".jar"); + + api.start(); + core.start(); + dummy.start(); + + final PrintStream bakStream = System.out; + try { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final PrintStream logStream = new PrintStream(baos); + System.setOut(logStream); + + log(dummy); + + final String result = baos.toString().substring( + 12).trim(); // remove the instant then the spaces at start and end, that are non constant + Assert.assertEquals("[main] ERROR org.apache.logging.log4j.configuration.CustomConfiguration - Test OK", + result); + } finally { + System.setOut(bakStream); + } + + dummy.stop(); + core.stop(); + api.stop(); + + dummy.uninstall(); + core.uninstall(); + api.uninstall(); + } + + /** + * Tests LOG4J2-920. + */ + @Test + public void testMissingImportOfCoreOsgiPackage() throws BundleException, ReflectiveOperationException { + + final BundleContext bundleContext = osgi.getFramework().getBundleContext(); + + final Bundle api = bundleContext.installBundle("file:" + getBundlePath()); + final Bundle core = bundleContext.installBundle( + "file:../log4j-core/target/log4j-core-" + bundleTestInfo.getVersion() + ".jar"); + final Bundle dummy = bundleContext.installBundle( + "file:../log4j-samples/configuration/target/log4j-samples-configuration-" + bundleTestInfo.getVersion() + ".jar"); + + api.start(); + core.start(); + dummy.start(); + + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final PrintStream logStream = new PrintStream(baos); + + final PrintStream bakStream = setupStream(api, logStream); + + log(dummy); + + setupStream(api, bakStream); + + final boolean result = baos.toString().contains( + "ERROR StatusLogger Unable to create context org.apache.logging.log4j.core.osgi.BundleContextSelector"); + Assert.assertFalse( + "org.apache.logging.log4j.core.osgi;resolution:=optional is missing in Import-Package in the POM", result); + + dummy.stop(); + core.stop(); + api.stop(); + + dummy.uninstall(); + core.uninstall(); + api.uninstall(); + } + + private void log(final Bundle dummy) throws ReflectiveOperationException { + // use reflection to log in the context of the dummy bundle + + final Class<?> logManagerClass = dummy.loadClass("org.apache.logging.log4j.LogManager"); + final Method getLoggerMethod = logManagerClass.getMethod("getLogger", Class.class); + + final Class<?> loggerClass = dummy.loadClass("org.apache.logging.log4j.configuration.CustomConfiguration"); + + final Object logger = getLoggerMethod.invoke(null, loggerClass); + final Method infoMethod = logger.getClass().getMethod("error", Object.class); + + infoMethod.invoke(logger, "Test OK"); + } + + private PrintStream setupStream(final Bundle api, final PrintStream newStream) throws ReflectiveOperationException { + // use reflection to access the classes internals and in the context of the api bundle + + final Class<?> statusLoggerClass = api.loadClass("org.apache.logging.log4j.status.StatusLogger"); + + final Field statusLoggerField = statusLoggerClass.getDeclaredField("STATUS_LOGGER"); + statusLoggerField.setAccessible(true); + final Object statusLoggerFieldValue = statusLoggerField.get(null); + + final Field loggerField = statusLoggerClass.getDeclaredField("logger"); + loggerField.setAccessible(true); + final Object loggerFieldValue = loggerField.get(statusLoggerFieldValue); + + final Class<?> simpleLoggerClass = api.loadClass("org.apache.logging.log4j.simple.SimpleLogger"); + + final Field streamField = simpleLoggerClass.getDeclaredField("stream"); + streamField.setAccessible(true); + + final PrintStream oldStream = (PrintStream) streamField.get(loggerFieldValue); + + streamField.set(loggerFieldValue, newStream); + + return oldStream; } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4ccf5cc4/log4j-api/src/test/java/org/apache/logging/log4j/osgi/BundleTestInfo.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/osgi/BundleTestInfo.java b/log4j-api/src/test/java/org/apache/logging/log4j/osgi/BundleTestInfo.java index 64c4a0b..cd53f63 100644 --- a/log4j-api/src/test/java/org/apache/logging/log4j/osgi/BundleTestInfo.java +++ b/log4j-api/src/test/java/org/apache/logging/log4j/osgi/BundleTestInfo.java @@ -78,7 +78,7 @@ public class BundleTestInfo { * @return the Maven version String. */ public String getVersion() { - return project.getProperties().getProperty("project.version.osgi"); + return project.getVersion(); } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4ccf5cc4/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/Activator.java ---------------------------------------------------------------------- diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/Activator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/Activator.java index 2cf6f47..d926d2e 100644 --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/Activator.java +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/osgi/Activator.java @@ -56,7 +56,8 @@ public final class Activator implements BundleActivator, SynchronousBundleListen private static void scanInstalledBundlesForPlugins(final BundleContext context) { final Bundle[] bundles = context.getBundles(); for (final Bundle bundle : bundles) { - if (bundle.getState() == Bundle.ACTIVE) { + // LOG4J2-920: don't scan system bundle for plugins + if (bundle.getState() == Bundle.ACTIVE && bundle.getBundleId() != 0) { // TODO: bundle state can change during this scanBundleForPlugins(bundle); } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4ccf5cc4/src/changes/changes.xml ---------------------------------------------------------------------- diff --git a/src/changes/changes.xml b/src/changes/changes.xml index a302ce3..80fc4b7 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -105,6 +105,9 @@ <action issue="LOG4J2-1254" dev="rpopma" type="fix" due-to="Josh Trow"> Fix typo in Flow Tracing documentation. </action> + <action issue="LOG4J2-920" dev="mattsicker" type="fix" due-to="Ludovic Hochet"> + ClassNotFoundException for BundleContextSelector when initialising in an OSGi environment. + </action> </release> <release version="2.5" date="2015-12-06" description="GA Release 2.5"> <action issue="LOG4J2-324" dev="rpopma" type="fix">
