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 */
017package org.apache.commons.io.filefilter;
018
019import java.io.File;
020import java.io.Serializable;
021import java.nio.file.FileVisitResult;
022import java.nio.file.Path;
023import java.nio.file.attribute.BasicFileAttributes;
024import java.util.List;
025import java.util.Objects;
026import java.util.stream.Stream;
027
028import org.apache.commons.io.IOCase;
029
030/**
031 * Filters file names for a certain name.
032 * <p>
033 * For example, to print all files and directories in the
034 * current directory whose name is {@code Test}:
035 * </p>
036 * <h2>Using Classic IO</h2>
037 * <pre>
038 * File dir = FileUtils.current();
039 * String[] files = dir.list(new NameFileFilter("Test"));
040 * for (String file : files) {
041 *     System.out.println(file);
042 * }
043 * </pre>
044 *
045 * <h2>Using NIO</h2>
046 * <pre>
047 * final Path dir = PathUtils.current();
048 * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new NameFileFilter("Test"));
049 * //
050 * // Walk one dir
051 * Files.<b>walkFileTree</b>(dir, Collections.emptySet(), 1, visitor);
052 * System.out.println(visitor.getPathCounters());
053 * System.out.println(visitor.getFileList());
054 * //
055 * visitor.getPathCounters().reset();
056 * //
057 * // Walk dir tree
058 * Files.<b>walkFileTree</b>(dir, visitor);
059 * System.out.println(visitor.getPathCounters());
060 * System.out.println(visitor.getDirList());
061 * System.out.println(visitor.getFileList());
062 * </pre>
063 * <h2>Deprecating Serialization</h2>
064 * <p>
065 * <em>Serialization is deprecated and will be removed in 3.0.</em>
066 * </p>
067 *
068 * @since 1.0
069 * @see FileFilterUtils#nameFileFilter(String)
070 * @see FileFilterUtils#nameFileFilter(String, IOCase)
071 */
072public class NameFileFilter extends AbstractFileFilter implements Serializable {
073
074    private static final long serialVersionUID = 176844364689077340L;
075
076    /** The file names to search for */
077    private final String[] names;
078
079    /** Whether the comparison is case-sensitive. */
080    private final IOCase ioCase;
081
082    /**
083     * Constructs a new case-sensitive name file filter for a list of names.
084     *
085     * @param names  the names to allow, must not be null
086     * @throws IllegalArgumentException if the name list is null
087     * @throws ClassCastException if the list does not contain Strings
088     */
089    public NameFileFilter(final List<String> names) {
090        this(names, null);
091    }
092
093    /**
094     * Constructs a new name file filter for a list of names specifying case-sensitivity.
095     *
096     * @param names  the names to allow, must not be null
097     * @param ioCase  how to handle case sensitivity, null means case-sensitive
098     * @throws NullPointerException if the name list is null
099     * @throws ClassCastException if the list does not contain Strings
100     */
101    public NameFileFilter(final List<String> names, final IOCase ioCase) {
102        Objects.requireNonNull(names, "names");
103        this.names = names.toArray(EMPTY_STRING_ARRAY);
104        this.ioCase = toIOCase(ioCase);
105    }
106
107    /**
108     * Constructs a new case-sensitive name file filter for a single name.
109     *
110     * @param name  the name to allow, must not be null
111     * @throws IllegalArgumentException if the name is null
112     */
113    public NameFileFilter(final String name) {
114        this(name, IOCase.SENSITIVE);
115    }
116
117    /**
118     * Constructs a new case-sensitive name file filter for an array of names.
119     * <p>
120     * The array is not cloned, so could be changed after constructing the
121     * instance. This would be inadvisable however.
122     * </p>
123     *
124     * @param names  the names to allow, must not be null
125     * @throws IllegalArgumentException if the names array is null
126     */
127    public NameFileFilter(final String... names) {
128        this(names, IOCase.SENSITIVE);
129    }
130
131    /**
132     * Constructs a new name file filter specifying case-sensitivity.
133     *
134     * @param name  the name to allow, must not be null
135     * @param ioCase  how to handle case sensitivity, null means case-sensitive
136     * @throws NullPointerException if the name is null
137     */
138    public NameFileFilter(final String name, final IOCase ioCase) {
139        Objects.requireNonNull(name, "name");
140        this.names = new String[] {name};
141        this.ioCase = toIOCase(ioCase);
142    }
143
144    /**
145     * Constructs a new name file filter for an array of names specifying case-sensitivity.
146     *
147     * @param names  the names to allow, must not be null
148     * @param ioCase  how to handle case sensitivity, null means case-sensitive
149     * @throws NullPointerException if the names array is null
150     */
151    public NameFileFilter(final String[] names, final IOCase ioCase) {
152        Objects.requireNonNull(names, "names");
153        this.names = names.clone();
154        this.ioCase = toIOCase(ioCase);
155    }
156
157    /**
158     * Checks to see if the file name matches.
159     *
160     * @param file  the File to check
161     * @return true if the file name matches
162     */
163    @Override
164    public boolean accept(final File file) {
165        return acceptBaseName(file.getName());
166    }
167
168    /**
169     * Checks to see if the file name matches.
170     *
171     * @param dir  the File directory (ignored)
172     * @param name  the file name
173     * @return true if the file name matches
174     */
175    @Override
176    public boolean accept(final File dir, final String name) {
177        return acceptBaseName(name);
178    }
179
180    /**
181     * Checks to see if the file name matches.
182     * @param file  the File to check
183     *
184     * @return true if the file name matches
185     * @since 2.9.0
186     */
187    @Override
188    public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) {
189        return toFileVisitResult(acceptBaseName(Objects.toString(file.getFileName(), null)));
190    }
191
192    private boolean acceptBaseName(final String baseName) {
193        return Stream.of(names).anyMatch(testName -> ioCase.checkEquals(baseName, testName));
194    }
195
196    private IOCase toIOCase(final IOCase ioCase) {
197        return IOCase.value(ioCase, IOCase.SENSITIVE);
198    }
199
200    /**
201     * Provide a String representation of this file filter.
202     *
203     * @return a String representation
204     */
205    @Override
206    public String toString() {
207        final StringBuilder buffer = new StringBuilder();
208        buffer.append(super.toString());
209        buffer.append("(");
210        append(names, buffer);
211        buffer.append(")");
212        return buffer.toString();
213    }
214
215}