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