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    *      https://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.commons.io.file;
19  
20  import java.io.IOException;
21  import java.nio.file.FileVisitResult;
22  import java.nio.file.Path;
23  import java.nio.file.attribute.BasicFileAttributes;
24  import java.util.ArrayList;
25  import java.util.Comparator;
26  import java.util.List;
27  import java.util.Objects;
28  
29  import org.apache.commons.io.file.Counters.PathCounters;
30  import org.apache.commons.io.function.IOBiFunction;
31  
32  /**
33   * Accumulates normalized paths during visitation.
34   * <p>
35   * Use with care on large file trees as each visited Path element is remembered.
36   * </p>
37   * <h2>Example</h2>
38   *
39   * <pre>
40   * Path dir = PathUtils.current();
41   * // We are interested in files older than one day
42   * Instant cutoff = Instant.now().minus(Duration.ofDays(1));
43   * AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new AgeFileFilter(cutoff));
44   * //
45   * // Walk one directory
46   * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
47   * System.out.println(visitor.getPathCounters());
48   * System.out.println(visitor.getFileList());
49   * //
50   * visitor.getPathCounters().reset();
51   * //
52   * // Walk directory tree
53   * Files.walkFileTree(dir, visitor);
54   * System.out.println(visitor.getPathCounters());
55   * System.out.println(visitor.getDirList());
56   * System.out.println(visitor.getFileList());
57   * </pre>
58   *
59   * @since 2.7
60   */
61  public class AccumulatorPathVisitor extends CountingPathVisitor {
62  
63      /**
64       * Builds instances of {@link AccumulatorPathVisitor}.
65       *
66       * @since 2.19.0
67       */
68      public static class Builder extends AbstractBuilder<AccumulatorPathVisitor, Builder> {
69  
70          /**
71           * Constructs a new builder.
72           */
73          public Builder() {
74              // empty.
75          }
76  
77          @Override
78          public AccumulatorPathVisitor get() {
79              return new AccumulatorPathVisitor(this);
80          }
81  
82      }
83  
84      /**
85       * Builds instances of {@link AccumulatorPathVisitor}.
86       *
87       * @return a new builder.
88       * @since 2.19.0
89       */
90      public static Builder builder() {
91          return new Builder();
92      }
93  
94      /**
95       * Constructs a new instance configured with a BigInteger {@link PathCounters}.
96       *
97       * @return a new instance configured with a BigInteger {@link PathCounters}.
98       * @see #builder()
99       * @see Builder
100      */
101     public static AccumulatorPathVisitor withBigIntegerCounters() {
102         return builder().setPathCounters(Counters.bigIntegerPathCounters()).get();
103     }
104 
105     /**
106      * Constructs a new instance configured with a BigInteger {@link PathCounters}.
107      *
108      * @param fileFilter Filters files to accumulate and count.
109      * @param dirFilter Filters directories to accumulate and count.
110      * @return a new instance configured with a long {@link PathCounters}.
111      * @see #builder()
112      * @see Builder
113      * @since 2.9.0
114      */
115     public static AccumulatorPathVisitor withBigIntegerCounters(final PathFilter fileFilter, final PathFilter dirFilter) {
116         return builder().setPathCounters(Counters.bigIntegerPathCounters()).setFileFilter(fileFilter).setDirectoryFilter(dirFilter).get();
117     }
118 
119     /**
120      * Constructs a new instance configured with a long {@link PathCounters}.
121      *
122      * @return a new instance configured with a long {@link PathCounters}.
123      * @see #builder()
124      * @see Builder
125      */
126     public static AccumulatorPathVisitor withLongCounters() {
127         return builder().setPathCounters(Counters.longPathCounters()).get();
128     }
129 
130     /**
131      * Constructs a new instance configured with a long {@link PathCounters}.
132      *
133      * @param fileFilter Filters files to accumulate and count.
134      * @param dirFilter Filters directories to accumulate and count.
135      * @return a new instance configured with a long {@link PathCounters}.
136      * @see #builder()
137      * @see Builder
138      * @since 2.9.0
139      */
140     public static AccumulatorPathVisitor withLongCounters(final PathFilter fileFilter, final PathFilter dirFilter) {
141         return builder().setPathCounters(Counters.longPathCounters()).setFileFilter(fileFilter).setDirectoryFilter(dirFilter).get();
142     }
143 
144     private final List<Path> dirList = new ArrayList<>();
145 
146     private final List<Path> fileList = new ArrayList<>();
147 
148     /**
149      * Constructs a new instance with a noop path counter.
150      *
151      * @since 2.9.0
152      * @deprecated Use {@link #builder()}.
153      */
154     @Deprecated
155     public AccumulatorPathVisitor() {
156         super(Counters.noopPathCounters());
157     }
158 
159     private AccumulatorPathVisitor(final Builder builder) {
160         super(builder);
161     }
162 
163     /**
164      * Constructs a new instance that counts file system elements.
165      *
166      * @param pathCounter How to count path visits.
167      * @deprecated Use {@link #builder()}.
168      */
169     @Deprecated
170     public AccumulatorPathVisitor(final PathCounters pathCounter) {
171         super(pathCounter);
172     }
173 
174     /**
175      * Constructs a new instance.
176      *
177      * @param pathCounter How to count path visits.
178      * @param fileFilter Filters which files to count.
179      * @param dirFilter Filters which directories to count.
180      * @since 2.9.0
181      * @deprecated Use {@link #builder()}.
182      */
183     @Deprecated
184     public AccumulatorPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter, final PathFilter dirFilter) {
185         super(pathCounter, fileFilter, dirFilter);
186     }
187 
188     /**
189      * Constructs a new instance.
190      *
191      * @param pathCounter How to count path visits.
192      * @param fileFilter Filters which files to count.
193      * @param dirFilter Filters which directories to count.
194      * @param visitFileFailed Called on {@link #visitFileFailed(Path, IOException)}.
195      * @since 2.12.0
196      * @deprecated Use {@link #builder()}.
197      */
198     @SuppressWarnings("deprecation")
199     @Deprecated
200     public AccumulatorPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter, final PathFilter dirFilter,
201         final IOBiFunction<Path, IOException, FileVisitResult> visitFileFailed) {
202         super(pathCounter, fileFilter, dirFilter, visitFileFailed);
203     }
204 
205     private void add(final List<Path> list, final Path dir) {
206         list.add(dir.normalize());
207     }
208 
209     @Override
210     public boolean equals(final Object obj) {
211         if (this == obj) {
212             return true;
213         }
214         if (!super.equals(obj)) {
215             return false;
216         }
217         if (!(obj instanceof AccumulatorPathVisitor)) {
218             return false;
219         }
220         final AccumulatorPathVisitor other = (AccumulatorPathVisitor) obj;
221         return Objects.equals(dirList, other.dirList) && Objects.equals(fileList, other.fileList);
222     }
223 
224     /**
225      * Gets a copy of the list of visited directories.
226      *
227      * @return a copy of the list of visited directories.
228      */
229     public List<Path> getDirList() {
230         return new ArrayList<>(dirList);
231     }
232 
233     /**
234      * Gets a copy of the list of visited files.
235      *
236      * @return a copy of the list of visited files.
237      */
238     public List<Path> getFileList() {
239         return new ArrayList<>(fileList);
240     }
241 
242     @Override
243     public int hashCode() {
244         final int prime = 31;
245         int result = super.hashCode();
246         result = prime * result + Objects.hash(dirList, fileList);
247         return result;
248     }
249 
250     /**
251      * Relativizes each directory path with {@link Path#relativize(Path)} against the given {@code parent}, optionally
252      * sorting the result.
253      *
254      * @param parent A parent path
255      * @param sort Whether to sort
256      * @param comparator How to sort, null uses default sorting.
257      * @return A new list
258      */
259     public List<Path> relativizeDirectories(final Path parent, final boolean sort,
260         final Comparator<? super Path> comparator) {
261         return PathUtils.relativize(getDirList(), parent, sort, comparator);
262     }
263 
264     /**
265      * Relativizes each file path with {@link Path#relativize(Path)} against the given {@code parent}, optionally
266      * sorting the result.
267      *
268      * @param parent A parent path
269      * @param sort Whether to sort
270      * @param comparator How to sort, null uses default sorting.
271      * @return A new list
272      */
273     public List<Path> relativizeFiles(final Path parent, final boolean sort,
274         final Comparator<? super Path> comparator) {
275         return PathUtils.relativize(getFileList(), parent, sort, comparator);
276     }
277 
278     @Override
279     protected void updateDirCounter(final Path dir, final IOException exc) {
280         super.updateDirCounter(dir, exc);
281         add(dirList, dir);
282     }
283 
284     @Override
285     protected void updateFileCounters(final Path file, final BasicFileAttributes attributes) {
286         super.updateFileCounters(file, attributes);
287         add(fileList, file);
288     }
289 
290 }