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