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