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