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