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