    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.io.file;
    019
    020import java.io.IOException;
    021import java.nio.file.Path;
    022import java.nio.file.attribute.BasicFileAttributes;
    023import java.util.ArrayList;
    024import java.util.Comparator;
    025import java.util.List;
    026import java.util.Objects;
    027
    028import org.apache.commons.io.file.Counters.PathCounters;
    029
    030/**
    031 * Accumulates normalized paths during visitation.
    032 * <p>
    033 * Use with care on large file trees as each visited Path element is remembered.
    034 * </p>
    035 * <h2>Example</h2>
    036 *
    037 * <pre>
    038 * Path dir = Paths.get("");
    039 * // We are interested in files older than one day
    040 * long cutoff = System.currentTimeMillis() - (24 * 60 * 60 * 1000);
    041 * AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new AgeFileFilter(cutoff));
    042 * //
    043 * // Walk one dir
    044 * Files.walkFileTree(dir, Collections.emptySet(), 1, visitor);
    045 * System.out.println(visitor.getPathCounters());
    046 * System.out.println(visitor.getFileList());
    047 * //
    048 * visitor.getPathCounters().reset();
    049 * //
    050 * // Walk dir tree
    051 * Files.walkFileTree(dir, visitor);
    052 * System.out.println(visitor.getPathCounters());
    053 * System.out.println(visitor.getDirList());
    054 * System.out.println(visitor.getFileList());
    055 * </pre>
    056 *
    057 * @since 2.7
    058 */
    059public class AccumulatorPathVisitor extends CountingPathVisitor {
    060
    061    /**
    062     * Creates a new instance configured with a BigInteger {@link PathCounters}.
    063     *
    064     * @return a new instance configured with a BigInteger {@link PathCounters}.
    065     */
    066    public static AccumulatorPathVisitor withBigIntegerCounters() {
    067        return new AccumulatorPathVisitor(Counters.bigIntegerPathCounters());
    068    }
    069
    070    /**
    071     * Creates a new instance configured with a BigInteger {@link PathCounters}.
    072     *
    073     * @param fileFilter Filters files to accumulate and count.
    074     * @param dirFilter Filters directories to accumulate and count.
    075     * @return a new instance configured with a long {@link PathCounters}.
    076     * @since 2.9.0
    077     */
    078    public static AccumulatorPathVisitor withBigIntegerCounters(final PathFilter fileFilter,
    079        final PathFilter dirFilter) {
    080        return new AccumulatorPathVisitor(Counters.bigIntegerPathCounters(), fileFilter, dirFilter);
    081    }
    082
    083    /**
    084     * Creates a new instance configured with a long {@link PathCounters}.
    085     *
    086     * @return a new instance configured with a long {@link PathCounters}.
    087     */
    088    public static AccumulatorPathVisitor withLongCounters() {
    089        return new AccumulatorPathVisitor(Counters.longPathCounters());
    090    }
    091
    092    /**
    093     * Creates a new instance configured with a long {@link PathCounters}.
    094     *
    095     * @param fileFilter Filters files to accumulate and count.
    096     * @param dirFilter Filters directories to accumulate and count.
    097     * @return a new instance configured with a long {@link PathCounters}.
    098     * @since 2.9.0
    099     */
    100    public static AccumulatorPathVisitor withLongCounters(final PathFilter fileFilter, final PathFilter dirFilter) {
    101        return new AccumulatorPathVisitor(Counters.longPathCounters(), fileFilter, dirFilter);
    102    }
    103
    104    private final List<Path> dirList = new ArrayList<>();
    105
    106    private final List<Path> fileList = new ArrayList<>();
    107
    108    /**
    109     * Constructs a new instance.
    110     *
    111     * @since 2.9.0
    112     */
    113    public AccumulatorPathVisitor() {
    114        super(Counters.noopPathCounters());
    115    }
    116
    117    /**
    118     * Constructs a new instance that counts file system elements.
    119     *
    120     * @param pathCounter How to count path visits.
    121     */
    122    public AccumulatorPathVisitor(final PathCounters pathCounter) {
    123        super(pathCounter);
    124    }
    125
    126    /**
    127     * Constructs a new instance.
    128     *
    129     * @param pathCounter How to count path visits.
    130     * @param fileFilter Filters which files to count.
    131     * @param dirFilter Filters which directories to count.
    132     * @since 2.9.0
    133     */
    134    public AccumulatorPathVisitor(final PathCounters pathCounter, final PathFilter fileFilter,
    135        final PathFilter dirFilter) {
    136        super(pathCounter, fileFilter, dirFilter);
    137    }
    138
    139    private void add(final List<Path> list, final Path dir) {
    140        list.add(dir.normalize());
    141    }
    142
    143    @Override
    144    public boolean equals(final Object obj) {
    145        if (this == obj) {
    146            return true;
    147        }
    148        if (!super.equals(obj)) {
    149            return false;
    150        }
    151        if (!(obj instanceof AccumulatorPathVisitor)) {
    152            return false;
    153        }
    154        final AccumulatorPathVisitor other = (AccumulatorPathVisitor) obj;
    155        return Objects.equals(dirList, other.dirList) && Objects.equals(fileList, other.fileList);
    156    }
    157
    158    /**
    159     * Gets the list of visited directories.
    160     *
    161     * @return the list of visited directories.
    162     */
    163    public List<Path> getDirList() {
    164        return dirList;
    165    }
    166
    167    /**
    168     * Gets the list of visited files.
    169     *
    170     * @return the list of visited files.
    171     */
    172    public List<Path> getFileList() {
    173        return fileList;
    174    }
    175
    176    @Override
    177    public int hashCode() {
    178        final int prime = 31;
    179        int result = super.hashCode();
    180        result = prime * result + Objects.hash(dirList, fileList);
    181        return result;
    182    }
    183
    184    /**
    185     * Relativizes each directory path with {@link Path#relativize(Path)} against the given {@code parent}, optionally
    186     * sorting the result.
    187     *
    188     * @param parent A parent path
    189     * @param sort Whether to sort
    190     * @param comparator How to sort, null uses default sorting.
    191     * @return A new list
    192     */
    193    public List<Path> relativizeDirectories(final Path parent, final boolean sort,
    194        final Comparator<? super Path> comparator) {
    195        return PathUtils.relativize(getDirList(), parent, sort, comparator);
    196    }
    197
    198    /**
    199     * Relativizes each file path with {@link Path#relativize(Path)} against the given {@code parent}, optionally
    200     * sorting the result.
    201     *
    202     * @param parent A parent path
    203     * @param sort Whether to sort
    204     * @param comparator How to sort, null uses default sorting.
    205     * @return A new list
    206     */
    207    public List<Path> relativizeFiles(final Path parent, final boolean sort,
    208        final Comparator<? super Path> comparator) {
    209        return PathUtils.relativize(getFileList(), parent, sort, comparator);
    210    }
    211
    212    @Override
    213    protected void updateDirCounter(final Path dir, final IOException exc) {
    214        super.updateDirCounter(dir, exc);
    215        add(dirList, dir);
    216    }
    217
    218    @Override
    219    protected void updateFileCounters(final Path file, final BasicFileAttributes attributes) {
    220        super.updateFileCounters(file, attributes);
    221        add(fileList, file);
    222    }
    223
    224}