    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 *      https://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.FileFilter;
    021import java.io.FilenameFilter;
    022import java.io.IOException;
    023import java.nio.file.FileVisitResult;
    024import java.nio.file.Path;
    025import java.nio.file.attribute.BasicFileAttributes;
    026import java.util.List;
    027import java.util.Objects;
    028
    029import org.apache.commons.io.file.PathFilter;
    030import org.apache.commons.io.file.PathVisitor;
    031import org.apache.commons.io.function.IOSupplier;
    032
    033/**
    034 * Abstracts the implementation of the {@link FileFilter} (IO), {@link FilenameFilter} (IO), {@link PathFilter} (NIO)
    035 * interfaces via our own {@link IOFileFilter} interface.
    036 * <p>
    037 * Note that a subclass MUST override one of the {@code accept} methods, otherwise that subclass will infinitely loop.
    038 * </p>
    039 *
    040 * @since 1.0
    041 */
    042public abstract class AbstractFileFilter implements IOFileFilter, PathVisitor {
    043
    044    static FileVisitResult toDefaultFileVisitResult(final boolean accept) {
    045        return accept ? FileVisitResult.CONTINUE : FileVisitResult.TERMINATE;
    046    }
    047
    048    /**
    049     * What to do when this filter accepts.
    050     */
    051    private final FileVisitResult onAccept;
    052
    053    /**
    054     * What to do when this filter rejects.
    055     */
    056    private final FileVisitResult onReject;
    057
    058    /**
    059     * Constructs a new instance.
    060     */
    061    public AbstractFileFilter() {
    062        this(FileVisitResult.CONTINUE, FileVisitResult.TERMINATE);
    063    }
    064
    065    /**
    066     * Constructs a new instance.
    067     *
    068     * @param onAccept What to do on acceptance.
    069     * @param onReject What to do on rejection.
    070     * @since 2.12.0.
    071     */
    072    protected AbstractFileFilter(final FileVisitResult onAccept, final FileVisitResult onReject) {
    073        this.onAccept = onAccept;
    074        this.onReject = onReject;
    075    }
    076
    077    /**
    078     * Tests to see if the File should be accepted by this filter.
    079     *
    080     * @param file the File to check
    081     * @return true if this file matches the test
    082     */
    083    @Override
    084    public boolean accept(final File file) {
    085        Objects.requireNonNull(file, "file");
    086        return accept(file.getParentFile(), file.getName());
    087    }
    088
    089    /**
    090     * Tests to see if the File should be accepted by this filter.
    091     *
    092     * @param dir the directory File to check
    093     * @param name the file name within the directory to check
    094     * @return true if this file matches the test
    095     */
    096    @Override
    097    public boolean accept(final File dir, final String name) {
    098        Objects.requireNonNull(name, "name");
    099        return accept(new File(dir, name));
    100    }
    101
    102    void append(final List<?> list, final StringBuilder buffer) {
    103        for (int i = 0; i < list.size(); i++) {
    104            if (i > 0) {
    105                buffer.append(",");
    106            }
    107            buffer.append(list.get(i));
    108        }
    109    }
    110
    111    void append(final Object[] array, final StringBuilder buffer) {
    112        for (int i = 0; i < array.length; i++) {
    113            if (i > 0) {
    114                buffer.append(",");
    115            }
    116            buffer.append(array[i]);
    117        }
    118    }
    119
    120    FileVisitResult get(final IOSupplier<FileVisitResult> supplier) {
    121        try {
    122            return supplier.get();
    123        } catch (final IOException e) {
    124            return handle(e);
    125        }
    126    }
    127
    128    /**
    129     * Handles exceptions caught while accepting.
    130     *
    131     * @param t the caught Throwable.
    132     * @return the given Throwable.
    133     * @since 2.9.0
    134     */
    135    protected FileVisitResult handle(final Throwable t) {
    136        return FileVisitResult.TERMINATE;
    137    }
    138
    139    boolean isDirectory(final File file) {
    140        return file != null && file.isDirectory();
    141    }
    142
    143    boolean isFile(final File file) {
    144        return file != null && file.isFile();
    145    }
    146
    147    @Override
    148    public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
    149        return FileVisitResult.CONTINUE;
    150    }
    151
    152    @Override
    153    public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attributes) throws IOException {
    154        return accept(dir, attributes);
    155    }
    156
    157    /**
    158     * Converts a boolean into a FileVisitResult.
    159     *
    160     * @param accept accepted or rejected.
    161     * @return a FileVisitResult.
    162     */
    163    FileVisitResult toFileVisitResult(final boolean accept) {
    164        return accept ? onAccept : onReject;
    165    }
    166
    167    /**
    168     * Provides a String representation of this file filter.
    169     *
    170     * @return a String representation
    171     */
    172    @Override
    173    public String toString() {
    174        return getClass().getSimpleName();
    175    }
    176
    177    @Override
    178    public FileVisitResult visitFile(final Path file, final BasicFileAttributes attributes) throws IOException {
    179        return accept(file, attributes);
    180    }
    181
    182    @Override
    183    public FileVisitResult visitFileFailed(final Path file, final IOException exc) throws IOException {
    184        return FileVisitResult.CONTINUE;
    185    }
    186
    187}