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 String doExecute() throws MojoFailureException {
81 try {
82 return 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
113 @SuppressWarnings("PMD.CognitiveComplexity")
114 private String run() throws ValidationException {
115 final List<Violation> results = new ArrayList<>(0);
116 final MavenEnvironment env = this.env();
117 final ValidatorsProvider prov = this.validators(env);
118 final Collection<ResourceValidator> resources = prov.externalResource();
119 final Collection<File> files = env.files("*.*");
120 if (!files.isEmpty()) {
121 final Collection<Future<Collection<Violation>>> futures =
122 this.submit(env, files, resources);
123 for (final Future<Collection<Violation>> future : futures) {
124 try {
125 if ("forever".equalsIgnoreCase(this.timeout)) {
126 results.addAll(future.get());
127 } else {
128 final long value = this.timeoutValue();
129 final TimeUnit units = this.timeoutUnits();
130 Logger.debug(
131 this,
132 "Waiting up to %d %s for validator result",
133 value,
134 units
135 );
136 results.addAll(future.get(value, units));
137 }
138 } catch (final InterruptedException ex) {
139 Thread.currentThread().interrupt();
140 throw new IllegalStateException(ex);
141 } catch (final ExecutionException | TimeoutException ex) {
142 throw new IllegalStateException(ex);
143 }
144 }
145 Collections.sort(results);
146 for (final Violation result : results) {
147 Logger.info(
148 this,
149 "%s: %s[%s]: %s (%s)",
150 result.validator(),
151 result.file().replace(
152 String.format(
153 "%s/", this.session().getExecutionRootDirectory()
154 ),
155 ""
156 ),
157 result.lines(),
158 result.message(),
159 result.name()
160 );
161 }
162 }
163 if (!results.isEmpty()) {
164 throw new ValidationException(
165 String.format("There are %d violations", results.size())
166 );
167 }
168 for (final Validator validator : prov.external()) {
169 Logger.info(this, "Starting %s validator", validator.name());
170 validator.validate(env);
171 Logger.info(this, "Finishing %s validator", validator.name());
172 }
173 for (final MavenValidator validator : prov.internal()) {
174 validator.validate(env);
175 }
176 return new Summary(files, resources).toString();
177 }
178
179
180
181
182
183
184 private ValidatorsProvider validators(final MavenEnvironment env) {
185 final ValidatorsProvider prov;
186 if (this.provider == null) {
187 prov = new DefaultValidatorsProvider(env);
188 } else {
189 prov = this.provider;
190 }
191 return prov;
192 }
193
194
195
196
197
198
199
200
201 private Collection<Future<Collection<Violation>>> submit(
202 final MavenEnvironment env, final Collection<File> files,
203 final Collection<ResourceValidator> validators
204 ) {
205 final Collection<Future<Collection<Violation>>> futures =
206 new ArrayList<>(validators.size());
207 for (final ResourceValidator validator : validators) {
208 futures.add(
209 this.executors.submit(
210 new CheckMojo.ValidatorCallable(validator, env, files)
211 )
212 );
213 }
214 return futures;
215 }
216
217
218
219
220
221 private long timeoutValue() {
222 final String clear = this.clearTimeout();
223 final long res;
224 if (clear.isEmpty()) {
225 res = 10L;
226 } else if (clear.endsWith("s") || clear.endsWith("m") || clear.endsWith("h")) {
227 res = Long.parseLong(clear.substring(0, clear.length() - 1));
228 } else {
229 res = Long.parseLong(clear);
230 }
231 return res;
232 }
233
234
235
236
237
238 private TimeUnit timeoutUnits() {
239 final String clear = this.clearTimeout();
240 final TimeUnit unit;
241 if (clear.endsWith("s")) {
242 unit = TimeUnit.SECONDS;
243 } else if (clear.endsWith("m")) {
244 unit = TimeUnit.MINUTES;
245 } else if (clear.endsWith("h")) {
246 unit = TimeUnit.HOURS;
247 } else {
248 unit = TimeUnit.MINUTES;
249 }
250 return unit;
251 }
252
253
254
255
256
257 private String clearTimeout() {
258 final String clear;
259 if (this.timeout == null) {
260 clear = "";
261 } else {
262 clear = this.timeout.trim()
263 .replaceAll(" ", "")
264 .toLowerCase(Locale.ENGLISH);
265 }
266 return clear;
267 }
268
269
270
271
272
273
274
275
276 private static Collection<File> filter(
277 final MavenEnvironment env,
278 final Collection<File> files, final ResourceValidator validator
279 ) {
280 final Collection<File> filtered = new ArrayList<>(files.size());
281 for (final File file : files) {
282 if (
283 !env.exclude(
284 validator.name().toLowerCase(Locale.ENGLISH),
285 file.toString()
286 )
287 ) {
288 filtered.add(file);
289 }
290 }
291 return filtered;
292 }
293
294
295
296
297
298 private static class ValidatorCallable
299 implements Callable<Collection<Violation>> {
300
301
302
303
304 private final ResourceValidator validator;
305
306
307
308
309 private final MavenEnvironment env;
310
311
312
313
314 private final Collection<File> files;
315
316
317
318
319
320
321
322 ValidatorCallable(
323 final ResourceValidator validator,
324 final MavenEnvironment env, final Collection<File> files
325 ) {
326 this.validator = validator;
327 this.env = env;
328 this.files = files;
329 }
330
331 @Override
332 public Collection<Violation> call() {
333 return this.validator.validate(
334 CheckMojo.filter(this.env, this.files, this.validator)
335 );
336 }
337 }
338 }