View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  
18  package org.apache.logging.log4j.core.appender.rolling.action;
19  
20  import java.io.IOException;
21  import java.nio.file.FileVisitOption;
22  import java.nio.file.FileVisitor;
23  import java.nio.file.Files;
24  import java.nio.file.Path;
25  import java.nio.file.Paths;
26  import java.util.Arrays;
27  import java.util.Collections;
28  import java.util.EnumSet;
29  import java.util.List;
30  import java.util.Set;
31  import java.util.concurrent.TimeUnit;
32  
33  import org.apache.logging.log4j.core.lookup.StrSubstitutor;
34  
35  /**
36   * Abstract action for processing files that are accepted by the specified PathFilters.
37   */
38  public abstract class AbstractPathAction extends AbstractAction {
39  
40      private final String basePathString;
41      private final Set<FileVisitOption> options;
42      private final int maxDepth;
43      private final List<PathCondition> pathConditions;
44      private final StrSubstitutor subst;
45  
46      /**
47       * Creates a new AbstractPathAction that starts scanning for files to process from the specified base path.
48       *
49       * @param basePath base path from where to start scanning for files to process.
50       * @param followSymbolicLinks whether to follow symbolic links. Default is false.
51       * @param maxDepth The maxDepth parameter is the maximum number of levels of directories to visit. A value of 0
52       *            means that only the starting file is visited, unless denied by the security manager. A value of
53       *            MAX_VALUE may be used to indicate that all levels should be visited.
54       * @param pathFilters an array of path filters (if more than one, they all need to accept a path before it is
55       *            processed).
56       */
57      protected AbstractPathAction(final String basePath, final boolean followSymbolicLinks, final int maxDepth,
58              final PathCondition[] pathFilters, final StrSubstitutor subst) {
59          this.basePathString = basePath;
60          this.options = followSymbolicLinks ? EnumSet.of(FileVisitOption.FOLLOW_LINKS)
61                  : Collections.<FileVisitOption> emptySet();
62          this.maxDepth = maxDepth;
63          this.pathConditions = Arrays.asList(Arrays.copyOf(pathFilters, pathFilters.length));
64          this.subst = subst;
65      }
66  
67      @Override
68      public boolean execute() throws IOException {
69          return execute(createFileVisitor(getBasePath(), pathConditions));
70      }
71  
72      public boolean execute(final FileVisitor<Path> visitor) throws IOException {
73          final long start = System.nanoTime();
74          LOGGER.debug("Starting {}", this);
75  
76          Files.walkFileTree(getBasePath(), options, maxDepth, visitor);
77  
78          final double duration = System.nanoTime() - start;
79          LOGGER.debug("{} complete in {} seconds", getClass().getSimpleName(), duration / TimeUnit.SECONDS.toNanos(1));
80  
81          // TODO return (visitor.success || ignoreProcessingFailure)
82          return true; // do not abort rollover even if processing failed
83      }
84  
85      /**
86       * Creates a new {@code FileVisitor<Path>} to pass to the {@link Files#walkFileTree(Path, Set, int, FileVisitor)}
87       * method when the {@link #execute()} method is invoked.
88       * <p>
89       * The visitor is responsible for processing the files it encounters that are accepted by all filters.
90       *
91       * @param visitorBaseDir base dir from where to start scanning for files to process
92       * @param conditions filters that determine if a file should be processed
93       * @return a new {@code FileVisitor<Path>}
94       */
95      protected abstract FileVisitor<Path> createFileVisitor(final Path visitorBaseDir,
96              final List<PathCondition> conditions);
97  
98      /**
99       * Returns the base path from where to start scanning for files to delete. Lookups are resolved, so if the
100      * configuration was <code>&lt;Delete basePath="${sys:user.home}/abc" /&gt;</code> then this method returns a path
101      * to the "abc" file or directory in the user's home directory.
102      *
103      * @return the base path (all lookups resolved)
104      */
105     public Path getBasePath() {
106         return Paths.get(subst.replace(getBasePathString()));
107     }
108 
109     /**
110      * Returns the base path as it was specified in the configuration. Lookups are not resolved.
111      *
112      * @return the base path as it was specified in the configuration
113      */
114     public String getBasePathString() {
115         return basePathString;
116     }
117 
118     public StrSubstitutor getStrSubstitutor() {
119         return subst;
120     }
121 
122     /**
123      * Returns whether to follow symbolic links or not.
124      *
125      * @return the options
126      */
127     public Set<FileVisitOption> getOptions() {
128         return Collections.unmodifiableSet(options);
129     }
130 
131     /**
132      * Returns whether to follow symbolic links or not.
133      *
134      * @return whether to follow symbolic links or not
135      */
136     public boolean isFollowSymbolicLinks() {
137         return options.contains(FileVisitOption.FOLLOW_LINKS);
138     }
139 
140     /**
141      * Returns the the maximum number of directory levels to visit.
142      *
143      * @return the maxDepth
144      */
145     public int getMaxDepth() {
146         return maxDepth;
147     }
148 
149     /**
150      * Returns the list of PathCondition objects.
151      *
152      * @return the pathFilters
153      */
154     public List<PathCondition> getPathConditions() {
155         return Collections.unmodifiableList(pathConditions);
156     }
157 
158     @Override
159     public String toString() {
160         return getClass().getSimpleName() + "[basePath=" + getBasePath() + ", options=" + options + ", maxDepth="
161                 + maxDepth + ", conditions=" + pathConditions + "]";
162     }
163 }