View Javadoc
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.Arrays;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.HashMap;
28  import java.util.LinkedHashMap;
29  import java.util.LinkedHashSet;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Properties;
33  import java.util.Set;
34  
35  import org.apache.maven.RepositoryUtils;
36  import org.apache.maven.artifact.Artifact;
37  import org.apache.maven.artifact.ArtifactUtils;
38  import org.apache.maven.artifact.InvalidRepositoryException;
39  import org.apache.maven.artifact.factory.ArtifactFactory;
40  import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
41  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
42  import org.apache.maven.artifact.metadata.ResolutionGroup;
43  import org.apache.maven.artifact.repository.ArtifactRepository;
44  import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata;
45  import org.apache.maven.artifact.repository.metadata.Metadata;
46  import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
47  import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
48  import org.apache.maven.artifact.repository.metadata.RepositoryMetadataResolutionException;
49  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
50  import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
51  import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
52  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
53  import org.apache.maven.artifact.resolver.filter.ExclusionArtifactFilter;
54  import org.apache.maven.artifact.versioning.ArtifactVersion;
55  import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
56  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
57  import org.apache.maven.artifact.versioning.VersionRange;
58  import org.apache.maven.bridge.MavenRepositorySystem;
59  import org.apache.maven.execution.MavenSession;
60  import org.apache.maven.model.Dependency;
61  import org.apache.maven.model.DependencyManagement;
62  import org.apache.maven.model.DistributionManagement;
63  import org.apache.maven.model.Model;
64  import org.apache.maven.model.Relocation;
65  import org.apache.maven.model.Repository;
66  import org.apache.maven.model.building.ModelBuildingException;
67  import org.apache.maven.model.building.ModelBuildingRequest;
68  import org.apache.maven.model.building.ModelProblem;
69  import org.apache.maven.model.resolution.UnresolvableModelException;
70  import org.apache.maven.plugin.LegacySupport;
71  import org.apache.maven.project.DefaultProjectBuildingRequest;
72  import org.apache.maven.project.MavenProject;
73  import org.apache.maven.project.ProjectBuilder;
74  import org.apache.maven.project.ProjectBuildingException;
75  import org.apache.maven.project.ProjectBuildingRequest;
76  import org.apache.maven.properties.internal.EnvironmentUtils;
77  import org.apache.maven.properties.internal.SystemProperties;
78  import org.apache.maven.repository.internal.MavenWorkspaceReader;
79  import org.apache.maven.repository.legacy.metadata.DefaultMetadataResolutionRequest;
80  import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
81  import org.codehaus.plexus.PlexusContainer;
82  import org.codehaus.plexus.component.annotations.Component;
83  import org.codehaus.plexus.component.annotations.Requirement;
84  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
85  import org.codehaus.plexus.logging.Logger;
86  import org.eclipse.aether.RepositorySystemSession;
87  import org.eclipse.aether.repository.RepositoryPolicy;
88  import org.eclipse.aether.repository.WorkspaceReader;
89  import org.eclipse.aether.transfer.ArtifactNotFoundException;
90  
91  /**
92   * @author Jason van Zyl
93   */
94  @Component( role = ArtifactMetadataSource.class, hint = "maven" )
95  public class MavenMetadataSource
96      implements ArtifactMetadataSource
97  {
98      @Requirement
99      private RepositoryMetadataManager repositoryMetadataManager;
100 
101     @Requirement
102     private ArtifactFactory artifactFactory;
103 
104     @Requirement
105     private MavenRepositorySystem repositorySystem;
106 
107     //TODO This prevents a cycle in the composition which shows us another problem we need to deal with.
108     //@Requirement
109     private ProjectBuilder projectBuilder;
110 
111     @Requirement
112     private PlexusContainer container;
113 
114     @Requirement
115     private Logger logger;
116 
117     @Requirement
118     private MavenMetadataCache cache;
119 
120     @Requirement
121     private LegacySupport legacySupport;
122 
123     private void injectSession( MetadataResolutionRequest request )
124     {
125         RepositorySystemSession session = legacySupport.getRepositorySession();
126 
127         if ( session != null )
128         {
129             request.setOffline( session.isOffline() );
130             request.setForceUpdate( RepositoryPolicy.UPDATE_POLICY_ALWAYS.equals( session.getUpdatePolicy() ) );
131         }
132     }
133 
134     @Override
135     public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
136                                      List<ArtifactRepository> remoteRepositories )
137         throws ArtifactMetadataRetrievalException
138     {
139         return retrieve( artifact, localRepository, remoteRepositories, false );
140     }
141 
142     public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
143                                      List<ArtifactRepository> remoteRepositories, boolean resolveManagedVersions )
144         throws ArtifactMetadataRetrievalException
145     {
146         MetadataResolutionRequest request = new DefaultMetadataResolutionRequest();
147         injectSession( request );
148         request.setArtifact( artifact );
149         request.setLocalRepository( localRepository );
150         request.setRemoteRepositories( remoteRepositories );
151         request.setResolveManagedVersions( resolveManagedVersions );
152         return retrieve( request );
153     }
154 
155     @Override
156     public ResolutionGroup retrieve( MetadataResolutionRequest request )
157         throws ArtifactMetadataRetrievalException
158     {
159         Artifact artifact = request.getArtifact();
160 
161         //
162         // If we have a system scoped artifact then we do not want any searching in local or remote repositories
163         // and we want artifact resolution to only return the system scoped artifact itself.
164         //
165         if ( artifact.getScope() != null && artifact.getScope().equals( Artifact.SCOPE_SYSTEM ) )
166         {
167             return new ResolutionGroup( null, null, null );
168         }
169 
170         ResolutionGroup cached =
171             cache.get( artifact, request.isResolveManagedVersions(), request.getLocalRepository(),
172                        request.getRemoteRepositories() );
173 
174         if ( cached != null
175         // if the POM has no file, we cached a missing artifact, only return the cached data if no update forced
176             && ( !request.isForceUpdate() || hasFile( cached.getPomArtifact() ) ) )
177         {
178             return cached;
179         }
180 
181         List<Dependency> dependencies;
182 
183         List<Dependency> managedDependencies = null;
184 
185         List<ArtifactRepository> pomRepositories = null;
186 
187         Artifact pomArtifact;
188 
189         Artifact relocatedArtifact = null;
190 
191         // TODO hack: don't rebuild model if it was already loaded during reactor resolution
192         RepositorySystemSession repositorySession = legacySupport.getRepositorySession();
193         final WorkspaceReader workspace = repositorySession.getWorkspaceReader();
194         Model model = null;
195         if ( workspace instanceof MavenWorkspaceReader )
196         {
197             model = ( (MavenWorkspaceReader) workspace ).findModel( RepositoryUtils.toArtifact( artifact ) );
198         }
199 
200         if ( model != null )
201         {
202             pomArtifact = artifact;
203             dependencies = model.getDependencies();
204             DependencyManagement dependencyManagement = model.getDependencyManagement();
205             managedDependencies = dependencyManagement == null ? null : dependencyManagement.getDependencies();
206             MavenSession session = legacySupport.getSession();
207             if ( session != null )
208             {
209                 Map<String, MavenProject> projectMap = session.getProjectMap();
210                 MavenProject project = projectMap == null ? null
211                                 : projectMap.get( ArtifactUtils.key( artifact.getGroupId(), artifact.getArtifactId(),
212                                                                      artifact.getVersion() ) );
213                 if ( project == null )
214                 {
215                     // if the project is not on the project map, read the repositories from the model itself!
216                     pomRepositories = getRepositoriesFromModel( repositorySession, model );
217                 }
218                 else
219                 {
220                     pomRepositories = project.getRemoteArtifactRepositories();
221                 }
222             }
223             else
224             {
225                 pomRepositories = new ArrayList<>();
226             }
227         }
228         else if ( artifact instanceof ArtifactWithDependencies )
229         {
230             pomArtifact = artifact;
231 
232             dependencies = ( (ArtifactWithDependencies) artifact ).getDependencies();
233 
234             managedDependencies = ( (ArtifactWithDependencies) artifact ).getManagedDependencies();
235         }
236         else
237         {
238             ProjectRelocation rel = retrieveRelocatedProject( artifact, request );
239 
240             if ( rel == null )
241             {
242                 return null;
243             }
244 
245             pomArtifact = rel.pomArtifact;
246 
247             relocatedArtifact = rel.relocatedArtifact;
248 
249             if ( rel.project == null )
250             {
251                 // When this happens we have a Maven 1.x POM, or some invalid POM.
252                 // It should have never found its way into Maven 2.x repository but it did.
253                 dependencies = Collections.emptyList();
254             }
255             else
256             {
257                 dependencies = rel.project.getDependencies();
258 
259                 DependencyManagement depMgmt = rel.project.getDependencyManagement();
260                 managedDependencies = ( depMgmt != null ) ? depMgmt.getDependencies() : null;
261 
262                 pomRepositories = rel.project.getRemoteArtifactRepositories();
263             }
264         }
265 
266         Set<Artifact> artifacts = Collections.emptySet();
267 
268         if ( !artifact.getArtifactHandler().isIncludesDependencies() )
269         {
270             artifacts = new LinkedHashSet<>();
271 
272             for ( Dependency dependency : dependencies )
273             {
274                 Artifact dependencyArtifact = createDependencyArtifact( dependency, artifact, pomArtifact );
275 
276                 if ( dependencyArtifact != null )
277                 {
278                     artifacts.add( dependencyArtifact );
279                 }
280             }
281         }
282 
283         Map<String, Artifact> managedVersions = null;
284 
285         if ( managedDependencies != null && request.isResolveManagedVersions() )
286         {
287             managedVersions = new HashMap<>();
288 
289             for ( Dependency managedDependency : managedDependencies )
290             {
291                 Artifact managedArtifact = createDependencyArtifact( managedDependency, null, pomArtifact );
292 
293                 managedVersions.put( managedDependency.getManagementKey(), managedArtifact );
294             }
295         }
296 
297         List<ArtifactRepository> aggregatedRepositories =
298             aggregateRepositories( request.getRemoteRepositories(), pomRepositories );
299 
300         ResolutionGroup result =
301             new ResolutionGroup( pomArtifact, relocatedArtifact, artifacts, managedVersions, aggregatedRepositories );
302 
303         cache.put( artifact, request.isResolveManagedVersions(), request.getLocalRepository(),
304                    request.getRemoteRepositories(), result );
305 
306         return result;
307     }
308 
309     private List<ArtifactRepository> getRepositoriesFromModel( RepositorySystemSession repositorySession, Model model )
310     {
311         List<ArtifactRepository> pomRepositories = new ArrayList<>();
312         for ( Repository modelRepository : model.getRepositories() )
313         {
314             try
315             {
316                 pomRepositories.add( MavenRepositorySystem.buildArtifactRepository( modelRepository ) );
317             }
318             catch ( InvalidRepositoryException e )
319             {
320                 // can not use this then
321             }
322         }
323         repositorySystem.injectMirror( repositorySession, pomRepositories );
324         repositorySystem.injectProxy( repositorySession, pomRepositories );
325         repositorySystem.injectAuthentication( repositorySession, pomRepositories );
326         return pomRepositories;
327     }
328 
329     private boolean hasFile( Artifact artifact )
330     {
331         return artifact != null && artifact.getFile() != null && artifact.getFile().exists();
332     }
333 
334     private List<ArtifactRepository> aggregateRepositories( List<ArtifactRepository> requestRepositories,
335                                                             List<ArtifactRepository> pomRepositories )
336     {
337         List<ArtifactRepository> repositories = requestRepositories;
338 
339         if ( pomRepositories != null && !pomRepositories.isEmpty() )
340         {
341             Map<String, ArtifactRepository> repos = new LinkedHashMap<>();
342 
343             for ( ArtifactRepository repo : requestRepositories )
344             {
345                 if ( !repos.containsKey( repo.getId() ) )
346                 {
347                     repos.put( repo.getId(), repo );
348                 }
349             }
350 
351             for ( ArtifactRepository repo : pomRepositories )
352             {
353                 if ( !repos.containsKey( repo.getId() ) )
354                 {
355                     repos.put( repo.getId(), repo );
356                 }
357             }
358 
359             repositories = new ArrayList<>( repos.values() );
360         }
361 
362         return repositories;
363     }
364 
365     private Artifact createDependencyArtifact( Dependency dependency, Artifact owner, Artifact pom )
366         throws ArtifactMetadataRetrievalException
367     {
368         try
369         {
370             String inheritedScope = ( owner != null ) ? owner.getScope() : null;
371 
372             ArtifactFilter inheritedFilter = ( owner != null ) ? owner.getDependencyFilter() : null;
373 
374             return createDependencyArtifact( artifactFactory, dependency, inheritedScope, inheritedFilter );
375         }
376         catch ( InvalidVersionSpecificationException e )
377         {
378             throw new ArtifactMetadataRetrievalException( "Invalid version for dependency "
379                 + dependency.getManagementKey() + ": " + e.getMessage(), e, pom );
380         }
381     }
382 
383     private static Artifact createDependencyArtifact( ArtifactFactory factory, Dependency dependency,
384                                                       String inheritedScope, ArtifactFilter inheritedFilter )
385         throws InvalidVersionSpecificationException
386     {
387         String effectiveScope = getEffectiveScope( dependency.getScope(), inheritedScope );
388 
389         if ( effectiveScope == null )
390         {
391             return null;
392         }
393 
394         VersionRange versionRange = VersionRange.createFromVersionSpec( dependency.getVersion() );
395 
396         Artifact dependencyArtifact =
397             factory.createDependencyArtifact( dependency.getGroupId(), dependency.getArtifactId(), versionRange,
398                                               dependency.getType(), dependency.getClassifier(), effectiveScope,
399                                               dependency.isOptional() );
400 
401         ArtifactFilter dependencyFilter = inheritedFilter;
402 
403         if ( dependencyFilter != null && !dependencyFilter.include( dependencyArtifact ) )
404         {
405             return null;
406         }
407 
408         if ( Artifact.SCOPE_SYSTEM.equals( effectiveScope ) )
409         {
410             dependencyArtifact.setFile( new File( dependency.getSystemPath() ) );
411         }
412 
413         dependencyArtifact.setDependencyFilter( createDependencyFilter( dependency, dependencyFilter ) );
414 
415         return dependencyArtifact;
416     }
417 
418     private static String getEffectiveScope( String originalScope, String inheritedScope )
419     {
420         String effectiveScope = Artifact.SCOPE_RUNTIME;
421 
422         if ( originalScope == null )
423         {
424             originalScope = Artifact.SCOPE_COMPILE;
425         }
426 
427         if ( inheritedScope == null )
428         {
429             // direct dependency retains its scope
430             effectiveScope = originalScope;
431         }
432         else if ( Artifact.SCOPE_TEST.equals( originalScope ) || Artifact.SCOPE_PROVIDED.equals( originalScope ) )
433         {
434             // test and provided are not transitive, so exclude them
435             effectiveScope = null;
436         }
437         else if ( Artifact.SCOPE_SYSTEM.equals( originalScope ) )
438         {
439             // system scope come through unchanged...
440             effectiveScope = Artifact.SCOPE_SYSTEM;
441         }
442         else if ( Artifact.SCOPE_COMPILE.equals( originalScope ) && Artifact.SCOPE_COMPILE.equals( inheritedScope ) )
443         {
444             // added to retain compile scope. Remove if you want compile inherited as runtime
445             effectiveScope = Artifact.SCOPE_COMPILE;
446         }
447         else if ( Artifact.SCOPE_TEST.equals( inheritedScope ) )
448         {
449             effectiveScope = Artifact.SCOPE_TEST;
450         }
451         else if ( Artifact.SCOPE_PROVIDED.equals( inheritedScope ) )
452         {
453             effectiveScope = Artifact.SCOPE_PROVIDED;
454         }
455 
456         return effectiveScope;
457     }
458 
459     private static ArtifactFilter createDependencyFilter( Dependency dependency, ArtifactFilter inheritedFilter )
460     {
461         ArtifactFilter effectiveFilter = inheritedFilter;
462 
463         if ( !dependency.getExclusions().isEmpty() )
464         {
465             effectiveFilter = new ExclusionArtifactFilter( dependency.getExclusions() );
466 
467             if ( inheritedFilter != null )
468             {
469                 effectiveFilter = new AndArtifactFilter( Arrays.asList( inheritedFilter, effectiveFilter ) );
470             }
471         }
472 
473         return effectiveFilter;
474     }
475 
476     @Override
477     public List<ArtifactVersion> retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository,
478                                                             List<ArtifactRepository> remoteRepositories )
479         throws ArtifactMetadataRetrievalException
480     {
481         MetadataResolutionRequest request = new DefaultMetadataResolutionRequest();
482         injectSession( request );
483         request.setArtifact( artifact );
484         request.setLocalRepository( localRepository );
485         request.setRemoteRepositories( remoteRepositories );
486         return retrieveAvailableVersions( request );
487     }
488 
489     @Override
490     public List<ArtifactVersion> retrieveAvailableVersions( MetadataResolutionRequest request )
491         throws ArtifactMetadataRetrievalException
492     {
493         RepositoryMetadata metadata = new ArtifactRepositoryMetadata( request.getArtifact() );
494 
495         try
496         {
497             repositoryMetadataManager.resolve( metadata, request );
498         }
499         catch ( RepositoryMetadataResolutionException e )
500         {
501             throw new ArtifactMetadataRetrievalException( e.getMessage(), e, request.getArtifact() );
502         }
503 
504         List<String> availableVersions = request.getLocalRepository().findVersions( request.getArtifact() );
505 
506         return retrieveAvailableVersionsFromMetadata( metadata.getMetadata(), availableVersions );
507     }
508 
509     @Override
510     public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository( Artifact artifact,
511                                                                                     ArtifactRepository localRepository,
512                                                                               ArtifactRepository deploymentRepository )
513         throws ArtifactMetadataRetrievalException
514     {
515         RepositoryMetadata metadata = new ArtifactRepositoryMetadata( artifact );
516 
517         try
518         {
519             repositoryMetadataManager.resolveAlways( metadata, localRepository, deploymentRepository );
520         }
521         catch ( RepositoryMetadataResolutionException e )
522         {
523             throw new ArtifactMetadataRetrievalException( e.getMessage(), e, artifact );
524         }
525 
526         List<String> availableVersions = localRepository.findVersions( artifact );
527 
528         return retrieveAvailableVersionsFromMetadata( metadata.getMetadata(), availableVersions );
529     }
530 
531     private List<ArtifactVersion> retrieveAvailableVersionsFromMetadata( Metadata repoMetadata,
532                                                                          List<String> availableVersions )
533     {
534         Collection<String> versions = new LinkedHashSet<>();
535 
536         if ( ( repoMetadata != null ) && ( repoMetadata.getVersioning() != null ) )
537         {
538             versions.addAll( repoMetadata.getVersioning().getVersions() );
539         }
540 
541         versions.addAll( availableVersions );
542 
543         List<ArtifactVersion> artifactVersions = new ArrayList<>( versions.size() );
544 
545         for ( String version : versions )
546         {
547             artifactVersions.add( new DefaultArtifactVersion( version ) );
548         }
549 
550         return artifactVersions;
551     }
552 
553     // USED BY MAVEN ASSEMBLY PLUGIN
554     @Deprecated
555     public static Set<Artifact> createArtifacts( ArtifactFactory artifactFactory, List<Dependency> dependencies,
556                                                  String inheritedScope, ArtifactFilter dependencyFilter,
557                                                  MavenProject project )
558         throws InvalidDependencyVersionException
559     {
560         Set<Artifact> artifacts = new LinkedHashSet<>();
561 
562         for ( Dependency d : dependencies )
563         {
564             Artifact dependencyArtifact;
565             try
566             {
567                 dependencyArtifact = createDependencyArtifact( artifactFactory, d, inheritedScope, dependencyFilter );
568             }
569             catch ( InvalidVersionSpecificationException e )
570             {
571                 throw new InvalidDependencyVersionException( project.getId(), d, project.getFile(), e );
572             }
573 
574             if ( dependencyArtifact != null )
575             {
576                 artifacts.add( dependencyArtifact );
577             }
578         }
579 
580         return artifacts;
581     }
582 
583     private ProjectBuilder getProjectBuilder()
584     {
585         if ( projectBuilder != null )
586         {
587             return projectBuilder;
588         }
589 
590         try
591         {
592             projectBuilder = container.lookup( ProjectBuilder.class );
593         }
594         catch ( ComponentLookupException e )
595         {
596             // Won't happen
597         }
598 
599         return projectBuilder;
600     }
601     @SuppressWarnings( "checkstyle:methodlength" )
602     private ProjectRelocation retrieveRelocatedProject( Artifact artifact, MetadataResolutionRequest repositoryRequest )
603         throws ArtifactMetadataRetrievalException
604     {
605         MavenProject project;
606 
607         Artifact pomArtifact;
608         Artifact relocatedArtifact = null;
609         boolean done = false;
610         do
611         {
612             project = null;
613 
614             pomArtifact =
615                 artifactFactory.createProjectArtifact( artifact.getGroupId(),
616                                                         artifact.getArtifactId(),
617                                                         artifact.getVersion(), artifact.getScope() );
618 
619             if ( "pom".equals( artifact.getType() ) )
620             {
621                 pomArtifact.setFile( artifact.getFile() );
622             }
623 
624             if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
625             {
626                 done = true;
627             }
628             else
629             {
630                 try
631                 {
632                     ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
633                     configuration.setLocalRepository( repositoryRequest.getLocalRepository() );
634                     configuration.setRemoteRepositories( repositoryRequest.getRemoteRepositories() );
635                     configuration.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
636                     configuration.setProcessPlugins( false );
637                     configuration.setRepositoryMerging( ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT );
638                     configuration.setSystemProperties( getSystemProperties() );
639                     configuration.setUserProperties( new Properties() );
640                     configuration.setRepositorySession( legacySupport.getRepositorySession() );
641 
642                     project = getProjectBuilder().build( pomArtifact, configuration ).getProject();
643                 }
644                 catch ( ProjectBuildingException e )
645                 {
646                     ModelProblem missingParentPom = hasMissingParentPom( e );
647                     if ( missingParentPom != null )
648                     {
649                         throw new ArtifactMetadataRetrievalException( "Failed to process POM for "
650                             + artifact.getId() + ": " + missingParentPom.getMessage(),
651                                                                       missingParentPom.getException(),
652                                                                       artifact );
653                     }
654 
655                     String message;
656 
657                     if ( isMissingPom( e ) )
658                     {
659                         message = "Missing POM for " + artifact.getId();
660                     }
661                     else if ( isNonTransferrablePom( e ) )
662                     {
663                         throw new ArtifactMetadataRetrievalException( "Failed to retrieve POM for "
664                             + artifact.getId() + ": " + e.getCause().getMessage(), e.getCause(),
665                                                                       artifact );
666                     }
667                     else
668                     {
669                         message =
670                             "Invalid POM for " + artifact.getId()
671                                 + ", transitive dependencies (if any) will not be available"
672                                 + ", enable debug logging for more details";
673                     }
674 
675                     if ( logger.isDebugEnabled() )
676                     {
677                         message += ": " + e.getMessage();
678                     }
679 
680                     logger.warn( message );
681                 }
682 
683                 if ( project != null )
684                 {
685                     Relocation relocation = null;
686 
687                     DistributionManagement distMgmt = project.getDistributionManagement();
688                     if ( distMgmt != null )
689                     {
690                         relocation = distMgmt.getRelocation();
691 
692                         artifact.setDownloadUrl( distMgmt.getDownloadUrl() );
693                         pomArtifact.setDownloadUrl( distMgmt.getDownloadUrl() );
694                     }
695 
696                     if ( relocation != null )
697                     {
698                         if ( relocation.getGroupId() != null )
699                         {
700                             artifact.setGroupId( relocation.getGroupId() );
701                             relocatedArtifact = artifact;
702                             project.setGroupId( relocation.getGroupId() );
703                         }
704                         if ( relocation.getArtifactId() != null )
705                         {
706                             artifact.setArtifactId( relocation.getArtifactId() );
707                             relocatedArtifact = artifact;
708                             project.setArtifactId( relocation.getArtifactId() );
709                         }
710                         if ( relocation.getVersion() != null )
711                         {
712                             // note: see MNG-3454. This causes a problem, but fixing it may break more.
713                             artifact.setVersionRange( VersionRange.createFromVersion( relocation.getVersion() ) );
714                             relocatedArtifact = artifact;
715                             project.setVersion( relocation.getVersion() );
716                         }
717 
718                         if ( artifact.getDependencyFilter() != null
719                             && !artifact.getDependencyFilter().include( artifact ) )
720                         {
721                             return null;
722                         }
723 
724                         // MNG-2861: the artifact data has changed. If the available versions where previously
725                         // retrieved, we need to update it.
726                         // TODO shouldn't the versions be merged across relocations?
727                         List<ArtifactVersion> available = artifact.getAvailableVersions();
728                         if ( available != null && !available.isEmpty() )
729                         {
730                             MetadataResolutionRequest metadataRequest =
731                                 new DefaultMetadataResolutionRequest( repositoryRequest );
732                             metadataRequest.setArtifact( artifact );
733                             available = retrieveAvailableVersions( metadataRequest );
734                             artifact.setAvailableVersions( available );
735                         }
736 
737                         String message =
738                             "\n  This artifact has been relocated to " + artifact.getGroupId() + ":"
739                                 + artifact.getArtifactId() + ":" + artifact.getVersion() + ".\n";
740 
741                         if ( relocation.getMessage() != null )
742                         {
743                             message += "  " + relocation.getMessage() + "\n";
744                         }
745 
746                         if ( artifact.getDependencyTrail() != null && artifact.getDependencyTrail().size() == 1 )
747                         {
748                             logger.warn( "While downloading " + pomArtifact.getGroupId() + ":"
749                                 + pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion() + message + "\n" );
750                         }
751                         else
752                         {
753                             logger.debug( "While downloading " + pomArtifact.getGroupId() + ":"
754                                 + pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion() + message + "\n" );
755                         }
756                     }
757                     else
758                     {
759                         done = true;
760                     }
761                 }
762                 else
763                 {
764                     done = true;
765                 }
766             }
767         }
768         while ( !done );
769 
770         ProjectRelocation rel = new ProjectRelocation();
771         rel.project = project;
772         rel.pomArtifact = pomArtifact;
773         rel.relocatedArtifact = relocatedArtifact;
774 
775         return rel;
776     }
777 
778     private ModelProblem hasMissingParentPom( ProjectBuildingException e )
779     {
780         if ( e.getCause() instanceof ModelBuildingException )
781         {
782             ModelBuildingException mbe = (ModelBuildingException) e.getCause();
783             for ( ModelProblem problem : mbe.getProblems() )
784             {
785                 if ( problem.getException() instanceof UnresolvableModelException )
786                 {
787                     return problem;
788                 }
789             }
790 
791         }
792         return null;
793     }
794 
795     private boolean isMissingPom( Exception e )
796     {
797         if ( e.getCause() instanceof MultipleArtifactsNotFoundException )
798         {
799             return true;
800         }
801         return e.getCause() instanceof org.eclipse.aether.resolution.ArtifactResolutionException
802             && e.getCause().getCause() instanceof ArtifactNotFoundException;
803     }
804 
805     private boolean isNonTransferrablePom( Exception e )
806     {
807         if ( e.getCause() instanceof ArtifactResolutionException )
808         {
809             return true;
810         }
811         return e.getCause() instanceof org.eclipse.aether.resolution.ArtifactResolutionException
812             && !( e.getCause().getCause() instanceof ArtifactNotFoundException );
813     }
814 
815     private Properties getSystemProperties()
816     {
817         Properties props = new Properties();
818 
819         EnvironmentUtils.addEnvVars( props );
820 
821         SystemProperties.addSystemProperties( props );
822 
823         return props;
824     }
825 
826     private static final class ProjectRelocation
827     {
828         private MavenProject project;
829 
830         private Artifact pomArtifact;
831 
832         private Artifact relocatedArtifact;
833     }
834 
835 }