1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.site.render;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.io.OutputStreamWriter;
25 import java.io.Writer;
26 import java.nio.file.Files;
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.Locale;
30
31 import org.apache.commons.lang3.StringUtils;
32 import org.apache.maven.doxia.sink.Sink;
33 import org.apache.maven.doxia.sink.SinkFactory;
34 import org.apache.maven.doxia.siterenderer.DocumentRenderer;
35 import org.apache.maven.doxia.siterenderer.DocumentRenderingContext;
36 import org.apache.maven.doxia.siterenderer.RendererException;
37 import org.apache.maven.doxia.siterenderer.SiteRenderer;
38 import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
39 import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
40 import org.apache.maven.plugin.logging.Log;
41 import org.apache.maven.reporting.MavenMultiPageReport;
42 import org.apache.maven.reporting.MavenReport;
43 import org.apache.maven.reporting.MavenReportException;
44 import org.apache.maven.reporting.exec.MavenReportExecution;
45 import org.codehaus.plexus.util.PathTool;
46
47 import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
48
49
50
51
52
53
54
55 public class ReportDocumentRenderer implements DocumentRenderer {
56 private final MavenReport report;
57
58 private final DocumentRenderingContext docRenderingContext;
59
60 private final String reportMojoInfo;
61
62 private final ClassLoader classLoader;
63
64 private final Log log;
65
66 public ReportDocumentRenderer(
67 MavenReportExecution mavenReportExecution, DocumentRenderingContext docRenderingContext, Log log) {
68 this.report = mavenReportExecution.getMavenReport();
69 this.docRenderingContext = docRenderingContext;
70 this.reportMojoInfo = mavenReportExecution.getGoal() == null
71 ? null
72 : mavenReportExecution.getPlugin().getArtifactId()
73 + ':'
74 + mavenReportExecution.getPlugin().getVersion()
75 + ':'
76 + mavenReportExecution.getGoal();
77 this.classLoader = mavenReportExecution.getClassLoader();
78 this.log = log;
79 }
80
81 private static class MultiPageSubSink extends SiteRendererSink {
82 private File outputDirectory;
83
84 private String outputName;
85
86 MultiPageSubSink(File outputDirectory, String outputName, DocumentRenderingContext docRenderingContext) {
87 super(docRenderingContext);
88 this.outputName = outputName;
89 this.outputDirectory = outputDirectory;
90 }
91
92 public String getOutputName() {
93 return outputName;
94 }
95
96 public File getOutputDirectory() {
97 return outputDirectory;
98 }
99 }
100
101 private static class MultiPageSinkFactory implements SinkFactory {
102
103
104
105 private MavenReport report;
106
107
108
109
110 private DocumentRenderingContext docRenderingContext;
111
112
113
114
115 private List<MultiPageSubSink> sinks = new ArrayList<>();
116
117 MultiPageSinkFactory(MavenReport report, DocumentRenderingContext docRenderingContext) {
118 this.report = report;
119 this.docRenderingContext = docRenderingContext;
120 }
121
122 @Override
123 public Sink createSink(File outputDirectory, String outputName) {
124
125 String document = PathTool.getRelativeFilePath(
126 report.getReportOutputDirectory().getPath(), new File(outputDirectory, outputName).getPath());
127
128 document = document.substring(0, document.lastIndexOf('.'));
129
130 DocumentRenderingContext subSinkContext = new DocumentRenderingContext(
131 docRenderingContext.getBasedir(),
132 docRenderingContext.getBasedirRelativePath(),
133 document,
134 docRenderingContext.getParserId(),
135 docRenderingContext.getExtension(),
136 docRenderingContext.isEditable(),
137 docRenderingContext.getGenerator());
138
139
140 MultiPageSubSink sink = new MultiPageSubSink(outputDirectory, outputName, subSinkContext);
141
142
143 sinks.add(sink);
144
145 return sink;
146 }
147
148 @Override
149 public Sink createSink(File arg0, String arg1, String arg2) throws IOException {
150
151 return null;
152 }
153
154 @Override
155 public Sink createSink(OutputStream arg0) throws IOException {
156
157 return null;
158 }
159
160 @Override
161 public Sink createSink(OutputStream arg0, String arg1) throws IOException {
162
163 return null;
164 }
165
166 public List<MultiPageSubSink> sinks() {
167 return sinks;
168 }
169 }
170
171 @Override
172 public void renderDocument(Writer writer, SiteRenderer siteRenderer, SiteRenderingContext siteRenderingContext)
173 throws RendererException, IOException {
174 Locale locale = siteRenderingContext.getLocale();
175 String localReportName = report.getName(locale);
176
177 String msg = "Generating \"" + buffer().strong(localReportName) + "\" report";
178
179 log.info(
180 reportMojoInfo == null
181 ? msg
182 : (StringUtils.rightPad(msg, 40)
183 + buffer().strong(" --- ").mojo(reportMojoInfo)));
184
185
186
187 SiteRendererSink mainSink = new SiteRendererSink(docRenderingContext);
188
189 MultiPageSinkFactory multiPageSinkFactory = new MultiPageSinkFactory(report, docRenderingContext);
190
191 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
192 try {
193 if (classLoader != null) {
194 Thread.currentThread().setContextClassLoader(classLoader);
195 }
196
197 if (report instanceof MavenMultiPageReport) {
198
199 ((MavenMultiPageReport) report).generate(mainSink, multiPageSinkFactory, locale);
200 } else {
201
202 report.generate(mainSink, locale);
203 }
204 } catch (MavenReportException e) {
205 String report = (reportMojoInfo == null) ? ('"' + localReportName + '"') : reportMojoInfo;
206 throw new RendererException("Error generating " + report + " report", e);
207 } catch (RuntimeException re) {
208
209 String report = (reportMojoInfo == null) ? ('"' + localReportName + '"') : reportMojoInfo;
210 throw new RendererException("Error generating " + report + " report", re);
211 } catch (LinkageError e) {
212 String report = (reportMojoInfo == null) ? ('"' + localReportName + '"') : reportMojoInfo;
213 log.warn(
214 "An issue has occurred with " + report + " report, skipping LinkageError " + e.getMessage()
215 + ", please report an issue to Maven dev team.",
216 e);
217 } finally {
218 if (classLoader != null) {
219 Thread.currentThread().setContextClassLoader(originalClassLoader);
220 }
221 mainSink.close();
222 }
223
224 if (report.isExternalReport()) {
225
226 return;
227 }
228
229
230 siteRenderer.mergeDocumentIntoSite(writer, mainSink, siteRenderingContext);
231
232
233 List<MultiPageSubSink> sinks = multiPageSinkFactory.sinks();
234
235 log.debug("Multipage report: " + sinks.size() + " subreports");
236
237 for (MultiPageSubSink mySink : sinks) {
238 String outputName = mySink.getOutputName();
239 log.debug(" Rendering " + outputName);
240
241
242 if (!mySink.getOutputDirectory().exists()) {
243 mySink.getOutputDirectory().mkdirs();
244 }
245
246 File outputFile = new File(mySink.getOutputDirectory(), outputName);
247
248 try (Writer out = new OutputStreamWriter(
249 Files.newOutputStream(outputFile.toPath()), siteRenderingContext.getOutputEncoding())) {
250 siteRenderer.mergeDocumentIntoSite(out, mySink, siteRenderingContext);
251 } finally {
252 mySink.close();
253 }
254 }
255 }
256
257 @Override
258 public String getOutputName() {
259 return docRenderingContext.getOutputName();
260 }
261
262 @Override
263 public String getOutputPath() {
264 return getOutputName();
265 }
266
267 @Override
268 public DocumentRenderingContext getRenderingContext() {
269 return docRenderingContext;
270 }
271
272 @Override
273 public boolean isOverwrite() {
274
275 return true;
276 }
277
278
279
280
281 @Override
282 public boolean isExternalReport() {
283 return report.isExternalReport();
284 }
285
286 public String getReportMojoInfo() {
287 return reportMojoInfo;
288 }
289 }