1 package org.apache.maven.plugins.pdf;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.Reader;
26 import java.io.StringReader;
27 import java.io.StringWriter;
28 import java.io.Writer;
29 import java.lang.reflect.InvocationHandler;
30 import java.lang.reflect.Method;
31 import java.lang.reflect.Proxy;
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Locale;
36 import java.util.Map;
37 import java.util.Properties;
38
39 import javax.swing.text.AttributeSet;
40
41 import org.apache.commons.io.input.XmlStreamReader;
42 import org.apache.maven.artifact.Artifact;
43 import org.apache.maven.artifact.repository.ArtifactRepository;
44 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
45 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
46 import org.apache.maven.artifact.versioning.ArtifactVersion;
47 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
48 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
49 import org.apache.maven.artifact.versioning.VersionRange;
50 import org.apache.maven.doxia.Doxia;
51 import org.apache.maven.doxia.docrenderer.AbstractDocumentRenderer;
52 import org.apache.maven.doxia.docrenderer.DocumentRenderer;
53 import org.apache.maven.doxia.docrenderer.DocumentRendererContext;
54 import org.apache.maven.doxia.docrenderer.DocumentRendererException;
55 import org.apache.maven.doxia.docrenderer.pdf.PdfRenderer;
56 import org.apache.maven.doxia.document.DocumentMeta;
57 import org.apache.maven.doxia.document.DocumentModel;
58 import org.apache.maven.doxia.document.DocumentTOCItem;
59 import org.apache.maven.doxia.document.io.xpp3.DocumentXpp3Writer;
60 import org.apache.maven.doxia.index.IndexEntry;
61 import org.apache.maven.doxia.index.IndexingSink;
62 import org.apache.maven.doxia.module.xdoc.XdocSink;
63 import org.apache.maven.doxia.parser.ParseException;
64 import org.apache.maven.doxia.parser.manager.ParserNotFoundException;
65 import org.apache.maven.doxia.sink.Sink;
66 import org.apache.maven.doxia.sink.SinkAdapter;
67 import org.apache.maven.doxia.sink.SinkEventAttributeSet;
68 import org.apache.maven.doxia.sink.SinkEventAttributes;
69 import org.apache.maven.doxia.site.decoration.DecorationModel;
70 import org.apache.maven.doxia.site.decoration.io.xpp3.DecorationXpp3Reader;
71 import org.apache.maven.doxia.siterenderer.Renderer;
72 import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
73 import org.apache.maven.doxia.tools.SiteTool;
74 import org.apache.maven.doxia.tools.SiteToolException;
75 import org.apache.maven.execution.MavenSession;
76 import org.apache.maven.model.MailingList;
77 import org.apache.maven.model.ReportPlugin;
78 import org.apache.maven.model.ReportSet;
79 import org.apache.maven.plugin.AbstractMojo;
80 import org.apache.maven.plugin.InvalidPluginException;
81 import org.apache.maven.plugin.MojoExecution;
82 import org.apache.maven.plugin.MojoExecutionException;
83 import org.apache.maven.plugin.MojoFailureException;
84 import org.apache.maven.plugin.PluginConfigurationException;
85 import org.apache.maven.plugin.PluginManager;
86 import org.apache.maven.plugin.PluginManagerException;
87 import org.apache.maven.plugin.PluginNotFoundException;
88 import org.apache.maven.plugin.descriptor.MojoDescriptor;
89 import org.apache.maven.plugin.descriptor.PluginDescriptor;
90 import org.apache.maven.plugin.version.PluginVersionNotFoundException;
91 import org.apache.maven.plugin.version.PluginVersionResolutionException;
92 import org.apache.maven.plugins.annotations.Component;
93 import org.apache.maven.plugins.annotations.Mojo;
94 import org.apache.maven.plugins.annotations.Parameter;
95 import org.apache.maven.project.MavenProject;
96 import org.apache.maven.project.MavenProjectBuilder;
97 import org.apache.maven.project.ProjectBuildingException;
98 import org.apache.maven.reporting.AbstractMavenReportRenderer;
99 import org.apache.maven.reporting.MavenReport;
100 import org.apache.maven.reporting.MavenReportException;
101 import org.apache.maven.reporting.exec.MavenReportExecution;
102 import org.apache.maven.reporting.exec.MavenReportExecutor;
103 import org.apache.maven.reporting.exec.MavenReportExecutorRequest;
104 import org.apache.maven.settings.Settings;
105 import org.codehaus.plexus.PlexusConstants;
106 import org.codehaus.plexus.PlexusContainer;
107 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
108 import org.codehaus.plexus.context.Context;
109 import org.codehaus.plexus.context.ContextException;
110 import org.codehaus.plexus.i18n.I18N;
111 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
112 import org.codehaus.plexus.util.FileUtils;
113 import org.codehaus.plexus.util.IOUtil;
114 import org.codehaus.plexus.util.PathTool;
115 import org.codehaus.plexus.util.ReaderFactory;
116 import org.codehaus.plexus.util.StringUtils;
117 import org.codehaus.plexus.util.WriterFactory;
118 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
119
120
121
122
123
124
125
126 @Mojo( name = "pdf", threadSafe = true )
127 public class PdfMojo
128 extends AbstractMojo implements Contextualizable
129 {
130
131
132
133 private static final String EOL = System.getProperty( "line.separator" );
134
135
136
137
138
139
140
141
142 @Component( hint = "fo" )
143 private PdfRenderer foRenderer;
144
145
146
147
148 @Component
149 private I18N i18n;
150
151
152
153
154 @Component( hint = "itext" )
155 private PdfRenderer itextRenderer;
156
157
158
159
160
161 @Parameter( property = "locales" )
162 private String locales;
163
164
165
166
167 @Component
168 private Renderer siteRenderer;
169
170
171
172
173 @Component
174 private SiteTool siteTool;
175
176
177
178
179
180
181 @Component( role = PluginManager.class )
182 private PluginManager pluginManager;
183
184
185
186
187
188
189 @Component
190 private Doxia doxia;
191
192
193
194
195
196
197 @Component
198 private MavenProjectBuilder mavenProjectBuilder;
199
200
201
202
203
204
205
206
207 @Parameter( defaultValue = "${project}", readonly = true, required = true )
208 private MavenProject project;
209
210
211
212
213
214
215 @Parameter( defaultValue = "${settings}", readonly = true, required = true )
216 private Settings settings;
217
218
219
220
221
222
223 @Parameter( defaultValue = "${session}", readonly = true, required = true )
224 private MavenSession session;
225
226
227
228
229 @Parameter( defaultValue = "${basedir}/src/site", required = true )
230 private File siteDirectory;
231
232
233
234
235
236
237 @Parameter( defaultValue = "${project.build.directory}/generated-site", required = true )
238 private File generatedSiteDirectory;
239
240
241
242
243 @Parameter( defaultValue = "${project.build.directory}/pdf", required = true )
244 private File outputDirectory;
245
246
247
248
249 @Parameter( defaultValue = "${project.build.directory}/pdf", required = true )
250 private File workingDirectory;
251
252
253
254
255 @Parameter( defaultValue = "src/site/pdf.xml" )
256 private File docDescriptor;
257
258
259
260
261 @Parameter( property = "implementation", defaultValue = "fo", required = true )
262 private String implementation;
263
264
265
266
267 @Parameter( defaultValue = "${localRepository}", required = true, readonly = true )
268 private ArtifactRepository localRepository;
269
270
271
272
273
274
275 @Parameter( defaultValue = "${project.remoteArtifactRepositories}" )
276 private List<ArtifactRepository> remoteRepositories;
277
278
279
280
281
282 @Parameter( property = "aggregate", defaultValue = "true" )
283 private boolean aggregate;
284
285
286
287
288 @Parameter( defaultValue = "${plugin.version}", readonly = true )
289 private String pluginVersion;
290
291
292
293
294
295
296
297
298 @Parameter( property = "includeReports", defaultValue = "true" )
299 private boolean includeReports;
300
301
302
303
304
305
306
307
308 @Parameter( property = "generateTOC", defaultValue = "start" )
309 private String generateTOC;
310
311
312
313
314
315
316
317
318
319 @Parameter( property = "validate", defaultValue = "false" )
320 private boolean validate;
321
322
323
324
325
326 @Parameter( defaultValue = "${reports}", required = true, readonly = true )
327 private MavenReport[] reports;
328
329
330
331
332
333
334
335
336
337
338
339
340 @Parameter( readonly = true )
341 private org.apache.maven.reporting.exec.ReportPlugin[] reportPlugins;
342
343
344
345
346
347
348
349
350
351 private DocumentRenderer docRenderer;
352
353
354
355
356 private Locale defaultLocale;
357
358
359
360
361 private List<Locale> localesList;
362
363
364
365
366 private DecorationModel defaultDecorationModel;
367
368
369
370
371
372
373 private File siteDirectoryTmp;
374
375
376
377
378
379
380 private File generatedSiteDirectoryTmp;
381
382
383
384
385
386
387 private Map<Locale, List<MavenReport>> generatedMavenReports;
388
389
390
391
392 private PlexusContainer container;
393
394
395
396
397
398
399 public void execute()
400 throws MojoExecutionException, MojoFailureException
401 {
402 init();
403
404 try
405 {
406 generatePdf();
407 }
408 catch ( IOException e )
409 {
410 debugLogGeneratedModel( getDocumentModel( Locale.ENGLISH ) );
411
412 throw new MojoExecutionException( "Error during document generation: " + e.getMessage(), e );
413 }
414
415 try
416 {
417 copyGeneratedPdf();
418 }
419 catch ( IOException e )
420 {
421 throw new MojoExecutionException( "Error copying generated PDF: " + e.getMessage(), e );
422 }
423 }
424
425
426 public void contextualize( Context context )
427 throws ContextException
428 {
429 container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
430 }
431
432
433
434
435
436
437
438
439 private void init()
440 {
441 if ( "fo".equalsIgnoreCase( implementation ) )
442 {
443 this.docRenderer = foRenderer;
444 }
445 else if ( "itext".equalsIgnoreCase( implementation ) )
446 {
447 this.docRenderer = itextRenderer;
448 }
449 else
450 {
451 getLog().warn( "Invalid 'implementation' parameter: '" + implementation
452 + "', using 'fo' as default." );
453
454 this.docRenderer = foRenderer;
455 }
456
457 if ( !( "none".equalsIgnoreCase( generateTOC )
458 || "start".equalsIgnoreCase( generateTOC ) || "end".equalsIgnoreCase( generateTOC ) ) )
459 {
460 getLog().warn( "Invalid 'generateTOC' parameter: '" + generateTOC
461 + "', using 'start' as default." );
462
463 this.generateTOC = "start";
464 }
465 }
466
467
468
469
470
471
472
473
474 private void copyGeneratedPdf()
475 throws MojoExecutionException, IOException
476 {
477 if ( outputDirectory.getCanonicalPath().equals( workingDirectory.getCanonicalPath() ) )
478 {
479 return;
480 }
481
482 String outputName = getDocumentModel( getDefaultLocale() ).getOutputName().trim();
483 if ( !outputName.endsWith( ".pdf" ) )
484 {
485 outputName = outputName.concat( ".pdf" );
486 }
487
488 for ( final Locale locale : getAvailableLocales() )
489 {
490 File generatedPdfSource = new File( getLocaleDirectory( workingDirectory, locale ), outputName );
491
492 if ( !generatedPdfSource.exists() )
493 {
494 getLog().warn( "Unable to find the generated pdf: " + generatedPdfSource.getAbsolutePath() );
495 continue;
496 }
497
498 File generatedPdfDest = new File( getLocaleDirectory( outputDirectory, locale ), outputName );
499
500 FileUtils.copyFile( generatedPdfSource, generatedPdfDest );
501 generatedPdfSource.delete();
502 }
503 }
504
505
506
507
508
509
510
511
512 private void generatePdf()
513 throws MojoExecutionException, IOException
514 {
515 Locale.setDefault( getDefaultLocale() );
516
517 for ( final Locale locale : getAvailableLocales() )
518 {
519 final File workingDir = getLocaleDirectory( workingDirectory, locale );
520
521 File siteDirectoryFile = getLocaleDirectory( getSiteDirectoryTmp(), locale );
522
523 copyResources( locale );
524
525 generateMavenReports( locale );
526
527 DocumentRendererContext context = new DocumentRendererContext();
528 context.put( "project", project );
529 context.put( "settings", settings );
530 context.put( "PathTool", new PathTool() );
531 context.put( "FileUtils", new FileUtils() );
532 context.put( "StringUtils", new StringUtils() );
533 context.put( "i18n", i18n );
534 context.put( "generateTOC", generateTOC );
535 context.put( "validate", validate );
536
537
538 for ( Map.Entry<Object, Object> entry : project.getProperties().entrySet() )
539 {
540 context.put( (String) entry.getKey(), entry.getValue() );
541 }
542
543 final DocumentModel model = aggregate ? getDocumentModel( locale ) : null;
544
545 try
546 {
547
548 ( (AbstractDocumentRenderer) docRenderer ).render( siteDirectoryFile, workingDir, model, context );
549 }
550 catch ( DocumentRendererException e )
551 {
552 throw new MojoExecutionException( "Error during document generation: " + e.getMessage(), e );
553 }
554 }
555 }
556
557
558
559
560
561
562 private File getSiteDirectoryTmp()
563 throws IOException
564 {
565 if ( this.siteDirectoryTmp == null )
566 {
567 final File tmpSiteDir = new File( workingDirectory, "site.tmp" );
568 prepareTempSiteDirectory( tmpSiteDir );
569
570 this.siteDirectoryTmp = tmpSiteDir;
571 }
572
573 return this.siteDirectoryTmp;
574 }
575
576
577
578
579
580 private File getGeneratedSiteDirectoryTmp()
581 {
582 if ( this.generatedSiteDirectoryTmp == null )
583 {
584 this.generatedSiteDirectoryTmp = new File( workingDirectory, "generated-site.tmp" );
585 }
586
587 return this.generatedSiteDirectoryTmp;
588 }
589
590
591
592
593
594
595
596
597
598
599
600 private void prepareTempSiteDirectory( final File tmpSiteDir )
601 throws IOException
602 {
603
604 tmpSiteDir.mkdirs();
605
606
607 if ( siteDirectory.exists() )
608 {
609 FileUtils.copyDirectoryStructure( siteDirectory, tmpSiteDir );
610 }
611
612
613 List<String> files =
614 FileUtils.getFileAndDirectoryNames( tmpSiteDir, FileUtils.getDefaultExcludesAsString(), null, true,
615 true, true, true );
616 for ( final String fileName : files )
617 {
618 final File file = new File( fileName );
619
620 if ( file.isDirectory() )
621 {
622 FileUtils.deleteDirectory( file );
623 }
624 else
625 {
626 file.delete();
627 }
628 }
629
630 copySiteDir( generatedSiteDirectory, tmpSiteDir );
631 }
632
633
634
635
636
637
638
639
640
641 private void copySiteDir( final File from, final File to )
642 throws IOException
643 {
644 if ( from == null || !from.exists() )
645 {
646 return;
647 }
648
649
650 for ( final Locale locale : getAvailableLocales() )
651 {
652 String excludes = getDefaultExcludesWithLocales( getAvailableLocales(), getDefaultLocale() );
653 List<String> siteFiles = FileUtils.getFileNames( siteDirectory, "**/*", excludes, false );
654 File siteDirectoryLocale = new File( siteDirectory, locale.getLanguage() );
655 if ( !locale.getLanguage().equals( getDefaultLocale().getLanguage() ) && siteDirectoryLocale.exists() )
656 {
657 siteFiles = FileUtils.getFileNames( siteDirectoryLocale, "**/*", excludes, false );
658 }
659
660 List<String> generatedSiteFiles = FileUtils.getFileNames( from, "**/*", excludes, false );
661 File fromLocale = new File( from, locale.getLanguage() );
662 if ( !locale.getLanguage().equals( getDefaultLocale().getLanguage() ) && fromLocale.exists() )
663 {
664 generatedSiteFiles = FileUtils.getFileNames( fromLocale, "**/*", excludes, false );
665 }
666
667 for ( final String generatedSiteFile : generatedSiteFiles )
668 {
669 if ( siteFiles.contains( generatedSiteFile ) )
670 {
671 getLog().warn( "Generated-site already contains a file in site: " + generatedSiteFile
672 + ". Ignoring copying it!" );
673 continue;
674 }
675
676 if ( !locale.getLanguage().equals( getDefaultLocale().getLanguage() ) )
677 {
678 if ( fromLocale.exists() )
679 {
680 File in = new File( fromLocale, generatedSiteFile );
681 File out = new File( new File( to, locale.getLanguage() ), generatedSiteFile );
682 out.getParentFile().mkdirs();
683 FileUtils.copyFile( in, out );
684 }
685 }
686 else
687 {
688 File in = new File( from, generatedSiteFile );
689 File out = new File( to, generatedSiteFile );
690 out.getParentFile().mkdirs();
691 FileUtils.copyFile( in, out );
692 }
693 }
694 }
695 }
696
697
698
699
700
701
702
703
704
705
706 private DocumentModel getDocumentModel( Locale locale )
707 throws MojoExecutionException
708 {
709 if ( docDescriptor.exists() )
710 {
711 DocumentModel doc = getDocumentModelFromDescriptor( locale );
712
713
714 appendGeneratedReports( doc, locale );
715
716 return doc;
717 }
718
719 DocumentModel model = new DocumentModelBuilder( project, getDefaultDecorationModel() ).getDocumentModel();
720
721 model.getMeta().setGenerator( getDefaultGenerator() );
722 model.getMeta().setLanguage( locale.getLanguage() );
723 model.getCover().setCoverType( i18n.getString( "pdf-plugin", getDefaultLocale(), "toc.type" ) );
724 model.getToc().setName( i18n.getString( "pdf-plugin", getDefaultLocale(), "toc.title" ) );
725
726 appendGeneratedReports( model, locale );
727
728 debugLogGeneratedModel( model );
729
730 return model;
731 }
732
733
734
735
736
737
738
739
740 private DocumentModel getDocumentModelFromDescriptor( Locale locale )
741 throws MojoExecutionException
742 {
743 DocumentModel model;
744
745 try
746 {
747 model =
748 new DocumentDescriptorReader( project, getLog() ).readAndFilterDocumentDescriptor( docDescriptor );
749 }
750 catch ( XmlPullParserException ex )
751 {
752 throw new MojoExecutionException( "Error reading DocumentDescriptor!", ex );
753 }
754 catch ( IOException io )
755 {
756 throw new MojoExecutionException( "Error opening DocumentDescriptor!", io );
757 }
758
759 if ( model.getMeta() == null )
760 {
761 model.setMeta( new DocumentMeta() );
762 }
763
764 if ( StringUtils.isEmpty( model.getMeta().getLanguage() ) )
765 {
766 model.getMeta().setLanguage( locale.getLanguage() );
767 }
768
769 if ( StringUtils.isEmpty( model.getMeta().getGenerator() ) )
770 {
771 model.getMeta().setGenerator( getDefaultGenerator() );
772 }
773
774 return model;
775 }
776
777
778
779
780
781
782
783
784 private File getLocaleDirectory( File basedir, Locale locale )
785 {
786 if ( locale.getLanguage().equals( getDefaultLocale().getLanguage() ) )
787 {
788 return basedir;
789 }
790
791 return new File( basedir, locale.getLanguage() );
792 }
793
794
795
796
797
798 private Locale getDefaultLocale()
799 {
800 if ( this.defaultLocale == null )
801 {
802 this.defaultLocale = getAvailableLocales().get( 0 );
803 }
804
805 return this.defaultLocale;
806 }
807
808
809
810
811
812 private List<Locale> getAvailableLocales()
813 {
814 if ( this.localesList == null )
815 {
816 this.localesList = siteTool.getAvailableLocales( locales );
817 }
818
819 return this.localesList;
820 }
821
822
823
824
825
826 private DecorationModel getDefaultDecorationModel()
827 throws MojoExecutionException
828 {
829 if ( this.defaultDecorationModel == null )
830 {
831 final Locale locale = getDefaultLocale();
832
833 final File basedir = project.getBasedir();
834 final String relativePath =
835 siteTool.getRelativePath( siteDirectory.getAbsolutePath(), basedir.getAbsolutePath() );
836
837 final File descriptorFile = siteTool.getSiteDescriptorFromBasedir( relativePath, basedir, locale );
838 DecorationModel decoration = null;
839
840 if ( descriptorFile.exists() )
841 {
842 XmlStreamReader reader = null;
843 try
844 {
845 reader = new XmlStreamReader( descriptorFile );
846 String enc = reader.getEncoding();
847
848 String siteDescriptorContent = IOUtil.toString( reader );
849 siteDescriptorContent =
850 siteTool.getInterpolatedSiteDescriptorContent( new HashMap<String, String>( 2 ), project,
851 siteDescriptorContent, enc, enc );
852
853 decoration = new DecorationXpp3Reader().read( new StringReader( siteDescriptorContent ) );
854 }
855 catch ( XmlPullParserException e )
856 {
857 throw new MojoExecutionException( "Error parsing site descriptor", e );
858 }
859 catch ( IOException e )
860 {
861 throw new MojoExecutionException( "Error reading site descriptor", e );
862 }
863 catch ( SiteToolException e )
864 {
865 throw new MojoExecutionException( "Error when interpoling site descriptor", e );
866 }
867 finally
868 {
869 IOUtil.close( reader );
870 }
871 }
872
873 this.defaultDecorationModel = decoration;
874 }
875
876 return this.defaultDecorationModel;
877 }
878
879
880
881
882
883
884
885
886 private void copyResources( Locale locale )
887 throws MojoExecutionException
888 {
889 final DecorationModel decorationModel = getDefaultDecorationModel();
890 if ( decorationModel == null )
891 {
892 return;
893 }
894
895 File skinFile;
896 try
897 {
898 skinFile =
899 siteTool.getSkinArtifactFromRepository( localRepository, project.getRemoteArtifactRepositories(),
900 decorationModel ).getFile();
901 }
902 catch ( SiteToolException e )
903 {
904 throw new MojoExecutionException( "SiteToolException: " + e.getMessage(), e );
905 }
906
907 if ( skinFile == null )
908 {
909 return;
910 }
911
912 if ( getLog().isDebugEnabled() )
913 {
914 getLog().debug( "Copy resources from skin artifact: '" + skinFile + "'..." );
915 }
916
917 try
918 {
919 final SiteRenderingContext context =
920 siteRenderer.createContextForSkin( skinFile, new HashMap( 2 ), decorationModel, project.getName(),
921 locale );
922 context.addSiteDirectory( new File( siteDirectory, locale.getLanguage() ) );
923
924 for ( final File siteDirectoryFile : context.getSiteDirectories() )
925 {
926 siteRenderer.copyResources( context, new File( siteDirectoryFile, "resources" ), workingDirectory );
927 }
928 }
929 catch ( IOException e )
930 {
931 throw new MojoExecutionException( "IOException: " + e.getMessage(), e );
932 }
933 }
934
935
936
937
938
939
940 private String getDefaultGenerator()
941 {
942 return "Maven PDF Plugin v. " + pluginVersion + ", '" + implementation + "' implementation.";
943 }
944
945
946
947
948
949
950 private void debugLogGeneratedModel( final DocumentModel docModel )
951 {
952 if ( getLog().isDebugEnabled() && project != null )
953 {
954 final File outputDir = new File( project.getBuild().getDirectory(), "pdf" );
955
956 if ( !outputDir.exists() )
957 {
958 outputDir.mkdirs();
959 }
960
961 final File doc = FileUtils.createTempFile( "pdf", ".xml", outputDir );
962 final DocumentXpp3Writer xpp3 = new DocumentXpp3Writer();
963
964 Writer w = null;
965 try
966 {
967 w = WriterFactory.newXmlWriter( doc );
968 xpp3.write( w, docModel );
969
970 getLog().debug( "Generated a default document model: " + doc.getAbsolutePath() );
971 }
972 catch ( IOException e )
973 {
974 getLog().error( "Failed to write document model: " + e.getMessage() );
975 getLog().debug( e );
976 }
977 finally
978 {
979 IOUtil.close( w );
980 }
981 }
982 }
983
984
985
986
987
988
989
990
991
992
993 private void generateMavenReports( Locale locale )
994 throws MojoExecutionException, IOException
995 {
996 if ( !includeReports )
997 {
998 getLog().info( "Skipped report generation." );
999 return;
1000 }
1001
1002 if ( project.getReporting() == null )
1003 {
1004 getLog().info( "No report was specified." );
1005 return;
1006 }
1007
1008 for ( final ReportPlugin reportPlugin : project.getReporting().getPlugins() )
1009 {
1010 final PluginDescriptor pluginDescriptor = getPluginDescriptor( reportPlugin );
1011
1012 if ( pluginDescriptor != null )
1013 {
1014 List<String> goals = new ArrayList<String>( 8 );
1015 for ( final ReportSet reportSet : reportPlugin.getReportSets() )
1016 {
1017 for ( String goal : reportSet.getReports() )
1018 {
1019 goals.add( goal );
1020 }
1021 }
1022
1023 List mojoDescriptors = pluginDescriptor.getMojos();
1024 for ( Object mojoDescriptor1 : mojoDescriptors )
1025 {
1026 final MojoDescriptor mojoDescriptor = (MojoDescriptor) mojoDescriptor1;
1027
1028 if ( goals.isEmpty() || ( !goals.isEmpty() && goals.contains( mojoDescriptor.getGoal() ) ) )
1029 {
1030 MavenReport report = getMavenReport( mojoDescriptor );
1031
1032 generateMavenReport( report, mojoDescriptor.getPluginDescriptor().getPluginArtifact(),
1033 locale );
1034 }
1035 }
1036 }
1037 }
1038
1039
1040 if ( !getGeneratedMavenReports( locale ).isEmpty() )
1041 {
1042 File outDir = new File( getGeneratedSiteDirectoryTmp(), "xdoc" );
1043 if ( !locale.getLanguage().equals( defaultLocale.getLanguage() ) )
1044 {
1045 outDir = new File( new File( getGeneratedSiteDirectoryTmp(), locale.getLanguage() ), "xdoc" );
1046 }
1047 outDir.mkdirs();
1048
1049 File piReport = new File( outDir, "project-info.xml" );
1050
1051 StringWriter sw = new StringWriter();
1052
1053 PdfSink sink = new PdfSink( sw );
1054 ProjectInfoRenderer r = new ProjectInfoRenderer( sink, getGeneratedMavenReports( locale ), i18n, locale );
1055 r.render();
1056
1057 writeGeneratedReport( sw.toString(), piReport );
1058 }
1059
1060
1061 copySiteDir( getGeneratedSiteDirectoryTmp(), getSiteDirectoryTmp() );
1062 copySiteDir( generatedSiteDirectory, getSiteDirectoryTmp() );
1063 }
1064
1065
1066
1067
1068
1069
1070
1071
1072 private PluginDescriptor getPluginDescriptor( ReportPlugin reportPlugin )
1073 throws MojoExecutionException
1074 {
1075 try
1076 {
1077 return pluginManager.verifyReportPlugin( reportPlugin, project, session );
1078 }
1079 catch ( ArtifactResolutionException e )
1080 {
1081 throw new MojoExecutionException( "ArtifactResolutionException: " + e.getMessage(), e );
1082 }
1083 catch ( ArtifactNotFoundException e )
1084 {
1085 throw new MojoExecutionException( "ArtifactNotFoundException: " + e.getMessage(), e );
1086 }
1087 catch ( PluginNotFoundException e )
1088 {
1089 throw new MojoExecutionException( "PluginNotFoundException: " + e.getMessage(), e );
1090 }
1091 catch ( PluginVersionResolutionException e )
1092 {
1093 throw new MojoExecutionException( "PluginVersionResolutionException: " + e.getMessage(), e );
1094 }
1095 catch ( InvalidVersionSpecificationException e )
1096 {
1097 throw new MojoExecutionException( "InvalidVersionSpecificationException: " + e.getMessage(), e );
1098 }
1099 catch ( InvalidPluginException e )
1100 {
1101 throw new MojoExecutionException( "InvalidPluginException: " + e.getMessage(), e );
1102 }
1103 catch ( PluginManagerException e )
1104 {
1105 throw new MojoExecutionException( "PluginManagerException: " + e.getMessage(), e );
1106 }
1107 catch ( PluginVersionNotFoundException e )
1108 {
1109 throw new MojoExecutionException( "PluginVersionNotFoundException: " + e.getMessage(), e );
1110 }
1111 catch ( NoSuchMethodError e )
1112 {
1113 getLog().info( "Ignoring api call removed in maven 3, no reports are generated!" );
1114 getLog().debug( e );
1115 return null;
1116 }
1117 }
1118
1119
1120
1121
1122
1123
1124
1125 private MavenReport getMavenReport( MojoDescriptor mojoDescriptor )
1126 throws MojoExecutionException
1127 {
1128 ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
1129 try
1130 {
1131 Thread.currentThread()
1132 .setContextClassLoader( mojoDescriptor.getPluginDescriptor().getClassRealm().getClassLoader() );
1133
1134 MojoExecution mojoExecution = new MojoExecution( mojoDescriptor );
1135
1136 return pluginManager.getReport( project, mojoExecution, session );
1137 }
1138 catch ( ArtifactNotFoundException e )
1139 {
1140 throw new MojoExecutionException( "ArtifactNotFoundException: " + e.getMessage(), e );
1141 }
1142 catch ( ArtifactResolutionException e )
1143 {
1144 throw new MojoExecutionException( "ArtifactResolutionException: " + e.getMessage(), e );
1145 }
1146 catch ( PluginConfigurationException e )
1147 {
1148 throw new MojoExecutionException( "PluginConfigurationException: " + e.getMessage(), e );
1149 }
1150 catch ( PluginManagerException e )
1151 {
1152 throw new MojoExecutionException( "PluginManagerException: " + e.getMessage(), e );
1153 }
1154 finally
1155 {
1156 Thread.currentThread().setContextClassLoader( oldClassLoader );
1157 }
1158 }
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171 private void generateMavenReport( MavenReport report, Artifact pluginArtifact, Locale locale )
1172 throws IOException, MojoExecutionException
1173 {
1174 if ( report == null )
1175 {
1176 return;
1177 }
1178
1179 String localReportName = report.getName( locale );
1180 if ( !report.canGenerateReport() )
1181 {
1182 getLog().info( "Skipped \"" + localReportName + "\" report." );
1183 getLog().debug( "canGenerateReport() was false." );
1184
1185 return;
1186 }
1187
1188 if ( report.isExternalReport() )
1189 {
1190 getLog().info( "Skipped external \"" + localReportName + "\" report." );
1191 getLog().debug( "isExternalReport() was false." );
1192
1193 return;
1194 }
1195
1196 for ( final MavenReport generatedReport : getGeneratedMavenReports( locale ) )
1197 {
1198 if ( report.getName( locale ).equals( generatedReport.getName( locale ) ) )
1199 {
1200 if ( getLog().isDebugEnabled() )
1201 {
1202 getLog().debug( report.getName( locale ) + " was already generated." );
1203 }
1204 return;
1205 }
1206 }
1207
1208 File outDir = new File( getGeneratedSiteDirectoryTmp(), "xdoc" );
1209 if ( !locale.getLanguage().equals( defaultLocale.getLanguage() ) )
1210 {
1211 outDir = new File( new File( getGeneratedSiteDirectoryTmp(), locale.getLanguage() ), "xdoc" );
1212 }
1213 outDir.mkdirs();
1214
1215 File generatedReport = new File( outDir, report.getOutputName() + ".xml" );
1216
1217 String excludes = getDefaultExcludesWithLocales( getAvailableLocales(), getDefaultLocale() );
1218 List<String> files =
1219 FileUtils.getFileNames( siteDirectory, "*/" + report.getOutputName() + ".*", excludes, false );
1220 if ( !locale.getLanguage().equals( defaultLocale.getLanguage() ) )
1221 {
1222 files =
1223 FileUtils.getFileNames( new File( siteDirectory, locale.getLanguage() ), "*/"
1224 + report.getOutputName() + ".*", excludes, false );
1225 }
1226
1227 if ( files.size() != 0 )
1228 {
1229 String displayLanguage = locale.getDisplayLanguage( Locale.ENGLISH );
1230
1231 if ( getLog().isInfoEnabled() )
1232 {
1233 getLog().info(
1234 "Skipped \"" + report.getName( locale ) + "\" report, file \""
1235 + report.getOutputName() + "\" already exists for the " + displayLanguage
1236 + " version." );
1237 }
1238
1239 return;
1240 }
1241
1242 if ( getLog().isInfoEnabled() )
1243 {
1244 getLog().info( "Generating \"" + localReportName + "\" report." );
1245 }
1246
1247 StringWriter sw = new StringWriter();
1248
1249 PdfSink sink = null;
1250 try
1251 {
1252 sink = new PdfSink( sw );
1253 org.codehaus.doxia.sink.Sink proxy = (org.codehaus.doxia.sink.Sink) Proxy.newProxyInstance(
1254 org.codehaus.doxia.sink.Sink.class.getClassLoader(),
1255 new Class[] { org.codehaus.doxia.sink.Sink.class }, new SinkDelegate( sink ) );
1256 report.generate( proxy, locale );
1257 }
1258 catch ( MavenReportException e )
1259 {
1260 throw new MojoExecutionException( "MavenReportException: " + e.getMessage(), e );
1261 }
1262 finally
1263 {
1264 if ( sink != null )
1265 {
1266 sink.close();
1267 }
1268 }
1269
1270 writeGeneratedReport( sw.toString(), generatedReport );
1271
1272 if ( isValidGeneratedReport( pluginArtifact, generatedReport, localReportName ) )
1273 {
1274 getGeneratedMavenReports( locale ).add( report );
1275 }
1276 }
1277
1278
1279
1280
1281
1282
1283
1284
1285 private List<MavenReport> getGeneratedMavenReports( Locale locale )
1286 {
1287 if ( this.generatedMavenReports == null )
1288 {
1289 this.generatedMavenReports = new HashMap<Locale, List<MavenReport>>( 2 );
1290 }
1291
1292 if ( this.generatedMavenReports.get( locale ) == null )
1293 {
1294 this.generatedMavenReports.put( locale, new ArrayList<MavenReport>( 2 ) );
1295 }
1296
1297 return this.generatedMavenReports.get( locale );
1298 }
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316 private void appendGeneratedReports( DocumentModel model, Locale locale )
1317 {
1318 if ( !includeReports )
1319 {
1320 return;
1321 }
1322 if ( getGeneratedMavenReports( locale ).isEmpty() )
1323 {
1324 return;
1325 }
1326
1327 final DocumentTOCItem documentTOCItem = new DocumentTOCItem();
1328 documentTOCItem.setName( i18n.getString( "pdf-plugin", locale, "toc.project-info.item" ) );
1329 documentTOCItem.setRef( "/project-info" );
1330
1331 List<String> addedRef = new ArrayList<String>( 4 );
1332
1333 List<DocumentTOCItem> items = new ArrayList<DocumentTOCItem>( 4 );
1334
1335
1336 for ( final MavenReport report : getGeneratedMavenReports( locale ) )
1337 {
1338 final DocumentTOCItem reportItem = new DocumentTOCItem();
1339 reportItem.setName( report.getName( locale ) );
1340 reportItem.setRef( "/" + report.getOutputName() );
1341
1342 items.add( reportItem );
1343
1344 addedRef.add( report.getOutputName() );
1345 }
1346
1347
1348 try
1349 {
1350 if ( generatedSiteDirectory.exists() )
1351 {
1352 String excludes = getDefaultExcludesWithLocales( getAvailableLocales(), getDefaultLocale() );
1353 List<String> generatedDirs = FileUtils.getDirectoryNames( generatedSiteDirectory, "*", excludes,
1354 true );
1355 if ( !locale.getLanguage().equals( getDefaultLocale().getLanguage() ) )
1356 {
1357 generatedDirs =
1358 FileUtils.getFileNames( new File( generatedSiteDirectory, locale.getLanguage() ), "*",
1359 excludes, true );
1360 }
1361
1362 for ( final String generatedDir : generatedDirs )
1363 {
1364 List<String> generatedFiles =
1365 FileUtils.getFileNames( new File( generatedDir ), "**.*", excludes, false );
1366
1367 for ( final String generatedFile : generatedFiles )
1368 {
1369 final String ref = generatedFile.substring( 0, generatedFile.lastIndexOf( '.' ) );
1370
1371 if ( !addedRef.contains( ref ) )
1372 {
1373 final String title =
1374 getGeneratedDocumentTitle( new File( generatedDir, generatedFile ) );
1375
1376 if ( title != null )
1377 {
1378 final DocumentTOCItem reportItem = new DocumentTOCItem();
1379 reportItem.setName( title );
1380 reportItem.setRef( "/" + ref );
1381
1382 items.add( reportItem );
1383 }
1384 }
1385 }
1386 }
1387 }
1388 }
1389 catch ( IOException e )
1390 {
1391 getLog().error( "IOException: " + e.getMessage() );
1392 getLog().debug( e );
1393 }
1394
1395
1396 documentTOCItem.setItems( items );
1397 model.getToc().addItem( documentTOCItem );
1398 }
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408 private String getGeneratedDocumentTitle( final File f )
1409 throws IOException
1410 {
1411 final IndexEntry entry = new IndexEntry( "index" );
1412 final IndexingSink titleSink = new IndexingSink( entry );
1413
1414 Reader reader = null;
1415 try
1416 {
1417 reader = ReaderFactory.newXmlReader( f );
1418
1419 doxia.parse( reader, f.getParentFile().getName(), titleSink );
1420 }
1421 catch ( ParseException e )
1422 {
1423 getLog().error( "ParseException: " + e.getMessage() );
1424 getLog().debug( e );
1425 return null;
1426 }
1427 catch ( ParserNotFoundException e )
1428 {
1429 getLog().error( "ParserNotFoundException: " + e.getMessage() );
1430 getLog().debug( e );
1431 return null;
1432 }
1433 finally
1434 {
1435 IOUtil.close( reader );
1436 }
1437
1438 return titleSink.getTitle();
1439 }
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450 private boolean isValidGeneratedReport( Artifact pluginArtifact, File generatedReport,
1451 String localReportName )
1452 {
1453 SinkAdapter sinkAdapter = new SinkAdapter();
1454 Reader reader = null;
1455 try
1456 {
1457 reader = ReaderFactory.newXmlReader( generatedReport );
1458
1459 doxia.parse( reader, generatedReport.getParentFile().getName(), sinkAdapter );
1460 }
1461 catch ( ParseException e )
1462 {
1463 StringBuilder sb = new StringBuilder( 1024 );
1464
1465 sb.append( EOL ).append( EOL );
1466 sb.append( "Error when parsing the generated report: " ).append( generatedReport.getAbsolutePath() );
1467 sb.append( EOL );
1468 sb.append( e.getMessage() );
1469 sb.append( EOL ).append( EOL );
1470
1471 sb.append( "You could:" ).append( EOL );
1472 sb.append( " * exclude all reports using -DincludeReports=false" ).append( EOL );
1473 sb.append( " * remove the " );
1474 sb.append( pluginArtifact.getGroupId() );
1475 sb.append( ":" );
1476 sb.append( pluginArtifact.getArtifactId() );
1477 sb.append( ":" );
1478 sb.append( pluginArtifact.getVersion() );
1479 sb.append( " from the <reporting/> part. To not affect the site generation, " );
1480 sb.append( "you could create a PDF profile." ).append( EOL );
1481 sb.append( EOL );
1482
1483 MavenProject pluginProject = getReportPluginProject( pluginArtifact );
1484
1485 if ( pluginProject == null )
1486 {
1487 sb.append( "You could also contact the Plugin team." ).append( EOL );
1488 }
1489 else
1490 {
1491 sb.append( "You could also contact the Plugin team:" ).append( EOL );
1492 if ( pluginProject.getMailingLists() != null && !pluginProject.getMailingLists().isEmpty() )
1493 {
1494 boolean appended = false;
1495 for ( Object o : pluginProject.getMailingLists() )
1496 {
1497 MailingList mailingList = (MailingList) o;
1498
1499 if ( StringUtils.isNotEmpty( mailingList.getName() )
1500 && StringUtils.isNotEmpty( mailingList.getPost() ) )
1501 {
1502 if ( !appended )
1503 {
1504 sb.append( " Mailing Lists:" ).append( EOL );
1505 appended = true;
1506 }
1507 sb.append( " " ).append( mailingList.getName() );
1508 sb.append( ": " ).append( mailingList.getPost() );
1509 sb.append( EOL );
1510 }
1511 }
1512 }
1513 if ( StringUtils.isNotEmpty( pluginProject.getUrl() ) )
1514 {
1515 sb.append( " Web Site:" ).append( EOL );
1516 sb.append( " " ).append( pluginProject.getUrl() );
1517 sb.append( EOL );
1518 }
1519 if ( pluginProject.getIssueManagement() != null
1520 && StringUtils.isNotEmpty( pluginProject.getIssueManagement().getUrl() ) )
1521 {
1522 sb.append( " Issue Tracking:" ).append( EOL );
1523 sb.append( " " ).append( pluginProject.getIssueManagement().getUrl() );
1524 sb.append( EOL );
1525 }
1526 }
1527
1528 sb.append( EOL ).append( "Ignoring the \"" ).append( localReportName )
1529 .append( "\" report in the PDF." ).append( EOL );
1530
1531 getLog().error( sb.toString() );
1532 getLog().debug( e );
1533
1534 return false;
1535 }
1536 catch ( ParserNotFoundException e )
1537 {
1538 getLog().error( "ParserNotFoundException: " + e.getMessage() );
1539 getLog().debug( e );
1540
1541 return false;
1542 }
1543 catch ( IOException e )
1544 {
1545 getLog().error( "IOException: " + e.getMessage() );
1546 getLog().debug( e );
1547
1548 return false;
1549 }
1550 finally
1551 {
1552 IOUtil.close( reader );
1553 }
1554
1555 return true;
1556 }
1557
1558
1559
1560
1561
1562
1563 private MavenProject getReportPluginProject( Artifact pluginArtifact )
1564 {
1565 try
1566 {
1567 return mavenProjectBuilder.buildFromRepository( pluginArtifact, remoteRepositories, localRepository );
1568 }
1569 catch ( ProjectBuildingException e )
1570 {
1571 getLog().error( "ProjectBuildingException: " + e.getMessage() );
1572 getLog().debug( e );
1573 }
1574
1575 return null;
1576 }
1577
1578 protected List<MavenReportExecution> getReports()
1579 throws MojoExecutionException
1580 {
1581 if ( isMaven3OrMore() )
1582 {
1583 MavenReportExecutorRequest mavenReportExecutorRequest = new MavenReportExecutorRequest();
1584 mavenReportExecutorRequest.setLocalRepository( localRepository );
1585 mavenReportExecutorRequest.setMavenSession( session );
1586 mavenReportExecutorRequest.setProject( project );
1587 mavenReportExecutorRequest.setReportPlugins( reportPlugins );
1588
1589 MavenReportExecutor mavenReportExecutor;
1590 try
1591 {
1592 mavenReportExecutor = (MavenReportExecutor) container.lookup( MavenReportExecutor.class.getName() );
1593 }
1594 catch ( ComponentLookupException e )
1595 {
1596 throw new MojoExecutionException( "could not get MavenReportExecutor component", e );
1597 }
1598 return mavenReportExecutor.buildMavenReports( mavenReportExecutorRequest );
1599 }
1600
1601 List<MavenReportExecution> reportExecutions = new ArrayList<MavenReportExecution>( reports.length );
1602 for ( MavenReport report : reports )
1603 {
1604 if ( report.canGenerateReport() )
1605 {
1606 reportExecutions.add( new MavenReportExecution( report ) );
1607 }
1608 }
1609 return reportExecutions;
1610 }
1611
1612
1613
1614
1615 protected static boolean isMaven3OrMore()
1616 {
1617 try
1618 {
1619 ArtifactVersion mavenVersion = new DefaultArtifactVersion( getMavenVersion() );
1620 return VersionRange.createFromVersionSpec( "[3.0,)" ).containsVersion( mavenVersion );
1621 }
1622 catch ( InvalidVersionSpecificationException e )
1623 {
1624 return false;
1625 }
1626
1627 }
1628
1629 protected static String getMavenVersion()
1630 {
1631
1632
1633
1634
1635 final Properties properties = new Properties();
1636 final InputStream in =
1637 MavenProject.class.getClassLoader().getResourceAsStream( "META-INF/maven/org.apache.maven/maven-core/"
1638 + "pom.properties" );
1639 try
1640 {
1641 properties.load( in );
1642 }
1643 catch ( IOException ioe )
1644 {
1645 return "";
1646 }
1647 finally
1648 {
1649 IOUtil.close( in );
1650 }
1651
1652 return properties.getProperty( "version" ).trim();
1653 }
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670 private static void writeGeneratedReport( String content, File toFile )
1671 throws IOException
1672 {
1673 if ( StringUtils.isEmpty( content ) )
1674 {
1675 return;
1676 }
1677
1678 Writer writer = null;
1679 try
1680 {
1681 writer = WriterFactory.newXmlWriter( toFile );
1682
1683 writer.write( StringUtils.replace( content, "<table><table", "<table" ) );
1684 }
1685 finally
1686 {
1687 IOUtil.close( writer );
1688 }
1689 }
1690
1691
1692
1693
1694
1695
1696
1697
1698 private static String getDefaultExcludesWithLocales( List<Locale> locales, Locale defaultLocale )
1699 {
1700 String excludesLocales = FileUtils.getDefaultExcludesAsString();
1701 for ( final Locale locale : locales )
1702 {
1703 if ( !locale.getLanguage().equals( defaultLocale.getLanguage() ) )
1704 {
1705 excludesLocales = excludesLocales + ",**/" + locale.getLanguage() + "/*";
1706 }
1707 }
1708
1709 return excludesLocales;
1710 }
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721 private static class PdfSink
1722 extends XdocSink
1723 {
1724 protected PdfSink( Writer writer )
1725 {
1726 super( writer );
1727 }
1728
1729
1730 public void text( String text )
1731 {
1732
1733 super.text( StringUtils.replace( text, "\u0092", "'" ) );
1734 }
1735 }
1736
1737
1738
1739
1740
1741
1742 private static class ProjectInfoRenderer
1743 extends AbstractMavenReportRenderer
1744 {
1745 private final List<MavenReport> generatedReports;
1746
1747 private final I18N i18n;
1748
1749 private final Locale locale;
1750
1751 ProjectInfoRenderer( Sink sink, List<MavenReport> generatedReports, I18N i18n, Locale locale )
1752 {
1753 super( sink );
1754
1755 this.generatedReports = generatedReports;
1756 this.i18n = i18n;
1757 this.locale = locale;
1758 }
1759
1760
1761 public String getTitle()
1762 {
1763 return i18n.getString( "pdf-plugin", locale, "report.project-info.title" );
1764 }
1765
1766
1767 public void renderBody()
1768 {
1769 sink.section1();
1770 sink.sectionTitle1();
1771 sink.text( i18n.getString( "pdf-plugin", locale, "report.project-info.title" ) );
1772 sink.sectionTitle1_();
1773
1774 sink.paragraph();
1775 sink.text( i18n.getString( "pdf-plugin", locale, "report.project-info.description1" ) + " " );
1776 sink.link( "http://maven.apache.org" );
1777 sink.text( "Maven" );
1778 sink.link_();
1779 sink.text( " " + i18n.getString( "pdf-plugin", locale, "report.project-info.description2" ) );
1780 sink.paragraph_();
1781
1782 sink.section2();
1783 sink.sectionTitle2();
1784 sink.text( i18n.getString( "pdf-plugin", locale, "report.project-info.sectionTitle" ) );
1785 sink.sectionTitle2_();
1786
1787 sink.table();
1788
1789 sink.tableRows( new int[] { Sink.JUSTIFY_LEFT, Sink.JUSTIFY_LEFT }, false );
1790
1791 String name = i18n.getString( "pdf-plugin", locale, "report.project-info.column.document" );
1792 String description = i18n.getString( "pdf-plugin", locale, "report.project-info.column.description" );
1793
1794 sink.tableRow();
1795
1796 sink.tableHeaderCell( SinkEventAttributeSet.CENTER );
1797
1798 sink.text( name );
1799
1800 sink.tableHeaderCell_();
1801
1802 sink.tableHeaderCell( SinkEventAttributeSet.CENTER );
1803
1804 sink.text( description );
1805
1806 sink.tableHeaderCell_();
1807
1808 sink.tableRow_();
1809
1810 if ( generatedReports != null )
1811 {
1812 for ( final MavenReport report : generatedReports )
1813 {
1814 sink.tableRow();
1815 sink.tableCell();
1816 sink.link( report.getOutputName() + ".html" );
1817 sink.text( report.getName( locale ) );
1818 sink.link_();
1819 sink.tableCell_();
1820 sink.tableCell();
1821 sink.text( report.getDescription( locale ) );
1822 sink.tableCell_();
1823 sink.tableRow_();
1824 }
1825 }
1826
1827 sink.tableRows_();
1828
1829 sink.table_();
1830
1831 sink.section2_();
1832
1833 sink.section1_();
1834 }
1835 }
1836
1837
1838
1839
1840
1841
1842
1843 private static class SinkDelegate
1844 implements InvocationHandler
1845 {
1846 private final Sink sink;
1847
1848 SinkDelegate( Sink sink )
1849 {
1850 this.sink = sink;
1851 }
1852
1853
1854 public Object invoke( Object proxy, Method method, Object[] args )
1855 throws Throwable
1856 {
1857 Class<?>[] parameterTypes = method.getParameterTypes();
1858
1859 for ( int i = parameterTypes.length - 1; i >= 0; i-- )
1860 {
1861 if ( AttributeSet.class.isAssignableFrom( parameterTypes[i] ) )
1862 {
1863 parameterTypes[i] = SinkEventAttributes.class;
1864 }
1865 }
1866
1867 if ( args != null )
1868 {
1869 for ( int i = args.length - 1; i >= 0; i-- )
1870 {
1871 if ( AttributeSet.class.isInstance( args[i] ) )
1872 {
1873 args[i] = new SinkEventAttributeSet( (AttributeSet) args[i] );
1874 }
1875 }
1876 }
1877
1878 Method target = Sink.class.getMethod( method.getName(), parameterTypes );
1879
1880 return target.invoke( sink, args );
1881 }
1882 }
1883 }