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.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(
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
76 private CheckMojo(final ExecutorService svc) {
77 this.executors = svc;
78 }
79
80 @Override
81 public String doExecute() throws MojoFailureException {
82 try {
83 return this.run();
84 } catch (final ValidationException ex) {
85 Logger.info(
86 this,
87 "Read our quality policy: https://www.qulice.com/quality.html"
88 );
89 throw new MojoFailureException("Failure", ex);
90 }
91 }
92
93
94
95
96
97
98 public void setValidatorsProvider(final ValidatorsProvider prov) {
99 this.provider = prov;
100 }
101
102
103
104
105
106
107 public void setTimeout(final String time) {
108 this.timeout = time;
109 }
110
111
112
113
114
115
116
117
118
119 static Collection<File> filter(
120 final MavenEnvironment env,
121 final Collection<File> files, final ResourceValidator validator
122 ) {
123 final Collection<File> filtered = new ArrayList<>(files.size());
124 for (final File file : files) {
125 if (
126 !env.exclude(
127 validator.name().toLowerCase(Locale.ENGLISH),
128 file.toString()
129 )
130 ) {
131 filtered.add(file);
132 }
133 }
134 return filtered;
135 }
136
137 @SuppressWarnings("PMD.CognitiveComplexity")
138 private String run() throws ValidationException {
139 final List<Violation> results = new ArrayList<>(0);
140 final MavenEnvironment env = this.env();
141 final ValidatorsProvider prov = this.validators(env);
142 final Collection<ResourceValidator> resources = prov.externalResource();
143 final Collection<File> files = env.files("*.*");
144 if (!files.isEmpty()) {
145 final Collection<Future<Collection<Violation>>> futures =
146 this.submit(env, files, resources);
147 for (final Future<Collection<Violation>> future : futures) {
148 try {
149 if ("forever".equalsIgnoreCase(this.timeout)) {
150 results.addAll(future.get());
151 } else {
152 final long value = this.timeoutValue();
153 final TimeUnit units = this.timeoutUnits();
154 Logger.debug(
155 this,
156 "Waiting up to %d %s for validator result",
157 value,
158 units
159 );
160 results.addAll(future.get(value, units));
161 }
162 } catch (final InterruptedException ex) {
163 Thread.currentThread().interrupt();
164 throw new IllegalStateException(ex);
165 } catch (final ExecutionException | TimeoutException ex) {
166 throw new IllegalStateException(ex);
167 }
168 }
169 Collections.sort(results);
170 for (final Violation result : results) {
171 Logger.info(
172 this,
173 "%s: %s[%s]: %s (%s)",
174 result.validator(),
175 result.file().replace(
176 String.format(
177 "%s/", this.session().getExecutionRootDirectory()
178 ),
179 ""
180 ),
181 result.lines(),
182 result.message(),
183 result.name()
184 );
185 }
186 }
187 if (!results.isEmpty()) {
188 throw new ValidationException(
189 String.format("There are %d violations", results.size())
190 );
191 }
192 for (final Validator validator : prov.external()) {
193 Logger.info(this, "Starting %s validator", validator.name());
194 validator.validate(env);
195 Logger.info(this, "Finishing %s validator", validator.name());
196 }
197 for (final MavenValidator validator : prov.internal()) {
198 validator.validate(env);
199 }
200 return new Summary(files, resources).toString();
201 }
202
203 private ValidatorsProvider validators(final MavenEnvironment env) {
204 final ValidatorsProvider prov;
205 if (this.provider == null) {
206 prov = new DefaultValidatorsProvider(env);
207 } else {
208 prov = this.provider;
209 }
210 return prov;
211 }
212
213 private Collection<Future<Collection<Violation>>> submit(
214 final MavenEnvironment env, final Collection<File> files,
215 final Collection<ResourceValidator> validators
216 ) {
217 final Collection<Future<Collection<Violation>>> futures =
218 new ArrayList<>(validators.size());
219 for (final ResourceValidator validator : validators) {
220 futures.add(
221 this.executors.submit(
222 new ValidatorCallable(validator, env, files)
223 )
224 );
225 }
226 return futures;
227 }
228
229 private long timeoutValue() {
230 final String clear = this.clearTimeout();
231 final long res;
232 if (clear.isEmpty()) {
233 res = 10L;
234 } else if (clear.endsWith("s") || clear.endsWith("m") || clear.endsWith("h")) {
235 res = Long.parseLong(clear.substring(0, clear.length() - 1));
236 } else {
237 res = Long.parseLong(clear);
238 }
239 return res;
240 }
241
242 private TimeUnit timeoutUnits() {
243 final String clear = this.clearTimeout();
244 final TimeUnit unit;
245 if (clear.endsWith("s")) {
246 unit = TimeUnit.SECONDS;
247 } else if (clear.endsWith("m")) {
248 unit = TimeUnit.MINUTES;
249 } else if (clear.endsWith("h")) {
250 unit = TimeUnit.HOURS;
251 } else {
252 unit = TimeUnit.MINUTES;
253 }
254 return unit;
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 }