View Javadoc

1   package org.apache.maven.project;
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.Collection;
23  import java.util.HashMap;
24  import java.util.Map;
25  
26  import org.apache.maven.RepositoryUtils;
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.model.Dependency;
29  import org.apache.maven.model.DependencyManagement;
30  import org.apache.maven.model.Exclusion;
31  import org.apache.maven.model.InputLocation;
32  import org.apache.maven.model.InputSource;
33  import org.codehaus.plexus.component.annotations.Component;
34  import org.codehaus.plexus.component.annotations.Requirement;
35  import org.codehaus.plexus.logging.Logger;
36  import org.codehaus.plexus.util.StringUtils;
37  import org.sonatype.aether.RepositorySystem;
38  import org.sonatype.aether.RepositorySystemSession;
39  import org.sonatype.aether.RequestTrace;
40  import org.sonatype.aether.artifact.ArtifactType;
41  import org.sonatype.aether.artifact.ArtifactTypeRegistry;
42  import org.sonatype.aether.collection.CollectRequest;
43  import org.sonatype.aether.collection.DependencyCollectionException;
44  import org.sonatype.aether.graph.DependencyFilter;
45  import org.sonatype.aether.graph.DependencyNode;
46  import org.sonatype.aether.graph.DependencyVisitor;
47  import org.sonatype.aether.resolution.ArtifactResult;
48  import org.sonatype.aether.resolution.DependencyRequest;
49  import org.sonatype.aether.util.DefaultRequestTrace;
50  import org.sonatype.aether.util.artifact.ArtifacIdUtils;
51  import org.sonatype.aether.util.artifact.ArtifactProperties;
52  import org.sonatype.aether.util.artifact.JavaScopes;
53  
54  /**
55   * @author Benjamin Bentmann
56   */
57  @Component( role = ProjectDependenciesResolver.class )
58  public class DefaultProjectDependenciesResolver
59      implements ProjectDependenciesResolver
60  {
61  
62      @Requirement
63      private Logger logger;
64  
65      @Requirement
66      private RepositorySystem repoSystem;
67  
68      public DependencyResolutionResult resolve( DependencyResolutionRequest request )
69          throws DependencyResolutionException
70      {
71          RequestTrace trace = DefaultRequestTrace.newChild( null, request );
72  
73          DefaultDependencyResolutionResult result = new DefaultDependencyResolutionResult();
74  
75          MavenProject project = request.getMavenProject();
76          RepositorySystemSession session = request.getRepositorySession();
77          DependencyFilter filter = request.getResolutionFilter();
78  
79          ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry();
80  
81          CollectRequest collect = new CollectRequest();
82          collect.setRequestContext( "project" );
83          collect.setRepositories( project.getRemoteProjectRepositories() );
84  
85          if ( project.getDependencyArtifacts() == null )
86          {
87              for ( Dependency dependency : project.getDependencies() )
88              {
89                  if ( StringUtils.isEmpty( dependency.getGroupId() ) || StringUtils.isEmpty( dependency.getArtifactId() )
90                      || StringUtils.isEmpty( dependency.getVersion() ) )
91                  {
92                      // guard against case where best-effort resolution for invalid models is requested
93                      continue;
94                  }
95                  collect.addDependency( RepositoryUtils.toDependency( dependency, stereotypes ) );
96              }
97          }
98          else
99          {
100             Map<String, Dependency> dependencies = new HashMap<String, Dependency>();
101             for ( Dependency dependency : project.getDependencies() )
102             {
103                 String classifier = dependency.getClassifier();
104                 if ( classifier == null )
105                 {
106                     ArtifactType type = stereotypes.get( dependency.getType() );
107                     if ( type != null )
108                     {
109                         classifier = type.getClassifier();
110                     }
111                 }
112                 String key =
113                     ArtifacIdUtils.toVersionlessId( dependency.getGroupId(), dependency.getArtifactId(),
114                                                     dependency.getType(), classifier );
115                 dependencies.put( key, dependency );
116             }
117             for ( Artifact artifact : project.getDependencyArtifacts() )
118             {
119                 String key = artifact.getDependencyConflictId();
120                 Dependency dependency = dependencies.get( key );
121                 Collection<Exclusion> exclusions = dependency != null ? dependency.getExclusions() : null;
122                 org.sonatype.aether.graph.Dependency dep = RepositoryUtils.toDependency( artifact, exclusions );
123                 if ( !JavaScopes.SYSTEM.equals( dep.getScope() ) && dep.getArtifact().getFile() != null )
124                 {
125                     // enable re-resolution
126                     org.sonatype.aether.artifact.Artifact art = dep.getArtifact();
127                     art = art.setFile( null ).setVersion( art.getBaseVersion() );
128                     dep = dep.setArtifact( art );
129                 }
130                 collect.addDependency( dep );
131             }
132         }
133 
134         DependencyManagement depMngt = project.getDependencyManagement();
135         if ( depMngt != null )
136         {
137             for ( Dependency dependency : depMngt.getDependencies() )
138             {
139                 collect.addManagedDependency( RepositoryUtils.toDependency( dependency, stereotypes ) );
140             }
141         }
142 
143         DependencyRequest depRequest = new DependencyRequest( collect, filter );
144         depRequest.setTrace( trace );
145 
146         DependencyNode node;
147         try
148         {
149             collect.setTrace( DefaultRequestTrace.newChild( trace, depRequest ) );
150             node = repoSystem.collectDependencies( session, collect ).getRoot();
151             result.setDependencyGraph( node );
152         }
153         catch ( DependencyCollectionException e )
154         {
155             result.setDependencyGraph( e.getResult().getRoot() );
156             result.setCollectionErrors( e.getResult().getExceptions() );
157 
158             throw new DependencyResolutionException( result, "Could not resolve dependencies for project "
159                 + project.getId() + ": " + e.getMessage(), e );
160         }
161 
162         depRequest.setRoot( node );
163 
164         if ( logger.isWarnEnabled() )
165         {
166             for ( DependencyNode child : node.getChildren() )
167             {
168                 if ( !child.getRelocations().isEmpty() )
169                 {
170                     logger.warn( "The artifact " + child.getRelocations().get( 0 ) + " has been relocated to "
171                         + child.getDependency().getArtifact() );
172                 }
173             }
174         }
175 
176         if ( logger.isDebugEnabled() )
177         {
178             node.accept( new GraphLogger( project ) );
179         }
180 
181         try
182         {
183             process( result, repoSystem.resolveDependencies( session, depRequest ).getArtifactResults() );
184         }
185         catch ( org.sonatype.aether.resolution.DependencyResolutionException e )
186         {
187             process( result, e.getResult().getArtifactResults() );
188 
189             throw new DependencyResolutionException( result, "Could not resolve dependencies for project "
190                 + project.getId() + ": " + e.getMessage(), e );
191         }
192 
193         return result;
194     }
195 
196     private void process( DefaultDependencyResolutionResult result, Collection<ArtifactResult> results )
197     {
198         for ( ArtifactResult ar : results )
199         {
200             DependencyNode node = ar.getRequest().getDependencyNode();
201             if ( ar.isResolved() )
202             {
203                 result.addResolvedDependency( node.getDependency() );
204             }
205             else
206             {
207                 result.setResolutionErrors( node.getDependency(), ar.getExceptions() );
208             }
209         }
210     }
211 
212     class GraphLogger
213         implements DependencyVisitor
214     {
215 
216         private final MavenProject project;
217 
218         private String indent = "";
219 
220         private Map<String, Dependency> managed;
221 
222         public GraphLogger( MavenProject project )
223         {
224             this.project = project;
225         }
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() );
242                     appendManagementSource( buffer, art, "scope" );
243                     buffer.append( ")" );
244                 }
245 
246                 if ( node.getPremanagedVersion() != null && !node.getPremanagedVersion().equals( art.getVersion() ) )
247                 {
248                     buffer.append( " (version managed from " ).append( node.getPremanagedVersion() );
249                     appendManagementSource( buffer, art, "version" );
250                     buffer.append( ")" );
251                 }
252             }
253             else
254             {
255                 buffer.append( project.getGroupId() );
256                 buffer.append( ':' ).append( project.getArtifactId() );
257                 buffer.append( ':' ).append( project.getPackaging() );
258                 buffer.append( ':' ).append( project.getVersion() );
259             }
260 
261             logger.debug( buffer.toString() );
262             indent += "   ";
263             return true;
264         }
265 
266         public boolean visitLeave( DependencyNode node )
267         {
268             indent = indent.substring( 0, indent.length() - 3 );
269             return true;
270         }
271 
272         private void appendManagementSource( StringBuilder buffer, org.sonatype.aether.artifact.Artifact artifact,
273                                              String field )
274         {
275             if ( managed == null )
276             {
277                 managed = new HashMap<String, Dependency>();
278                 if ( project.getDependencyManagement() != null )
279                 {
280                     for ( Dependency dep : project.getDependencyManagement().getDependencies() )
281                     {
282                         managed.put( dep.getManagementKey(), dep );
283                     }
284                 }
285             }
286 
287             String key =
288                 ArtifacIdUtils.toVersionlessId( artifact.getGroupId(), artifact.getArtifactId(),
289                                                 artifact.getProperty( ArtifactProperties.TYPE, "jar" ),
290                                                 artifact.getClassifier() );
291 
292             Dependency dependency = managed.get( key );
293             if ( dependency != null )
294             {
295                 InputLocation location = dependency.getLocation( field );
296                 if ( location != null )
297                 {
298                     InputSource source = location.getSource();
299                     if ( source != null )
300                     {
301                         buffer.append( " by " ).append( source.getModelId() );
302                     }
303                 }
304             }
305         }
306 
307     }
308 
309 }