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