001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2014  Oliver Burn
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////////////////////////////////////////////////////////////////////////////////
019package com.puppycrawl.tools.checkstyle.api;
020
021import java.io.File;
022import java.util.List;
023import java.util.TreeSet;
024
025/**
026 * Provides common functionality for many FileSetChecks.
027 *
028 * @author lkuehne
029 * @author oliver
030 */
031public abstract class AbstractFileSetCheck
032    extends AbstractViolationReporter
033    implements FileSetCheck
034{
035    /** The dispatcher errors are fired to. */
036    private MessageDispatcher mDispatcher;
037
038    /** the file extensions that are accepted by this filter */
039    private String[] mFileExtensions = {};
040
041    /** collects the error messages */
042    private final LocalizedMessages mMessages = new LocalizedMessages();
043
044    /**
045     * Called to process a file that matches the specified file extensions.
046     * @param aFile the file to be processed
047     * @param aLines an immutable list of the contents of the file.
048     */
049    protected abstract void processFiltered(File aFile, List<String> aLines);
050
051    /** {@inheritDoc} */
052    public void init()
053    {
054    }
055
056    /** {@inheritDoc} */
057    public void destroy()
058    {
059    }
060
061    /** {@inheritDoc} */
062    public void beginProcessing(String aCharset)
063    {
064    }
065
066    /** {@inheritDoc} */
067    public final TreeSet<LocalizedMessage> process(File aFile,
068                                                   List<String> aLines)
069    {
070        getMessageCollector().reset();
071        // Process only what interested in
072        if (fileExtensionMatches(aFile)) {
073            processFiltered(aFile, aLines);
074        }
075        return getMessageCollector().getMessages();
076    }
077
078    /** {@inheritDoc} */
079    public void finishProcessing()
080    {
081    }
082
083    /** {@inheritDoc} */
084    public final void setMessageDispatcher(MessageDispatcher aDispatcher)
085    {
086        mDispatcher = aDispatcher;
087    }
088
089    /**
090     * A message dispatcher is used to fire violation messages to
091     * interested audit listeners.
092     *
093     * @return the current MessageDispatcher.
094     */
095    protected final MessageDispatcher getMessageDispatcher()
096    {
097        return mDispatcher;
098    }
099
100    /**
101     * Sets the file extensions that identify the files that pass the
102     * filter of this FileSetCheck.
103     * @param aExtensions the set of file extensions. A missing
104     * initial '.' character of an extension is automatically added.
105     */
106    public final void setFileExtensions(String[] aExtensions)
107    {
108        if (aExtensions == null) {
109            mFileExtensions = null;
110            return;
111        }
112
113        mFileExtensions = new String[aExtensions.length];
114        for (int i = 0; i < aExtensions.length; i++) {
115            final String extension = aExtensions[i];
116            if (extension.startsWith(".")) {
117                mFileExtensions[i] = extension;
118            }
119            else {
120                mFileExtensions[i] = "." + extension;
121            }
122        }
123    }
124
125    /**
126     * Returns the collector for violation messages.
127     * Subclasses can use the collector to find out the violation
128     * messages to fire via the message dispatcher.
129     *
130     * @return the collector for localized messages.
131     */
132    protected final LocalizedMessages getMessageCollector()
133    {
134        return mMessages;
135    }
136
137    @Override
138    public final void log(int aLine, String aKey, Object... aArgs)
139    {
140        log(aLine, 0, aKey, aArgs);
141    }
142
143    @Override
144    public final void log(int aLineNo, int aColNo, String aKey,
145            Object... aArgs)
146    {
147        getMessageCollector().add(
148            new LocalizedMessage(aLineNo,
149                                 aColNo,
150                                 getMessageBundle(),
151                                 aKey,
152                                 aArgs,
153                                 getSeverityLevel(),
154                                 getId(),
155                                 this.getClass(),
156                                 this.getCustomMessages().get(aKey)));
157    }
158
159    /**
160     * Notify all listeners about the errors in a file.
161     * Calls <code>MessageDispatcher.fireErrors()</code> with
162     * all logged errors and than clears errors' list.
163     * @param aFileName the audited file
164     */
165    protected final void fireErrors(String aFileName)
166    {
167        final TreeSet<LocalizedMessage> errors = getMessageCollector()
168                .getMessages();
169        getMessageCollector().reset();
170        getMessageDispatcher().fireErrors(aFileName, errors);
171    }
172
173    /**
174     * Returns whether the file extension matches what we are meant to
175     * process.
176     * @param aFile the file to be checked.
177     * @return whether there is a match.
178     */
179    private boolean fileExtensionMatches(File aFile)
180    {
181        if ((null == mFileExtensions) || (mFileExtensions.length == 0)) {
182            return true;
183        }
184
185        // normalize extensions so all of them have a leading dot
186        final String[] withDotExtensions = new String[mFileExtensions.length];
187        for (int i = 0; i < mFileExtensions.length; i++) {
188            final String extension = mFileExtensions[i];
189            if (extension.startsWith(".")) {
190                withDotExtensions[i] = extension;
191            }
192            else {
193                withDotExtensions[i] = "." + extension;
194            }
195        }
196
197        final String fileName = aFile.getName();
198        for (final String fileExtension : withDotExtensions) {
199            if (fileName.endsWith(fileExtension)) {
200                return true;
201            }
202        }
203
204        return false;
205    }
206}