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