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.FileVisitResult;
022import java.nio.file.Files;
023import java.nio.file.Path;
024import java.nio.file.attribute.BasicFileAttributes;
025import java.util.ArrayList;
026import java.util.Comparator;
027import java.util.List;
028import java.util.Objects;
029
030import org.apache.commons.io.file.Counters.PathCounters;
031
032/**
033 * Accumulates normalized paths during visitation.
034 * <p>
035 * Use with care on large file trees as each visited Path element is remembered.
036 * </p>
037 *
038 * @since 2.7
039 */
040public class AccumulatorPathVisitor extends CountingPathVisitor {
041
042    /**
043     * Creates a new instance configured with a BigInteger {@link PathCounters}.
044     *
045     * @return a new instance configured with a BigInteger {@link PathCounters}.
046     */
047    public static AccumulatorPathVisitor withBigIntegerCounters() {
048        return new AccumulatorPathVisitor(Counters.bigIntegerPathCounters());
049    }
050
051    /**
052     * Creates a new instance configured with a long {@link PathCounters}.
053     *
054     * @return a new instance configured with a long {@link PathCounters}.
055     */
056    public static AccumulatorPathVisitor withLongCounters() {
057        return new AccumulatorPathVisitor(Counters.longPathCounters());
058    }
059
060    private final List<Path> dirList = new ArrayList<>();
061
062    private final List<Path> fileList = new ArrayList<>();
063
064    /**
065     * Constructs a new instance.
066     *
067     * @param pathCounter How to count path visits.
068     */
069    public AccumulatorPathVisitor(PathCounters pathCounter) {
070        super(pathCounter);
071    }
072
073    @Override
074    public boolean equals(Object obj) {
075        if (this == obj) {
076            return true;
077        }
078        if (!super.equals(obj)) {
079            return false;
080        }
081        if (!(obj instanceof AccumulatorPathVisitor)) {
082            return false;
083        }
084        AccumulatorPathVisitor other = (AccumulatorPathVisitor) obj;
085        return Objects.equals(dirList, other.dirList) && Objects.equals(fileList, other.fileList);
086    }
087
088    /**
089     * Gets the list of visited directories.
090     * 
091     * @return the list of visited directories.
092     */
093    public List<Path> getDirList() {
094        return dirList;
095    }
096
097    /**
098     * Gets the list of visited files.
099     * 
100     * @return the list of visited files.
101     */
102    public List<Path> getFileList() {
103        return fileList;
104    }
105
106    @Override
107    public int hashCode() {
108        final int prime = 31;
109        int result = super.hashCode();
110        result = prime * result + Objects.hash(dirList, fileList);
111        return result;
112    }
113
114    /**
115     * Relativizes each directory path with {@link Path#relativize(Path)} against the given {@code parent}, optionally
116     * sorting the result.
117     * 
118     * @param parent A parent path
119     * @param sort Whether to sort
120     * @param comparator How to sort, null uses default sorting.
121     * @return A new list
122     */
123    public List<Path> relativizeDirectories(final Path parent, boolean sort, Comparator<? super Path> comparator) {
124        return PathUtils.relativize(getDirList(), parent, sort, comparator);
125    }
126
127    /**
128     * Relativizes each file path with {@link Path#relativize(Path)} against the given {@code parent}, optionally
129     * sorting the result.
130     * 
131     * @param parent A parent path
132     * @param sort Whether to sort
133     * @param comparator How to sort, null uses default sorting.
134     * @return A new list
135     */
136    public List<Path> relativizeFiles(final Path parent, boolean sort, Comparator<? super Path> comparator) {
137        return PathUtils.relativize(getFileList(), parent, sort, comparator);
138    }
139
140    @Override
141    public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException {
142        ((Files.isDirectory(file)) ? dirList : fileList).add(file.normalize());
143        return super.visitFile(file, attributes);
144    }
145
146}