001    package org.apache.maven.plugin.internal;
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.util.LinkedHashMap;
023    import java.util.List;
024    import java.util.Map;
025    
026    import org.apache.maven.ArtifactFilterManager;
027    import org.apache.maven.RepositoryUtils;
028    import org.apache.maven.model.Dependency;
029    import org.apache.maven.model.Plugin;
030    import org.apache.maven.plugin.PluginResolutionException;
031    import org.codehaus.plexus.component.annotations.Component;
032    import org.codehaus.plexus.component.annotations.Requirement;
033    import org.codehaus.plexus.logging.Logger;
034    import org.eclipse.aether.DefaultRepositorySystemSession;
035    import org.eclipse.aether.RepositorySystem;
036    import org.eclipse.aether.RepositorySystemSession;
037    import org.eclipse.aether.RequestTrace;
038    import org.eclipse.aether.artifact.Artifact;
039    import org.eclipse.aether.artifact.DefaultArtifact;
040    import org.eclipse.aether.collection.CollectRequest;
041    import org.eclipse.aether.collection.DependencyCollectionException;
042    import org.eclipse.aether.collection.DependencyGraphTransformer;
043    import org.eclipse.aether.collection.DependencySelector;
044    import org.eclipse.aether.graph.DependencyFilter;
045    import org.eclipse.aether.graph.DependencyNode;
046    import org.eclipse.aether.graph.DependencyVisitor;
047    import org.eclipse.aether.repository.RemoteRepository;
048    import org.eclipse.aether.resolution.ArtifactDescriptorException;
049    import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
050    import org.eclipse.aether.resolution.ArtifactDescriptorResult;
051    import org.eclipse.aether.resolution.ArtifactRequest;
052    import org.eclipse.aether.resolution.ArtifactResolutionException;
053    import org.eclipse.aether.resolution.DependencyRequest;
054    import org.eclipse.aether.resolution.DependencyResolutionException;
055    import org.eclipse.aether.util.artifact.JavaScopes;
056    import org.eclipse.aether.util.filter.AndDependencyFilter;
057    import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
058    import org.eclipse.aether.util.filter.ScopeDependencyFilter;
059    import org.eclipse.aether.util.graph.selector.AndDependencySelector;
060    import org.eclipse.aether.util.graph.transformer.ChainedDependencyGraphTransformer;
061    import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy;
062    
063    /**
064     * Assists in resolving the dependencies of a plugin. <strong>Warning:</strong> This is an internal utility class that
065     * is only public for technical reasons, it is not part of the public API. In particular, this class can be changed or
066     * deleted without prior notice.
067     * 
068     * @since 3.0
069     * @author Benjamin Bentmann
070     */
071    @Component( role = PluginDependenciesResolver.class )
072    public class DefaultPluginDependenciesResolver
073        implements PluginDependenciesResolver
074    {
075    
076        private static final String REPOSITORY_CONTEXT = "plugin";
077    
078        @Requirement
079        private Logger logger;
080    
081        @Requirement
082        private ArtifactFilterManager artifactFilterManager;
083    
084        @Requirement
085        private RepositorySystem repoSystem;
086    
087        private Artifact toArtifact( Plugin plugin, RepositorySystemSession session )
088        {
089            return new DefaultArtifact( plugin.getGroupId(), plugin.getArtifactId(), null, "jar", plugin.getVersion(),
090                                        session.getArtifactTypeRegistry().get( "maven-plugin" ) );
091        }
092    
093        public Artifact resolve( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
094            throws PluginResolutionException
095        {
096            RequestTrace trace = RequestTrace.newChild( null, plugin );
097    
098            Artifact pluginArtifact = toArtifact( plugin, session );
099    
100            try
101            {
102                DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session );
103                pluginSession.setArtifactDescriptorPolicy( new SimpleArtifactDescriptorPolicy( true, false ) );
104    
105                ArtifactDescriptorRequest request =
106                    new ArtifactDescriptorRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT );
107                request.setTrace( trace );
108                ArtifactDescriptorResult result = repoSystem.readArtifactDescriptor( pluginSession, request );
109    
110                pluginArtifact = result.getArtifact();
111    
112                String requiredMavenVersion = (String) result.getProperties().get( "prerequisites.maven" );
113                if ( requiredMavenVersion != null )
114                {
115                    Map<String, String> props = new LinkedHashMap<String, String>( pluginArtifact.getProperties() );
116                    props.put( "requiredMavenVersion", requiredMavenVersion );
117                    pluginArtifact = pluginArtifact.setProperties( props );
118                }
119            }
120            catch ( ArtifactDescriptorException e )
121            {
122                throw new PluginResolutionException( plugin, e );
123            }
124    
125            try
126            {
127                ArtifactRequest request = new ArtifactRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT );
128                request.setTrace( trace );
129                pluginArtifact = repoSystem.resolveArtifact( session, request ).getArtifact();
130            }
131            catch ( ArtifactResolutionException e )
132            {
133                throw new PluginResolutionException( plugin, e );
134            }
135    
136            return pluginArtifact;
137        }
138    
139        public DependencyNode resolve( Plugin plugin, Artifact pluginArtifact, DependencyFilter dependencyFilter,
140                                       List<RemoteRepository> repositories, RepositorySystemSession session )
141            throws PluginResolutionException
142        {
143            RequestTrace trace = RequestTrace.newChild( null, plugin );
144    
145            if ( pluginArtifact == null )
146            {
147                pluginArtifact = toArtifact( plugin, session );
148            }
149    
150            DependencyFilter collectionFilter = new ScopeDependencyFilter( "provided", "test" );
151    
152            DependencyFilter resolutionFilter =
153                new ExclusionsDependencyFilter( artifactFilterManager.getCoreArtifactExcludes() );
154            resolutionFilter = AndDependencyFilter.newInstance( resolutionFilter, dependencyFilter );
155            resolutionFilter = new AndDependencyFilter( collectionFilter, resolutionFilter );
156    
157            DependencyNode node;
158    
159            try
160            {
161                DependencySelector selector =
162                    AndDependencySelector.newInstance( session.getDependencySelector(), new WagonExcluder() );
163    
164                DependencyGraphTransformer transformer =
165                    ChainedDependencyGraphTransformer.newInstance( session.getDependencyGraphTransformer(),
166                                                                   new PlexusUtilsInjector() );
167    
168                DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session );
169                pluginSession.setDependencySelector( selector );
170                pluginSession.setDependencyGraphTransformer( transformer );
171    
172                CollectRequest request = new CollectRequest();
173                request.setRequestContext( REPOSITORY_CONTEXT );
174                request.setRepositories( repositories );
175                request.setRoot( new org.eclipse.aether.graph.Dependency( pluginArtifact, null ) );
176                for ( Dependency dependency : plugin.getDependencies() )
177                {
178                    org.eclipse.aether.graph.Dependency pluginDep =
179                        RepositoryUtils.toDependency( dependency, session.getArtifactTypeRegistry() );
180                    if ( !JavaScopes.SYSTEM.equals( pluginDep.getScope() ) )
181                    {
182                        pluginDep = pluginDep.setScope( JavaScopes.RUNTIME );
183                    }
184                    request.addDependency( pluginDep );
185                }
186    
187                DependencyRequest depRequest = new DependencyRequest( request, resolutionFilter );
188                depRequest.setTrace( trace );
189    
190                request.setTrace( RequestTrace.newChild( trace, depRequest ) );
191    
192                node = repoSystem.collectDependencies( pluginSession, request ).getRoot();
193    
194                if ( logger.isDebugEnabled() )
195                {
196                    node.accept( new GraphLogger() );
197                }
198    
199                depRequest.setRoot( node );
200                repoSystem.resolveDependencies( session, depRequest );
201            }
202            catch ( DependencyCollectionException e )
203            {
204                throw new PluginResolutionException( plugin, e );
205            }
206            catch ( DependencyResolutionException e )
207            {
208                throw new PluginResolutionException( plugin, e.getCause() );
209            }
210    
211            return node;
212        }
213    
214        class GraphLogger
215            implements DependencyVisitor
216        {
217    
218            private String indent = "";
219    
220            public boolean visitEnter( DependencyNode node )
221            {
222                StringBuilder buffer = new StringBuilder( 128 );
223                buffer.append( indent );
224                org.eclipse.aether.graph.Dependency dep = node.getDependency();
225                if ( dep != null )
226                {
227                    org.eclipse.aether.artifact.Artifact art = dep.getArtifact();
228    
229                    buffer.append( art );
230                    buffer.append( ':' ).append( dep.getScope() );
231                }
232    
233                logger.debug( buffer.toString() );
234                indent += "   ";
235                return true;
236            }
237    
238            public boolean visitLeave( DependencyNode node )
239            {
240                indent = indent.substring( 0, indent.length() - 3 );
241                return true;
242            }
243    
244        }
245    
246    }