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

pkarwasz pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


The following commit(s) were added to refs/heads/release-2.x by this push:
     new 1e90f9aeb1 [LOG4J2-3483] Adds support for Apache Extras 
RollingFileAppender
1e90f9aeb1 is described below

commit 1e90f9aeb1a559bbbb7d2510a93fe718505ba30c
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Mon May 23 22:41:09 2022 +0200

    [LOG4J2-3483] Adds support for Apache Extras RollingFileAppender
    
    Adds a builder for Apache Extras' `RollingFileAppender`.
---
 .../org/apache/log4j/builders/AbstractBuilder.java |  27 +++
 .../org/apache/log4j/builders/BuilderManager.java  |   7 +
 .../EnhancedRollingFileAppenderBuilder.java        | 241 +++++++++++++++++++++
 .../rolling/CompositeTriggeringPolicyBuilder.java  |  74 +++++++
 .../rolling/SizeBasedTriggeringPolicyBuilder.java  |  75 +++++++
 .../rolling/TimeBasedRollingPolicyBuilder.java     |  56 +++++
 .../builders/rolling/TriggeringPolicyBuilder.java  |  24 ++
 .../log4j/config/PropertiesConfiguration.java      |   9 +
 .../org/apache/log4j/xml/XmlConfiguration.java     |   7 +
 .../config/AbstractLog4j1ConfigurationTest.java    |  73 +++++++
 .../log4j/config/PropertiesConfigurationTest.java  |  11 +-
 .../apache/log4j/config/XmlConfigurationTest.java  |  26 ++-
 .../log4j-EnhancedRollingFileAppender.properties   |  66 ++++++
 .../log4j-EnhancedRollingFileAppender.xml          |  94 ++++++++
 src/changes/changes.xml                            |   4 +
 15 files changed, 792 insertions(+), 2 deletions(-)

diff --git 
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java 
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
index 6bf0c2cbc0..16240f45a5 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
@@ -24,6 +24,7 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.log4j.bridge.FilterAdapter;
@@ -120,6 +121,19 @@ public abstract class AbstractBuilder<T> implements 
Builder<T> {
         return defaultValue;
     }
 
+    public long getLongProperty(final String key, final long defaultValue) {
+        String value = null;
+        try {
+            value = getProperty(key);
+            if (value != null) {
+                return Long.parseLong(value);
+            }
+        } catch (final Exception ex) {
+            LOGGER.warn("Error converting value {} of {} to a long: {}", 
value, key, ex.getMessage());
+        }
+        return defaultValue;
+    }
+
     protected String getNameAttribute(final Element element) {
         return element.getAttribute(NAME_ATTR);
     }
@@ -195,6 +209,19 @@ public abstract class AbstractBuilder<T> implements 
Builder<T> {
         }
     }
 
+    protected void set(final String name, final Element element, AtomicLong 
ref) {
+        final String value = getValueAttribute(element);
+        if (value == null) {
+            LOGGER.warn("No value for {} parameter, using default {}", name, 
ref);
+        } else {
+            try {
+                ref.set(Long.parseLong(value));
+            } catch (NumberFormatException e) {
+                LOGGER.warn("{} parsing {} parameter, using default {}: {}", 
e.getClass().getName(), name, ref, e.getMessage(), e);
+            }
+        }
+    }
+
     protected void set(final String name, final Element element, 
AtomicReference<String> ref) {
         final String value = getValueAttribute(element);
         if (value == null) {
diff --git 
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java 
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java
index 226fa3a865..dba7d267df 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java
@@ -32,11 +32,13 @@ import org.apache.log4j.builders.appender.AppenderBuilder;
 import org.apache.log4j.builders.filter.FilterBuilder;
 import org.apache.log4j.builders.layout.LayoutBuilder;
 import org.apache.log4j.builders.rewrite.RewritePolicyBuilder;
+import org.apache.log4j.builders.rolling.TriggeringPolicyBuilder;
 import org.apache.log4j.config.PropertiesConfiguration;
 import org.apache.log4j.rewrite.RewritePolicy;
 import org.apache.log4j.spi.Filter;
 import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
 import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
 import org.apache.logging.log4j.core.config.plugins.util.PluginType;
 import org.apache.logging.log4j.status.StatusLogger;
@@ -161,4 +163,9 @@ public class BuilderManager {
                 INVALID_REWRITE_POLICY);
     }
 
+    public TriggeringPolicy parseTriggeringPolicy(final String className, 
final Element policyElement,
+            final XmlConfiguration config) {
+        return newInstance(this.<TriggeringPolicyBuilder>getPlugin(className), 
b -> b.parse(policyElement, config),
+                (TriggeringPolicy) null);
+    }
 }
