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.Locale;
17 import java.util.concurrent.Callable;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.ExecutorService;
20 import java.util.concurrent.Executors;
21 import java.util.concurrent.Future;
22 import java.util.concurrent.TimeUnit;
23 import java.util.concurrent.TimeoutException;
24 import org.apache.maven.plugin.MojoFailureException;
25 import org.apache.maven.plugins.annotations.LifecyclePhase;
26 import org.apache.maven.plugins.annotations.Mojo;
27 import org.apache.maven.plugins.annotations.Parameter;
28 import org.apache.maven.plugins.annotations.ResolutionScope;
29
30
31
32
33
34
35 @Mojo(name = "check", defaultPhase = LifecyclePhase.VERIFY,
36 requiresDependencyResolution = ResolutionScope.TEST,
37 threadSafe = true)
38 public final class CheckMojo extends AbstractQuliceMojo {
39
40
41
42
43 private final ExecutorService executors =
44 Executors.newFixedThreadPool(5);
45
46
47
48
49 private ValidatorsProvider provider =
50 new DefaultValidatorsProvider(this.env());
51
52
53
54
55
56
57
58
59
60 @Parameter(property = "qulice.check-timeout", defaultValue = "10")
61 private String timeout;
62
63 @Override
64 public void doExecute() throws MojoFailureException {
65 try {
66 this.run();
67 } catch (final ValidationException ex) {
68 Logger.info(
69 this,
70 "Read our quality policy: http://www.qulice.com/quality.html"
71 );
72 throw new MojoFailureException("Failure", ex);
73 }
74 }
75
76
77
78
79
80 public void setValidatorsProvider(final ValidatorsProvider prov) {
81 this.provider = prov;
82 }
83
84
85
86
87
88 public void setTimeout(final String time) {
89 this.timeout = time;
90 }
91
92
93
94
95
96 @SuppressWarnings("PMD.CognitiveComplexity")
97 private void run() throws ValidationException {
98 final LinkedList<Violation> results = new LinkedList<>();
99 final MavenEnvironment env = this.env();
100 final Collection<File> files = env.files("*.*");
101 if (!files.isEmpty()) {
102 final Collection<ResourceValidator> validators =
103 this.provider.externalResource();
104 final Collection<Future<Collection<Violation>>> futures =
105 this.submit(env, files, validators);
106 for (final Future<Collection<Violation>> future : futures) {
107 try {
108 if ("forever".equalsIgnoreCase(this.timeout)) {
109 results.addAll(future.get());
110 } else {
111 final var value = this.timeoutValue();
112 final var units = this.timeoutUnits();
113 Logger.debug(
114 this,
115 "Waiting up to %d %s for validator result",
116 value,
117 units
118 );
119 results.addAll(future.get(value, units));
120 }
121 } catch (final InterruptedException ex) {
122 Thread.currentThread().interrupt();
123 throw new IllegalStateException(ex);
124 } catch (final ExecutionException | TimeoutException ex) {
125 throw new IllegalStateException(ex);
126 }
127 }
128 Collections.sort(results);
129 for (final Violation result : results) {
130 Logger.info(
131 this,
132 "%s: %s[%s]: %s (%s)",
133 result.validator(),
134 result.file().replace(
135 String.format(
136 "%s/", this.session().getExecutionRootDirectory()
137 ),
138 ""
139 ),
140 result.lines(),
141 result.message(),
142 result.name()
143 );
144 }
145 }
146 if (!results.isEmpty()) {
147 throw new ValidationException(
148 String.format("There are %d violations", results.size())
149 );
150 }
151 for (final Validator validator : this.provider.external()) {
152 Logger.info(this, "Starting %s validator", validator.name());
153 validator.validate(env);
154 Logger.info(this, "Finishing %s validator", validator.name());
155 }
156 for (final MavenValidator validator : this.provider.internal()) {
157 validator.validate(env);
158 }
159 }
160
161
162
163
164
165
166
167
168 @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
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 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
267 private static class ValidatorCallable
268 implements Callable<Collection<Violation>> {
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 }