This is an automated email from the ASF dual-hosted git repository.

rgoers pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


The following commit(s) were added to refs/heads/master by this push:
     new 2f0d50f2c0 log4j-jul is now a JPMS module
2f0d50f2c0 is described below

commit 2f0d50f2c018c02372707cb11d1831d08f9ec4dd
Author: Ralph Goers <[email protected]>
AuthorDate: Thu Sep 1 01:47:43 2022 -0700

    log4j-jul is now a JPMS module
---
 .../appender/rolling/RollingNewDirectoryTest.java  |  19 +-
 log4j-jul/pom.xml                                  |  65 +-
 .../java/module-info.java}                         |  57 +-
 ...ultLevelConverterTest.java => module-info.java} |  62 +-
 .../log4j/jul/{ => test}/AbstractLoggerTest.java   |   5 +-
 .../log4j/jul/{ => test}/ApiLoggerTest.java        |   6 +-
 .../jul/{ => test}/AsyncLoggerThreadsTest.java     |   7 +-
 .../BracketInNotInterpolatedMessageTest.java       |   4 +-
 .../jul/{ => test}/CallerInformationTest.java      | 179 ++--
 .../log4j/jul/{ => test}/CoreLoggerTest.java       |   4 +-
 .../DefaultLevelConverterCustomJulLevelsTest.java  |   4 +-
 .../jul/{ => test}/DefaultLevelConverterTest.java  |  63 +-
 .../jul/{ => test}/JavaLevelTranslatorTest.java    |   3 +-
 .../logging/log4j/jul/test/ListAppender.java       | 289 +++++++
 .../jul/{ => test}/Log4jBridgeHandlerTest.java     | 918 ++++++++++-----------
 .../jul/{ => test}/Log4jLevelTranslatorTest.java   |   3 +-
 .../src/test/resources/log4j2-calling-class.xml    |  37 +
 .../src/test/resources/log4j2-julBridge-test.xml   |   2 +-
 pom.xml                                            |   2 +-
 19 files changed, 1078 insertions(+), 651 deletions(-)

diff --git 
a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingNewDirectoryTest.java
 
b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingNewDirectoryTest.java
index 4909ac110b..1dd931b4a0 100644
--- 
a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingNewDirectoryTest.java
+++ 
b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/rolling/RollingNewDirectoryTest.java
@@ -20,17 +20,20 @@ import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
 import org.apache.logging.log4j.plugins.Named;
 import org.apache.logging.log4j.test.junit.CleanUpDirectories;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 import java.io.File;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.fail;
 
 /**
  * Tests
  */
