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