Coverage Report - org.apache.maven.plugins.pdf.PdfMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
PdfMojo
24%
121/497
18%
36/192
5.846
PdfMojo$PdfSink
0%
0/4
N/A
5.846
PdfMojo$ProjectInfoRenderer
0%
0/51
0%
0/4
5.846
PdfMojo$SinkDelegate
0%
0/13
0%
0/10
5.846
 
 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 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  
  * Generates a PDF document for a project.
 122  
  *
 123  
  * @author ltheussl
 124  
  * @version $Id: PdfMojo.java 1642369 2014-11-28 21:54:06Z hboutemy $
 125  
  */
 126  
 @Mojo( name = "pdf", threadSafe = true )
 127  4
 public class PdfMojo
 128  
     extends AbstractMojo implements Contextualizable
 129  
 {
 130  
     /**
 131  
      * The vm line separator
 132  
      */
 133  1
     private static final String EOL = System.getProperty( "line.separator" );
 134  
 
 135  
     // ----------------------------------------------------------------------
 136  
     // Mojo components
 137  
     // ----------------------------------------------------------------------
 138  
 
 139  
     /**
 140  
      * FO Document Renderer.
 141  
      */
 142  
     @Component( hint = "fo" )
 143  
     private PdfRenderer foRenderer;
 144  
 
 145  
     /**
 146  
      * Internationalization.
 147  
      */
 148  
     @Component
 149  
     private I18N i18n;
 150  
 
 151  
     /**
 152  
      * IText Document Renderer.
 153  
      */
 154  
     @Component( hint = "itext" )
 155  
     private PdfRenderer itextRenderer;
 156  
 
 157  
     /**
 158  
      * A comma separated list of locales supported by Maven.
 159  
      * The first valid token will be the default Locale for this instance of the Java Virtual Machine.
 160  
      */
 161  
     @Parameter( property = "locales" )
 162  
     private String locales;
 163  
 
 164  
     /**
 165  
      * Site renderer.
 166  
      */
 167  
     @Component
 168  
     private Renderer siteRenderer;
 169  
 
 170  
     /**
 171  
      * SiteTool.
 172  
      */
 173  
     @Component
 174  
     private SiteTool siteTool;
 175  
 
 176  
     /**
 177  
      * The Plugin manager instance used to resolve Plugin descriptors.
 178  
      *
 179  
      * @since 1.1
 180  
      */
 181  
     @Component( role = PluginManager.class )
 182  
     private PluginManager pluginManager;
 183  
 
 184  
     /**
 185  
      * Doxia.
 186  
      *
 187  
      * @since 1.1
 188  
      */
 189  
     @Component
 190  
     private Doxia doxia;
 191  
 
 192  
     /**
 193  
      * Project builder.
 194  
      *
 195  
      * @since 1.1
 196  
      */
 197  
     @Component
 198  
     private MavenProjectBuilder mavenProjectBuilder;
 199  
 
 200  
     // ----------------------------------------------------------------------
 201  
     // Mojo Parameters
 202  
     // ----------------------------------------------------------------------
 203  
 
 204  
     /**
 205  
      * The Maven Project Object.
 206  
      */
 207  
     @Parameter( defaultValue = "${project}", readonly = true, required = true )
 208  
     private MavenProject project;
 209  
 
 210  
     /**
 211  
      * The Maven Settings.
 212  
      *
 213  
      * @since 1.1
 214  
      */
 215  
     @Parameter( defaultValue = "${settings}", readonly = true, required = true )
 216  
     private Settings settings;
 217  
 
 218  
     /**
 219  
      * The current build session instance.
 220  
      *
 221  
      * @since 1.1
 222  
      */
 223  
     @Parameter( defaultValue = "${session}", readonly = true, required = true )
 224  
     private MavenSession session;
 225  
 
 226  
     /**
 227  
      * Directory containing source for apt, fml and xdoc docs.
 228  
      */
 229  
     @Parameter( defaultValue = "${basedir}/src/site", required = true )
 230  
     private File siteDirectory;
 231  
 
 232  
     /**
 233  
      * Directory containing generated sources for apt, fml and xdoc docs.
 234  
      *
 235  
      * @since 1.1
 236  
      */
 237  
     @Parameter( defaultValue = "${project.build.directory}/generated-site", required = true )
 238  
     private File generatedSiteDirectory;
 239  
 
 240  
     /**
 241  
      * Output directory where PDF files should be created.
 242  
      */
 243  
     @Parameter( defaultValue = "${project.build.directory}/pdf", required = true )
 244  
     private File outputDirectory;
 245  
 
 246  
     /**
 247  
      * Working directory for working files like temp files/resources.
 248  
      */
 249  
     @Parameter( defaultValue = "${project.build.directory}/pdf", required = true )
 250  
     private File workingDirectory;
 251  
 
 252  
     /**
 253  
      * File that contains the DocumentModel of the PDF to generate.
 254  
      */
 255  
     @Parameter( defaultValue = "src/site/pdf.xml" )
 256  
     private File docDescriptor;
 257  
 
 258  
     /**
 259  
      * Identifies the framework to use for pdf generation: either "fo" (default) or "itext".
 260  
      */
 261  
     @Parameter( property = "implementation", defaultValue = "fo", required = true )
 262  
     private String implementation;
 263  
 
 264  
     /**
 265  
      * The local repository.
 266  
      */
 267  
     @Parameter( defaultValue = "${localRepository}", required = true, readonly = true )
 268  
     private ArtifactRepository localRepository;
 269  
 
 270  
     /**
 271  
      * The remote repositories where artifacts are located.
 272  
      *
 273  
      * @since 1.1
 274  
      */
 275  
     @Parameter( defaultValue = "${project.remoteArtifactRepositories}"  )
 276  
     private List<ArtifactRepository> remoteRepositories;
 277  
 
 278  
     /**
 279  
      * If <code>true</false>, aggregate all source documents in one pdf, otherwise generate one pdf for each
 280  
      * source document.
 281  
      */
 282  
     @Parameter( property = "aggregate", defaultValue = "true" )
 283  
     private boolean aggregate;
 284  
 
 285  
     /**
 286  
      * The current version of this plugin.
 287  
      */
 288  
     @Parameter( defaultValue = "${plugin.version}", readonly = true )
 289  
     private String pluginVersion;
 290  
 
 291  
     /**
 292  
      * If <code>true</false>, generate all Maven reports defined in <code>${project.reporting}</code> and append
 293  
      * them as a new entry in the TOC (Table Of Contents).
 294  
      * <b>Note</b>: Including the report generation could fail the PDF generation or increase the build time.
 295  
      *
 296  
      * @since 1.1
 297  
      */
 298  
     @Parameter( property = "includeReports", defaultValue = "true" )
 299  
     private boolean includeReports;
 300  
 
 301  
     /**
 302  
      * Generate a TOC (Table Of Content) for all items defined in the &lt;toc/&gt; element from the document descriptor.
 303  
      * <br/>
 304  
      * Possible values are: 'none', 'start' and 'end'.
 305  
      *
 306  
      * @since 1.1
 307  
      */
 308  
     @Parameter( property = "generateTOC", defaultValue = "start" )
 309  
     private String generateTOC;
 310  
 
 311  
     /**
 312  
      * Whether to validate xml input documents.
 313  
      * If set to true, <strong>all</strong> input documents in xml format
 314  
      * (in particular xdoc and fml) will be validated and any error will
 315  
      * lead to a build failure.
 316  
      *
 317  
      * @since 1.2
 318  
      */
 319  
     @Parameter( property = "validate", defaultValue = "false" )
 320  
     private boolean validate;
 321  
     
 322  
     /**
 323  
      * Reports (Maven 2).
 324  
      * @since 1.3
 325  
      */
 326  
     @Parameter( defaultValue = "${reports}", required = true, readonly = true )
 327  
     private MavenReport[] reports;
 328  
     
 329  
     /**
 330  
      * <p>Configuration section <b>used internally</b> by Maven 3.</p>
 331  
      * <p>More details available here:
 332  
      * <a href="http://maven.apache.org/plugins/maven-site-plugin/maven-3.html#Configuration_formats" target="_blank">
 333  
      * http://maven.apache.org/plugins/maven-site-plugin/maven-3.html#Configuration_formats</a>
 334  
      * </p>
 335  
      * <p><b>Note:</b> using this field is not mandatory with Maven 3 as Maven core injects usual
 336  
      * <code>&lt;reporting&gt;</code> section into this field.</p>
 337  
      *
 338  
      * @since 1.3
 339  
      */
 340  
     @Parameter( readonly = true )
 341  
     private org.apache.maven.reporting.exec.ReportPlugin[] reportPlugins;
 342  
 
 343  
     // ----------------------------------------------------------------------
 344  
     // Instance fields
 345  
     // ----------------------------------------------------------------------
 346  
 
 347  
     /**
 348  
      * The current document Renderer.
 349  
      * @see #implementation
 350  
      */
 351  
     private DocumentRenderer docRenderer;
 352  
 
 353  
     /**
 354  
      * The default locale.
 355  
      */
 356  
     private Locale defaultLocale;
 357  
 
 358  
     /**
 359  
      * The available locales list.
 360  
      */
 361  
     private List<Locale> localesList;
 362  
 
 363  
     /**
 364  
      * The default decoration model.
 365  
      */
 366  
     private DecorationModel defaultDecorationModel;
 367  
 
 368  
     /**
 369  
      * The temp Site dir to have all site and generated-site files.
 370  
      *
 371  
      * @since 1.1
 372  
      */
 373  
     private File siteDirectoryTmp;
 374  
 
 375  
     /**
 376  
      * The temp Generated Site dir to have generated reports by this plugin.
 377  
      *
 378  
      * @since 1.1
 379  
      */
 380  
     private File generatedSiteDirectoryTmp;
 381  
 
 382  
     /**
 383  
      * A map of generated MavenReport list using locale as key.
 384  
      *
 385  
      * @since 1.1
 386  
      */
 387  
     private Map<Locale, List<MavenReport>> generatedMavenReports;
 388  
     
 389  
     /**
 390  
      * @since 1.3
 391  
      */
 392  
     private PlexusContainer container;
 393  
 
 394  
     // ----------------------------------------------------------------------
 395  
     // Public methods
 396  
     // ----------------------------------------------------------------------
 397  
 
 398  
     /** {@inheritDoc} */
 399  
     public void execute()
 400  
         throws MojoExecutionException, MojoFailureException
 401  
     {
 402  4
         init();
 403  
 
 404  
         try
 405  
         {
 406  4
             generatePdf();
 407  
         }
 408  0
         catch ( IOException e )
 409  
         {
 410  0
             debugLogGeneratedModel( getDocumentModel( Locale.ENGLISH ) );
 411  
 
 412  0
             throw new MojoExecutionException( "Error during document generation: " + e.getMessage(), e );
 413  4
         }
 414  
 
 415  
         try
 416  
         {
 417  4
             copyGeneratedPdf();
 418  
         }
 419  0
         catch ( IOException e )
 420  
         {
 421  0
             throw new MojoExecutionException( "Error copying generated PDF: " + e.getMessage(), e );
 422  4
         }
 423  4
     }
 424  
     
 425  
     /** {@inheritDoc} */
 426  
     public void contextualize( Context context )
 427  
         throws ContextException
 428  
     {
 429  4
         container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
 430  4
     }
 431  
 
 432  
     // ----------------------------------------------------------------------
 433  
     // Private methods
 434  
     // ----------------------------------------------------------------------
 435  
 
 436  
     /**
 437  
      * Init and validate parameters
 438  
      */
 439  
     private void init()
 440  
     {
 441  4
         if ( "fo".equalsIgnoreCase( implementation ) )
 442  
         {
 443  3
             this.docRenderer = foRenderer;
 444  
         }
 445  1
         else if ( "itext".equalsIgnoreCase( implementation ) )
 446  
         {
 447  1
             this.docRenderer = itextRenderer;
 448  
         }
 449  
         else
 450  
         {
 451  0
             getLog().warn( "Invalid 'implementation' parameter: '" + implementation
 452  
                     + "', using 'fo' as default." );
 453  
 
 454  0
             this.docRenderer = foRenderer;
 455  
         }
 456  
 
 457  4
         if ( !( "none".equalsIgnoreCase( generateTOC )
 458  
                 || "start".equalsIgnoreCase( generateTOC ) || "end".equalsIgnoreCase( generateTOC ) ) )
 459  
         {
 460  0
             getLog().warn( "Invalid 'generateTOC' parameter: '" + generateTOC
 461  
                     + "', using 'start' as default." );
 462  
 
 463  0
             this.generateTOC = "start";
 464  
         }
 465  4
     }
 466  
 
 467  
     /**
 468  
      * Copy the generated PDF to outputDirectory.
 469  
      *
 470  
      * @throws MojoExecutionException if any
 471  
      * @throws IOException if any
 472  
      * @since 1.1
 473  
      */
 474  
     private void copyGeneratedPdf()
 475  
         throws MojoExecutionException, IOException
 476  
     {
 477  4
         if ( outputDirectory.getCanonicalPath().equals( workingDirectory.getCanonicalPath() ) )
 478  
         {
 479  4
             return;
 480  
         }
 481  
 
 482  0
         String outputName = getDocumentModel( getDefaultLocale() ).getOutputName().trim();
 483  0
         if ( !outputName.endsWith( ".pdf" ) )
 484  
         {
 485  0
             outputName = outputName.concat( ".pdf" );
 486  
         }
 487  
 
 488  0
         for ( final Locale locale : getAvailableLocales() )
 489  
         {
 490  0
             File generatedPdfSource = new File( getLocaleDirectory( workingDirectory, locale ), outputName );
 491  
 
 492  0
             if ( !generatedPdfSource.exists() )
 493  
             {
 494  0
                 getLog().warn( "Unable to find the generated pdf: " + generatedPdfSource.getAbsolutePath() );
 495  0
                 continue;
 496  
             }
 497  
 
 498  0
             File generatedPdfDest = new File( getLocaleDirectory( outputDirectory, locale ), outputName );
 499  
 
 500  0
             FileUtils.copyFile( generatedPdfSource, generatedPdfDest );
 501  0
             generatedPdfSource.delete();
 502  0
         }
 503  0
     }
 504  
 
 505  
     /**
 506  
      * Generate the PDF.
 507  
      *
 508  
      * @throws MojoExecutionException if any
 509  
      * @throws IOException if any
 510  
      * @since 1.1
 511  
      */
 512  
     private void generatePdf()
 513  
         throws MojoExecutionException, IOException
 514  
     {
 515  4
         Locale.setDefault( getDefaultLocale() );
 516  
 
 517  4
         for ( final Locale locale : getAvailableLocales() )
 518  
         {
 519  4
             final File workingDir = getLocaleDirectory( workingDirectory, locale );
 520  
 
 521  4
             File siteDirectoryFile = getLocaleDirectory( getSiteDirectoryTmp(), locale );
 522  
 
 523  4
             copyResources( locale );
 524  
 
 525  4
             generateMavenReports( locale );
 526  
 
 527  4
             DocumentRendererContext context = new DocumentRendererContext();
 528  4
             context.put( "project", project );
 529  4
             context.put( "settings", settings );
 530  4
             context.put( "PathTool", new PathTool() );
 531  4
             context.put( "FileUtils", new FileUtils() );
 532  4
             context.put( "StringUtils", new StringUtils() );
 533  4
             context.put( "i18n", i18n );
 534  4
             context.put( "generateTOC", generateTOC );
 535  4
             context.put( "validate", validate );
 536  
 
 537  
             // Put any of the properties in directly into the Velocity context
 538  4
             for ( Map.Entry<Object, Object> entry : project.getProperties().entrySet() )
 539  
             {
 540  1
                 context.put( (String) entry.getKey(), entry.getValue() );
 541  1
             }
 542  
             
 543  4
             final DocumentModel model = aggregate ? getDocumentModel( locale ) : null;
 544  
 
 545  
             try
 546  
             {
 547  
                 // TODO use interface see DOXIASITETOOLS-30
 548  4
                 ( (AbstractDocumentRenderer) docRenderer ).render( siteDirectoryFile, workingDir, model, context );
 549  
             }
 550  0
             catch ( DocumentRendererException e )
 551  
             {
 552  0
                 throw new MojoExecutionException( "Error during document generation: " + e.getMessage(), e );
 553  4
             }
 554  4
         }
 555  4
     }
 556  
 
 557  
     /**
 558  
      * @return the default tmpSiteDirectory.
 559  
      * @throws IOException if any
 560  
      * @since 1.1
 561  
      */
 562  
     private File getSiteDirectoryTmp()
 563  
         throws IOException
 564  
     {
 565  4
         if ( this.siteDirectoryTmp == null )
 566  
         {
 567  4
             final File tmpSiteDir = new File( workingDirectory, "site.tmp" );
 568  4
             prepareTempSiteDirectory( tmpSiteDir );
 569  
 
 570  4
             this.siteDirectoryTmp = tmpSiteDir;
 571  
         }
 572  
 
 573  4
         return this.siteDirectoryTmp;
 574  
     }
 575  
 
 576  
     /**
 577  
      * @return the default tmpGeneratedSiteDirectory when report will be created.
 578  
      * @since 1.1
 579  
      */
 580  
     private File getGeneratedSiteDirectoryTmp()
 581  
     {
 582  0
         if ( this.generatedSiteDirectoryTmp == null )
 583  
         {
 584  0
             this.generatedSiteDirectoryTmp = new File( workingDirectory, "generated-site.tmp" );
 585  
         }
 586  
 
 587  0
         return this.generatedSiteDirectoryTmp;
 588  
     }
 589  
 
 590  
     /**
 591  
      * Copy all site and generated-site files in the tmpSiteDirectory.
 592  
      * <br/>
 593  
      * <b>Note</b>: ignore copying of <code>generated-site</code> files if they already exist in the
 594  
      * <code>site</code> dir.
 595  
      *
 596  
      * @param tmpSiteDir not null
 597  
      * @throws IOException if any
 598  
      * @since 1.1
 599  
      */
 600  
     private void prepareTempSiteDirectory( final File tmpSiteDir )
 601  
         throws IOException
 602  
     {
 603  
         // safety
 604  4
         tmpSiteDir.mkdirs();
 605  
 
 606  
         // copy site
 607  4
         if ( siteDirectory.exists() )
 608  
         {
 609  4
             FileUtils.copyDirectoryStructure( siteDirectory, tmpSiteDir );
 610  
         }
 611  
 
 612  
         // Remove SCM files
 613  4
         List<String> files =
 614  
             FileUtils.getFileAndDirectoryNames( tmpSiteDir, FileUtils.getDefaultExcludesAsString(), null, true,
 615  
                                                 true, true, true );
 616  4
         for ( final String fileName : files )
 617  
         {
 618  0
             final File file = new File( fileName );
 619  
 
 620  0
             if ( file.isDirectory() )
 621  
             {
 622  0
                 FileUtils.deleteDirectory( file );
 623  
             }
 624  
             else
 625  
             {
 626  0
                 file.delete();
 627  
             }
 628  0
         }
 629  
 
 630  4
         copySiteDir( generatedSiteDirectory, tmpSiteDir );
 631  4
     }
 632  
 
 633  
     /**
 634  
      * Copy the from site dir to the to dir.
 635  
      *
 636  
      * @param from not null
 637  
      * @param to not null
 638  
      * @throws IOException if any
 639  
      * @since 1.1
 640  
      */
 641  
     private void copySiteDir( final File from, final File to )
 642  
         throws IOException
 643  
     {
 644  4
         if ( from == null || !from.exists() )
 645  
         {
 646  4
             return;
 647  
         }
 648  
 
 649  
         // copy generated-site
 650  0
         for ( final Locale locale : getAvailableLocales() )
 651  
         {
 652  0
             String excludes = getDefaultExcludesWithLocales( getAvailableLocales(), getDefaultLocale() );
 653  0
             List<String> siteFiles = FileUtils.getFileNames( siteDirectory, "**/*", excludes, false );
 654  0
             File siteDirectoryLocale = new File( siteDirectory, locale.getLanguage() );
 655  0
             if ( !locale.getLanguage().equals( getDefaultLocale().getLanguage() ) && siteDirectoryLocale.exists() )
 656  
             {
 657  0
                 siteFiles = FileUtils.getFileNames( siteDirectoryLocale, "**/*", excludes, false );
 658  
             }
 659  
 
 660  0
             List<String> generatedSiteFiles = FileUtils.getFileNames( from, "**/*", excludes, false );
 661  0
             File fromLocale = new File( from, locale.getLanguage() );
 662  0
             if ( !locale.getLanguage().equals( getDefaultLocale().getLanguage() ) && fromLocale.exists() )
 663  
             {
 664  0
                 generatedSiteFiles = FileUtils.getFileNames( fromLocale, "**/*", excludes, false );
 665  
             }
 666  
 
 667  0
             for ( final String generatedSiteFile : generatedSiteFiles )
 668  
             {
 669  0
                 if ( siteFiles.contains( generatedSiteFile ) )
 670  
                 {
 671  0
                     getLog().warn( "Generated-site already contains a file in site: " + generatedSiteFile
 672  
                                        + ". Ignoring copying it!" );
 673  0
                     continue;
 674  
                 }
 675  
 
 676  0
                 if ( !locale.getLanguage().equals( getDefaultLocale().getLanguage() ) )
 677  
                 {
 678  0
                     if ( fromLocale.exists() )
 679  
                     {
 680  0
                         File in = new File( fromLocale, generatedSiteFile );
 681  0
                         File out = new File( new File( to, locale.getLanguage() ), generatedSiteFile );
 682  0
                         out.getParentFile().mkdirs();
 683  0
                         FileUtils.copyFile( in, out );
 684  0
                     }
 685  
                 }
 686  
                 else
 687  
                 {
 688  0
                     File in = new File( from, generatedSiteFile );
 689  0
                     File out = new File( to, generatedSiteFile );
 690  0
                     out.getParentFile().mkdirs();
 691  0
                     FileUtils.copyFile( in, out );
 692  
                 }
 693  0
             }
 694  0
         }
 695  0
     }
 696  
 
 697  
     /**
 698  
      * Constructs a DocumentModel for the current project. The model is either read from
 699  
      * a descriptor file, if it exists, or constructed from information in the pom and site.xml.
 700  
      *
 701  
      * @param locale not null
 702  
      * @return DocumentModel.
 703  
      * @throws MojoExecutionException if any
 704  
      * @see #appendGeneratedReports(DocumentModel, Locale)
 705  
      */
 706  
     private DocumentModel getDocumentModel( Locale locale )
 707  
         throws MojoExecutionException
 708  
     {
 709  4
         if ( docDescriptor.exists() )
 710  
         {
 711  3
             DocumentModel doc = getDocumentModelFromDescriptor( locale );
 712  
             // TODO: descriptor model should get merged into default model, see MODELLO-63
 713  
 
 714  3
             appendGeneratedReports( doc, locale );
 715  
 
 716  3
             return doc;
 717  
         }
 718  
 
 719  1
         DocumentModel model = new DocumentModelBuilder( project, getDefaultDecorationModel() ).getDocumentModel();
 720  
 
 721  1
         model.getMeta().setGenerator( getDefaultGenerator() );
 722  1
         model.getMeta().setLanguage( locale.getLanguage() );
 723  1
         model.getCover().setCoverType( i18n.getString( "pdf-plugin", getDefaultLocale(), "toc.type" ) );
 724  1
         model.getToc().setName( i18n.getString( "pdf-plugin", getDefaultLocale(), "toc.title" ) );
 725  
 
 726  1
         appendGeneratedReports( model, locale );
 727  
 
 728  1
         debugLogGeneratedModel( model );
 729  
 
 730  1
         return model;
 731  
     }
 732  
 
 733  
     /**
 734  
      * Read a DocumentModel from a file.
 735  
      *
 736  
      * @param locale used to set the language.
 737  
      * @return the DocumentModel read from the configured document descriptor.
 738  
      * @throws org.apache.maven.plugin.MojoExecutionException if the model could not be read.
 739  
      */
 740  
     private DocumentModel getDocumentModelFromDescriptor( Locale locale )
 741  
         throws MojoExecutionException
 742  
     {
 743  
         DocumentModel model;
 744  
 
 745  
         try
 746  
         {
 747  3
             model =
 748  
                 new DocumentDescriptorReader( project, getLog() ).readAndFilterDocumentDescriptor( docDescriptor );
 749  
         }
 750  0
         catch ( XmlPullParserException ex )
 751  
         {
 752  0
             throw new MojoExecutionException( "Error reading DocumentDescriptor!", ex );
 753  
         }
 754  0
         catch ( IOException io )
 755  
         {
 756  0
             throw new MojoExecutionException( "Error opening DocumentDescriptor!", io );
 757  3
         }
 758  
 
 759  3
         if ( model.getMeta() == null )
 760  
         {
 761  0
             model.setMeta( new DocumentMeta() );
 762  
         }
 763  
 
 764  3
         if ( StringUtils.isEmpty( model.getMeta().getLanguage() ) )
 765  
         {
 766  0
             model.getMeta().setLanguage( locale.getLanguage() );
 767  
         }
 768  
 
 769  3
         if ( StringUtils.isEmpty( model.getMeta().getGenerator() ) )
 770  
         {
 771  3
             model.getMeta().setGenerator( getDefaultGenerator() );
 772  
         }
 773  
 
 774  3
         return model;
 775  
     }
 776  
 
 777  
     /**
 778  
      * Return the directory for a given Locale and the current default Locale.
 779  
      *
 780  
      * @param basedir the base directory
 781  
      * @param locale a Locale.
 782  
      * @return File.
 783  
      */
 784  
     private File getLocaleDirectory( File basedir, Locale locale )
 785  
     {
 786  8
         if ( locale.getLanguage().equals( getDefaultLocale().getLanguage() ) )
 787  
         {
 788  8
             return basedir;
 789  
         }
 790  
 
 791  0
         return new File( basedir, locale.getLanguage() );
 792  
     }
 793  
 
 794  
     /**
 795  
      * @return the default locale from <code>siteTool</code>.
 796  
      * @see #getAvailableLocales()
 797  
      */
 798  
     private Locale getDefaultLocale()
 799  
     {
 800  18
         if ( this.defaultLocale == null )
 801  
         {
 802  4
             this.defaultLocale = getAvailableLocales().get( 0 );
 803  
         }
 804  
 
 805  18
         return this.defaultLocale;
 806  
     }
 807  
 
 808  
     /**
 809  
      * @return the available locales from <code>siteTool</code>.
 810  
      * @see SiteTool#getAvailableLocales(String)
 811  
      */
 812  
     private List<Locale> getAvailableLocales()
 813  
     {
 814  8
         if ( this.localesList == null )
 815  
         {
 816  4
             this.localesList = siteTool.getAvailableLocales( locales );
 817  
         }
 818  
 
 819  8
         return this.localesList;
 820  
     }
 821  
 
 822  
     /**
 823  
      * @return the DecorationModel instance from <code>site.xml</code>
 824  
      * @throws MojoExecutionException if any
 825  
      */
 826  
     private DecorationModel getDefaultDecorationModel()
 827  
         throws MojoExecutionException
 828  
     {
 829  5
         if ( this.defaultDecorationModel == null )
 830  
         {
 831  4
             final Locale locale = getDefaultLocale();
 832  
 
 833  4
             final File basedir = project.getBasedir();
 834  4
             final String relativePath =
 835  
                 siteTool.getRelativePath( siteDirectory.getAbsolutePath(), basedir.getAbsolutePath() );
 836  
 
 837  4
             final File descriptorFile = siteTool.getSiteDescriptorFromBasedir( relativePath, basedir, locale );
 838  4
             DecorationModel decoration = null;
 839  
 
 840  4
             if ( descriptorFile.exists() )
 841  
             {
 842  4
                 XmlStreamReader reader = null;
 843  
                 try
 844  
                 {
 845  4
                     reader = new XmlStreamReader( descriptorFile );
 846  4
                     String enc = reader.getEncoding();
 847  
 
 848  4
                     String siteDescriptorContent = IOUtil.toString( reader );
 849  4
                     siteDescriptorContent =
 850  
                         siteTool.getInterpolatedSiteDescriptorContent( new HashMap<String, String>( 2 ), project,
 851  
                                                                        siteDescriptorContent, enc, enc );
 852  
 
 853  4
                     decoration = new DecorationXpp3Reader().read( new StringReader( siteDescriptorContent ) );
 854  
                 }
 855  0
                 catch ( XmlPullParserException e )
 856  
                 {
 857  0
                     throw new MojoExecutionException( "Error parsing site descriptor", e );
 858  
                 }
 859  0
                 catch ( IOException e )
 860  
                 {
 861  0
                     throw new MojoExecutionException( "Error reading site descriptor", e );
 862  
                 }
 863  0
                 catch ( SiteToolException e )
 864  
                 {
 865  0
                     throw new MojoExecutionException( "Error when interpoling site descriptor", e );
 866  
                 }
 867  
                 finally
 868  
                 {
 869  4
                     IOUtil.close( reader );
 870  4
                 }
 871  
             }
 872  
 
 873  4
             this.defaultDecorationModel = decoration;
 874  
         }
 875  
 
 876  5
         return this.defaultDecorationModel;
 877  
     }
 878  
 
 879  
     /**
 880  
      * Parse the decoration model to find the skin artifact and copy its resources to the output dir.
 881  
      *
 882  
      * @param locale not null
 883  
      * @throws MojoExecutionException if any
 884  
      * @see #getDefaultDecorationModel()
 885  
      */
 886  
     private void copyResources( Locale locale )
 887  
         throws MojoExecutionException
 888  
     {
 889  4
         final DecorationModel decorationModel = getDefaultDecorationModel();
 890  4
         if ( decorationModel == null )
 891  
         {
 892  0
             return;
 893  
         }
 894  
 
 895  
         File skinFile;
 896  
         try
 897  
         {
 898  4
             skinFile =
 899  
                 siteTool.getSkinArtifactFromRepository( localRepository, project.getRemoteArtifactRepositories(),
 900  
                                                         decorationModel ).getFile();
 901  
         }
 902  0
         catch ( SiteToolException e )
 903  
         {
 904  0
             throw new MojoExecutionException( "SiteToolException: " + e.getMessage(), e );
 905  4
         }
 906  
 
 907  4
         if ( skinFile == null )
 908  
         {
 909  0
             return;
 910  
         }
 911  
 
 912  4
         if ( getLog().isDebugEnabled() )
 913  
         {
 914  0
             getLog().debug( "Copy resources from skin artifact: '" + skinFile + "'..." );
 915  
         }
 916  
 
 917  
         try
 918  
         {
 919  4
             final SiteRenderingContext context =
 920  
                 siteRenderer.createContextForSkin( skinFile, new HashMap( 2 ), decorationModel, project.getName(),
 921  
                                                    locale );
 922  4
             context.addSiteDirectory( new File( siteDirectory, locale.getLanguage() ) );
 923  
 
 924  4
             for ( final File siteDirectoryFile : context.getSiteDirectories() )
 925  
             {
 926  4
                 siteRenderer.copyResources( context, new File( siteDirectoryFile, "resources" ), workingDirectory );
 927  4
             }
 928  
         }
 929  0
         catch ( IOException e )
 930  
         {
 931  0
             throw new MojoExecutionException( "IOException: " + e.getMessage(), e );
 932  4
         }
 933  4
     }
 934  
 
 935  
     /**
 936  
      * Construct a default producer.
 937  
      *
 938  
      * @return A String in the form <code>Maven PDF Plugin v. 1.1.1, 'fo' implementation</code>.
 939  
      */
 940  
     private String getDefaultGenerator()
 941  
     {
 942  4
         return "Maven PDF Plugin v. " + pluginVersion + ", '" + implementation + "' implementation.";
 943  
     }
 944  
 
 945  
     /**
 946  
      * Write the auto-generated model to disc.
 947  
      *
 948  
      * @param docModel the model to write.
 949  
      */
 950  
     private void debugLogGeneratedModel( final DocumentModel docModel )
 951  
     {
 952  1
         if ( getLog().isDebugEnabled() && project != null )
 953  
         {
 954  0
             final File outputDir = new File( project.getBuild().getDirectory(), "pdf" );
 955  
 
 956  0
             if ( !outputDir.exists() )
 957  
             {
 958  0
                 outputDir.mkdirs();
 959  
             }
 960  
 
 961  0
             final File doc = FileUtils.createTempFile( "pdf", ".xml", outputDir );
 962  0
             final DocumentXpp3Writer xpp3 = new DocumentXpp3Writer();
 963  
 
 964  0
             Writer w = null;
 965  
             try
 966  
             {
 967  0
                 w = WriterFactory.newXmlWriter( doc );
 968  0
                 xpp3.write( w, docModel );
 969  
 
 970  0
                 getLog().debug( "Generated a default document model: " + doc.getAbsolutePath() );
 971  
             }
 972  0
             catch ( IOException e )
 973  
             {
 974  0
                 getLog().error( "Failed to write document model: " + e.getMessage() );
 975  0
                 getLog().debug( e );
 976  
             }
 977  
             finally
 978  
             {
 979  0
                 IOUtil.close( w );
 980  0
             }
 981  
         }
 982  1
     }
 983  
 
 984  
     /**
 985  
      * Generate all Maven reports defined in <code>${project.reporting}</code> part
 986  
      * only if <code>generateReports</code> is enabled.
 987  
      *
 988  
      * @param locale not null
 989  
      * @throws MojoExecutionException if any
 990  
      * @throws IOException if any
 991  
      * @since 1.1
 992  
      */
 993  
     private void generateMavenReports( Locale locale )
 994  
         throws MojoExecutionException, IOException
 995  
     {
 996  4
         if ( !includeReports )
 997  
         {
 998  4
             getLog().info( "Skipped report generation." );
 999  4
             return;
 1000  
         }
 1001  
 
 1002  0
         if ( project.getReporting() == null )
 1003  
         {
 1004  0
             getLog().info( "No report was specified." );
 1005  0
             return;
 1006  
         }
 1007  
         
 1008  0
         for ( final ReportPlugin reportPlugin : project.getReporting().getPlugins() )
 1009  
         {
 1010  0
             final PluginDescriptor pluginDescriptor = getPluginDescriptor( reportPlugin );
 1011  
 
 1012  0
             if ( pluginDescriptor != null )
 1013  
             {
 1014  0
                 List<String> goals = new ArrayList<String>( 8 );
 1015  0
                 for ( final ReportSet reportSet : reportPlugin.getReportSets() )
 1016  
                 {
 1017  0
                     for ( String goal : reportSet.getReports() )
 1018  
                     {
 1019  0
                         goals.add( goal );
 1020  0
                     }
 1021  0
                 }
 1022  
     
 1023  0
                 List mojoDescriptors = pluginDescriptor.getMojos();
 1024  0
                 for ( Object mojoDescriptor1 : mojoDescriptors )
 1025  
                 {
 1026  0
                     final MojoDescriptor mojoDescriptor = (MojoDescriptor) mojoDescriptor1;
 1027  
 
 1028  0
                     if ( goals.isEmpty() || ( !goals.isEmpty() && goals.contains( mojoDescriptor.getGoal() ) ) )
 1029  
                     {
 1030  0
                         MavenReport report = getMavenReport( mojoDescriptor );
 1031  
 
 1032  0
                         generateMavenReport( report, mojoDescriptor.getPluginDescriptor().getPluginArtifact(),
 1033  
                                              locale );
 1034  
                     }
 1035  0
                 }
 1036  
             }
 1037  0
         }
 1038  
 
 1039  
         // generate project-info report
 1040  0
         if ( !getGeneratedMavenReports( locale ).isEmpty() )
 1041  
         {
 1042  0
             File outDir = new File( getGeneratedSiteDirectoryTmp(), "xdoc" );
 1043  0
             if ( !locale.getLanguage().equals( defaultLocale.getLanguage() ) )
 1044  
             {
 1045  0
                 outDir = new File( new File( getGeneratedSiteDirectoryTmp(), locale.getLanguage() ), "xdoc" );
 1046  
             }
 1047  0
             outDir.mkdirs();
 1048  
 
 1049  0
             File piReport = new File( outDir, "project-info.xml" );
 1050  
 
 1051  0
             StringWriter sw = new StringWriter();
 1052  
 
 1053  0
             PdfSink sink = new PdfSink( sw );
 1054  0
             ProjectInfoRenderer r = new ProjectInfoRenderer( sink, getGeneratedMavenReports( locale ), i18n, locale );
 1055  0
             r.render();
 1056  
 
 1057  0
             writeGeneratedReport( sw.toString(), piReport );
 1058  
         }
 1059  
 
 1060  
         // copy generated site
 1061  0
         copySiteDir( getGeneratedSiteDirectoryTmp(), getSiteDirectoryTmp() );
 1062  0
         copySiteDir( generatedSiteDirectory, getSiteDirectoryTmp() );
 1063  0
     }
 1064  
 
 1065  
     /**
 1066  
      * TODO olamy : remove when maven 3 will be the de facto standard :-)
 1067  
      * @param reportPlugin not null
 1068  
      * @return the PluginDescriptor instance for the given reportPlugin.
 1069  
      * @throws MojoExecutionException if any
 1070  
      * @since 1.1
 1071  
      */
 1072  
     private PluginDescriptor getPluginDescriptor( ReportPlugin reportPlugin )
 1073  
         throws MojoExecutionException
 1074  
     {
 1075  
         try
 1076  
         {
 1077  0
             return pluginManager.verifyReportPlugin( reportPlugin, project, session );
 1078  
         }
 1079  0
         catch ( ArtifactResolutionException e )
 1080  
         {
 1081  0
             throw new MojoExecutionException( "ArtifactResolutionException: " + e.getMessage(), e );
 1082  
         }
 1083  0
         catch ( ArtifactNotFoundException e )
 1084  
         {
 1085  0
             throw new MojoExecutionException( "ArtifactNotFoundException: " + e.getMessage(), e );
 1086  
         }
 1087  0
         catch ( PluginNotFoundException e )
 1088  
         {
 1089  0
             throw new MojoExecutionException( "PluginNotFoundException: " + e.getMessage(), e );
 1090  
         }
 1091  0
         catch ( PluginVersionResolutionException e )
 1092  
         {
 1093  0
             throw new MojoExecutionException( "PluginVersionResolutionException: " + e.getMessage(), e );
 1094  
         }
 1095  0
         catch ( InvalidVersionSpecificationException e )
 1096  
         {
 1097  0
             throw new MojoExecutionException( "InvalidVersionSpecificationException: " + e.getMessage(), e );
 1098  
         }
 1099  0
         catch ( InvalidPluginException e )
 1100  
         {
 1101  0
             throw new MojoExecutionException( "InvalidPluginException: " + e.getMessage(), e );
 1102  
         }
 1103  0
         catch ( PluginManagerException e )
 1104  
         {
 1105  0
             throw new MojoExecutionException( "PluginManagerException: " + e.getMessage(), e );
 1106  
         }
 1107  0
         catch ( PluginVersionNotFoundException e )
 1108  
         {
 1109  0
             throw new MojoExecutionException( "PluginVersionNotFoundException: " + e.getMessage(), e );
 1110  
         }
 1111  0
         catch ( NoSuchMethodError e )
 1112  
         {
 1113  0
             getLog().info( "Ignoring api call removed in maven 3, no reports are generated!" );
 1114  0
             getLog().debug( e );
 1115  0
             return null;
 1116  
         }
 1117  
     }
 1118  
 
 1119  
     /**
 1120  
      * @param mojoDescriptor not null
 1121  
      * @return the MavenReport instance for the given mojoDescriptor.
 1122  
      * @throws MojoExecutionException if any
 1123  
      * @since 1.1
 1124  
      */
 1125  
     private MavenReport getMavenReport( MojoDescriptor mojoDescriptor )
 1126  
         throws MojoExecutionException
 1127  
     {
 1128  0
         ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
 1129  
         try
 1130  
         {
 1131  0
             Thread.currentThread()
 1132  
                   .setContextClassLoader( mojoDescriptor.getPluginDescriptor().getClassRealm().getClassLoader() );
 1133  
 
 1134  0
             MojoExecution mojoExecution = new MojoExecution( mojoDescriptor );
 1135  
 
 1136  0
             return pluginManager.getReport( project, mojoExecution, session );
 1137  
         }
 1138  0
         catch ( ArtifactNotFoundException e )
 1139  
         {
 1140  0
             throw new MojoExecutionException( "ArtifactNotFoundException: " + e.getMessage(), e );
 1141  
         }
 1142  0
         catch ( ArtifactResolutionException e )
 1143  
         {
 1144  0
             throw new MojoExecutionException( "ArtifactResolutionException: " + e.getMessage(), e );
 1145  
         }
 1146  0
         catch ( PluginConfigurationException e )
 1147  
         {
 1148  0
             throw new MojoExecutionException( "PluginConfigurationException: " + e.getMessage(), e );
 1149  
         }
 1150  0
         catch ( PluginManagerException e )
 1151  
         {
 1152  0
             throw new MojoExecutionException( "PluginManagerException: " + e.getMessage(), e );
 1153  
         }
 1154  
         finally
 1155  
         {
 1156  0
             Thread.currentThread().setContextClassLoader( oldClassLoader );
 1157  
         }
 1158  
     }
 1159  
 
 1160  
     /**
 1161  
      * Generate the given Maven report only if it is not an external report and the report could be generated.
 1162  
      *
 1163  
      * @param mojoDescriptor not null, to catch linkage error
 1164  
      * @param report could be null
 1165  
      * @param locale not null
 1166  
      * @throws IOException if any
 1167  
      * @throws MojoExecutionException if any
 1168  
      * @see #isValidGeneratedReport(MojoDescriptor, File, String)
 1169  
      * @since 1.1
 1170  
      */
 1171  
     private void generateMavenReport( MavenReport report, Artifact pluginArtifact, Locale locale )
 1172  
         throws IOException, MojoExecutionException
 1173  
     {
 1174  0
         if ( report == null )
 1175  
         {
 1176  0
             return;
 1177  
         }
 1178  
 
 1179  0
         String localReportName = report.getName( locale );
 1180  0
         if ( !report.canGenerateReport() )
 1181  
         {
 1182  0
             getLog().info( "Skipped \"" + localReportName + "\" report." );
 1183  0
             getLog().debug( "canGenerateReport() was false." );
 1184  
 
 1185  0
             return;
 1186  
         }
 1187  
 
 1188  0
         if ( report.isExternalReport() )
 1189  
         {
 1190  0
             getLog().info( "Skipped external \"" + localReportName + "\" report." );
 1191  0
             getLog().debug( "isExternalReport() was false." );
 1192  
 
 1193  0
             return;
 1194  
         }
 1195  
 
 1196  0
         for ( final MavenReport generatedReport : getGeneratedMavenReports( locale ) )
 1197  
         {
 1198  0
             if ( report.getName( locale ).equals( generatedReport.getName( locale ) ) )
 1199  
             {
 1200  0
                 if ( getLog().isDebugEnabled() )
 1201  
                 {
 1202  0
                     getLog().debug( report.getName( locale ) + " was already generated." );
 1203  
                 }
 1204  0
                 return;
 1205  
             }
 1206  0
         }
 1207  
 
 1208  0
         File outDir = new File( getGeneratedSiteDirectoryTmp(), "xdoc" );
 1209  0
         if ( !locale.getLanguage().equals( defaultLocale.getLanguage() ) )
 1210  
         {
 1211  0
             outDir = new File( new File( getGeneratedSiteDirectoryTmp(), locale.getLanguage() ), "xdoc" );
 1212  
         }
 1213  0
         outDir.mkdirs();
 1214  
 
 1215  0
         File generatedReport = new File( outDir, report.getOutputName() + ".xml" );
 1216  
 
 1217  0
         String excludes = getDefaultExcludesWithLocales( getAvailableLocales(), getDefaultLocale() );
 1218  0
         List<String> files =
 1219  
             FileUtils.getFileNames( siteDirectory, "*/" + report.getOutputName() + ".*", excludes, false );
 1220  0
         if ( !locale.getLanguage().equals( defaultLocale.getLanguage() ) )
 1221  
         {
 1222  0
             files =
 1223  
                 FileUtils.getFileNames( new File( siteDirectory, locale.getLanguage() ), "*/"
 1224  
                     + report.getOutputName() + ".*", excludes, false );
 1225  
         }
 1226  
 
 1227  0
         if ( files.size() != 0 )
 1228  
         {
 1229  0
             String displayLanguage = locale.getDisplayLanguage( Locale.ENGLISH );
 1230  
 
 1231  0
             if ( getLog().isInfoEnabled() )
 1232  
             {
 1233  0
                 getLog().info(
 1234  
                                "Skipped \"" + report.getName( locale ) + "\" report, file \""
 1235  
                                    + report.getOutputName() + "\" already exists for the " + displayLanguage
 1236  
                                    + " version." );
 1237  
             }
 1238  
 
 1239  0
             return;
 1240  
         }
 1241  
 
 1242  0
         if ( getLog().isInfoEnabled() )
 1243  
         {
 1244  0
             getLog().info( "Generating \"" + localReportName + "\" report." );
 1245  
         }
 1246  
 
 1247  0
         StringWriter sw = new StringWriter();
 1248  
 
 1249  0
         PdfSink sink = null;
 1250  
         try
 1251  
         {
 1252  0
             sink = new PdfSink( sw );
 1253  0
             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  0
             report.generate( proxy, locale );
 1257  
         }
 1258  0
         catch ( MavenReportException e )
 1259  
         {
 1260  0
             throw new MojoExecutionException( "MavenReportException: " + e.getMessage(), e );
 1261  
         }
 1262  
         finally
 1263  
         {
 1264  0
             if ( sink != null )
 1265  
             {
 1266  0
                 sink.close();
 1267  
             }
 1268  
         }
 1269  
 
 1270  0
         writeGeneratedReport( sw.toString(), generatedReport );
 1271  
 
 1272  0
         if ( isValidGeneratedReport( pluginArtifact, generatedReport, localReportName ) )
 1273  
         {
 1274  0
             getGeneratedMavenReports( locale ).add( report );
 1275  
         }
 1276  0
     }
 1277  
 
 1278  
     /**
 1279  
      * @param locale not null
 1280  
      * @return the generated reports
 1281  
      * @see #generateMavenReport(MojoDescriptor, MavenReport, Locale)
 1282  
      * @see #isValidGeneratedReport(MojoDescriptor, File, String)
 1283  
      * @since 1.1
 1284  
      */
 1285  
     private List<MavenReport> getGeneratedMavenReports( Locale locale )
 1286  
     {
 1287  0
         if ( this.generatedMavenReports == null )
 1288  
         {
 1289  0
             this.generatedMavenReports = new HashMap<Locale, List<MavenReport>>( 2 );
 1290  
         }
 1291  
 
 1292  0
         if ( this.generatedMavenReports.get( locale ) == null )
 1293  
         {
 1294  0
             this.generatedMavenReports.put( locale, new ArrayList<MavenReport>( 2 ) );
 1295  
         }
 1296  
 
 1297  0
         return this.generatedMavenReports.get( locale );
 1298  
     }
 1299  
 
 1300  
     /**
 1301  
      * Append generated reports to the toc only if <code>generateReports</code> is enabled, for instance:
 1302  
      * <pre>
 1303  
      * &lt;item name="Project Reports" ref="/project-info"&gt;
 1304  
      * &nbsp;&nbsp;&lt;item name="Project License" ref="/license" /&gt;
 1305  
      * &nbsp;&nbsp;&lt;item name="Project Team" ref="/team-list" /&gt;
 1306  
      * &nbsp;&nbsp;&lt;item name="Continuous Integration" ref="/integration" /&gt;
 1307  
      * &nbsp;&nbsp;...
 1308  
      * &lt;/item&gt;
 1309  
      * </pre>
 1310  
      *
 1311  
      * @param model not null
 1312  
      * @param locale not null
 1313  
      * @see #generateMavenReports(Locale)
 1314  
      * @since 1.1
 1315  
      */
 1316  
     private void appendGeneratedReports( DocumentModel model, Locale locale )
 1317  
     {
 1318  4
         if ( !includeReports )
 1319  
         {
 1320  4
             return;
 1321  
         }
 1322  0
         if ( getGeneratedMavenReports( locale ).isEmpty() )
 1323  
         {
 1324  0
             return;
 1325  
         }
 1326  
 
 1327  0
         final DocumentTOCItem documentTOCItem = new DocumentTOCItem();
 1328  0
         documentTOCItem.setName( i18n.getString( "pdf-plugin", locale, "toc.project-info.item" ) );
 1329  0
         documentTOCItem.setRef( "/project-info" ); // see #generateMavenReports(Locale)
 1330  
 
 1331  0
         List<String> addedRef = new ArrayList<String>( 4 );
 1332  
 
 1333  0
         List<DocumentTOCItem> items = new ArrayList<DocumentTOCItem>( 4 );
 1334  
 
 1335  
         // append generated report defined as MavenReport
 1336  0
         for ( final MavenReport report : getGeneratedMavenReports( locale ) )
 1337  
         {
 1338  0
             final DocumentTOCItem reportItem = new DocumentTOCItem();
 1339  0
             reportItem.setName( report.getName( locale ) );
 1340  0
             reportItem.setRef( "/" + report.getOutputName() );
 1341  
 
 1342  0
             items.add( reportItem );
 1343  
 
 1344  0
             addedRef.add( report.getOutputName() );
 1345  0
         }
 1346  
 
 1347  
         // append all generated reports from generated-site
 1348  
         try
 1349  
         {
 1350  0
             if ( generatedSiteDirectory.exists() )
 1351  
             {
 1352  0
                 String excludes = getDefaultExcludesWithLocales( getAvailableLocales(), getDefaultLocale() );
 1353  0
                 List<String> generatedDirs = FileUtils.getDirectoryNames( generatedSiteDirectory, "*", excludes,
 1354  
                                                                           true );
 1355  0
                 if ( !locale.getLanguage().equals( getDefaultLocale().getLanguage() ) )
 1356  
                 {
 1357  0
                     generatedDirs =
 1358  
                         FileUtils.getFileNames( new File( generatedSiteDirectory, locale.getLanguage() ), "*",
 1359  
                                                 excludes, true );
 1360  
                 }
 1361  
 
 1362  0
                 for ( final String generatedDir : generatedDirs )
 1363  
                 {
 1364  0
                     List<String> generatedFiles =
 1365  
                         FileUtils.getFileNames( new File( generatedDir ), "**.*", excludes, false );
 1366  
 
 1367  0
                     for ( final String generatedFile : generatedFiles )
 1368  
                     {
 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( Artifact pluginArtifact, 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( pluginArtifact.getGroupId() );
 1475  0
             sb.append( ":" );
 1476  0
             sb.append( pluginArtifact.getArtifactId() );
 1477  0
             sb.append( ":" );
 1478  0
             sb.append( pluginArtifact.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( pluginArtifact );
 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 ( Object o : pluginProject.getMailingLists() )
 1496  
                     {
 1497  0
                         MailingList mailingList = (MailingList) o;
 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( Artifact pluginArtifact )
 1564  
     {
 1565  
         try
 1566  
         {
 1567  0
             return mavenProjectBuilder.buildFromRepository( pluginArtifact, remoteRepositories, localRepository );
 1568  
         }
 1569  0
         catch ( ProjectBuildingException e )
 1570  
         {
 1571  0
             getLog().error( "ProjectBuildingException: " + e.getMessage() );
 1572  0
             getLog().debug( e );
 1573  
         }
 1574  
 
 1575  0
         return null;
 1576  
     }
 1577  
     
 1578  
     protected List<MavenReportExecution> getReports()
 1579  
         throws MojoExecutionException
 1580  
     {
 1581  0
         if ( isMaven3OrMore() )
 1582  
         {
 1583  0
             MavenReportExecutorRequest mavenReportExecutorRequest = new MavenReportExecutorRequest();
 1584  0
             mavenReportExecutorRequest.setLocalRepository( localRepository );
 1585  0
             mavenReportExecutorRequest.setMavenSession( session );
 1586  0
             mavenReportExecutorRequest.setProject( project );
 1587  0
             mavenReportExecutorRequest.setReportPlugins( reportPlugins );
 1588  
 
 1589  
             MavenReportExecutor mavenReportExecutor;
 1590  
             try
 1591  
             {
 1592  0
                 mavenReportExecutor = (MavenReportExecutor) container.lookup( MavenReportExecutor.class.getName() );
 1593  
             }
 1594  0
             catch ( ComponentLookupException e )
 1595  
             {
 1596  0
                 throw new MojoExecutionException( "could not get MavenReportExecutor component", e );
 1597  0
             }
 1598  0
             return mavenReportExecutor.buildMavenReports( mavenReportExecutorRequest );
 1599  
         }
 1600  
 
 1601  0
         List<MavenReportExecution> reportExecutions = new ArrayList<MavenReportExecution>( reports.length );
 1602  0
         for ( MavenReport report : reports )
 1603  
         {
 1604  0
             if ( report.canGenerateReport() )
 1605  
             {
 1606  0
                 reportExecutions.add( new MavenReportExecution( report ) );
 1607  
             }
 1608  
         }
 1609  0
         return reportExecutions;
 1610  
     }
 1611  
     
 1612  
     /**
 1613  
      * Check the current Maven version to see if it's Maven 3.0 or newer.
 1614  
      */
 1615  
     protected static boolean isMaven3OrMore()
 1616  
     {
 1617  
         try
 1618  
         {
 1619  0
             ArtifactVersion mavenVersion = new DefaultArtifactVersion( getMavenVersion() );
 1620  0
             return VersionRange.createFromVersionSpec( "[3.0,)" ).containsVersion( mavenVersion );
 1621  
         }
 1622  0
         catch ( InvalidVersionSpecificationException e )
 1623  
         {
 1624  0
             return false;
 1625  
         }
 1626  
 //        return new ComparableVersion( getMavenVersion() ).compareTo( new ComparableVersion( "3.0" ) ) >= 0;
 1627  
     }
 1628  
 
 1629  
     protected static String getMavenVersion()
 1630  
     {
 1631  
         // This relies on the fact that MavenProject is the in core classloader
 1632  
         // and that the core classloader is for the maven-core artifact
 1633  
         // and that should have a pom.properties file
 1634  
         // if this ever changes, we will have to revisit this code.
 1635  0
         final Properties properties = new Properties();
 1636  0
         final InputStream in =
 1637  
             MavenProject.class.getClassLoader().getResourceAsStream( "META-INF/maven/org.apache.maven/maven-core/"
 1638  
                                                                          + "pom.properties" );
 1639  
         try
 1640  
         {
 1641  0
             properties.load( in );
 1642  
         }
 1643  0
         catch ( IOException ioe )
 1644  
         {
 1645  0
             return "";
 1646  
         }
 1647  
         finally
 1648  
         {
 1649  0
             IOUtil.close( in );
 1650  0
         }
 1651  
 
 1652  0
         return properties.getProperty( "version" ).trim();
 1653  
     }
 1654  
 
 1655  
     // ----------------------------------------------------------------------
 1656  
     // static methods
 1657  
     // ----------------------------------------------------------------------
 1658  
 
 1659  
     /**
 1660  
      * Write the given content to the given file.
 1661  
      * <br/>
 1662  
      * <b>Note</b>: try also to fix the content due to some issues in
 1663  
      * {@link org.apache.maven.reporting.AbstractMavenReport}.
 1664  
      *
 1665  
      * @param content the given content
 1666  
      * @param toFile the report file
 1667  
      * @throws IOException if any
 1668  
      * @since 1.1
 1669  
      */
 1670  
     private static void writeGeneratedReport( String content, File toFile )
 1671  
         throws IOException
 1672  
     {
 1673  0
         if ( StringUtils.isEmpty( content ) )
 1674  
         {
 1675  0
             return;
 1676  
         }
 1677  
 
 1678  0
         Writer writer = null;
 1679  
         try
 1680  
         {
 1681  0
             writer = WriterFactory.newXmlWriter( toFile );
 1682  
             // see PdfSink#table()
 1683  0
             writer.write( StringUtils.replace( content, "<table><table", "<table" ) );
 1684  
         }
 1685  
         finally
 1686  
         {
 1687  0
             IOUtil.close( writer );
 1688  0
         }
 1689  0
     }
 1690  
 
 1691  
     /**
 1692  
      * @param locales the list of locales dir to exclude
 1693  
      * @param defaultLocale the default locale.
 1694  
      * @return the comma separated list of default excludes and locales dir.
 1695  
      * @see FileUtils#getDefaultExcludesAsString()
 1696  
      * @since 1.1
 1697  
      */
 1698  
     private static String getDefaultExcludesWithLocales( List<Locale> locales, Locale defaultLocale )
 1699  
     {
 1700  0
         String excludesLocales = FileUtils.getDefaultExcludesAsString();
 1701  0
         for ( final Locale locale : locales )
 1702  
         {
 1703  0
             if ( !locale.getLanguage().equals( defaultLocale.getLanguage() ) )
 1704  
             {
 1705  0
                 excludesLocales = excludesLocales + ",**/" + locale.getLanguage() + "/*";
 1706  
             }
 1707  0
         }
 1708  
 
 1709  0
         return excludesLocales;
 1710  
     }
 1711  
 
 1712  
     // ----------------------------------------------------------------------
 1713  
     // Inner class
 1714  
     // ----------------------------------------------------------------------
 1715  
 
 1716  
     /**
 1717  
      * A sink to generate a Maven report as xdoc with some known workarounds.
 1718  
      *
 1719  
      * @since 1.1
 1720  
      */
 1721  
     private static class PdfSink
 1722  
         extends XdocSink
 1723  
     {
 1724  
         protected PdfSink( Writer writer )
 1725  
         {
 1726  0
             super( writer );
 1727  0
         }
 1728  
 
 1729  
         /** {@inheritDoc} */
 1730  
         public void text( String text )
 1731  
         {
 1732  
             // workaround to fix quotes introduced with MPIR-59 (then removed in MPIR-136)
 1733  0
             super.text( StringUtils.replace( text, "\u0092", "'" ) );
 1734  0
         }
 1735  
     }
 1736  
 
 1737  
     /**
 1738  
      * Renderer Maven report similar to org.apache.maven.plugins.site.CategorySummaryDocumentRenderer
 1739  
      *
 1740  
      * @since 1.1
 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  0
             super( sink );
 1754  
 
 1755  0
             this.generatedReports = generatedReports;
 1756  0
             this.i18n = i18n;
 1757  0
             this.locale = locale;
 1758  0
         }
 1759  
 
 1760  
         /** {@inheritDoc} */
 1761  
         public String getTitle()
 1762  
         {
 1763  0
             return i18n.getString( "pdf-plugin", locale, "report.project-info.title" );
 1764  
         }
 1765  
 
 1766  
         /** {@inheritDoc} */
 1767  
         public void renderBody()
 1768  
         {
 1769  0
             sink.section1();
 1770  0
             sink.sectionTitle1();
 1771  0
             sink.text( i18n.getString( "pdf-plugin", locale, "report.project-info.title" ) );
 1772  0
             sink.sectionTitle1_();
 1773  
 
 1774  0
             sink.paragraph();
 1775  0
             sink.text( i18n.getString( "pdf-plugin", locale, "report.project-info.description1" ) + " " );
 1776  0
             sink.link( "http://maven.apache.org" );
 1777  0
             sink.text( "Maven" );
 1778  0
             sink.link_();
 1779  0
             sink.text( " " + i18n.getString( "pdf-plugin", locale, "report.project-info.description2" ) );
 1780  0
             sink.paragraph_();
 1781  
 
 1782  0
             sink.section2();
 1783  0
             sink.sectionTitle2();
 1784  0
             sink.text( i18n.getString( "pdf-plugin", locale, "report.project-info.sectionTitle" ) );
 1785  0
             sink.sectionTitle2_();
 1786  
 
 1787  0
             sink.table();
 1788  
 
 1789  0
             sink.tableRows( new int[] { Sink.JUSTIFY_LEFT, Sink.JUSTIFY_LEFT }, false );
 1790  
 
 1791  0
             String name = i18n.getString( "pdf-plugin", locale, "report.project-info.column.document" );
 1792  0
             String description = i18n.getString( "pdf-plugin", locale, "report.project-info.column.description" );
 1793  
 
 1794  0
             sink.tableRow();
 1795  
 
 1796  0
             sink.tableHeaderCell( SinkEventAttributeSet.CENTER );
 1797  
 
 1798  0
             sink.text( name );
 1799  
 
 1800  0
             sink.tableHeaderCell_();
 1801  
 
 1802  0
             sink.tableHeaderCell( SinkEventAttributeSet.CENTER );
 1803  
 
 1804  0
             sink.text( description );
 1805  
 
 1806  0
             sink.tableHeaderCell_();
 1807  
 
 1808  0
             sink.tableRow_();
 1809  
 
 1810  0
             if ( generatedReports != null )
 1811  
             {
 1812  0
                 for ( final MavenReport report : generatedReports )
 1813  
                 {
 1814  0
                     sink.tableRow();
 1815  0
                     sink.tableCell();
 1816  0
                     sink.link( report.getOutputName() + ".html" );
 1817  0
                     sink.text( report.getName( locale ) );
 1818  0
                     sink.link_();
 1819  0
                     sink.tableCell_();
 1820  0
                     sink.tableCell();
 1821  0
                     sink.text( report.getDescription( locale ) );
 1822  0
                     sink.tableCell_();
 1823  0
                     sink.tableRow_();
 1824  0
                 }
 1825  
             }
 1826  
 
 1827  0
             sink.tableRows_();
 1828  
 
 1829  0
             sink.table_();
 1830  
 
 1831  0
             sink.section2_();
 1832  
 
 1833  0
             sink.section1_();
 1834  0
         }
 1835  
     }
 1836  
 
 1837  
     /**
 1838  
      * Delegates the method invocations on <code>org.codehaus.doxia.sink.Sink@maven-core-realm</code> to
 1839  
      * <code>org.apache.maven.doxia.sink.Sink@pdf-plugin-realm</code>.
 1840  
      *
 1841  
      * @author Benjamin Bentmann
 1842  
      */
 1843  4
     private static class SinkDelegate
 1844  
         implements InvocationHandler
 1845  
     {
 1846  
         private final Sink sink;
 1847  
 
 1848  
         SinkDelegate( Sink sink )
 1849  0
         {
 1850  0
             this.sink = sink;
 1851  0
         }
 1852  
 
 1853  
         /** {@inheritDoc} */
 1854  
         public Object invoke( Object proxy, Method method, Object[] args )
 1855  
             throws Throwable
 1856  
         {
 1857  0
             Class<?>[] parameterTypes = method.getParameterTypes();
 1858  
 
 1859  0
             for ( int i = parameterTypes.length - 1; i >= 0; i-- )
 1860  
             {
 1861  0
                 if ( AttributeSet.class.isAssignableFrom( parameterTypes[i] ) )
 1862  
                 {
 1863  0
                     parameterTypes[i] = SinkEventAttributes.class;
 1864  
                 }
 1865  
             }
 1866  
 
 1867  0
             if ( args != null )
 1868  
             {
 1869  0
                 for ( int i = args.length - 1; i >= 0; i-- )
 1870  
                 {
 1871  0
                     if ( AttributeSet.class.isInstance( args[i] ) )
 1872  
                     {
 1873  0
                         args[i] = new SinkEventAttributeSet( (AttributeSet) args[i] );
 1874  
                     }
 1875  
                 }
 1876  
             }
 1877  
 
 1878  0
             Method target = Sink.class.getMethod( method.getName(), parameterTypes );
 1879  
 
 1880  0
             return target.invoke( sink, args );
 1881  
         }
 1882  
     }
 1883  
 }