-public class RollingNewDirectoryTest extends AbstractRollingListenerTest {
+public class RollingNewDirectoryTest implements RolloverListener {
     private static final String CONFIG = "log4j-rolling-new-directory.xml";
 
     private static final String DIR = "target/rolling-new-directory";
@@ -43,14 +46,24 @@ public class RollingNewDirectoryTest extends 
AbstractRollingListenerTest {
         manager.addRolloverListener(this);
         for (int i = 0; i < 10; ++i) {
             logger.info("AAA");
-            currentTimeMillis.addAndGet(300);
+            Thread.sleep(300);
+        }
+        try {
+            if (!rollover.await(5, TimeUnit.SECONDS)) {
+                fail("Timer expired before rollover");
+            }
+        } catch (InterruptedException ie) {
+            fail("Thread was interrupted");
         }
-        rollover.await();
         final File dir = new File(DIR);
         assertThat(dir).isNotEmptyDirectory();
         assertThat(dir.listFiles()).hasSizeGreaterThan(2);
     }
 
+    @Override
+    public void rolloverTriggered(final String fileName) {
+    }
+
     @Override
     public void rolloverComplete(final String fileName) {
         rollover.countDown();
diff --git a/log4j-jul/pom.xml b/log4j-jul/pom.xml
index 04d76b3140..d77dbd7bc9 100644
--- a/log4j-jul/pom.xml
+++ b/log4j-jul/pom.xml
@@ -26,7 +26,6 @@
 
   <properties>
     <log4jParentDir>${basedir}/..</log4jParentDir>
-    <module.name>org.apache.logging.log4j.jul</module.name>
     <maven.doap.skip>true</maven.doap.skip>
   </properties>
 
@@ -44,6 +43,42 @@
       <artifactId>log4j-core</artifactId>
       <optional>true</optional>
     </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api-test</artifactId>
+      <scope>test</scope>
+      <exclusions>
+        <!-- Exclude Junit 5 - it is hardwired to use java.util.logging and 
breaks all these tests -->
+        <exclusion>
+          <groupId>org.junit.jupiter</groupId>
+          <artifactId>junit-jupiter-api</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.junit.jupiter</groupId>
+          <artifactId>junit-jupiter-engine</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.junit.platform</groupId>
+          <artifactId>junit-platform-commons</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.junit.platform</groupId>
+          <artifactId>junit-platform-launcher</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.junit.jupiter</groupId>
+          <artifactId>junit-jupiter-migrationsupport</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.junit.jupiter</groupId>
+          <artifactId>junit-jupiter-params</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.junit-pioneer</groupId>
+          <artifactId>junit-pioneer</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-core-test</artifactId>
@@ -112,6 +147,34 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-jar</id>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+            <configuration combine.self="override">
+              <archive>
+                <manifestFile>${manifestfile}</manifestFile>
+                <manifestEntries>
+                  <Specification-Title>${project.name}</Specification-Title>
+                  
<Specification-Version>${project.version}</Specification-Version>
+                  
<Specification-Vendor>${project.organization.name}</Specification-Vendor>
+                  <Implementation-Title>${project.name}</Implementation-Title>
+                  
<Implementation-Version>${project.version}</Implementation-Version>
+                  
<Implementation-Vendor>${project.organization.name}</Implementation-Vendor>
+                  
<Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
+                  
<X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK>
+                  
<X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK>
+                </manifestEntries>
+              </archive>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
       <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
diff --git 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/DefaultLevelConverterTest.java
 b/log4j-jul/src/main/java/module-info.java
similarity index 66%
copy from 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/DefaultLevelConverterTest.java
copy to log4j-jul/src/main/java/module-info.java
index 801749ec27..31c51021c4 100644
--- 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/DefaultLevelConverterTest.java
+++ b/log4j-jul/src/main/java/module-info.java
@@ -1,31 +1,26 @@
-/*
- * 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.jul;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-public class DefaultLevelConverterTest {
-
-    /**
-     * (LOG4J2-1108) NullPointerException when passing null to 
java.util.logging.Logger.setLevel().
-     */
-    @Test
-    public void testJulSetNull() {
-        Assert.assertEquals(null, new DefaultLevelConverter().toLevel(null));
-    }
-}
+/*
+ * 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.
+ */
+
+module org.apache.logging.log4j.jul {
+    exports org.apache.logging.log4j.jul;
+    opens org.apache.logging.log4j.jul to org.apache.logging.log4j;
+
+    requires org.apache.logging.log4j;
+    requires org.apache.logging.log4j.core;
+    requires java.desktop;
+    requires java.logging;
+}
diff --git 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/DefaultLevelConverterTest.java
 b/log4j-jul/src/test/java/module-info.java
similarity index 62%
copy from 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/DefaultLevelConverterTest.java
copy to log4j-jul/src/test/java/module-info.java
index 801749ec27..764f4036d3 100644
--- 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/DefaultLevelConverterTest.java
+++ b/log4j-jul/src/test/java/module-info.java
@@ -1,31 +1,31 @@
-/*
- * 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.jul;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-public class DefaultLevelConverterTest {
-
-    /**
-     * (LOG4J2-1108) NullPointerException when passing null to 
java.util.logging.Logger.setLevel().
-     */
-    @Test
-    public void testJulSetNull() {
-        Assert.assertEquals(null, new DefaultLevelConverter().toLevel(null));
-    }
-}
+/*
+ * 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.
+ */
+module org.apache.logging.log4j.jul.test {
+    exports org.apache.logging.log4j.jul.test;
+
+    requires org.apache.logging.log4j;
+    requires org.apache.logging.log4j.core;
+    requires org.apache.logging.log4j.jul;
+    requires org.assertj.core;
+    requires org.hamcrest;
+    requires java.desktop;
+    requires java.logging;
+
+    requires junit;
+
+    provides org.apache.logging.log4j.plugins.processor.PluginService with 
org.apache.logging.log4j.jul.test.plugins.Log4jPlugins;
+}
\ No newline at end of file
diff --git 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/AbstractLoggerTest.java 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AbstractLoggerTest.java
similarity index 98%
rename from 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/AbstractLoggerTest.java
rename to 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AbstractLoggerTest.java
index 263765235b..1e446e4397 100644
--- 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/AbstractLoggerTest.java
+++ 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AbstractLoggerTest.java
@@ -15,7 +15,7 @@
  * limitations under the license.
  */
 
-package org.apache.logging.log4j.jul;
+package org.apache.logging.log4j.jul.test;
 
 import java.util.List;
 import java.util.logging.Logger;
@@ -23,7 +23,8 @@ import java.util.logging.Logger;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.impl.Log4jLogEvent;
-import org.apache.logging.log4j.core.test.appender.ListAppender;
+import org.apache.logging.log4j.jul.ApiLogger;
+import org.apache.logging.log4j.jul.LevelTranslator;
 import org.junit.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
diff --git 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/ApiLoggerTest.java 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/ApiLoggerTest.java
similarity index 93%
rename from 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/ApiLoggerTest.java
rename to 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/ApiLoggerTest.java
index aafd287871..bb69781f9f 100644
--- a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/ApiLoggerTest.java
+++ 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/ApiLoggerTest.java
@@ -15,7 +15,7 @@
  * limitations under the license.
  */
 
-package org.apache.logging.log4j.jul;
+package org.apache.logging.log4j.jul.test;
 
 import static org.hamcrest.Matchers.equalTo;
 import static org.junit.Assert.assertNotNull;
@@ -24,7 +24,9 @@ import static org.junit.Assert.assertThat;
 
 import java.util.logging.Logger;
 
-import org.apache.logging.log4j.core.test.appender.ListAppender;
+import org.apache.logging.log4j.jul.ApiLoggerAdapter;
+import org.apache.logging.log4j.jul.Constants;
+import org.apache.logging.log4j.jul.LogManager;
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
diff --git 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/AsyncLoggerThreadsTest.java
 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AsyncLoggerThreadsTest.java
similarity index 89%
rename from 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/AsyncLoggerThreadsTest.java
rename to 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AsyncLoggerThreadsTest.java
index 509c36ce44..3d8c02bf9b 100644
--- 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/AsyncLoggerThreadsTest.java
+++ 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/AsyncLoggerThreadsTest.java
@@ -14,11 +14,10 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.jul;
+package org.apache.logging.log4j.jul.test;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector;
-import org.apache.logging.log4j.core.test.categories.AsyncLoggers;
 import org.apache.logging.log4j.core.util.Constants;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -31,7 +30,7 @@ import java.util.stream.Collectors;
 
 import static org.junit.Assert.assertEquals;
 
-@Category(AsyncLoggers.class)
+//@Category(AsyncLoggers.class)
 @Ignore("https://issues.apache.org/jira/browse/LOG4J2-3523";)
 public class AsyncLoggerThreadsTest {
 
@@ -39,7 +38,7 @@ public class AsyncLoggerThreadsTest {
     public static void beforeClass() {
         System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR,
                 AsyncLoggerContextSelector.class.getName());
-        System.setProperty("java.util.logging.manager", 
org.apache.logging.log4j.jul.LogManager.class.getName());
+        System.setProperty("java.util.logging.manager", 
LogManager.class.getName());
     }
 
     @AfterClass
diff --git 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/BracketInNotInterpolatedMessageTest.java
 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/BracketInNotInterpolatedMessageTest.java
similarity index 95%
rename from 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/BracketInNotInterpolatedMessageTest.java
rename to 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/BracketInNotInterpolatedMessageTest.java
index 598cb84332..d2385b0785 100644
--- 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/BracketInNotInterpolatedMessageTest.java
+++ 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/BracketInNotInterpolatedMessageTest.java
@@ -14,14 +14,14 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.jul;
+package org.apache.logging.log4j.jul.test;
 
 import java.util.List;
 import java.util.logging.LogRecord;
 import java.util.logging.Logger;
 
 import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.test.appender.ListAppender;
+import org.apache.logging.log4j.jul.LogManager;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
diff --git 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/CallerInformationTest.java
 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/CallerInformationTest.java
similarity index 72%
rename from 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/CallerInformationTest.java
rename to 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/CallerInformationTest.java
index 2df2827145..74bdedae5f 100644
--- 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/CallerInformationTest.java
+++ 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/CallerInformationTest.java
@@ -1,78 +1,101 @@
-/*
- * 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.jul;
-
-import java.util.List;
-import java.util.logging.Logger;
-
-import org.apache.logging.log4j.core.test.junit.LoggerContextRule;
-import org.apache.logging.log4j.core.test.appender.ListAppender;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Rule;
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class CallerInformationTest {
-
-    // config from log4j-core test-jar
-    private static final String CONFIG = "log4j2-calling-class.xml";
-
-    @Rule
-    public final LoggerContextRule ctx = new LoggerContextRule(CONFIG);
-
-    @BeforeClass
-    public static void setUpClass() {
-        System.setProperty("java.util.logging.manager", 
LogManager.class.getName());
-    }
-
-    @AfterClass
-    public static void tearDownClass() {
-        System.clearProperty("java.util.logging.manager");
-    }
-
-    @Test
-    public void testClassLogger() throws Exception {
-        final ListAppender app = ctx.getListAppender("Class").clear();
-        final Logger logger = Logger.getLogger("ClassLogger");
-        logger.info("Ignored message contents.");
-        logger.warning("Verifying the caller class is still correct.");
-        logger.severe("Hopefully nobody breaks me!");
-        final List<String> messages = app.getMessages();
-        assertEquals("Incorrect number of messages.", 3, messages.size());
-        for (final String message : messages) {
-            assertEquals("Incorrect caller class name.", 
this.getClass().getName(), message);
-        }
-    }
-
-    @Test
-    public void testMethodLogger() throws Exception {
-        final ListAppender app = ctx.getListAppender("Method").clear();
-        final Logger logger = Logger.getLogger("MethodLogger");
-        logger.info("More messages.");
-        logger.warning("CATASTROPHE INCOMING!");
-        logger.severe("ZOMBIES!!!");
-        logger.warning("brains~~~");
-        logger.info("Itchy. Tasty.");
-        final List<String> messages = app.getMessages();
-        assertEquals("Incorrect number of messages.", 5, messages.size());
-        for (final String message : messages) {
-            assertEquals("Incorrect caller method name.", "testMethodLogger", 
message);
-        }
-    }
-}
+/*
+ * 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.jul.test;
+
+import java.net.URI;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.jul.LogManager;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class CallerInformationTest {
+
+    // config from log4j-core test-jar
+    private static final String CONFIG = "log4j2-calling-class.xml";
+
+    private LoggerContext ctx;
+    private ListAppender app;
+
+
+    @BeforeClass
+    public static void setUpClass() {
+        System.setProperty("java.util.logging.manager", 
LogManager.class.getName());
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+        System.clearProperty("java.util.logging.manager");
+    }
+
+    @Before
+    public void beforeEach() throws Exception {
+        URI uri = this.getClass().getClassLoader().getResource(CONFIG).toURI();
+        ctx = 
(LoggerContext)org.apache.logging.log4j.LogManager.getContext(null, false, uri);
+        assertNotNull("No LoggerContext", ctx);
+    }
+
+    @After
+    public void afterEach() throws Exception {
+        if (ctx != null) {
+            ctx.stop();
+            ctx = null;
+            app = null;
+        }
+    }
+
+    @Test
+    public void testClassLogger() throws Exception {
+        app = ctx.getConfiguration().getAppender("Class");
+        assertNotNull("No ListAppender", app);
+        app.clear();
+        final Logger logger = Logger.getLogger("ClassLogger");
+        logger.info("Ignored message contents.");
+        logger.warning("Verifying the caller class is still correct.");
+        logger.severe("Hopefully nobody breaks me!");
+        final List<String> messages = app.getMessages();
+        assertEquals("Incorrect number of messages.", 3, messages.size());
+        for (final String message : messages) {
+            assertEquals("Incorrect caller class name.", 
this.getClass().getName(), message);
+        }
+    }
+
+    @Test
+    public void testMethodLogger() throws Exception {
+        app = ctx.getConfiguration().getAppender("Method");
+        assertNotNull("No ListAppender", app);
+        app.clear();
+        final Logger logger = Logger.getLogger("MethodLogger");
+        logger.info("More messages.");
+        logger.warning("CATASTROPHE INCOMING!");
+        logger.severe("ZOMBIES!!!");
+        logger.warning("brains~~~");
+        logger.info("Itchy. Tasty.");
+        final List<String> messages = app.getMessages();
+        assertEquals("Incorrect number of messages.", 5, messages.size());
+        for (final String message : messages) {
+            assertEquals("Incorrect caller method name.", "testMethodLogger", 
message);
+        }
+    }
+}
diff --git 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/CoreLoggerTest.java 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/CoreLoggerTest.java
similarity index 97%
rename from 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/CoreLoggerTest.java
rename to 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/CoreLoggerTest.java
index 39aefee74c..6cf6b547e2 100644
--- a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/CoreLoggerTest.java
+++ 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/CoreLoggerTest.java
@@ -15,7 +15,7 @@
  * limitations under the license.
  */
 
-package org.apache.logging.log4j.jul;
+package org.apache.logging.log4j.jul.test;
 
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.is;
@@ -25,7 +25,7 @@ import static org.junit.Assert.assertThat;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import org.apache.logging.log4j.core.test.appender.ListAppender;
+import org.apache.logging.log4j.jul.LogManager;
 import org.apache.logging.log4j.util.Strings;
 import org.junit.After;
 import org.junit.AfterClass;
diff --git 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/DefaultLevelConverterCustomJulLevelsTest.java
 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/DefaultLevelConverterCustomJulLevelsTest.java
similarity index 97%
rename from 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/DefaultLevelConverterCustomJulLevelsTest.java
rename to 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/DefaultLevelConverterCustomJulLevelsTest.java
index 03f3cffda1..6183951ae7 100644
--- 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/DefaultLevelConverterCustomJulLevelsTest.java
+++ 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/DefaultLevelConverterCustomJulLevelsTest.java
@@ -14,9 +14,11 @@
  * See the license for the specific language governing permissions and
  * limitations under the license.
  */
-package org.apache.logging.log4j.jul;
+package org.apache.logging.log4j.jul.test;
 
 import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.jul.DefaultLevelConverter;
+import org.apache.logging.log4j.jul.LevelTranslator;
 import org.junit.Assert;
 import org.junit.Test;
 
diff --git 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/DefaultLevelConverterTest.java
 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/DefaultLevelConverterTest.java
similarity index 91%
rename from 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/DefaultLevelConverterTest.java
rename to 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/DefaultLevelConverterTest.java
index 801749ec27..7ae1803808 100644
--- 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/DefaultLevelConverterTest.java
+++ 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/DefaultLevelConverterTest.java
@@ -1,31 +1,32 @@
-/*
- * 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.jul;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-public class DefaultLevelConverterTest {
-
-    /**
-     * (LOG4J2-1108) NullPointerException when passing null to 
java.util.logging.Logger.setLevel().
-     */
-    @Test
-    public void testJulSetNull() {
-        Assert.assertEquals(null, new DefaultLevelConverter().toLevel(null));
-    }
-}
+/*
+ * 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.jul.test;
+
+import org.apache.logging.log4j.jul.DefaultLevelConverter;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class DefaultLevelConverterTest {
+
+    /**
+     * (LOG4J2-1108) NullPointerException when passing null to 
java.util.logging.Logger.setLevel().
+     */
+    @Test
+    public void testJulSetNull() {
+        Assert.assertEquals(null, new DefaultLevelConverter().toLevel(null));
+    }
+}
diff --git 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/JavaLevelTranslatorTest.java
 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/JavaLevelTranslatorTest.java
