    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.ArrayList;
    025import java.util.Collections;
    026import java.util.List;
    027import java.util.Objects;
    028
    029/**
    030 * A {@link java.io.FileFilter} providing conditional OR logic across a list of file filters. This filter returns
    031 * {@code true} if any filters in the list return {@code true}. Otherwise, it returns {@code false}. Checking of the
    032 * file filter list stops when the first filter returns {@code true}.
    033 *
    034 * @since 1.0
    035 * @see FileFilterUtils#or(IOFileFilter...)
    036 */
    037public class OrFileFilter extends AbstractFileFilter implements ConditionalFileFilter, Serializable {
    038
    039    private static final long serialVersionUID = 5767770777065432721L;
    040
    041    /** The list of file filters. */
    042    private final List<IOFileFilter> fileFilters;
    043
    044    /**
    045     * Constructs a new instance of {@code OrFileFilter}.
    046     *
    047     * @since 1.1
    048     */
    049    public OrFileFilter() {
    050        this(0);
    051    }
    052
    053    /**
    054     * Constructs a new instance with the given initial list.
    055     *
    056     * @param initialList the initial list.
    057     */
    058    private OrFileFilter(final ArrayList<IOFileFilter> initialList) {
    059        this.fileFilters = Objects.requireNonNull(initialList, "initialList");
    060    }
    061
    062    /**
    063     * Constructs a new instance with the given initial capacity.
    064     *
    065     * @param initialCapacity the initial capacity.
    066     */
    067    private OrFileFilter(final int initialCapacity) {
    068        this(new ArrayList<>(initialCapacity));
    069    }
    070
    071    /**
    072     * Constructs a new instance for the give filters.
    073     * @param fileFilters filters to OR.
    074     *
    075     * @since 2.9.0
    076     */
    077    public OrFileFilter(final IOFileFilter... fileFilters) {
    078        this(Objects.requireNonNull(fileFilters, "fileFilters").length);
    079        addFileFilter(fileFilters);
    080    }
    081
    082    /**
    083     * Constructs a new file filter that ORs the result of other filters.
    084     *
    085     * @param filter1 the first filter, must not be null
    086     * @param filter2 the second filter, must not be null
    087     * @throws IllegalArgumentException if either filter is null
    088     */
    089    public OrFileFilter(final IOFileFilter filter1, final IOFileFilter filter2) {
    090        this(2);
    091        addFileFilter(filter1);
    092        addFileFilter(filter2);
    093    }
    094
    095    /**
    096     * Constructs a new instance of {@code OrFileFilter} with the specified filters.
    097     *
    098     * @param fileFilters the file filters for this filter, copied.
    099     * @since 1.1
    100     */
    101    public OrFileFilter(final List<IOFileFilter> fileFilters) {
    102        this(new ArrayList<>(Objects.requireNonNull(fileFilters, "fileFilters")));
    103    }
    104
    105    /**
    106     * {@inheritDoc}
    107     */
    108    @Override
    109    public boolean accept(final File file) {
    110        for (final IOFileFilter fileFilter : fileFilters) {
    111            if (fileFilter.accept(file)) {
    112                return true;
    113            }
    114        }
    115        return false;
    116    }
    117
    118    /**
    119     * {@inheritDoc}
    120     */
    121    @Override
    122    public boolean accept(final File file, final String name) {
    123        for (final IOFileFilter fileFilter : fileFilters) {
    124            if (fileFilter.accept(file, name)) {
    125                return true;
    126            }
    127        }
    128        return false;
    129    }
    130
    131    /**
    132     * {@inheritDoc}
    133     */
    134    @Override
    135    public FileVisitResult accept(final Path file, final BasicFileAttributes attributes) {
    136        for (final IOFileFilter fileFilter : fileFilters) {
    137            if (fileFilter.accept(file, attributes) == FileVisitResult.CONTINUE) {
    138                return FileVisitResult.CONTINUE;
    139            }
    140        }
    141        return FileVisitResult.TERMINATE;
    142    }
    143
    144    /**
    145     * {@inheritDoc}
    146     */
    147    @Override
    148    public void addFileFilter(final IOFileFilter fileFilter) {
    149        this.fileFilters.add(Objects.requireNonNull(fileFilter, "fileFilter"));
    150    }
    151
    152    /**
    153     * Adds the given file filters.
    154     *
    155     * @param fileFilters the filters to add.
    156     * @since 2.9.0
    157     */
    158    public void addFileFilter(final IOFileFilter... fileFilters) {
    159        for (final IOFileFilter fileFilter : Objects.requireNonNull(fileFilters, "fileFilters")) {
    160            addFileFilter(fileFilter);
    161        }
    162    }
    163
    164    /**
    165     * {@inheritDoc}
    166     */
    167    @Override
    168    public List<IOFileFilter> getFileFilters() {
    169        return Collections.unmodifiableList(this.fileFilters);
    170    }
    171
    172    /**
    173     * {@inheritDoc}
    174     */
    175    @Override
    176    public boolean removeFileFilter(final IOFileFilter fileFilter) {
    177        return this.fileFilters.remove(fileFilter);
    178    }
    179
    180    /**
    181     * {@inheritDoc}
    182     */
    183    @Override
    184    public void setFileFilters(final List<IOFileFilter> fileFilters) {
    185        this.fileFilters.clear();
    186        this.fileFilters.addAll(Objects.requireNonNull(fileFilters, "fileFilters"));
    187    }
    188
    189    /**
    190     * Provide a String representation of this file filter.
    191     *
    192     * @return a String representation
    193     */
    194    @Override
    195    public String toString() {
    196        final StringBuilder buffer = new StringBuilder();
    197        buffer.append(super.toString());
    198        buffer.append("(");
    199        if (fileFilters != null) {
    200            for (int i = 0; i < fileFilters.size(); i++) {
    201                if (i > 0) {
    202                    buffer.append(",");
    203                }
    204                buffer.append(fileFilters.get(i));
    205            }
    206        }
    207        buffer.append(")");
    208        return buffer.toString();
    209    }
    210
    211}