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.Files;
023import java.nio.file.Path;
024import java.nio.file.attribute.BasicFileAttributes;
025import java.util.List;
026import java.util.Objects;
027import java.util.stream.Stream;
028
029import org.apache.commons.io.FilenameUtils;
030import org.apache.commons.io.file.PathUtils;
031
032/**
033 * Filters files using the supplied wildcards.
034 * <p>
035 * This filter selects files, but not directories, based on one or more wildcards
036 * and using case-sensitive comparison.
037 * </p>
038 * <p>
039 * The wildcard matcher uses the characters '?' and '*' to represent a
040 * single or multiple wildcard characters.
041 * This is the same as often found on DOS/Unix command lines.
042 * The extension check is case-sensitive.
043 * See {@link FilenameUtils#wildcardMatch(String, String)} for more information.
044 * </p>
045 * <p>
046 * For example:
047 * </p>
048 * <h2>Using Classic IO</h2>
049 * <pre>
050 * File dir = FileUtils.current();
051 * FileFilter fileFilter = new WildcardFilter("*test*.java~*~");
052 * File[] files = dir.listFiles(fileFilter);
053 * for (String file : files) {
054 *     System.out.println(file);
055 * }
056 * </pre>
057 *
058 * <h2>Using NIO</h2>
059 * <pre>
060 * final Path dir = PathUtils.current();
061 * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new WildcardFilter("*test*.java~*~"));
062 * //
063 * // Walk one dir
064 * Files.<b>walkFileTree</b>(dir, Collections.emptySet(), 1, visitor);
065 * System.out.println(visitor.getPathCounters());
066 * System.out.println(visitor.getFileList());
067 * //
068 * visitor.getPathCounters().reset();
069 * //
070 * // Walk dir tree
071 * Files.<b>walkFileTree</b>(dir, visitor);
072 * System.out.println(visitor.getPathCounters());
073 * System.out.println(visitor.getDirList());
074 * System.out.println(visitor.getFileList());
075 * </pre>
076 * <h2>Deprecating Serialization</h2>
077 * <p>
078 * <em>Serialization is deprecated and will be removed in 3.0.</em>
079 * </p>
080 *
081 * @since 1.1
082 * @deprecated Use WildcardFileFilter. Deprecated as this class performs directory
083 * filtering which it shouldn't do, but that can't be removed due to compatibility.
084 */
085@Deprecated
086public class WildcardFilter extends AbstractFileFilter implements Serializable {
087
088    private static final long serialVersionUID = -5037645902506953517L;
089
090    /** The wildcards that will be used to match file names. */
091    private final String[] wildcards;
092
093    /**
094     * Constructs a new case-sensitive wildcard filter for a list of wildcards.
095     *
096     * @param wildcards  the list of wildcards to match
097     * @throws NullPointerException if the pattern list is null
098     * @throws ClassCastException if the list does not contain Strings
099     */
100    public WildcardFilter(final List<String> wildcards) {
101        Objects.requireNonNull(wildcards, "wildcards");
102        this.wildcards = wildcards.toArray(EMPTY_STRING_ARRAY);
103    }
104
105    /**
106     * Constructs a new case-sensitive wildcard filter for a single wildcard.
107     *
108     * @param wildcard  the wildcard to match
109     * @throws NullPointerException if the pattern is null
110     */
111    public WildcardFilter(final String wildcard) {
112        Objects.requireNonNull(wildcard, "wildcard");
113        this.wildcards = new String[] { wildcard };
114    }
115
116    /**
117     * Constructs a new case-sensitive wildcard filter for an array of wildcards.
118     *
119     * @param wildcards  the array of wildcards to match
120     * @throws NullPointerException if the pattern array is null
121     */
122    public WildcardFilter(final String... wildcards) {
123        Objects.requireNonNull(wildcards, "wildcards");
124        this.wildcards = wildcards.clone();
125    }
126
127    /**
128     * Checks to see if the file name matches one of the wildcards.
129     *
130     * @param file the file to check
131     * @return true if the file name matches one of the wildcards
132     */
133    @Override
134    public boolean accept(final File file) {
135        if (file.isDirectory()) {
136            return false;
137        }
138        return Stream.of(wildcards).anyMatch(wildcard -> FilenameUtils.wildcardMatch(file.getName(), wildcard));
139    }
140
141    /**
142     * Checks to see if the file name matches one of the wildcards.
143     *
144     * @param dir  the file directory
145     * @param name  the file name
146     * @return true if the file name matches one of the wildcards
147     */
148    @Override
149    public boolean accept(final File dir, final String name) {
150        if (dir != null && new File(dir, name).isDirectory()) {
151            return false;
152        }
153        return Stream.of(wildcards).anyMatch(wildcard -> FilenameUtils.wildcardMatch(name, wildcard));
154    }
155
156    /**
157     * Checks to see if the file name matches one of the wildcards.
158     * @param path the file to check
159     *
160     * @return true if the file name matches one of the wildcards
161     * @since 2.9.0
162     */
163    @Override
164    public FileVisitResult accept(final Path path, final BasicFileAttributes attributes) {
165        if (Files.isDirectory(path)) {
166            return FileVisitResult.TERMINATE;
167        }
168        return toDefaultFileVisitResult(
169                Stream.of(wildcards).anyMatch(wildcard -> FilenameUtils.wildcardMatch(PathUtils.getFileNameString(path), wildcard)));
170
171    }
172
173}