Coverage Report - org.apache.maven.plugins.site.AbstractDeployMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractDeployMojo
14%
22/157
32%
26/82
0
 
 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  
 
 24  
 import java.util.List;
 25  
 import java.util.Locale;
 26  
 
 27  
 import org.apache.maven.artifact.manager.WagonConfigurationException;
 28  
 import org.apache.maven.artifact.manager.WagonManager;
 29  
 import org.apache.maven.model.DistributionManagement;
 30  
 import org.apache.maven.model.Site;
 31  
 import org.apache.maven.plugin.MojoExecutionException;
 32  
 import org.apache.maven.plugin.logging.Log;
 33  
 import org.apache.maven.project.MavenProject;
 34  
 import org.apache.maven.settings.Server;
 35  
 import org.apache.maven.settings.Settings;
 36  
 import org.apache.maven.wagon.CommandExecutionException;
 37  
 import org.apache.maven.wagon.CommandExecutor;
 38  
 import org.apache.maven.wagon.ConnectionException;
 39  
 import org.apache.maven.wagon.ResourceDoesNotExistException;
 40  
 import org.apache.maven.wagon.TransferFailedException;
 41  
 import org.apache.maven.wagon.UnsupportedProtocolException;
 42  
 import org.apache.maven.wagon.Wagon;
 43  
 import org.apache.maven.wagon.authentication.AuthenticationException;
 44  
 import org.apache.maven.wagon.authentication.AuthenticationInfo;
 45  
 import org.apache.maven.wagon.authorization.AuthorizationException;
 46  
 import org.apache.maven.wagon.observers.Debug;
 47  
 import org.apache.maven.wagon.proxy.ProxyInfo;
 48  
 import org.apache.maven.wagon.repository.Repository;
 49  
 
 50  
 import org.codehaus.plexus.PlexusConstants;
 51  
 import org.codehaus.plexus.PlexusContainer;
 52  
 import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
 53  
 import org.codehaus.plexus.component.configurator.ComponentConfigurator;
 54  
 import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
 55  
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 56  
 import org.codehaus.plexus.configuration.PlexusConfiguration;
 57  
 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
 58  
 import org.codehaus.plexus.context.Context;
 59  
 import org.codehaus.plexus.context.ContextException;
 60  
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
 61  
 import org.codehaus.plexus.util.StringUtils;
 62  
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 63  
 
 64  
 /**
 65  
  * Abstract base class for deploy mojos.
 66  
  * Since 2.3 this includes {@link SiteStageMojo} and {@link SiteStageDeployMojo}.
 67  
  *
 68  
  * @author ltheussl
 69  
  *
 70  
  * @since 2.3
 71  
  */
 72  0
 public abstract class AbstractDeployMojo
 73  
     extends AbstractSiteMojo implements Contextualizable
 74  
 {
 75  
     /**
 76  
      * Directory containing the generated project sites and report distributions.
 77  
      *
 78  
      * @parameter alias="outputDirectory" expression="${project.reporting.outputDirectory}"
 79  
      * @required
 80  
      */
 81  
     private File inputDirectory;
 82  
 
 83  
     /**
 84  
      * Whether to run the "chmod" command on the remote site after the deploy.
 85  
      * Defaults to "true".
 86  
      *
 87  
      * @parameter expression="${maven.site.chmod}" default-value="true"
 88  
      * @since 2.1
 89  
      */
 90  
     private boolean chmod;
 91  
 
 92  
     /**
 93  
      * The mode used by the "chmod" command. Only used if chmod = true.
 94  
      * Defaults to "g+w,a+rX".
 95  
      *
 96  
      * @parameter expression="${maven.site.chmod.mode}" default-value="g+w,a+rX"
 97  
      * @since 2.1
 98  
      */
 99  
     private String chmodMode;
 100  
 
 101  
     /**
 102  
      * The options used by the "chmod" command. Only used if chmod = true.
 103  
      * Defaults to "-Rf".
 104  
      *
 105  
      * @parameter expression="${maven.site.chmod.options}" default-value="-Rf"
 106  
      * @since 2.1
 107  
      */
 108  
     private String chmodOptions;
 109  
 
 110  
     /**
 111  
      * @component
 112  
      */
 113  
     private WagonManager wagonManager;
 114  
 
 115  
     /**
 116  
      * The current user system settings for use in Maven.
 117  
      *
 118  
      * @parameter expression="${settings}"
 119  
      * @required
 120  
      * @readonly
 121  
      */
 122  
     private Settings settings;
 123  
 
 124  
     private PlexusContainer container;
 125  
 
 126  
     /**
 127  
      * The String "staging/".
 128  
      */
 129  
     protected static final String DEFAULT_STAGING_DIRECTORY = "staging/";
 130  
 
 131  
     /** {@inheritDoc} */
 132  
     public void execute()
 133  
         throws MojoExecutionException
 134  
     {
 135  0
         deployTo( new org.apache.maven.plugins.site.wagon.repository.Repository(
 136  
             getDeployRepositoryID(),
 137  
             appendSlash( getDeployRepositoryURL() ) ) );
 138  0
     }
 139  
 
 140  
     /**
 141  
      * Make sure the given url ends with a slash.
 142  
      *
 143  
      * @param url a String.
 144  
      *
 145  
      * @return if url already ends with '/' it is returned unchanged,
 146  
      *      otherwise a '/' character is appended.
 147  
      */
 148  
     protected static String appendSlash( final String url )
 149  
     {
 150  0
         if ( url.endsWith( "/" ) )
 151  
         {
 152  0
             return url;
 153  
         }
 154  
         else
 155  
         {
 156  0
             return url + "/";
 157  
         }
 158  
     }
 159  
 
 160  
     /**
 161  
      * Specifies the id to look up credential settings.
 162  
      *
 163  
      * @return the id to look up credentials for the deploy. Not null.
 164  
      *
 165  
      * @throws MojoExecutionException
 166  
      *      if the ID cannot be determined
 167  
      */
 168  
     protected abstract String getDeployRepositoryID()
 169  
         throws MojoExecutionException;
 170  
 
 171  
     /**
 172  
      * Specifies the target URL for the deploy.
 173  
      * This should be the top-level URL, ie above modules and locale sub-directories.
 174  
      *
 175  
      * @return the url to deploy to. Not null.
 176  
      *
 177  
      * @throws MojoExecutionException
 178  
      *      if the URL cannot be constructed
 179  
      */
 180  
     protected abstract String getDeployRepositoryURL()
 181  
         throws MojoExecutionException;
 182  
 
 183  
     /**
 184  
      * Find the relative path between the distribution URLs of the top parent and the current project.
 185  
      *
 186  
      * @return the relative path or "./" if the two URLs are the same.
 187  
      *
 188  
      * @throws MojoExecutionException
 189  
      */
 190  
     private String getDeployModuleDirectory()
 191  
         throws MojoExecutionException
 192  
     {
 193  0
         String relative = siteTool.getRelativePath( getSite( project ).getUrl(),
 194  
             getRootSite( project ).getUrl() );
 195  
 
 196  
         // SiteTool.getRelativePath() uses File.separatorChar,
 197  
         // so we need to convert '\' to '/' in order for the URL to be valid for Windows users
 198  0
         relative = relative.replace( '\\', '/' );
 199  
 
 200  0
         return ( "".equals( relative ) ) ? "./" : relative;
 201  
     }
 202  
 
 203  
     /**
 204  
      * Use wagon to deploy the generated site to a given repository.
 205  
      *
 206  
      * @param repository the repository to deply to.
 207  
      *      This needs to contain a valid, non-null {@link Repository#getId() id}
 208  
      *      to look up credentials for the deploy, and a valid, non-null
 209  
      *      {@link Repository#getUrl() scm url} to deploy to.
 210  
      *
 211  
      * @throws MojoExecutionException if the deploy fails.
 212  
      */
 213  
     private void deployTo( final Repository repository )
 214  
         throws MojoExecutionException
 215  
     {
 216  0
         if ( !inputDirectory.exists() )
 217  
         {
 218  0
             throw new MojoExecutionException( "The site does not exist, please run site:site first" );
 219  
         }
 220  
 
 221  0
         if ( getLog().isDebugEnabled() )
 222  
         {
 223  0
             getLog().debug( "Deploying to '" + repository.getUrl()
 224  
                 + "',\n    Using credentials from server id '" + repository.getId() + "'" );
 225  
         }
 226  
 
 227  0
         deploy( inputDirectory, repository );
 228  0
     }
 229  
 
 230  
     private void deploy( final File directory, final Repository repository )
 231  
         throws MojoExecutionException
 232  
     {
 233  
         // TODO: work on moving this into the deployer like the other deploy methods
 234  0
         final Wagon wagon = getWagon( repository, wagonManager );
 235  
 
 236  
         try
 237  
         {
 238  0
             configureWagon( wagon, repository.getId(), settings, container, getLog() );
 239  
         }
 240  0
         catch ( WagonConfigurationException e )
 241  
         {
 242  0
             throw new MojoExecutionException( "Unable to configure Wagon: '" + repository.getProtocol() + "'", e );
 243  0
         }
 244  
 
 245  
         try
 246  
         {
 247  0
             final ProxyInfo proxyInfo = getProxyInfo( repository, wagonManager );
 248  
 
 249  0
             push( directory, repository, wagonManager, wagon, proxyInfo,
 250  
                 siteTool.getAvailableLocales( locales ), getDeployModuleDirectory(), getLog() );
 251  
 
 252  0
             if ( chmod )
 253  
             {
 254  0
                 chmod( wagon, repository, chmodOptions, chmodMode );
 255  
             }
 256  
         }
 257  
         finally
 258  
         {
 259  0
             try
 260  
             {
 261  0
                 wagon.disconnect();
 262  
             }
 263  0
             catch ( ConnectionException e )
 264  
             {
 265  0
                 getLog().error( "Error disconnecting wagon - ignored", e );
 266  0
             }
 267  0
         }
 268  0
     }
 269  
 
 270  
     /**
 271  
      * Find the build directory of the top level project in the reactor.
 272  
      * If no top level project is found, the build directory of the current project is returned.
 273  
      *
 274  
      * @return the build directory of the top level project.
 275  
      */
 276  
     protected File getTopLevelBuildDirectory()
 277  
     {
 278  
         // Find the top level project in the reactor
 279  0
         final MavenProject topLevelProject = getTopLevelProject( reactorProjects );
 280  
 
 281  
         // Use the top level project's build directory if there is one, otherwise use this project's build directory
 282  
         final File buildDirectory;
 283  
 
 284  0
         if ( topLevelProject == null )
 285  
         {
 286  0
             getLog().debug( "No top level project found in the reactor, using the current project." );
 287  
 
 288  0
             buildDirectory = new File( project.getBuild().getDirectory() );
 289  
         }
 290  
         else
 291  
         {
 292  0
             getLog().debug( "Using the top level project found in the reactor." );
 293  
 
 294  0
             buildDirectory = new File( topLevelProject.getBuild().getDirectory() );
 295  
         }
 296  
 
 297  0
         return buildDirectory;
 298  
     }
 299  
 
 300  
     private static Wagon getWagon( final Repository repository, final WagonManager manager )
 301  
         throws MojoExecutionException
 302  
     {
 303  
         final Wagon wagon;
 304  
 
 305  
         try
 306  
         {
 307  0
             wagon = manager.getWagon( repository );
 308  
         }
 309  0
         catch ( UnsupportedProtocolException e )
 310  
         {
 311  0
             throw new MojoExecutionException( "Unsupported protocol: '" + repository.getProtocol() + "'", e );
 312  
         }
 313  0
         catch ( WagonConfigurationException e )
 314  
         {
 315  0
             throw new MojoExecutionException( "Unable to configure Wagon: '" + repository.getProtocol() + "'", e );
 316  0
         }
 317  
 
 318  0
         if ( !wagon.supportsDirectoryCopy() )
 319  
         {
 320  0
             throw new MojoExecutionException(
 321  
                 "Wagon protocol '" + repository.getProtocol() + "' doesn't support directory copying" );
 322  
         }
 323  
 
 324  0
         return wagon;
 325  
     }
 326  
 
 327  
     private static void push( final File inputDirectory, final Repository repository, final WagonManager manager,
 328  
                               final Wagon wagon, final ProxyInfo proxyInfo, final List<Locale> localesList,
 329  
                               final String relativeDir, final Log log )
 330  
         throws MojoExecutionException
 331  
     {
 332  0
         AuthenticationInfo authenticationInfo = manager.getAuthenticationInfo( repository.getId() );
 333  0
         log.debug( "authenticationInfo with id '" + repository.getId() + "': "
 334  
             + ( ( authenticationInfo == null ) ? "-" : authenticationInfo.getUserName() ) );
 335  
 
 336  
         try
 337  
         {
 338  0
             Debug debug = new Debug();
 339  
 
 340  0
             wagon.addSessionListener( debug );
 341  
 
 342  0
             wagon.addTransferListener( debug );
 343  
 
 344  0
             if ( proxyInfo != null )
 345  
             {
 346  0
                 log.debug( "connect with proxyInfo" );
 347  0
                 wagon.connect( repository, authenticationInfo, proxyInfo );
 348  
             }
 349  0
             else if ( proxyInfo == null && authenticationInfo != null )
 350  
             {
 351  0
                 log.debug( "connect with authenticationInfo and without proxyInfo" );
 352  0
                 wagon.connect( repository, authenticationInfo );
 353  
             }
 354  
             else
 355  
             {
 356  0
                 log.debug( "connect without authenticationInfo and without proxyInfo" );
 357  0
                 wagon.connect( repository );
 358  
             }
 359  
 
 360  0
             log.info( "Pushing " + inputDirectory );
 361  
 
 362  
             // Default is first in the list
 363  0
             final String defaultLocale = localesList.get( 0 ).getLanguage();
 364  
 
 365  0
             for ( Locale locale : localesList )
 366  
             {
 367  0
                 if ( locale.getLanguage().equals( defaultLocale ) )
 368  
                 {
 369  
                     // TODO: this also uploads the non-default locales,
 370  
                     // is there a way to exclude directories in wagon?
 371  0
                     log.info( "   >>> to " + repository.getUrl() + relativeDir );
 372  
 
 373  0
                     wagon.putDirectory( inputDirectory, relativeDir );
 374  
                 }
 375  
                 else
 376  
                 {
 377  0
                     log.info( "   >>> to " + repository.getUrl() + locale.getLanguage() + "/" + relativeDir );
 378  
 
 379  0
                     wagon.putDirectory( new File( inputDirectory, locale.getLanguage() ),
 380  
                         locale.getLanguage() + "/" + relativeDir );
 381  
                 }
 382  
             }
 383  
         }
 384  0
         catch ( ResourceDoesNotExistException e )
 385  
         {
 386  0
             throw new MojoExecutionException( "Error uploading site", e );
 387  
         }
 388  0
         catch ( TransferFailedException e )
 389  
         {
 390  0
             throw new MojoExecutionException( "Error uploading site", e );
 391  
         }
 392  0
         catch ( AuthorizationException e )
 393  
         {
 394  0
             throw new MojoExecutionException( "Error uploading site", e );
 395  
         }
 396  0
         catch ( ConnectionException e )
 397  
         {
 398  0
             throw new MojoExecutionException( "Error uploading site", e );
 399  
         }
 400  0
         catch ( AuthenticationException e )
 401  
         {
 402  0
             throw new MojoExecutionException( "Error uploading site", e );
 403  0
         }
 404  0
     }
 405  
 
 406  
     private static void chmod( final Wagon wagon, final Repository repository,
 407  
         final String chmodOptions, final String chmodMode )
 408  
         throws MojoExecutionException
 409  
     {
 410  
         try
 411  
         {
 412  0
             if ( wagon instanceof CommandExecutor )
 413  
             {
 414  0
                 CommandExecutor exec = (CommandExecutor) wagon;
 415  0
                 exec.executeCommand( "chmod " + chmodOptions + " " + chmodMode + " " + repository.getBasedir() );
 416  
             }
 417  
             // else ? silently ignore, FileWagon is not a CommandExecutor!
 418  
         }
 419  0
         catch ( CommandExecutionException e )
 420  
         {
 421  0
             throw new MojoExecutionException( "Error uploading site", e );
 422  0
         }
 423  0
     }
 424  
 
 425  
     /**
 426  
      * <p>
 427  
      * Get the <code>ProxyInfo</code> of the proxy associated with the <code>host</code>
 428  
      * and the <code>protocol</code> of the given <code>repository</code>.
 429  
      * </p>
 430  
      * <p>
 431  
      * Extract from <a href="http://java.sun.com/j2se/1.5.0/docs/guide/net/properties.html">
 432  
      * J2SE Doc : Networking Properties - nonProxyHosts</a> : "The value can be a list of hosts,
 433  
      * each separated by a |, and in addition a wildcard character (*) can be used for matching"
 434  
      * </p>
 435  
      * <p>
 436  
      * Defensively support for comma (",") and semi colon (";") in addition to pipe ("|") as separator.
 437  
      * </p>
 438  
      *
 439  
      * @param repository the Repository to extract the ProxyInfo from.
 440  
      * @param wagonManager the WagonManager used to connect to the Repository.
 441  
      * @return a ProxyInfo object instantiated or <code>null</code> if no matching proxy is found
 442  
      */
 443  
     public static ProxyInfo getProxyInfo( Repository repository, WagonManager wagonManager )
 444  
     {
 445  11
         ProxyInfo proxyInfo = wagonManager.getProxy( repository.getProtocol() );
 446  
 
 447  11
         if ( proxyInfo == null )
 448  
         {
 449  1
             return null;
 450  
         }
 451  
 
 452  10
         String host = repository.getHost();
 453  10
         String nonProxyHostsAsString = proxyInfo.getNonProxyHosts();
 454  10
         String[] nonProxyHosts = StringUtils.split( nonProxyHostsAsString, ",;|" );
 455  19
         for ( int i = 0; i < nonProxyHosts.length; i++ )
 456  
         {
 457  13
             String nonProxyHost = nonProxyHosts[i];
 458  13
             if ( StringUtils.contains( nonProxyHost, "*" ) )
 459  
             {
 460  
                 // Handle wildcard at the end, beginning or middle of the nonProxyHost
 461  8
                 final int pos = nonProxyHost.indexOf( '*' );
 462  8
                 String nonProxyHostPrefix = nonProxyHost.substring( 0, pos );
 463  8
                 String nonProxyHostSuffix = nonProxyHost.substring( pos + 1 );
 464  
                 // prefix*
 465  8
                 if ( StringUtils.isNotEmpty( nonProxyHostPrefix ) && host.startsWith( nonProxyHostPrefix )
 466  
                     && StringUtils.isEmpty( nonProxyHostSuffix ) )
 467  
                 {
 468  1
                     return null;
 469  
                 }
 470  
                 // *suffix
 471  7
                 if ( StringUtils.isEmpty( nonProxyHostPrefix )
 472  
                     && StringUtils.isNotEmpty( nonProxyHostSuffix ) && host.endsWith( nonProxyHostSuffix ) )
 473  
                 {
 474  1
                     return null;
 475  
                 }
 476  
                 // prefix*suffix
 477  6
                 if ( StringUtils.isNotEmpty( nonProxyHostPrefix ) && host.startsWith( nonProxyHostPrefix )
 478  
                     && StringUtils.isNotEmpty( nonProxyHostSuffix ) && host.endsWith( nonProxyHostSuffix ) )
 479  
                 {
 480  1
                     return null;
 481  
                 }
 482  5
             }
 483  5
             else if ( host.equals( nonProxyHost ) )
 484  
             {
 485  1
                 return null;
 486  
             }
 487  
         }
 488  6
         return proxyInfo;
 489  
     }
 490  
 
 491  
     /**
 492  
      * Configure the Wagon with the information from serverConfigurationMap ( which comes from settings.xml )
 493  
      *
 494  
      * @todo Remove when {@link WagonManager#getWagon(Repository) is available}. It's available in Maven 2.0.5.
 495  
      * @param wagon
 496  
      * @param repositoryId
 497  
      * @param settings
 498  
      * @param container
 499  
      * @param log
 500  
      * @throws WagonConfigurationException
 501  
      */
 502  
     private static void configureWagon( Wagon wagon, String repositoryId, Settings settings, PlexusContainer container,
 503  
                                         Log log )
 504  
         throws WagonConfigurationException
 505  
     {
 506  0
         log.debug( " configureWagon " );
 507  
 
 508  
         // MSITE-25: Make sure that the server settings are inserted
 509  0
         for ( int i = 0; i < settings.getServers().size(); i++ )
 510  
         {
 511  0
             Server server = settings.getServers().get( i );
 512  0
             String id = server.getId();
 513  
 
 514  0
             log.debug( "configureWagon server " + id );
 515  
 
 516  0
             if ( id != null && id.equals( repositoryId ) )
 517  
             {
 518  0
                 if ( server.getConfiguration() != null )
 519  
                 {
 520  0
                     final PlexusConfiguration plexusConf =
 521  
                         new XmlPlexusConfiguration( (Xpp3Dom) server.getConfiguration() );
 522  
 
 523  0
                     ComponentConfigurator componentConfigurator = null;
 524  
                     try
 525  
                     {
 526  0
                         componentConfigurator = (ComponentConfigurator) container.lookup( ComponentConfigurator.ROLE );
 527  0
                         componentConfigurator.configureComponent( wagon, plexusConf, container.getContainerRealm() );
 528  
                     }
 529  0
                     catch ( final ComponentLookupException e )
 530  
                     {
 531  0
                         throw new WagonConfigurationException( repositoryId, "Unable to lookup wagon configurator."
 532  
                             + " Wagon configuration cannot be applied.", e );
 533  
                     }
 534  0
                     catch ( ComponentConfigurationException e )
 535  
                     {
 536  0
                         throw new WagonConfigurationException( repositoryId, "Unable to apply wagon configuration.",
 537  
                             e );
 538  
                     }
 539  
                     finally
 540  
                     {
 541  0
                         if ( componentConfigurator != null )
 542  
                         {
 543  
                             try
 544  
                             {
 545  0
                                 container.release( componentConfigurator );
 546  
                             }
 547  0
                             catch ( ComponentLifecycleException e )
 548  
                             {
 549  0
                                 log.error( "Problem releasing configurator - ignoring: " + e.getMessage() );
 550  0
                             }
 551  
                         }
 552  
                     }
 553  
                 }
 554  
             }
 555  
         }
 556  0
     }
 557  
 
 558  
     /** {@inheritDoc} */
 559  
     public void contextualize( Context context )
 560  
         throws ContextException
 561  
     {
 562  0
         container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
 563  0
     }
 564  
 
 565  
     /**
 566  
      * Find the top level parent in the reactor, i.e. the execution root.
 567  
      *
 568  
      * @param reactorProjects The projects in the reactor. May be null in which case null is returnned.
 569  
      *
 570  
      * @return The top level project in the reactor, or <code>null</code> if none can be found
 571  
      */
 572  
     private static MavenProject getTopLevelProject( List<MavenProject> reactorProjects )
 573  
     {
 574  0
         if ( reactorProjects == null )
 575  
         {
 576  0
             return null;
 577  
         }
 578  
 
 579  0
         for ( MavenProject reactorProject : reactorProjects )
 580  
         {
 581  0
             if ( reactorProject.isExecutionRoot() )
 582  
             {
 583  0
                 return reactorProject;
 584  
             }
 585  
         }
 586  
 
 587  0
         return null;
 588  
     }
 589  
 
 590  
     /**
 591  
      * Extract the distributionManagment site from the given MavenProject.
 592  
      *
 593  
      * @param project the MavenProject. Not null.
 594  
      *
 595  
      * @return the project site. Not null.
 596  
      *      Also site.getUrl() and site.getId() are guaranteed to be not null.
 597  
      *
 598  
      * @throws MojoExecutionException if any of the site info is missing.
 599  
      */
 600  
     protected static Site getSite( final MavenProject project )
 601  
         throws MojoExecutionException
 602  
     {
 603  0
         final String name = project.getName() + " ("
 604  
             + project.getGroupId() + ":" + project.getArtifactId() + ":" + project.getVersion() + ")";
 605  
 
 606  0
         final DistributionManagement distributionManagement = project.getDistributionManagement();
 607  
 
 608  0
         if ( distributionManagement == null )
 609  
         {
 610  0
             throw new MojoExecutionException( "Missing distribution management in project " + name );
 611  
         }
 612  
 
 613  0
         final Site site = distributionManagement.getSite();
 614  
 
 615  0
         if ( site == null )
 616  
         {
 617  0
             throw new MojoExecutionException(
 618  
                 "Missing site information in the distribution management of the project " + name );
 619  
         }
 620  
 
 621  0
         if ( site.getUrl() == null || site.getId() == null )
 622  
         {
 623  0
             throw new MojoExecutionException( "Missing site data: specify url and id for project " + name );
 624  
         }
 625  
 
 626  0
         return site;
 627  
     }
 628  
 
 629  
     /**
 630  
      * Extract the distributionManagment site of the top level parent of the given MavenProject.
 631  
      * This climbs up the project hierarchy and returns the site of the last project
 632  
      * for which {@link #getSite(org.apache.maven.project.MavenProject)} returns a site.
 633  
      *
 634  
      * @param project the MavenProject. Not null.
 635  
      *
 636  
      * @return the top level site. Not null.
 637  
      *      Also site.getUrl() and site.getId() are guaranteed to be not null.
 638  
      *
 639  
      * @throws MojoExecutionException if no site info is found in the tree.
 640  
      */
 641  
     protected static Site getRootSite( MavenProject project )
 642  
         throws MojoExecutionException
 643  
     {
 644  0
         Site site = getSite( project );
 645  
 
 646  0
         MavenProject parent = project;
 647  
 
 648  0
         while ( parent.getParent() != null )
 649  
         {
 650  0
             parent = parent.getParent();
 651  
 
 652  
             try
 653  
             {
 654  0
                 site = getSite( parent );
 655  
             }
 656  0
             catch ( MojoExecutionException e )
 657  
             {
 658  0
                 break;
 659  0
             }
 660  
         }
 661  
 
 662  0
         return site;
 663  
     }
 664  
 }