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