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