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}