001package 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
022import java.util.LinkedHashMap;
023import java.util.List;
024import java.util.Map;
025
026import org.apache.maven.ArtifactFilterManager;
027import org.apache.maven.RepositoryUtils;
028import org.apache.maven.model.Dependency;
029import org.apache.maven.model.Plugin;
030import org.apache.maven.plugin.PluginResolutionException;
031import org.codehaus.plexus.component.annotations.Component;
032import org.codehaus.plexus.component.annotations.Requirement;
033import org.codehaus.plexus.logging.Logger;
034import org.eclipse.aether.DefaultRepositorySystemSession;
035import org.eclipse.aether.RepositorySystem;
036import org.eclipse.aether.RepositorySystemSession;
037import org.eclipse.aether.RequestTrace;
038import org.eclipse.aether.artifact.Artifact;
039import org.eclipse.aether.artifact.DefaultArtifact;
040import org.eclipse.aether.collection.CollectRequest;
041import org.eclipse.aether.collection.DependencyCollectionException;
042import org.eclipse.aether.collection.DependencyGraphTransformer;
043import org.eclipse.aether.collection.DependencySelector;
044import org.eclipse.aether.graph.DependencyFilter;
045import org.eclipse.aether.graph.DependencyNode;
046import org.eclipse.aether.graph.DependencyVisitor;
047import org.eclipse.aether.repository.RemoteRepository;
048import org.eclipse.aether.resolution.ArtifactDescriptorException;
049import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
050import org.eclipse.aether.resolution.ArtifactDescriptorResult;
051import org.eclipse.aether.resolution.ArtifactRequest;
052import org.eclipse.aether.resolution.ArtifactResolutionException;
053import org.eclipse.aether.resolution.DependencyRequest;
054import org.eclipse.aether.resolution.DependencyResolutionException;
055import org.eclipse.aether.util.artifact.JavaScopes;
056import org.eclipse.aether.util.filter.AndDependencyFilter;
057import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
058import org.eclipse.aether.util.filter.ScopeDependencyFilter;
059import org.eclipse.aether.util.graph.selector.AndDependencySelector;
060import org.eclipse.aether.util.graph.transformer.ChainedDependencyGraphTransformer;
061import 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 )
072public 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                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}