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