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