similarity index 96%
rename from 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/JavaLevelTranslatorTest.java
rename to 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/JavaLevelTranslatorTest.java
index 5ccc9c2345..46c010cf6b 100644
--- 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/JavaLevelTranslatorTest.java
+++ 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/JavaLevelTranslatorTest.java
@@ -15,12 +15,13 @@
  * limitations under the license.
  */
 
-package org.apache.logging.log4j.jul;
+package org.apache.logging.log4j.jul.test;
 
 import java.util.Arrays;
 import java.util.Collection;
 
 import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.jul.LevelTranslator;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
diff --git 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/ListAppender.java 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/ListAppender.java
new file mode 100644
index 0000000000..1f7fe83a4a
--- /dev/null
+++ 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/ListAppender.java
@@ -0,0 +1,289 @@
+/*
+ * 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.jul.test;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.Layout;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.Property;
+import org.apache.logging.log4j.core.impl.MutableLogEvent;
+import org.apache.logging.log4j.plugins.Configurable;
+import org.apache.logging.log4j.plugins.Plugin;
+import org.apache.logging.log4j.plugins.PluginAttribute;
+import org.apache.logging.log4j.plugins.PluginElement;
+import org.apache.logging.log4j.plugins.PluginFactory;
+import org.apache.logging.log4j.plugins.validation.constraints.Required;
+
+/**
+ * This appender is primarily used for testing. Use in a real environment is 
discouraged as the List could eventually
+ * grow to cause an OutOfMemoryError.
+ *
+ * This appender is not thread-safe.
+ *
+ * This appender will use {@link Layout#toByteArray(LogEvent)}.
+ *
+ */
+@Configurable(elementType = Appender.ELEMENT_TYPE, printObject = true)
+@Plugin("List")
+public class ListAppender extends AbstractAppender {
+
+    // Use Collections.synchronizedList rather than CopyOnWriteArrayList 
because we expect
+    // more frequent writes than reads.
+    final List<LogEvent> events = Collections.synchronizedList(new 
ArrayList<>());
+
+    private final List<String> messages = Collections.synchronizedList(new 
ArrayList<>());
+
+    final List<byte[]> data = Collections.synchronizedList(new ArrayList<>());
+
+    private final boolean newLine;
+
+    private final boolean raw;
+
+    private static final String WINDOWS_LINE_SEP = "\r\n";
+
+    /**
+     * CountDownLatch for asynchronous logging tests. Example usage:
+     * 
+     * <pre>
+     * &#64;Rule
+     * public LoggerContextRule context = new 
LoggerContextRule("log4j-list.xml");
+     * private ListAppender listAppender;
+     *
+     * &#64;Before
+     * public void before() throws Exception {
+     *     listAppender = context.getListAppender("List");
+     * }
+     *
+     * &#64;Test
+     * public void testSomething() throws Exception {
+     *     listAppender.countDownLatch = new CountDownLatch(1);
+     *
+     *     Logger logger = LogManager.getLogger();
+     *     logger.info("log one event asynchronously");
+     *
+     *     // wait for the appender to finish processing this event (wait max 
1 second)
+     *     listAppender.countDownLatch.await(1, TimeUnit.SECONDS);
+     *
+     *     // now assert something or do follow-up tests...
+     * }
+     * </pre>
+     */
+    public volatile CountDownLatch countDownLatch = null;
+
+    public ListAppender(final String name) {
+        super(name, null, null, true, Property.EMPTY_ARRAY);
+        newLine = false;
+        raw = false;
+    }
+
+    public ListAppender(final String name, final Filter filter, final Layout<? 
extends Serializable> layout,
+            final boolean newline, final boolean raw) {
+        super(name, filter, layout, true, Property.EMPTY_ARRAY);
+        this.newLine = newline;
+        this.raw = raw;
+        if (layout != null) {
+            final byte[] bytes = layout.getHeader();
+            if (bytes != null) {
+                write(bytes);
+            }
+        }
+    }
+
+    @Override
+    public void append(final LogEvent event) {
+        final Layout<? extends Serializable> layout = getLayout();
+        if (layout == null) {
+            if (event instanceof MutableLogEvent) {
+                // must take snapshot or subsequent calls to logger.log() will 
modify this event
+                events.add(((MutableLogEvent) event).createMemento());
+            } else {
+                events.add(event);
+            }
+        } else {
+            write(layout.toByteArray(event));
+        }
+        if (countDownLatch != null) {
+            countDownLatch.countDown();
+        }
+    }
+
+    void write(final byte[] bytes) {
+        if (raw) {
+            data.add(bytes);
+            return;
+        }
+        final String str = new String(bytes);
+        if (newLine) {
+            int index = 0;
+            while (index < str.length()) {
+                int end;
+                final int wend = str.indexOf(WINDOWS_LINE_SEP, index);
+                final int lend = str.indexOf('\n', index);
+                int length;
+                if (wend >= 0 && wend < lend) {
+                    end = wend;
+                    length = 2;
+                } else {
+                    end = lend;
+                    length = 1;
+                }
+                if (index == end) {
+                    if (!messages.get(messages.size() - length).isEmpty()) {
+                        messages.add("");
+                    }
+                } else if (end >= 0) {
+                    messages.add(str.substring(index, end));
+                } else {
+                    messages.add(str.substring(index));
+                    break;
+                }
+                index = end + length;
+            }
+        } else {
+            messages.add(str);
+        }
+    }
+
+    @Override
+    public boolean stop(final long timeout, final TimeUnit timeUnit) {
+        setStopping();
+        super.stop(timeout, timeUnit, false);
+        final Layout<? extends Serializable> layout = getLayout();
+        if (layout != null) {
+            final byte[] bytes = layout.getFooter();
+            if (bytes != null) {
+                write(bytes);
+            }
+        }
+        setStopped();
+        return true;
+    }
+
+    public ListAppender clear() {
+        events.clear();
+        messages.clear();
+        data.clear();
+        return this;
+    }
+
+    /** Returns an immutable snapshot of captured log events */
+    public List<LogEvent> getEvents() {
+        return Collections.unmodifiableList(new ArrayList<>(events));
+    }
+
+    /** Returns an immutable snapshot of captured messages */
+    public List<String> getMessages() {
+        return List.copyOf(messages);
+    }
+
+    /**
+     * Polls the messages list for it to grow to a given minimum size at most 
timeout timeUnits and return a copy of
+     * what we have so far.
+     */
+    public List<String> getMessages(final int minSize, final long timeout, 
final TimeUnit timeUnit)
+            throws InterruptedException {
+        final long endMillis = System.currentTimeMillis() + 
timeUnit.toMillis(timeout);
+        while (messages.size() < minSize && System.currentTimeMillis() < 
endMillis) {
+            Thread.sleep(100);
+        }
+        return getMessages();
+    }
+
+    /** Returns an immutable snapshot of captured data */
+    public List<byte[]> getData() {
+        return List.copyOf(data);
+    }
+
+    public static ListAppender createAppender(final String name, final boolean 
newLine, final boolean raw,
+            final Layout<? extends Serializable> layout, final Filter filter) {
+        return new ListAppender(name, filter, layout, newLine, raw);
+    }
+
+    @PluginFactory
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    public static class Builder implements 
org.apache.logging.log4j.plugins.util.Builder<ListAppender> {
+
+        private String name;
+        private boolean entryPerNewLine;
+        private boolean raw;
+        private Layout<? extends Serializable> layout;
+        private Filter filter;
+
+        public Builder setName(@Required @PluginAttribute final String name) {
+            this.name = name;
+            return this;
+        }
+
+        public Builder setEntryPerNewLine(@PluginAttribute final boolean 
entryPerNewLine) {
+            this.entryPerNewLine = entryPerNewLine;
+            return this;
+        }
+
+        public Builder setRaw(@PluginAttribute final boolean raw) {
+            this.raw = raw;
+            return this;
+        }
+
+        public Builder setLayout(@PluginElement final Layout<? extends 
Serializable> layout) {
+            this.layout = layout;
+            return this;
+        }
+
+        public Builder setFilter(@PluginElement final Filter filter) {
+            this.filter = filter;
+            return this;
+        }
+
+        @Override
+        public ListAppender build() {
+            return new ListAppender(name, filter, layout, entryPerNewLine, 
raw);
+        }
+    }
+
+    /**
+     * Gets the named ListAppender if it has been registered.
+     *
+     * @param name
+     *            the name of the ListAppender
+     * @return the named ListAppender or {@code null} if it does not exist
+     * @see LoggerContextRule#getListAppender(String)
+     */
+    public static ListAppender getListAppender(final String name) {
+        return 
(LoggerContext.getContext(false)).getConfiguration().getAppender(name);
+    }
+
+    @Override
+    public String toString() {
+        return "ListAppender [events=" + events + ", messages=" + messages + 
", data=" + data + ", newLine=" + newLine
+                + ", raw=" + raw + ", countDownLatch=" + countDownLatch + ", 
getHandler()=" + getHandler()
+                + ", getLayout()=" + getLayout() + ", getName()=" + getName() 
+ ", ignoreExceptions()="
+                + ignoreExceptions() + ", getFilter()=" + getFilter() + ", 
getState()=" + getState() + "]";
+    }
+}
diff --git 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/Log4jBridgeHandlerTest.java
 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/Log4jBridgeHandlerTest.java
