1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.filters;
21
22 import java.io.FileNotFoundException;
23 import java.io.IOException;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Locale;
27 import java.util.Map;
28 import java.util.Set;
29 import java.util.regex.PatternSyntaxException;
30
31 import javax.xml.parsers.ParserConfigurationException;
32
33 import org.xml.sax.Attributes;
34 import org.xml.sax.InputSource;
35 import org.xml.sax.SAXException;
36
37 import com.puppycrawl.tools.checkstyle.TreeWalkerFilter;
38 import com.puppycrawl.tools.checkstyle.XmlLoader;
39 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
40 import com.puppycrawl.tools.checkstyle.api.FilterSet;
41 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
42
43
44
45
46 public final class SuppressionsLoader
47 extends XmlLoader {
48
49
50 private static final String DTD_PUBLIC_ID_1_0 =
51 "-//Puppy Crawl//DTD Suppressions 1.0//EN";
52
53 private static final String DTD_PUBLIC_CS_ID_1_0 =
54 "-//Checkstyle//DTD SuppressionFilter Configuration 1.0//EN";
55
56 private static final String DTD_SUPPRESSIONS_NAME_1_0 =
57 "com/puppycrawl/tools/checkstyle/suppressions_1_0.dtd";
58
59 private static final String DTD_PUBLIC_ID_1_1 =
60 "-//Puppy Crawl//DTD Suppressions 1.1//EN";
61
62 private static final String DTD_PUBLIC_CS_ID_1_1 =
63 "-//Checkstyle//DTD SuppressionFilter Configuration 1.1//EN";
64
65 private static final String DTD_SUPPRESSIONS_NAME_1_1 =
66 "com/puppycrawl/tools/checkstyle/suppressions_1_1.dtd";
67
68 private static final String DTD_PUBLIC_ID_1_2 =
69 "-//Puppy Crawl//DTD Suppressions 1.2//EN";
70
71 private static final String DTD_PUBLIC_CS_ID_1_2 =
72 "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN";
73
74 private static final String DTD_SUPPRESSIONS_NAME_1_2 =
75 "com/puppycrawl/tools/checkstyle/suppressions_1_2.dtd";
76
77
78 private static final String DTD_PUBLIC_ID_1_1_XPATH_EXPERIMENTAL =
79 "-//Puppy Crawl//DTD Suppressions Xpath Experimental 1.1//EN";
80
81 private static final String DTD_PUBLIC_CS_ID_1_1_XPATH_EXPERIMENTAL =
82 "-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.1//EN";
83
84 private static final String DTD_PUBLIC_ID_1_1_XPATH =
85 "-//Puppy Crawl//DTD Suppressions Xpath 1.1//EN";
86
87 private static final String DTD_PUBLIC_CS_ID_1_1_XPATH =
88 "-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.1//EN";
89
90 private static final String DTD_SUPPRESSIONS_NAME_1_1_XPATH =
91 "com/puppycrawl/tools/checkstyle/suppressions_1_1_xpath.dtd";
92
93
94 private static final String DTD_PUBLIC_ID_1_2_XPATH_EXPERIMENTAL =
95 "-//Puppy Crawl//DTD Suppressions Xpath Experimental 1.2//EN";
96
97 private static final String DTD_PUBLIC_CS_ID_1_2_XPATH_EXPERIMENTAL =
98 "-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2//EN";
99
100 private static final String DTD_PUBLIC_ID_1_2_XPATH =
101 "-//Puppy Crawl//DTD Suppressions Xpath 1.2//EN";
102
103 private static final String DTD_PUBLIC_CS_ID_1_2_XPATH =
104 "-//Checkstyle//DTD SuppressionXpathFilter Configuration 1.2//EN";
105
106 private static final String DTD_SUPPRESSIONS_NAME_1_2_XPATH =
107 "com/puppycrawl/tools/checkstyle/suppressions_1_2_xpath.dtd";
108
109
110 private static final String UNABLE_TO_FIND_ERROR_MESSAGE = "Unable to find: ";
111
112 private static final String ATTRIBUTE_NAME_FILES = "files";
113
114 private static final String ATTRIBUTE_NAME_CHECKS = "checks";
115
116 private static final String ATTRIBUTE_NAME_MESSAGE = "message";
117
118 private static final String ATTRIBUTE_NAME_ID = "id";
119
120 private static final String ATTRIBUTE_NAME_QUERY = "query";
121
122 private static final String ATTRIBUTE_NAME_LINES = "lines";
123
124 private static final String ATTRIBUTE_NAME_COLUMNS = "columns";
125
126
127
128
129
130 private final FilterSet filterChain = new FilterSet();
131
132
133
134
135 private final Set<TreeWalkerFilter> treeWalkerFilters = new HashSet<>();
136
137
138
139
140
141
142
143 private SuppressionsLoader()
144 throws ParserConfigurationException, SAXException {
145 super(createIdToResourceNameMap());
146 }
147
148 @Override
149 public void startElement(String namespaceUri,
150 String localName,
151 String qName,
152 Attributes attributes)
153 throws SAXException {
154 if ("suppress".equals(qName)) {
155
156 final SuppressFilterElement suppress = getSuppressElement(attributes);
157 filterChain.addFilter(suppress);
158 }
159 else if ("suppress-xpath".equals(qName)) {
160 final XpathFilterElement filter = getXpathFilter(attributes);
161 treeWalkerFilters.add(filter);
162 }
163 }
164
165
166
167
168
169
170
171
172
173 private static SuppressFilterElement getSuppressElement(Attributes attributes)
174 throws SAXException {
175 final String checks = attributes.getValue(ATTRIBUTE_NAME_CHECKS);
176 final String modId = attributes.getValue(ATTRIBUTE_NAME_ID);
177 final String message = attributes.getValue(ATTRIBUTE_NAME_MESSAGE);
178 if (checks == null && modId == null && message == null) {
179
180 throw new SAXException("missing checks or id or message attribute");
181 }
182 final SuppressFilterElement suppress;
183 try {
184 final String files = attributes.getValue(ATTRIBUTE_NAME_FILES);
185 final String lines = attributes.getValue(ATTRIBUTE_NAME_LINES);
186 final String columns = attributes.getValue(ATTRIBUTE_NAME_COLUMNS);
187 suppress = new SuppressFilterElement(files, checks, message, modId, lines, columns);
188 }
189 catch (final PatternSyntaxException exc) {
190
191 throw new SAXException("invalid files or checks or message format", exc);
192 }
193 return suppress;
194 }
195
196
197
198
199
200
201
202
203
204 private static XpathFilterElement getXpathFilter(Attributes attributes) throws SAXException {
205 final String checks = attributes.getValue(ATTRIBUTE_NAME_CHECKS);
206 final String modId = attributes.getValue(ATTRIBUTE_NAME_ID);
207 final String message = attributes.getValue(ATTRIBUTE_NAME_MESSAGE);
208 if (checks == null && modId == null && message == null) {
209
210 throw new SAXException("missing checks or id or message attribute for suppress-xpath");
211 }
212 final XpathFilterElement filter;
213 try {
214 final String files = attributes.getValue(ATTRIBUTE_NAME_FILES);
215 final String xpathQuery = attributes.getValue(ATTRIBUTE_NAME_QUERY);
216 filter = new XpathFilterElement(files, checks, message, modId, xpathQuery);
217 }
218 catch (final PatternSyntaxException exc) {
219
220 throw new SAXException("invalid files or checks or message format for suppress-xpath",
221 exc);
222 }
223 return filter;
224 }
225
226
227
228
229
230
231
232
233 public static FilterSet loadSuppressions(String filename)
234 throws CheckstyleException {
235 return loadSuppressions(CommonUtil.sourceFromFilename(filename), filename);
236 }
237
238
239
240
241
242
243
244
245
246 private static FilterSet loadSuppressions(
247 InputSource source, String sourceName)
248 throws CheckstyleException {
249 return getSuppressionLoader(source, sourceName).filterChain;
250 }
251
252
253
254
255
256
257
258
259 public static Set<TreeWalkerFilter> loadXpathSuppressions(String filename)
260 throws CheckstyleException {
261 return loadXpathSuppressions(CommonUtil.sourceFromFilename(filename), filename);
262 }
263
264
265
266
267
268
269
270
271
272 private static Set<TreeWalkerFilter> loadXpathSuppressions(
273 InputSource source, String sourceName)
274 throws CheckstyleException {
275 return getSuppressionLoader(source, sourceName).treeWalkerFilters;
276 }
277
278
279
280
281
282
283
284
285
286 private static SuppressionsLoader getSuppressionLoader(InputSource source, String sourceName)
287 throws CheckstyleException {
288 try {
289 final SuppressionsLoader suppressionsLoader =
290 new SuppressionsLoader();
291 suppressionsLoader.parseInputSource(source);
292 return suppressionsLoader;
293 }
294 catch (final FileNotFoundException exc) {
295 throw new CheckstyleException(UNABLE_TO_FIND_ERROR_MESSAGE + sourceName, exc);
296 }
297 catch (final ParserConfigurationException | SAXException exc) {
298 final String message = String.format(Locale.ROOT, "Unable to parse %s - %s",
299 sourceName, exc.getMessage());
300 throw new CheckstyleException(message, exc);
301 }
302 catch (final IOException exc) {
303 throw new CheckstyleException("Unable to read " + sourceName, exc);
304 }
305 catch (final NumberFormatException exc) {
306 final String message = String.format(Locale.ROOT, "Number format exception %s - %s",
307 sourceName, exc.getMessage());
308 throw new CheckstyleException(message, exc);
309 }
310 }
311
312
313
314
315
316
317 private static Map<String, String> createIdToResourceNameMap() {
318 final Map<String, String> map = new HashMap<>();
319 map.put(DTD_PUBLIC_ID_1_0, DTD_SUPPRESSIONS_NAME_1_0);
320 map.put(DTD_PUBLIC_ID_1_1, DTD_SUPPRESSIONS_NAME_1_1);
321 map.put(DTD_PUBLIC_ID_1_2, DTD_SUPPRESSIONS_NAME_1_2);
322 map.put(DTD_PUBLIC_CS_ID_1_0, DTD_SUPPRESSIONS_NAME_1_0);
323 map.put(DTD_PUBLIC_CS_ID_1_1, DTD_SUPPRESSIONS_NAME_1_1);
324 map.put(DTD_PUBLIC_CS_ID_1_2, DTD_SUPPRESSIONS_NAME_1_2);
325
326
327 map.put(DTD_PUBLIC_ID_1_1_XPATH_EXPERIMENTAL, DTD_SUPPRESSIONS_NAME_1_1_XPATH);
328 map.put(DTD_PUBLIC_CS_ID_1_1_XPATH_EXPERIMENTAL, DTD_SUPPRESSIONS_NAME_1_1_XPATH);
329 map.put(DTD_PUBLIC_ID_1_1_XPATH, DTD_SUPPRESSIONS_NAME_1_1_XPATH);
330 map.put(DTD_PUBLIC_CS_ID_1_1_XPATH, DTD_SUPPRESSIONS_NAME_1_1_XPATH);
331
332
333 map.put(DTD_PUBLIC_ID_1_2_XPATH_EXPERIMENTAL, DTD_SUPPRESSIONS_NAME_1_2_XPATH);
334 map.put(DTD_PUBLIC_CS_ID_1_2_XPATH_EXPERIMENTAL, DTD_SUPPRESSIONS_NAME_1_2_XPATH);
335 map.put(DTD_PUBLIC_ID_1_2_XPATH, DTD_SUPPRESSIONS_NAME_1_2_XPATH);
336 map.put(DTD_PUBLIC_CS_ID_1_2_XPATH, DTD_SUPPRESSIONS_NAME_1_2_XPATH);
337 return map;
338 }
339
340 }