View Javadoc
1   package org.apache.maven.plugin.internal;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.LinkedHashMap;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.apache.maven.ArtifactFilterManager;
27  import org.apache.maven.RepositoryUtils;
28  import org.apache.maven.model.Dependency;
29  import org.apache.maven.model.Plugin;
30  import org.apache.maven.plugin.PluginResolutionException;
31  import org.codehaus.plexus.component.annotations.Component;
32  import org.codehaus.plexus.component.annotations.Requirement;
33  import org.codehaus.plexus.logging.Logger;
34  import org.eclipse.aether.DefaultRepositorySystemSession;
35  import org.eclipse.aether.RepositorySystem;
36  import org.eclipse.aether.RepositorySystemSession;
37  import org.eclipse.aether.RequestTrace;
38  import org.eclipse.aether.artifact.Artifact;
39  import org.eclipse.aether.artifact.DefaultArtifact;
40  import org.eclipse.aether.collection.CollectRequest;
41  import org.eclipse.aether.collection.DependencyCollectionException;
42  import org.eclipse.aether.collection.DependencyGraphTransformer;
43  import org.eclipse.aether.collection.DependencySelector;
44  import org.eclipse.aether.graph.DependencyFilter;
45  import org.eclipse.aether.graph.DependencyNode;
46  import org.eclipse.aether.graph.DependencyVisitor;
47  import org.eclipse.aether.repository.RemoteRepository;
48  import org.eclipse.aether.resolution.ArtifactDescriptorException;
49  import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
50  import org.eclipse.aether.resolution.ArtifactDescriptorResult;
51  import org.eclipse.aether.resolution.ArtifactRequest;
52  import org.eclipse.aether.resolution.ArtifactResolutionException;
53  import org.eclipse.aether.resolution.DependencyRequest;
54  import org.eclipse.aether.resolution.DependencyResolutionException;
55  import org.eclipse.aether.util.artifact.JavaScopes;
56  import org.eclipse.aether.util.filter.AndDependencyFilter;
57  import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
58  import org.eclipse.aether.util.filter.ScopeDependencyFilter;
59  import org.eclipse.aether.util.graph.selector.AndDependencySelector;
60  import org.eclipse.aether.util.graph.transformer.ChainedDependencyGraphTransformer;
61  import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy;
62  
63  /**
64   * Assists in resolving the dependencies of a plugin. <strong>Warning:</strong> This is an internal utility class that
65   * is only public for technical reasons, it is not part of the public API. In particular, this class can be changed or
66   * deleted without prior notice.
67   * 
68   * @since 3.0
69   * @author Benjamin Bentmann
70   */
71  @Component( role = PluginDependenciesResolver.class )
72  public class DefaultPluginDependenciesResolver
73      implements PluginDependenciesResolver
74  {
75  
76      private static final String REPOSITORY_CONTEXT = "plugin";
77  
78      @Requirement
79      private Logger logger;
80  
81      @Requirement
82      private ArtifactFilterManager artifactFilterManager;
83  
84      @Requirement
85      private RepositorySystem repoSystem;
86  
87      private Artifact toArtifact( Plugin plugin, RepositorySystemSession session )
88      {
89          return new DefaultArtifact( plugin.getGroupId(), plugin.getArtifactId(), null, "jar", plugin.getVersion(),
90                                      session.getArtifactTypeRegistry().get( "maven-plugin" ) );
91      }
92  
93      public Artifact resolve( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
94          throws PluginResolutionException
95      {
96          RequestTrace trace = RequestTrace.newChild( null, plugin );
97  
98          Artifact pluginArtifact = toArtifact( plugin, session );
99  
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 }