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