001package org.apache.maven.project.artifact;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.File;
023import java.util.ArrayList;
024import java.util.Arrays;
025import java.util.Collection;
026import java.util.Collections;
027import java.util.HashMap;
028import java.util.LinkedHashMap;
029import java.util.LinkedHashSet;
030import java.util.List;
031import java.util.Map;
032import java.util.Properties;
033import java.util.Set;
034
035import org.apache.maven.artifact.Artifact;
036import org.apache.maven.artifact.factory.ArtifactFactory;
037import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
038import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
039import org.apache.maven.artifact.metadata.ResolutionGroup;
040import org.apache.maven.artifact.repository.ArtifactRepository;
041import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata;
042import org.apache.maven.artifact.repository.metadata.Metadata;
043import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
044import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
045import org.apache.maven.artifact.repository.metadata.RepositoryMetadataResolutionException;
046import org.apache.maven.artifact.resolver.ArtifactResolutionException;
047import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
048import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
049import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
050import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
051import org.apache.maven.artifact.versioning.ArtifactVersion;
052import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
053import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
054import org.apache.maven.artifact.versioning.VersionRange;
055import org.apache.maven.model.Dependency;
056import org.apache.maven.model.DependencyManagement;
057import org.apache.maven.model.DistributionManagement;
058import org.apache.maven.model.Exclusion;
059import org.apache.maven.model.Relocation;
060import org.apache.maven.model.building.ModelBuildingException;
061import org.apache.maven.model.building.ModelBuildingRequest;
062import org.apache.maven.model.building.ModelProblem;
063import org.apache.maven.model.resolution.UnresolvableModelException;
064import org.apache.maven.plugin.LegacySupport;
065import org.apache.maven.project.DefaultProjectBuildingRequest;
066import org.apache.maven.project.MavenProject;
067import org.apache.maven.project.ProjectBuilder;
068import org.apache.maven.project.ProjectBuildingException;
069import org.apache.maven.project.ProjectBuildingRequest;
070import org.apache.maven.properties.internal.EnvironmentUtils;
071import org.apache.maven.properties.internal.SystemProperties;
072import org.apache.maven.repository.legacy.metadata.DefaultMetadataResolutionRequest;
073import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
074import org.codehaus.plexus.PlexusContainer;
075import org.codehaus.plexus.component.annotations.Component;
076import org.codehaus.plexus.component.annotations.Requirement;
077import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
078import org.codehaus.plexus.logging.Logger;
079import org.eclipse.aether.RepositorySystemSession;
080import org.eclipse.aether.repository.RepositoryPolicy;
081import org.eclipse.aether.transfer.ArtifactNotFoundException;
082
083/**
084 * @author Jason van Zyl
085 */
086@Component( role = ArtifactMetadataSource.class, hint = "maven" )
087public class MavenMetadataSource
088    implements ArtifactMetadataSource
089{
090    @Requirement
091    private RepositoryMetadataManager repositoryMetadataManager;
092
093    @Requirement
094    private ArtifactFactory repositorySystem;
095
096    //TODO: This prevents a cycle in the composition which shows us another problem we need to deal with.
097    //@Requirement
098    private ProjectBuilder projectBuilder;
099
100    @Requirement
101    private PlexusContainer container;
102
103    @Requirement
104    private Logger logger;
105
106    @Requirement
107    private MavenMetadataCache cache;
108
109    @Requirement
110    private LegacySupport legacySupport;
111
112    private void injectSession( MetadataResolutionRequest request )
113    {
114        RepositorySystemSession session = legacySupport.getRepositorySession();
115
116        if ( session != null )
117        {
118            request.setOffline( session.isOffline() );
119            request.setForceUpdate( RepositoryPolicy.UPDATE_POLICY_ALWAYS.equals( session.getUpdatePolicy() ) );
120        }
121    }
122
123    public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
124                                     List<ArtifactRepository> remoteRepositories )
125        throws ArtifactMetadataRetrievalException
126    {
127        return retrieve( artifact, localRepository, remoteRepositories, false );
128    }
129
130    public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
131                                     List<ArtifactRepository> remoteRepositories, boolean resolveManagedVersions )
132        throws ArtifactMetadataRetrievalException
133    {
134        MetadataResolutionRequest request = new DefaultMetadataResolutionRequest();
135        injectSession( request );
136        request.setArtifact( artifact );
137        request.setLocalRepository( localRepository );
138        request.setRemoteRepositories( remoteRepositories );
139        request.setResolveManagedVersions( resolveManagedVersions );
140        return retrieve( request );
141    }
142
143    public ResolutionGroup retrieve( MetadataResolutionRequest request )
144        throws ArtifactMetadataRetrievalException
145    {
146        Artifact artifact = request.getArtifact();
147
148        //
149        // If we have a system scoped artifact then we do not want any searching in local or remote repositories
150        // and we want artifact resolution to only return the system scoped artifact itself.
151        //
152        if ( artifact.getScope() != null && artifact.getScope().equals( Artifact.SCOPE_SYSTEM ) )
153        {
154            return new ResolutionGroup( null, null, null );
155        }
156
157        ResolutionGroup cached =
158            cache.get( artifact, request.isResolveManagedVersions(), 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        {
165            return cached;
166        }
167
168        List<Dependency> dependencies;
169
170        List<Dependency> managedDependencies = null;
171
172        List<ArtifactRepository> pomRepositories = null;
173
174        Artifact pomArtifact;
175
176        Artifact relocatedArtifact = null;
177
178        //TODO: Not even sure this is really required as the project will be cached in the builder, we'll see this
179        // is currently the biggest hotspot
180        if ( artifact instanceof ArtifactWithDependencies )
181        {
182            pomArtifact = artifact;
183
184            dependencies = ( (ArtifactWithDependencies) artifact ).getDependencies();
185
186            managedDependencies = ( (ArtifactWithDependencies) artifact ).getManagedDependencies();
187        }
188        else
189        {
190            ProjectRelocation rel = retrieveRelocatedProject( artifact, request );
191
192            if ( rel == null )
193            {
194                return null;
195            }
196
197            pomArtifact = rel.pomArtifact;
198
199            relocatedArtifact = rel.relocatedArtifact;
200
201            if ( rel.project == null )
202            {
203                // When this happens we have a Maven 1.x POM, or some invalid POM.
204                // It should have never found its way into Maven 2.x repository but it did.
205                dependencies = Collections.emptyList();
206            }
207            else
208            {
209                dependencies = rel.project.getDependencies();
210
211                DependencyManagement depMngt = rel.project.getDependencyManagement();
212                managedDependencies = ( depMngt != null ) ? depMngt.getDependencies() : null;
213
214                pomRepositories = rel.project.getRemoteArtifactRepositories();
215            }
216        }
217
218        Set<Artifact> artifacts = Collections.emptySet();
219
220        if ( !artifact.getArtifactHandler().isIncludesDependencies() )
221        {
222            artifacts = new LinkedHashSet<>();
223
224            for ( Dependency dependency : dependencies )
225            {
226                Artifact dependencyArtifact = createDependencyArtifact( dependency, artifact, pomArtifact );
227
228                if ( dependencyArtifact != null )
229                {
230                    artifacts.add( dependencyArtifact );
231                }
232            }
233        }
234
235        Map<String, Artifact> managedVersions = null;
236
237        if ( managedDependencies != null && request.isResolveManagedVersions() )
238        {
239            managedVersions = new HashMap<>();
240
241            for ( Dependency managedDependency : managedDependencies )
242            {
243                Artifact managedArtifact = createDependencyArtifact( managedDependency, null, pomArtifact );
244
245                managedVersions.put( managedDependency.getManagementKey(), managedArtifact );
246            }
247        }
248
249        List<ArtifactRepository> aggregatedRepositories =
250            aggregateRepositories( request.getRemoteRepositories(), pomRepositories );
251
252        ResolutionGroup result =
253            new ResolutionGroup( pomArtifact, relocatedArtifact, artifacts, managedVersions, aggregatedRepositories );
254
255        cache.put( artifact, request.isResolveManagedVersions(), request.getLocalRepository(),
256                   request.getRemoteRepositories(), result );
257
258        return result;
259    }
260
261    private boolean hasFile( Artifact artifact )
262    {
263        return artifact != null && artifact.getFile() != null && artifact.getFile().exists();
264    }
265
266    private List<ArtifactRepository> aggregateRepositories( List<ArtifactRepository> requestRepositories,
267                                                            List<ArtifactRepository> pomRepositories )
268    {
269        List<ArtifactRepository> repositories = requestRepositories;
270
271        if ( pomRepositories != null && !pomRepositories.isEmpty() )
272        {
273            Map<String, ArtifactRepository> repos = new LinkedHashMap<>();
274
275            for ( ArtifactRepository repo : requestRepositories )
276            {
277                if ( !repos.containsKey( repo.getId() ) )
278                {
279                    repos.put( repo.getId(), repo );
280                }
281            }
282
283            for ( ArtifactRepository repo : pomRepositories )
284            {
285                if ( !repos.containsKey( repo.getId() ) )
286                {
287                    repos.put( repo.getId(), repo );
288                }
289            }
290
291            repositories = new ArrayList<>( repos.values() );
292        }
293
294        return repositories;
295    }
296
297    private Artifact createDependencyArtifact( Dependency dependency, Artifact owner, Artifact pom )
298        throws ArtifactMetadataRetrievalException
299    {
300        try
301        {
302            String inheritedScope = ( owner != null ) ? owner.getScope() : null;
303
304            ArtifactFilter inheritedFilter = ( owner != null ) ? owner.getDependencyFilter() : null;
305
306            return createDependencyArtifact( repositorySystem, dependency, inheritedScope, inheritedFilter );
307        }
308        catch ( InvalidVersionSpecificationException e )
309        {
310            throw new ArtifactMetadataRetrievalException( "Invalid version for dependency "
311                + dependency.getManagementKey() + ": " + e.getMessage(), e, pom );
312        }
313    }
314
315    private static Artifact createDependencyArtifact( ArtifactFactory factory, Dependency dependency,
316                                                      String inheritedScope, ArtifactFilter inheritedFilter )
317        throws InvalidVersionSpecificationException
318    {
319        String effectiveScope = getEffectiveScope( dependency.getScope(), inheritedScope );
320
321        if ( effectiveScope == null )
322        {
323            return null;
324        }
325
326        VersionRange versionRange = VersionRange.createFromVersionSpec( dependency.getVersion() );
327
328        Artifact dependencyArtifact =
329            factory.createDependencyArtifact( dependency.getGroupId(), dependency.getArtifactId(), versionRange,
330                                              dependency.getType(), dependency.getClassifier(), effectiveScope,
331                                              dependency.isOptional() );
332
333        ArtifactFilter dependencyFilter = inheritedFilter;
334
335        if ( dependencyFilter != null && !dependencyFilter.include( dependencyArtifact ) )
336        {
337            return null;
338        }
339
340        if ( Artifact.SCOPE_SYSTEM.equals( effectiveScope ) )
341        {
342            dependencyArtifact.setFile( new File( dependency.getSystemPath() ) );
343        }
344
345        dependencyArtifact.setDependencyFilter( createDependencyFilter( dependency, dependencyFilter ) );
346
347        return dependencyArtifact;
348    }
349
350    private static String getEffectiveScope( String originalScope, String inheritedScope )
351    {
352        String effectiveScope = Artifact.SCOPE_RUNTIME;
353
354        if ( originalScope == null )
355        {
356            originalScope = Artifact.SCOPE_COMPILE;
357        }
358
359        if ( inheritedScope == null )
360        {
361            // direct dependency retains its scope
362            effectiveScope = originalScope;
363        }
364        else if ( Artifact.SCOPE_TEST.equals( originalScope ) || Artifact.SCOPE_PROVIDED.equals( originalScope ) )
365        {
366            // test and provided are not transitive, so exclude them
367            effectiveScope = null;
368        }
369        else if ( Artifact.SCOPE_SYSTEM.equals( originalScope ) )
370        {
371            // system scope come through unchanged...
372            effectiveScope = Artifact.SCOPE_SYSTEM;
373        }
374        else if ( Artifact.SCOPE_COMPILE.equals( originalScope ) && Artifact.SCOPE_COMPILE.equals( inheritedScope ) )
375        {
376            // added to retain compile scope. Remove if you want compile inherited as runtime
377            effectiveScope = Artifact.SCOPE_COMPILE;
378        }
379        else if ( Artifact.SCOPE_TEST.equals( inheritedScope ) )
380        {
381            effectiveScope = Artifact.SCOPE_TEST;
382        }
383        else if ( Artifact.SCOPE_PROVIDED.equals( inheritedScope ) )
384        {
385            effectiveScope = Artifact.SCOPE_PROVIDED;
386        }
387
388        return effectiveScope;
389    }
390
391    private static ArtifactFilter createDependencyFilter( Dependency dependency, ArtifactFilter inheritedFilter )
392    {
393        ArtifactFilter effectiveFilter = inheritedFilter;
394
395        if ( !dependency.getExclusions().isEmpty() )
396        {
397            List<String> exclusions = new ArrayList<>();
398
399            for ( Exclusion e : dependency.getExclusions() )
400            {
401                exclusions.add( e.getGroupId() + ':' + e.getArtifactId() );
402            }
403
404            effectiveFilter = new ExcludesArtifactFilter( exclusions );
405
406            if ( inheritedFilter != null )
407            {
408                effectiveFilter = new AndArtifactFilter( Arrays.asList( inheritedFilter, effectiveFilter ) );
409            }
410        }
411
412        return effectiveFilter;
413    }
414
415    public List<ArtifactVersion> retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository,
416                                                            List<ArtifactRepository> remoteRepositories )
417        throws ArtifactMetadataRetrievalException
418    {
419        MetadataResolutionRequest request = new DefaultMetadataResolutionRequest();
420        injectSession( request );
421        request.setArtifact( artifact );
422        request.setLocalRepository( localRepository );
423        request.setRemoteRepositories( remoteRepositories );
424        return retrieveAvailableVersions( request );
425    }
426
427    public List<ArtifactVersion> retrieveAvailableVersions( MetadataResolutionRequest request )
428        throws ArtifactMetadataRetrievalException
429    {
430        RepositoryMetadata metadata = new ArtifactRepositoryMetadata( request.getArtifact() );
431
432        try
433        {
434            repositoryMetadataManager.resolve( metadata, request );
435        }
436        catch ( RepositoryMetadataResolutionException e )
437        {
438            throw new ArtifactMetadataRetrievalException( e.getMessage(), e, request.getArtifact() );
439        }
440
441        List<String> availableVersions = request.getLocalRepository().findVersions( request.getArtifact() );
442
443        return retrieveAvailableVersionsFromMetadata( metadata.getMetadata(), availableVersions );
444    }
445
446    public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository( Artifact artifact,
447                                                                                    ArtifactRepository localRepository,
448                                                                              ArtifactRepository deploymentRepository )
449        throws ArtifactMetadataRetrievalException
450    {
451        RepositoryMetadata metadata = new ArtifactRepositoryMetadata( artifact );
452
453        try
454        {
455            repositoryMetadataManager.resolveAlways( metadata, localRepository, deploymentRepository );
456        }
457        catch ( RepositoryMetadataResolutionException e )
458        {
459            throw new ArtifactMetadataRetrievalException( e.getMessage(), e, artifact );
460        }
461
462        List<String> availableVersions = localRepository.findVersions( artifact );
463
464        return retrieveAvailableVersionsFromMetadata( metadata.getMetadata(), availableVersions );
465    }
466
467    private List<ArtifactVersion> retrieveAvailableVersionsFromMetadata( Metadata repoMetadata,
468                                                                         List<String> availableVersions )
469    {
470        Collection<String> versions = new LinkedHashSet<>();
471
472        if ( ( repoMetadata != null ) && ( repoMetadata.getVersioning() != null ) )
473        {
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        {
483            artifactVersions.add( new DefaultArtifactVersion( version ) );
484        }
485
486        return artifactVersions;
487    }
488
489    // USED BY MAVEN ASSEMBLY PLUGIN
490    @Deprecated
491    public static Set<Artifact> createArtifacts( ArtifactFactory artifactFactory, List<Dependency> dependencies,
492                                                 String inheritedScope, ArtifactFilter dependencyFilter,
493                                                 MavenProject project )
494        throws InvalidDependencyVersionException
495    {
496        Set<Artifact> artifacts = new LinkedHashSet<>();
497
498        for ( Dependency d : dependencies )
499        {
500            Artifact dependencyArtifact;
501            try
502            {
503                dependencyArtifact = createDependencyArtifact( artifactFactory, d, inheritedScope, dependencyFilter );
504            }
505            catch ( InvalidVersionSpecificationException e )
506            {
507                throw new InvalidDependencyVersionException( project.getId(), d, project.getFile(), e );
508            }
509
510            if ( dependencyArtifact != null )
511            {
512                artifacts.add( dependencyArtifact );
513            }
514        }
515
516        return artifacts;
517    }
518
519    private ProjectBuilder getProjectBuilder()
520    {
521        if ( projectBuilder != null )
522        {
523            return projectBuilder;
524        }
525
526        try
527        {
528            projectBuilder = container.lookup( ProjectBuilder.class );
529        }
530        catch ( ComponentLookupException e )
531        {
532            // Won't happen
533        }
534
535        return projectBuilder;
536    }
537
538    private ProjectRelocation retrieveRelocatedProject( Artifact artifact, MetadataResolutionRequest repositoryRequest )
539        throws ArtifactMetadataRetrievalException
540    {
541        MavenProject project;
542
543        Artifact pomArtifact;
544        Artifact relocatedArtifact = null;
545        boolean done = false;
546        do
547        {
548            project = null;
549
550            pomArtifact =
551                repositorySystem.createProjectArtifact( artifact.getGroupId(),
552                                                        artifact.getArtifactId(),
553                                                        artifact.getVersion(), artifact.getScope() );
554
555            if ( "pom".equals( artifact.getType() ) )
556            {
557                pomArtifact.setFile( artifact.getFile() );
558            }
559
560            if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
561            {
562                done = true;
563            }
564            else
565            {
566                try
567                {
568                    ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
569                    configuration.setLocalRepository( repositoryRequest.getLocalRepository() );
570                    configuration.setRemoteRepositories( repositoryRequest.getRemoteRepositories() );
571                    configuration.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
572                    configuration.setProcessPlugins( false );
573                    configuration.setRepositoryMerging( ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT );
574                    configuration.setSystemProperties( getSystemProperties() );
575                    configuration.setRepositorySession( legacySupport.getRepositorySession() );
576
577                    project = getProjectBuilder().build( pomArtifact, configuration ).getProject();
578                }
579                catch ( ProjectBuildingException e )
580                {
581                    ModelProblem missingParentPom = hasMissingParentPom( e );
582                    if ( missingParentPom != null )
583                    {
584                        throw new ArtifactMetadataRetrievalException( "Failed to process POM for "
585                            + artifact.getId() + ": " + missingParentPom.getMessage(),
586                                                                      missingParentPom.getException(),
587                                                                      artifact );
588                    }
589
590                    String message;
591
592                    if ( isMissingPom( e ) )
593                    {
594                        message = "Missing POM for " + artifact.getId();
595                    }
596                    else if ( isNonTransferrablePom( e ) )
597                    {
598                        throw new ArtifactMetadataRetrievalException( "Failed to retrieve POM for "
599                            + artifact.getId() + ": " + e.getCause().getMessage(), e.getCause(),
600                                                                      artifact );
601                    }
602                    else
603                    {
604                        message =
605                            "Invalid POM for " + artifact.getId()
606                                + ", transitive dependencies (if any) will not be available"
607                                + ", enable debug logging for more details";
608                    }
609
610                    if ( logger.isDebugEnabled() )
611                    {
612                        message += ": " + e.getMessage();
613                    }
614
615                    logger.warn( message );
616                }
617
618                if ( project != null )
619                {
620                    Relocation relocation = null;
621
622                    DistributionManagement distMgmt = project.getDistributionManagement();
623                    if ( distMgmt != null )
624                    {
625                        relocation = distMgmt.getRelocation();
626
627                        artifact.setDownloadUrl( distMgmt.getDownloadUrl() );
628                        pomArtifact.setDownloadUrl( distMgmt.getDownloadUrl() );
629                    }
630
631                    if ( relocation != null )
632                    {
633                        if ( relocation.getGroupId() != null )
634                        {
635                            artifact.setGroupId( relocation.getGroupId() );
636                            relocatedArtifact = artifact;
637                            project.setGroupId( relocation.getGroupId() );
638                        }
639                        if ( relocation.getArtifactId() != null )
640                        {
641                            artifact.setArtifactId( relocation.getArtifactId() );
642                            relocatedArtifact = artifact;
643                            project.setArtifactId( relocation.getArtifactId() );
644                        }
645                        if ( relocation.getVersion() != null )
646                        {
647                            // note: see MNG-3454. This causes a problem, but fixing it may break more.
648                            artifact.setVersionRange( VersionRange.createFromVersion( relocation.getVersion() ) );
649                            relocatedArtifact = artifact;
650                            project.setVersion( relocation.getVersion() );
651                        }
652
653                        if ( artifact.getDependencyFilter() != null
654                            && !artifact.getDependencyFilter().include( artifact ) )
655                        {
656                            return null;
657                        }
658
659                        // MNG-2861: the artifact data has changed. If the available versions where previously
660                        // retrieved, we need to update it.
661                        // TODO: shouldn't the versions be merged across relocations?
662                        List<ArtifactVersion> available = artifact.getAvailableVersions();
663                        if ( available != null && !available.isEmpty() )
664                        {
665                            MetadataResolutionRequest metadataRequest =
666                                new DefaultMetadataResolutionRequest( repositoryRequest );
667                            metadataRequest.setArtifact( artifact );
668                            available = retrieveAvailableVersions( metadataRequest );
669                            artifact.setAvailableVersions( available );
670                        }
671
672                        String message =
673                            "\n  This artifact has been relocated to " + artifact.getGroupId() + ":"
674                                + artifact.getArtifactId() + ":" + artifact.getVersion() + ".\n";
675
676                        if ( relocation.getMessage() != null )
677                        {
678                            message += "  " + relocation.getMessage() + "\n";
679                        }
680
681                        if ( artifact.getDependencyTrail() != null && artifact.getDependencyTrail().size() == 1 )
682                        {
683                            logger.warn( "While downloading " + pomArtifact.getGroupId() + ":"
684                                + pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion() + message + "\n" );
685                        }
686                        else
687                        {
688                            logger.debug( "While downloading " + pomArtifact.getGroupId() + ":"
689                                + pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion() + message + "\n" );
690                        }
691                    }
692                    else
693                    {
694                        done = true;
695                    }
696                }
697                else
698                {
699                    done = true;
700                }
701            }
702        }
703        while ( !done );
704
705        ProjectRelocation rel = new ProjectRelocation();
706        rel.project = project;
707        rel.pomArtifact = pomArtifact;
708        rel.relocatedArtifact = relocatedArtifact;
709
710        return rel;
711    }
712
713    private ModelProblem hasMissingParentPom( ProjectBuildingException e )
714    {
715        if ( e.getCause() instanceof ModelBuildingException )
716        {
717            ModelBuildingException mbe = (ModelBuildingException) e.getCause();
718            for ( ModelProblem problem : mbe.getProblems() )
719            {
720                if ( problem.getException() instanceof UnresolvableModelException )
721                {
722                    return problem;
723                }
724            }
725
726        }
727        return null;
728    }
729
730    private boolean isMissingPom( Exception e )
731    {
732        if ( e.getCause() instanceof MultipleArtifactsNotFoundException )
733        {
734            return true;
735        }
736        return e.getCause() instanceof org.eclipse.aether.resolution.ArtifactResolutionException
737            && e.getCause().getCause() instanceof ArtifactNotFoundException;
738    }
739
740    private boolean isNonTransferrablePom( Exception e )
741    {
742        if ( e.getCause() instanceof ArtifactResolutionException )
743        {
744            return true;
745        }
746        return e.getCause() instanceof org.eclipse.aether.resolution.ArtifactResolutionException
747            && !( e.getCause().getCause() instanceof ArtifactNotFoundException );
748    }
749
750    private Properties getSystemProperties()
751    {
752        Properties props = new Properties();
753
754        EnvironmentUtils.addEnvVars( props );
755
756        SystemProperties.addSystemProperties( props );
757
758        return props;
759    }
760
761    private static final class ProjectRelocation
762    {
763        private MavenProject project;
764
765        private Artifact pomArtifact;
766
767        private Artifact relocatedArtifact;
768    }
769
770}