Coverage Report - org.apache.maven.plugins.pdf.PdfMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
PdfMojo
61%
73/119
55%
23/42
5.889
 
 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.StringReader;
 25  
 import java.io.Writer;
 26  
 import java.util.HashMap;
 27  
 import java.util.Iterator;
 28  
 import java.util.List;
 29  
 import java.util.Locale;
 30  
 
 31  
 import org.apache.maven.artifact.repository.ArtifactRepository;
 32  
 import org.apache.maven.doxia.docrenderer.DocumentRenderer;
 33  
 import org.apache.maven.doxia.docrenderer.DocumentRendererException;
 34  
 import org.apache.maven.doxia.docrenderer.pdf.PdfRenderer;
 35  
 import org.apache.maven.doxia.document.DocumentModel;
 36  
 import org.apache.maven.doxia.document.io.xpp3.DocumentXpp3Writer;
 37  
 import org.apache.maven.doxia.site.decoration.DecorationModel;
 38  
 import org.apache.maven.doxia.site.decoration.io.xpp3.DecorationXpp3Reader;
 39  
 import org.apache.maven.doxia.siterenderer.Renderer;
 40  
 import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
 41  
 import org.apache.maven.doxia.tools.SiteTool;
 42  
 import org.apache.maven.doxia.tools.SiteToolException;
 43  
 
 44  
 import org.apache.maven.plugin.AbstractMojo;
 45  
 import org.apache.maven.plugin.MojoExecutionException;
 46  
 import org.apache.maven.plugin.MojoFailureException;
 47  
 import org.apache.maven.project.MavenProject;
 48  
 
 49  
 import org.codehaus.plexus.i18n.I18N;
 50  
 import org.codehaus.plexus.util.FileUtils;
 51  
 import org.codehaus.plexus.util.IOUtil;
 52  
 import org.codehaus.plexus.util.ReaderFactory;
 53  
 import org.codehaus.plexus.util.StringUtils;
 54  
 import org.codehaus.plexus.util.WriterFactory;
 55  
 import org.codehaus.plexus.util.xml.XmlStreamReader;
 56  
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 57  
 
 58  
 /**
 59  
  * Generates a PDF document for a project.
 60  
  *
 61  
  * @author ltheussl
 62  
  * @version $Id: PdfMojo.java 787639 2009-06-23 11:35:05Z ltheussl $
 63  
  * @goal pdf
 64  
  */
 65  4
 public class PdfMojo
 66  
     extends AbstractMojo
 67  
 {
 68  
     // ----------------------------------------------------------------------
 69  
     // Mojo components
 70  
     // ----------------------------------------------------------------------
 71  
 
 72  
     /**
 73  
      * FO Document Renderer.
 74  
      *
 75  
      * @component role-hint="fo"
 76  
      */
 77  
     private PdfRenderer foRenderer;
 78  
 
 79  
     /**
 80  
      * Internationalization.
 81  
      *
 82  
      * @component
 83  
      */
 84  
     private I18N i18n;
 85  
 
 86  
     /**
 87  
      * IText Document Renderer.
 88  
      *
 89  
      * @component role-hint="itext"
 90  
      */
 91  
     private PdfRenderer itextRenderer;
 92  
 
 93  
     /**
 94  
      * A comma separated list of locales supported by Maven.
 95  
      * The first valid token will be the default Locale for this instance of the Java Virtual Machine.
 96  
      *
 97  
      * @parameter expression="${locales}"
 98  
      */
 99  
     private String locales;
 100  
 
 101  
     /**
 102  
      * Site renderer.
 103  
      *
 104  
      * @component
 105  
      */
 106  
     private Renderer siteRenderer;
 107  
 
 108  
     /**
 109  
      * SiteTool.
 110  
      *
 111  
      * @component
 112  
      */
 113  
     private SiteTool siteTool;
 114  
 
 115  
     // ----------------------------------------------------------------------
 116  
     // Mojo Parameters
 117  
     // ----------------------------------------------------------------------
 118  
 
 119  
     /**
 120  
      * The Maven Project Object.
 121  
      *
 122  
      * @parameter expression="${project}"
 123  
      * @required
 124  
      * @readonly
 125  
      */
 126  
     private MavenProject project;
 127  
 
 128  
     /**
 129  
      * Directory containing source for apt, fml and xdoc docs.
 130  
      *
 131  
      * @parameter default-value="${basedir}/src/site"
 132  
      * @required
 133  
      */
 134  
     private File siteDirectory;
 135  
 
 136  
     /**
 137  
      * Output directory where PDF files should be created.
 138  
      *
 139  
      * @parameter default-value="${project.build.directory}/pdf"
 140  
      * @required
 141  
      */
 142  
     private File outputDirectory;
 143  
 
 144  
     /**
 145  
      * Working directory for working files like temp files/resources.
 146  
      *
 147  
      * @parameter default-value="${project.build.directory}/pdf"
 148  
      * @required
 149  
      */
 150  
     private File workingDirectory;
 151  
 
 152  
     /**
 153  
      * File that contains the DocumentModel of the PDF to generate.
 154  
      *
 155  
      * @parameter default-value="src/site/pdf.xml"
 156  
      */
 157  
     private File docDescriptor;
 158  
 
 159  
     /**
 160  
      * Identifies the framework to use for pdf generation: either "fo" (default) or "itext".
 161  
      *
 162  
      * @parameter expression="${implementation}" default-value="fo"
 163  
      * @required
 164  
      */
 165  
     private String implementation;
 166  
 
 167  
     /**
 168  
      * The local repository.
 169  
      *
 170  
      * @parameter expression="${localRepository}"
 171  
      * @required
 172  
      */
 173  
     private ArtifactRepository localRepository;
 174  
 
 175  
     /**
 176  
      * If <code>true</false>, aggregate all source documents in one pdf, otherwise generate one pdf for each
 177  
      * source document.
 178  
      *
 179  
      * @parameter default-value="true"
 180  
      */
 181  
     private boolean aggregate;
 182  
 
 183  
     /**
 184  
      * Document Renderer.
 185  
      */
 186  
     private DocumentRenderer docRenderer;
 187  
 
 188  
     /**
 189  
      * Default locale
 190  
      */
 191  
     private Locale defaultLocale;
 192  
 
 193  
     /**
 194  
      * Default decoration model
 195  
      */
 196  
     private DecorationModel defaultDecorationModel;
 197  
 
 198  
     /**
 199  
      * @parameter expression="${plugin.version}"
 200  
      */
 201  
     private String pluginVersion;
 202  
 
 203  
     // ----------------------------------------------------------------------
 204  
     // Public methods
 205  
     // ----------------------------------------------------------------------
 206  
 
 207  
     /**
 208  
      * {@inheritDoc}
 209  
      *
 210  
      * @throws MojoExecutionException if an exception ocurred during mojo execution.
 211  
      * @throws MojoFailureException if the mojo could not be executed.
 212  
      */
 213  
     public void execute()
 214  
         throws MojoExecutionException, MojoFailureException
 215  
     {
 216  4
         if ( "fo".equals( implementation ) )
 217  
         {
 218  3
             this.docRenderer = foRenderer;
 219  
         }
 220  1
         else if ( "itext".equals( implementation ) )
 221  
         {
 222  1
             this.docRenderer = itextRenderer;
 223  
         }
 224  
         else
 225  
         {
 226  0
             throw new MojoFailureException( "Not a valid implementation: " + implementation );
 227  
         }
 228  
 
 229  
         try
 230  
         {
 231  4
             final List localesList = siteTool.getAvailableLocales( locales );
 232  
 
 233  
             // Default is first in the list
 234  4
             this.defaultLocale = (Locale) localesList.get( 0 );
 235  4
             Locale.setDefault( defaultLocale );
 236  
 
 237  4
             for ( final Iterator iterator = localesList.iterator(); iterator.hasNext(); )
 238  
             {
 239  4
                 final Locale locale = (Locale) iterator.next();
 240  
 
 241  4
                 final File workingDir = getWorkingDirectory( locale );
 242  
 
 243  4
                 File siteDirectoryFile = siteDirectory;
 244  4
                 if ( !locale.getLanguage().equals( defaultLocale.getLanguage() ) )
 245  
                 {
 246  0
                     siteDirectoryFile = new File( siteDirectory, locale.getLanguage() );
 247  
                 }
 248  
 
 249  
                 // Copy extra-resources
 250  4
                 copyResources( locale );
 251  
 
 252  
                 try
 253  
                 {
 254  4
                     if ( aggregate )
 255  
                     {
 256  4
                         docRenderer.render( siteDirectoryFile, workingDir, getDocumentModel( locale ) );
 257  
                     }
 258  
                     else
 259  
                     {
 260  0
                         docRenderer.render( siteDirectoryFile, workingDir, null );
 261  
                     }
 262  
                 }
 263  0
                 catch ( DocumentRendererException e )
 264  
                 {
 265  0
                     throw new MojoExecutionException( "Error during document generation", e );
 266  8
                 }
 267  
             }
 268  
 
 269  4
             if ( !outputDirectory.getCanonicalPath().equals( workingDirectory.getCanonicalPath() ) )
 270  
             {
 271  0
                 final List pdfs = FileUtils.getFiles( workingDirectory, "**/*.pdf", null );
 272  
 
 273  0
                 for ( final Iterator it = pdfs.iterator(); it.hasNext(); )
 274  
                 {
 275  0
                     final File pdf = (File) it.next();
 276  
 
 277  0
                     FileUtils.copyFile( pdf, new File( outputDirectory, pdf.getName() ) );
 278  0
                     pdf.delete();
 279  
                 }
 280  
             }
 281  
         }
 282  0
         catch ( IOException e )
 283  
         {
 284  0
             throw new MojoExecutionException( "Error during document generation", e );
 285  4
         }
 286  4
     }
 287  
 
 288  
     // ----------------------------------------------------------------------
 289  
     // Private methods
 290  
     // ----------------------------------------------------------------------
 291  
 
 292  
     /**
 293  
      * Constructs a DocumentModel for the current project. The model is either read from
 294  
      * a descriptor file, if it exists, or constructed from information in the pom and site.xml.
 295  
      *
 296  
      * @param locale not null
 297  
      * @return DocumentModel.
 298  
      * @throws MojoExecutionException if any
 299  
      * @see #readAndFilterDocumentDescriptor(MavenProject, File, Log)
 300  
      */
 301  
     private DocumentModel getDocumentModel( Locale locale )
 302  
         throws MojoExecutionException
 303  
     {
 304  4
         if ( docDescriptor.exists() )
 305  
         {
 306  3
             DocumentModel doc = getDocumentModelFromDescriptor( locale );
 307  
             // TODO: descriptor model should get merged into default model, see MODELLO-63
 308  
 
 309  3
             return doc;
 310  
         }
 311  
 
 312  1
         DocumentModel model = new DocumentModelBuilder( project, getDefaultDecorationModel() ).getDocumentModel();
 313  
 
 314  1
         model.getMeta().setGenerator( getDefaultGenerator() );
 315  1
         model.getMeta().setLanguage( locale.getLanguage() );
 316  1
         model.getCover().setCoverType( i18n.getString( "pdf-plugin", defaultLocale, "toc.type" ) );
 317  1
         model.getToc().setName( i18n.getString( "pdf-plugin", defaultLocale, "toc.title" ) );
 318  
 
 319  1
         debugLogGeneratedModel( model );
 320  
 
 321  1
         return model;
 322  
     }
 323  
 
 324  
     /**
 325  
      * Read a DocumentModel from a file.
 326  
      *
 327  
      * @param locale used to set the language.
 328  
      * @return the DocumentModel read from the configured document descriptor.
 329  
      * @throws org.apache.maven.plugin.MojoExecutionException if the model could not be read.
 330  
      */
 331  
     private DocumentModel getDocumentModelFromDescriptor( Locale locale )
 332  
             throws MojoExecutionException
 333  
     {
 334  3
         DocumentModel model = null;
 335  
 
 336  
         try
 337  
         {
 338  3
             model = new DocumentDescriptorReader( project, getLog() ).readAndFilterDocumentDescriptor( docDescriptor );
 339  
         }
 340  0
         catch ( XmlPullParserException ex )
 341  
         {
 342  0
             throw new MojoExecutionException( "Error reading DocumentDescriptor!", ex );
 343  
         }
 344  0
         catch ( IOException io )
 345  
         {
 346  0
             throw new MojoExecutionException( "Error opening DocumentDescriptor!", io );
 347  3
         }
 348  
 
 349  3
         if ( StringUtils.isEmpty( model.getMeta().getLanguage() ) )
 350  
         {
 351  0
             model.getMeta().setLanguage( locale.getLanguage() );
 352  
         }
 353  
 
 354  3
         if ( StringUtils.isEmpty( model.getMeta().getGenerator() ) )
 355  
         {
 356  3
             model.getMeta().setGenerator( getDefaultGenerator() );
 357  
         }
 358  
 
 359  3
         return model;
 360  
     }
 361  
 
 362  
     /**
 363  
      * Return the working directory for a given Locale and the current default Locale.
 364  
      *
 365  
      * @param locale a Locale.
 366  
      * @return File.
 367  
      */
 368  
     private File getWorkingDirectory( Locale locale )
 369  
     {
 370  4
         if ( locale.getLanguage().equals( defaultLocale.getLanguage() ) )
 371  
         {
 372  4
             return workingDirectory;
 373  
         }
 374  
 
 375  0
         return new File( workingDirectory, locale.getLanguage() );
 376  
     }
 377  
 
 378  
     /**
 379  
      * @return the default locale from <code>siteTool</code>.
 380  
      */
 381  
     private Locale getDefaultLocale()
 382  
     {
 383  4
         if ( this.defaultLocale == null )
 384  
         {
 385  0
             final List localesList = siteTool.getAvailableLocales( locales );
 386  0
             this.defaultLocale = (Locale) localesList.get( 0 );
 387  
         }
 388  
 
 389  4
         return this.defaultLocale;
 390  
     }
 391  
 
 392  
     /**
 393  
      * @return the DecorationModel instance from <code>site.xml</code>
 394  
      * @throws MojoExecutionException if any
 395  
      */
 396  
     private DecorationModel getDefaultDecorationModel()
 397  
         throws MojoExecutionException
 398  
     {
 399  5
         if ( this.defaultDecorationModel == null )
 400  
         {
 401  4
             final Locale locale = getDefaultLocale();
 402  
 
 403  4
             final File basedir = project.getBasedir();
 404  4
             final String relativePath = siteTool.getRelativePath(
 405  
                     siteDirectory.getAbsolutePath(), basedir.getAbsolutePath() );
 406  
 
 407  4
             final File descriptorFile = siteTool.getSiteDescriptorFromBasedir( relativePath, basedir, locale );
 408  4
             DecorationModel decoration = null;
 409  
 
 410  4
             if ( descriptorFile.exists() )
 411  
             {
 412  4
                 XmlStreamReader reader = null;
 413  
                 try
 414  
                 {
 415  4
                     reader = ReaderFactory.newXmlReader( descriptorFile );
 416  4
                     String siteDescriptorContent = IOUtil.toString( reader );
 417  
 
 418  4
                     siteDescriptorContent =
 419  
                         siteTool.getInterpolatedSiteDescriptorContent( new HashMap(), project, siteDescriptorContent,
 420  
                                                                        reader.getEncoding(), reader.getEncoding() );
 421  
 
 422  4
                     decoration = new DecorationXpp3Reader().read( new StringReader( siteDescriptorContent ) );
 423  
                 }
 424  0
                 catch ( XmlPullParserException e )
 425  
                 {
 426  0
                     throw new MojoExecutionException( "Error parsing site descriptor", e );
 427  
                 }
 428  0
                 catch ( IOException e )
 429  
                 {
 430  0
                     throw new MojoExecutionException( "Error reading site descriptor", e );
 431  
                 }
 432  0
                 catch ( SiteToolException e )
 433  
                 {
 434  0
                     throw new MojoExecutionException( "Error when interpoling site descriptor", e );
 435  
                 }
 436  
                 finally
 437  
                 {
 438  4
                     IOUtil.close( reader );
 439  4
                 }
 440  
             }
 441  
 
 442  4
             this.defaultDecorationModel = decoration;
 443  
         }
 444  
 
 445  5
         return this.defaultDecorationModel;
 446  
     }
 447  
 
 448  
     /**
 449  
      * Parse the decoration model to find the skin artifact and copy its resources to the output dir.
 450  
      *
 451  
      * @param locale not null
 452  
      * @throws MojoExecutionException if any
 453  
      * @see #getDefaultDecorationModel()
 454  
      */
 455  
     private void copyResources( Locale locale )
 456  
         throws MojoExecutionException
 457  
     {
 458  4
         final DecorationModel decorationModel = getDefaultDecorationModel();
 459  
 
 460  4
         if ( decorationModel == null )
 461  
         {
 462  0
             return;
 463  
         }
 464  
 
 465  
         File skinFile;
 466  
 
 467  
         try
 468  
         {
 469  4
             skinFile =
 470  
                 siteTool.getSkinArtifactFromRepository( localRepository, project.getRemoteArtifactRepositories(),
 471  
                                                         decorationModel ).getFile();
 472  
         }
 473  0
         catch ( SiteToolException e )
 474  
         {
 475  0
             throw new MojoExecutionException( "SiteToolException: " + e.getMessage(), e );
 476  4
         }
 477  
 
 478  4
         if ( skinFile == null )
 479  
         {
 480  0
             return;
 481  
         }
 482  
 
 483  4
         if ( getLog().isDebugEnabled() )
 484  
         {
 485  0
             getLog().debug( "Copy resources from skin artifact: '" + skinFile + "'..." );
 486  
         }
 487  
 
 488  
         try
 489  
         {
 490  4
             final SiteRenderingContext context =
 491  
                 siteRenderer.createContextForSkin( skinFile, new HashMap(), decorationModel, project.getName(),
 492  
                                                    locale );
 493  4
             context.addSiteDirectory( new File( siteDirectory, locale.getLanguage() ) );
 494  
 
 495  4
             for ( final Iterator i = context.getSiteDirectories().iterator(); i.hasNext(); )
 496  
             {
 497  4
                 final File siteDirectoryFile = (File) i.next();
 498  
 
 499  4
                 siteRenderer.copyResources( context, new File( siteDirectoryFile, "resources" ), workingDirectory );
 500  
             }
 501  
         }
 502  0
         catch ( IOException e )
 503  
         {
 504  0
             throw new MojoExecutionException( "IOException: " + e.getMessage(), e );
 505  4
         }
 506  4
     }
 507  
 
 508  
     /**
 509  
      * Construct a default producer.
 510  
      *
 511  
      * @return A String in the form <code>Maven PDF Plugin v. 1.1.1, 'fo' implementation</code>.
 512  
      */
 513  
     private String getDefaultGenerator()
 514  
     {
 515  4
         return "Maven PDF Plugin v. " + pluginVersion + ", '" + implementation + "' implementation.";
 516  
     }
 517  
 
 518  
     /**
 519  
      * Write the auto-generated model to disc.
 520  
      *
 521  
      * @param docModel the model to write.
 522  
      */
 523  
     private void debugLogGeneratedModel( final DocumentModel docModel )
 524  
     {
 525  1
         if ( getLog().isDebugEnabled() && project != null )
 526  
         {
 527  0
             final File outputDir = new File( project.getBuild().getDirectory(), "pdf" );
 528  
 
 529  0
             if ( !outputDir.exists() )
 530  
             {
 531  0
                 outputDir.mkdirs();
 532  
             }
 533  
 
 534  0
             final File doc = FileUtils.createTempFile( "pdf", ".xml", outputDir );
 535  0
             final DocumentXpp3Writer xpp3 = new DocumentXpp3Writer();
 536  
 
 537  0
             Writer w = null;
 538  
 
 539  
             try
 540  
             {
 541  0
                 w = WriterFactory.newXmlWriter( doc );
 542  0
                 xpp3.write( w, docModel );
 543  0
                 getLog().debug( "Generated a default document model: " + doc.getAbsolutePath() );
 544  
             }
 545  0
             catch ( IOException io )
 546  
             {
 547  0
                 getLog().debug( "Failed to write document model: " + doc.getAbsolutePath(), io );
 548  
             }
 549  
             finally
 550  
             {
 551  0
                 IOUtil.close( w );
 552  0
             }
 553  
         }
 554  1
     }
 555  
 }