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