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;
21
22 import java.io.OutputStream;
23 import java.io.OutputStreamWriter;
24 import java.io.PrintWriter;
25 import java.nio.charset.StandardCharsets;
26 import java.nio.file.Path;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.Map;
30 import java.util.Set;
31
32 import com.puppycrawl.tools.checkstyle.api.AuditEvent;
33 import com.puppycrawl.tools.checkstyle.api.AuditListener;
34
35
36
37
38
39 public class ChecksAndFilesSuppressionFileGeneratorAuditListener
40 extends AbstractAutomaticBean
41 implements AuditListener {
42
43
44 private static final String QUOTE_CHAR = "\"";
45
46
47
48
49 private final PrintWriter writer;
50
51
52 private final boolean closeStream;
53
54
55
56
57 private final Map<Path, Set<String>> filesAndChecksCollector = new HashMap<>();
58
59
60
61
62 private final Map<Path, Set<String>> filesAndModuleIdCollector = new HashMap<>();
63
64
65 private boolean isXmlHeaderPrinted;
66
67
68
69
70
71
72
73
74 public ChecksAndFilesSuppressionFileGeneratorAuditListener(OutputStream out,
75 OutputStreamOptions outputStreamOptions) {
76 writer = new PrintWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
77 closeStream = outputStreamOptions == OutputStreamOptions.CLOSE;
78 }
79
80 @Override
81 public void fileStarted(AuditEvent event) {
82
83 }
84
85 @Override
86 public void fileFinished(AuditEvent event) {
87
88 }
89
90 @Override
91 public void auditStarted(AuditEvent event) {
92
93 }
94
95 @Override
96 public void auditFinished(AuditEvent event) {
97 if (isXmlHeaderPrinted) {
98 writer.println("</suppressions>");
99 }
100
101 writer.flush();
102 if (closeStream) {
103 writer.close();
104 }
105 }
106
107 @Override
108 public void addError(AuditEvent event) {
109 printXmlHeader();
110
111 final Path path = Path.of(event.getFileName());
112 final Path fileName = path.getFileName();
113 final String checkName =
114 PackageObjectFactory.getShortFromFullModuleNames(event.getSourceName());
115 final String moduleIdName = event.getModuleId();
116
117 final boolean isAlreadyPresent;
118
119 if (fileName != null) {
120 if (moduleIdName == null) {
121 isAlreadyPresent = isFileAndCheckNamePresent(fileName, checkName);
122 }
123 else {
124 isAlreadyPresent = isFileAndModuleIdPresent(fileName, moduleIdName);
125 }
126 }
127 else {
128 isAlreadyPresent = true;
129 }
130
131 if (!isAlreadyPresent) {
132 suppressXmlWriter(fileName, checkName, moduleIdName);
133 }
134 }
135
136
137
138
139
140
141
142
143
144
145 private boolean isFileAndCheckNamePresent(Path fileName, String checkName) {
146 boolean isPresent = false;
147 final Set<String> checks = filesAndChecksCollector.get(fileName);
148 if (checks != null) {
149 isPresent = checks.contains(checkName);
150 }
151 return isPresent;
152 }
153
154
155
156
157
158
159
160
161
162
163 private boolean isFileAndModuleIdPresent(Path fileName, String moduleIdName) {
164 boolean isPresent = false;
165 final Set<String> moduleIds = filesAndModuleIdCollector.get(fileName);
166 if (moduleIds != null) {
167 isPresent = moduleIds.contains(moduleIdName);
168 }
169 return isPresent;
170 }
171
172 @Override
173 public void addException(AuditEvent event, Throwable throwable) {
174 throw new UnsupportedOperationException("Operation is not supported");
175 }
176
177
178
179
180
181
182
183
184
185 private void suppressXmlWriter(Path fileName, String checkName, String moduleIdName) {
186 writer.println(" <suppress");
187 writer.print(" files=\"");
188 writer.print(fileName);
189 writer.println(QUOTE_CHAR);
190
191 if (moduleIdName == null) {
192 writer.print(" checks=\"");
193 writer.print(checkName);
194 }
195 else {
196 writer.print(" id=\"");
197 writer.print(moduleIdName);
198 }
199 writer.println("\"/>");
200 addCheckOrModuleId(fileName, checkName, moduleIdName);
201 }
202
203
204
205
206
207
208
209
210
211
212 private void addCheckOrModuleId(Path fileName, String checkName, String moduleIdName) {
213 if (moduleIdName == null) {
214 addToCollector(filesAndChecksCollector, fileName, checkName);
215 }
216 else {
217 addToCollector(filesAndModuleIdCollector, fileName, moduleIdName);
218 }
219 }
220
221
222
223
224
225
226
227
228
229 private static void addToCollector(Map<Path, Set<String>> collector,
230 Path fileName, String value) {
231 final Set<String> values = collector.computeIfAbsent(fileName, key -> new HashSet<>());
232 values.add(value);
233 }
234
235
236
237
238 private void printXmlHeader() {
239 if (!isXmlHeaderPrinted) {
240 writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
241 writer.println("<!DOCTYPE suppressions PUBLIC");
242 writer.println(" \"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN\"");
243 writer.println(" \"https://checkstyle.org/dtds/configuration_1_3.dtd\">");
244 writer.println("<suppressions>");
245 isXmlHeaderPrinted = true;
246 }
247 }
248
249 @Override
250 protected void finishLocalSetup() {
251
252 }
253 }