I will have to look at that. I am in the process of implementing a 
ScheduledRolloverTriggeringPolicy, which uses the ConfigurationScheduler to 
trigger rollovers.

Ralph

> On Nov 14, 2015, at 2:39 PM, Gary Gregory <garydgreg...@gmail.com> wrote:
> 
> I wonder if Duration belongs in core.util; we could reuse it other places, 
> like in the Configuration monitorInterval setting.
> 
> Gary
> 
> ---------- Forwarded message ----------
> From: <rpo...@apache.org <mailto:rpo...@apache.org>>
> Date: Sat, Nov 14, 2015 at 11:25 AM
> Subject: [1/4] logging-log4j2 git commit: LOG4J2-435 actions and filters for 
> delete-on-rollover support
> To: comm...@logging.apache.org <mailto:comm...@logging.apache.org>
> 
> 
> Repository: logging-log4j2
> Updated Branches:
>   refs/heads/LOG4J2-435-delete-on-rollover [created] 07175148e
> 
> 
> LOG4J2-435 actions and filters for delete-on-rollover support
> 
> - AbstractPathAction defines an Action that can process multiple files
> starting at some base path and excluding files rejected by nested
> filters
> - DeleteAction extends AbstractPathAction to run Files.walkFileTree with
> a DeletingVisitor
> - DeletingVisitor deletes files that are accepted by all PathFilters
> - PathFilter accepts/rejects a basePath + relativePath + fileAttributes
> combination
> - And, Or, Not are composite PathFilters
> - FileLastModifiedFilter accepts paths whose lastModifiedTime is at
> least the specified duration in the past
> - Duration implements ISO8601
> - FileNameFilter accepts paths based on either a regex or a name check
> (with simple wildcarts)
> 
> Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo 
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo>
> Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/7b7bdfaf 
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/7b7bdfaf>
> Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/7b7bdfaf 
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/7b7bdfaf>
> Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/7b7bdfaf 
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/7b7bdfaf>
> 
> Branch: refs/heads/LOG4J2-435-delete-on-rollover
> Commit: 7b7bdfafb348caf59025c8f6efc530a78d0ff45f
> Parents: d9fa7eb
> Author: rpopma <rpo...@apache.org <mailto:rpo...@apache.org>>
> Authored: Sun Nov 15 04:22:27 2015 +0900
> Committer: rpopma <rpo...@apache.org <mailto:rpo...@apache.org>>
> Committed: Sun Nov 15 04:22:27 2015 +0900
> 
> ----------------------------------------------------------------------
>  .../rolling/action/AbstractPathAction.java      | 154 +++++++++++
>  .../log4j/core/appender/rolling/action/And.java |  76 ++++++
>  .../appender/rolling/action/DeleteAction.java   |  83 ++++++
>  .../rolling/action/DeletingVisitor.java         |  74 ++++++
>  .../core/appender/rolling/action/Duration.java  | 256 +++++++++++++++++++
>  .../rolling/action/FileLastModifiedFilter.java  |  77 ++++++
>  .../appender/rolling/action/FileNameFilter.java | 144 +++++++++++
>  .../log4j/core/appender/rolling/action/Not.java |  70 +++++
>  .../log4j/core/appender/rolling/action/Or.java  |  74 ++++++
>  .../appender/rolling/action/PathFilter.java     |  37 +++
>  10 files changed, 1045 insertions(+)
> ----------------------------------------------------------------------
> 
> 
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/AbstractPathAction.java
>  
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/AbstractPathAction.java>
> ----------------------------------------------------------------------
> diff --git 
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/AbstractPathAction.java
>  
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/AbstractPathAction.java
> new file mode 100644
> index 0000000..d976549
> --- /dev/null
> +++ 
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/AbstractPathAction.java
> @@ -0,0 +1,154 @@
> +/*
> + * 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 
> <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.IOException;
> +import java.nio.file.FileSystems;
> +import java.nio.file.FileVisitOption;
> +import java.nio.file.FileVisitor;
> +import java.nio.file.Files;
> +import java.nio.file.Path;
> +import java.util.Arrays;
> +import java.util.Collections;
> +import java.util.EnumSet;
> +import java.util.List;
> +import java.util.Set;
> +import java.util.concurrent.TimeUnit;
> +
> +import org.apache.logging.log4j.core.lookup.StrSubstitutor;
> +
> +/**
> + * Abstract action for processing files that are accepted by the specified 
> PathFilters.
> + */
> +public abstract class AbstractPathAction extends AbstractAction {
> +
> +    private final String basePathString;
> +    private final Set<FileVisitOption> options;
> +    private final int maxDepth;
> +    private final List<PathFilter> pathFilters;
> +    private final StrSubstitutor subst;
> +
> +    /**
> +     * Creates a new AbstractPathAction that starts scanning for files to 
> process from the specified base path.
> +     *
> +     * @param basePath base path from where to start scanning for files to 
> process.
> +     * @param followSymbolicLinks whether to follow symbolic links. Default 
> is false.
> +     * @param maxDepth The maxDepth parameter is the maximum number of 
> levels of directories to visit. A value of 0
> +     *            means that only the starting file is visited, unless 
> denied by the security manager. A value of
> +     *            MAX_VALUE may be used to indicate that all levels should 
> be visited.
> +     * @param pathFilters an array of path filters (if more than one, they 
> all need to accept a path before it is
> +     *            processed).
> +     */
> +    protected AbstractPathAction(final String basePath, final boolean 
> followSymbolicLinks, final int maxDepth,
> +            final PathFilter[] pathFilters, final StrSubstitutor subst) {
> +        this.basePathString = basePath;
> +        this.options = followSymbolicLinks ? 
> EnumSet.of(FileVisitOption.FOLLOW_LINKS) //
> +                : Collections.<FileVisitOption> emptySet();
> +        this.maxDepth = maxDepth;
> +        this.pathFilters = Arrays.asList(Arrays.copyOf(pathFilters, 
> pathFilters.length));
> +        this.subst = subst;
> +    }
> +
> +    @Override
> +    public boolean execute() throws IOException {
> +        return execute(createFileVisitor(getBasePath(), pathFilters));
> +    }
> +
> +    public boolean execute(final FileVisitor<Path> visitor) throws 
> IOException {
> +        final long start = System.nanoTime();
> +        LOGGER.debug("Starting {}", this);
> +
> +        Files.walkFileTree(getBasePath(), options, maxDepth, visitor);
> +
> +        final double duration = System.nanoTime() - start;
> +        LOGGER.debug("{} complete in {} seconds", 
> getClass().getSimpleName(), duration / TimeUnit.SECONDS.toNanos(1));
> +
> +        // TODO return (visitor.success || ignoreProcessingFailure)
> +        return true; // do not abort rollover even if processing failed
> +    }
> +
> +    /**
> +     * Creates a new {@code FileVisitor<Path>} to pass to the {@link 
> Files#walkFileTree(Path, Set, int, FileVisitor)}
> +     * method when the {@link #execute()} method is invoked.
> +     * <p>
> +     * The visitor is responsible for processing the files it encounters 
> that are accepted by all filters.
> +     *
> +     * @param visitorBaseDir base dir from where to start scanning for files 
> to process
> +     * @param visitorFilters filters that determine if a file should be 
> processed
> +     * @return a new {@code FileVisitor<Path>}
> +     */
> +    protected abstract FileVisitor<Path> createFileVisitor(final Path 
> visitorBaseDir,
> +            final List<PathFilter> visitorFilters);
> +
> +    /**
> +     * Returns the base path from where to start scanning for files to 
> delete. Lookups are resolved, so if the
> +     * configuration was <code>&lt;Delete basePath="${sys:user.home}/abc" 
> /&gt;</code> then this method returns a path
> +     * to the "abc" file or directory in the user's home directory.
> +     *
> +     * @return the base path (all lookups resolved)
> +     */
> +    public Path getBasePath() {
> +        return 
> FileSystems.getDefault().getPath(subst.replace(getBasePathString()));
> +    }
> +
> +    /**
> +     * Returns the base path as it was specified in the configuration. 
> Lookups are not resolved.
> +     *
> +     * @return the base path as it was specified in the configuration
> +     */
> +    public String getBasePathString() {
> +        return basePathString;
> +    }
> +
> +    public StrSubstitutor getStrSubstitutor() {
> +        return subst;
> +    }
> +
> +    /**
> +     * Returns whether to follow symbolic links or not.
> +     *
> +     * @return the options
> +     */
> +    public Set<FileVisitOption> getOptions() {
> +        return Collections.unmodifiableSet(options);
> +    }
> +
> +    /**
> +     * Returns the the maximum number of directory levels to visit.
> +     *
> +     * @return the maxDepth
> +     */
> +    public int getMaxDepth() {
> +        return maxDepth;
> +    }
> +
> +    /**
> +     * Returns the list of PathFilter objects.
> +     *
> +     * @return the pathFilters
> +     */
> +    public List<PathFilter> getPathFilters() {
> +        return Collections.unmodifiableList(pathFilters);
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return getClass().getSimpleName() + "[basePath=" + getBasePath() + 
> ", options=" + options + ", maxDepth="
> +                + maxDepth + ", filters=" + pathFilters + "]";
> +    }
> +}
> 
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/And.java
>  
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/And.java>
> ----------------------------------------------------------------------
> diff --git 
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/And.java
>  
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/And.java
> new file mode 100644
> index 0000000..c701c8e
> --- /dev/null
> +++ 
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/And.java
> @@ -0,0 +1,76 @@
> +/*
> + * 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 
> <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 DeleteFilter} that only accepts objects that are 
> accepted by <em>all</em> component filters.
> + */
> +@Plugin(name = "And", category = "Core", printObject = true)
> +public final class And implements PathFilter {
> +
> +    private final PathFilter[] components;
> +
> +    private And(final PathFilter... filters) {
> +        this.components = Objects.requireNonNull(filters, "filters");
> +    }
> +
> +    public PathFilter[] getDeleteFilters() {
> +        return components;
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     *
> +     * @see 
> org.apache.logging.log4j.core.appender.rolling.action.DeleteFilter#accept(java.nio.file.Path,
> +     * java.nio.file.Path)
> +     */
> +    @Override
> +    public boolean accept(final Path baseDir, final Path relativePath, final 
> BasicFileAttributes attrs) {
> +        for (final PathFilter component : components) {
> +            if (!component.accept(baseDir, relativePath, attrs)) {
> +                return false;
> +            }
> +        }
> +        return true;
> +    }
> +
> +    /**
> +     * Create a Composite DeleteFilter.
> +     *
> +     * @param components The component filters.
> +     * @return A CompositeDeleteFilter.
> +     */
> +    @PluginFactory
> +    public static And createAndFilter( //
> +            @PluginElement("Filters") final PathFilter... components) {
> +        return new And(components);
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return "And(filters=" + Arrays.toString(components) + ")";
> +    }
> +}
> 
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeleteAction.java
>  
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeleteAction.java>
> ----------------------------------------------------------------------
> diff --git 
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeleteAction.java
>  
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeleteAction.java
> new file mode 100644
> index 0000000..47fddc5
> --- /dev/null
> +++ 
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeleteAction.java
> @@ -0,0 +1,83 @@
> +/*
> + * 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 
> <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.FileVisitor;
> +import java.nio.file.Path;
> +import java.util.List;
> +
> +import org.apache.logging.log4j.core.config.Configuration;
> +import org.apache.logging.log4j.core.config.plugins.Plugin;
> +import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
> +import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
> +import org.apache.logging.log4j.core.config.plugins.PluginElement;
> +import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> +import org.apache.logging.log4j.core.lookup.StrSubstitutor;
> +
> +/**
> + * Rollover or scheduled action for deleting old log files that are accepted 
> by the specified PathFilters.
> + */
> +@Plugin(name = "Delete", category = "Core", printObject = true)
> +public class DeleteAction extends AbstractPathAction {
> +
> +    /**
> +     * Creates a new DeleteAction that starts scanning for files to delete 
> from the specified base path.
> +     *
> +     * @param basePath base path from where to start scanning for files to 
> delete.
> +     * @param followSymbolicLinks whether to follow symbolic links. Default 
> is false.
> +     * @param maxDepth The maxDepth parameter is the maximum number of 
> levels of directories to visit. A value of 0
> +     *            means that only the starting file is visited, unless 
> denied by the security manager. A value of
> +     *            MAX_VALUE may be used to indicate that all levels should 
> be visited.
> +     * @param pathFilters an array of path filters (if more than one, they 
> all need to accept a path before it is
> +     *            deleted).
> +     */
> +    DeleteAction(final String basePath, final boolean followSymbolicLinks, 
> final int maxDepth,
> +            final PathFilter[] pathFilters, final StrSubstitutor subst) {
> +        super(basePath, followSymbolicLinks, maxDepth, pathFilters, subst);
> +    }
> +
> +    @Override
> +    protected FileVisitor<Path> createFileVisitor(final Path visitorBaseDir, 
> final List<PathFilter> visitorFilters) {
> +        return new DeletingVisitor(visitorBaseDir, visitorFilters);
> +    }
> +
> +    /**
> +     * Create a DeleteAction.
> +     *
> +     * @param basePath base path from where to start scanning for files to 
> delete.
> +     * @param followLinks whether to follow symbolic links. Default is false.
> +     * @param maxDepth The maxDepth parameter is the maximum number of 
> levels of directories to visit. A value of 0
> +     *            means that only the starting file is visited, unless 
> denied by the security manager. A value of
> +     *            MAX_VALUE may be used to indicate that all levels should 
> be visited.
> +     * @param pathFilters an array of path filters (if more than one, they 
> all need to accept a path before it is
> +     *            deleted).
> +     * @param config The Configuration.
> +     * @return A DeleteAction.
> +     */
> +    @PluginFactory
> +    public static DeleteAction createDeleteAction(
> +            // @formatter:off
> +            @PluginAttribute("basePath") final String basePath, //
> +            @PluginAttribute(value = "followLinks", defaultBoolean = false) 
> final boolean followLinks,
> +            @PluginAttribute(value = "maxDepth", defaultInt = 1) final int 
> maxDepth,
> +            @PluginElement("PathFilters") final PathFilter[] pathFilters,
> +            @PluginConfiguration final Configuration config) {
> +            // @formatter:on
> +        return new DeleteAction(basePath, followLinks, maxDepth, 
> pathFilters, config.getStrSubstitutor());
> +    }
> +}
> 
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeletingVisitor.java
>  
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeletingVisitor.java>
> ----------------------------------------------------------------------
> diff --git 
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeletingVisitor.java
>  
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeletingVisitor.java
> new file mode 100644
> index 0000000..ba290d9
> --- /dev/null
> +++ 
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/DeletingVisitor.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 
> <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.IOException;
> +import java.nio.file.FileVisitResult;
> +import java.nio.file.Files;
> +import java.nio.file.Path;
> +import java.nio.file.SimpleFileVisitor;
> +import java.nio.file.attribute.BasicFileAttributes;
> +import java.util.List;
> +import java.util.Objects;
> +
> +import org.apache.logging.log4j.Logger;
> +import org.apache.logging.log4j.status.StatusLogger;
> +
> +/**
> + * FileVisitor that deletes files that are accepted by all PathFilters. 
> Directories are ignored.
> + */
> +public class DeletingVisitor extends SimpleFileVisitor<Path> {
> +    private static final Logger LOGGER = StatusLogger.getLogger();
> +
> +    private final Path basePath;
> +    private final List<? extends PathFilter> pathFilters;
> +
> +    /**
> +     * Constructs a new DeletingVisitor.
> +     *
> +     * @param basePath used to relativize paths
> +     * @param pathFilters objects that need to confirm whether a file can be 
> deleted
> +     */
> +    public DeletingVisitor(final Path basePath, final List<? extends 
> PathFilter> pathFilters) {
> +        this.basePath = Objects.requireNonNull(basePath, "basePath");
> +        this.pathFilters = Objects.requireNonNull(pathFilters, "filters");
> +    }
> +
> +    @Override
> +    public FileVisitResult visitFile(final Path file, final 
> BasicFileAttributes attrs) throws IOException {
> +        for (final PathFilter pathFilter : pathFilters) {
> +            if (!pathFilter.accept(basePath, basePath.relativize(file), 
> attrs)) {
> +                LOGGER.trace("Not deleting {}", file);
> +                return FileVisitResult.CONTINUE;
> +            }
> +        }
> +        delete(file);
> +        return FileVisitResult.CONTINUE;
> +    }
> +
> +    /**
> +     * Deletes the specified file.
> +     *
> +     * @param file the file to delete
> +     * @throws IOException if a problem occurred deleting the file
> +     */
> +    protected void delete(final Path file) throws IOException {
> +        LOGGER.trace("Deleting {}", file);
> +        Files.delete(file);
> +    }
> +}
> 
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Duration.java
>  
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/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
> new file mode 100644
> index 0000000..d2b1e18
> --- /dev/null
> +++ 
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Duration.java
> @@ -0,0 +1,256 @@
> +/*
> + * 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 
> <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 
> <https://en.wikipedia.org/wiki/ISO_8601#Durations>">ISO-8601 Durations</a>
> + * standard. The supported format is {@code PnDTnHnMnS}. 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 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" must 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());
> +    }
> +}
> 
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/FileLastModifiedFilter.java
>  
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/FileLastModifiedFilter.java>
> ----------------------------------------------------------------------
> diff --git 
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/FileLastModifiedFilter.java
>  
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/FileLastModifiedFilter.java
> new file mode 100644
> index 0000000..6904ade
> --- /dev/null
> +++ 
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/FileLastModifiedFilter.java
> @@ -0,0 +1,77 @@
> +/*
> + * 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 
> <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.nio.file.attribute.FileTime;
> +import java.util.Objects;
> +
> +import org.apache.logging.log4j.core.config.plugins.Plugin;
> +import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
> +import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> +import org.apache.logging.log4j.core.util.Clock;
> +import org.apache.logging.log4j.core.util.ClockFactory;
> +
> +/**
> + * PathFilter that accepts paths that are older than the specified duration.
> + */
> +@Plugin(name = "LastModified", category = "Core", printObject = true)
> +public final class FileLastModifiedFilter implements PathFilter {
> +    private static final Clock CLOCK = ClockFactory.getClock();
> +
> +    private final Duration duration;
> +
> +    private FileLastModifiedFilter(final Duration duration) {
> +        this.duration = Objects.requireNonNull(duration, "duration");
> +    }
> +
> +    public Duration getDuration() {
> +        return duration;
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     *
> +     * @see 
> org.apache.logging.log4j.core.appender.rolling.action.PathFilter#accept(java.nio.file.Path,
> +     * java.nio.file.Path)
> +     */
> +    @Override
> +    public boolean accept(final Path baseDir, final Path relativePath, final 
> BasicFileAttributes attrs) {
> +        final FileTime fileTime = attrs.lastModifiedTime();
> +        final long millis = fileTime.toMillis();
> +        final long ageMillis = CLOCK.currentTimeMillis() - millis;
> +        return ageMillis >= duration.toMillis();
> +    }
> +
> +    /**
> +     * Create a FileLastModifiedFilter filter.
> +     *
> +     * @param duration The path age that is accepted by this filter. Must be 
> a valid Duration.
> +     * @return A FileLastModifiedFilter filter.
> +     */
> +    @PluginFactory
> +    public static FileLastModifiedFilter createAgeFilter( //
> +            @PluginAttribute("duration") final Duration duration) {
> +        return new FileLastModifiedFilter(duration);
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return "FileLastModifiedFilter(age=" + duration + ")";
> +    }
> +}
> 
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/FileNameFilter.java
>  
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/FileNameFilter.java>
> ----------------------------------------------------------------------
> diff --git 
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/FileNameFilter.java
>  
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/FileNameFilter.java
> new file mode 100644
> index 0000000..cbde2a9
> --- /dev/null
> +++ 
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/FileNameFilter.java
> @@ -0,0 +1,144 @@
> +/*
> + * 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 
> <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.regex.Matcher;
> +import java.util.regex.Pattern;
> +
> +import org.apache.logging.log4j.core.config.plugins.Plugin;
> +import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
> +import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> +
> +/**
> + * PathFilter that accepts files for deletion if their relative path matches 
> either a path pattern or a regular
> + * expression.
> + * <p>
> + * If both a regular expression and a path pattern are specified the path 
> pattern is used and the regular expression is
> + * ignored.
> + * <p>
> + * The path pattern may contain '?' and '*' wildcarts.
> + */
> +@Plugin(name = "File", category = "Core", printObject = true)
> +public final class FileNameFilter implements PathFilter {
> +
> +    private final Pattern regex;
> +    private final String pathPattern;
> +
> +    /**
> +     * Constructs a FileNameFilter filter. If both a regular expression and 
> a path pattern are specified the path
> +     * pattern is used and the regular expression is ignored.
> +     *
> +     * @param path the baseDir-relative path pattern of the files to delete 
> (may contain '*' and '?' wildcarts)
> +     * @param regex the regular expression that matches the baseDir-relative 
> path of the file(s) to delete
> +     */
> +    private FileNameFilter(final String path, final String regex) {
> +        if (regex == null && path == null) {
> +            throw new IllegalArgumentException("Specify either a path or a 
> regular expression. Both cannot be null.");
> +        }
> +        this.regex = regex != null ? Pattern.compile(regex) : null;
> +        this.pathPattern = path;
> +    }
> +
> +    /**
> +     * Returns the compiled regular expression that matches the 
> baseDir-relative path of the file(s) to delete, or
> +     * {@code null} if no regular expression was specified.
> +     *
> +     * @return the compiled regular expression, or {@code null}
> +     */
> +    public Pattern getRegex() {
> +        return regex;
> +    }
> +
> +    /**
> +     * Returns the baseDir-relative path pattern of the files to delete, or 
> {@code null} if not specified. This path
> +     * pattern may contain '*' and '?' wildcarts.
> +     *
> +     * @return relative path of the file(s) to delete (may contain '*' and 
> '?' wildcarts)
> +     */
> +    public String getPathPattern() {
> +        return pathPattern;
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     *
> +     * @see 
> org.apache.logging.log4j.core.appender.rolling.action.PathFilter#accept(java.nio.file.Path,
> +     * java.nio.file.Path)
> +     */
> +    @Override
> +    public boolean accept(final Path baseDir, final Path relativePath, final 
> BasicFileAttributes attrs) {
> +        if (pathPattern != null) {
> +            return isMatch(relativePath.toString(), pathPattern);
> +        } else {
> +            Matcher matcher = regex.matcher(relativePath.toString());
> +            return (matcher.matches());
> +        }
> +    }
> +
> +    // package protected for unit tests
> +    static boolean isMatch(final String text, final String pattern) {
> +        int i = 0;
> +        int j = 0;
> +        int starIndex = -1;
> +        int iIndex = -1;
> +
> +        while (i < text.length()) {
> +            if (j < pattern.length() && (pattern.charAt(j) == '?' || 
> pattern.charAt(j) == text.charAt(i))) {
> +                ++i;
> +                ++j;
> +            } else if (j < pattern.length() && pattern.charAt(j) == '*') {
> +                starIndex = j;
> +                iIndex = i;
> +                j++;
> +            } else if (starIndex != -1) {
> +                j = starIndex + 1;
> +                i = iIndex + 1;
> +                iIndex++;
> +            } else {
> +                return false;
> +            }
> +        }
> +
> +        while (j < pattern.length() && pattern.charAt(j) == '*') {
> +            ++j;
> +        }
> +        return j == pattern.length();
> +    }
> +
> +    /**
> +     * Creates a FileNameFilter filter. If both a regular expression and a 
> path pattern are specified the path pattern
> +     * is used and the regular expression is ignored.
> +     *
> +     * @param path the baseDir-relative path pattern of the files to delete 
> (may contain '*' and '?' wildcarts)
> +     * @param regex the regular expression that matches the baseDir-relative 
> path of the file(s) to delete
> +     * @return A FileNameFilter filter.
> +     */
> +    @PluginFactory
> +    public static FileNameFilter createNameFilter( //
> +            @PluginAttribute("path") final String path, //
> +            @PluginAttribute("regex") final String regex) {
> +        return new FileNameFilter(path, regex);
> +    }
> +
> +    @Override
> +    public String toString() {
> +        final String pattern = regex == null ? "null" : regex.pattern();
> +        return "FileNameFilter(regex=" + pattern + ", name=" + pathPattern + 
> ")";
> +    }
> +}
> 
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Not.java
>  
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Not.java>
> ----------------------------------------------------------------------
> diff --git 
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Not.java
>  
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Not.java
> new file mode 100644
> index 0000000..7265dce
> --- /dev/null
> +++ 
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Not.java
> @@ -0,0 +1,70 @@
> +/*
> + * 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 
> <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.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;
> +
> +/**
> + * Wrapper {@code DeleteFilter} that accepts objects that are rejected by 
> the wrapped component filter.
> + */
> +@Plugin(name = "Not", category = "Core", printObject = true)
> +public final class Not implements PathFilter {
> +
> +    private final PathFilter negate;
> +
> +    private Not(final PathFilter negate) {
> +        this.negate = Objects.requireNonNull(negate, "filter");
> +    }
> +
> +    public PathFilter getWrappedFilter() {
> +        return negate;
> +    }
> +
> +    /*
> +     * (non-Javadoc)
> +     *
> +     * @see 
> org.apache.logging.log4j.core.appender.rolling.action.DeleteFilter#accept(java.nio.file.Path,
> +     * java.nio.file.Path)
> +     */
> +    @Override
> +    public boolean accept(final Path baseDir, final Path relativePath, final 
> BasicFileAttributes attrs) {
> +        return !negate.accept(baseDir, relativePath, attrs);
> +    }
> +
> +    /**
> +     * Create a Not filter.
> +     *
> +     * @param filter The filter to negate.
> +     * @return A Not filter.
> +     */
> +    @PluginFactory
> +    public static Not createNotFilter( //
> +            @PluginElement("Filters") final PathFilter filter) {
> +        return new Not(filter);
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return "Not(filters=" + negate + ")";
> +    }
> +}
> 
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Or.java
>  
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Or.java>
> ----------------------------------------------------------------------
> diff --git 
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Or.java
>  
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Or.java
> new file mode 100644
> index 0000000..68de219
> --- /dev/null
> +++ 
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/Or.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 
> <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 DeleteFilter} that accepts objects that are accepted by 
> <em>any</em> component filters.
> + */
> +@Plugin(name = "Or", category = "Core", printObject = true)
> +public final class Or implements PathFilter {
> +
> +    private final PathFilter[] components;
> +
> +    private Or(final PathFilter... filters) {
> +        this.components = Objects.requireNonNull(filters, "filters");
> +    }
> +
> +    public PathFilter[] getDeleteFilters() {
> +        return components;
> +    }
> +
> +    /* (non-Javadoc)
> +     * @see 
> org.apache.logging.log4j.core.appender.rolling.action.DeleteFilter#accept(java.nio.file.Path,
> +     * java.nio.file.Path)
> +     */
> +    @Override
> +    public boolean accept(final Path baseDir, final Path relativePath, final 
> BasicFileAttributes attrs) {
> +        for (final PathFilter component : components) {
> +            if (component.accept(baseDir, relativePath, attrs)) {
> +                return true;
> +            }
> +        }
> +        return false;
> +    }
> +
> +    /**
> +     * Create a Composite DeleteFilter.
> +     *
> +     * @param components The component filters.
> +     * @return A CompositeDeleteFilter.
> +     */
> +    @PluginFactory
> +    public static Or createOrFilter( //
> +            @PluginElement("Filters") final PathFilter... components) {
> +        return new Or(components);
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return "Or(filters=" + Arrays.toString(components) + ")";
> +    }
> +}
> 
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathFilter.java
>  
> <http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b7bdfaf/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathFilter.java>
> ----------------------------------------------------------------------
> diff --git 
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathFilter.java
>  
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathFilter.java
> new file mode 100644
> index 0000000..f6b782a
> --- /dev/null
> +++ 
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/rolling/action/PathFilter.java
> @@ -0,0 +1,37 @@
> +/*
> + * 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 
> <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;
> +
> +/**
> + * Filter that accepts or rejects a candidate {@code Path} for deletion.
> + */
> +public interface PathFilter {
> +
> +    /**
> +     * Returns {@code true} if the specified candidate path should be 
> deleted, {@code false} otherwise.
> +     *
> +     * @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 whether the candidate path should be deleted
> +     */
> +    boolean accept(final Path baseDir, final Path relativePath, final 
> BasicFileAttributes attrs);
> +}
> 
> 
> 
> 
> -- 
> E-Mail: garydgreg...@gmail.com <mailto:garydgreg...@gmail.com> | 
> ggreg...@apache.org  <mailto:ggreg...@apache.org>
> Java Persistence with Hibernate, Second Edition 
> <http://www.manning.com/bauer3/>
> JUnit in Action, Second Edition <http://www.manning.com/tahchiev/>
> Spring Batch in Action <http://www.manning.com/templier/>
> Blog: http://garygregory.wordpress.com <http://garygregory.wordpress.com/> 
> Home: http://garygregory.com/ <http://garygregory.com/>
> Tweet! http://twitter.com/GaryGregory <http://twitter.com/GaryGregory>

Reply via email to