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.IOUtil;
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 ctx )
138 {
139 super( ctx );
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 private RenderingContext context;
160
161 private List<MultiPageSubSink> sinks = new ArrayList<MultiPageSubSink>();
162
163 MultiPageSinkFactory( RenderingContext ctx )
164 {
165 this.context = ctx;
166 }
167
168 public Sink createSink( File outputDir, String outputName )
169 {
170 MultiPageSubSink sink = new MultiPageSubSink( outputDir, outputName, context );
171 sinks.add( sink );
172 return sink;
173 }
174
175 public Sink createSink( File arg0, String arg1, String arg2 )
176 throws IOException
177 {
178
179 return null;
180 }
181
182 public Sink createSink( OutputStream arg0 )
183 throws IOException
184 {
185
186 return null;
187 }
188
189 public Sink createSink( OutputStream arg0, String arg1 )
190 throws IOException
191 {
192
193 return null;
194 }
195
196 public List<MultiPageSubSink> sinks()
197 {
198 return sinks;
199 }
200 }
201
202 public void renderDocument( Writer writer, Renderer renderer, SiteRenderingContext siteRenderingContext )
203 throws RendererException, FileNotFoundException
204 {
205 Locale locale = siteRenderingContext.getLocale();
206 String localReportName = report.getName( locale );
207
208 String msg = "Generating \"" + buffer().strong( localReportName ) + "\" report";
209
210 log.info( reportMojoInfo == null ? ( msg + '.' )
211 : ( StringUtils.rightPad( msg, 40 ) + buffer().strong( " --- " ).mojo( reportMojoInfo ) ) );
212
213
214
215 SiteRendererSink mainSink = new SiteRendererSink( renderingContext );
216
217 MultiPageSinkFactory multiPageSinkFactory = new MultiPageSinkFactory( renderingContext );
218
219 ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
220 try
221 {
222 if ( classLoader != null )
223 {
224 Thread.currentThread().setContextClassLoader( classLoader );
225 }
226
227 if ( report instanceof MavenMultiPageReport )
228 {
229
230 ( (MavenMultiPageReport) report ).generate( mainSink, multiPageSinkFactory, locale );
231 }
232 else if ( generateMultiPage( locale, multiPageSinkFactory, mainSink ) )
233 {
234
235 }
236 else
237 {
238
239 report.generate( mainSink, locale );
240 }
241 }
242 catch ( MavenReportException e )
243 {
244 String report = ( reportMojoInfo == null ) ? ( '"' + localReportName + '"' ) : reportMojoInfo;
245 throw new RendererException( "Error generating " + report + " report", e );
246 }
247 catch ( LinkageError e )
248 {
249 String report = ( reportMojoInfo == null ) ? ( '"' + localReportName + '"' ) : reportMojoInfo;
250 log.warn( "An issue has occurred with " + report + " report, skipping LinkageError "
251 + e.getMessage() + ", please report an issue to Maven dev team.", e );
252 }
253 finally
254 {
255 if ( classLoader != null )
256 {
257 Thread.currentThread().setContextClassLoader( originalClassLoader );
258 }
259 mainSink.close();
260 }
261
262 if ( report.isExternalReport() )
263 {
264
265 return;
266 }
267
268
269 renderer.mergeDocumentIntoSite( writer, mainSink, siteRenderingContext );
270
271
272 String outputName = "";
273 try
274 {
275 List<MultiPageSubSink> sinks = multiPageSinkFactory.sinks();
276
277 log.debug( "Multipage report: " + sinks.size() + " subreports" );
278
279 for ( MultiPageSubSink mySink : sinks )
280 {
281 mySink.enableLogging( new MojoLogWrapper( log ) );
282
283 outputName = mySink.getOutputName();
284 log.debug( " Rendering " + outputName );
285
286 File outputFile = new File( mySink.getOutputDir(), outputName );
287
288 Writer out = null;
289 try
290 {
291 out = WriterFactory.newWriter( outputFile, siteRenderingContext.getOutputEncoding() );
292 renderer.mergeDocumentIntoSite( out, mySink, siteRenderingContext );
293 mySink.close();
294 mySink = null;
295 out.close();
296 out = null;
297 }
298 finally
299 {
300 IOUtil.close( out );
301
302 if ( mySink != null )
303 {
304 mySink.close();
305 }
306 }
307 }
308 }
309 catch ( IOException e )
310 {
311 throw new RendererException( "Cannot create writer to " + outputName, e );
312 }
313 }
314
315
316
317
318
319
320 private boolean generateMultiPage( Locale locale, SinkFactory sf, Sink sink )
321 throws MavenReportException
322 {
323 try
324 {
325
326
327 Method generate =
328 report.getClass().getMethod( "generate", Sink.class, SinkFactory.class, Locale.class );
329
330 generate.invoke( report, sink, sf, locale );
331
332 return true;
333 }
334 catch ( SecurityException se )
335 {
336 return false;
337 }
338 catch ( NoSuchMethodException nsme )
339 {
340 return false;
341 }
342 catch ( IllegalArgumentException iae )
343 {
344 throw new MavenReportException( "error while invoking generate on " + report.getClass(), iae );
345 }
346 catch ( IllegalAccessException iae )
347 {
348 throw new MavenReportException( "error while invoking generate on " + report.getClass(), iae );
349 }
350 catch ( InvocationTargetException ite )
351 {
352 throw new MavenReportException( "error while invoking generate on " + report.getClass(), ite );
353 }
354 }
355
356 public String getOutputName()
357 {
358 return renderingContext.getOutputName();
359 }
360
361 public RenderingContext getRenderingContext()
362 {
363 return renderingContext;
364 }
365
366 public boolean isOverwrite()
367 {
368
369 return true;
370 }
371
372
373
374
375 public boolean isExternalReport()
376 {
377 return report.isExternalReport();
378 }
379 }