001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2017 the original author or authors.
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018////////////////////////////////////////////////////////////////////////////////
019
020package com.puppycrawl.tools.checkstyle.filters;
021
022import java.io.IOException;
023import java.io.InputStream;
024import java.net.URI;
025import java.net.URL;
026import java.util.Collections;
027import java.util.Objects;
028import java.util.Set;
029
030import com.puppycrawl.tools.checkstyle.api.AuditEvent;
031import com.puppycrawl.tools.checkstyle.api.AutomaticBean;
032import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
033import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder;
034import com.puppycrawl.tools.checkstyle.api.Filter;
035import com.puppycrawl.tools.checkstyle.api.FilterSet;
036import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
037
038/**
039 * <p>
040 * This filter accepts AuditEvents according to file, check, line, and
041 * column, as specified in a suppression file.
042 * </p>
043 * @author Rick Giles
044 * @author <a href="mailto:piotr.listkiewicz@gmail.com">liscju</a>
045 */
046public class SuppressionFilter extends AutomaticBean implements Filter, ExternalResourceHolder {
047
048    /** Filename of supression file. */
049    private String file;
050    /** Tells whether config file existence is optional. */
051    private boolean optional;
052    /** Set of individual suppresses. */
053    private FilterSet filters = new FilterSet();
054
055    /**
056     * Sets name of the supression file.
057     * @param fileName name of the suppressions file.
058     */
059    public void setFile(String fileName) {
060        file = fileName;
061    }
062
063    /**
064     * Sets whether config file existence is optional.
065     * @param optional tells if config file existence is optional.
066     */
067    public void setOptional(boolean optional) {
068        this.optional = optional;
069    }
070
071    @Override
072    public boolean accept(AuditEvent event) {
073        return filters.accept(event);
074    }
075
076    @Override
077    public boolean equals(Object obj) {
078        if (this == obj) {
079            return true;
080        }
081        if (obj == null || getClass() != obj.getClass()) {
082            return false;
083        }
084        final SuppressionFilter suppressionFilter = (SuppressionFilter) obj;
085        return Objects.equals(filters, suppressionFilter.filters);
086    }
087
088    @Override
089    public int hashCode() {
090        return Objects.hash(filters);
091    }
092
093    @Override
094    protected void finishLocalSetup() throws CheckstyleException {
095        if (file != null) {
096            if (optional) {
097                if (suppressionSourceExists(file)) {
098                    filters = SuppressionsLoader.loadSuppressions(file);
099                }
100                else {
101                    filters = new FilterSet();
102                }
103            }
104            else {
105                filters = SuppressionsLoader.loadSuppressions(file);
106            }
107        }
108    }
109
110    @Override
111    public Set<String> getExternalResourceLocations() {
112        return Collections.singleton(file);
113    }
114
115    /**
116     * Checks if suppression source with given fileName exists.
117     * @param fileName name of the suppressions file.
118     * @return true if suppression file exists, otherwise false
119     */
120    private static boolean suppressionSourceExists(String fileName) {
121        boolean suppressionSourceExists = true;
122        InputStream sourceInput = null;
123        try {
124            final URI uriByFilename = CommonUtils.getUriByFilename(fileName);
125            final URL url = uriByFilename.toURL();
126            sourceInput = url.openStream();
127        }
128        catch (CheckstyleException | IOException ignored) {
129            suppressionSourceExists = false;
130        }
131        finally {
132            if (sourceInput != null) {
133                try {
134                    sourceInput.close();
135                }
136                catch (IOException ignored) {
137                    suppressionSourceExists = false;
138                }
139            }
140        }
141        return suppressionSourceExists;
142    }
143}