1 package org.apache.maven.plugins.site.render;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
23
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.io.OutputStream;
27 import java.io.Writer;
28 import java.io.File;
29 import java.lang.reflect.InvocationTargetException;
30 import java.lang.reflect.Method;
31 import java.util.ArrayList;
32 import java.util.Locale;
33 import java.util.List;
34
35 import org.apache.maven.doxia.sink.Sink;
36 import org.apache.maven.doxia.sink.SinkFactory;
37 import org.apache.maven.doxia.siterenderer.DocumentRenderer;
38 import org.apache.maven.doxia.siterenderer.Renderer;
39 import org.apache.maven.doxia.siterenderer.RendererException;
40 import org.apache.maven.doxia.siterenderer.RenderingContext;
41 import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
42 import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
43 import org.apache.maven.doxia.tools.MojoLogWrapper;
44 import org.apache.maven.plugin.logging.Log;
45 import org.apache.maven.reporting.MavenMultiPageReport;
46 import org.apache.maven.reporting.MavenReport;
47 import org.apache.maven.reporting.MavenReportException;
48 import org.apache.maven.reporting.exec.MavenReportExecution;
49 import org.codehaus.plexus.util.PathTool;
50 import org.codehaus.plexus.util.StringUtils;
51 import org.codehaus.plexus.util.WriterFactory;
52
53
54
55
56
57
58
59 public class ReportDocumentRenderer
60 implements DocumentRenderer
61 {
62 private final MavenReport report;
63
64 private final RenderingContext renderingContext;
65
66 private final String reportMojoInfo;
67
68 private final ClassLoader classLoader;
69
70 private final Log log;
71
72 public ReportDocumentRenderer( MavenReportExecution mavenReportExecution, RenderingContext renderingContext,
73 Log log )
74 {
75 this.report = mavenReportExecution.getMavenReport();
76
77 this.renderingContext = renderingContext;
78
79
80 this.reportMojoInfo =
81 mavenReportExecution.getPlugin().getArtifactId() + ':' + mavenReportExecution.getPlugin().getVersion()
82 + ':' + mavenReportExecution.getGoal();
83
84 this.classLoader = mavenReportExecution.getClassLoader();
85
86 this.log = log;
87 }
88
89 private static class MultiPageSubSink
90 extends SiteRendererSink
91 {
92 private File outputDir;
93
94 private String outputName;
95
96 MultiPageSubSink( File outputDir, String outputName, RenderingContext context )
97 {
98 super( context );
99 this.outputName = outputName;
100 this.outputDir = outputDir;
101 }
102
103 public String getOutputName()
104 {
105 return outputName;
106 }
107
108 public File getOutputDir()
109 {
110 return outputDir;
111 }
112
113 }
114
115 private static class MultiPageSinkFactory
116 implements SinkFactory
117 {
118
119
120
121 private MavenReport report;
122
123
124
125
126 private RenderingContext context;
127
128
129
130
131 private List<MultiPageSubSink> sinks = new ArrayList<MultiPageSubSink>();
132
133 MultiPageSinkFactory( MavenReport report, RenderingContext context )
134 {
135 this.report = report;
136 this.context = context;
137 }
138
139 @Override
140 public Sink createSink( File outputDir, String outputName )
141 {
142
143 String outputRelativeToTargetSite = PathTool.getRelativeFilePath(
144 report.getReportOutputDirectory().getPath(),
145 new File( outputDir, outputName ).getPath()
146 );
147
148 RenderingContext subSinkContext = new RenderingContext(
149 context.getBasedir(),
150 context.getBasedirRelativePath(),
151 outputRelativeToTargetSite,
152 context.getParserId(),
153 context.getExtension(),
154 context.isEditable(),
155 context.getGenerator()
156 );
157
158
159 MultiPageSubSink sink = new MultiPageSubSink( outputDir, outputName, subSinkContext );
160
161
162 sinks.add( sink );
163
164 return sink;
165 }
166
167 @Override
168 public Sink createSink( File arg0, String arg1, String arg2 )
169 throws IOException
170 {
171
172 return null;
173 }
174
175 @Override
176 public Sink createSink( OutputStream arg0 )
177 throws IOException
178 {
179
180 return null;
181 }
182
183 @Override
184 public Sink createSink( OutputStream arg0, String arg1 )
185 throws IOException
186 {
187
188 return null;
189 }
190
191 public List<MultiPageSubSink> sinks()
192 {
193 return sinks;
194 }
195 }
196
197 @Override
198 public void renderDocument( Writer writer, Renderer renderer, SiteRenderingContext siteRenderingContext )
199 throws RendererException, FileNotFoundException
200 {
201 Locale locale = siteRenderingContext.getLocale();
202 String localReportName = report.getName( locale );
203
204 String msg = "Generating \"" + buffer().strong( localReportName ) + "\" report";
205
206 log.info( reportMojoInfo == null ? ( msg + '.' )
207 : ( StringUtils.rightPad( msg, 40 ) + buffer().strong( " --- " ).mojo( reportMojoInfo ) ) );
208
209
210
211 SiteRendererSink mainSink = new SiteRendererSink( renderingContext );
212
213 MultiPageSinkFactory multiPageSinkFactory = new MultiPageSinkFactory( report, renderingContext );
214
215 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
216 try
217 {
218 if ( classLoader != null )
219 {
220 Thread.currentThread().setContextClassLoader( classLoader );
221 }
222
223 if ( report instanceof MavenMultiPageReport )
224 {
225
226 ( (MavenMultiPageReport) report ).generate( mainSink, multiPageSinkFactory, locale );
227 }
228 else if ( generateMultiPage( locale, multiPageSinkFactory, mainSink ) )
229 {
230
231 }
232 else
233 {
234
235 report.generate( mainSink, locale );
236 }
237 }
238 catch ( MavenReportException e )
239 {
240 String report = ( reportMojoInfo == null ) ? ( '"' + localReportName + '"' ) : reportMojoInfo;
241 throw new RendererException( "Error generating " + report + " report", e );
242 }
243 catch ( RuntimeException re )
244 {
245
246 String report = ( reportMojoInfo == null ) ? ( '"' + localReportName + '"' ) : reportMojoInfo;
247 throw new RendererException( "Error generating " + report + " report", re );
248 }
249 catch ( LinkageError e )
250 {
251 String report = ( reportMojoInfo == null ) ? ( '"' + localReportName + '"' ) : reportMojoInfo;
252 log.warn( "An issue has occurred with " + report + " report, skipping LinkageError "
253 + e.getMessage() + ", please report an issue to Maven dev team.", e );
254 }
255 finally
256 {
257 if ( classLoader != null )
258 {
259 Thread.currentThread().setContextClassLoader( originalClassLoader );
260 }
261 mainSink.close();
262 }
263
264 if ( report.isExternalReport() )
265 {
266
267 return;
268 }
269
270
271 renderer.mergeDocumentIntoSite( writer, mainSink, siteRenderingContext );
272
273
274 String outputName = "";
275 try
276 {
277 List<MultiPageSubSink> sinks = multiPageSinkFactory.sinks();
278
279 log.debug( "Multipage report: " + sinks.size() + " subreports" );
280
281 for ( MultiPageSubSink mySink : sinks )
282 {
283 mySink.enableLogging( new MojoLogWrapper( log ) );
284
285 outputName = mySink.getOutputName();
286 log.debug( " Rendering " + outputName );
287
288
289 if ( !mySink.getOutputDir().exists() )
290 {
291 mySink.getOutputDir().mkdirs();
292 }
293
294 File outputFile = new File( mySink.getOutputDir(), outputName );
295
296 try ( Writer out = WriterFactory.newWriter( outputFile, siteRenderingContext.getOutputEncoding() ) )
297 {
298 renderer.mergeDocumentIntoSite( out, mySink, siteRenderingContext );
299 mySink.close();
300 mySink = null;
301 }
302 finally
303 {
304 if ( mySink != null )
305 {
306 mySink.close();
307 }
308 }
309 }
310 }
311 catch ( IOException e )
312 {
313 throw new RendererException( "Cannot create writer to " + outputName, e );
314 }
315 }
316
317
318
319
320
321
322 private boolean generateMultiPage( Locale locale, SinkFactory sf, Sink sink )
323 throws MavenReportException
324 {
325 try
326 {
327
328
329 Method generate =
330 report.getClass().getMethod( "generate", Sink.class, SinkFactory.class, Locale.class );
331
332 generate.invoke( report, sink, sf, locale );
333
334 return true;
335 }
336 catch ( SecurityException se )
337 {
338 return false;
339 }
340 catch ( NoSuchMethodException nsme )
341 {
342 return false;
343 }
344 catch ( IllegalArgumentException | IllegalAccessException | InvocationTargetException ite )
345 {
346 throw new MavenReportException( "error while invoking generate on " + report.getClass(), ite );
347 }
348 }
349
350 @Override
351 public String getOutputName()
352 {
353 return renderingContext.getOutputName();
354 }
355
356 @Override
357 public RenderingContext getRenderingContext()
358 {
359 return renderingContext;
360 }
361
362 @Override
363 public boolean isOverwrite()
364 {
365
366 return true;
367 }
368
369
370
371
372 @Override
373 public boolean isExternalReport()
374 {
375 return report.isExternalReport();
376 }
377
378 public String getReportMojoInfo()
379 {
380 return reportMojoInfo;
381 }
382 }