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.sonatype.aether.RepositorySystem;
35  import org.sonatype.aether.RepositorySystemSession;
36  import org.sonatype.aether.RequestTrace;
37  import org.sonatype.aether.artifact.Artifact;
38  import org.sonatype.aether.collection.CollectRequest;
39  import org.sonatype.aether.collection.DependencyCollectionException;
40  import org.sonatype.aether.collection.DependencyGraphTransformer;
41  import org.sonatype.aether.collection.DependencySelector;
42  import org.sonatype.aether.graph.DependencyFilter;
43  import org.sonatype.aether.graph.DependencyNode;
44  import org.sonatype.aether.graph.DependencyVisitor;
45  import org.sonatype.aether.repository.RemoteRepository;
46  import org.sonatype.aether.resolution.ArtifactDescriptorException;
47  import org.sonatype.aether.resolution.ArtifactDescriptorRequest;
48  import org.sonatype.aether.resolution.ArtifactDescriptorResult;
49  import org.sonatype.aether.resolution.ArtifactRequest;
50  import org.sonatype.aether.resolution.ArtifactResolutionException;
51  import org.sonatype.aether.resolution.DependencyRequest;
52  import org.sonatype.aether.resolution.DependencyResolutionException;
53  import org.sonatype.aether.util.DefaultRepositorySystemSession;
54  import org.sonatype.aether.util.DefaultRequestTrace;
55  import org.sonatype.aether.util.FilterRepositorySystemSession;
56  import org.sonatype.aether.util.artifact.DefaultArtifact;
57  import org.sonatype.aether.util.artifact.JavaScopes;
58  import org.sonatype.aether.util.filter.AndDependencyFilter;
59  import org.sonatype.aether.util.filter.ExclusionsDependencyFilter;
60  import org.sonatype.aether.util.filter.ScopeDependencyFilter;
61  import org.sonatype.aether.util.graph.selector.AndDependencySelector;
62  import org.sonatype.aether.util.graph.transformer.ChainedDependencyGraphTransformer;
63  
64  /**
65   * Assists in resolving the dependencies of a plugin. <strong>Warning:</strong> This is an internal utility class that
66   * is only public for technical reasons, it is not part of the public API. In particular, this class can be changed or
67   * deleted without prior notice.
68   * 
69   * @since 3.0
70   * @author Benjamin Bentmann
71   */
72  @Component( role = PluginDependenciesResolver.class )
73  public class DefaultPluginDependenciesResolver
74      implements PluginDependenciesResolver
75  {
76  
77      private static final String REPOSITORY_CONTEXT = "plugin";
78  
79      @Requirement
80      private Logger logger;
81  
82      @Requirement
83      private ArtifactFilterManager artifactFilterManager;
84  
85      @Requirement
86      private RepositorySystem repoSystem;
87  
88      private Artifact toArtifact( Plugin plugin, RepositorySystemSession session )
89      {
90          return new DefaultArtifact( plugin.getGroupId(), plugin.getArtifactId(), null, "jar", plugin.getVersion(),
91                                      session.getArtifactTypeRegistry().get( "maven-plugin" ) );
92      }
93  
94      public Artifact resolve( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
95          throws PluginResolutionException
96      {
97          RequestTrace trace = DefaultRequestTrace.newChild( null, plugin );
98  
99          Artifact pluginArtifact = toArtifact( plugin, session );
100 
101         try
102         {
103             RepositorySystemSession pluginSession = new FilterRepositorySystemSession( session )
104             {
105                 @Override
106                 public boolean isIgnoreMissingArtifactDescriptor()
107                 {
108                     return false;
109                 }
110             };
111 
112             ArtifactDescriptorRequest request =
113                 new ArtifactDescriptorRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT );
114             request.setTrace( trace );
115             ArtifactDescriptorResult result = repoSystem.readArtifactDescriptor( pluginSession, request );
116 
117             pluginArtifact = result.getArtifact();
118 
119             String requiredMavenVersion = (String) result.getProperties().get( "prerequisites.maven" );
120             if ( requiredMavenVersion != null )
121             {
122                 Map<String, String> props = new LinkedHashMap<String, String>( pluginArtifact.getProperties() );
123                 props.put( "requiredMavenVersion", requiredMavenVersion );
124                 pluginArtifact = pluginArtifact.setProperties( props );
125             }
126         }
127         catch ( ArtifactDescriptorException e )
128         {
129             throw new PluginResolutionException( plugin, e );
130         }
131 
132         try
133         {
134             ArtifactRequest request = new ArtifactRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT );
135             request.setTrace( trace );
136             pluginArtifact = repoSystem.resolveArtifact( session, request ).getArtifact();
137         }
138         catch ( ArtifactResolutionException e )
139         {
140             throw new PluginResolutionException( plugin, e );
141         }
142 
143         return pluginArtifact;
144     }
145 
146     public DependencyNode resolve( Plugin plugin, Artifact pluginArtifact, DependencyFilter dependencyFilter,
147                                    List<RemoteRepository> repositories, RepositorySystemSession session )
148         throws PluginResolutionException
149     {
150         RequestTrace trace = DefaultRequestTrace.newChild( null, plugin );
151 
152         if ( pluginArtifact == null )
153         {
154             pluginArtifact = toArtifact( plugin, session );
155         }
156 
157         DependencyFilter collectionFilter = new ScopeDependencyFilter( "provided", "test" );
158 
159         DependencyFilter resolutionFilter =
160             new ExclusionsDependencyFilter( artifactFilterManager.getCoreArtifactExcludes() );
161         resolutionFilter = AndDependencyFilter.newInstance( resolutionFilter, dependencyFilter );
162         resolutionFilter = new AndDependencyFilter( collectionFilter, resolutionFilter );
163 
164         DependencyNode node;
165 
166         try
167         {
168             DependencySelector selector =
169                 AndDependencySelector.newInstance( session.getDependencySelector(), new WagonExcluder() );
170 
171             DependencyGraphTransformer transformer =
172                 ChainedDependencyGraphTransformer.newInstance( session.getDependencyGraphTransformer(),
173                                                                new PlexusUtilsInjector() );
174 
175             DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session );
176             pluginSession.setDependencySelector( selector );
177             pluginSession.setDependencyGraphTransformer( transformer );
178 
179             CollectRequest request = new CollectRequest();
180             request.setRequestContext( REPOSITORY_CONTEXT );
181             request.setRepositories( repositories );
182             request.setRoot( new org.sonatype.aether.graph.Dependency( pluginArtifact, null ) );
183             for ( Dependency dependency : plugin.getDependencies() )
184             {
185                 org.sonatype.aether.graph.Dependency pluginDep =
186                     RepositoryUtils.toDependency( dependency, session.getArtifactTypeRegistry() );
187                 if ( !JavaScopes.SYSTEM.equals( pluginDep.getScope() ) )
188                 {
189                     pluginDep = pluginDep.setScope( JavaScopes.RUNTIME );
190                 }
191                 request.addDependency( pluginDep );
192             }
193 
194             DependencyRequest depRequest = new DependencyRequest( request, resolutionFilter );
195             depRequest.setTrace( trace );
196 
197             request.setTrace( DefaultRequestTrace.newChild( trace, depRequest ) );
198 
199             node = repoSystem.collectDependencies( pluginSession, request ).getRoot();
200 
201             if ( logger.isDebugEnabled() )
202             {
203                 node.accept( new GraphLogger() );
204             }
205 
206             depRequest.setRoot( node );
207             repoSystem.resolveDependencies( session, depRequest );
208         }
209         catch ( DependencyCollectionException e )
210         {
211             throw new PluginResolutionException( plugin, e );
212         }
213         catch ( DependencyResolutionException e )
214         {
215             throw new PluginResolutionException( plugin, e.getCause() );
216         }
217 
218         return node;
219     }
220 
221     class GraphLogger
222         implements DependencyVisitor
223     {
224 
225         private String indent = "";
226 
227         public boolean visitEnter( DependencyNode node )
228         {
229             StringBuilder buffer = new StringBuilder( 128 );
230             buffer.append( indent );
231             org.sonatype.aether.graph.Dependency dep = node.getDependency();
232             if ( dep != null )
233             {
234                 org.sonatype.aether.artifact.Artifact art = dep.getArtifact();
235 
236                 buffer.append( art );
237                 buffer.append( ':' ).append( dep.getScope() );
238 
239                 if ( node.getPremanagedScope() != null && !node.getPremanagedScope().equals( dep.getScope() ) )
240                 {
241                     buffer.append( " (scope managed from " ).append( node.getPremanagedScope() ).append( ")" );
242                 }
243 
244                 if ( node.getPremanagedVersion() != null && !node.getPremanagedVersion().equals( art.getVersion() ) )
245                 {
246                     buffer.append( " (version managed from " ).append( node.getPremanagedVersion() ).append( ")" );
247                 }
248             }
249 
250             logger.debug( buffer.toString() );
251             indent += "   ";
252             return true;
253         }
254 
255         public boolean visitLeave( DependencyNode node )
256         {
257             indent = indent.substring( 0, indent.length() - 3 );
258             return true;
259         }
260 
261     }
262 
263 }