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