AccumulatorPathVisitor.java

  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. package org.apache.commons.io.file;

  18. import java.io.IOException;
  19. import java.nio.file.FileVisitResult;
  20. import java.nio.file.Path;
  21. import java.nio.file.attribute.BasicFileAttributes;
  22. import java.util.ArrayList;
  23. import java.util.Comparator;
  24. import java.util.List;
  25. import java.util.Objects;

  26. import org.apache.commons.io.file.Counters.PathCounters;
  27. import org.apache.commons.io.function.IOBiFunction;

  28. /**
  29.  * Accumulates normalized paths during visitation.
  30.  * <p>
  31.  * Use with care on large file trees as each visited Path element is remembered.
  32.  * </p>
  33.  * <h2>Example</h2>
  34.  *
  35.  * <pre>
  36.  * Path dir = PathUtils.current();
  37.  * // We are interested in files older than one day
  38.  * Instant cutoff = Instant.now().minus(Duration.ofDays(1));
  39.  * AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new AgeFileFilter(cutoff));
  40.  * //
  41.  * // Walk one directory
  42.  * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
  43.  * System.out.println(visitor.getPathCounters());
  44.  * System.out.println(visitor.getFileList());
  45.  * //
  46.  * visitor.getPathCounters().reset();
  47.  * //
  48.  * // Walk directory tree
  49.  * Files.walkFileTree(dir, visitor);
  50.  * System.out.println(visitor.getPathCounters());
  51.  * System.out.println(visitor.getDirList());
  52.  * System.out.println(visitor.getFileList());
  53.  * </pre>
  54.  *
  55.  * @since 2.7
  56.  */
  57. public class AccumulatorPathVisitor extends CountingPathVisitor {

  58.     /**
  59.      * Builds instances of {@link AccumulatorPathVisitor}.
  60.      *
  61.      * @since 2.19.0
  62.      */
  63.     public static class Builder extends AbstractBuilder<AccumulatorPathVisitor, Builder> {

  64.         /**
  65.          * Constructs a new builder.
  66.          */
  67.         public Builder() {
  68.             // empty.
  69.         }

  70.         @Override
  71.         public AccumulatorPathVisitor get() {
  72.             return new AccumulatorPathVisitor(this);
  73.         }

  74.     }

  75.     /**
  76.      * Builds instances of {@link AccumulatorPathVisitor}.
  77.      *
  78.      * @return a new builder.
  79.      * @since 2.19.0
  80.      */
  81.     public static Builder builder() {
  82.         return new Builder();
  83.     }

  84.     /**
  85.      * Constructs a new instance configured with a BigInteger {@link PathCounters}.
  86.      *
  87.      * @return a new instance configured with a BigInteger {@link PathCounters}.
  88.      * @see #builder()
  89.      * @see Builder
  90.      */
  91.     public static AccumulatorPathVisitor withBigIntegerCounters() {
  92.         return builder().setPathCounters(Counters.bigIntegerPathCounters()).get();
  93.     }

  94.     /**
  95.      * Constructs a new instance configured with a BigInteger {@link PathCounters}.
  96.      *
  97.      * @param fileFilter Filters files to accumulate and count.
  98.      * @param dirFilter Filters directories to accumulate and count.
  99.      * @return a new instance configured with a long {@link PathCounters}.
  100.      * @see #builder()
  101.      * @see Builder
  102.      * @since 2.9.0
  103.      */
  104.     public static AccumulatorPathVisitor withBigIntegerCounters(final PathFilter fileFilter, final PathFilter dirFilter) {
  105.         return builder().setPathCounters(Counters.bigIntegerPathCounters()).setFileFilter(fileFilter).setDirectoryFilter(dirFilter).get();
  106.     }

  107.     /**
  108.      * Constructs a new instance configured with a long {@link PathCounters}.
  109.      *
  110.      * @return a new instance configured with a long {@link PathCounters}.
  111.      * @see #builder()
  112.      * @see Builder
  113.      */
  114.     public static AccumulatorPathVisitor withLongCounters() {
  115.         return builder().setPathCounters(Counters.longPathCounters()).get();
  116.     }

  117.     /**
  118.      * Constructs a new instance configured with a long {@link PathCounters}.
  119.      *
  120.      * @param fileFilter Filters files to accumulate and count.
  121.      * @param dirFilter Filters directories to accumulate and count.
  122.      * @return a new instance configured with a long {@link PathCounters}.
  123.      * @see #builder()
  124.      * @see Builder
  125.      * @since 2.9.0
  126.      */
  127.     public static AccumulatorPathVisitor withLongCounters(final PathFilter fileFilter, final PathFilter dirFilter) {
  128.         return builder().setPathCounters(Counters.longPathCounters()).setFileFilter(fileFilter).setDirectoryFilter(dirFilter).get();
  129.     }

  130.     private final List<Path> dirList = new ArrayList<>();

  131.     private final List<Path> fileList = new ArrayList<>();

  132.     /**
  133.      * Constructs a new instance with a noop path counter.
  134.      *
  135.      * @since 2.9.0
  136.      * @deprecated Use {@link #builder()}.
  137.      */
  138.     @Deprecated
  139.     public AccumulatorPathVisitor() {
  140.         super(Counters.noopPathCounters());
  141.     }

  142.     private AccumulatorPathVisitor(final Builder builder) {
  143.         super(builder);
  144.     }

  145.     /**
  146.      * Constructs a new instance that counts file system elements.
  147.      *
  148.      * @param pathCounter How to count path visits.
  149.      * @deprecated Use {@link #builder()}.
  150.      */
  151.     @Deprecated
  152.     public AccumulatorPathVisitor(final PathCounters pathCounter) {
  153.         super(pathCounter);
  154.     }

  155.     /**
  156.      * Constructs a new instance.
  157.      *
  158.      * @param pathCounter How to count path visits.
  159.      * @param fileFilter Filters which files to count.
  160.      * @param dirFilter Filters which directories to count.
  161.      * @since 2.9.0
  162.      * @deprecated Use {@link #builder()}.
  163.      */
  164.     @Deprecated
  165.     public AccumulatorPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter, final PathFilter dirFilter) {
  166.         super(pathCounter, fileFilter, dirFilter);
  167.     }

  168.     /**
  169.      * Constructs a new instance.
  170.      *
  171.      * @param pathCounter How to count path visits.
  172.      * @param fileFilter Filters which files to count.
  173.      * @param dirFilter Filters which directories to count.
  174.      * @param visitFileFailed Called on {@link #visitFileFailed(Path, IOException)}.
  175.      * @since 2.12.0
  176.      * @deprecated Use {@link #builder()}.
  177.      */
  178.     @Deprecated
  179.     public AccumulatorPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter, final PathFilter dirFilter,
  180.         final IOBiFunction<Path, IOException, FileVisitResult> visitFileFailed) {
  181.         super(pathCounter, fileFilter, dirFilter, visitFileFailed);
  182.     }

  183.     private void add(final List<Path> list, final Path dir) {
  184.         list.add(dir.normalize());
  185.     }

  186.     @Override
  187.     public boolean equals(final Object obj) {
  188.         if (this == obj) {
  189.             return true;
  190.         }
  191.         if (!super.equals(obj)) {
  192.             return false;
  193.         }
  194.         if (!(obj instanceof AccumulatorPathVisitor)) {
  195.             return false;
  196.         }
  197.         final AccumulatorPathVisitor other = (AccumulatorPathVisitor) obj;
  198.         return Objects.equals(dirList, other.dirList) && Objects.equals(fileList, other.fileList);
  199.     }

  200.     /**
  201.      * Gets a copy of the list of visited directories.
  202.      *
  203.      * @return a copy of the list of visited directories.
  204.      */
  205.     public List<Path> getDirList() {
  206.         return new ArrayList<>(dirList);
  207.     }

  208.     /**
  209.      * Gets a copy of the list of visited files.
  210.      *
  211.      * @return a copy of the list of visited files.
  212.      */
  213.     public List<Path> getFileList() {
  214.         return new ArrayList<>(fileList);
  215.     }

  216.     @Override
  217.     public int hashCode() {
  218.         final int prime = 31;
  219.         int result = super.hashCode();
  220.         result = prime * result + Objects.hash(dirList, fileList);
  221.         return result;
  222.     }

  223.     /**
  224.      * Relativizes each directory path with {@link Path#relativize(Path)} against the given {@code parent}, optionally
  225.      * sorting the result.
  226.      *
  227.      * @param parent A parent path
  228.      * @param sort Whether to sort
  229.      * @param comparator How to sort, null uses default sorting.
  230.      * @return A new list
  231.      */
  232.     public List<Path> relativizeDirectories(final Path parent, final boolean sort,
  233.         final Comparator<? super Path> comparator) {
  234.         return PathUtils.relativize(getDirList(), parent, sort, comparator);
  235.     }

  236.     /**
  237.      * Relativizes each file path with {@link Path#relativize(Path)} against the given {@code parent}, optionally
  238.      * sorting the result.
  239.      *
  240.      * @param parent A parent path
  241.      * @param sort Whether to sort
  242.      * @param comparator How to sort, null uses default sorting.
  243.      * @return A new list
  244.      */
  245.     public List<Path> relativizeFiles(final Path parent, final boolean sort,
  246.         final Comparator<? super Path> comparator) {
  247.         return PathUtils.relativize(getFileList(), parent, sort, comparator);
  248.     }

  249.     @Override
  250.     protected void updateDirCounter(final Path dir, final IOException exc) {
  251.         super.updateDirCounter(dir, exc);
  252.         add(dirList, dir);
  253.     }

  254.     @Override
  255.     protected void updateFileCounters(final Path file, final BasicFileAttributes attributes) {
  256.         super.updateFileCounters(file, attributes);
  257.         add(fileList, file);
  258.     }

  259. }