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><Delete basePath="${sys:user.home}/abc" > /></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>