View Javadoc
1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2018 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.api;
21  
22  import java.io.File;
23  import java.util.Arrays;
24  import java.util.SortedSet;
25  import java.util.TreeSet;
26  
27  import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
28  
29  /**
30   * Provides common functionality for many FileSetChecks.
31   *
32   * @author lkuehne
33   * @author oliver
34   * @noinspection NoopMethodInAbstractClass
35   */
36  public abstract class AbstractFileSetCheck
37      extends AbstractViolationReporter
38      implements FileSetCheck {
39  
40      /**
41       * Collects the error messages.
42       */
43      private static final ThreadLocal<SortedSet<LocalizedMessage>> MESSAGE_COLLECTOR =
44              ThreadLocal.withInitial(TreeSet::new);
45  
46      /** The dispatcher errors are fired to. */
47      private MessageDispatcher messageDispatcher;
48  
49      /** The file extensions that are accepted by this filter. */
50      private String[] fileExtensions = CommonUtils.EMPTY_STRING_ARRAY;
51  
52      /**
53       * Called to process a file that matches the specified file extensions.
54       * @param file the file to be processed
55       * @param fileText the contents of the file.
56       * @throws CheckstyleException if error condition within Checkstyle occurs.
57       */
58      protected abstract void processFiltered(File file, FileText fileText)
59              throws CheckstyleException;
60  
61      @Override
62      public void init() {
63          // No code by default, should be overridden only by demand at subclasses
64      }
65  
66      @Override
67      public void destroy() {
68          // No code by default, should be overridden only by demand at subclasses
69      }
70  
71      @Override
72      public void beginProcessing(String charset) {
73          // No code by default, should be overridden only by demand at subclasses
74      }
75  
76      @Override
77      public final SortedSet<LocalizedMessage> process(File file, FileText fileText)
78              throws CheckstyleException {
79          final SortedSet<LocalizedMessage> messages = MESSAGE_COLLECTOR.get();
80          messages.clear();
81          // Process only what interested in
82          if (CommonUtils.matchesFileExtension(file, fileExtensions)) {
83              processFiltered(file, fileText);
84          }
85          final SortedSet<LocalizedMessage> result = new TreeSet<>(messages);
86          messages.clear();
87          return result;
88      }
89  
90      @Override
91      public void finishProcessing() {
92          // No code by default, should be overridden only by demand at subclasses
93      }
94  
95      @Override
96      public final void setMessageDispatcher(MessageDispatcher messageDispatcher) {
97          this.messageDispatcher = messageDispatcher;
98      }
99  
100     /**
101      * A message dispatcher is used to fire violation messages to
102      * interested audit listeners.
103      *
104      * @return the current MessageDispatcher.
105      */
106     protected final MessageDispatcher getMessageDispatcher() {
107         return messageDispatcher;
108     }
109 
110     /**
111      * Makes copy of file extensions and returns them.
112      * @return file extensions that identify the files that pass the
113      *     filter of this FileSetCheck.
114      */
115     public String[] getFileExtensions() {
116         return Arrays.copyOf(fileExtensions, fileExtensions.length);
117     }
118 
119     /**
120      * Sets the file extensions that identify the files that pass the
121      * filter of this FileSetCheck.
122      * @param extensions the set of file extensions. A missing
123      *         initial '.' character of an extension is automatically added.
124      * @throws IllegalArgumentException is argument is null
125      */
126     public final void setFileExtensions(String... extensions) {
127         if (extensions == null) {
128             throw new IllegalArgumentException("Extensions array can not be null");
129         }
130 
131         fileExtensions = new String[extensions.length];
132         for (int i = 0; i < extensions.length; i++) {
133             final String extension = extensions[i];
134             if (CommonUtils.startsWithChar(extension, '.')) {
135                 fileExtensions[i] = extension;
136             }
137             else {
138                 fileExtensions[i] = "." + extension;
139             }
140         }
141     }
142 
143     /**
144      * Adds the sorted set of {@link LocalizedMessage} to the message collector.
145      * @param messages the sorted set of {@link LocalizedMessage}.
146      */
147     protected static void addMessages(SortedSet<LocalizedMessage> messages) {
148         MESSAGE_COLLECTOR.get().addAll(messages);
149     }
150 
151     @Override
152     public final void log(int line, String key, Object... args) {
153         log(line, 0, key, args);
154     }
155 
156     @Override
157     public final void log(int lineNo, int colNo, String key,
158             Object... args) {
159         MESSAGE_COLLECTOR.get().add(
160                 new LocalizedMessage(lineNo,
161                         colNo,
162                         getMessageBundle(),
163                         key,
164                         args,
165                         getSeverityLevel(),
166                         getId(),
167                         getClass(),
168                         getCustomMessages().get(key)));
169     }
170 
171     /**
172      * Notify all listeners about the errors in a file.
173      * Calls {@code MessageDispatcher.fireErrors()} with
174      * all logged errors and than clears errors' list.
175      * @param fileName the audited file
176      */
177     protected final void fireErrors(String fileName) {
178         final SortedSet<LocalizedMessage> errors = new TreeSet<>(MESSAGE_COLLECTOR.get());
179         MESSAGE_COLLECTOR.get().clear();
180         messageDispatcher.fireErrors(fileName, errors);
181     }
182 
183 }