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.model.Dependency;
056    import org.apache.maven.model.DependencyManagement;
057    import org.apache.maven.model.DistributionManagement;
058    import org.apache.maven.model.Exclusion;
059    import org.apache.maven.model.Relocation;
060    import org.apache.maven.model.building.ModelBuildingException;
061    import org.apache.maven.model.building.ModelBuildingRequest;
062    import org.apache.maven.model.building.ModelProblem;
063    import org.apache.maven.model.resolution.UnresolvableModelException;
064    import org.apache.maven.plugin.LegacySupport;
065    import org.apache.maven.project.DefaultProjectBuildingRequest;
066    import org.apache.maven.project.MavenProject;
067    import org.apache.maven.project.ProjectBuilder;
068    import org.apache.maven.project.ProjectBuildingException;
069    import org.apache.maven.project.ProjectBuildingRequest;
070    import org.apache.maven.properties.internal.EnvironmentUtils;
071    import org.apache.maven.repository.legacy.metadata.DefaultMetadataResolutionRequest;
072    import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
073    import org.codehaus.plexus.PlexusContainer;
074    import org.codehaus.plexus.component.annotations.Component;
075    import org.codehaus.plexus.component.annotations.Requirement;
076    import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
077    import org.codehaus.plexus.logging.Logger;
078    import org.eclipse.aether.RepositorySystemSession;
079    import org.eclipse.aether.repository.RepositoryPolicy;
080    import org.eclipse.aether.transfer.ArtifactNotFoundException;
081    
082    /**
083     * @author Jason van Zyl
084     */
085    @Component( role = ArtifactMetadataSource.class, hint = "maven" )
086    public 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    }