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