Coverage Report - org.apache.maven.plugins.site.AbstractSiteRenderingMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractSiteRenderingMojo
2%
3/132
0%
0/64
6
 
 1  
 package org.apache.maven.plugins.site;
 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  
 
 25  
 import java.util.ArrayList;
 26  
 import java.util.Collection;
 27  
 import java.util.HashMap;
 28  
 import java.util.Iterator;
 29  
 import java.util.LinkedHashMap;
 30  
 import java.util.List;
 31  
 import java.util.Locale;
 32  
 import java.util.Map;
 33  
 
 34  
 import org.apache.maven.artifact.Artifact;
 35  
 import org.apache.maven.artifact.repository.ArtifactRepository;
 36  
 import org.apache.maven.doxia.sink.render.RenderingContext;
 37  
 import org.apache.maven.doxia.site.decoration.DecorationModel;
 38  
 import org.apache.maven.doxia.site.decoration.Menu;
 39  
 import org.apache.maven.doxia.site.decoration.MenuItem;
 40  
 import org.apache.maven.doxia.site.decoration.inheritance.DecorationModelInheritanceAssembler;
 41  
 import org.apache.maven.doxia.siterenderer.DocumentRenderer;
 42  
 import org.apache.maven.doxia.siterenderer.Renderer;
 43  
 import org.apache.maven.doxia.siterenderer.RendererException;
 44  
 import org.apache.maven.doxia.siterenderer.SiteRenderingContext;
 45  
 import org.apache.maven.doxia.tools.SiteToolException;
 46  
 import org.apache.maven.execution.MavenSession;
 47  
 import org.apache.maven.plugin.MojoExecutionException;
 48  
 import org.apache.maven.plugin.MojoFailureException;
 49  
 import org.apache.maven.reporting.MavenReport;
 50  
 import org.apache.maven.reporting.exec.MavenReportExecution;
 51  
 import org.apache.maven.reporting.exec.MavenReportExecutor;
 52  
 import org.apache.maven.reporting.exec.MavenReportExecutorRequest;
 53  
 import org.apache.maven.reporting.exec.ReportPlugin;
 54  
 import org.codehaus.plexus.PlexusConstants;
 55  
 import org.codehaus.plexus.PlexusContainer;
 56  
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 57  
 import org.codehaus.plexus.context.Context;
 58  
 import org.codehaus.plexus.context.ContextException;
 59  
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
 60  
 
 61  
 /**
 62  
  * Base class for site rendering mojos.
 63  
  *
 64  
  * @author <a href="mailto:brett@apache.org">Brett Porter</a>
 65  
  * @version $Id$
 66  
  */
 67  1
 public abstract class AbstractSiteRenderingMojo
 68  
     extends AbstractSiteMojo implements Contextualizable
 69  
 {
 70  
     /**
 71  
      * Module type exclusion mappings
 72  
      * ex: <code>fml  -> **&#47;*-m1.fml</code>  (excludes fml files ending in '-m1.fml' recursively)
 73  
      * <p/>
 74  
      * The configuration looks like this:
 75  
      * <pre>
 76  
      *   &lt;moduleExcludes&gt;
 77  
      *     &lt;moduleType&gt;filename1.ext,**&#47;*sample.ext&lt;/moduleType&gt;
 78  
      *     &lt;!-- moduleType can be one of 'apt', 'fml' or 'xdoc'. --&gt;
 79  
      *     &lt;!-- The value is a comma separated list of           --&gt;
 80  
      *     &lt;!-- filenames or fileset patterns.                   --&gt;
 81  
      *     &lt;!-- Here's an example:                               --&gt;
 82  
      *     &lt;xdoc&gt;changes.xml,navigation.xml&lt;/xdoc&gt;
 83  
      *   &lt;/moduleExcludes&gt;
 84  
      * </pre>
 85  
      *
 86  
      * @parameter
 87  
      */
 88  
     private Map<String, String> moduleExcludes;
 89  
 
 90  
     /**
 91  
      * The component for assembling inheritance.
 92  
      *
 93  
      * @component
 94  
      */
 95  
     private DecorationModelInheritanceAssembler assembler;
 96  
 
 97  
     /**
 98  
      * Remote repositories used for the project.
 99  
      *
 100  
      * @todo this is used for site descriptor resolution - it should relate to the actual project but for some reason they are not always filled in
 101  
      * @parameter default-value="${project.remoteArtifactRepositories}"
 102  
      * @readonly
 103  
      */
 104  
     private List<ArtifactRepository> repositories;
 105  
 
 106  
     /**
 107  
      * Directory containing the template page.
 108  
      *
 109  
      * @parameter expression="${templateDirectory}" default-value="src/site"
 110  
      * @deprecated use templateFile or skinning instead
 111  
      */
 112  
     private File templateDirectory;
 113  
 
 114  
     /**
 115  
      * Default template page.
 116  
      *
 117  
      * @parameter expression="${template}"
 118  
      * @deprecated use templateFile or skinning instead
 119  
      */
 120  
     private String template;
 121  
 
 122  
     /**
 123  
      * The location of a Velocity template file to use. When used, skins and the default templates, CSS and images
 124  
      * are disabled. It is highly recommended that you package this as a skin instead.
 125  
      *
 126  
      * @parameter expression="${templateFile}"
 127  
      * @since 2.0-beta-5
 128  
      */
 129  
     private File templateFile;
 130  
 
 131  
     /**
 132  
      * Additional template properties for rendering the site. See
 133  
      * <a href="/doxia/doxia-sitetools/doxia-site-renderer/">Doxia Site Renderer</a>.
 134  
      *
 135  
      * @parameter
 136  
      */
 137  
     private Map<String, Object> attributes;
 138  
 
 139  
     /**
 140  
      * Site renderer.
 141  
      *
 142  
      * @component
 143  
      */
 144  
     protected Renderer siteRenderer;
 145  
 
 146  
     /**
 147  
      * Reports (Maven 2).
 148  
      * 
 149  
      * @parameter expression="${reports}"
 150  
      * @required
 151  
      * @readonly
 152  
      */
 153  
     protected List<MavenReport> reports;
 154  
 
 155  
     /**
 156  
      * Alternative directory for xdoc source, useful for m1 to m2 migration
 157  
      *
 158  
      * @parameter default-value="${basedir}/xdocs"
 159  
      * @deprecated use the standard m2 directory layout
 160  
      */
 161  
     private File xdocDirectory;
 162  
 
 163  
     /**
 164  
      * Directory containing generated documentation.
 165  
      * This is used to pick up other source docs that might have been generated at build time.
 166  
      *
 167  
      * @parameter alias="workingDirectory" default-value="${project.build.directory}/generated-site"
 168  
      *
 169  
      * @todo should we deprecate in favour of reports?
 170  
      */
 171  
     protected File generatedSiteDirectory;
 172  
 
 173  
     /**
 174  
      * The current Maven session.
 175  
      * 
 176  
      * @parameter expression="${session}"
 177  
      * @required
 178  
      * @readonly
 179  
      */
 180  
     protected MavenSession mavenSession;
 181  
 
 182  
     /**
 183  
      * <p>Configuration section used internally by Maven 3.</p>
 184  
      * <p>More details available here:
 185  
      * <a href="http://maven.apache.org/plugins/maven-site-plugin/maven-3.html#Configuration_formats" target="_blank">
 186  
      *     http://maven.apache.org/plugins/maven-site-plugin/maven-3.html#Configuration_formats</a>
 187  
      * </p>
 188  
      * <p><b>Note:</b> using this field is not mandatory with Maven 3 as Maven core injects usual
 189  
      * <code>&lt;reporting&gt;</code> section into this field.</p>
 190  
      *
 191  
      * @parameter
 192  
      * @since 3.0-beta-1
 193  
      */
 194  
     private ReportPlugin[] reportPlugins;
 195  
 
 196  
     private PlexusContainer container;
 197  
 
 198  
     /**
 199  
      * Make links in the site descriptor relative to the project URL.
 200  
      * By default, any absolute links that appear in the site descriptor,
 201  
      * e.g. banner hrefs, breadcrumbs, menu links, etc., will be made relative to project.url.
 202  
      *
 203  
      * Links will not be changed if this is set to false, or if the project has no URL defined.
 204  
      *
 205  
      * @parameter expression="${relativizeDecorationLinks}" default-value="true"
 206  
      *
 207  
      * @since 2.3
 208  
      */
 209  
     private boolean relativizeDecorationLinks;
 210  
 
 211  
     /**
 212  
      * Whether to generate the summary page for project reports: project-info.html.
 213  
      *
 214  
      * @parameter expression="${generateProjectInfo}" default-value="true"
 215  
      *
 216  
      * @since 2.3
 217  
      */
 218  
     private boolean generateProjectInfo;
 219  
 
 220  
     /** {@inheritDoc} */
 221  
     public void contextualize( Context context )
 222  
         throws ContextException
 223  
     {
 224  1
         container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
 225  1
     }
 226  
 
 227  
     protected List<MavenReportExecution> getReports()
 228  
         throws MojoExecutionException
 229  
     {
 230  0
         if ( isMaven3OrMore() )
 231  
         {
 232  0
             MavenReportExecutorRequest mavenReportExecutorRequest = new MavenReportExecutorRequest();
 233  0
             mavenReportExecutorRequest.setLocalRepository( localRepository );
 234  0
             mavenReportExecutorRequest.setMavenSession( mavenSession );
 235  0
             mavenReportExecutorRequest.setProject( project );
 236  0
             mavenReportExecutorRequest.setReportPlugins( reportPlugins );
 237  
 
 238  
             MavenReportExecutor mavenReportExecutor;
 239  
             try
 240  
             {
 241  0
                 mavenReportExecutor = (MavenReportExecutor) container.lookup( MavenReportExecutor.class.getName() );
 242  
             }
 243  0
             catch ( ComponentLookupException e )
 244  
             {
 245  0
                 throw new MojoExecutionException( "could not get MavenReportExecutor component", e );
 246  0
             }
 247  0
             return mavenReportExecutor.buildMavenReports( mavenReportExecutorRequest );
 248  
         }
 249  
 
 250  0
         List<MavenReportExecution> reportExecutions = new ArrayList<MavenReportExecution>( reports.size() );
 251  0
         for ( MavenReport report : reports )
 252  
         {
 253  0
             if ( report.canGenerateReport() )
 254  
             {
 255  0
                 reportExecutions.add( new MavenReportExecution( report ) );
 256  
             }
 257  
         }
 258  0
         return reportExecutions;
 259  
     }
 260  
 
 261  
     protected SiteRenderingContext createSiteRenderingContext( Locale locale )
 262  
         throws MojoExecutionException, IOException, MojoFailureException
 263  
     {
 264  0
         if ( attributes == null )
 265  
         {
 266  0
             attributes = new HashMap<String, Object>();
 267  
         }
 268  
 
 269  0
         if ( attributes.get( "project" ) == null )
 270  
         {
 271  0
             attributes.put( "project", project );
 272  
         }
 273  
 
 274  0
         if ( attributes.get( "inputEncoding" ) == null )
 275  
         {
 276  0
             attributes.put( "inputEncoding", getInputEncoding() );
 277  
         }
 278  
 
 279  0
         if ( attributes.get( "outputEncoding" ) == null )
 280  
         {
 281  0
             attributes.put( "outputEncoding", getOutputEncoding() );
 282  
         }
 283  
 
 284  
         // Put any of the properties in directly into the Velocity context
 285  0
         for ( Map.Entry<Object, Object> entry : project.getProperties().entrySet() )
 286  
         {
 287  0
             attributes.put( (String) entry.getKey(), entry.getValue() );
 288  
         }
 289  
 
 290  
         DecorationModel decorationModel;
 291  
         try
 292  
         {
 293  0
             decorationModel = siteTool.getDecorationModel( project, reactorProjects, localRepository, repositories,
 294  
                                                            siteTool.getRelativePath( siteDirectory.getAbsolutePath(),
 295  
                                                            project.getBasedir().getAbsolutePath() ),
 296  
                                                            locale, getInputEncoding(), getOutputEncoding() );
 297  
         }
 298  0
         catch ( SiteToolException e )
 299  
         {
 300  0
             throw new MojoExecutionException( "SiteToolException: " + e.getMessage(), e );
 301  0
         }
 302  
 
 303  0
         if ( relativizeDecorationLinks )
 304  
         {
 305  0
             final String url = project.getUrl();
 306  
 
 307  0
             if ( url == null )
 308  
             {
 309  0
                 getLog().warn( "No project URL defined - decoration links will not be relativized!" );
 310  
             }
 311  
             else
 312  
             {
 313  0
                 getLog().info( "Relativizing decoration links with respect to project URL: " + url );
 314  0
                 assembler.resolvePaths( decorationModel, url );
 315  
             }
 316  
         }
 317  
 
 318  0
         if ( template != null )
 319  
         {
 320  0
             if ( templateFile != null )
 321  
             {
 322  0
                 getLog().warn( "'template' configuration is ignored when 'templateFile' is set" );
 323  
             }
 324  
             else
 325  
             {
 326  0
                 templateFile = new File( templateDirectory, template );
 327  
             }
 328  
         }
 329  
 
 330  
         File skinFile;
 331  
         try
 332  
         {
 333  0
             Artifact skinArtifact =
 334  
                 siteTool.getSkinArtifactFromRepository( localRepository, repositories, decorationModel );
 335  0
             getLog().info( "Rendering site with " + skinArtifact.getId() + " skin." );
 336  
 
 337  0
             skinFile = skinArtifact.getFile();
 338  
         }
 339  0
         catch ( SiteToolException e )
 340  
         {
 341  0
             throw new MojoExecutionException( "SiteToolException: " + e.getMessage(), e );
 342  0
         }
 343  
         SiteRenderingContext context;
 344  0
         if ( templateFile != null )
 345  
         {
 346  0
             if ( !templateFile.exists() )
 347  
             {
 348  0
                 throw new MojoFailureException( "Template file '" + templateFile + "' does not exist" );
 349  
             }
 350  0
             context = siteRenderer.createContextForTemplate( templateFile, skinFile, attributes, decorationModel,
 351  
                                                              project.getName(), locale );
 352  
         }
 353  
         else
 354  
         {
 355  0
             context = siteRenderer.createContextForSkin( skinFile, attributes, decorationModel, project.getName(),
 356  
                                                          locale );
 357  
         }
 358  
 
 359  
         // Generate static site
 360  0
         if ( !locale.getLanguage().equals( Locale.getDefault().getLanguage() ) )
 361  
         {
 362  0
             context.addSiteDirectory( new File( siteDirectory, locale.getLanguage() ) );
 363  0
             context.addModuleDirectory( new File( xdocDirectory, locale.getLanguage() ), "xdoc" );
 364  0
             context.addModuleDirectory( new File( xdocDirectory, locale.getLanguage() ), "fml" );
 365  
         }
 366  
         else
 367  
         {
 368  0
             context.addSiteDirectory( siteDirectory );
 369  0
             context.addModuleDirectory( xdocDirectory, "xdoc" );
 370  0
             context.addModuleDirectory( xdocDirectory, "fml" );
 371  
         }
 372  
 
 373  0
         if ( moduleExcludes != null )
 374  
         {
 375  0
             context.setModuleExcludes( moduleExcludes );
 376  
         }
 377  
 
 378  0
         return context;
 379  
     }
 380  
 
 381  
     /**
 382  
      * Go through the list of reports and process each one like this:
 383  
      * <ul>
 384  
      * <li>Add the report to a map of reports keyed by filename having the report itself as value
 385  
      * <li>If the report is not yet in the map of documents, add it together with a suitable renderer
 386  
      * </ul>
 387  
      *
 388  
      * @param reports A List of MavenReports
 389  
      * @param documents A Map of documents, keyed by filename
 390  
      * @param locale the Locale the reports are processed for.
 391  
      * @return A map with all reports keyed by filename having the report itself as value.
 392  
      * The map will be used to populate a menu.
 393  
      */
 394  
     protected Map<String, MavenReport> locateReports( List<MavenReportExecution> reports,
 395  
                                                       Map<String, DocumentRenderer> documents, Locale locale )
 396  
     {
 397  
         // copy Collection to prevent ConcurrentModificationException
 398  0
         List<MavenReportExecution> filtered = new ArrayList<MavenReportExecution>( reports );
 399  
 
 400  0
         Map<String, MavenReport> reportsByOutputName = new LinkedHashMap<String, MavenReport>();
 401  0
         for ( MavenReportExecution mavenReportExecution : filtered )
 402  
         {
 403  0
             MavenReport report = mavenReportExecution.getMavenReport();
 404  
 
 405  0
             String outputName = report.getOutputName() + ".html";
 406  
 
 407  
             // Always add the report to the menu, see MSITE-150
 408  0
             reportsByOutputName.put( report.getOutputName(), report );
 409  
 
 410  0
             if ( documents.containsKey( outputName ) )
 411  
             {
 412  0
                 String displayLanguage = locale.getDisplayLanguage( Locale.ENGLISH );
 413  
 
 414  0
                 getLog().info( "Skipped \"" + report.getName( locale ) + "\" report, file \"" + outputName
 415  
                                    + "\" already exists for the " + displayLanguage + " version." );
 416  0
                 reports.remove( mavenReportExecution );
 417  0
             }
 418  
             else
 419  
             {
 420  0
                 RenderingContext renderingContext = new RenderingContext( siteDirectory, outputName );
 421  0
                 DocumentRenderer renderer = new ReportDocumentRenderer( mavenReportExecution, renderingContext, getLog() );
 422  0
                 documents.put( outputName, renderer );
 423  
             }
 424  0
         }
 425  0
         return reportsByOutputName;
 426  
     }
 427  
 
 428  
     /**
 429  
      * Go through the collection of reports and put each report into a list for the appropriate category. The list is
 430  
      * put into a map keyed by the name of the category.
 431  
      *
 432  
      * @param reports A Collection of MavenReports
 433  
      * @return A map keyed category having the report itself as value
 434  
      */
 435  
     protected Map<String, List<MavenReport>> categoriseReports( Collection<MavenReport> reports )
 436  
     {
 437  0
         Map<String, List<MavenReport>> categories = new LinkedHashMap<String, List<MavenReport>>();
 438  0
         for ( MavenReport report : reports )
 439  
         {
 440  0
             List<MavenReport> categoryReports = categories.get( report.getCategoryName() );
 441  0
             if ( categoryReports == null )
 442  
             {
 443  0
                 categoryReports = new ArrayList<MavenReport>();
 444  0
                 categories.put( report.getCategoryName(), categoryReports );
 445  
             }
 446  0
             categoryReports.add( report );
 447  0
         }
 448  0
         return categories;
 449  
     }
 450  
 
 451  
     protected Map<String, DocumentRenderer> locateDocuments( SiteRenderingContext context, List<MavenReportExecution> reports,
 452  
                                                              Locale locale )
 453  
         throws IOException, RendererException
 454  
     {
 455  0
         Map<String, DocumentRenderer> documents = siteRenderer.locateDocumentFiles( context );
 456  
 
 457  0
         Map<String, MavenReport> reportsByOutputName = locateReports( reports, documents, locale );
 458  
 
 459  
         // TODO: I want to get rid of categories eventually. There's no way to add your own in a fully i18n manner
 460  0
         Map<String, List<MavenReport>> categories = categoriseReports( reportsByOutputName.values() );
 461  
 
 462  0
         siteTool.populateReportsMenu( context.getDecoration(), locale, categories );
 463  0
         populateReportItems( context.getDecoration(), locale, reportsByOutputName );
 464  
 
 465  0
         if ( categories.containsKey( MavenReport.CATEGORY_PROJECT_INFORMATION ) && generateProjectInfo )
 466  
         {
 467  0
             List<MavenReport> categoryReports = categories.get( MavenReport.CATEGORY_PROJECT_INFORMATION );
 468  
 
 469  0
             RenderingContext renderingContext = new RenderingContext( siteDirectory, "project-info.html" );
 470  0
             String title = i18n.getString( "site-plugin", locale, "report.information.title" );
 471  0
             String desc1 = i18n.getString( "site-plugin", locale, "report.information.description1" );
 472  0
             String desc2 = i18n.getString( "site-plugin", locale, "report.information.description2" );
 473  0
             DocumentRenderer renderer = new CategorySummaryDocumentRenderer( renderingContext, title, desc1, desc2,
 474  
                                                                              i18n, categoryReports, getLog() );
 475  
 
 476  0
             if ( !documents.containsKey( renderer.getOutputName() ) )
 477  
             {
 478  0
                 documents.put( renderer.getOutputName(), renderer );
 479  
             }
 480  
             else
 481  
             {
 482  0
                 getLog().info( "Category summary '" + renderer.getOutputName() + "' skipped; already exists" );
 483  
             }
 484  
         }
 485  
 
 486  0
         if ( categories.containsKey( MavenReport.CATEGORY_PROJECT_REPORTS ) )
 487  
         {
 488  0
             List<MavenReport> categoryReports = categories.get( MavenReport.CATEGORY_PROJECT_REPORTS );
 489  0
             RenderingContext renderingContext = new RenderingContext( siteDirectory, "project-reports.html" );
 490  0
             String title = i18n.getString( "site-plugin", locale, "report.project.title" );
 491  0
             String desc1 = i18n.getString( "site-plugin", locale, "report.project.description1" );
 492  0
             String desc2 = i18n.getString( "site-plugin", locale, "report.project.description2" );
 493  0
             DocumentRenderer renderer = new CategorySummaryDocumentRenderer( renderingContext, title, desc1, desc2,
 494  
                                                                              i18n, categoryReports, getLog() );
 495  
 
 496  0
             if ( !documents.containsKey( renderer.getOutputName() ) )
 497  
             {
 498  0
                 documents.put( renderer.getOutputName(), renderer );
 499  
             }
 500  
             else
 501  
             {
 502  0
                 getLog().info( "Category summary '" + renderer.getOutputName() + "' skipped; already exists" );
 503  
             }
 504  
         }
 505  0
         return documents;
 506  
     }
 507  
 
 508  
     protected void populateReportItems( DecorationModel decorationModel, Locale locale,
 509  
                                         Map<String, MavenReport> reportsByOutputName )
 510  
     {
 511  0
         for ( Menu menu : decorationModel.getMenus() )
 512  
         {
 513  0
             populateItemRefs( menu.getItems(), locale, reportsByOutputName );
 514  
         }
 515  0
     }
 516  
 
 517  
     private void populateItemRefs( List<MenuItem> items, Locale locale, Map<String, MavenReport> reportsByOutputName )
 518  
     {
 519  0
         for ( Iterator<MenuItem> i = items.iterator(); i.hasNext(); )
 520  
         {
 521  0
             MenuItem item = i.next();
 522  
 
 523  0
             if ( item.getRef() != null )
 524  
             {
 525  0
                 MavenReport report = reportsByOutputName.get( item.getRef() );
 526  
 
 527  0
                 if ( report != null )
 528  
                 {
 529  0
                     if ( item.getName() == null )
 530  
                     {
 531  0
                         item.setName( report.getName( locale ) );
 532  
                     }
 533  
 
 534  0
                     if ( item.getHref() == null || item.getHref().length() == 0 )
 535  
                     {
 536  0
                         item.setHref( report.getOutputName() + ".html" );
 537  
                     }
 538  
                 }
 539  
                 else
 540  
                 {
 541  0
                     getLog().warn( "Unrecognised reference: '" + item.getRef() + "'" );
 542  0
                     i.remove();
 543  
                 }
 544  
             }
 545  
 
 546  0
             populateItemRefs( item.getItems(), locale, reportsByOutputName );
 547  0
         }
 548  0
     }
 549  
 }