1
2
3
4
5 package com.qulice.maven;
6
7 import com.jcabi.log.Logger;
8 import com.qulice.spi.ResourceValidator;
9 import com.qulice.spi.ValidationException;
10 import com.qulice.spi.Validator;
11 import com.qulice.spi.Violation;
12 import java.io.File;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.List;
17 import java.util.Locale;
18 import java.util.concurrent.Callable;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.ExecutorService;
21 import java.util.concurrent.Executors;
22 import java.util.concurrent.Future;
23 import java.util.concurrent.TimeUnit;
24 import java.util.concurrent.TimeoutException;
25 import org.apache.maven.plugin.MojoFailureException;
26 import org.apache.maven.plugins.annotations.LifecyclePhase;
27 import org.apache.maven.plugins.annotations.Mojo;
28 import org.apache.maven.plugins.annotations.Parameter;
29 import org.apache.maven.plugins.annotations.ResolutionScope;
30
31
32
33
34
35 @Mojo(
36 name = "check",
37 defaultPhase = LifecyclePhase.VERIFY,
38 requiresDependencyResolution = ResolutionScope.TEST,
39 threadSafe = true
40 )
41 public final class CheckMojo extends AbstractQuliceMojo {
42
43
44
45
46 private final ExecutorService executors;
47
48
49
50
51 private ValidatorsProvider provider;
52
53
54
55
56
57
58
59
60
61 @Parameter(property = "qulice.check-timeout", defaultValue = "10")
62 private String timeout;
63
64
65
66
67 public CheckMojo() {
68 this(Executors.newFixedThreadPool(5));
69 }
70
71
72
73
74
75 private CheckMojo(final ExecutorService svc) {
76 this.executors = svc;
77 }
78
79 @Override
80 public void doExecute() throws MojoFailureException {
81 try {
82 this.run();
83 } catch (final ValidationException ex) {
84 Logger.info(
85 this,
86 "Read our quality policy: https://www.qulice.com/quality.html"
87 );
88 throw new MojoFailureException("Failure", ex);
89 }
90 }
91
92
93
94
95
96 public void setValidatorsProvider(final ValidatorsProvider prov) {
97 this.provider = prov;
98 }
99
100
101
102
103
104 public void setTimeout(final String time) {
105 this.timeout = time;
106 }
107
108
109
110
111
112 @SuppressWarnings("PMD.CognitiveComplexity")
113 private void run() throws ValidationException {
114 final List<Violation> results = new ArrayList<>(0);
115 final MavenEnvironment env = this.env();
116 final ValidatorsProvider prov = this.validators(env);
117 final Collection<File> files = env.files("*.*");
118 if (!files.isEmpty()) {
119 final Collection<Future<Collection<Violation>>> futures =
120 this.submit(env, files, prov.externalResource());
121 for (final Future<Collection<Violation>> future : futures) {
122 try {
123 if ("forever".equalsIgnoreCase(this.timeout)) {
124 results.addAll(future.get());
125 } else {
126 final long value = this.timeoutValue();
127 final TimeUnit units = this.timeoutUnits();
128 Logger.debug(
129 this,
130 "Waiting up to %d %s for validator result",
131 value,
132 units
133 );
134 results.addAll(future.get(value, units));
135 }
136 } catch (final InterruptedException ex) {
137 Thread.currentThread().interrupt();
138 throw new IllegalStateException(ex);
139 } catch (final ExecutionException | TimeoutException ex) {
140 throw new IllegalStateException(ex);
141 }
142 }
143 Collections.sort(results);
144 for (final Violation result : results) {
145 Logger.info(
146 this,
147 "%s: %s[%s]: %s (%s)",
148 result.validator(),
149 result.file().replace(
150 String.format(
151 "%s/", this.session().getExecutionRootDirectory()
152 ),
153 ""
154 ),
155 result.lines(),
156 result.message(),
157 result.name()
158 );
159 }
160 }
161 if (!results.isEmpty()) {
162 throw new ValidationException(
163 String.format("There are %d violations", results.size())
164 );
165 }
166 for (final Validator validator : prov.external()) {
167 Logger.info(this, "Starting %s validator", validator.name());
168 validator.validate(env);
169 Logger.info(this, "Finishing %s validator", validator.name());
170 }
171 for (final MavenValidator validator : prov.internal()) {
172 validator.validate(env);
173 }
174 }
175
176
177
178
179
180
181 private ValidatorsProvider validators(final MavenEnvironment env) {
182 final ValidatorsProvider prov;
183 if (this.provider == null) {
184 prov = new DefaultValidatorsProvider(env);
185 } else {
186 prov = this.provider;
187 }
188 return prov;
189 }
190
191
192
193
194
195
196
197
198 private Collection<Future<Collection<Violation>>> submit(
199 final MavenEnvironment env, final Collection<File> files,
200 final Collection<ResourceValidator> validators
201 ) {
202 final Collection<Future<Collection<Violation>>> futures =
203 new ArrayList<>(validators.size());
204 for (final ResourceValidator validator : validators) {
205 futures.add(
206 this.executors.submit(
207 new CheckMojo.ValidatorCallable(validator, env, files)
208 )
209 );
210 }
211 return futures;
212 }
213
214
215
216
217
218 private long timeoutValue() {
219 final String clear = this.clearTimeout();
220 final long res;
221 if (clear.isEmpty()) {
222 res = 10L;
223 } else if (clear.endsWith("s") || clear.endsWith("m") || clear.endsWith("h")) {
224 res = Long.parseLong(clear.substring(0, clear.length() - 1));
225 } else {
226 res = Long.parseLong(clear);
227 }
228 return res;
229 }
230
231
232
233
234
235 private TimeUnit timeoutUnits() {
236 final String clear = this.clearTimeout();
237 final TimeUnit unit;
238 if (clear.endsWith("s")) {
239 unit = TimeUnit.SECONDS;
240 } else if (clear.endsWith("m")) {
241 unit = TimeUnit.MINUTES;
242 } else if (clear.endsWith("h")) {
243 unit = TimeUnit.HOURS;
244 } else {
245 unit = TimeUnit.MINUTES;
246 }
247 return unit;
248 }
249
250
251
252
253
254 private String clearTimeout() {
255 final String clear;
256 if (this.timeout == null) {
257 clear = "";
258 } else {
259 clear = this.timeout.trim()
260 .replaceAll(" ", "")
261 .toLowerCase(Locale.ENGLISH);
262 }
263 return clear;
264 }
265
266
267
268
269
270
271
272
273 private static Collection<File> filter(
274 final MavenEnvironment env,
275 final Collection<File> files, final ResourceValidator validator
276 ) {
277 final Collection<File> filtered = new ArrayList<>(files.size());
278 for (final File file : files) {
279 if (
280 !env.exclude(
281 validator.name().toLowerCase(Locale.ENGLISH),
282 file.toString()
283 )
284 ) {
285 filtered.add(file);
286 }
287 }
288 return filtered;
289 }
290
291
292
293
294
295 private static class ValidatorCallable
296 implements Callable<Collection<Violation>> {
297
298
299
300
301 private final ResourceValidator validator;
302
303
304
305
306 private final MavenEnvironment env;
307
308
309
310
311 private final Collection<File> files;
312
313
314
315
316
317
318
319 ValidatorCallable(
320 final ResourceValidator validator,
321 final MavenEnvironment env, final Collection<File> files
322 ) {
323 this.validator = validator;
324 this.env = env;
325 this.files = files;
326 }
327
328 @Override
329 public Collection<Violation> call() {
330 return this.validator.validate(
331 CheckMojo.filter(this.env, this.files, this.validator)
332 );
333 }
334 }
335 }