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