similarity index 97%
rename from 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/Log4jBridgeHandlerTest.java
rename to 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/Log4jBridgeHandlerTest.java
index 93093f868a..18b06263b0 100644
--- 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/Log4jBridgeHandlerTest.java
+++ 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/Log4jBridgeHandlerTest.java
@@ -1,459 +1,459 @@
-/*
- * 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.jul;
-
-//note: NO import of Logger, Level, LogManager to prevent conflicts JUL/log4j
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.Map.Entry;
-
-import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.ConfigurationListener;
-import org.apache.logging.log4j.core.config.Configurator;
-import org.apache.logging.log4j.core.config.LoggerConfig;
-import org.apache.logging.log4j.core.config.Reconfigurable;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.FixMethodOrder;
-import org.junit.Test;
-
-
-/**
- * Test the Log4jBridgeHandler.
- * Requires some configurations in the log-config-files, for format/layout
- * see also jul() and log4j():
- * - JUL-config ("logging-test.properties", must be set on JVM-start via 
"-D..."):
- *   + handlers = org.apache.logging.log4j.jul.Log4jBridgeHandler, 
java.util.logging.ConsoleHandler
- *   + org.apache.logging.log4j.jul.Log4jBridgeHandler.appendSuffix = _JUL
- *   + java.util.logging.ConsoleHandler.level = ALL
- *   + java.util.logging.SimpleFormatter.format = JUL:  %1$tT.%1$tL %4$s 
[%3$s: %2$s]  -  %5$s%6$s%n
- *   + .level = FINER
- * - log4j2-config ("log4j2-test.xml"):
- *   + <Root level="TRACE">
- *   + <Appenders> <Console> with target="SYSTEM_ERR", follow="true",
- *      <PatternLayout> "log4j2:  %d{HH:mm:ss.SSS} %5level - 
[%thread][%logger: %class/%method/%line]  -  %message%n"
- *
- * This test needs to capture syserr because it uses 
java.util.logging.ConsoleHandler.
- * Also, it performs some outputs to console (sysout and syserr); see also 
field OUTPUT_CAPTURED.
- *
- * The code also contains evaluation/test code for development time. It is not 
used for the unit tests
- * but kept here for reference and info. See field DEVTEST.
- */
-@FixMethodOrder(org.junit.runners.MethodSorters.NAME_ASCENDING)    // is nicer 
for manually checking console output
-public class Log4jBridgeHandlerTest {
-    /** Perform developer tests? */
-    private static final boolean DEVTEST = false;
-
-    /** Do output the captured logger-output to stdout? */
-    private static final boolean OUTPUT_CAPTURED = !DEVTEST  &&  
Boolean.parseBoolean(
-            System.getProperty("log4j.Log4jBridgeHandlerTest.outputCaptured"));
-
-    /** This classes' simple name = relevant part of logger name. */
-    private static final String CSNAME = 
Log4jBridgeHandlerTest.class.getSimpleName();
-    // loggers used in many tests
-    private static final java.util.logging.Logger julLog = 
java.util.logging.Logger.getLogger(Log4jBridgeHandlerTest.class.getName());
-    private static final org.apache.logging.log4j.Logger log4jLog = 
org.apache.logging.log4j.LogManager.getLogger();
-
-    // capture sysout/syserr
-    //@Rule  public final SystemErrRule systemOutRule = new 
SystemErrRule().enableLog();
-    private static final ByteArrayOutputStream sysoutBytes = new 
ByteArrayOutputStream(1024);
-    private static PrintStream prevSysErrStream;
-
-
-    @BeforeClass
-    public static void beforeClass() {
-        // debug output to easily recognize misconfig.:
-        //System.out.println("sys-props:\n" + System.getProperties());
-        System.out.println("sysout:  logging-cfg-file:  " + 
System.getProperty("java.util.logging.config.file"));
-        if (DEVTEST)  devTestBeforeClass();    // call before stderr capturing
-
-        // JUL does not like setting stderr inbetween, so set it once and 
reset collecting stream
-        // for each method; (thus 
com.github.stefanbirkner:system-rules:SystemErrRule cannot be used)
-        System.err.println("vvv--- BEGIN capturing output to stderr ---vvv"
-                + "   (do output of captured text to orig. stderr: " + 
OUTPUT_CAPTURED + ")");
-        prevSysErrStream = System.err;
-        System.setErr(new PrintStream(sysoutBytes, true));
-    }
-
-    @AfterClass
-    public static void afterClass() {
-        // reset sysout/err to original value
-        System.setErr(prevSysErrStream);
-        System.err.println("^^^--- END capturing output of stderr ---^^^");
-    }
-
-
-    @Before
-    public void beforeTest() {
-        // reset sysout collector
-        sysoutBytes.reset();
-    }
-
-
-
-    /** Assert that captured sysout matches given regexp (any text may follow 
afterwards). */
-    private void assertSysoutMatches(String regex) {
-        //String logOutput = systemOutRule.getLogWithNormalizedLineSeparator();
-        String logOutput = sysoutBytes.toString();
-        if (OUTPUT_CAPTURED)  prevSysErrStream.print(logOutput);
-        logOutput = logOutput.replace("\r\n", "\n");
-        regex = regex + "(.|\\n)*";        // allow any text with NL afterwards
-        assertTrue("Unmatching output:\n" + logOutput + "\n-- vs: --\n" + 
regex + "\n----", logOutput.matches(regex));
-    }
-
-    /** Get regex for a JUL console output. Must match JUL-Console-Formatter! 
*/
-    private String jul(java.util.logging.Level lvl, String locationPartRE,
-            String msgPartRE, String exceptionClassAndMsgRE) {
-        return "JUL:.*" + lvl.getLocalizedName() + ".*" + CSNAME
-                + ".*" + locationPartRE + ".*" + msgPartRE + ".*\n"    // use 
real \n at end here for better error output
-                + (exceptionClassAndMsgRE == null  ?  ""
-                        :  ".*" + exceptionClassAndMsgRE + ".*\\n(\tat 
.*\\n)*\\n?");
-    }
-
-    /** Get regex for a log4j console output. Must match 
log4j2-Console-Layout! */
-    private String log4j(org.apache.logging.log4j.Level lvl, boolean 
julBridged,
-            String methodPartRE, String msgPartRE, String 
exceptionClassAndMsgRE) {
-        return "log4j2:.*" + lvl.name() + ".*" + CSNAME + (julBridged ? 
"\\._JUL" : "")
-                + ".*" + CSNAME + "/\\w*" + methodPartRE + "\\w*/.*"
-                + msgPartRE + ".*\n"        // use real \n at end here for 
better error output
-                + (exceptionClassAndMsgRE == null  ?  ""
-                    :  ".*" + exceptionClassAndMsgRE + ".*\\n(\tat 
.*\\n)*\\n?");
-    }
-
-
-
-    @Test
-    public void test1SimpleLoggings1Jul() {
-        julLog.info("Test-'Info'-Log with JUL");
-        julLog.fine("Test-'Fine'-Log with JUL");
-        julLog.finest("Test-'Finest'-Log with JUL");    // should not be 
logged because JUL-level is FINER
-        julLog.warning("Test-'Warn'-Log with JUL");    // thus add another log 
afterwards to allow checking
-        String methodRE = "SimpleLoggings1Jul";
-        assertSysoutMatches(
-                log4j(org.apache.logging.log4j.Level.INFO, true, methodRE, 
"'Info'-Log with JUL", null)
-                + jul(java.util.logging.Level.INFO, methodRE, "'Info'-Log with 
JUL", null)
-                + log4j(org.apache.logging.log4j.Level.DEBUG, true, methodRE, 
"'Fine'-Log with JUL", null)
-                + jul(java.util.logging.Level.FINE, methodRE, "'Fine'-Log with 
JUL", null)
-                // no finest/trace
-                + log4j(org.apache.logging.log4j.Level.WARN, true, methodRE, 
"'Warn'-Log with JUL", null)
-                + jul(java.util.logging.Level.WARNING, methodRE, "'Warn'-Log 
with JUL", null)
-                );
-    }
-
-    @Test
-    public void test1SimpleLoggings2Log4jDirect() {
-        log4jLog.info("Test-'Info'-Log with log4j2");
-        log4jLog.debug("Test-'Debug'-Log with log4j2");
-        log4jLog.trace("Test-'Trace'-Log with log4j2");
-        String methodRE = "SimpleLoggings2Log4jDirect";
-        assertSysoutMatches(
-                log4j(org.apache.logging.log4j.Level.INFO, false, methodRE, 
"'Info'-Log with log4j2", null)
-                + log4j(org.apache.logging.log4j.Level.DEBUG, false, methodRE, 
"'Debug'-Log with log4j2", null)
-                + log4j(org.apache.logging.log4j.Level.TRACE, false, methodRE, 
"'Trace'-Log with log4j2", null)
-                );
-    }
-
-
-    @Test
-    public void test2SubMethod() {
-        subMethodWithLogs();        // location info is sub method now
-        String methodRE = "subMethodWithLogs";
-        assertSysoutMatches(
-                log4j(org.apache.logging.log4j.Level.DEBUG, true, methodRE, 
"'Fine'-Log with JUL in subMethod", null)
-                + jul(java.util.logging.Level.FINE, methodRE, "'Fine'-Log with 
JUL in subMethod", null)
-                + log4j(org.apache.logging.log4j.Level.INFO, false, methodRE, 
"'Info'-Log with log4j2 in subMethod", null)
-                );
-    }
-    private void subMethodWithLogs() {
-        julLog.fine("Test-'Fine'-Log with JUL in subMethod");
-        log4jLog.info("Test-'Info'-Log with log4j2 in subMethod");
-    }
-
-
-    @Test
-    public void test3JulFlow1() {
-        // note: manually given source information get lost in log4j!
-        julLog.entering("enteringExampleClassParam", 
"enteringExampleMethodParam");
-        String methodRE = "JulFlow";
-        assertSysoutMatches(
-                log4j(org.apache.logging.log4j.Level.TRACE, true, methodRE, 
"ENTRY", null)
-                + jul(java.util.logging.Level.FINER, 
"enteringExampleClassParam enteringExampleMethodParam", "ENTRY", null)
-                );
-    }
-
-    @Test
-    public void test3JulFlow2() {
-        // note: manually given source information get lost in log4j!
-        julLog.entering("enteringExampleClassParam", 
"enteringExampleMethodParam_withParams",
-                new Object[] {"with some", "parameters", 42} );
-        String methodRE = "JulFlow";
-        assertSysoutMatches(
-                log4j(org.apache.logging.log4j.Level.TRACE, true, methodRE,
-                        "ENTRY.*with some.*param.*42", null)
-                + jul(java.util.logging.Level.FINER, 
"enteringExampleClassParam enteringExampleMethodParam_withParams",
-                        "ENTRY.*with some.*param.*42", null)
-                );
-    }
-
-    @Test
-    public void test3JulFlow3() {
-        // note: manually given source information get lost in log4j!
-        julLog.exiting("exitingExampleClassParam", "exitingExampleMethodParam",
-                Arrays.asList("array of Strings", "that are the exit", 
"result"));
-        String methodRE = "JulFlow";
-        assertSysoutMatches(
-                log4j(org.apache.logging.log4j.Level.TRACE, true, methodRE,
-                        "RETURN.*array of Str.*that are.*result", null)
-                + jul(java.util.logging.Level.FINER, "exitingExampleClassParam 
exitingExampleMethodParam",
-                        "RETURN.*array of Str.*that are.*result", null)
-                );
-    }
-
-    @Test
-    public void test3JulFlow4() {
-        // note: manually given source information get lost in log4j!
-        julLog.throwing("throwingExampleClassParam", 
"throwingExampleMethodParam",
-                new IllegalStateException("ONLY TEST for JUL-throwing()"));
-        String methodRE = "JulFlow";
-        assertSysoutMatches(
-                log4j(org.apache.logging.log4j.Level.TRACE, true, methodRE,
-                        "THROW",  "IllegalStateException.*ONLY TEST for 
JUL-throwing")
-                + jul(java.util.logging.Level.FINER, 
"throwingExampleClassParam throwingExampleMethodParam",
-                        "THROW",  "IllegalStateException.*ONLY TEST for 
JUL-throwing")
-                );
-    }
-
-
-
-    @Test
-    public void test4JulSpecials1() {
-        julLog.log(java.util.logging.Level.WARNING, "JUL-Test via log() as 
warning with exception",
-                new java.util.zip.DataFormatException("ONLY TEST for 
JUL.log()"));
-        String methodRE = "JulSpecials";
-        assertSysoutMatches(
-                log4j(org.apache.logging.log4j.Level.WARN, true, methodRE,
-                        "JUL-Test via log\\(\\) as warning",  
"DataFormatException.*ONLY TEST for JUL")
-                + jul(java.util.logging.Level.WARNING, methodRE, "JUL-Test via 
log\\(\\) as warning",
-                        "DataFormatException.*ONLY TEST for JUL")
-                );
-    }
-
-    @Test
-    public void test4JulSpecials2() {
-        // test with MessageFormat
-        julLog.log(java.util.logging.Level.INFO, "JUL-Test via log() with 
parameters (0={0}, 1={1}, 2={2,number,##000.0})",
-                new Object[] {"a", "b", 42} );
-        String methodRE = "JulSpecials";
-        assertSysoutMatches(
-                log4j(org.apache.logging.log4j.Level.INFO, true, methodRE,
-                        "JUL-Test via log\\(\\) with parameters \\(0=a, 1=b, 
2=042.0\\)", null)
-                + jul(java.util.logging.Level.INFO, methodRE,
-                        "JUL-Test via log\\(\\) with parameters \\(0=a, 1=b, 
2=042.0\\)", null)
-                );
-    }
-
-    // no test for logrb(ResourceBundle)-case as this is very specific and 
seldom used (in
-    // my opinion); and it does not add any real thing to test here
-
-
-    private void assertLogLevel(String loggerName, java.util.logging.Level 
julLevel) {
-        java.util.logging.Logger lg = 
java.util.logging.LogManager.getLogManager().getLogger(loggerName);
-        assertEquals("Logger '" + loggerName + "'", julLevel, (lg == null  ?  
null  :  lg.getLevel()));
-    }
-
-    @Test
-    public void test5LevelPropFromConfigFile() {
-        // JUL levels are set from config files and the initial propagation
-        assertLogLevel("", java.util.logging.Level.FINE);
-        assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate1", 
java.util.logging.Level.FINE);
-        assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate1.nested1", 
java.util.logging.Level.FINER);
-        
assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate1.nested2.deeplyNested", 
java.util.logging.Level.WARNING);
-        assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate2", 
java.util.logging.Level.ALL);
-        
assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate2.nested.deeplyNested", 
java.util.logging.Level.INFO);
-        // these are set in logging.properties but not in log4j2.xml:
-        assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate2.nested", null);
-        assertLogLevel("javax.mail", null);
-        // these should not exist:
-        assertLogLevel("log4j.Log4jBridgeHandlerTest", null);
-        assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate1.nested", null);
-        
assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate1.nested1.deeplyNested", 
null);
-    }
-
-
-    @Test
-    public void test5LevelPropSetLevel() {
-        String name = "log4j.test.new_logger_level_set";
-        Configurator.setLevel(name, org.apache.logging.log4j.Level.DEBUG);
-        assertLogLevel(name, java.util.logging.Level.FINE);
-        test5LevelPropFromConfigFile();    // the rest should be untouched!
-
-        name = "log4j.Log4jBridgeHandlerTest.propagate1.nested1";
-        Configurator.setLevel(name, org.apache.logging.log4j.Level.WARN);
-        assertLogLevel(name, java.util.logging.Level.WARNING);
-        // the others around should be untouched
-        assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate1", 
java.util.logging.Level.FINE);
-        
assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate1.nested2.deeplyNested", 
java.util.logging.Level.WARNING);
-
-        // note: no need to check for the other set[Root]Level() methods, 
because they all call
-        // loggerContext.updateLoggers() which calls firePropertyChangeEvent()
-    }
-
-
-    @Test
-    public void test5LevelPropGC() {
-        // this test will fail if you comment out "julLoggerRefs.add(julLog);" 
in propagateLogLevels()
-        test5LevelPropFromConfigFile();    // at start, all should be fine
-        java.util.logging.Logger julLogRef = java.util.logging.Logger
-                .getLogger("log4j.Log4jBridgeHandlerTest.propagate1.nested1");
-        System.gc();    // a single call is sufficient
-        System.out.println("sysout:  test5LevelPropGC() still has reference to 
JUL-logger: "
-                + julLogRef.getName() + " / " + julLogRef);
-        try {
-            test5LevelPropFromConfigFile();    // even after GC the not 
referenced loggers should still be there
-        } catch (Throwable t) {
-            debugPrintJulLoggers("After GC");
-            // => JUL root logger, above explicitly referenced logger and its 
parent ("...propagate1")
-            //    and the global referenced julLog 
("...jul.Log4jBridgeHandlerTest") are still there, the
-            //    others are null-references now
-            throw t;
-        }
-    }
-
-
-    /** Print all available JUL loggers to stdout. */
-    private static void debugPrintJulLoggers(String infoStr) {
-        java.util.logging.LogManager julMgr = 
java.util.logging.LogManager.getLogManager();
-        System.out.println("sysout:  " + infoStr + " - for " + julMgr);
-        java.util.List<String> txt = new java.util.ArrayList<>();
-        int n = 1;
-        for (Enumeration<String> en = julMgr.getLoggerNames();  
en.hasMoreElements(); ) {
-            String ln = en.nextElement();
-            java.util.logging.Logger lg = julMgr.getLogger(ln);
-            if (lg == null) {
-                txt.add("(!null-Logger '" + ln + "')  #" + n);
-            } else if (lg.getLevel() == null) {
-                txt.add("(null-Level Logger '" + ln + "')  #" + n);
-            } else {
-                txt.add("Logger '" + ln + "',  lvl = " + lg.getLevel() + "  #" 
+ n);
-            }
-            n++;
-        } // for
-        java.util.Collections.sort(txt, String.CASE_INSENSITIVE_ORDER);
-        for (String s : txt) {
-            System.out.println("  - " + s);
-        }
-    }
-
-
-
-
-////////////////
-////////////////   INTERNAL DEVELOPER TESTS follow
-////////////////   (these are NOT neccessary for unit test but source is kept 
here for reference and info)
-
-
-    static {
-        if (DEVTEST) {
-            System.out.println("sysout:  static init. BEGIN");
-
-            // get log4j context impl. (requires log4j-core!)
-            // note:  "LogManager.getContext();"  does not work, it returns 
another instance!?!
-            LoggerContext context = LoggerContext.getContext(false);    // 
this matches Configurator.setLevel() impl.
-            Configuration cfg = context.getConfiguration();
-            // print real loggers (=> is empty when using 
LogManager.getContext()!?! only contains already instantiated loggers)
-            System.out.println("LogCtx " + context + " '" + context.getName() 
+ "',  loc = "
-                    + context.getConfigLocation() + ",  cfg = " + cfg + " = " 
+ System.identityHashCode(cfg));
-            for (org.apache.logging.log4j.Logger lg : context.getLoggers()) {
-                System.out.println("- Logger '" + lg.getName() + "',  lvl = " 
+ lg.getLevel());
-            }
-            // print logger configurations (=> all loggers with level are 
present here)
-            System.out.println("Loggers in Cfg:");
-            for (Entry<String, LoggerConfig> entry : 
cfg.getLoggers().entrySet()) {
-                LoggerConfig lcfg = entry.getValue();
-                System.out.println("- '" + entry.getKey() + "' = '" + 
lcfg.getName() + "' / "
-                        + lcfg.getLevel() + "; " + lcfg);
-            }
-
-            // print JUL loggers (=> is completely init. here, even if first 
JUL log and BridgeHandler-creation happens later)
-            debugPrintJulLoggers("in static-class-init");
-            /* java.util.logging.LogManager julMgr = 
java.util.logging.LogManager.getLogManager();
-            System.out.println("\nJUL-Loggers for " + julMgr);
-            for (Enumeration<String> en = julMgr.getLoggerNames();  
en.hasMoreElements(); ) {
-                String ln = en.nextElement();
-                java.util.logging.Logger lg = julMgr.getLogger(ln);
-                if (lg.getLevel() == null) {
-                    System.out.println("-    (null-Level Logger '" + ln + 
"')");
-                } else {
-                    System.out.println("- Logger '" + ln + "',  lvl = " + 
lg.getLevel());
-                }
-            } */
-
-            // changing of log4j config. is to be done via 
log4j.core.config.Configurator,
-            // e.g. setLevel(loggerName, newLevel)
-            // Note: the (internal) log4j.core.Logger has a setLevel() but 
this should not be used.
-            CfgListener listener = new CfgListener();
-            cfg.addListener(listener);    // => onChange() is never called: 
not on start, not on setLevel
-            context.addPropertyChangeListener(listener);
-
-            System.out.println("sysout:  static init. END");
-        } // if
-    }
-
-
-    private static void devTestBeforeClass() {
-        log4jLog.info("Dummy-Start-Log in beforeClass()");    // force init. 
of log4j (needed?? does not harm)
-        @SuppressWarnings("resource")
-        LoggerContext context = LoggerContext.getContext(false);    // this 
matches Configurator.setLevel() impl. (instead of "LogManager.getContext();")
-        System.out.println("beforeClass():  LogCtx " + context + " '" + 
context.getName() + "',  loc = " + context.getConfigLocation()
-                + ",  cfg = " + context.getConfiguration());
-        for (org.apache.logging.log4j.Logger lg : context.getLoggers()) {
-            System.out.println("- Logger '" + lg.getName() + "',  lvl = " + 
lg.getLevel());
-        }
-
-        // force level change
-        System.out.println("sysout:  now calling log4j-setLevel()");
-        Configurator.setLevel("log4jTest.Dummy_set_in_devTestBeforeClass", 
org.apache.logging.log4j.Level.DEBUG);
-    }
-
-
-    private static class CfgListener implements ConfigurationListener, 
PropertyChangeListener {
-        public CfgListener() {
-            System.out.println("sysout:  CfgListener created: " + this);
-        }
-
-        @Override
-        public void onChange(Reconfigurable reconfigurable) {    // from 
ConfigurationListener
-            System.out.println("sysout:  CfgListener.CfgLi-onChange(): " + 
reconfigurable
-                    + " = " + System.identityHashCode(reconfigurable));
-        }
-
-        @Override
-        public void propertyChange(PropertyChangeEvent evt) {    // from 
PropertyChangeListener
-            System.out.println("sysout:  
CfgListener.PropChLi-propertyChange(): " + evt);
-        }
-    }
-
-}
+/*
+ * 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.jul.test;
+
+//note: NO import of Logger, Level, LogManager to prevent conflicts JUL/log4j
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Map.Entry;
+
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationListener;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.core.config.Reconfigurable;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+
+
+/**
+ * Test the Log4jBridgeHandler.
+ * Requires some configurations in the log-config-files, for format/layout
+ * see also jul() and log4j():
+ * - JUL-config ("logging-test.properties", must be set on JVM-start via 
"-D..."):
+ *   + handlers = org.apache.logging.log4j.jul.Log4jBridgeHandler, 
java.util.logging.ConsoleHandler
+ *   + org.apache.logging.log4j.jul.Log4jBridgeHandler.appendSuffix = _JUL
+ *   + java.util.logging.ConsoleHandler.level = ALL
+ *   + java.util.logging.SimpleFormatter.format = JUL:  %1$tT.%1$tL %4$s 
[%3$s: %2$s]  -  %5$s%6$s%n
+ *   + .level = FINER
+ * - log4j2-config ("log4j2-test.xml"):
+ *   + <Root level="TRACE">
+ *   + <Appenders> <Console> with target="SYSTEM_ERR", follow="true",
+ *      <PatternLayout> "log4j2:  %d{HH:mm:ss.SSS} %5level - 
[%thread][%logger: %class/%method/%line]  -  %message%n"
+ *
+ * This test needs to capture syserr because it uses 
java.util.logging.ConsoleHandler.
+ * Also, it performs some outputs to console (sysout and syserr); see also 
field OUTPUT_CAPTURED.
+ *
+ * The code also contains evaluation/test code for development time. It is not 
used for the unit tests
+ * but kept here for reference and info. See field DEVTEST.
+ */
+@FixMethodOrder(org.junit.runners.MethodSorters.NAME_ASCENDING)    // is nicer 
for manually checking console output
+public class Log4jBridgeHandlerTest {
+    /** Perform developer tests? */
+    private static final boolean DEVTEST = false;
+
+    /** Do output the captured logger-output to stdout? */
+    private static final boolean OUTPUT_CAPTURED = !DEVTEST  &&  
Boolean.parseBoolean(
+            System.getProperty("log4j.Log4jBridgeHandlerTest.outputCaptured"));
+
+    /** This classes' simple name = relevant part of logger name. */
+    private static final String CSNAME = 
Log4jBridgeHandlerTest.class.getSimpleName();
+    // loggers used in many tests
+    private static final java.util.logging.Logger julLog = 
java.util.logging.Logger.getLogger(Log4jBridgeHandlerTest.class.getName());
+    private static final org.apache.logging.log4j.Logger log4jLog = 
org.apache.logging.log4j.LogManager.getLogger();
+
+    // capture sysout/syserr
+    //@Rule  public final SystemErrRule systemOutRule = new 
SystemErrRule().enableLog();
+    private static final ByteArrayOutputStream sysoutBytes = new 
ByteArrayOutputStream(1024);
+    private static PrintStream prevSysErrStream;
+
+
+    @BeforeClass
+    public static void beforeClass() {
+        // debug output to easily recognize misconfig.:
+        //System.out.println("sys-props:\n" + System.getProperties());
+        System.out.println("sysout:  logging-cfg-file:  " + 
System.getProperty("java.util.logging.config.file"));
+        if (DEVTEST)  devTestBeforeClass();    // call before stderr capturing
+
+        // JUL does not like setting stderr inbetween, so set it once and 
reset collecting stream
+        // for each method; (thus 
com.github.stefanbirkner:system-rules:SystemErrRule cannot be used)
+        System.err.println("vvv--- BEGIN capturing output to stderr ---vvv"
+                + "   (do output of captured text to orig. stderr: " + 
OUTPUT_CAPTURED + ")");
+        prevSysErrStream = System.err;
+        System.setErr(new PrintStream(sysoutBytes, true));
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        // reset sysout/err to original value
+        System.setErr(prevSysErrStream);
+        System.err.println("^^^--- END capturing output of stderr ---^^^");
+    }
+
+
+    @Before
+    public void beforeTest() {
+        // reset sysout collector
+        sysoutBytes.reset();
+    }
+
+
+
+    /** Assert that captured sysout matches given regexp (any text may follow 
afterwards). */
+    private void assertSysoutMatches(String regex) {
+        //String logOutput = systemOutRule.getLogWithNormalizedLineSeparator();
+        String logOutput = sysoutBytes.toString();
+        if (OUTPUT_CAPTURED)  prevSysErrStream.print(logOutput);
+        logOutput = logOutput.replace("\r\n", "\n");
+        regex = regex + "(.|\\n)*";        // allow any text with NL afterwards
+        assertTrue("Unmatching output:\n" + logOutput + "\n-- vs: --\n" + 
regex + "\n----", logOutput.matches(regex));
+    }
+
+    /** Get regex for a JUL console output. Must match JUL-Console-Formatter! 
*/
+    private String jul(java.util.logging.Level lvl, String locationPartRE,
+            String msgPartRE, String exceptionClassAndMsgRE) {
+        return "JUL:.*" + lvl.getLocalizedName() + ".*" + CSNAME
+                + ".*" + locationPartRE + ".*" + msgPartRE + ".*\n"    // use 
real \n at end here for better error output
+                + (exceptionClassAndMsgRE == null  ?  ""
+                        :  ".*" + exceptionClassAndMsgRE + ".*\\n(\tat 
.*\\n)*\\n?");
+    }
+
+    /** Get regex for a log4j console output. Must match 
log4j2-Console-Layout! */
+    private String log4j(org.apache.logging.log4j.Level lvl, boolean 
julBridged,
+            String methodPartRE, String msgPartRE, String 
exceptionClassAndMsgRE) {
+        return "log4j2:.*" + lvl.name() + ".*" + CSNAME + (julBridged ? 
"\\._JUL" : "")
+                + ".*" + CSNAME + "/\\w*" + methodPartRE + "\\w*/.*"
+                + msgPartRE + ".*\n"        // use real \n at end here for 
better error output
+                + (exceptionClassAndMsgRE == null  ?  ""
+                    :  ".*" + exceptionClassAndMsgRE + ".*\\n(\tat 
.*\\n)*\\n?");
+    }
+
+
+
+    @Test
+    public void test1SimpleLoggings1Jul() {
+        julLog.info("Test-'Info'-Log with JUL");
+        julLog.fine("Test-'Fine'-Log with JUL");
+        julLog.finest("Test-'Finest'-Log with JUL");    // should not be 
logged because JUL-level is FINER
+        julLog.warning("Test-'Warn'-Log with JUL");    // thus add another log 
afterwards to allow checking
+        String methodRE = "SimpleLoggings1Jul";
+        assertSysoutMatches(
+                log4j(org.apache.logging.log4j.Level.INFO, true, methodRE, 
"'Info'-Log with JUL", null)
+                + jul(java.util.logging.Level.INFO, methodRE, "'Info'-Log with 
JUL", null)
+                + log4j(org.apache.logging.log4j.Level.DEBUG, true, methodRE, 
"'Fine'-Log with JUL", null)
+                + jul(java.util.logging.Level.FINE, methodRE, "'Fine'-Log with 
JUL", null)
+                // no finest/trace
+                + log4j(org.apache.logging.log4j.Level.WARN, true, methodRE, 
"'Warn'-Log with JUL", null)
+                + jul(java.util.logging.Level.WARNING, methodRE, "'Warn'-Log 
with JUL", null)
+                );
+    }
+
+    @Test
+    public void test1SimpleLoggings2Log4jDirect() {
+        log4jLog.info("Test-'Info'-Log with log4j2");
+        log4jLog.debug("Test-'Debug'-Log with log4j2");
+        log4jLog.trace("Test-'Trace'-Log with log4j2");
+        String methodRE = "SimpleLoggings2Log4jDirect";
+        assertSysoutMatches(
+                log4j(org.apache.logging.log4j.Level.INFO, false, methodRE, 
"'Info'-Log with log4j2", null)
+                + log4j(org.apache.logging.log4j.Level.DEBUG, false, methodRE, 
"'Debug'-Log with log4j2", null)
+                + log4j(org.apache.logging.log4j.Level.TRACE, false, methodRE, 
"'Trace'-Log with log4j2", null)
+                );
+    }
+
+
+    @Test
+    public void test2SubMethod() {
+        subMethodWithLogs();        // location info is sub method now
+        String methodRE = "subMethodWithLogs";
+        assertSysoutMatches(
+                log4j(org.apache.logging.log4j.Level.DEBUG, true, methodRE, 
"'Fine'-Log with JUL in subMethod", null)
+                + jul(java.util.logging.Level.FINE, methodRE, "'Fine'-Log with 
JUL in subMethod", null)
+                + log4j(org.apache.logging.log4j.Level.INFO, false, methodRE, 
"'Info'-Log with log4j2 in subMethod", null)
+                );
+    }
+    private void subMethodWithLogs() {
+        julLog.fine("Test-'Fine'-Log with JUL in subMethod");
+        log4jLog.info("Test-'Info'-Log with log4j2 in subMethod");
+    }
+
+
+    @Test
+    public void test3JulFlow1() {
+        // note: manually given source information get lost in log4j!
+        julLog.entering("enteringExampleClassParam", 
"enteringExampleMethodParam");
+        String methodRE = "JulFlow";
+        assertSysoutMatches(
+                log4j(org.apache.logging.log4j.Level.TRACE, true, methodRE, 
"ENTRY", null)
+                + jul(java.util.logging.Level.FINER, 
"enteringExampleClassParam enteringExampleMethodParam", "ENTRY", null)
+                );
+    }
+
+    @Test
+    public void test3JulFlow2() {
+        // note: manually given source information get lost in log4j!
+        julLog.entering("enteringExampleClassParam", 
"enteringExampleMethodParam_withParams",
+                new Object[] {"with some", "parameters", 42} );
+        String methodRE = "JulFlow";
+        assertSysoutMatches(
+                log4j(org.apache.logging.log4j.Level.TRACE, true, methodRE,
+                        "ENTRY.*with some.*param.*42", null)
+                + jul(java.util.logging.Level.FINER, 
"enteringExampleClassParam enteringExampleMethodParam_withParams",
+                        "ENTRY.*with some.*param.*42", null)
+                );
+    }
+
+    @Test
+    public void test3JulFlow3() {
+        // note: manually given source information get lost in log4j!
+        julLog.exiting("exitingExampleClassParam", "exitingExampleMethodParam",
+                Arrays.asList("array of Strings", "that are the exit", 
"result"));
+        String methodRE = "JulFlow";
+        assertSysoutMatches(
+                log4j(org.apache.logging.log4j.Level.TRACE, true, methodRE,
+                        "RETURN.*array of Str.*that are.*result", null)
+                + jul(java.util.logging.Level.FINER, "exitingExampleClassParam 
exitingExampleMethodParam",
+                        "RETURN.*array of Str.*that are.*result", null)
+                );
+    }
+
+    @Test
+    public void test3JulFlow4() {
+        // note: manually given source information get lost in log4j!
+        julLog.throwing("throwingExampleClassParam", 
"throwingExampleMethodParam",
+                new IllegalStateException("ONLY TEST for JUL-throwing()"));
+        String methodRE = "JulFlow";
+        assertSysoutMatches(
+                log4j(org.apache.logging.log4j.Level.TRACE, true, methodRE,
+                        "THROW",  "IllegalStateException.*ONLY TEST for 
JUL-throwing")
+                + jul(java.util.logging.Level.FINER, 
"throwingExampleClassParam throwingExampleMethodParam",
+                        "THROW",  "IllegalStateException.*ONLY TEST for 
JUL-throwing")
+                );
+    }
+
+
+
+    @Test
+    public void test4JulSpecials1() {
+        julLog.log(java.util.logging.Level.WARNING, "JUL-Test via log() as 
warning with exception",
+                new java.util.zip.DataFormatException("ONLY TEST for 
JUL.log()"));
+        String methodRE = "JulSpecials";
+        assertSysoutMatches(
+                log4j(org.apache.logging.log4j.Level.WARN, true, methodRE,
+                        "JUL-Test via log\\(\\) as warning",  
"DataFormatException.*ONLY TEST for JUL")
+                + jul(java.util.logging.Level.WARNING, methodRE, "JUL-Test via 
log\\(\\) as warning",
+                        "DataFormatException.*ONLY TEST for JUL")
+                );
+    }
+
+    @Test
+    public void test4JulSpecials2() {
+        // test with MessageFormat
+        julLog.log(java.util.logging.Level.INFO, "JUL-Test via log() with 
parameters (0={0}, 1={1}, 2={2,number,##000.0})",
+                new Object[] {"a", "b", 42} );
+        String methodRE = "JulSpecials";
+        assertSysoutMatches(
+                log4j(org.apache.logging.log4j.Level.INFO, true, methodRE,
+                        "JUL-Test via log\\(\\) with parameters \\(0=a, 1=b, 
2=042.0\\)", null)
+                + jul(java.util.logging.Level.INFO, methodRE,
+                        "JUL-Test via log\\(\\) with parameters \\(0=a, 1=b, 
2=042.0\\)", null)
+                );
+    }
+
+    // no test for logrb(ResourceBundle)-case as this is very specific and 
seldom used (in
+    // my opinion); and it does not add any real thing to test here
+
+
+    private void assertLogLevel(String loggerName, java.util.logging.Level 
julLevel) {
+        java.util.logging.Logger lg = 
java.util.logging.LogManager.getLogManager().getLogger(loggerName);
+        assertEquals("Logger '" + loggerName + "'", julLevel, (lg == null  ?  
null  :  lg.getLevel()));
+    }
+
+    @Test
+    public void test5LevelPropFromConfigFile() {
+        // JUL levels are set from config files and the initial propagation
+        assertLogLevel("", java.util.logging.Level.FINE);
+        assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate1", 
java.util.logging.Level.FINE);
+        assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate1.nested1", 
java.util.logging.Level.FINER);
+        
assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate1.nested2.deeplyNested", 
java.util.logging.Level.WARNING);
+        assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate2", 
java.util.logging.Level.ALL);
+        
assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate2.nested.deeplyNested", 
java.util.logging.Level.INFO);
+        // these are set in logging.properties but not in log4j2.xml:
+        assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate2.nested", null);
+        assertLogLevel("javax.mail", null);
+        // these should not exist:
+        assertLogLevel("log4j.Log4jBridgeHandlerTest", null);
+        assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate1.nested", null);
+        
assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate1.nested1.deeplyNested", 
null);
+    }
+
+
+    @Test
+    public void test5LevelPropSetLevel() {
+        String name = "log4j.test.new_logger_level_set";
+        Configurator.setLevel(name, org.apache.logging.log4j.Level.DEBUG);
+        assertLogLevel(name, java.util.logging.Level.FINE);
+        test5LevelPropFromConfigFile();    // the rest should be untouched!
+
+        name = "log4j.Log4jBridgeHandlerTest.propagate1.nested1";
+        Configurator.setLevel(name, org.apache.logging.log4j.Level.WARN);
+        assertLogLevel(name, java.util.logging.Level.WARNING);
+        // the others around should be untouched
+        assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate1", 
java.util.logging.Level.FINE);
+        
assertLogLevel("log4j.Log4jBridgeHandlerTest.propagate1.nested2.deeplyNested", 
java.util.logging.Level.WARNING);
+
+        // note: no need to check for the other set[Root]Level() methods, 
because they all call
+        // loggerContext.updateLoggers() which calls firePropertyChangeEvent()
+    }
+
+
+    @Test
+    public void test5LevelPropGC() {
+        // this test will fail if you comment out "julLoggerRefs.add(julLog);" 
in propagateLogLevels()
+        test5LevelPropFromConfigFile();    // at start, all should be fine
+        java.util.logging.Logger julLogRef = java.util.logging.Logger
+                .getLogger("log4j.Log4jBridgeHandlerTest.propagate1.nested1");
+        System.gc();    // a single call is sufficient
+        System.out.println("sysout:  test5LevelPropGC() still has reference to 
JUL-logger: "
+                + julLogRef.getName() + " / " + julLogRef);
+        try {
+            test5LevelPropFromConfigFile();    // even after GC the not 
referenced loggers should still be there
+        } catch (Throwable t) {
+            debugPrintJulLoggers("After GC");
+            // => JUL root logger, above explicitly referenced logger and its 
parent ("...propagate1")
+            //    and the global referenced julLog 
("...jul.Log4jBridgeHandlerTest") are still there, the
+            //    others are null-references now
+            throw t;
+        }
+    }
+
+
+    /** Print all available JUL loggers to stdout. */
+    private static void debugPrintJulLoggers(String infoStr) {
+        java.util.logging.LogManager julMgr = 
java.util.logging.LogManager.getLogManager();
+        System.out.println("sysout:  " + infoStr + " - for " + julMgr);
+        java.util.List<String> txt = new java.util.ArrayList<>();
+        int n = 1;
+        for (Enumeration<String> en = julMgr.getLoggerNames();  
en.hasMoreElements(); ) {
+            String ln = en.nextElement();
+            java.util.logging.Logger lg = julMgr.getLogger(ln);
+            if (lg == null) {
+                txt.add("(!null-Logger '" + ln + "')  #" + n);
+            } else if (lg.getLevel() == null) {
+                txt.add("(null-Level Logger '" + ln + "')  #" + n);
+            } else {
+                txt.add("Logger '" + ln + "',  lvl = " + lg.getLevel() + "  #" 
+ n);
+            }
+            n++;
+        } // for
+        java.util.Collections.sort(txt, String.CASE_INSENSITIVE_ORDER);
+        for (String s : txt) {
+            System.out.println("  - " + s);
+        }
+    }
+
+
+
+
+////////////////
+////////////////   INTERNAL DEVELOPER TESTS follow
+////////////////   (these are NOT neccessary for unit test but source is kept 
here for reference and info)
+
+
+    static {
+        if (DEVTEST) {
+            System.out.println("sysout:  static init. BEGIN");
+
+            // get log4j context impl. (requires log4j-core!)
+            // note:  "LogManager.getContext();"  does not work, it returns 
another instance!?!
+            LoggerContext context = LoggerContext.getContext(false);    // 
this matches Configurator.setLevel() impl.
+            Configuration cfg = context.getConfiguration();
+            // print real loggers (=> is empty when using 
LogManager.getContext()!?! only contains already instantiated loggers)
+            System.out.println("LogCtx " + context + " '" + context.getName() 
+ "',  loc = "
+                    + context.getConfigLocation() + ",  cfg = " + cfg + " = " 
+ System.identityHashCode(cfg));
+            for (org.apache.logging.log4j.Logger lg : context.getLoggers()) {
+                System.out.println("- Logger '" + lg.getName() + "',  lvl = " 
+ lg.getLevel());
+            }
+            // print logger configurations (=> all loggers with level are 
present here)
+            System.out.println("Loggers in Cfg:");
+            for (Entry<String, LoggerConfig> entry : 
cfg.getLoggers().entrySet()) {
+                LoggerConfig lcfg = entry.getValue();
+                System.out.println("- '" + entry.getKey() + "' = '" + 
lcfg.getName() + "' / "
+                        + lcfg.getLevel() + "; " + lcfg);
+            }
+
+            // print JUL loggers (=> is completely init. here, even if first 
JUL log and BridgeHandler-creation happens later)
+            debugPrintJulLoggers("in static-class-init");
+            /* java.util.logging.LogManager julMgr = 
java.util.logging.LogManager.getLogManager();
+            System.out.println("\nJUL-Loggers for " + julMgr);
+            for (Enumeration<String> en = julMgr.getLoggerNames();  
en.hasMoreElements(); ) {
+                String ln = en.nextElement();
+                java.util.logging.Logger lg = julMgr.getLogger(ln);
+                if (lg.getLevel() == null) {
+                    System.out.println("-    (null-Level Logger '" + ln + 
"')");
+                } else {
+                    System.out.println("- Logger '" + ln + "',  lvl = " + 
lg.getLevel());
+                }
+            } */
+
+            // changing of log4j config. is to be done via 
log4j.core.config.Configurator,
+            // e.g. setLevel(loggerName, newLevel)
+            // Note: the (internal) log4j.core.Logger has a setLevel() but 
this should not be used.
+            CfgListener listener = new CfgListener();
+            cfg.addListener(listener);    // => onChange() is never called: 
not on start, not on setLevel
+            context.addPropertyChangeListener(listener);
+
+            System.out.println("sysout:  static init. END");
+        } // if
+    }
+
+
+    private static void devTestBeforeClass() {
+        log4jLog.info("Dummy-Start-Log in beforeClass()");    // force init. 
of log4j (needed?? does not harm)
+        @SuppressWarnings("resource")
+        LoggerContext context = LoggerContext.getContext(false);    // this 
matches Configurator.setLevel() impl. (instead of "LogManager.getContext();")
+        System.out.println("beforeClass():  LogCtx " + context + " '" + 
context.getName() + "',  loc = " + context.getConfigLocation()
+                + ",  cfg = " + context.getConfiguration());
+        for (org.apache.logging.log4j.Logger lg : context.getLoggers()) {
+            System.out.println("- Logger '" + lg.getName() + "',  lvl = " + 
lg.getLevel());
+        }
+
+        // force level change
+        System.out.println("sysout:  now calling log4j-setLevel()");
+        Configurator.setLevel("log4jTest.Dummy_set_in_devTestBeforeClass", 
org.apache.logging.log4j.Level.DEBUG);
+    }
+
+
+    private static class CfgListener implements ConfigurationListener, 
PropertyChangeListener {
+        public CfgListener() {
+            System.out.println("sysout:  CfgListener created: " + this);
+        }
+
+        @Override
+        public void onChange(Reconfigurable reconfigurable) {    // from 
ConfigurationListener
+            System.out.println("sysout:  CfgListener.CfgLi-onChange(): " + 
reconfigurable
+                    + " = " + System.identityHashCode(reconfigurable));
+        }
+
+        @Override
+        public void propertyChange(PropertyChangeEvent evt) {    // from 
PropertyChangeListener
+            System.out.println("sysout:  
CfgListener.PropChLi-propertyChange(): " + evt);
+        }
+    }
+
+}
diff --git 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/Log4jLevelTranslatorTest.java
 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/Log4jLevelTranslatorTest.java
