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 if ( mavenReportExecution.getPlugin() == null )
80 {
81
82 this.reportMojoInfo = getPluginInfo( report );
83 }
84 else
85 {
86
87 this.reportMojoInfo =
88 mavenReportExecution.getPlugin().getArtifactId() + ':' + mavenReportExecution.getPlugin().getVersion()
89 + ':' + mavenReportExecution.getGoal();
90 }
91
92 this.classLoader = mavenReportExecution.getClassLoader();
93
94 this.log = log;
95 }
96
97
98
99
100
101
102
103
104 private String getPluginInfo( MavenReport report )
105 {
106 Package pkg = report.getClass().getPackage();
107
108 if ( pkg != null )
109 {
110 String title = pkg.getSpecificationTitle();
111 String version = pkg.getSpecificationVersion();
112
113 if ( title == null )
114 {
115 return version;
116 }
117 else if ( version == null )
118 {
119 return title;
120 }
121 else
122 {
123 return title + ' ' + version;
124 }
125 }
126
127 return null;
128 }
129
130 private static class MultiPageSubSink
131 extends SiteRendererSink
132 {
133 private File outputDir;
134
135 private String outputName;
136
137 MultiPageSubSink( File outputDir, String outputName, RenderingContext context )
138 {
139 super( context );
140 this.outputName = outputName;
141 this.outputDir = outputDir;
142 }
143
144 public String getOutputName()
145 {
146 return outputName;
147 }
148
149 public File getOutputDir()
150 {
151 return outputDir;
152 }
153
154 }
155
156 private static class MultiPageSinkFactory
157 implements SinkFactory
158 {
159
160
161
162 private MavenReport report;
163
164
165
166
167 private RenderingContext context;
168
169
170
171
172 private List<MultiPageSubSink> sinks = new ArrayList<MultiPageSubSink>();
173
174 MultiPageSinkFactory( MavenReport report, RenderingContext context )
175 {
176 this.report = report;
177 this.context = context;
178 }
179
180 @Override
181 public Sink createSink( File outputDir, String outputName )
182 {
183
184 String outputRelativeToTargetSite = PathTool.getRelativeFilePath(
185 report.getReportOutputDirectory().getPath(),
186 new File( outputDir, outputName ).getPath()
187 );
188
189 RenderingContext subSinkContext = new RenderingContext(
190 context.getBasedir(),
191 context.getBasedirRelativePath(),
192 outputRelativeToTargetSite,
193 context.getParserId(),
194 context.getExtension(),
195 context.isEditable(),
196 context.getGenerator()
197 );
198
199
200 MultiPageSubSink sink = new MultiPageSubSink( outputDir, outputName, subSinkContext );
201
202
203 sinks.add( sink );
204
205 return sink;
206 }
207
208 @Override
209 public Sink createSink( File arg0, String arg1, String arg2 )
210 throws IOException
211 {
212
213 return null;
214 }
215
216 @Override
217 public Sink createSink( OutputStream arg0 )
218 throws IOException
219 {
220
221 return null;
222 }
223
224 @Override
225 public Sink createSink( OutputStream arg0, String arg1 )
226 throws IOException
227 {
228
229 return null;
230 }
231
232 public List<MultiPageSubSink> sinks()
233 {
234 return sinks;
235 }
236 }
237
238 @Override
239 public void renderDocument( Writer writer, Renderer renderer, SiteRenderingContext siteRenderingContext )
240 throws RendererException, FileNotFoundException
241 {
242 Locale locale = siteRenderingContext.getLocale();
243 String localReportName = report.getName( locale );
244
245 String msg = "Generating \"" + buffer().strong( localReportName ) + "\" report";
246
247 log.info( reportMojoInfo == null ? ( msg + '.' )
248 : ( StringUtils.rightPad( msg, 40 ) + buffer().strong( " --- " ).mojo( reportMojoInfo ) ) );
249
250
251
252 SiteRendererSink mainSink = new SiteRendererSink( renderingContext );
253
254 MultiPageSinkFactory multiPageSinkFactory = new MultiPageSinkFactory( report, renderingContext );
255
256 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
257 try
258 {
259 if ( classLoader != null )
260 {
261 Thread.currentThread().setContextClassLoader( classLoader );
262 }
263
264 if ( report instanceof MavenMultiPageReport )
265 {
266
267 ( (MavenMultiPageReport) report ).generate( mainSink, multiPageSinkFactory, locale );
268 }
269 else if ( generateMultiPage( locale, multiPageSinkFactory, mainSink ) )
270 {
271
272 }
273 else
274 {
275
276 report.generate( mainSink, locale );
277 }
278 }
279 catch ( MavenReportException e )
280 {
281 String report = ( reportMojoInfo == null ) ? ( '"' + localReportName + '"' ) : reportMojoInfo;
282 throw new RendererException( "Error generating " + report + " report", e );
283 }
284 catch ( RuntimeException re )
285 {
286
287 String report = ( reportMojoInfo == null ) ? ( '"' + localReportName + '"' ) : reportMojoInfo;
288 throw new RendererException( "Error generating " + report + " report", re );
289 }
290 catch ( LinkageError e )
291 {
292 String report = ( reportMojoInfo == null ) ? ( '"' + localReportName + '"' ) : reportMojoInfo;
293 log.warn( "An issue has occurred with " + report + " report, skipping LinkageError "
294 + e.getMessage() + ", please report an issue to Maven dev team.", e );
295 }
296 finally
297 {
298 if ( classLoader != null )
299 {
300 Thread.currentThread().setContextClassLoader( originalClassLoader );
301 }
302 mainSink.close();
303 }
304
305 if ( report.isExternalReport() )
306 {
307
308 return;
309 }
310
311
312 renderer.mergeDocumentIntoSite( writer, mainSink, siteRenderingContext );
313
314
315 String outputName = "";
316 try
317 {
318 List<MultiPageSubSink> sinks = multiPageSinkFactory.sinks();
319
320 log.debug( "Multipage report: " + sinks.size() + " subreports" );
321
322 for ( MultiPageSubSink mySink : sinks )
323 {
324 mySink.enableLogging( new MojoLogWrapper( log ) );
325
326 outputName = mySink.getOutputName();
327 log.debug( " Rendering " + outputName );
328
329
330 if ( !mySink.getOutputDir().exists() )
331 {
332 mySink.getOutputDir().mkdirs();
333 }
334
335 File outputFile = new File( mySink.getOutputDir(), outputName );
336
337 try ( Writer out = WriterFactory.newWriter( outputFile, siteRenderingContext.getOutputEncoding() ) )
338 {
339 renderer.mergeDocumentIntoSite( out, mySink, siteRenderingContext );
340 mySink.close();
341 mySink = null;
342 }
343 finally
344 {
345 if ( mySink != null )
346 {
347 mySink.close();
348 }
349 }
350 }
351 }
352 catch ( IOException e )
353 {
354 throw new RendererException( "Cannot create writer to " + outputName, e );
355 }
356 }
357
358
359
360
361
362
363 private boolean generateMultiPage( Locale locale, SinkFactory sf, Sink sink )
364 throws MavenReportException
365 {
366 try
367 {
368
369
370 Method generate =
371 report.getClass().getMethod( "generate", Sink.class, SinkFactory.class, Locale.class );
372
373 generate.invoke( report, sink, sf, locale );
374
375 return true;
376 }
377 catch ( SecurityException se )
378 {
379 return false;
380 }
381 catch ( NoSuchMethodException nsme )
382 {
383 return false;
384 }
385 catch ( IllegalArgumentException | IllegalAccessException | InvocationTargetException ite )
386 {
387 throw new MavenReportException( "error while invoking generate on " + report.getClass(), ite );
388 }
389 }
390
391 @Override
392 public String getOutputName()
393 {
394 return renderingContext.getOutputName();
395 }
396
397 @Override
398 public RenderingContext getRenderingContext()
399 {
400 return renderingContext;
401 }
402
403 @Override
404 public boolean isOverwrite()
405 {
406
407 return true;
408 }
409
410
411
412
413 @Override
414 public boolean isExternalReport()
415 {
416 return report.isExternalReport();
417 }
418 }