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 org.apache.maven.artifact.Artifact;
23 import org.apache.maven.doxia.site.decoration.DecorationModel;
24 import org.apache.maven.doxia.site.decoration.Menu;
25 import org.apache.maven.doxia.site.decoration.MenuItem;
26 import org.apache.maven.doxia.siterenderer.DocumentRenderer;
27 import org.apache.maven.doxia.siterenderer.Renderer;
28 import org.apache.maven.doxia.siterenderer.RendererException;
29 import org.apache.maven.doxia.siterenderer.RenderingContext;
30 import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
31 import org.apache.maven.doxia.tools.SiteToolException;
32 import org.apache.maven.execution.MavenSession;
33 import org.apache.maven.model.ReportPlugin;
34 import org.apache.maven.model.Reporting;
35 import org.apache.maven.plugin.MojoExecutionException;
36 import org.apache.maven.plugin.MojoFailureException;
37 import org.apache.maven.plugin.descriptor.PluginDescriptor;
38 import org.apache.maven.plugins.annotations.Component;
39 import org.apache.maven.plugins.annotations.Parameter;
40 import org.apache.maven.plugins.site.descriptor.AbstractSiteDescriptorMojo;
41 import org.apache.maven.reporting.MavenReport;
42 import org.apache.maven.reporting.exec.MavenReportExecution;
43 import org.apache.maven.reporting.exec.MavenReportExecutor;
44 import org.apache.maven.reporting.exec.MavenReportExecutorRequest;
45 import org.codehaus.plexus.PlexusConstants;
46 import org.codehaus.plexus.PlexusContainer;
47 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
48 import org.codehaus.plexus.context.Context;
49 import org.codehaus.plexus.context.ContextException;
50 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
51 import org.codehaus.plexus.util.ReaderFactory;
52 import org.codehaus.plexus.util.StringUtils;
53
54 import java.io.File;
55 import java.io.IOException;
56 import java.util.ArrayList;
57 import java.util.Collection;
58 import java.util.HashMap;
59 import java.util.Iterator;
60 import java.util.LinkedHashMap;
61 import java.util.List;
62 import java.util.Locale;
63 import java.util.Map;
64
65 import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
66
67
68
69
70
71
72
73 public abstract class AbstractSiteRenderingMojo
74 extends AbstractSiteDescriptorMojo implements Contextualizable
75 {
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 @Parameter
93 private Map<String, String> moduleExcludes;
94
95
96
97
98
99
100
101 @Parameter( property = "templateFile" )
102 private File templateFile;
103
104
105
106
107
108 @Parameter
109 private Map<String, Object> attributes;
110
111
112
113
114 @Component
115 protected Renderer siteRenderer;
116
117
118
119
120 @Parameter( defaultValue = "${reports}", required = true, readonly = true )
121 protected List<MavenReport> reports;
122
123
124
125
126
127
128 @Parameter( defaultValue = "${basedir}/xdocs" )
129 private File xdocDirectory;
130
131
132
133
134
135
136
137
138
139
140
141 @Parameter( alias = "workingDirectory", defaultValue = "${project.build.directory}/generated-site" )
142 protected File generatedSiteDirectory;
143
144
145
146
147 @Parameter( defaultValue = "${session}", readonly = true, required = true )
148 protected MavenSession mavenSession;
149
150
151
152
153
154
155
156 @Parameter( defaultValue = "${project.reporting}", readonly = true )
157 private Reporting reporting;
158
159 private PlexusContainer container;
160
161
162
163
164
165
166 @Parameter( property = "generateProjectInfo", defaultValue = "true" )
167 private boolean generateProjectInfo;
168
169
170
171
172
173
174 @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
175 private String inputEncoding;
176
177
178
179
180
181
182 @Parameter( property = "outputEncoding", defaultValue = "${project.reporting.outputEncoding}" )
183 private String outputEncoding;
184
185
186
187
188
189
190 protected String getInputEncoding()
191 {
192 return ( StringUtils.isEmpty( inputEncoding ) ) ? ReaderFactory.FILE_ENCODING : inputEncoding;
193 }
194
195
196
197
198
199
200 protected String getOutputEncoding()
201 {
202 return ( outputEncoding == null ) ? ReaderFactory.UTF_8 : outputEncoding;
203 }
204
205
206
207
208
209
210
211 @Parameter
212 private boolean saveProcessedContent;
213
214
215 public void contextualize( Context context )
216 throws ContextException
217 {
218 container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
219 }
220
221 protected void checkInputEncoding()
222 {
223 if ( StringUtils.isEmpty( inputEncoding ) )
224 {
225 getLog().warn( "Input file encoding has not been set, using platform encoding "
226 + ReaderFactory.FILE_ENCODING + ", i.e. build is platform dependent!" );
227 }
228 }
229
230 protected List<MavenReportExecution> getReports()
231 throws MojoExecutionException
232 {
233 final List<MavenReportExecution> allReports;
234 if ( isMaven3OrMore() )
235 {
236
237 MavenReportExecutorRequest mavenReportExecutorRequest = new MavenReportExecutorRequest();
238 mavenReportExecutorRequest.setLocalRepository( localRepository );
239 mavenReportExecutorRequest.setMavenSession( mavenSession );
240 mavenReportExecutorRequest.setProject( project );
241 mavenReportExecutorRequest.setReportPlugins( getReportingPlugins() );
242
243 MavenReportExecutor mavenReportExecutor;
244 try
245 {
246 mavenReportExecutor = container.lookup( MavenReportExecutor.class );
247 }
248 catch ( ComponentLookupException e )
249 {
250 throw new MojoExecutionException( "could not get MavenReportExecutor component", e );
251 }
252
253 allReports = mavenReportExecutor.buildMavenReports( mavenReportExecutorRequest );
254 }
255 else
256 {
257
258 allReports = new ArrayList<>( reports.size() );
259 for ( MavenReport report : reports )
260 {
261 allReports.add( new MavenReportExecution( report ) );
262 }
263 }
264
265
266
267 List<MavenReportExecution> reportExecutions = new ArrayList<>( allReports.size() );
268 for ( MavenReportExecution exec : allReports )
269 {
270 if ( exec.canGenerateReport() )
271 {
272 reportExecutions.add( exec );
273 }
274 }
275 return reportExecutions;
276 }
277
278
279
280
281
282
283
284
285 private ReportPlugin[] getReportingPlugins()
286 {
287 List<ReportPlugin> reportingPlugins = reporting.getPlugins();
288
289
290 boolean hasMavenProjectInfoReportsPlugin = false;
291 for ( ReportPlugin plugin : reportingPlugins )
292 {
293 if ( "org.apache.maven.plugins".equals( plugin.getGroupId() )
294 && "maven-project-info-reports-plugin".equals( plugin.getArtifactId() ) )
295 {
296 hasMavenProjectInfoReportsPlugin = true;
297 break;
298 }
299 }
300
301 if ( !reporting.isExcludeDefaults() && !hasMavenProjectInfoReportsPlugin )
302 {
303 ReportPlugin mpir = new ReportPlugin();
304 mpir.setArtifactId( "maven-project-info-reports-plugin" );
305 reportingPlugins.add( mpir );
306 }
307 return reportingPlugins.toArray( new ReportPlugin[reportingPlugins.size()] );
308 }
309
310 protected SiteRenderingContext createSiteRenderingContext( Locale locale )
311 throws MojoExecutionException, IOException, MojoFailureException
312 {
313 DecorationModel decorationModel = prepareDecorationModel( locale );
314 if ( attributes == null )
315 {
316 attributes = new HashMap<>();
317 }
318
319 if ( attributes.get( "project" ) == null )
320 {
321 attributes.put( "project", project );
322 }
323
324 if ( attributes.get( "inputEncoding" ) == null )
325 {
326 attributes.put( "inputEncoding", getInputEncoding() );
327 }
328
329 if ( attributes.get( "outputEncoding" ) == null )
330 {
331 attributes.put( "outputEncoding", getOutputEncoding() );
332 }
333
334
335 for ( Map.Entry<Object, Object> entry : project.getProperties().entrySet() )
336 {
337 attributes.put( (String) entry.getKey(), entry.getValue() );
338 }
339
340 SiteRenderingContext context;
341 if ( templateFile != null )
342 {
343 getLog().info( buffer().a( "Rendering content with " ).strong( templateFile
344 + " template file" ).a( '.' ).toString() );
345
346 if ( !templateFile.exists() )
347 {
348 throw new MojoFailureException( "Template file '" + templateFile + "' does not exist" );
349 }
350 context = siteRenderer.createContextForTemplate( templateFile, attributes, decorationModel,
351 project.getName(), locale );
352 }
353 else
354 {
355 try
356 {
357 Artifact skinArtifact =
358 siteTool.getSkinArtifactFromRepository( localRepository, repositories, decorationModel );
359
360 getLog().info( buffer().a( "Rendering content with " ).strong( skinArtifact.getId()
361 + " skin" ).a( '.' ).toString() );
362
363 context = siteRenderer.createContextForSkin( skinArtifact, attributes, decorationModel,
364 project.getName(), locale );
365 }
366 catch ( SiteToolException e )
367 {
368 throw new MojoExecutionException( "SiteToolException while preparing skin: " + e.getMessage(), e );
369 }
370 catch ( RendererException e )
371 {
372 throw new MojoExecutionException( "RendererException while preparing context for skin: "
373 + e.getMessage(), e );
374 }
375 }
376
377
378 context.setRootDirectory( project.getBasedir() );
379 if ( !locale.getLanguage().equals( Locale.getDefault().getLanguage() ) )
380 {
381 context.addSiteDirectory( new File( siteDirectory, locale.getLanguage() ) );
382 context.addModuleDirectory( new File( xdocDirectory, locale.getLanguage() ), "xdoc" );
383 context.addModuleDirectory( new File( xdocDirectory, locale.getLanguage() ), "fml" );
384 }
385 else
386 {
387 context.addSiteDirectory( siteDirectory );
388 context.addModuleDirectory( xdocDirectory, "xdoc" );
389 context.addModuleDirectory( xdocDirectory, "fml" );
390 }
391
392 if ( moduleExcludes != null )
393 {
394 context.setModuleExcludes( moduleExcludes );
395 }
396
397 if ( saveProcessedContent )
398 {
399 context.setProcessedContentOutput( new File( generatedSiteDirectory, "processed" ) );
400 }
401
402 return context;
403 }
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418 protected Map<String, MavenReport> locateReports( List<MavenReportExecution> reports,
419 Map<String, DocumentRenderer> documents, Locale locale )
420 {
421
422 List<MavenReportExecution> filtered = new ArrayList<>( reports );
423
424 Map<String, MavenReport> reportsByOutputName = new LinkedHashMap<>();
425 for ( MavenReportExecution mavenReportExecution : filtered )
426 {
427 MavenReport report = mavenReportExecution.getMavenReport();
428
429 String outputName = report.getOutputName() + ".html";
430
431
432 reportsByOutputName.put( report.getOutputName(), report );
433
434 if ( documents.containsKey( outputName ) )
435 {
436 String reportMojoInfo =
437 ( mavenReportExecution.getGoal() == null ) ? "" : ( " ("
438 + mavenReportExecution.getPlugin().getArtifactId() + ':'
439 + mavenReportExecution.getPlugin().getVersion() + ':' + mavenReportExecution.getGoal() + ')' );
440
441 getLog().info( "Skipped \"" + report.getName( locale ) + "\" report" + reportMojoInfo + ", file \""
442 + outputName + "\" already exists." );
443
444 reports.remove( mavenReportExecution );
445 }
446 else
447 {
448 String reportMojoInfo = mavenReportExecution.getPlugin().getGroupId() + ':'
449 + mavenReportExecution.getPlugin().getArtifactId() + ':'
450 + mavenReportExecution.getPlugin().getVersion() + ':' + mavenReportExecution.getGoal();
451 RenderingContext renderingContext = new RenderingContext( siteDirectory, outputName, reportMojoInfo );
452 DocumentRenderer renderer =
453 new ReportDocumentRenderer( mavenReportExecution, renderingContext, getLog() );
454 documents.put( outputName, renderer );
455 }
456 }
457 return reportsByOutputName;
458 }
459
460
461
462
463
464
465
466
467 protected Map<String, List<MavenReport>> categoriseReports( Collection<MavenReport> reports )
468 {
469 Map<String, List<MavenReport>> categories = new LinkedHashMap<>();
470 for ( MavenReport report : reports )
471 {
472 List<MavenReport> categoryReports = categories.get( report.getCategoryName() );
473 if ( categoryReports == null )
474 {
475 categoryReports = new ArrayList<>();
476 categories.put( report.getCategoryName(), categoryReports );
477 }
478 categoryReports.add( report );
479 }
480 return categories;
481 }
482
483
484
485
486
487
488
489
490
491 protected Map<String, DocumentRenderer> locateDocuments( SiteRenderingContext context,
492 List<MavenReportExecution> reports, Locale locale )
493 throws IOException, RendererException
494 {
495 Map<String, DocumentRenderer> documents = siteRenderer.locateDocumentFiles( context, true );
496
497 Map<String, MavenReport> reportsByOutputName = locateReports( reports, documents, locale );
498
499
500 Map<String, List<MavenReport>> categories = categoriseReports( reportsByOutputName.values() );
501
502 siteTool.populateReportsMenu( context.getDecoration(), locale, categories );
503 populateReportItems( context.getDecoration(), locale, reportsByOutputName );
504
505 if ( categories.containsKey( MavenReport.CATEGORY_PROJECT_INFORMATION ) && generateProjectInfo )
506 {
507
508 List<MavenReport> categoryReports = categories.get( MavenReport.CATEGORY_PROJECT_INFORMATION );
509
510 RenderingContext renderingContext =
511 new RenderingContext( siteDirectory, "project-info.html",
512 getSitePluginInfo() + ":CategorySummaryDocumentRenderer" );
513 String title = i18n.getString( "site-plugin", locale, "report.information.title" );
514 String desc1 = i18n.getString( "site-plugin", locale, "report.information.description1" );
515 String desc2 = i18n.getString( "site-plugin", locale, "report.information.description2" );
516 DocumentRenderer renderer = new CategorySummaryDocumentRenderer( renderingContext, title, desc1, desc2,
517 i18n, categoryReports, getLog() );
518
519 if ( !documents.containsKey( renderer.getOutputName() ) )
520 {
521 documents.put( renderer.getOutputName(), renderer );
522 }
523 else
524 {
525 getLog().info( "Category summary '" + renderer.getOutputName() + "' skipped; already exists" );
526 }
527 }
528
529 if ( categories.containsKey( MavenReport.CATEGORY_PROJECT_REPORTS ) )
530 {
531
532 List<MavenReport> categoryReports = categories.get( MavenReport.CATEGORY_PROJECT_REPORTS );
533 RenderingContext renderingContext =
534 new RenderingContext( siteDirectory, "project-reports.html",
535 getSitePluginInfo() + ":CategorySummaryDocumentRenderer" );
536 String title = i18n.getString( "site-plugin", locale, "report.project.title" );
537 String desc1 = i18n.getString( "site-plugin", locale, "report.project.description1" );
538 String desc2 = i18n.getString( "site-plugin", locale, "report.project.description2" );
539 DocumentRenderer renderer = new CategorySummaryDocumentRenderer( renderingContext, title, desc1, desc2,
540 i18n, categoryReports, getLog() );
541
542 if ( !documents.containsKey( renderer.getOutputName() ) )
543 {
544 documents.put( renderer.getOutputName(), renderer );
545 }
546 else
547 {
548 getLog().info( "Category summary '" + renderer.getOutputName() + "' skipped; already exists" );
549 }
550 }
551 return documents;
552 }
553
554 private String getSitePluginInfo()
555 {
556 PluginDescriptor pluginDescriptor = (PluginDescriptor) getPluginContext().get( "pluginDescriptor" );
557 return pluginDescriptor.getId();
558 }
559 protected void populateReportItems( DecorationModel decorationModel, Locale locale,
560 Map<String, MavenReport> reportsByOutputName )
561 {
562 for ( Menu menu : decorationModel.getMenus() )
563 {
564 populateItemRefs( menu.getItems(), locale, reportsByOutputName );
565 }
566 }
567
568 private void populateItemRefs( List<MenuItem> items, Locale locale, Map<String, MavenReport> reportsByOutputName )
569 {
570 for ( Iterator<MenuItem> i = items.iterator(); i.hasNext(); )
571 {
572 MenuItem item = i.next();
573
574 if ( item.getRef() != null )
575 {
576 MavenReport report = reportsByOutputName.get( item.getRef() );
577
578 if ( report != null )
579 {
580 if ( item.getName() == null )
581 {
582 item.setName( report.getName( locale ) );
583 }
584
585 if ( item.getHref() == null || item.getHref().length() == 0 )
586 {
587 item.setHref( report.getOutputName() + ".html" );
588 }
589 }
590 else
591 {
592 getLog().warn( "Unrecognised reference: '" + item.getRef() + "'" );
593 i.remove();
594 }
595 }
596
597 populateItemRefs( item.getItems(), locale, reportsByOutputName );
598 }
599 }
600 }