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