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 private static final String DTD_PUBLIC_ID_1_1_XPATH =
78 "-//Puppy Crawl//DTD Suppressions Xpath Experimental 1.1//EN";
79
80 private static final String DTD_PUBLIC_CS_ID_1_1_XPATH =
81 "-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.1//EN";
82
83 private static final String DTD_SUPPRESSIONS_NAME_1_1_XPATH =
84 "com/puppycrawl/tools/checkstyle/suppressions_1_1_xpath_experimental.dtd";
85
86 private static final String DTD_PUBLIC_ID_1_2_XPATH =
87 "-//Puppy Crawl//DTD Suppressions Xpath Experimental 1.2//EN";
88
89 private static final String DTD_PUBLIC_CS_ID_1_2_XPATH =
90 "-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2//EN";
91
92 private static final String DTD_SUPPRESSIONS_NAME_1_2_XPATH =
93 "com/puppycrawl/tools/checkstyle/suppressions_1_2_xpath_experimental.dtd";
94
95 private static final String UNABLE_TO_FIND_ERROR_MESSAGE = "Unable to find: ";
96
97 private static final String ATTRIBUTE_NAME_FILES = "files";
98
99 private static final String ATTRIBUTE_NAME_CHECKS = "checks";
100
101 private static final String ATTRIBUTE_NAME_MESSAGE = "message";
102
103 private static final String ATTRIBUTE_NAME_ID = "id";
104
105 private static final String ATTRIBUTE_NAME_QUERY = "query";
106
107 private static final String ATTRIBUTE_NAME_LINES = "lines";
108
109 private static final String ATTRIBUTE_NAME_COLUMNS = "columns";
110
111
112
113
114
115 private final FilterSet filterChain = new FilterSet();
116
117
118
119
120 private final Set<TreeWalkerFilter> treeWalkerFilters = new HashSet<>();
121
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
158 private static SuppressFilterElement getSuppressElement(Attributes attributes)
159 throws SAXException {
160 final String checks = attributes.getValue(ATTRIBUTE_NAME_CHECKS);
161 final String modId = attributes.getValue(ATTRIBUTE_NAME_ID);
162 final String message = attributes.getValue(ATTRIBUTE_NAME_MESSAGE);
163 if (checks == null && modId == null && message == null) {
164
165 throw new SAXException("missing checks or id or message attribute");
166 }
167 final SuppressFilterElement suppress;
168 try {
169 final String files = attributes.getValue(ATTRIBUTE_NAME_FILES);
170 final String lines = attributes.getValue(ATTRIBUTE_NAME_LINES);
171 final String columns = attributes.getValue(ATTRIBUTE_NAME_COLUMNS);
172 suppress = new SuppressFilterElement(files, checks, message, modId, lines, columns);
173 }
174 catch (final PatternSyntaxException ex) {
175
176 throw new SAXException("invalid files or checks or message format", ex);
177 }
178 return suppress;
179 }
180
181
182
183
184
185
186
187
188
189 private static XpathFilterElement getXpathFilter(Attributes attributes) throws SAXException {
190 final String checks = attributes.getValue(ATTRIBUTE_NAME_CHECKS);
191 final String modId = attributes.getValue(ATTRIBUTE_NAME_ID);
192 final String message = attributes.getValue(ATTRIBUTE_NAME_MESSAGE);
193 if (checks == null && modId == null && message == null) {
194
195 throw new SAXException("missing checks or id or message attribute for suppress-xpath");
196 }
197 final XpathFilterElement filter;
198 try {
199 final String files = attributes.getValue(ATTRIBUTE_NAME_FILES);
200 final String xpathQuery = attributes.getValue(ATTRIBUTE_NAME_QUERY);
201 filter = new XpathFilterElement(files, checks, message, modId, xpathQuery);
202 }
203 catch (final PatternSyntaxException ex) {
204
205 throw new SAXException("invalid files or checks or message format for suppress-xpath",
206 ex);
207 }
208 return filter;
209 }
210
211
212
213
214
215
216
217
218 public static FilterSet loadSuppressions(String filename)
219 throws CheckstyleException {
220 return loadSuppressions(CommonUtil.sourceFromFilename(filename), filename);
221 }
222
223
224
225
226
227
228
229
230
231 private static FilterSet loadSuppressions(
232 InputSource source, String sourceName)
233 throws CheckstyleException {
234 return getSuppressionLoader(source, sourceName).filterChain;
235 }
236
237
238
239
240
241
242
243
244 public static Set<TreeWalkerFilter> loadXpathSuppressions(String filename)
245 throws CheckstyleException {
246 return loadXpathSuppressions(CommonUtil.sourceFromFilename(filename), filename);
247 }
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
271 private static SuppressionsLoader getSuppressionLoader(InputSource source, String sourceName)
272 throws CheckstyleException {
273 try {
274 final SuppressionsLoader suppressionsLoader =
275 new SuppressionsLoader();
276 suppressionsLoader.parseInputSource(source);
277 return suppressionsLoader;
278 }
279 catch (final FileNotFoundException ex) {
280 throw new CheckstyleException(UNABLE_TO_FIND_ERROR_MESSAGE + sourceName, ex);
281 }
282 catch (final ParserConfigurationException | SAXException ex) {
283 final String message = String.format(Locale.ROOT, "Unable to parse %s - %s",
284 sourceName, ex.getMessage());
285 throw new CheckstyleException(message, ex);
286 }
287 catch (final IOException ex) {
288 throw new CheckstyleException("Unable to read " + sourceName, ex);
289 }
290 catch (final NumberFormatException ex) {
291 final String message = String.format(Locale.ROOT, "Number format exception %s - %s",
292 sourceName, ex.getMessage());
293 throw new CheckstyleException(message, ex);
294 }
295 }
296
297
298
299
300
301
302 private static Map<String, String> createIdToResourceNameMap() {
303 final Map<String, String> map = new HashMap<>();
304 map.put(DTD_PUBLIC_ID_1_0, DTD_SUPPRESSIONS_NAME_1_0);
305 map.put(DTD_PUBLIC_ID_1_1, DTD_SUPPRESSIONS_NAME_1_1);
306 map.put(DTD_PUBLIC_ID_1_2, DTD_SUPPRESSIONS_NAME_1_2);
307 map.put(DTD_PUBLIC_ID_1_1_XPATH, DTD_SUPPRESSIONS_NAME_1_1_XPATH);
308 map.put(DTD_PUBLIC_ID_1_2_XPATH, DTD_SUPPRESSIONS_NAME_1_2_XPATH);
309 map.put(DTD_PUBLIC_CS_ID_1_0, DTD_SUPPRESSIONS_NAME_1_0);
310 map.put(DTD_PUBLIC_CS_ID_1_1, DTD_SUPPRESSIONS_NAME_1_1);
311 map.put(DTD_PUBLIC_CS_ID_1_2, DTD_SUPPRESSIONS_NAME_1_2);
312 map.put(DTD_PUBLIC_CS_ID_1_1_XPATH, DTD_SUPPRESSIONS_NAME_1_1_XPATH);
313 map.put(DTD_PUBLIC_CS_ID_1_2_XPATH, DTD_SUPPRESSIONS_NAME_1_2_XPATH);
314 return map;
315 }
316
317 }