similarity index 96%
rename from 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/Log4jLevelTranslatorTest.java
rename to 
log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/Log4jLevelTranslatorTest.java
index dd65105642..b0979b48fe 100644
--- 
a/log4j-jul/src/test/java/org/apache/logging/log4j/jul/Log4jLevelTranslatorTest.java
+++ 
b/log4j-jul/src/test/java/org/apache/logging/log4j/jul/test/Log4jLevelTranslatorTest.java
@@ -15,7 +15,7 @@
  * limitations under the license.
  */
 
-package org.apache.logging.log4j.jul;
+package org.apache.logging.log4j.jul.test;
 
 import static org.junit.Assert.assertEquals;
 
@@ -23,6 +23,7 @@ import java.util.Arrays;
 import java.util.Collection;
 
 import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.jul.LevelTranslator;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
diff --git a/log4j-jul/src/test/resources/log4j2-calling-class.xml 
b/log4j-jul/src/test/resources/log4j2-calling-class.xml
new file mode 100644
index 0000000000..4432c82806
--- /dev/null
+++ b/log4j-jul/src/test/resources/log4j2-calling-class.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+<Configuration name="CallerInformationTest" status="ERROR">
+  <Appenders>
+    <List name="Class">
+      <PatternLayout pattern="%class"/>
+    </List>
+    <List name="Method">
+      <PatternLayout pattern="%method"/>
+    </List>
+  </Appenders>
+  <Loggers>
+    <Logger name="ClassLogger" level="info">
+      <AppenderRef ref="Class"/>
+    </Logger>
+    <Logger name="MethodLogger" level="info">
+      <AppenderRef ref="Method"/>
+    </Logger>
+    <Root level="off"/>
+  </Loggers>
+</Configuration>
\ No newline at end of file
diff --git a/log4j-jul/src/test/resources/log4j2-julBridge-test.xml 
b/log4j-jul/src/test/resources/log4j2-julBridge-test.xml
index edc0cab0b6..ea769f8617 100644
--- a/log4j-jul/src/test/resources/log4j2-julBridge-test.xml
+++ b/log4j-jul/src/test/resources/log4j2-julBridge-test.xml
@@ -13,7 +13,7 @@
         </Root>
 
         <!-- needs to be set to a lower level: -->
-        <Logger name="org.apache.logging.log4j.jul.Log4jBridgeHandlerTest" 
level="TRACE" />
+        <Logger 
name="org.apache.logging.log4j.jul.test.Log4jBridgeHandlerTest" level="TRACE" />
         <!-- some test configs: -->
         <Logger name="log4j.Log4jBridgeHandlerTest.propagate1" level="DEBUG" />
         <Logger name="log4j.Log4jBridgeHandlerTest.propagate1.nested1" 
level="TRACE" />
diff --git a/pom.xml b/pom.xml
index 62d3d54e9e..fef715f40a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -234,7 +234,7 @@
     <mongodb3.version>3.12.4</mongodb3.version>
     <mongodb4.version>4.0.3</mongodb4.version>
     <groovy.version>4.0.2</groovy.version>
-    <compiler.plugin.version>3.8.1</compiler.plugin.version>
+    <compiler.plugin.version>3.10.1</compiler.plugin.version>
     <pmd.plugin.version>3.13.0</pmd.plugin.version>
     <spotbugs.plugin.version>4.0.4</spotbugs.plugin.version>
     <spotbugs.version>4.1.2</spotbugs.version>

Reply via email to