Add final modifier to method parameters.

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/7a5dcd43
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/7a5dcd43
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/7a5dcd43

Branch: refs/heads/LOG4J-1181
Commit: 7a5dcd43d559971caf3f00c55586f372ca4d9046
Parents: fe22ab8
Author: ggregory <[email protected]>
Authored: Fri Jun 3 10:05:18 2016 -0700
Committer: ggregory <[email protected]>
Committed: Fri Jun 3 10:05:18 2016 -0700

----------------------------------------------------------------------
 .../org/apache/logging/log4j/core/Logger.java   |   2 +-
 .../logging/log4j/core/LoggerContext.java       |   4 +-
 .../log4j/core/appender/AbstractManager.java    |   8 +-
 .../log4j/core/appender/AsyncAppender.java      |   2 +-
 .../log4j/core/appender/ConsoleAppender.java    |   2 +-
 .../core/appender/CountingNoOpAppender.java     |   4 +-
 .../core/appender/OutputStreamManager.java      |   4 +-
 .../log4j/core/appender/SocketAppender.java     |   2 +-
 .../appender/rolling/CronTriggeringPolicy.java  |   6 +-
 .../rolling/DefaultRolloverStrategy.java        |   6 +-
 .../log4j/core/appender/rolling/FileSize.java   | 180 ++---
 .../core/appender/rolling/action/Duration.java  | 514 +++++++-------
 .../core/appender/rolling/action/IfAll.java     | 232 +++----
 .../core/appender/routing/IdlePurgePolicy.java  |   8 +-
 .../core/appender/routing/RoutingAppender.java  |   4 +-
 .../logging/log4j/core/async/AsyncLogger.java   |   4 +-
 .../core/async/AsyncLoggerConfigDisruptor.java  |   2 +-
 .../log4j/core/async/AsyncLoggerContext.java    |   4 +-
 .../log4j/core/async/AsyncLoggerDisruptor.java  | 472 ++++++-------
 .../log4j/core/async/RingBufferLogEvent.java    |  10 +-
 .../core/config/AbstractConfiguration.java      |   8 +-
 .../AwaitCompletionReliabilityStrategy.java     | 350 +++++-----
 ...AwaitUnconditionallyReliabilityStrategy.java | 246 +++----
 .../log4j/core/config/ConfigurationFactory.java |   2 +-
 .../core/config/ConfigurationScheduler.java     |  16 +-
 .../core/config/ConfiguratonFileWatcher.java    |   4 +-
 .../logging/log4j/core/config/Configurator.java | 688 +++++++++----------
 .../core/config/DefaultReliabilityStrategy.java | 214 +++---
 .../core/config/LockingReliabilityStrategy.java | 270 ++++----
 .../impl/DefaultConfigurationBuilder.java       |  20 +-
 .../impl/DefaultLoggerComponentBuilder.java     |   4 +-
 .../impl/DefaultScriptFileComponentBuilder.java |   8 +-
 .../composite/CompositeConfiguration.java       |   6 +-
 .../config/composite/DefaultMergeStrategy.java  |  16 +-
 .../properties/PropertiesConfiguration.java     |   2 +-
 .../PropertiesConfigurationBuilder.java         |   2 +-
 .../log4j/core/config/xml/XmlConfiguration.java |   2 +-
 .../core/filter/DynamicThresholdFilter.java     |   2 +-
 .../logging/log4j/core/impl/Log4jLogEvent.java  |  32 +-
 .../log4j/core/impl/MutableLogEvent.java        |  30 +-
 .../log4j/core/layout/AbstractStringLayout.java |   2 +-
 .../logging/log4j/core/layout/GelfLayout.java   |   4 +-
 .../log4j/core/layout/JacksonFactory.java       |   4 +-
 .../core/layout/MarkerPatternSelector.java      |   2 +-
 .../core/layout/ScriptPatternSelector.java      |   4 +-
 .../log4j/core/layout/TextEncoderHelper.java    |   2 +-
 .../logging/log4j/core/net/SmtpManager.java     |   4 +-
 .../log4j/core/net/TcpSocketManager.java        |   2 +-
 .../pattern/EqualsReplacementConverter.java     |   2 +-
 .../log4j/core/pattern/NameAbbreviator.java     |   4 +-
 .../logging/log4j/core/script/Script.java       |   2 +-
 .../logging/log4j/core/script/ScriptFile.java   |   2 +-
 .../log4j/core/script/ScriptManager.java        |   2 +-
 .../logging/log4j/core/script/ScriptRef.java    |   4 +-
 .../logging/log4j/core/util/CronExpression.java |  48 +-
 .../logging/log4j/core/util/DummyNanoClock.java |  96 +--
 .../core/util/ExtensionLanguageMapping.java     |   6 +-
 .../logging/log4j/core/util/FileUtils.java      |   2 +-
 .../logging/log4j/core/util/JsonUtils.java      |   6 +-
 .../logging/log4j/core/util/StringEncoder.java  |   6 +-
 .../logging/log4j/core/util/WatchManager.java   |  10 +-
 .../core/util/datetime/FixedDateFormat.java     | 686 +++++++++---------
 .../core/GcFreeAsynchronousLoggingTest.java     |   2 +-
 .../log4j/core/GcFreeLoggingTestUtil.java       |   4 +-
 .../core/GcFreeMixedSyncAyncLoggingTest.java    |   2 +-
 .../core/GcFreeSynchronousLoggingTest.java      |   2 +-
 .../AsyncAppenderQueueFullPolicyTest.java       |   2 +-
 .../appender/mom/kafka/KafkaAppenderTest.java   | 292 ++++----
 .../RollingAppenderCustomDeleteActionTest.java  |   2 +-
 ...lingAppenderDeleteAccumulatedCount1Test.java |   4 +-
 ...lingAppenderDeleteAccumulatedCount2Test.java |   4 +-
 .../RollingAppenderDeleteMaxDepthTest.java      |   4 +-
 .../RollingAppenderDeleteNestedTest.java        |   4 +-
 ...ollingAppenderNoUnconditionalDeleteTest.java |   2 +-
 .../rolling/action/CountingCondition.java       | 124 ++--
 .../rolling/action/DeleteActionTest.java        | 238 +++----
 .../rolling/action/DeletingVisitorTest.java     | 270 ++++----
 .../appender/rolling/action/FixedCondition.java |  88 +--
 .../action/PathSortByModificationTimeTest.java  | 186 ++---
 .../routing/RoutingAppenderWithPurgingTest.java |   2 +-
 .../core/async/perftest/PerfTestDriver.java     |   4 +-
 .../core/async/perftest/ResponseTimeTest.java   |  18 +-
 .../core/async/perftest/SimplePerfTest.java     |   2 +-
 .../core/config/CompositeConfigurationTest.java |   2 +-
 .../log4j/core/config/ConfiguratorTest.java     |  94 +--
 .../builder/ConfigurationAssemblerTest.java     |   2 +-
 .../builder/CustomConfigurationFactory.java     |   4 +-
 .../core/filter/AbstractFilterableTest.java     |   4 +-
 .../log4j/core/impl/Log4jLogEventTest.java      |   6 +-
 .../log4j/core/impl/ThrowableProxyTest.java     |   2 +-
 .../core/layout/CsvLogEventLayoutTest.java      |   2 +-
 .../core/layout/CsvParameterLayoutTest.java     |   2 +-
 .../log4j/core/layout/GelfLayoutTest.java       |   2 +-
 .../log4j/core/layout/PatternLayoutTest.java    |   2 +-
 .../log4j/core/layout/PatternSelectorTest.java  | 130 ++--
 .../core/layout/SpyByteBufferDestination.java   |   2 +-
 .../core/pattern/DatePatternConverterTest.java  |   2 +-
 ...qualsIgnoreCaseReplacementConverterTest.java |   2 +-
 .../log4j/core/pattern/PatternParserTest.java   |   2 +-
 ...riablesNotEmptyReplacementConverterTest.java |   2 +-
 .../log4j/core/util/WatchManagerTest.java       |   4 +-
 .../logging/log4j/junit/LoggerContextRule.java  |   4 +-
 .../test/appender/EncodingListAppender.java     |   4 +-
 .../logging/log4j/jul/AbstractLoggerTest.java   |   4 +-
 104 files changed, 2913 insertions(+), 2913 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java
