Coverage Report - org.apache.maven.project.artifact.MavenMetadataSource
 
Classes in this File Line Coverage Branch Coverage Complexity
MavenMetadataSource
53 %
93/176
44 %
44/100
9
MavenMetadataSource$1
N/A
N/A
9
MavenMetadataSource$ProjectRelocation
100 %
1/1
N/A
9
 
 1  
 package org.apache.maven.project.artifact;
 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.util.ArrayList;
 24  
 import java.util.Collections;
 25  
 import java.util.HashSet;
 26  
 import java.util.Iterator;
 27  
 import java.util.LinkedHashSet;
 28  
 import java.util.List;
 29  
 import java.util.Set;
 30  
 
 31  
 import org.apache.maven.artifact.Artifact;
 32  
 import org.apache.maven.artifact.factory.ArtifactFactory;
 33  
 import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
 34  
 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
 35  
 import org.apache.maven.artifact.metadata.ResolutionGroup;
 36  
 import org.apache.maven.artifact.repository.ArtifactRepository;
 37  
 import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata;
 38  
 import org.apache.maven.artifact.repository.metadata.Metadata;
 39  
 import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
 40  
 import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
 41  
 import org.apache.maven.artifact.repository.metadata.RepositoryMetadataResolutionException;
 42  
 import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
 43  
 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
 44  
 import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
 45  
 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
 46  
 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
 47  
 import org.apache.maven.artifact.versioning.VersionRange;
 48  
 import org.apache.maven.model.Dependency;
 49  
 import org.apache.maven.model.DistributionManagement;
 50  
 import org.apache.maven.model.Exclusion;
 51  
 import org.apache.maven.model.Relocation;
 52  
 import org.apache.maven.project.DefaultProjectBuilderConfiguration;
 53  
 import org.apache.maven.project.InvalidProjectModelException;
 54  
 import org.apache.maven.project.MavenProject;
 55  
 import org.apache.maven.project.MavenProjectBuilder;
 56  
 import org.apache.maven.project.ProjectBuildingException;
 57  
 import org.apache.maven.project.validation.ModelValidationResult;
 58  
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 59  
 import org.codehaus.plexus.util.StringUtils;
 60  
 
 61  
 /**
 62  
  * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
 63  
  * @author <a href="mailto:brett@apache.org">Brett Porter</a>
 64  
  * @version $Id: MavenMetadataSource.java 736547 2009-01-22 03:57:09Z jdcasey $
 65  
  */
 66  13
 public class MavenMetadataSource
 67  
     extends AbstractLogEnabled
 68  
     implements ArtifactMetadataSource
 69  
 {
 70  
     public static final String ROLE_HINT = "maven";
 71  
 
 72  
     private MavenProjectBuilder mavenProjectBuilder;
 73  
 
 74  
     private ArtifactFactory artifactFactory;
 75  
 
 76  
     private RepositoryMetadataManager repositoryMetadataManager;
 77  
 
 78  
     // lazily instantiated and cached.
 79  
     private MavenProject superProject;
 80  
     
 81  13
     private Set warnedPoms = new HashSet();
 82  
 
 83  
     /**
 84  
      * Resolve all relocations in the POM for this artifact, and return the new artifact coordinate.
 85  
      */
 86  
     public Artifact retrieveRelocatedArtifact( Artifact artifact, ArtifactRepository localRepository, List remoteRepositories )
 87  
         throws ArtifactMetadataRetrievalException
 88  
     {
 89  48
         if ( artifact instanceof ActiveProjectArtifact )
 90  
         {
 91  0
             return artifact;
 92  
         }
 93  
 
 94  48
         ProjectRelocation rel = retrieveRelocatedProject( artifact, localRepository, remoteRepositories );
 95  
         
 96  48
         if ( rel == null )
 97  
         {
 98  0
             return artifact;
 99  
         }
 100  
         
 101  48
         MavenProject project = rel.project;
 102  48
         if ( project == null || getRelocationKey( artifact ).equals( getRelocationKey( project.getArtifact() ) ) )
 103  
         {
 104  48
             return artifact;
 105  
         }
 106  
 
 107  
         
 108  
         // NOTE: Using artifact information here, since some POMs are deployed 
 109  
         // to central with one version in the filename, but another in the <version> string!
 110  
         // Case in point: org.apache.ws.commons:XmlSchema:1.1:pom.
 111  
         //
 112  
         // Since relocation triggers a reconfiguration of the artifact's information
 113  
         // in retrieveRelocatedProject(..), this is safe to do.
 114  0
         Artifact result = null;
 115  0
         if ( artifact.getClassifier() != null )
 116  
         {
 117  0
             result = artifactFactory.createArtifactWithClassifier( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), artifact.getType(), artifact.getClassifier() );
 118  
         }
 119  
         else
 120  
         {
 121  0
             result = artifactFactory.createArtifact( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), artifact.getScope(), artifact.getType() );
 122  
         }
 123  
 
 124  0
         result.setResolved( artifact.isResolved() );
 125  0
         result.setFile( artifact.getFile() );
 126  
 
 127  0
         result.setScope( artifact.getScope() );
 128  0
         result.setArtifactHandler( artifact.getArtifactHandler() );
 129  0
         result.setDependencyFilter( artifact.getDependencyFilter() );
 130  0
         result.setDependencyTrail( artifact.getDependencyTrail() );
 131  0
         result.setOptional( artifact.isOptional() );
 132  0
         result.setRelease( artifact.isRelease() );
 133  
 
 134  0
         return result;
 135  
     }
 136  
 
 137  
     private String getRelocationKey( Artifact artifact )
 138  
     {
 139  96
         return artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion();
 140  
     }
 141  
 
 142  
     private ProjectRelocation retrieveRelocatedProject( Artifact artifact, ArtifactRepository localRepository, List remoteRepositories )
 143  
         throws ArtifactMetadataRetrievalException
 144  
     {
 145  96
         MavenProject project = null;
 146  
 
 147  
         Artifact pomArtifact;
 148  96
         boolean done = false;
 149  
         do
 150  
         {
 151  
             // TODO: can we just modify the original?
 152  96
             pomArtifact = artifactFactory.createProjectArtifact( artifact.getGroupId(), artifact.getArtifactId(),
 153  
                                                                  artifact.getVersion(), artifact.getScope() );
 154  
 
 155  96
             if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
 156  
             {
 157  0
                 done = true;
 158  
             }
 159  
             else
 160  
             {
 161  
                 try
 162  
                 {
 163  96
                     project = mavenProjectBuilder.buildFromRepository( pomArtifact, remoteRepositories, localRepository,
 164  
                                                                        true );
 165  
                 }
 166  0
                 catch ( InvalidProjectModelException e )
 167  
                 {
 168  0
                     String id = pomArtifact.getId();
 169  
                     
 170  0
                     if ( !warnedPoms.contains( id ) )
 171  
                     {
 172  0
                         warnedPoms.add( pomArtifact.getId() );
 173  
 
 174  0
                         getLogger().warn( "POM for \'"
 175  
                                               + pomArtifact
 176  
                                               + "\' is invalid.\n\nIts dependencies (if any) will NOT be available to the current build." );
 177  
 
 178  0
                         if ( getLogger().isDebugEnabled() )
 179  
                         {
 180  0
                             getLogger().debug( "Reason: " + e.getMessage() );
 181  
 
 182  0
                             ModelValidationResult validationResult = e.getValidationResult();
 183  
 
 184  0
                             if ( validationResult != null )
 185  
                             {
 186  0
                                 getLogger().debug( "\nValidation Errors:" );
 187  0
                                 for ( Iterator i = validationResult.getMessages().iterator(); i.hasNext(); )
 188  
                                 {
 189  0
                                     getLogger().debug( i.next().toString() );
 190  
                                 }
 191  0
                                 getLogger().debug( "\n" );
 192  
                             }
 193  
                         }
 194  
                     }
 195  
 
 196  0
                     project = null;
 197  
                 }
 198  0
                 catch ( ProjectBuildingException e )
 199  
                 {
 200  0
                     throw new ArtifactMetadataRetrievalException( "Unable to read the metadata file for artifact '" +
 201  
                         artifact.getDependencyConflictId() + "': " + e.getMessage(), e, artifact );
 202  96
                 }
 203  
 
 204  96
                 if ( project != null )
 205  
                 {
 206  96
                     Relocation relocation = null;
 207  
 
 208  96
                     DistributionManagement distMgmt = project.getDistributionManagement();
 209  96
                     if ( distMgmt != null )
 210  
                     {
 211  0
                         relocation = distMgmt.getRelocation();
 212  
 
 213  0
                         artifact.setDownloadUrl( distMgmt.getDownloadUrl() );
 214  0
                         pomArtifact.setDownloadUrl( distMgmt.getDownloadUrl() );
 215  
                     }
 216  
 
 217  96
                     if ( relocation != null )
 218  
                     {
 219  0
                         if ( relocation.getGroupId() != null )
 220  
                         {
 221  0
                             artifact.setGroupId( relocation.getGroupId() );
 222  0
                             project.setGroupId( relocation.getGroupId() );
 223  
                         }
 224  0
                         if ( relocation.getArtifactId() != null )
 225  
                         {
 226  0
                             artifact.setArtifactId( relocation.getArtifactId() );
 227  0
                             project.setArtifactId( relocation.getArtifactId() );
 228  
                         }
 229  0
                         if ( relocation.getVersion() != null )
 230  
                         {
 231  
                             //note: see MNG-3454. This causes a problem, but fixing it may break more.
 232  0
                             artifact.setVersionRange( VersionRange.createFromVersion( relocation.getVersion() ) );
 233  0
                             project.setVersion( relocation.getVersion() );
 234  
                         }
 235  
 
 236  0
                         if ( artifact.getDependencyFilter() != null &&
 237  
                             !artifact.getDependencyFilter().include( artifact ) )
 238  
                         {
 239  0
                             return null;
 240  
                         }
 241  
 
 242  
                         //MNG-2861: the artifact data has changed. If the available versions where previously retrieved,
 243  
                         //we need to update it. TODO: shouldn't the versions be merged across relocations?
 244  0
                         List available = artifact.getAvailableVersions();
 245  0
                         if ( available != null && !available.isEmpty() )
 246  
                         {
 247  0
                             artifact.setAvailableVersions( retrieveAvailableVersions( artifact, localRepository,
 248  
                                                                                            remoteRepositories ) );
 249  
 
 250  
                         }
 251  
 
 252  0
                         String message = "\n  This artifact has been relocated to " + artifact.getGroupId() + ":" +
 253  
                             artifact.getArtifactId() + ":" + artifact.getVersion() + ".\n";
 254  
 
 255  0
                         if ( relocation.getMessage() != null )
 256  
                         {
 257  0
                             message += "  " + relocation.getMessage() + "\n";
 258  
                         }
 259  
 
 260  0
                         if ( artifact.getDependencyTrail() != null && artifact.getDependencyTrail().size() == 1 )
 261  
                         {
 262  0
                             getLogger().warn( "While downloading " + pomArtifact.getGroupId() + ":" +
 263  
                                 pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion() + message + "\n" );
 264  
                         }
 265  
                         else
 266  
                         {
 267  0
                             getLogger().debug( "While downloading " + pomArtifact.getGroupId() + ":" +
 268  
                                 pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion() + message + "\n" );
 269  
                         }
 270  0
                     }
 271  
                     else
 272  
                     {
 273  96
                         done = true;
 274  
                     }
 275  96
                 }
 276  
                 else
 277  
                 {
 278  0
                     done = true;
 279  
                 }
 280  
             }
 281  
         }
 282  96
         while ( !done );
 283  
 
 284  96
         ProjectRelocation rel = new ProjectRelocation();
 285  96
         rel.project = project;
 286  96
         rel.pomArtifact = pomArtifact;
 287  
         
 288  96
         return rel;
 289  
     }
 290  
 
 291  
     /**
 292  
      * Retrieve the metadata for the project from the repository.
 293  
      * Uses the ProjectBuilder, to enable post-processing and inheritance calculation before retrieving the
 294  
      * associated artifacts.
 295  
      */
 296  
     public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository, List remoteRepositories )
 297  
         throws ArtifactMetadataRetrievalException
 298  
     {
 299  48
         ProjectRelocation rel = retrieveRelocatedProject( artifact, localRepository, remoteRepositories );
 300  
         
 301  48
         if ( rel == null )
 302  
         {
 303  0
             return null;
 304  
         }
 305  
         
 306  48
         MavenProject project = rel.project;
 307  48
         Artifact pomArtifact = rel.pomArtifact;
 308  
 
 309  
         // last ditch effort to try to get this set...
 310  48
         if ( artifact.getDownloadUrl() == null && pomArtifact != null )
 311  
         {
 312  
             // TODO: this could come straight from the project, negating the need to set it in the project itself?
 313  48
             artifact.setDownloadUrl( pomArtifact.getDownloadUrl() );
 314  
         }
 315  
 
 316  
         ResolutionGroup result;
 317  
 
 318  48
         if ( project == null )
 319  
         {
 320  
             // if the project is null, we encountered an invalid model (read: m1 POM)
 321  
             // we'll just return an empty resolution group.
 322  
             // or used the inherited scope (should that be passed to the buildFromRepository method above?)
 323  0
             result = new ResolutionGroup( pomArtifact, Collections.EMPTY_SET, Collections.EMPTY_LIST );
 324  
         }
 325  
         else
 326  
         {
 327  48
             Set artifacts = Collections.EMPTY_SET;
 328  48
             if ( !artifact.getArtifactHandler().isIncludesDependencies() )
 329  
             {
 330  
                 // TODO: we could possibly use p.getDependencyArtifacts instead of this call, but they haven't been filtered
 331  
                 // or used the inherited scope (should that be passed to the buildFromRepository method above?)
 332  
                 try
 333  
                 {
 334  48
                     artifacts = project.createArtifacts( artifactFactory, artifact.getScope(),
 335  
                                                          artifact.getDependencyFilter() );
 336  
                 }
 337  0
                 catch ( InvalidDependencyVersionException e )
 338  
                 {
 339  0
                     throw new ArtifactMetadataRetrievalException( "Error in metadata for artifact '" +
 340  
                         artifact.getDependencyConflictId() + "': " + e.getMessage(), e );
 341  48
                 }
 342  
             }
 343  
 
 344  48
             List repositories = aggregateRepositoryLists( remoteRepositories, project.getRemoteArtifactRepositories() );
 345  
 
 346  48
             result = new ResolutionGroup( pomArtifact, artifacts, repositories );
 347  
         }
 348  
 
 349  48
         return result;
 350  
     }
 351  
 
 352  
     private List aggregateRepositoryLists( List remoteRepositories, List remoteArtifactRepositories )
 353  
         throws ArtifactMetadataRetrievalException
 354  
     {
 355  48
         if ( superProject == null )
 356  
         {
 357  
             try
 358  
             {
 359  10
                 superProject = mavenProjectBuilder.buildStandaloneSuperProject( new DefaultProjectBuilderConfiguration() );
 360  
             }
 361  0
             catch ( ProjectBuildingException e )
 362  
             {
 363  0
                 throw new ArtifactMetadataRetrievalException(
 364  
                     "Unable to parse the Maven built-in model: " + e.getMessage(), e );
 365  10
             }
 366  
         }
 367  
 
 368  48
         List repositories = new ArrayList();
 369  
 
 370  48
         repositories.addAll( remoteRepositories );
 371  
 
 372  
         // ensure that these are defined
 373  48
         for ( Iterator it = superProject.getRemoteArtifactRepositories().iterator(); it.hasNext(); )
 374  
         {
 375  48
             ArtifactRepository superRepo = (ArtifactRepository) it.next();
 376  
 
 377  48
             for ( Iterator aggregatedIterator = repositories.iterator(); aggregatedIterator.hasNext(); )
 378  
             {
 379  48
                 ArtifactRepository repo = (ArtifactRepository) aggregatedIterator.next();
 380  
 
 381  
                 // if the repository exists in the list and was introduced by another POM's super-pom,
 382  
                 // remove it...the repository definitions from the super-POM should only be at the end of
 383  
                 // the list.
 384  
                 // if the repository has been redefined, leave it.
 385  48
                 if ( repo.getId().equals( superRepo.getId() ) && repo.getUrl().equals( superRepo.getUrl() ) )
 386  
                 {
 387  33
                     aggregatedIterator.remove();
 388  
                 }
 389  48
             }
 390  48
         }
 391  
 
 392  
         // this list should contain the super-POM repositories, so we don't have to explicitly add them back.
 393  48
         for ( Iterator it = remoteArtifactRepositories.iterator(); it.hasNext(); )
 394  
         {
 395  48
             ArtifactRepository repository = (ArtifactRepository) it.next();
 396  
 
 397  48
             if ( !repositories.contains( repository ) )
 398  
             {
 399  33
                 repositories.add( repository );
 400  
             }
 401  48
         }
 402  
 
 403  48
         return repositories;
 404  
     }
 405  
 
 406  
     /**
 407  
      * @todo desperately needs refactoring. It's just here because it's implementation is maven-project specific
 408  
      * @return {@link Set} &lt; {@link Artifact} >
 409  
      */
 410  
     public static Set createArtifacts( ArtifactFactory artifactFactory, List dependencies, String inheritedScope,
 411  
                                        ArtifactFilter dependencyFilter, MavenProject project )
 412  
         throws InvalidDependencyVersionException
 413  
     {
 414  79
         Set projectArtifacts = new LinkedHashSet( dependencies.size() );
 415  
 
 416  79
         for ( Iterator i = dependencies.iterator(); i.hasNext(); )
 417  
         {
 418  73
             Dependency d = (Dependency) i.next();
 419  
 
 420  73
             String scope = d.getScope();
 421  
 
 422  73
             if ( StringUtils.isEmpty( scope ) )
 423  
             {
 424  33
                 scope = Artifact.SCOPE_COMPILE;
 425  
 
 426  33
                 d.setScope( scope );
 427  
             }
 428  
 
 429  
             VersionRange versionRange;
 430  
             try
 431  
             {
 432  73
                 versionRange = VersionRange.createFromVersionSpec( d.getVersion() );
 433  
             }
 434  0
             catch ( InvalidVersionSpecificationException e )
 435  
             {
 436  0
                 throw new InvalidDependencyVersionException( "Unable to parse version '" + d.getVersion() +
 437  
                     "' for dependency '" + d.getManagementKey() + "': " + e.getMessage(), e );
 438  73
             }
 439  73
             Artifact artifact = artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(),
 440  
                                                                           versionRange, d.getType(), d.getClassifier(),
 441  
                                                                           scope, inheritedScope, d.isOptional() );
 442  
 
 443  73
             if ( Artifact.SCOPE_SYSTEM.equals( scope ) )
 444  
             {
 445  0
                 artifact.setFile( new File( d.getSystemPath() ) );
 446  
             }
 447  
 
 448  73
             ArtifactFilter artifactFilter = dependencyFilter;
 449  
 
 450  
             // MNG-3769: It would be nice to be able to process relocations here, 
 451  
             // so we could have this filtering step apply to post-relocated dependencies.
 452  
             // HOWEVER, this would require a much more invasive POM resolution process
 453  
             // in order to look for relocations, which would make the early steps in 
 454  
             // a Maven build way too heavy.
 455  73
             if ( artifact != null && ( artifactFilter == null || artifactFilter.include( artifact ) ) )
 456  
             {
 457  71
                 if ( d.getExclusions() != null && !d.getExclusions().isEmpty() )
 458  
                 {
 459  1
                     List exclusions = new ArrayList();
 460  1
                     for ( Iterator j = d.getExclusions().iterator(); j.hasNext(); )
 461  
                     {
 462  1
                         Exclusion e = (Exclusion) j.next();
 463  1
                         exclusions.add( e.getGroupId() + ":" + e.getArtifactId() );
 464  1
                     }
 465  
 
 466  1
                     ArtifactFilter newFilter = new ExcludesArtifactFilter( exclusions );
 467  
 
 468  1
                     if ( artifactFilter != null )
 469  
                     {
 470  1
                         AndArtifactFilter filter = new AndArtifactFilter();
 471  1
                         filter.add( artifactFilter );
 472  1
                         filter.add( newFilter );
 473  1
                         artifactFilter = filter;
 474  1
                     }
 475  
                     else
 476  
                     {
 477  0
                         artifactFilter = newFilter;
 478  
                     }
 479  
                 }
 480  
 
 481  71
                 artifact.setDependencyFilter( artifactFilter );
 482  
 
 483  71
                 if ( project != null )
 484  
                 {
 485  71
                     artifact = project.replaceWithActiveArtifact( artifact );
 486  
                 }
 487  
 
 488  71
                 projectArtifacts.add( artifact );
 489  
             }
 490  73
         }
 491  
 
 492  79
         return projectArtifacts;
 493  
     }
 494  
 
 495  
     public List retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository,
 496  
                                            List remoteRepositories )
 497  
         throws ArtifactMetadataRetrievalException
 498  
     {
 499  0
         RepositoryMetadata metadata = new ArtifactRepositoryMetadata( artifact );
 500  
         try
 501  
         {
 502  0
             repositoryMetadataManager.resolve( metadata, remoteRepositories, localRepository );
 503  
         }
 504  0
         catch ( RepositoryMetadataResolutionException e )
 505  
         {
 506  0
             throw new ArtifactMetadataRetrievalException( e.getMessage(), e );
 507  0
         }
 508  
 
 509  
         List versions;
 510  0
         Metadata repoMetadata = metadata.getMetadata();
 511  0
         if ( repoMetadata != null && repoMetadata.getVersioning() != null )
 512  
         {
 513  0
             List metadataVersions = repoMetadata.getVersioning().getVersions();
 514  0
             versions = new ArrayList( metadataVersions.size() );
 515  0
             for ( Iterator i = metadataVersions.iterator(); i.hasNext(); )
 516  
             {
 517  0
                 String version = (String) i.next();
 518  0
                 versions.add( new DefaultArtifactVersion( version ) );
 519  0
             }
 520  0
         }
 521  
         else
 522  
         {
 523  0
             versions = Collections.EMPTY_LIST;
 524  
         }
 525  
 
 526  0
         return versions;
 527  
     }
 528  
     
 529  13
     private static final class ProjectRelocation
 530  
     {
 531  
         private MavenProject project;
 532  
         private Artifact pomArtifact;
 533  
     }
 534  
     
 535  
 }