diff --git 
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/EnhancedRollingFileAppenderBuilder.java
 
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/EnhancedRollingFileAppenderBuilder.java
new file mode 100644
index 0000000000..91f124167a
--- /dev/null
+++ 
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/EnhancedRollingFileAppenderBuilder.java
@@ -0,0 +1,241 @@
+/*
+ * 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.log4j.builders.appender;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.config.Log4j1Configuration.THRESHOLD_PARAM;
+import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.bridge.LayoutAdapter;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.spi.Filter;
+import org.apache.log4j.xml.XmlConfiguration;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.appender.RollingFileAppender;
+import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
+import 
org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.w3c.dom.Element;
+
+/**
+ * Build a File Appender
+ */
+@Plugin(name = "org.apache.log4j.rolling.RollingFileAppender", category = 
CATEGORY)
+
+public class EnhancedRollingFileAppenderBuilder extends 
AbstractBuilder<Appender> implements AppenderBuilder<Appender> {
+
+    private static final String TIME_BASED_ROLLING_POLICY = 
"org.apache.log4j.rolling.TimeBasedRollingPolicy";
+    private static final String FIXED_WINDOW_ROLLING_POLICY = 
"org.apache.log4j.rolling.FixedWindowRollingPolicy";
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String TRIGGERING_TAG = "triggeringPolicy";
+    private static final String ROLLING_TAG = "rollingPolicy";
+    private static final int DEFAULT_MIN_INDEX = 1;
+    private static final int DEFAULT_MAX_INDEX = 7;
+    private static final String ACTIVE_FILE_PARAM = "ActiveFileName";
+    private static final String FILE_PATTERN_PARAM = "FileNamePattern";
+    private static final String MIN_INDEX_PARAM = "MinIndex";
+    private static final String MAX_INDEX_PARAM = "MaxIndex";
+
+    public EnhancedRollingFileAppenderBuilder() {
+    }
+
+    public EnhancedRollingFileAppenderBuilder(final String prefix, final 
Properties properties) {
+        super(prefix, properties);
+    }
+
+    private void parseRollingPolicy(Element element, XmlConfiguration 
configuration,
+            AtomicReference<String> rollingPolicyClassName, 
AtomicReference<String> activeFileName,
+            AtomicReference<String> fileNamePattern, AtomicInteger minIndex,
+            AtomicInteger maxIndex) {
+        
rollingPolicyClassName.set(configuration.subst(element.getAttribute("class"), 
getProperties()));
+        forEachElement(element.getChildNodes(), currentElement -> {
+            switch (currentElement.getTagName()) {
+                case PARAM_TAG:
+                    switch (getNameAttributeKey(currentElement)) {
+                        case ACTIVE_FILE_PARAM:
+                            set(ACTIVE_FILE_PARAM, currentElement, 
activeFileName);
+                            break;
+                        case FILE_PATTERN_PARAM:
+                            set(FILE_PATTERN_PARAM, currentElement, 
fileNamePattern);
+                            break;
+                        case MIN_INDEX_PARAM:
+                            set(MIN_INDEX_PARAM, currentElement, minIndex);
+                            break;
+                        case MAX_INDEX_PARAM:
+                            set(MAX_INDEX_PARAM, currentElement, maxIndex);
+                    }
+            }
+        });
+    }
+
+    @Override
+    public Appender parseAppender(Element element, XmlConfiguration 
configuration) {
+        // FileAppender
+        final String name = getNameAttribute(element);
+        final AtomicReference<Layout> layout = new AtomicReference<>();
+        final AtomicReference<Filter> filter = new AtomicReference<>();
+        final AtomicReference<String> fileName = new AtomicReference<>();
+        final AtomicReference<String> level = new AtomicReference<>();
+        final AtomicBoolean immediateFlush = new AtomicBoolean(true);
+        final AtomicBoolean append = new AtomicBoolean(true);
+        final AtomicBoolean bufferedIo = new AtomicBoolean();
+        final AtomicInteger bufferSize = new AtomicInteger(8192);
+        // specific to RollingFileAppender
+        final AtomicReference<String> rollingPolicyClassName = new 
AtomicReference<>();
+        final AtomicReference<String> activeFileName = new AtomicReference<>();
+        final AtomicReference<String> fileNamePattern = new 
AtomicReference<>();
+        final AtomicInteger minIndex = new AtomicInteger(DEFAULT_MIN_INDEX);
+        final AtomicInteger maxIndex = new AtomicInteger(DEFAULT_MAX_INDEX);
+        final AtomicReference<TriggeringPolicy> triggeringPolicy = new 
AtomicReference<>();
+        forEachElement(element.getChildNodes(), currentElement -> {
+            switch (currentElement.getTagName()) {
+                case ROLLING_TAG:
+                    parseRollingPolicy(currentElement, configuration, 
rollingPolicyClassName, activeFileName,
+                            fileNamePattern, minIndex, maxIndex);
+                    break;
+                case TRIGGERING_TAG:
+                    
triggeringPolicy.set(configuration.parseTriggeringPolicy(currentElement));
+                    break;
+                case LAYOUT_TAG:
+                    layout.set(configuration.parseLayout(currentElement));
+                    break;
+                case FILTER_TAG:
+                    configuration.addFilter(filter, currentElement);
+                    break;
+                case PARAM_TAG:
+                    switch (getNameAttributeKey(currentElement)) {
+                        case FILE_PARAM:
+                            set(FILE_PARAM, currentElement, fileName);
+                            break;
+                        case APPEND_PARAM:
+                            set(APPEND_PARAM, currentElement, append);
+                            break;
+                        case BUFFERED_IO_PARAM:
+                            set(BUFFERED_IO_PARAM, currentElement, bufferedIo);
+                            break;
+                        case BUFFER_SIZE_PARAM:
+                            set(BUFFER_SIZE_PARAM, currentElement, bufferSize);
+                            break;
+                        case THRESHOLD_PARAM:
+                            set(THRESHOLD_PARAM, currentElement, level);
+                            break;
+                        case IMMEDIATE_FLUSH_PARAM:
+                            set(IMMEDIATE_FLUSH_PARAM, currentElement, 
immediateFlush);
+                            break;
+                    }
+                    break;
+            }
+        });
+        return createAppender(name, layout.get(), filter.get(), 
fileName.get(), level.get(), immediateFlush.get(),
+                append.get(), bufferedIo.get(), bufferSize.get(), 
rollingPolicyClassName.get(), activeFileName.get(),
+                fileNamePattern.get(), minIndex.get(), maxIndex.get(), 
triggeringPolicy.get(), configuration);
+    }
+
+    @Override
+    public Appender parseAppender(String name, String appenderPrefix, String 
layoutPrefix, String filterPrefix,
+            Properties props, PropertiesConfiguration configuration) {
+        final Layout layout = configuration.parseLayout(layoutPrefix, name, 
props);
+        final Filter filter = configuration.parseAppenderFilters(props, 
filterPrefix, name);
+        final String level = getProperty(THRESHOLD_PARAM);
+        final String fileName = getProperty(FILE_PARAM);
+        final boolean append = getBooleanProperty(APPEND_PARAM, true);
+        final boolean immediateFlush = 
getBooleanProperty(IMMEDIATE_FLUSH_PARAM, true);
+        final boolean bufferedIo = getBooleanProperty(BUFFERED_IO_PARAM, 
false);
+        final int bufferSize = Integer.parseInt(getProperty(BUFFER_SIZE_PARAM, 
"8192"));
+        final String rollingPolicyClassName = getProperty(ROLLING_TAG);
+        final int minIndex = getIntegerProperty(ROLLING_TAG + "." + 
MIN_INDEX_PARAM, DEFAULT_MIN_INDEX);
+        final int maxIndex = getIntegerProperty(ROLLING_TAG + "." + 
MAX_INDEX_PARAM, DEFAULT_MAX_INDEX);
+        final String activeFileName = getProperty(ROLLING_TAG + "." + 
ACTIVE_FILE_PARAM);
+        final String fileNamePattern = getProperty(ROLLING_TAG + "." + 
FILE_PATTERN_PARAM);
+        final TriggeringPolicy triggeringPolicy = 
configuration.parseTriggeringPolicy(props,
+                appenderPrefix + "." + TRIGGERING_TAG);
+        return createAppender(name, layout, filter, fileName, level, 
immediateFlush, append, bufferedIo, bufferSize,
+                rollingPolicyClassName, activeFileName, fileNamePattern, 
minIndex, maxIndex, triggeringPolicy,
+                configuration);
+    }
+
+    private Appender createAppender(final String name, final Layout layout, 
final Filter filter, final String fileName,
+            final String level, final boolean immediateFlush, final boolean 
append, final boolean bufferedIo,
+            final int bufferSize, final String rollingPolicyClassName, final 
String activeFileName,
+            final String fileNamePattern, final int minIndex, final int 
maxIndex,
+            final TriggeringPolicy triggeringPolicy, final Configuration 
configuration) {
+        final org.apache.logging.log4j.core.Layout<?> fileLayout = 
LayoutAdapter.adapt(layout);
+        final boolean actualImmediateFlush = bufferedIo ? false : 
immediateFlush;
+        final org.apache.logging.log4j.core.Filter fileFilter = 
buildFilters(level, filter);
+        if (rollingPolicyClassName == null) {
+            LOGGER.error("Unable to create RollingFileAppender, no rolling 
policy provided.");
+            return null;
+        }
+        final String actualFileName = activeFileName != null ? activeFileName 
: fileName;
+        if (actualFileName == null) {
+            LOGGER.error("Unable to create RollingFileAppender, no file name 
provided.");
+            return null;
+        }
+        if (fileNamePattern == null) {
+            LOGGER.error("Unable to create RollingFileAppender, no file name 
pattern provided.");
+            return null;
+        }
+        final DefaultRolloverStrategy.Builder rolloverStrategyBuilder = 
DefaultRolloverStrategy.newBuilder();
+        switch (rollingPolicyClassName) {
+            case FIXED_WINDOW_ROLLING_POLICY:
+                
rolloverStrategyBuilder.withMin(Integer.toString(minIndex)).withMax(Integer.toString(maxIndex));
+                break;
+            case TIME_BASED_ROLLING_POLICY:
+                break;
+            default:
+                LOGGER.warn("Unsupported rolling policy: {}", 
rollingPolicyClassName);
+        }
+        final TriggeringPolicy actualTriggeringPolicy;
+        if (triggeringPolicy != null) {
+            actualTriggeringPolicy = triggeringPolicy;
+        } else if (rollingPolicyClassName.equals(TIME_BASED_ROLLING_POLICY)) {
+            actualTriggeringPolicy = 
TimeBasedTriggeringPolicy.newBuilder().build();
+        } else {
+            LOGGER.error("Unable to create RollingFileAppender, no triggering 
policy provided.");
+            return null;
+        }
+        return AppenderWrapper.adapt(RollingFileAppender.newBuilder()
+                .withAppend(append)
+                .setBufferedIo(bufferedIo)
+                .setBufferSize(bufferedIo ? bufferSize : 0)
+                .setConfiguration(configuration)
+                .withFileName(actualFileName)
+                .withFilePattern(fileNamePattern)
+                .setFilter(fileFilter)
+                .setImmediateFlush(actualImmediateFlush)
+                .setLayout(fileLayout)
+                .setName(name)
+                .withPolicy(actualTriggeringPolicy)
+                .withStrategy(rolloverStrategyBuilder.build())
+                .build());
+    }
+}
diff --git 
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/CompositeTriggeringPolicyBuilder.java
 
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/CompositeTriggeringPolicyBuilder.java
new file mode 100644
index 0000000000..ece2a0e80a
--- /dev/null
+++ 
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/CompositeTriggeringPolicyBuilder.java
@@ -0,0 +1,74 @@
+/*
+ * 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.log4j.builders.rolling;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
+import 
org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.w3c.dom.Element;
+
+@Plugin(name = "org.apache.log4j.rolling.CompositeTriggeringPolicy", category 
= CATEGORY)
+public class CompositeTriggeringPolicyBuilder extends 
AbstractBuilder<TriggeringPolicy>
+        implements TriggeringPolicyBuilder {
+
+    private static final TriggeringPolicy[] EMPTY_TRIGGERING_POLICIES = new 
TriggeringPolicy[0];
+    private static final String POLICY_TAG = "triggeringPolicy";
+
+    public CompositeTriggeringPolicyBuilder() {
+        super();
+    }
+
+    public CompositeTriggeringPolicyBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+    @Override
+    public CompositeTriggeringPolicy parse(Element element, XmlConfiguration 
configuration) {
+        final List<TriggeringPolicy> policies = new ArrayList<>();
+        forEachElement(element.getChildNodes(), currentElement -> {
+            switch (currentElement.getTagName()) {
+                case POLICY_TAG:
+                    final TriggeringPolicy policy = 
configuration.parseTriggeringPolicy(currentElement);
+                    if (policy != null) {
+                        policies.add(policy);
+                    }
+                    break;
+            }
+        });
+        return createTriggeringPolicy(policies);
+    }
+
+    @Override
+    public CompositeTriggeringPolicy parse(PropertiesConfiguration 
configuration) {
+        return createTriggeringPolicy(Collections.emptyList());
+    }
+
+    private CompositeTriggeringPolicy 
createTriggeringPolicy(List<TriggeringPolicy> policies) {
+        return 
CompositeTriggeringPolicy.createPolicy(policies.toArray(EMPTY_TRIGGERING_POLICIES));
+    }
+}
diff --git 
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/SizeBasedTriggeringPolicyBuilder.java
 
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/SizeBasedTriggeringPolicyBuilder.java
new file mode 100644
index 0000000000..3ab1402b82
--- /dev/null
+++ 
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/SizeBasedTriggeringPolicyBuilder.java
@@ -0,0 +1,75 @@
+/*
+ * 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.log4j.builders.rolling;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
+import 
org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.w3c.dom.Element;
+
+@Plugin(name = "org.apache.log4j.rolling.SizeBasedTriggeringPolicy", category 
= CATEGORY)
+public class SizeBasedTriggeringPolicyBuilder extends 
AbstractBuilder<TriggeringPolicy>
+        implements TriggeringPolicyBuilder {
+
+    private static final String MAX_SIZE_PARAM = "MaxFileSize";
+    private static final long DEFAULT_MAX_SIZE = 10 * 1024 * 1024;
+
+    public SizeBasedTriggeringPolicyBuilder() {
+        super();
+    }
+
+    public SizeBasedTriggeringPolicyBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+    @Override
+    public SizeBasedTriggeringPolicy parse(Element element, XmlConfiguration 
configuration) {
+        final AtomicLong maxSize = new AtomicLong(DEFAULT_MAX_SIZE);
+        forEachElement(element.getChildNodes(), currentElement -> {
+            switch (currentElement.getTagName()) {
+                case PARAM_TAG:
+                    switch (getNameAttributeKey(currentElement)) {
+                        case MAX_SIZE_PARAM:
+                            set(MAX_SIZE_PARAM, currentElement, maxSize);
+                            break;
+                    }
+                    break;
+            }
+        });
+        return createTriggeringPolicy(maxSize.get());
+    }
+
+    @Override
+    public SizeBasedTriggeringPolicy parse(PropertiesConfiguration 
configuration) {
+        final long maxSize = getLongProperty(MAX_SIZE_PARAM, DEFAULT_MAX_SIZE);
+        return createTriggeringPolicy(maxSize);
+    }
+
+    private SizeBasedTriggeringPolicy createTriggeringPolicy(long maxSize) {
+        return SizeBasedTriggeringPolicy.createPolicy(Long.toString(maxSize));
+    }
+}
diff --git 
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/TimeBasedRollingPolicyBuilder.java
 
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/TimeBasedRollingPolicyBuilder.java
new file mode 100644
index 0000000000..70f3ee3645
--- /dev/null
+++ 
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/TimeBasedRollingPolicyBuilder.java
@@ -0,0 +1,56 @@
+/*
+ * 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.log4j.builders.rolling;
+
+import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+
+import java.util.Properties;
+
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
+import 
org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.w3c.dom.Element;
+
+@Plugin(name = "org.apache.log4j.rolling.TimeBasedRollingPolicy", category = 
CATEGORY)
+public class TimeBasedRollingPolicyBuilder extends 
AbstractBuilder<TriggeringPolicy>
+        implements TriggeringPolicyBuilder {
+
+    public TimeBasedRollingPolicyBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+    public TimeBasedRollingPolicyBuilder() {
+        super();
+    }
+
+    @Override
+    public TimeBasedTriggeringPolicy parse(Element element, XmlConfiguration 
configuration) {
+        return createTriggeringPolicy();
+    }
+
+    @Override
+    public TimeBasedTriggeringPolicy parse(PropertiesConfiguration 
configuration) {
+        return createTriggeringPolicy();
+    }
+
+    private TimeBasedTriggeringPolicy createTriggeringPolicy() {
+        return TimeBasedTriggeringPolicy.newBuilder().build();
+    }
+}
diff --git 
a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/TriggeringPolicyBuilder.java
 
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/TriggeringPolicyBuilder.java
new file mode 100644
index 0000000000..f7dfff12a9
--- /dev/null
+++ 
b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/rolling/TriggeringPolicyBuilder.java
@@ -0,0 +1,24 @@
+/*
+ * 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.log4j.builders.rolling;
+
+import org.apache.log4j.builders.Parser;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
+
+public interface TriggeringPolicyBuilder extends Parser<TriggeringPolicy> {
+    // NOP
+}
diff --git 
a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
 
b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
index 2378edfd6e..ebfa443568 100644
--- 
a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
+++ 
b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
@@ -43,6 +43,7 @@ import org.apache.log4j.spi.Filter;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.Filter.Result;
 import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.ConfigurationSource;
 import org.apache.logging.log4j.core.config.LoggerConfig;
@@ -590,6 +591,14 @@ public class PropertiesConfiguration extends 
Log4j1Configuration {
         return filter;
     }
 
+    public TriggeringPolicy parseTriggeringPolicy(final Properties props, 
final String policyPrefix) {
+        final String policyClass = OptionConverter.findAndSubst(policyPrefix, 
props);
+        if (policyClass == null) {
+            return null;
+        }
+        return manager.parse(policyClass, policyPrefix, props, this, null);
+    }
+
     private static <T> T newInstanceOf(final String className, final String 
type) {
         try {
             return LoaderUtil.newInstanceOf(className);
diff --git 
a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java 
b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
index 7c43c15c80..a24a3515a0 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
@@ -44,6 +44,7 @@ import org.apache.log4j.spi.AppenderAttachable;
 import org.apache.log4j.spi.ErrorHandler;
 import org.apache.log4j.spi.Filter;
 import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
 import org.apache.logging.log4j.core.Filter.Result;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.ConfigurationSource;
@@ -655,6 +656,12 @@ public class XmlConfiguration extends Log4j1Configuration {
         return null;
     }
 
+    public TriggeringPolicy parseTriggeringPolicy(Element policyElement) {
+        String className = subst(policyElement.getAttribute(CLASS_ATTR));
+        LOGGER.debug("Parsing triggering policy of class: \"{}\"", className);
+        return manager.parseTriggeringPolicy(className, policyElement, this);
+    }
+
     /**
      * Used internally to parse a level  element.
      */
diff --git 
a/log4j-1.2-api/src/test/java/org/apache/log4j/config/AbstractLog4j1ConfigurationTest.java
 
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/AbstractLog4j1ConfigurationTest.java
index 3524292dc8..34fdb03d5b 100644
--- 
a/log4j-1.2-api/src/test/java/org/apache/log4j/config/AbstractLog4j1ConfigurationTest.java
+++ 
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/AbstractLog4j1ConfigurationTest.java
@@ -26,6 +26,7 @@ import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
@@ -77,6 +78,12 @@ public abstract class AbstractLog4j1ConfigurationTest {
 
     abstract Configuration getConfiguration(String configResourcePrefix) 
throws URISyntaxException, IOException;
 
+    protected InputStream getResourceAsStream(String configResource) throws 
IOException {
+        final InputStream is = 
getClass().getClassLoader().getResourceAsStream(configResource);
+        assertNotNull(is);
+        return is;
+    }
+
     protected LoggerContext configure(String configResourcePrefix) throws 
URISyntaxException, IOException {
         Configurator.reconfigure(getConfiguration(configResourcePrefix));
         return (LoggerContext) 
org.apache.logging.log4j.LogManager.getContext(false);
@@ -538,4 +545,70 @@ public abstract class AbstractLog4j1ConfigurationTest {
             assertEquals(1, legacyAppender.getEvents().size());
         }
     }
+
+    protected void testEnhancedRollingFileAppender(Configuration 
configuration) {
+        Appender appender;
+        TriggeringPolicy policy;
+        RolloverStrategy strategy;
+        DefaultRolloverStrategy defaultRolloverStrategy;
+        // Time policy with default attributes
+        appender = configuration.getAppender("DEFAULT_TIME");
+        assertTrue("is RollingFileAppender", appender instanceof 
RollingFileAppender);
+        final RollingFileAppender defaultTime = (RollingFileAppender) appender;
+        assertEquals("append", true, defaultTime.getManager().isAppend());
+        assertEquals("bufferSize", 8192, 
defaultTime.getManager().getBufferSize());
+        assertEquals("immediateFlush", true, defaultTime.getImmediateFlush());
+        assertEquals("fileName", 
"target/EnhancedRollingFileAppender/defaultTime.log", 
defaultTime.getFileName());
+        assertEquals("filePattern", 
"target/EnhancedRollingFileAppender/defaultTime.%d{yyyy-MM-dd}.log",
+                defaultTime.getFilePattern());
+        policy = defaultTime.getTriggeringPolicy();
+        assertTrue("is TimeBasedTriggeringPolicy", policy instanceof 
TimeBasedTriggeringPolicy);
+        // Size policy with default attributes
+        appender = configuration.getAppender("DEFAULT_SIZE");
+        assertTrue("is RollingFileAppender", appender instanceof 
RollingFileAppender);
+        final RollingFileAppender defaultSize = (RollingFileAppender) appender;
+        assertEquals("append", true, defaultSize.getManager().isAppend());
+        assertEquals("bufferSize", 8192, 
defaultSize.getManager().getBufferSize());
+        assertEquals("immediateFlush", true, defaultSize.getImmediateFlush());
+        assertEquals("fileName", 
"target/EnhancedRollingFileAppender/defaultSize.log", 
defaultSize.getFileName());
+        assertEquals("filePattern", 
"target/EnhancedRollingFileAppender/defaultSize.%i.log",
+                defaultSize.getFilePattern());
+        policy = defaultSize.getTriggeringPolicy();
+        assertTrue("is SizeBasedTriggeringPolicy", policy instanceof 
SizeBasedTriggeringPolicy);
+        assertEquals(10 * 1024 * 1024L, ((SizeBasedTriggeringPolicy) 
policy).getMaxFileSize());
+        strategy = defaultSize.getManager().getRolloverStrategy();
+        assertTrue("is DefaultRolloverStrategy", strategy instanceof 
DefaultRolloverStrategy);
+        defaultRolloverStrategy = (DefaultRolloverStrategy) strategy;
+        assertEquals(1, defaultRolloverStrategy.getMinIndex());
+        assertEquals(7, defaultRolloverStrategy.getMaxIndex());
+        // Time policy with custom attributes
+        appender = configuration.getAppender("TIME");
+        assertTrue("is RollingFileAppender", appender instanceof 
RollingFileAppender);
+        final RollingFileAppender time = (RollingFileAppender) appender;
+        assertEquals("append", false, time.getManager().isAppend());
+        assertEquals("bufferSize", 1000, time.getManager().getBufferSize());
+        assertEquals("immediateFlush", false, time.getImmediateFlush());
+        assertEquals("fileName", 
"target/EnhancedRollingFileAppender/time.log", time.getFileName());
+        assertEquals("filePattern", 
"target/EnhancedRollingFileAppender/time.%d{yyyy-MM-dd}.log",
+                time.getFilePattern());
+        policy = time.getTriggeringPolicy();
+        assertTrue("is TimeBasedTriggeringPolicy", policy instanceof 
TimeBasedTriggeringPolicy);
+        // Size policy with custom attributes
+        appender = configuration.getAppender("SIZE");
+        assertTrue("is RollingFileAppender", appender instanceof 
RollingFileAppender);
+        final RollingFileAppender size = (RollingFileAppender) appender;
+        assertEquals("append", false, size.getManager().isAppend());
+        assertEquals("bufferSize", 1000, size.getManager().getBufferSize());
+        assertEquals("immediateFlush", false, size.getImmediateFlush());
+        assertEquals("fileName", 
"target/EnhancedRollingFileAppender/size.log", size.getFileName());
+        assertEquals("filePattern", 
"target/EnhancedRollingFileAppender/size.%i.log", size.getFilePattern());
+        policy = size.getTriggeringPolicy();
+        assertTrue("is SizeBasedTriggeringPolicy", policy instanceof 
SizeBasedTriggeringPolicy);
+        assertEquals(10_000_000L, ((SizeBasedTriggeringPolicy) 
policy).getMaxFileSize());
+        strategy = size.getManager().getRolloverStrategy();
+        assertTrue("is DefaultRolloverStrategy", strategy instanceof 
DefaultRolloverStrategy);
+        defaultRolloverStrategy = (DefaultRolloverStrategy) strategy;
+        assertEquals(11, defaultRolloverStrategy.getMinIndex());
+        assertEquals(20, defaultRolloverStrategy.getMaxIndex());
+    }
 }
diff --git 
a/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java
 
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java
index d07f33871d..219848abba 100644
--- 
a/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java
+++ 
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java
@@ -64,7 +64,7 @@ public class PropertiesConfigurationTest extends 
AbstractLog4j1ConfigurationTest
     @Override
     Configuration getConfiguration(String configResourcePrefix) throws 
URISyntaxException, IOException {
         final String configResource = configResourcePrefix + SUFFIX;
-        final InputStream inputStream = 
ClassLoader.getSystemResourceAsStream(configResource);
+        final InputStream inputStream = getResourceAsStream(configResource);
         final ConfigurationSource source = new 
ConfigurationSource(inputStream);
         final LoggerContext context = LoggerContext.getContext(false);
         final Configuration configuration = new 
PropertiesConfigurationFactory().getConfiguration(context, source);
@@ -317,4 +317,13 @@ public class PropertiesConfigurationTest extends 
AbstractLog4j1ConfigurationTest
         super.testGlobalThreshold();
     }
 
+    @Test
+    public void testEnhancedRollingFileAppender() throws Exception {
+        try (final LoggerContext ctx = 
configure("config-1.2/log4j-EnhancedRollingFileAppender")) {
+            final Configuration configuration = ctx.getConfiguration();
+            assertNotNull(configuration);
+            testEnhancedRollingFileAppender(configuration);
+        }
+    }
+
 }
diff --git 
a/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationTest.java 
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationTest.java
index e1da067b79..bec639f202 100644
--- 
a/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationTest.java
+++ 
b/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationTest.java
@@ -18,6 +18,7 @@ package org.apache.log4j.config;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import java.io.File;
 import java.io.IOException;
@@ -34,6 +35,11 @@ import org.apache.log4j.spi.LoggingEvent;
 import org.apache.log4j.xml.XmlConfigurationFactory;
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.RollingFileAppender;
+import 
org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
+import 
org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
+import 
org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
+import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.ConfigurationSource;
 import org.junit.Test;
@@ -48,7 +54,7 @@ public class XmlConfigurationTest extends 
AbstractLog4j1ConfigurationTest {
     @Override
     Configuration getConfiguration(String configResourcePrefix) throws 
URISyntaxException, IOException {
         final String configResource = configResourcePrefix + SUFFIX;
-        final InputStream inputStream = 
ClassLoader.getSystemResourceAsStream(configResource);
+        final InputStream inputStream = getResourceAsStream(configResource);
         final ConfigurationSource source = new 
ConfigurationSource(inputStream);
         final LoggerContext context = LoggerContext.getContext(false);
         final Configuration configuration = new 
XmlConfigurationFactory().getConfiguration(context, source);
@@ -178,4 +184,22 @@ public class XmlConfigurationTest extends 
AbstractLog4j1ConfigurationTest {
         super.testGlobalThreshold();
     }
 
+    @Test
+    public void testEnhancedRollingFileAppender() throws Exception {
+        try (final LoggerContext ctx = 
configure("config-1.2/log4j-EnhancedRollingFileAppender")) {
+            final Configuration configuration = ctx.getConfiguration();
+            assertNotNull(configuration);
+            testEnhancedRollingFileAppender(configuration);
+            // Only supported through XML configuration
+            final Appender appender = configuration.getAppender("MIXED");
+            assertTrue("is RollingFileAppender", appender instanceof 
RollingFileAppender);
+            final TriggeringPolicy policy = ((RollingFileAppender) 
appender).getTriggeringPolicy();
+            assertTrue("is CompositeTriggeringPolicy", policy instanceof 
CompositeTriggeringPolicy);
+            final TriggeringPolicy[] policies = ((CompositeTriggeringPolicy) 
policy).getTriggeringPolicies();
+            assertEquals(2, policies.length);
+            assertTrue("is TimeBasedTriggeringPolicy", policies[0] instanceof 
TimeBasedTriggeringPolicy);
+            assertTrue("is SizeBasedTriggeringPolicy", policies[1] instanceof 
SizeBasedTriggeringPolicy);
+        }
+    }
+
 }
diff --git 
a/log4j-1.2-api/src/test/resources/config-1.2/log4j-EnhancedRollingFileAppender.properties
 
b/log4j-1.2-api/src/test/resources/config-1.2/log4j-EnhancedRollingFileAppender.properties
new file mode 100644
index 0000000000..8e59ee43c6
--- /dev/null
+++ 
b/log4j-1.2-api/src/test/resources/config-1.2/log4j-EnhancedRollingFileAppender.properties
@@ -0,0 +1,66 @@
+#
+# 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.
+#
+
+###############################################################################
+#
+# Log4J 1.2 Configuration.
+#
+
+log4j.rootLogger=TRACE, DEFAULT_TIME, DEFAULT_SIZE, TIME, SIZE
+
+log4j.appender.DEFAULT_TIME = org.apache.log4j.rolling.RollingFileAppender
+log4j.appender.DEFAULT_TIME.layout = org.apache.log4j.SimpleLayout
+log4j.appender.DEFAULT_TIME.File = 
target/EnhancedRollingFileAppender/defaultTime.log
+log4j.appender.DEFAULT_TIME.rollingPolicy = 
org.apache.log4j.rolling.TimeBasedRollingPolicy
+log4j.appender.DEFAULT_TIME.rollingPolicy.FileNamePattern = 
target/EnhancedRollingFileAppender/defaultTime.%d{yyyy-MM-dd}.log
+
+log4j.appender.DEFAULT_SIZE = org.apache.log4j.rolling.RollingFileAppender
+log4j.appender.DEFAULT_SIZE.File = 
target/EnhancedRollingFileAppender/defaultSize.log
+log4j.appender.DEFAULT_SIZE.layout = org.apache.log4j.SimpleLayout
+log4j.appender.DEFAULT_SIZE.triggeringPolicy = 
org.apache.log4j.rolling.SizeBasedTriggeringPolicy
+log4j.appender.DEFAULT_SIZE.rollingPolicy = 
org.apache.log4j.rolling.FixedWindowRollingPolicy
+log4j.appender.DEFAULT_SIZE.rollingPolicy.FileNamePattern = 
target/EnhancedRollingFileAppender/defaultSize.%i.log
+
+log4j.appender.TIME = org.apache.log4j.rolling.RollingFileAppender
+log4j.appender.TIME.Append = false
+log4j.appender.TIME.BufferedIO = true
+log4j.appender.TIME.BufferSize = 1000
+log4j.appender.TIME.File = target/EnhancedRollingFileAppender/ignoredTime.log
+log4j.appender.TIME.ImmediateFlush = false
+log4j.appender.TIME.layout = org.apache.log4j.SimpleLayout
+log4j.appender.TIME.triggeringPolicy = 
org.apache.log4j.rolling.TimeBasedRollingPolicy
+# It is explicitly not a TimeBasedRolling
+log4j.appender.TIME.rollingPolicy = 
org.apache.log4j.rolling.FixedWindowRollingPolicy
+log4j.appender.TIME.rollingPolicy.ActiveFileName = 
target/EnhancedRollingFileAppender/time.log
+log4j.appender.TIME.rollingPolicy.FileNamePattern = 
target/EnhancedRollingFileAppender/time.%d{yyyy-MM-dd}.log
+
+log4j.appender.SIZE = org.apache.log4j.rolling.RollingFileAppender
+log4j.appender.SIZE.Append = false
+log4j.appender.SIZE.BufferedIO = true
+log4j.appender.SIZE.BufferSize = 1000
+log4j.appender.SIZE.File = target/EnhancedRollingFileAppender/ignoredSize.log
+log4j.appender.SIZE.ImmediateFlush = false
+log4j.appender.SIZE.layout = org.apache.log4j.SimpleLayout
+log4j.appender.SIZE.FileName = target/EnhancedRollingFileAppender/size.log
+log4j.appender.SIZE.triggeringPolicy = 
org.apache.log4j.rolling.SizeBasedTriggeringPolicy
+log4j.appender.SIZE.triggeringPolicy.MaxFileSize = 10000000
+log4j.appender.SIZE.rollingPolicy = 
org.apache.log4j.rolling.FixedWindowRollingPolicy
+log4j.appender.SIZE.rollingPolicy.ActiveFileName = 
target/EnhancedRollingFileAppender/size.log
+log4j.appender.SIZE.rollingPolicy.FileNamePattern = 
target/EnhancedRollingFileAppender/size.%i.log
+log4j.appender.SIZE.rollingPolicy.MinIndex = 11
+log4j.appender.SIZE.rollingPolicy.MaxIndex = 20
+
diff --git 
a/log4j-1.2-api/src/test/resources/config-1.2/log4j-EnhancedRollingFileAppender.xml
 
b/log4j-1.2-api/src/test/resources/config-1.2/log4j-EnhancedRollingFileAppender.xml
new file mode 100644
index 0000000000..a1d2395c9c
--- /dev/null
+++ 
b/log4j-1.2-api/src/test/resources/config-1.2/log4j-EnhancedRollingFileAppender.xml
@@ -0,0 +1,94 @@
+<?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.
+-->
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/";>
+
+  <appender name="DEFAULT_TIME" 
class="org.apache.log4j.rolling.RollingFileAppender">
+    <param name="File" 
value="target/EnhancedRollingFileAppender/defaultTime.log" />
+    <layout class="org.apache.log4j.SimpleLayout" />
+    <rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
+      <param name="FileNamePattern" 
value="target/EnhancedRollingFileAppender/defaultTime.%d{yyyy-MM-dd}.log" />
+    </rollingPolicy>
+  </appender>
+
+  <appender name="DEFAULT_SIZE" 
class="org.apache.log4j.rolling.RollingFileAppender">
+    <param name="File" 
value="target/EnhancedRollingFileAppender/defaultSize.log" />
+    <layout class="org.apache.log4j.SimpleLayout" />
+    <triggeringPolicy 
class="org.apache.log4j.rolling.SizeBasedTriggeringPolicy" />
+    <rollingPolicy class="org.apache.log4j.rolling.FixedWindowRollingPolicy">
+      <param name="FileNamePattern" 
value="target/EnhancedRollingFileAppender/defaultSize.%i.log" />
+    </rollingPolicy>
+  </appender>
+
+  <appender name="TIME" class="org.apache.log4j.rolling.RollingFileAppender">
+    <param name="Append" value="false" />
+    <param name="BufferedIO" value="true" />
+    <param name="BufferSize" value="1000" />
+    <param name="File" 
value="target/EnhancedRollingFileAppender/ignoredTime.log" />
+    <param name="ImmediateFlush" value="false" />
+    <layout class="org.apache.log4j.SimpleLayout" />
+    <triggeringPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy" 
/>
+    <rollingPolicy class="org.apache.log4j.rolling.FixedWindowRollingPolicy">
+      <param name="ActiveFileName" 
value="target/EnhancedRollingFileAppender/time.log" />
+      <param name="FileNamePattern" 
value="target/EnhancedRollingFileAppender/time.%d{yyyy-MM-dd}.log" />
+    </rollingPolicy>
+  </appender>
+
+  <appender name="SIZE" class="org.apache.log4j.rolling.RollingFileAppender">
+    <param name="Append" value="false" />
+    <param name="BufferedIO" value="true" />
+    <param name="BufferSize" value="1000" />
+    <param name="File" 
value="target/EnhancedRollingFileAppender/ignoredSize.log" />
+    <param name="ImmediateFlush" value="false" />
+    <layout class="org.apache.log4j.SimpleLayout" />
+    <triggeringPolicy 
class="org.apache.log4j.rolling.SizeBasedTriggeringPolicy">
+      <param name="MaxFileSize" value="10000000" />
+    </triggeringPolicy>
+    <rollingPolicy class="org.apache.log4j.rolling.FixedWindowRollingPolicy">
+      <param name="ActiveFileName" 
value="target/EnhancedRollingFileAppender/size.log" />
+      <param name="FileNamePattern" 
value="target/EnhancedRollingFileAppender/size.%i.log" />
+      <param name="MinIndex" value="11" />
+      <param name="MaxIndex" value="20" />
+    </rollingPolicy>
+  </appender>
+
+  <!-- This should not work in the original Apache Extras, since 
TimeBasedRollingPolicy
+       triggers a rollover every second and **must** use itself as rolling 
policy.
+   -->
+  <appender name="MIXED" class="org.apache.log4j.rolling.RollingFileAppender">
+    <param name="File" value="target/EnhancedRollingFileAppender/mixed.log" />
+    <layout class="org.apache.log4j.SimpleLayout" />
+    <triggeringPolicy 
class="org.apache.log4j.rolling.CompositeTriggeringPolicy">
+      <triggeringPolicy 
class="org.apache.log4j.rolling.TimeBasedRollingPolicy" />
+      <triggeringPolicy 
class="org.apache.log4j.rolling.SizeBasedTriggeringPolicy" />
+    </triggeringPolicy>
+    <rollingPolicy class="org.apache.log4j.rolling.FixedWindowRollingPolicy">
+      <param name="FileNamePattern" 
value="target/EnhancedRollingFileAppender/mixed.%d{yyyy-MM-dd}.%i.log" />
+    </rollingPolicy>
+  </appender>
+
+  <root>
+    <priority value="trace" />
+    <appender-ref ref="DEFAULT_TIME" />
+    <appender-ref ref="DEFAULT_SIZE" />
+    <appender-ref ref="TIME" />
+    <appender-ref ref="SIZE" />
+    <appender-ref ref="MIXED" />
+  </root>
+
+</log4j:configuration>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 0b770930c7..05f2a42645 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -138,6 +138,10 @@
       <action issue="LOG4J2-3362" dev="pkarwasz" type="add">
         Add support for Jakarta Mail API in the SMTP appender.
       </action>
+      <action issue="LOG4J2-3483" dev="pkarwasz" type="add">
+        Add support for Apache Extras' RollingFileAppender in Log4j 1.x bridge.
+      </action>
+      <!-- UPDATES -->
       <action issue="LOG4J2-3428" dev="ggregory" type="fix" due-to="LF-Lin">
         Update 3rd party dependencies for 2.18.0.
       </action>

Reply via email to