index d08dd8a..99f4207 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/Logger.java
@@ -632,7 +632,7 @@ public class Logger extends AbstractLogger implements 
Supplier<LoggerConfig> {
         private final String name;
         private final MessageFactory messageFactory;
 
-        public LoggerProxy(String name, MessageFactory messageFactory) {
+        public LoggerProxy(final String name, final MessageFactory 
messageFactory) {
             this.name = name;
             this.messageFactory = messageFactory;
         }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
index 82a6de8..fea1975 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
@@ -424,7 +424,7 @@ public class LoggerContext extends AbstractLifeCycle 
implements org.apache.loggi
      * @return True if the Logger exists, false otherwise.
      */
     @Override
-    public boolean hasLogger(final String name, MessageFactory messageFactory) 
{
+    public boolean hasLogger(final String name, final MessageFactory 
messageFactory) {
         return loggerRegistry.hasLogger(name, messageFactory);
     }
 
@@ -435,7 +435,7 @@ public class LoggerContext extends AbstractLifeCycle 
implements org.apache.loggi
      * @return True if the Logger exists, false otherwise.
      */
     @Override
-    public boolean hasLogger(final String name, Class<? extends 
MessageFactory> messageFactoryClass) {
+    public boolean hasLogger(final String name, final Class<? extends 
MessageFactory> messageFactoryClass) {
         return loggerRegistry.hasLogger(name, messageFactoryClass);
     }
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java
index 45f5141..fd15f17 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AbstractManager.java
@@ -150,21 +150,21 @@ public abstract class AbstractManager {
         return new HashMap<>();
     }
 
-    protected void log(Level level, String message, Throwable throwable) {
+    protected void log(final Level level, final String message, final 
Throwable throwable) {
         Message m = LOGGER.getMessageFactory().newMessage("{} {} {}: {}",
                 getClass().getSimpleName(), getName(), message, throwable);
         LOGGER.log(level, m, throwable);
     }
 
-    protected void logDebug(String message, Throwable throwable) {
+    protected void logDebug(final String message, final Throwable throwable) {
         log(Level.DEBUG, message, throwable);
     }
 
-    protected void logError(String message, Throwable throwable) {
+    protected void logError(final String message, final Throwable throwable) {
         log(Level.ERROR, message, throwable);
     }
 
-    protected void logWarn(String message, Throwable throwable) {
+    protected void logWarn(final String message, final Throwable throwable) {
         log(Level.WARN, message, throwable);
     }
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
index 83afd92..0abb07e 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/AsyncAppender.java
@@ -141,7 +141,7 @@ public final class AsyncAppender extends AbstractAppender {
      * @param logEvent The LogEvent.
      */
     @Override
-    public void append(LogEvent logEvent) {
+    public void append(final LogEvent logEvent) {
         if (!isStarted()) {
             throw new IllegalStateException("AsyncAppender " + getName() + " 
is not active");
         }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
index 4e1e87c..0eb05d8 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
@@ -69,7 +69,7 @@ public final class ConsoleAppender extends 
AbstractOutputStreamAppender<OutputSt
     }
 
     private ConsoleAppender(final String name, final Layout<? extends 
Serializable> layout, final Filter filter,
-            final OutputStreamManager manager, final boolean ignoreExceptions, 
Target target) {
+            final OutputStreamManager manager, final boolean ignoreExceptions, 
final Target target) {
         super(name, layout, filter, ignoreExceptions, true, manager);
         this.target = target;
     }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/CountingNoOpAppender.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/CountingNoOpAppender.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/CountingNoOpAppender.java
index 8164aea..38775eb 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/CountingNoOpAppender.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/CountingNoOpAppender.java
@@ -33,7 +33,7 @@ public class CountingNoOpAppender extends AbstractAppender  {
 
     private final AtomicLong total = new AtomicLong();
 
-    public CountingNoOpAppender(String name, Layout<?> layout) {
+    public CountingNoOpAppender(final String name, final Layout<?> layout) {
         super(name, null, layout);
     }
 
@@ -42,7 +42,7 @@ public class CountingNoOpAppender extends AbstractAppender  {
     }
 
     @Override
-    public void append(LogEvent event) {
+    public void append(final LogEvent event) {
         total.incrementAndGet();
     }
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
index 20ef401..5e3ae5d 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java
@@ -143,7 +143,7 @@ public class OutputStreamManager extends AbstractManager 
implements ByteBufferDe
      * @param immediateFlush If true, flushes after writing.
      * @throws AppenderLoggingException if an error occurs.
      */
-    protected void write(final byte[] bytes, boolean immediateFlush)  {
+    protected void write(final byte[] bytes, final boolean immediateFlush)  {
         write(bytes, 0, bytes.length, immediateFlush);
     }
 
@@ -168,7 +168,7 @@ public class OutputStreamManager extends AbstractManager 
implements ByteBufferDe
      * @param immediateFlush flushes immediately after writing.
      * @throws AppenderLoggingException if an error occurs.
      */
-    protected synchronized void write(final byte[] bytes, final int offset, 
final int length, boolean immediateFlush) {
+    protected synchronized void write(final byte[] bytes, final int offset, 
final int length, final boolean immediateFlush) {
         if (immediateFlush && byteBuffer.position() == 0) {
             writeToDestination(bytes, offset, length);
             flushDestination();

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
index 1a542db..c49ed46 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SocketAppender.java
@@ -199,7 +199,7 @@ public class SocketAppender extends 
AbstractOutputStreamAppender<AbstractSocketM
             final String name,
             final String immediateFlush,
             final String ignore,
-            Layout<? extends Serializable> layout,
+            final Layout<? extends Serializable> layout,
             final Filter filter,
             final String advertise,
             final Configuration config) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/CronTriggeringPolicy.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/CronTriggeringPolicy.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/CronTriggeringPolicy.java
index b45d6e0..b4d1b1b 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/CronTriggeringPolicy.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/CronTriggeringPolicy.java
@@ -44,7 +44,7 @@ public final class CronTriggeringPolicy implements 
TriggeringPolicy {
     private final Configuration configuration;
     private final boolean checkOnStartup;
 
-    private CronTriggeringPolicy(CronExpression schedule, boolean 
checkOnStartup, Configuration configuration) {
+    private CronTriggeringPolicy(final CronExpression schedule, final boolean 
checkOnStartup, final Configuration configuration) {
         this.cronExpression = schedule;
         this.configuration = configuration;
         this.checkOnStartup = checkOnStartup;
@@ -89,7 +89,7 @@ public final class CronTriggeringPolicy implements 
TriggeringPolicy {
      */
     @PluginFactory
     public static CronTriggeringPolicy createPolicy(
-            @PluginConfiguration Configuration configuration,
+            @PluginConfiguration final Configuration configuration,
             @PluginAttribute("evaluateOnStartup") final String 
evaluateOnStartup,
             @PluginAttribute("schedule") final String schedule) {
         CronExpression cronExpression;
@@ -107,7 +107,7 @@ public final class CronTriggeringPolicy implements 
TriggeringPolicy {
         return new CronTriggeringPolicy(cronExpression, checkOnStartup, 
configuration);
     }
 
-    private static CronExpression getSchedule(String expression) {
+    private static CronExpression getSchedule(final String expression) {
         try {
             return new CronExpression(expression);
         } catch (ParseException pe) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
index 547cc3e..6097586 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/DefaultRolloverStrategy.java
@@ -131,7 +131,7 @@ public class DefaultRolloverStrategy implements 
RolloverStrategy {
             }
         };
 
-        static FileExtensions lookup(String fileExtension) {
+        static FileExtensions lookup(final String fileExtension) {
             for (FileExtensions ext : values()) {
                 if (ext.isExtensionFor(fileExtension)) {
                     return ext;
@@ -162,11 +162,11 @@ public class DefaultRolloverStrategy implements 
RolloverStrategy {
             return extension.length();
         }
 
-        File source(String fileName) {
+        File source(final String fileName) {
             return new File(fileName);
         }
 
-        File target(String fileName) {
+        File target(final String fileName) {
             return new File(fileName);
         }
     };

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/FileSize.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/FileSize.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/FileSize.java
index e134b1f..08e6b9e 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/FileSize.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/FileSize.java
@@ -1,90 +1,90 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-
-package org.apache.logging.log4j.core.appender.rolling;
-
-import java.text.NumberFormat;
-import java.text.ParseException;
-import java.util.Locale;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.status.StatusLogger;
-
-/**
- * FileSize utility class.
- */
-public final class FileSize {
-    private static final Logger LOGGER = StatusLogger.getLogger();
-
-    private static final long KB = 1024;
-    private static final long MB = KB * KB;
-    private static final long GB = KB * MB;
-
-    /**
-     * Pattern for string parsing.
-     */
-    private static final Pattern VALUE_PATTERN =
-        Pattern.compile("([0-9]+([\\.,][0-9]+)?)\\s*(|K|M|G)B?", 
Pattern.CASE_INSENSITIVE);
-
-    private FileSize() {
-    }
-
-    /**
-     * Converts a string to a number of bytes. Strings consist of a floating 
point value followed by
-     * K, M, or G for kilobytes, megabytes, gigabytes, respectively. The
-     * abbreviations KB, MB, and GB are also accepted. Matching is case 
insensitive.
-     *
-     * @param string The string to convert
-     * @return The Bytes value for the string
-     */
-    public static long parse(final String string, long defaultValue) {
-        final Matcher matcher = VALUE_PATTERN.matcher(string);
-
-        // Valid input?
-        if (matcher.matches()) {
-            try {
-                // Get double precision value
-                final long value = 
NumberFormat.getNumberInstance(Locale.getDefault()).parse(
-                    matcher.group(1)).longValue();
-
-                // Get units specified
-                final String units = matcher.group(3);
-
-                if (units.isEmpty()) {
-                    return value;
-                } else if (units.equalsIgnoreCase("K")) {
-                    return value * KB;
-                } else if (units.equalsIgnoreCase("M")) {
-                    return value * MB;
-                } else if (units.equalsIgnoreCase("G")) {
-                    return value * GB;
-                } else {
-                    LOGGER.error("FileSize units not recognized: " + string);
-                    return defaultValue;
-                }
-            } catch (final ParseException e) {
-                LOGGER.error("FileSize unable to parse numeric part: " + 
string, e);
-                return defaultValue;
-            }
-        }
-        LOGGER.error("FileSize unable to parse bytes: " + string);
-        return defaultValue;
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.core.appender.rolling;
+
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * FileSize utility class.
+ */
+public final class FileSize {
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
+    private static final long KB = 1024;
+    private static final long MB = KB * KB;
+    private static final long GB = KB * MB;
+
+    /**
+     * Pattern for string parsing.
+     */
+    private static final Pattern VALUE_PATTERN =
+        Pattern.compile("([0-9]+([\\.,][0-9]+)?)\\s*(|K|M|G)B?", 
Pattern.CASE_INSENSITIVE);
+
+    private FileSize() {
+    }
+
+    /**
+     * Converts a string to a number of bytes. Strings consist of a floating 
point value followed by
+     * K, M, or G for kilobytes, megabytes, gigabytes, respectively. The
+     * abbreviations KB, MB, and GB are also accepted. Matching is case 
insensitive.
+     *
+     * @param string The string to convert
+     * @return The Bytes value for the string
+     */
+    public static long parse(final String string, final long defaultValue) {
+        final Matcher matcher = VALUE_PATTERN.matcher(string);
+
+        // Valid input?
+        if (matcher.matches()) {
+            try {
+                // Get double precision value
+                final long value = 
NumberFormat.getNumberInstance(Locale.getDefault()).parse(
+                    matcher.group(1)).longValue();
+
+                // Get units specified
+                final String units = matcher.group(3);
+
+                if (units.isEmpty()) {
+                    return value;
+                } else if (units.equalsIgnoreCase("K")) {
+                    return value * KB;
+                } else if (units.equalsIgnoreCase("M")) {
+                    return value * MB;
+                } else if (units.equalsIgnoreCase("G")) {
+                    return value * GB;
+                } else {
+                    LOGGER.error("FileSize units not recognized: " + string);
+                    return defaultValue;
+                }
+            } catch (final ParseException e) {
+                LOGGER.error("FileSize unable to parse numeric part: " + 
string, e);
+                return defaultValue;
+            }
+        }
+        LOGGER.error("FileSize unable to parse bytes: " + string);
+        return defaultValue;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Duration.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Duration.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Duration.java
index 8508f03..a5103f7 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Duration.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Duration.java
@@ -1,257 +1,257 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-
-package org.apache.logging.log4j.core.appender.rolling.action;
-
-import java.io.Serializable;
-import java.util.Objects;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Simplified implementation of the <a 
href="https://en.wikipedia.org/wiki/ISO_8601#Durations";>ISO-8601 Durations</a>
- * standard. The supported format is {@code PnDTnHnMnS}, with 'P' and 'T' 
optional. Days are considered to be exactly 24
- * hours.
- * <p>
- * Similarly to the {@code java.time.Duration} class, this class does not 
support year or month sections in the format.
- * This implementation does not support fractions or negative values.
- * 
- * @see #parse(CharSequence)
- */
-public class Duration implements Serializable, Comparable<Duration> {
-    private static final long serialVersionUID = -3756810052716342061L;
-
-    /**
-     * Constant for a duration of zero.
-     */
-    public static final Duration ZERO = new Duration(0);
-
-    /**
-     * Hours per day.
-     */
-    private static final int HOURS_PER_DAY = 24;
-    /**
-     * Minutes per hour.
-     */
-    private static final int MINUTES_PER_HOUR = 60;
-    /**
-     * Seconds per minute.
-     */
-    private static final int SECONDS_PER_MINUTE = 60;
-    /**
-     * Seconds per hour.
-     */
-    private static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * 
MINUTES_PER_HOUR;
-    /**
-     * Seconds per day.
-     */
-    private static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * 
HOURS_PER_DAY;
-
-    /**
-     * The pattern for parsing.
-     */
-    private static final Pattern PATTERN = Pattern.compile("P?(?:([0-9]+)D)?"
-            + "(T?(?:([0-9]+)H)?(?:([0-9]+)M)?(?:([0-9]+)?S)?)?", 
Pattern.CASE_INSENSITIVE);
-
-    /**
-     * The number of seconds in the duration.
-     */
-    private final long seconds;
-
-    /**
-     * Constructs an instance of {@code Duration} using seconds.
-     *
-     * @param seconds the length of the duration in seconds, positive or 
negative
-     */
-    private Duration(long seconds) {
-        super();
-        this.seconds = seconds;
-    }
-
-    /**
-     * Obtains a {@code Duration} from a text string such as {@code 
PnDTnHnMnS}.
-     * <p>
-     * This will parse a textual representation of a duration, including the 
string produced by {@code toString()}. The
-     * formats accepted are based on the ISO-8601 duration format {@code 
PnDTnHnMnS} with days considered to be exactly
-     * 24 hours.
-     * <p>
-     * This implementation does not support negative numbers or fractions (so 
the smallest non-zero value a Duration can
-     * have is one second).
-     * <p>
-     * The string optionally starts with the ASCII letter "P" in upper or 
lower case. There are then four sections, each
-     * consisting of a number and a suffix. The sections have suffixes in 
ASCII of "D", "H", "M" and "S" for days,
-     * hours, minutes and seconds, accepted in upper or lower case. The 
suffixes must occur in order. The ASCII letter
-     * "T" may occur before the first occurrence, if any, of an hour, minute 
or second section. At least one of the four
-     * sections must be present, and if "T" is present there must be at least 
one section after the "T". The number part
-     * of each section must consist of one or more ASCII digits. The number 
may not be prefixed by the ASCII negative or
-     * positive symbol. The number of days, hours, minutes and seconds must 
parse to a {@code long}.
-     * <p>
-     * Examples:
-     * 
-     * <pre>
-     *    "PT20S" -- parses as "20 seconds"
-     *    "PT15M"     -- parses as "15 minutes" (where a minute is 60 seconds)
-     *    "PT10H"     -- parses as "10 hours" (where an hour is 3600 seconds)
-     *    "P2D"       -- parses as "2 days" (where a day is 24 hours or 86400 
seconds)
-     *    "P2DT3H4M"  -- parses as "2 days, 3 hours and 4 minutes"
-     * </pre>
-     *
-     * @param text the text to parse, not null
-     * @return the parsed duration, not null
-     * @throws IllegalArgumentException if the text cannot be parsed to a 
duration
-     */
-    public static Duration parse(CharSequence text) {
-        Objects.requireNonNull(text, "text");
-        Matcher matcher = PATTERN.matcher(text);
-        if (matcher.matches()) {
-            // check for letter T but no time sections
-            if ("T".equals(matcher.group(2)) == false) {
-                String dayMatch = matcher.group(1);
-                String hourMatch = matcher.group(3);
-                String minuteMatch = matcher.group(4);
-                String secondMatch = matcher.group(5);
-                if (dayMatch != null || hourMatch != null || minuteMatch != 
null || secondMatch != null) {
-                    long daysAsSecs = parseNumber(text, dayMatch, 
SECONDS_PER_DAY, "days");
-                    long hoursAsSecs = parseNumber(text, hourMatch, 
SECONDS_PER_HOUR, "hours");
-                    long minsAsSecs = parseNumber(text, minuteMatch, 
SECONDS_PER_MINUTE, "minutes");
-                    long seconds = parseNumber(text, secondMatch, 1, 
"seconds");
-                    try {
-                        return create(daysAsSecs, hoursAsSecs, minsAsSecs, 
seconds);
-                    } catch (ArithmeticException ex) {
-                        throw new IllegalArgumentException("Text cannot be 
parsed to a Duration (overflow) " + text, ex);
-                    }
-                }
-            }
-        }
-        throw new IllegalArgumentException("Text cannot be parsed to a 
Duration: " + text);
-    }
-
-    private static long parseNumber(final CharSequence text, final String 
parsed, final int multiplier,
-            final String errorText) {
-        // regex limits to [0-9]+
-        if (parsed == null) {
-            return 0;
-        }
-        try {
-            final long val = Long.parseLong(parsed);
-            return val * multiplier;
-        } catch (final Exception ex) {
-            throw new IllegalArgumentException("Text cannot be parsed to a 
Duration: " + errorText + " (in " + text
-                    + ")", ex);
-        }
-    }
-
-    private static Duration create(final long daysAsSecs, final long 
hoursAsSecs, final long minsAsSecs, final long secs) {
-        return create(daysAsSecs + hoursAsSecs + minsAsSecs + secs);
-    }
-
-    /**
-     * Obtains an instance of {@code Duration} using seconds.
-     *
-     * @param seconds the length of the duration in seconds, positive only
-     */
-    private static Duration create(final long seconds) {
-        if ((seconds) == 0) {
-            return ZERO;
-        }
-        return new Duration(seconds);
-    }
-
-    /**
-     * Converts this duration to the total length in milliseconds.
-     *
-     * @return the total length of the duration in milliseconds
-     */
-    public long toMillis() {
-        return seconds * 1000L;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == this) {
-            return true;
-        }
-        if (!(obj instanceof Duration)) {
-            return false;
-        }
-        Duration other = (Duration) obj;
-        return other.seconds == this.seconds;
-    }
-
-    @Override
-    public int hashCode() {
-        return (int) (seconds ^ (seconds >>> 32));
-    }
-
-    /**
-     * A string representation of this duration using ISO-8601 seconds based 
representation, such as {@code PT8H6M12S}.
-     * <p>
-     * The format of the returned string will be {@code PnDTnHnMnS}, where n 
is the relevant days, hours, minutes or
-     * seconds part of the duration. If a section has a zero value, it is 
omitted. The hours, minutes and seconds are
-     * all positive.
-     * <p>
-     * Examples:
-     * 
-     * <pre>
-     *    "20 seconds"                     -- "PT20S
-     *    "15 minutes" (15 * 60 seconds)   -- "PT15M"
-     *    "10 hours" (10 * 3600 seconds)   -- "PT10H"
-     *    "2 days" (2 * 86400 seconds)     -- "P2D"
-     * </pre>
-     * 
-     * @return an ISO-8601 representation of this duration, not null
-     */
-    @Override
-    public String toString() {
-        if (this == ZERO) {
-            return "PT0S";
-        }
-        final long days = seconds / SECONDS_PER_DAY;
-        final long hours = (seconds % SECONDS_PER_DAY) / SECONDS_PER_HOUR;
-        final int minutes = (int) ((seconds % SECONDS_PER_HOUR) / 
SECONDS_PER_MINUTE);
-        final int secs = (int) (seconds % SECONDS_PER_MINUTE);
-        final StringBuilder buf = new StringBuilder(24);
-        buf.append("P");
-        if (days != 0) {
-            buf.append(days).append('D');
-        }
-        if ((hours | minutes | secs) != 0) {
-            buf.append('T');
-        }
-        if (hours != 0) {
-            buf.append(hours).append('H');
-        }
-        if (minutes != 0) {
-            buf.append(minutes).append('M');
-        }
-        if (secs == 0 && buf.length() > 0) {
-            return buf.toString();
-        }
-        buf.append(secs).append('S');
-        return buf.toString();
-    }
-
-    /*
-     * (non-Javadoc)
-     * 
-     * @see java.lang.Comparable#compareTo(java.lang.Object)
-     */
-    @Override
-    public int compareTo(Duration other) {
-        return Long.signum(toMillis() - other.toMillis());
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.core.appender.rolling.action;
+
+import java.io.Serializable;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Simplified implementation of the <a 
href="https://en.wikipedia.org/wiki/ISO_8601#Durations";>ISO-8601 Durations</a>
+ * standard. The supported format is {@code PnDTnHnMnS}, with 'P' and 'T' 
optional. Days are considered to be exactly 24
+ * hours.
+ * <p>
+ * Similarly to the {@code java.time.Duration} class, this class does not 
support year or month sections in the format.
+ * This implementation does not support fractions or negative values.
+ * 
+ * @see #parse(CharSequence)
+ */
+public class Duration implements Serializable, Comparable<Duration> {
+    private static final long serialVersionUID = -3756810052716342061L;
+
+    /**
+     * Constant for a duration of zero.
+     */
+    public static final Duration ZERO = new Duration(0);
+
+    /**
+     * Hours per day.
+     */
+    private static final int HOURS_PER_DAY = 24;
+    /**
+     * Minutes per hour.
+     */
+    private static final int MINUTES_PER_HOUR = 60;
+    /**
+     * Seconds per minute.
+     */
+    private static final int SECONDS_PER_MINUTE = 60;
+    /**
+     * Seconds per hour.
+     */
+    private static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * 
MINUTES_PER_HOUR;
+    /**
+     * Seconds per day.
+     */
+    private static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * 
HOURS_PER_DAY;
+
+    /**
+     * The pattern for parsing.
+     */
+    private static final Pattern PATTERN = Pattern.compile("P?(?:([0-9]+)D)?"
+            + "(T?(?:([0-9]+)H)?(?:([0-9]+)M)?(?:([0-9]+)?S)?)?", 
Pattern.CASE_INSENSITIVE);
+
+    /**
+     * The number of seconds in the duration.
+     */
+    private final long seconds;
+
+    /**
+     * Constructs an instance of {@code Duration} using seconds.
+     *
+     * @param seconds the length of the duration in seconds, positive or 
negative
+     */
+    private Duration(final long seconds) {
+        super();
+        this.seconds = seconds;
+    }
+
+    /**
+     * Obtains a {@code Duration} from a text string such as {@code 
PnDTnHnMnS}.
+     * <p>
+     * This will parse a textual representation of a duration, including the 
string produced by {@code toString()}. The
+     * formats accepted are based on the ISO-8601 duration format {@code 
PnDTnHnMnS} with days considered to be exactly
+     * 24 hours.
+     * <p>
+     * This implementation does not support negative numbers or fractions (so 
the smallest non-zero value a Duration can
+     * have is one second).
+     * <p>
+     * The string optionally starts with the ASCII letter "P" in upper or 
lower case. There are then four sections, each
+     * consisting of a number and a suffix. The sections have suffixes in 
ASCII of "D", "H", "M" and "S" for days,
+     * hours, minutes and seconds, accepted in upper or lower case. The 
suffixes must occur in order. The ASCII letter
+     * "T" may occur before the first occurrence, if any, of an hour, minute 
or second section. At least one of the four
+     * sections must be present, and if "T" is present there must be at least 
one section after the "T". The number part
+     * of each section must consist of one or more ASCII digits. The number 
may not be prefixed by the ASCII negative or
+     * positive symbol. The number of days, hours, minutes and seconds must 
parse to a {@code long}.
+     * <p>
+     * Examples:
+     * 
+     * <pre>
+     *    "PT20S" -- parses as "20 seconds"
+     *    "PT15M"     -- parses as "15 minutes" (where a minute is 60 seconds)
+     *    "PT10H"     -- parses as "10 hours" (where an hour is 3600 seconds)
+     *    "P2D"       -- parses as "2 days" (where a day is 24 hours or 86400 
seconds)
+     *    "P2DT3H4M"  -- parses as "2 days, 3 hours and 4 minutes"
+     * </pre>
+     *
+     * @param text the text to parse, not null
+     * @return the parsed duration, not null
+     * @throws IllegalArgumentException if the text cannot be parsed to a 
duration
+     */
+    public static Duration parse(final CharSequence text) {
+        Objects.requireNonNull(text, "text");
+        Matcher matcher = PATTERN.matcher(text);
+        if (matcher.matches()) {
+            // check for letter T but no time sections
+            if ("T".equals(matcher.group(2)) == false) {
+                String dayMatch = matcher.group(1);
+                String hourMatch = matcher.group(3);
+                String minuteMatch = matcher.group(4);
+                String secondMatch = matcher.group(5);
+                if (dayMatch != null || hourMatch != null || minuteMatch != 
null || secondMatch != null) {
+                    long daysAsSecs = parseNumber(text, dayMatch, 
SECONDS_PER_DAY, "days");
+                    long hoursAsSecs = parseNumber(text, hourMatch, 
SECONDS_PER_HOUR, "hours");
+                    long minsAsSecs = parseNumber(text, minuteMatch, 
SECONDS_PER_MINUTE, "minutes");
+                    long seconds = parseNumber(text, secondMatch, 1, 
"seconds");
+                    try {
+                        return create(daysAsSecs, hoursAsSecs, minsAsSecs, 
seconds);
+                    } catch (ArithmeticException ex) {
+                        throw new IllegalArgumentException("Text cannot be 
parsed to a Duration (overflow) " + text, ex);
+                    }
+                }
+            }
+        }
+        throw new IllegalArgumentException("Text cannot be parsed to a 
Duration: " + text);
+    }
+
+    private static long parseNumber(final CharSequence text, final String 
parsed, final int multiplier,
+            final String errorText) {
+        // regex limits to [0-9]+
+        if (parsed == null) {
+            return 0;
+        }
+        try {
+            final long val = Long.parseLong(parsed);
+            return val * multiplier;
+        } catch (final Exception ex) {
+            throw new IllegalArgumentException("Text cannot be parsed to a 
Duration: " + errorText + " (in " + text
+                    + ")", ex);
+        }
+    }
+
+    private static Duration create(final long daysAsSecs, final long 
hoursAsSecs, final long minsAsSecs, final long secs) {
+        return create(daysAsSecs + hoursAsSecs + minsAsSecs + secs);
+    }
+
+    /**
+     * Obtains an instance of {@code Duration} using seconds.
+     *
+     * @param seconds the length of the duration in seconds, positive only
+     */
+    private static Duration create(final long seconds) {
+        if ((seconds) == 0) {
+            return ZERO;
+        }
+        return new Duration(seconds);
+    }
+
+    /**
+     * Converts this duration to the total length in milliseconds.
+     *
+     * @return the total length of the duration in milliseconds
+     */
+    public long toMillis() {
+        return seconds * 1000L;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof Duration)) {
+            return false;
+        }
+        Duration other = (Duration) obj;
+        return other.seconds == this.seconds;
+    }
+
+    @Override
+    public int hashCode() {
+        return (int) (seconds ^ (seconds >>> 32));
+    }
+
+    /**
+     * A string representation of this duration using ISO-8601 seconds based 
representation, such as {@code PT8H6M12S}.
+     * <p>
+     * The format of the returned string will be {@code PnDTnHnMnS}, where n 
is the relevant days, hours, minutes or
+     * seconds part of the duration. If a section has a zero value, it is 
omitted. The hours, minutes and seconds are
+     * all positive.
+     * <p>
+     * Examples:
+     * 
+     * <pre>
+     *    "20 seconds"                     -- "PT20S
+     *    "15 minutes" (15 * 60 seconds)   -- "PT15M"
+     *    "10 hours" (10 * 3600 seconds)   -- "PT10H"
+     *    "2 days" (2 * 86400 seconds)     -- "P2D"
+     * </pre>
+     * 
+     * @return an ISO-8601 representation of this duration, not null
+     */
+    @Override
+    public String toString() {
+        if (this == ZERO) {
+            return "PT0S";
+        }
+        final long days = seconds / SECONDS_PER_DAY;
+        final long hours = (seconds % SECONDS_PER_DAY) / SECONDS_PER_HOUR;
+        final int minutes = (int) ((seconds % SECONDS_PER_HOUR) / 
SECONDS_PER_MINUTE);
+        final int secs = (int) (seconds % SECONDS_PER_MINUTE);
+        final StringBuilder buf = new StringBuilder(24);
+        buf.append("P");
+        if (days != 0) {
+            buf.append(days).append('D');
+        }
+        if ((hours | minutes | secs) != 0) {
+            buf.append('T');
+        }
+        if (hours != 0) {
+            buf.append(hours).append('H');
+        }
+        if (minutes != 0) {
+            buf.append(minutes).append('M');
+        }
+        if (secs == 0 && buf.length() > 0) {
+            return buf.toString();
+        }
+        buf.append(secs).append('S');
+        return buf.toString();
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    @Override
+    public int compareTo(final Duration other) {
+        return Long.signum(toMillis() - other.toMillis());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfAll.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfAll.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfAll.java
index 627a082..9591804 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfAll.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/IfAll.java
@@ -1,116 +1,116 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.core.appender.rolling.action;
-
-import java.nio.file.Path;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.Arrays;
-import java.util.Objects;
-
-import org.apache.logging.log4j.core.config.plugins.Plugin;
-import org.apache.logging.log4j.core.config.plugins.PluginElement;
-import org.apache.logging.log4j.core.config.plugins.PluginFactory;
-
-/**
- * Composite {@code PathCondition} that only accepts objects that are accepted 
by <em>all</em> component conditions.
- * Corresponds to logical "AND".
- */
-@Plugin(name = "IfAll", category = "Core", printObject = true)
-public final class IfAll implements PathCondition {
-
-    private final PathCondition[] components;
-
-    private IfAll(final PathCondition... filters) {
-        this.components = Objects.requireNonNull(filters, "filters");
-    }
-
-    public PathCondition[] getDeleteFilters() {
-        return components;
-    }
-
-    /*
-     * (non-Javadoc)
-     * 
-     * @see 
org.apache.logging.log4j.core.appender.rolling.action.PathCondition#accept(java.nio.file.Path,
-     * java.nio.file.Path, java.nio.file.attribute.BasicFileAttributes)
-     */
-    @Override
-    public boolean accept(final Path baseDir, final Path relativePath, final 
BasicFileAttributes attrs) {
-        if (components == null || components.length == 0) {
-            return false; // unconditional delete not supported
-        }
-        return accept(components, baseDir, relativePath, attrs);
-    }
-
-    /**
-     * Returns {@code true} if all the specified conditions accept the 
specified path, {@code false} otherwise.
-     * 
-     * @param list the array of conditions to evaluate
-     * @param baseDir the directory from where to start scanning for deletion 
candidate files
-     * @param relativePath the candidate for deletion. This path is relative 
to the baseDir.
-     * @param attrs attributes of the candidate path
-     * @return {@code true} if all the specified conditions accept the 
specified path, {@code false} otherwise
-     * @throws NullPointerException if any of the parameters is {@code null}
-     */
-    public static boolean accept(final PathCondition[] list, final Path 
baseDir, final Path relativePath,
-            final BasicFileAttributes attrs) {
-        for (final PathCondition component : list) {
-            if (!component.accept(baseDir, relativePath, attrs)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /*
-     * (non-Javadoc)
-     * 
-     * @see 
org.apache.logging.log4j.core.appender.rolling.action.PathCondition#beforeFileTreeWalk()
-     */
-    @Override
-    public void beforeFileTreeWalk() {
-        beforeFileTreeWalk(components);
-    }
-
-    /**
-     * Calls {@link #beforeFileTreeWalk()} on all of the specified nested 
conditions.
-     * 
-     * @param nestedConditions the conditions to call {@link 
#beforeFileTreeWalk()} on
-     */
-    public static void beforeFileTreeWalk(PathCondition[] nestedConditions) {
-        for (PathCondition condition : nestedConditions) {
-            condition.beforeFileTreeWalk();
-        }
-    }
-
-    /**
-     * Create a Composite PathCondition whose components all need to accept 
before this condition accepts.
-     * 
-     * @param components The component filters.
-     * @return A Composite PathCondition.
-     */
-    @PluginFactory
-    public static IfAll createAndCondition( //
-            @PluginElement("PathConditions") final PathCondition... 
components) {
-        return new IfAll(components);
-    }
-
-    @Override
-    public String toString() {
-        return "IfAll" + Arrays.toString(components);
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core.appender.rolling.action;
+
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Arrays;
+import java.util.Objects;
+
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
+
+/**
+ * Composite {@code PathCondition} that only accepts objects that are accepted 
by <em>all</em> component conditions.
+ * Corresponds to logical "AND".
+ */
+@Plugin(name = "IfAll", category = "Core", printObject = true)
+public final class IfAll implements PathCondition {
+
+    private final PathCondition[] components;
+
+    private IfAll(final PathCondition... filters) {
+        this.components = Objects.requireNonNull(filters, "filters");
+    }
+
+    public PathCondition[] getDeleteFilters() {
+        return components;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see 
org.apache.logging.log4j.core.appender.rolling.action.PathCondition#accept(java.nio.file.Path,
+     * java.nio.file.Path, java.nio.file.attribute.BasicFileAttributes)
+     */
+    @Override
+    public boolean accept(final Path baseDir, final Path relativePath, final 
BasicFileAttributes attrs) {
+        if (components == null || components.length == 0) {
+            return false; // unconditional delete not supported
+        }
+        return accept(components, baseDir, relativePath, attrs);
+    }
+
+    /**
+     * Returns {@code true} if all the specified conditions accept the 
specified path, {@code false} otherwise.
+     * 
+     * @param list the array of conditions to evaluate
+     * @param baseDir the directory from where to start scanning for deletion 
candidate files
+     * @param relativePath the candidate for deletion. This path is relative 
to the baseDir.
+     * @param attrs attributes of the candidate path
+     * @return {@code true} if all the specified conditions accept the 
specified path, {@code false} otherwise
+     * @throws NullPointerException if any of the parameters is {@code null}
+     */
+    public static boolean accept(final PathCondition[] list, final Path 
baseDir, final Path relativePath,
+            final BasicFileAttributes attrs) {
+        for (final PathCondition component : list) {
+            if (!component.accept(baseDir, relativePath, attrs)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see 
org.apache.logging.log4j.core.appender.rolling.action.PathCondition#beforeFileTreeWalk()
+     */
+    @Override
+    public void beforeFileTreeWalk() {
+        beforeFileTreeWalk(components);
+    }
+
+    /**
+     * Calls {@link #beforeFileTreeWalk()} on all of the specified nested 
conditions.
+     * 
+     * @param nestedConditions the conditions to call {@link 
#beforeFileTreeWalk()} on
+     */
+    public static void beforeFileTreeWalk(final PathCondition[] 
nestedConditions) {
+        for (PathCondition condition : nestedConditions) {
+            condition.beforeFileTreeWalk();
+        }
+    }
+
+    /**
+     * Create a Composite PathCondition whose components all need to accept 
before this condition accepts.
+     * 
+     * @param components The component filters.
+     * @return A Composite PathCondition.
+     */
+    @PluginFactory
+    public static IfAll createAndCondition( //
+            @PluginElement("PathConditions") final PathCondition... 
components) {
+        return new IfAll(components);
+    }
+
+    @Override
+    public String toString() {
+        return "IfAll" + Arrays.toString(components);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/IdlePurgePolicy.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/IdlePurgePolicy.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/IdlePurgePolicy.java
index 953f1bc..e9e7469 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/IdlePurgePolicy.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/IdlePurgePolicy.java
@@ -48,13 +48,13 @@ public class IdlePurgePolicy extends AbstractLifeCycle 
implements PurgePolicy, R
     private final ConfigurationScheduler scheduler;
     private volatile ScheduledFuture<?> future = null;
 
-    public IdlePurgePolicy(long timeToLive, ConfigurationScheduler scheduler) {
+    public IdlePurgePolicy(final long timeToLive, final ConfigurationScheduler 
scheduler) {
         this.timeToLive = timeToLive;
         this.scheduler = scheduler;
     }
 
     @Override
-    public void initialize(RoutingAppender routingAppender) {
+    public void initialize(final RoutingAppender routingAppender) {
         this.routingAppender = routingAppender;
     }
 
@@ -80,7 +80,7 @@ public class IdlePurgePolicy extends AbstractLifeCycle 
implements PurgePolicy, R
     }
 
     @Override
-    public void update(String key, LogEvent event) {
+    public void update(final String key, final LogEvent event) {
         long now = System.currentTimeMillis();
         appendersUsage.put(key, now);
         if (future == null) {
@@ -123,7 +123,7 @@ public class IdlePurgePolicy extends AbstractLifeCycle 
implements PurgePolicy, R
     public static PurgePolicy createPurgePolicy(
         @PluginAttribute("timeToLive") final String timeToLive,
         @PluginAttribute("timeUnit") final String timeUnit,
-        @PluginConfiguration Configuration configuration) {
+        @PluginConfiguration final Configuration configuration) {
 
         if (timeToLive == null) {
             LOGGER.error("A timeToLive  value is required");

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
index a6b5df0..02f2d33 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/routing/RoutingAppender.java
@@ -55,7 +55,7 @@ public final class RoutingAppender extends AbstractAppender {
          private final PurgePolicy purgePolicy;
 
     private RoutingAppender(final String name, final Filter filter, final 
boolean ignoreExceptions, final Routes routes,
-                            final RewritePolicy rewritePolicy, final 
Configuration config, PurgePolicy purgePolicy) {
+                            final RewritePolicy rewritePolicy, final 
Configuration config, final PurgePolicy purgePolicy) {
         super(name, filter, null, ignoreExceptions);
         this.routes = routes;
         this.config = config;
@@ -181,7 +181,7 @@ public final class RoutingAppender extends AbstractAppender 
{
      * 
      * @param key The appender's key
      */
-    public void deleteAppender(String key) {
+    public void deleteAppender(final String key) {
        LOGGER.debug("Stopping route with key" + key);
        AppenderControl control = appenders.remove(key);
        control.getAppender().stop();

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
index 4c590c1..df7eb8a 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLogger.java
@@ -98,7 +98,7 @@ public class AsyncLogger extends Logger implements 
EventTranslatorVararg<RingBuf
      * @see 
org.apache.logging.log4j.core.Logger#updateConfiguration(org.apache.logging.log4j.core.config.Configuration)
      */
     @Override
-    protected void updateConfiguration(Configuration newConfig) {
+    protected void updateConfiguration(final Configuration newConfig) {
         nanoClock = newConfig.getNanoClock();
         includeLocation = newConfig.getLoggerConfig(name).isIncludeLocation();
         super.updateConfiguration(newConfig);
@@ -215,7 +215,7 @@ public class AsyncLogger extends Logger implements 
EventTranslatorVararg<RingBuf
      * @param fqcn fully qualified caller name.
      * @return the caller location if requested, {@code null} otherwise.
      */
-    private StackTraceElement calcLocationIfRequested(String fqcn) {
+    private StackTraceElement calcLocationIfRequested(final String fqcn) {
         // location: very expensive operation. LOG4J2-153:
         // Only include if "includeLocation=true" is specified,
         // exclude if not specified or if "false" was specified.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
index 276d2ed..d0c9eea 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.java
@@ -66,7 +66,7 @@ public class AsyncLoggerConfigDisruptor implements 
AsyncLoggerConfigDelegate {
         public Log4jEventWrapper() {
         }
 
-        public Log4jEventWrapper(MutableLogEvent mutableLogEvent) {
+        public Log4jEventWrapper(final MutableLogEvent mutableLogEvent) {
             event = mutableLogEvent;
         }
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContext.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContext.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContext.java
index a256238..a06893c 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContext.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerContext.java
@@ -81,12 +81,12 @@ public class AsyncLoggerContext extends LoggerContext {
      * @see 
org.apache.logging.log4j.core.LoggerContext#start(org.apache.logging.log4j.core.config.Configuration)
      */
     @Override
-    public void start(Configuration config) {
+    public void start(final Configuration config) {
         maybeStartHelper(config);
         super.start(config);
     }
 
-    private void maybeStartHelper(Configuration config) {
+    private void maybeStartHelper(final Configuration config) {
         // If no log4j configuration was found, there are no loggers
         // and there is no point in starting the disruptor (which takes up
         // significant memory and starts a thread).

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7a5dcd43/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerDisruptor.java
----------------------------------------------------------------------
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerDisruptor.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerDisruptor.java
index 628f4ff..a2dcb19 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerDisruptor.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncLoggerDisruptor.java
@@ -1,236 +1,236 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-
-package org.apache.logging.log4j.core.async;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.core.jmx.RingBufferAdmin;
-import org.apache.logging.log4j.status.StatusLogger;
-
-import com.lmax.disruptor.ExceptionHandler;
-import com.lmax.disruptor.RingBuffer;
-import com.lmax.disruptor.WaitStrategy;
-import com.lmax.disruptor.dsl.Disruptor;
-import com.lmax.disruptor.dsl.ProducerType;
-
-/**
- * Helper class for async loggers: AsyncLoggerDisruptor handles the mechanics 
of working with the LMAX Disruptor, and
- * works with its associated AsyncLoggerContext to synchronize the life cycle 
of the Disruptor and its thread with the
- * life cycle of the context. The AsyncLoggerDisruptor of the context is 
shared by all AsyncLogger objects created by
- * that AsyncLoggerContext.
- */
-class AsyncLoggerDisruptor {
-    private static final int SLEEP_MILLIS_BETWEEN_DRAIN_ATTEMPTS = 50;
-    private static final int MAX_DRAIN_ATTEMPTS_BEFORE_SHUTDOWN = 200;
-    private static final StatusLogger LOGGER = StatusLogger.getLogger();
-
-    private volatile Disruptor<RingBufferLogEvent> disruptor;
-    private ExecutorService executor;
-    private String contextName;
-
-    private boolean useThreadLocalTranslator = true;
-    private long backgroundThreadId;
-    private AsyncQueueFullPolicy asyncQueueFullPolicy;
-    private int ringBufferSize;
-
-    AsyncLoggerDisruptor(String contextName) {
-        this.contextName = contextName;
-    }
-
-    public String getContextName() {
-        return contextName;
-    }
-
-    public void setContextName(String name) {
-        contextName = name;
-    }
-
-    Disruptor<RingBufferLogEvent> getDisruptor() {
-        return disruptor;
-    }
-
-    /**
-     * Creates and starts a new Disruptor and associated thread if none 
currently exists.
-     *
-     * @see #stop()
-     */
-    synchronized void start() {
-        if (disruptor != null) {
-            LOGGER.trace(
-                    "[{}] AsyncLoggerDisruptor not starting new disruptor for 
this context, using existing object.",
-                    contextName);
-            return;
-        }
-        LOGGER.trace("[{}] AsyncLoggerDisruptor creating new disruptor for 
this context.", contextName);
-        ringBufferSize = 
DisruptorUtil.calculateRingBufferSize("AsyncLogger.RingBufferSize");
-        final WaitStrategy waitStrategy = 
DisruptorUtil.createWaitStrategy("AsyncLogger.WaitStrategy");
-        executor = Executors.newSingleThreadExecutor(new 
DaemonThreadFactory("AsyncLogger[" + contextName + "]"));
-        backgroundThreadId = DisruptorUtil.getExecutorThreadId(executor);
-        asyncQueueFullPolicy = AsyncQueueFullPolicyFactory.create();
-
-        disruptor = new Disruptor<>(RingBufferLogEvent.FACTORY, 
ringBufferSize, executor, ProducerType.MULTI,
-                waitStrategy);
-
-        final ExceptionHandler<RingBufferLogEvent> errorHandler = 
DisruptorUtil.getAsyncLoggerExceptionHandler();
-        disruptor.handleExceptionsWith(errorHandler);
-
-        final RingBufferLogEventHandler[] handlers = {new 
RingBufferLogEventHandler()};
-        disruptor.handleEventsWith(handlers);
-
-        LOGGER.debug("[{}] Starting AsyncLogger disruptor for this context 
with ringbufferSize={}, waitStrategy={}, "
-                + "exceptionHandler={}...", contextName, 
disruptor.getRingBuffer().getBufferSize(), waitStrategy
-                .getClass().getSimpleName(), errorHandler);
-        disruptor.start();
-
-        LOGGER.trace("[{}] AsyncLoggers use a {} translator", contextName, 
useThreadLocalTranslator ? "threadlocal"
-                : "vararg");
-    }
-
-    /**
-     * Decreases the reference count. If the reference count reached zero, the 
Disruptor and its associated thread are
-     * shut down and their references set to {@code null}.
-     */
-    synchronized void stop() {
-        final Disruptor<RingBufferLogEvent> temp = getDisruptor();
-        if (temp == null) {
-            LOGGER.trace("[{}] AsyncLoggerDisruptor: disruptor for this 
context already shut down.", contextName);
-            return; // disruptor was already shut down by another thread
-        }
-        LOGGER.debug("[{}] AsyncLoggerDisruptor: shutting down disruptor for 
this context.", contextName);
-
-        // We must guarantee that publishing to the RingBuffer has stopped 
before we call disruptor.shutdown().
-        disruptor = null; // client code fails with NPE if log after stop. 
This is by design.
-
-        // Calling Disruptor.shutdown() will wait until all enqueued events 
are fully processed,
-        // but this waiting happens in a busy-spin. To avoid (postpone) 
wasting CPU,
-        // we sleep in short chunks, up to 10 seconds, waiting for the 
ringbuffer to drain.
-        for (int i = 0; hasBacklog(temp) && i < 
MAX_DRAIN_ATTEMPTS_BEFORE_SHUTDOWN; i++) {
-            try {
-                Thread.sleep(SLEEP_MILLIS_BETWEEN_DRAIN_ATTEMPTS); // give up 
the CPU for a while
-            } catch (final InterruptedException e) { // ignored
-            }
-        }
-        temp.shutdown(); // busy-spins until all events currently in the 
disruptor have been processed
-
-        LOGGER.trace("[{}] AsyncLoggerDisruptor: shutting down disruptor 
executor.", contextName);
-        executor.shutdown(); // finally, kill the processor thread
-        executor = null;
-
-        if 
(DiscardingAsyncQueueFullPolicy.getDiscardCount(asyncQueueFullPolicy) > 0) {
-            LOGGER.trace("AsyncLoggerDisruptor: {} discarded {} events.", 
asyncQueueFullPolicy,
-                    
DiscardingAsyncQueueFullPolicy.getDiscardCount(asyncQueueFullPolicy));
-        }
-    }
-
-    /**
-     * Returns {@code true} if the specified disruptor still has unprocessed 
events.
-     */
-    private static boolean hasBacklog(final Disruptor<?> theDisruptor) {
-        final RingBuffer<?> ringBuffer = theDisruptor.getRingBuffer();
-        return !ringBuffer.hasAvailableCapacity(ringBuffer.getBufferSize());
-    }
-
-    /**
-     * Creates and returns a new {@code RingBufferAdmin} that instruments the 
ringbuffer of the {@code AsyncLogger}.
-     *
-     * @param jmxContextName name of the {@code AsyncLoggerContext}
-     * @return a new {@code RingBufferAdmin} that instruments the ringbuffer
-     */
-    public RingBufferAdmin createRingBufferAdmin(final String jmxContextName) {
-        final RingBuffer<RingBufferLogEvent> ring = disruptor == null ? null : 
disruptor.getRingBuffer();
-        return RingBufferAdmin.forAsyncLogger(ring, jmxContextName);
-    }
-
-    EventRoute getEventRoute(final Level logLevel) {
-        final int remainingCapacity = remainingDisruptorCapacity();
-        if (remainingCapacity < 0) {
-            return EventRoute.DISCARD;
-        }
-        return asyncQueueFullPolicy.getRoute(backgroundThreadId, logLevel);
-    }
-
-    private int remainingDisruptorCapacity() {
-        final Disruptor<RingBufferLogEvent> temp = disruptor;
-        if (hasLog4jBeenShutDown(temp)) {
-            return -1;
-        }
-        return (int) temp.getRingBuffer().remainingCapacity();
-    }
-        /**
-         * Returns {@code true} if the specified disruptor is null.
-         */
-    private boolean hasLog4jBeenShutDown(final Disruptor<RingBufferLogEvent> 
aDisruptor) {
-        if (aDisruptor == null) { // LOG4J2-639
-            LOGGER.warn("Ignoring log event after log4j was shut down");
-            return true;
-        }
-        return false;
-    }
-
-    public boolean tryPublish(final RingBufferLogEventTranslator translator) {
-        // LOG4J2-639: catch NPE if disruptor field was set to null in stop()
-        try {
-            return disruptor.getRingBuffer().tryPublishEvent(translator);
-        } catch (final NullPointerException npe) {
-            LOGGER.warn("[{}] Ignoring log event after log4j was shut down.", 
contextName);
-            return false;
-        }
-    }
-
-    void enqueueLogMessageInfo(final RingBufferLogEventTranslator translator) {
-        // LOG4J2-639: catch NPE if disruptor field was set to null in stop()
-        try {
-            // Note: we deliberately access the volatile disruptor field 
afresh here.
-            // Avoiding this and using an older reference could result in 
adding a log event to the disruptor after it
-            // was shut down, which could cause the publishEvent method to 
hang and never return.
-            disruptor.publishEvent(translator);
-        } catch (final NullPointerException npe) {
-            LOGGER.warn("[{}] Ignoring log event after log4j was shut down.", 
contextName);
-        }
-    }
-
-    /**
-     * Returns whether it is allowed to store non-JDK classes in ThreadLocal 
objects for efficiency.
-     *
-     * @return whether AsyncLoggers are allowed to use ThreadLocal objects
-     * @since 2.5
-     * @see <a 
href="https://issues.apache.org/jira/browse/LOG4J2-1172";>LOG4J2-1172</a>
-     */
-    public boolean isUseThreadLocals() {
-        return useThreadLocalTranslator;
-    }
-
-    /**
-     * Signals this AsyncLoggerDisruptor whether it is allowed to store 
non-JDK classes in ThreadLocal objects for
-     * efficiency.
-     * <p>
-     * This property may be modified after the {@link #start()} method has 
been called.
-     * </p>
-     *
-     * @param allow whether AsyncLoggers are allowed to use ThreadLocal objects
-     * @since 2.5
-     * @see <a 
href="https://issues.apache.org/jira/browse/LOG4J2-1172";>LOG4J2-1172</a>
-     */
-    public void setUseThreadLocals(final boolean allow) {
-        useThreadLocalTranslator = allow;
-        LOGGER.trace("[{}] AsyncLoggers have been modified to use a {} 
translator", contextName,
-                useThreadLocalTranslator ? "threadlocal" : "vararg");
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+package org.apache.logging.log4j.core.async;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.jmx.RingBufferAdmin;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import com.lmax.disruptor.ExceptionHandler;
+import com.lmax.disruptor.RingBuffer;
+import com.lmax.disruptor.WaitStrategy;
+import com.lmax.disruptor.dsl.Disruptor;
+import com.lmax.disruptor.dsl.ProducerType;
+
+/**
+ * Helper class for async loggers: AsyncLoggerDisruptor handles the mechanics 
of working with the LMAX Disruptor, and
+ * works with its associated AsyncLoggerContext to synchronize the life cycle 
of the Disruptor and its thread with the
+ * life cycle of the context. The AsyncLoggerDisruptor of the context is 
shared by all AsyncLogger objects created by
+ * that AsyncLoggerContext.
+ */
+class AsyncLoggerDisruptor {
+    private static final int SLEEP_MILLIS_BETWEEN_DRAIN_ATTEMPTS = 50;
+    private static final int MAX_DRAIN_ATTEMPTS_BEFORE_SHUTDOWN = 200;
+    private static final StatusLogger LOGGER = StatusLogger.getLogger();
+
+    private volatile Disruptor<RingBufferLogEvent> disruptor;
+    private ExecutorService executor;
+    private String contextName;
+
+    private boolean useThreadLocalTranslator = true;
+    private long backgroundThreadId;
+    private AsyncQueueFullPolicy asyncQueueFullPolicy;
+    private int ringBufferSize;
+
+    AsyncLoggerDisruptor(final String contextName) {
+        this.contextName = contextName;
+    }
+
+    public String getContextName() {
+        return contextName;
+    }
+
+    public void setContextName(final String name) {
+        contextName = name;
+    }
+
+    Disruptor<RingBufferLogEvent> getDisruptor() {
+        return disruptor;
+    }
+
+    /**
+     * Creates and starts a new Disruptor and associated thread if none 
currently exists.
+     *
+     * @see #stop()
+     */
+    synchronized void start() {
+        if (disruptor != null) {
+            LOGGER.trace(
+                    "[{}] AsyncLoggerDisruptor not starting new disruptor for 
this context, using existing object.",
+                    contextName);
+            return;
+        }
+        LOGGER.trace("[{}] AsyncLoggerDisruptor creating new disruptor for 
this context.", contextName);
+        ringBufferSize = 
DisruptorUtil.calculateRingBufferSize("AsyncLogger.RingBufferSize");
+        final WaitStrategy waitStrategy = 
DisruptorUtil.createWaitStrategy("AsyncLogger.WaitStrategy");
+        executor = Executors.newSingleThreadExecutor(new 
DaemonThreadFactory("AsyncLogger[" + contextName + "]"));
+        backgroundThreadId = DisruptorUtil.getExecutorThreadId(executor);
+        asyncQueueFullPolicy = AsyncQueueFullPolicyFactory.create();
+
+        disruptor = new Disruptor<>(RingBufferLogEvent.FACTORY, 
ringBufferSize, executor, ProducerType.MULTI,
+                waitStrategy);
+
+        final ExceptionHandler<RingBufferLogEvent> errorHandler = 
DisruptorUtil.getAsyncLoggerExceptionHandler();
+        disruptor.handleExceptionsWith(errorHandler);
+
+        final RingBufferLogEventHandler[] handlers = {new 
RingBufferLogEventHandler()};
+        disruptor.handleEventsWith(handlers);
+
+        LOGGER.debug("[{}] Starting AsyncLogger disruptor for this context 
with ringbufferSize={}, waitStrategy={}, "
+                + "exceptionHandler={}...", contextName, 
disruptor.getRingBuffer().getBufferSize(), waitStrategy
+                .getClass().getSimpleName(), errorHandler);
+        disruptor.start();
+
+        LOGGER.trace("[{}] AsyncLoggers use a {} translator", contextName, 
useThreadLocalTranslator ? "threadlocal"
+                : "vararg");
+    }
+
+    /**
+     * Decreases the reference count. If the reference count reached zero, the 
Disruptor and its associated thread are
+     * shut down and their references set to {@code null}.
+     */
+    synchronized void stop() {
+        final Disruptor<RingBufferLogEvent> temp = getDisruptor();
+        if (temp == null) {
+            LOGGER.trace("[{}] AsyncLoggerDisruptor: disruptor for this 
context already shut down.", contextName);
+            return; // disruptor was already shut down by another thread
+        }
+        LOGGER.debug("[{}] AsyncLoggerDisruptor: shutting down disruptor for 
this context.", contextName);
+
+        // We must guarantee that publishing to the RingBuffer has stopped 
before we call disruptor.shutdown().
+        disruptor = null; // client code fails with NPE if log after stop. 
This is by design.
+
+        // Calling Disruptor.shutdown() will wait until all enqueued events 
are fully processed,
+        // but this waiting happens in a busy-spin. To avoid (postpone) 
wasting CPU,
+        // we sleep in short chunks, up to 10 seconds, waiting for the 
ringbuffer to drain.
+        for (int i = 0; hasBacklog(temp) && i < 
MAX_DRAIN_ATTEMPTS_BEFORE_SHUTDOWN; i++) {
+            try {
+                Thread.sleep(SLEEP_MILLIS_BETWEEN_DRAIN_ATTEMPTS); // give up 
the CPU for a while
+            } catch (final InterruptedException e) { // ignored
+            }
+        }
+        temp.shutdown(); // busy-spins until all events currently in the 
disruptor have been processed
+
+        LOGGER.trace("[{}] AsyncLoggerDisruptor: shutting down disruptor 
executor.", contextName);
+        executor.shutdown(); // finally, kill the processor thread
+        executor = null;
+
+        if 
(DiscardingAsyncQueueFullPolicy.getDiscardCount(asyncQueueFullPolicy) > 0) {
+            LOGGER.trace("AsyncLoggerDisruptor: {} discarded {} events.", 
asyncQueueFullPolicy,
+                    
DiscardingAsyncQueueFullPolicy.getDiscardCount(asyncQueueFullPolicy));
+        }
+    }
+
+    /**
+     * Returns {@code true} if the specified disruptor still has unprocessed 
events.
+     */
+    private static boolean hasBacklog(final Disruptor<?> theDisruptor) {
+        final RingBuffer<?> ringBuffer = theDisruptor.getRingBuffer();
+        return !ringBuffer.hasAvailableCapacity(ringBuffer.getBufferSize());
+    }
+
+    /**
+     * Creates and returns a new {@code RingBufferAdmin} that instruments the 
ringbuffer of the {@code AsyncLogger}.
+     *
+     * @param jmxContextName name of the {@code AsyncLoggerContext}
+     * @return a new {@code RingBufferAdmin} that instruments the ringbuffer
+     */
+    public RingBufferAdmin createRingBufferAdmin(final String jmxContextName) {
+        final RingBuffer<RingBufferLogEvent> ring = disruptor == null ? null : 
disruptor.getRingBuffer();
+        return RingBufferAdmin.forAsyncLogger(ring, jmxContextName);
+    }
+
+    EventRoute getEventRoute(final Level logLevel) {
+        final int remainingCapacity = remainingDisruptorCapacity();
+        if (remainingCapacity < 0) {
+            return EventRoute.DISCARD;
+        }
+        return asyncQueueFullPolicy.getRoute(backgroundThreadId, logLevel);
+    }
+
+    private int remainingDisruptorCapacity() {
+        final Disruptor<RingBufferLogEvent> temp = disruptor;
+        if (hasLog4jBeenShutDown(temp)) {
+            return -1;
+        }
+        return (int) temp.getRingBuffer().remainingCapacity();
+    }
+        /**
+         * Returns {@code true} if the specified disruptor is null.
+         */
+    private boolean hasLog4jBeenShutDown(final Disruptor<RingBufferLogEvent> 
aDisruptor) {
+        if (aDisruptor == null) { // LOG4J2-639
+            LOGGER.warn("Ignoring log event after log4j was shut down");
+            return true;
+        }
+        return false;
+    }
+
+    public boolean tryPublish(final RingBufferLogEventTranslator translator) {
+        // LOG4J2-639: catch NPE if disruptor field was set to null in stop()
+        try {
+            return disruptor.getRingBuffer().tryPublishEvent(translator);
+        } catch (final NullPointerException npe) {
+            LOGGER.warn("[{}] Ignoring log event after log4j was shut down.", 
contextName);
+            return false;
+        }
+    }
+
+    void enqueueLogMessageInfo(final RingBufferLogEventTranslator translator) {
+        // LOG4J2-639: catch NPE if disruptor field was set to null in stop()
+        try {
+            // Note: we deliberately access the volatile disruptor field 
afresh here.
+            // Avoiding this and using an older reference could result in 
adding a log event to the disruptor after it
+            // was shut down, which could cause the publishEvent method to 
hang and never return.
+            disruptor.publishEvent(translator);
+        } catch (final NullPointerException npe) {
+            LOGGER.warn("[{}] Ignoring log event after log4j was shut down.", 
contextName);
+        }
+    }
+
+    /**
+     * Returns whether it is allowed to store non-JDK classes in ThreadLocal 
objects for efficiency.
+     *
+     * @return whether AsyncLoggers are allowed to use ThreadLocal objects
+     * @since 2.5
+     * @see <a 
href="https://issues.apache.org/jira/browse/LOG4J2-1172";>LOG4J2-1172</a>
+     */
+    public boolean isUseThreadLocals() {
+        return useThreadLocalTranslator;
+    }
+
+    /**
+     * Signals this AsyncLoggerDisruptor whether it is allowed to store 
non-JDK classes in ThreadLocal objects for
+     * efficiency.
+     * <p>
+     * This property may be modified after the {@link #start()} method has 
been called.
+     * </p>
+     *
+     * @param allow whether AsyncLoggers are allowed to use ThreadLocal objects
+     * @since 2.5
+     * @see <a 
href="https://issues.apache.org/jira/browse/LOG4J2-1172";>LOG4J2-1172</a>
+     */
+    public void setUseThreadLocals(final boolean allow) {
+        useThreadLocalTranslator = allow;
+        LOGGER.trace("[{}] AsyncLoggers have been modified to use a {} 
translator", contextName,
+                useThreadLocalTranslator ? "threadlocal" : "vararg");
+    }
+}

Reply via email to