1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.rat.mp;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.OutputStreamWriter;
25 import java.io.Writer;
26 import java.nio.charset.StandardCharsets;
27 import java.nio.file.Files;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Locale;
31 import java.util.Map;
32 import java.util.ResourceBundle;
33
34 import org.apache.maven.artifact.Artifact;
35 import org.apache.maven.doxia.sink.Sink;
36 import org.apache.maven.doxia.sink.SinkFactory;
37 import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
38 import org.apache.maven.doxia.site.SiteModel;
39 import org.apache.maven.doxia.siterenderer.DocumentRenderingContext;
40 import org.apache.maven.doxia.siterenderer.Renderer;
41 import org.apache.maven.doxia.siterenderer.RendererException;
42 import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
43 import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
44 import org.apache.maven.doxia.tools.SiteTool;
45 import org.apache.maven.doxia.tools.SiteToolException;
46 import org.apache.maven.execution.MavenSession;
47 import org.apache.maven.plugin.MojoExecutionException;
48 import org.apache.maven.plugins.annotations.Component;
49 import org.apache.maven.plugins.annotations.Mojo;
50 import org.apache.maven.plugins.annotations.Parameter;
51 import org.apache.maven.plugins.annotations.ResolutionScope;
52 import org.apache.maven.reporting.MavenMultiPageReport;
53 import org.apache.maven.reporting.MavenReportException;
54 import org.apache.rat.ReportConfiguration;
55 import org.apache.rat.Reporter;
56 import org.apache.rat.VersionInfo;
57 import org.apache.rat.license.LicenseSetFactory.LicenseFilter;
58 import org.codehaus.plexus.util.ReaderFactory;
59 import org.eclipse.aether.repository.ArtifactRepository;
60 import org.eclipse.aether.repository.RemoteRepository;
61
62 import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
63
64
65
66
67 @Mojo(name = "rat", requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true)
68 public class RatReportMojo extends AbstractRatMojo implements MavenMultiPageReport {
69
70
71
72
73
74
75
76 @Parameter(defaultValue = "${project.reporting.outputDirectory}", readonly = true, required = true)
77 protected File outputDirectory;
78
79
80
81
82 @Parameter(property = "encoding", defaultValue = "${project.build.sourceEncoding}", readonly = true)
83 private String inputEncoding;
84
85
86
87
88 @Parameter(property = "outputEncoding", defaultValue = "${project.reporting.outputEncoding}", readonly = true)
89 private String outputEncoding;
90
91
92
93
94 @Parameter(defaultValue = "${session}", readonly = true, required = true)
95 protected MavenSession session;
96
97
98
99
100
101
102 @Parameter(defaultValue = "${project.remoteArtifactRepositories}", readonly = true, required = true)
103 @Deprecated
104 protected List<ArtifactRepository> remoteArtifactRepositories;
105
106
107
108
109 @Parameter(defaultValue = "${project.remoteProjectRepositories}", readonly = true, required = true)
110 protected List<RemoteRepository> remoteRepositories;
111
112
113
114
115 @Component
116 protected SiteTool siteTool;
117
118
119
120
121 @Component
122 protected Renderer siteRenderer;
123
124
125
126
127 private Sink sink;
128
129
130
131
132 private SinkFactory sinkFactory;
133
134
135
136
137 private File reportOutputDirectory;
138
139
140
141
142
143
144
145
146 @Override
147 public void execute() throws MojoExecutionException {
148 if (!canGenerateReport()) {
149 return;
150 }
151
152 File outputDirectory = new File(getOutputDirectory());
153
154 String filename = getOutputName() + ".html";
155
156 Locale locale = Locale.getDefault();
157
158 try {
159 SiteRenderingContext siteContext = createSiteRenderingContext(locale);
160
161
162 getSiteRenderer().copyResources(siteContext, outputDirectory);
163
164
165 DocumentRenderingContext docContext =
166 new DocumentRenderingContext(outputDirectory, filename, "xhtml5");
167 SiteRendererSink sink = new SiteRendererSink(docContext);
168
169 generate(sink, null, locale);
170
171
172 if (!isExternalReport()) {
173 if (!outputDirectory.exists() && !outputDirectory.mkdirs()) {
174 getLog().error("Unable to create output directory: " + outputDirectory);
175 }
176 try (Writer writer = new OutputStreamWriter(
177 Files.newOutputStream(new File(outputDirectory, filename).toPath()),
178 getOutputEncoding())) {
179
180 getSiteRenderer().mergeDocumentIntoSite(writer, sink, siteContext);
181 }
182
183 }
184
185
186 getSiteRenderer().copyResources(siteContext, outputDirectory);
187 } catch (RendererException | IOException | MavenReportException e) {
188 throw new MojoExecutionException(
189 "An error has occurred in " + getName(Locale.ENGLISH) + " report generation.", e);
190 }
191 }
192
193 private SiteRenderingContext createSiteRenderingContext(final Locale locale)
194 throws MavenReportException, IOException {
195 SiteModel siteModel = new SiteModel();
196
197 Map<String, Object> templateProperties = new HashMap<>();
198 templateProperties.put("standalone", Boolean.TRUE);
199 templateProperties.put("project", getProject());
200 templateProperties.put("inputEncoding", getInputEncoding());
201 templateProperties.put("outputEncoding", getOutputEncoding());
202 for (Map.Entry<Object, Object> entry : getProject().getProperties().entrySet()) {
203 templateProperties.put((String) entry.getKey(), entry.getValue());
204 }
205
206 org.apache.maven.doxia.site.Skin siteSkin = siteModel.getSkin();
207
208 if (siteSkin == null || siteSkin.getGroupId() == null
209 || siteSkin.getArtifactId() == null || siteSkin.getVersion() == null) {
210 getLog().debug("No skin configuration found in site.xml. Using default Maven skin configuration.");
211
212
213 siteSkin = new org.apache.maven.doxia.site.Skin();
214 siteSkin.setGroupId("org.apache.maven.skins");
215 siteSkin.setArtifactId("maven-fluido-skin");
216 }
217
218 try {
219 Artifact skinArtifact = siteTool.getSkinArtifactFromRepository(
220 session.getRepositorySession(),
221 remoteRepositories,
222 siteSkin
223 );
224
225 getLog().debug(buffer().a("Rendering content with ").strong(skinArtifact.getId() + " skin").a('.').build());
226
227 SiteRenderingContext context = siteRenderer.createContextForSkin(
228 skinArtifact,
229 templateProperties,
230 siteModel,
231 project.getName(),
232 locale
233 );
234 context.setRootDirectory(project.getBasedir());
235 return context;
236
237 } catch (SiteToolException e) {
238 throw new MavenReportException("Failed to retrieve skin artifact", e);
239 } catch (RendererException e) {
240 throw new MavenReportException("Failed to create context for skin", e);
241 }
242 }
243
244
245
246
247
248
249
250
251
252
253 @Override
254 public void generate(final Sink sink, final SinkFactory sinkFactory, final Locale locale) throws MavenReportException {
255 if (!canGenerateReport()) {
256
257 getLog().info("This report cannot be generated as part of the current build. "
258 + "The report name should be referenced in this line of output.");
259 } else {
260 this.sink = sink;
261 this.sinkFactory = sinkFactory;
262
263 if (!(sink instanceof SiteRendererSink)) {
264
265 generateReportManually(locale);
266 } else {
267 executeReport(locale);
268 }
269
270 closeReport();
271 }
272 }
273
274 private void generateReportManually(final Locale locale) throws MavenReportException {
275 try {
276 File outputDir = new File(getOutputDirectory());
277 String filename = getOutputName() + ".html";
278
279 SiteRenderingContext siteContext = createSiteRenderingContext(locale);
280
281 if (!outputDir.exists() && !outputDir.mkdirs()) {
282 getLog().error("Unable to create output directory: " + outputDir);
283 }
284
285 DocumentRenderingContext docContext =
286 new DocumentRenderingContext(outputDir, filename, "xhtml5");
287
288 SiteRendererSink sink = new SiteRendererSink(docContext);
289
290 this.sink = sink;
291 this.sinkFactory = null;
292
293 executeReport(locale);
294
295 try (Writer writer = new OutputStreamWriter(
296 Files.newOutputStream(new File(outputDir, filename).toPath()),
297 getOutputEncoding())) {
298 getSiteRenderer().mergeDocumentIntoSite(writer, sink, siteContext);
299 }
300
301 } catch (IOException | RendererException e) {
302 throw new MavenReportException("Failed to render RAT report manually", e);
303 }
304 }
305
306
307
308
309
310
311
312
313
314 @Deprecated
315 public void generate(final Sink sink, final Locale locale) throws MavenReportException {
316 generate(sink, null, locale);
317 }
318
319
320
321
322 @Override
323 public String getCategoryName() {
324 return CATEGORY_PROJECT_REPORTS;
325 }
326
327 @Override
328 public File getReportOutputDirectory() {
329 if (reportOutputDirectory == null) {
330 reportOutputDirectory = new File(getOutputDirectory());
331 }
332
333 return reportOutputDirectory;
334 }
335
336 @Override
337 public void setReportOutputDirectory(final File reportOutputDirectory) {
338 this.reportOutputDirectory = reportOutputDirectory;
339 this.outputDirectory = reportOutputDirectory;
340 }
341
342 protected String getOutputDirectory() {
343 return outputDirectory.getAbsolutePath();
344 }
345
346 protected Renderer getSiteRenderer() {
347 return siteRenderer;
348 }
349
350
351
352
353
354
355 protected String getInputEncoding() {
356 return (inputEncoding == null) ? ReaderFactory.FILE_ENCODING : inputEncoding;
357 }
358
359
360
361
362
363
364
365 protected String getOutputEncoding() {
366 return (outputEncoding == null) ? StandardCharsets.UTF_8.toString() : outputEncoding;
367 }
368
369
370
371
372 protected void closeReport() {
373 getSink().close();
374 }
375
376
377
378
379 public Sink getSink() {
380 return sink;
381 }
382
383
384
385
386 public SinkFactory getSinkFactory() {
387 return sinkFactory;
388 }
389
390
391
392
393
394 @Override
395 public boolean isExternalReport() {
396 return false;
397 }
398
399 @Override
400 public boolean canGenerateReport() {
401 return !skip;
402 }
403
404
405
406
407
408
409
410 protected void executeReport(final Locale locale) throws MavenReportException {
411 ResourceBundle bundle = getBundle(locale);
412 final String title = bundle.getString("report.rat.title");
413 sink.head();
414 sink.title();
415 sink.text(title);
416 sink.title_();
417 sink.head_();
418
419 sink.body();
420
421 sink.section1();
422 sink.sectionTitle1();
423 sink.text(title);
424 sink.sectionTitle1_();
425
426 sink.paragraph();
427 sink.text(bundle.getString("report.rat.link") + " ");
428 sink.link(bundle.getString("report.rat.url"));
429 sink.text(bundle.getString("report.rat.fullName"));
430 sink.link_();
431 final String ratVersion = new VersionInfo(RatReportMojo.class).toString();
432 if (ratVersion != null) {
433 sink.text(" " + ratVersion);
434 }
435 sink.text(".");
436 sink.paragraph_();
437
438 sink.paragraph();
439 sink.verbatim(new SinkEventAttributeSet());
440 try {
441 ReportConfiguration config = getConfiguration();
442 config.setFrom(getDefaultsBuilder().build());
443 logLicenses(config.getLicenses(LicenseFilter.ALL));
444 ByteArrayOutputStream baos = new ByteArrayOutputStream();
445 config.setOut(() -> baos);
446 new Reporter(config).output();
447 sink.text(baos.toString(StandardCharsets.UTF_8.name()));
448 } catch (Exception e) {
449 throw new MavenReportException(e.getMessage(), e);
450 }
451 sink.verbatim_();
452 sink.paragraph_();
453 sink.section1_();
454 sink.body_();
455 }
456
457
458
459
460
461
462
463 private ResourceBundle getBundle(final Locale locale) {
464 return ResourceBundle.getBundle("org/apache/rat/mp/rat-report", locale, getClass().getClassLoader());
465 }
466
467
468
469
470
471
472
473
474 @Override
475 public String getDescription(final Locale locale) {
476 return getBundle(locale).getString("report.rat.description");
477 }
478
479
480
481
482
483
484
485 @Override
486 public String getName(final Locale locale) {
487 return getBundle(locale).getString("report.rat.name");
488 }
489
490
491
492
493
494
495 @Override
496 public String getOutputName() {
497 return "rat-report";
498 }
499 }