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