1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.surefire.report;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.net.MalformedURLException;
24 import java.net.URL;
25 import java.net.URLClassLoader;
26 import java.text.MessageFormat;
27 import java.util.ArrayList;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Locale;
31 import java.util.MissingResourceException;
32 import java.util.ResourceBundle;
33
34 import org.apache.maven.model.ReportPlugin;
35 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
36 import org.apache.maven.plugins.annotations.Component;
37 import org.apache.maven.plugins.annotations.Parameter;
38 import org.apache.maven.project.MavenProject;
39 import org.apache.maven.reporting.AbstractMavenReport;
40 import org.apache.maven.reporting.MavenReportException;
41 import org.apache.maven.settings.Settings;
42 import org.apache.maven.shared.utils.PathTool;
43 import org.codehaus.plexus.i18n.I18N;
44 import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
45 import org.codehaus.plexus.interpolation.InterpolationException;
46 import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
47 import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
48 import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
49
50 import static java.util.Collections.addAll;
51 import static org.apache.maven.plugins.surefire.report.SurefireReportParser.hasReportFiles;
52
53
54
55
56
57
58 public abstract class AbstractSurefireReportMojo extends AbstractMavenReport {
59
60
61
62
63 @Parameter(defaultValue = "true", required = true, property = "showSuccess")
64 private boolean showSuccess;
65
66
67
68
69 @Parameter
70 private File[] reportsDirectories;
71
72
73
74
75
76 @Deprecated
77 @Parameter
78 private File reportsDirectory;
79
80
81
82
83 @Parameter(defaultValue = "${reactorProjects}", readonly = true)
84 private List<MavenProject> reactorProjects;
85
86
87
88
89 @Parameter(defaultValue = "${project.reporting.outputDirectory}/xref-test")
90 private File xrefLocation;
91
92
93
94
95
96 @Parameter(defaultValue = "true", property = "linkXRef")
97 private boolean linkXRef;
98
99
100
101
102 @Parameter(defaultValue = "false", property = "aggregate")
103 private boolean aggregate;
104
105
106
107
108 @Parameter(defaultValue = "${settings}", readonly = true, required = true)
109 private Settings settings;
110
111
112
113
114
115
116
117 @Parameter(defaultValue = "${basedir}/src/site/custom/surefire-report.properties")
118 private String customBundle;
119
120
121
122
123 @Component
124 private I18N i18n;
125
126 private List<File> resolvedReportsDirectories;
127
128
129
130
131
132
133
134 protected boolean isSkipped() {
135 return false;
136 }
137
138
139
140
141
142
143
144 protected boolean isGeneratedWhenNoResults() {
145 return false;
146 }
147
148
149
150
151 @Override
152 public void executeReport(Locale locale) throws MavenReportException {
153 SurefireReportRenderer r = new SurefireReportRenderer(
154 getSink(),
155 getI18N(locale),
156 getI18Nsection(),
157 locale,
158 getConsoleLogger(),
159 showSuccess,
160 getReportsDirectories(),
161 determineXrefLocation());
162 r.render();
163 }
164
165 @Override
166 public boolean canGenerateReport() {
167 if (isSkipped()) {
168 return false;
169 }
170
171 final List<File> reportsDirectories = getReportsDirectories();
172
173 if (reportsDirectories == null) {
174 return false;
175 }
176
177 if (!isGeneratedWhenNoResults()) {
178 boolean atLeastOneDirectoryExists = false;
179 for (Iterator<File> i = reportsDirectories.iterator(); i.hasNext() && !atLeastOneDirectoryExists; ) {
180 atLeastOneDirectoryExists = hasReportFiles(i.next());
181 }
182 if (!atLeastOneDirectoryExists) {
183 return false;
184 }
185 }
186 return true;
187 }
188
189 private List<File> getReportsDirectories() {
190 if (resolvedReportsDirectories != null) {
191 return resolvedReportsDirectories;
192 }
193
194 resolvedReportsDirectories = new ArrayList<>();
195
196 if (this.reportsDirectories != null) {
197 addAll(resolvedReportsDirectories, this.reportsDirectories);
198 }
199
200 if (reportsDirectory != null) {
201
202 resolvedReportsDirectories.add(reportsDirectory);
203 }
204 if (aggregate) {
205 if (!project.isExecutionRoot()) {
206 return null;
207 }
208 if (this.reportsDirectories == null) {
209 if (reactorProjects.size() > 1) {
210 for (MavenProject mavenProject : getProjectsWithoutRoot()) {
211 resolvedReportsDirectories.add(getSurefireReportsDirectory(mavenProject));
212 }
213 } else {
214 resolvedReportsDirectories.add(getSurefireReportsDirectory(project));
215 }
216 } else {
217
218
219 String parentBaseDir = getProject().getBasedir().getAbsolutePath();
220 for (MavenProject subProject : getProjectsWithoutRoot()) {
221 String moduleBaseDir = subProject.getBasedir().getAbsolutePath();
222 for (File reportsDirectory1 : this.reportsDirectories) {
223 String reportDir = reportsDirectory1.getPath();
224 if (reportDir.startsWith(parentBaseDir)) {
225 reportDir = reportDir.substring(parentBaseDir.length());
226 }
227 File reportsDirectory = new File(moduleBaseDir, reportDir);
228 if (reportsDirectory.exists() && reportsDirectory.isDirectory()) {
229 getConsoleLogger().debug("Adding report dir: " + moduleBaseDir + reportDir);
230 resolvedReportsDirectories.add(reportsDirectory);
231 }
232 }
233 }
234 }
235 } else {
236 if (resolvedReportsDirectories.isEmpty()) {
237
238 resolvedReportsDirectories.add(getSurefireReportsDirectory(project));
239 }
240 }
241 return resolvedReportsDirectories;
242 }
243
244
245
246
247
248
249
250 protected abstract File getSurefireReportsDirectory(MavenProject subProject);
251
252 private List<MavenProject> getProjectsWithoutRoot() {
253 List<MavenProject> result = new ArrayList<>();
254 for (MavenProject subProject : reactorProjects) {
255 if (!project.equals(subProject)) {
256 result.add(subProject);
257 }
258 }
259 return result;
260 }
261
262 private String determineXrefLocation() {
263 String location = null;
264
265 if (linkXRef) {
266 String relativePath = PathTool.getRelativePath(getOutputDirectory(), xrefLocation.getAbsolutePath());
267 if (relativePath == null || relativePath.isEmpty()) {
268 relativePath = ".";
269 }
270 relativePath = relativePath + "/" + xrefLocation.getName();
271 if (xrefLocation.exists()) {
272
273 location = relativePath;
274 } else {
275
276 for (Object o : project.getReportPlugins()) {
277 ReportPlugin report = (ReportPlugin) o;
278
279 String artifactId = report.getArtifactId();
280 if ("maven-jxr-plugin".equals(artifactId) || "jxr-maven-plugin".equals(artifactId)) {
281 location = relativePath;
282 }
283 }
284 }
285
286 if (location == null) {
287 getConsoleLogger().warning("Unable to locate Test Source XRef to link to - DISABLED");
288 }
289 }
290 return location;
291 }
292
293
294
295
296
297
298 protected String getI18nString(Locale locale, String key) {
299 return getI18N(locale).getString("surefire-report", locale, "report." + getI18Nsection() + '.' + key);
300 }
301
302
303
304
305 protected I18N getI18N(Locale locale) {
306 if (customBundle != null) {
307 File customBundleFile = new File(customBundle);
308 if (customBundleFile.isFile() && customBundleFile.getName().endsWith(".properties")) {
309 if (!i18n.getClass().isAssignableFrom(CustomI18N.class)
310 || !i18n.getDefaultLanguage().equals(locale.getLanguage())) {
311
312 i18n = new CustomI18N(project, settings, customBundleFile, locale, i18n);
313 }
314 }
315 }
316
317 return i18n;
318 }
319
320
321
322 protected abstract String getI18Nsection();
323
324
325 public String getName(Locale locale) {
326 return getI18nString(locale, "name");
327 }
328
329
330 public String getDescription(Locale locale) {
331 return getI18nString(locale, "description");
332 }
333
334
335
336
337 @Override
338 public abstract String getOutputName();
339
340 protected final ConsoleLogger getConsoleLogger() {
341 return new PluginConsoleLogger(getLog());
342 }
343
344 @Override
345 protected MavenProject getProject() {
346 return project;
347 }
348
349
350 private static class CustomI18N implements I18N {
351 private final MavenProject project;
352
353 private final Settings settings;
354
355 private final String bundleName;
356
357 private final Locale locale;
358
359 private final I18N i18nOriginal;
360
361 private ResourceBundle bundle;
362
363 private static final Object[] NO_ARGS = new Object[0];
364
365 CustomI18N(MavenProject project, Settings settings, File customBundleFile, Locale locale, I18N i18nOriginal) {
366 super();
367 this.project = project;
368 this.settings = settings;
369 this.locale = locale;
370 this.i18nOriginal = i18nOriginal;
371 this.bundleName = customBundleFile
372 .getName()
373 .substring(0, customBundleFile.getName().indexOf(".properties"));
374
375 URLClassLoader classLoader = null;
376 try {
377 classLoader = new URLClassLoader(
378 new URL[] {customBundleFile.getParentFile().toURI().toURL()}, null);
379 } catch (MalformedURLException e) {
380
381 }
382
383 this.bundle = ResourceBundle.getBundle(this.bundleName, locale, classLoader);
384 if (!this.bundle.getLocale().getLanguage().equals(locale.getLanguage())) {
385 this.bundle = ResourceBundle.getBundle(this.bundleName, Locale.getDefault(), classLoader);
386 }
387 }
388
389
390 public String getDefaultLanguage() {
391 return locale.getLanguage();
392 }
393
394
395 public String getDefaultCountry() {
396 return locale.getCountry();
397 }
398
399
400 public String getDefaultBundleName() {
401 return bundleName;
402 }
403
404
405 public String[] getBundleNames() {
406 return new String[] {bundleName};
407 }
408
409
410 public ResourceBundle getBundle() {
411 return bundle;
412 }
413
414
415 public ResourceBundle getBundle(String bundleName) {
416 return bundle;
417 }
418
419
420 public ResourceBundle getBundle(String bundleName, String languageHeader) {
421 return bundle;
422 }
423
424
425 public ResourceBundle getBundle(String bundleName, Locale locale) {
426 return bundle;
427 }
428
429
430 public Locale getLocale(String languageHeader) {
431 return new Locale(languageHeader);
432 }
433
434
435 public String getString(String key) {
436 return getString(bundleName, locale, key);
437 }
438
439
440 public String getString(String key, Locale locale) {
441 return getString(bundleName, locale, key);
442 }
443
444
445 public String getString(String bundleName, Locale locale, String key) {
446 String value;
447
448 if (locale == null) {
449 locale = getLocale(null);
450 }
451
452 ResourceBundle rb = getBundle(bundleName, locale);
453 value = getStringOrNull(rb, key);
454
455 if (value == null) {
456
457 value = i18nOriginal.getString(bundleName, locale, key);
458 }
459
460 if (!value.contains("${")) {
461 return value;
462 }
463
464 final RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
465 try {
466 interpolator.addValueSource(new EnvarBasedValueSource());
467 } catch (final IOException e) {
468
469 }
470
471 interpolator.addValueSource(new PropertiesBasedValueSource(System.getProperties()));
472 interpolator.addValueSource(new PropertiesBasedValueSource(project.getProperties()));
473 interpolator.addValueSource(new PrefixedObjectValueSource("project", project));
474 interpolator.addValueSource(new PrefixedObjectValueSource("pom", project));
475 interpolator.addValueSource(new PrefixedObjectValueSource("settings", settings));
476
477 try {
478 value = interpolator.interpolate(value);
479 } catch (final InterpolationException e) {
480
481 }
482
483 return value;
484 }
485
486
487 public String format(String key, Object arg1) {
488 return format(bundleName, locale, key, new Object[] {arg1});
489 }
490
491
492 public String format(String key, Object arg1, Object arg2) {
493 return format(bundleName, locale, key, new Object[] {arg1, arg2});
494 }
495
496
497 public String format(String bundleName, Locale locale, String key, Object arg1) {
498 return format(bundleName, locale, key, new Object[] {arg1});
499 }
500
501
502 public String format(String bundleName, Locale locale, String key, Object arg1, Object arg2) {
503 return format(bundleName, locale, key, new Object[] {arg1, arg2});
504 }
505
506
507 public String format(String bundleName, Locale locale, String key, Object[] args) {
508 if (locale == null) {
509 locale = getLocale(null);
510 }
511
512 String value = getString(bundleName, locale, key);
513 if (args == null) {
514 args = NO_ARGS;
515 }
516
517 MessageFormat messageFormat = new MessageFormat("");
518 messageFormat.setLocale(locale);
519 messageFormat.applyPattern(value);
520
521 return messageFormat.format(args);
522 }
523
524 private String getStringOrNull(ResourceBundle rb, String key) {
525 if (rb != null) {
526 try {
527 return rb.getString(key);
528 } catch (MissingResourceException ignored) {
529
530 }
531 }
532 return null;
533 }
534 }
535 }