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