View Javadoc
1   package org.apache.maven.shared.dependency.graph.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 org.apache.maven.artifact.Artifact;
23  import org.apache.maven.artifact.factory.ArtifactFactory;
24  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
25  import org.apache.maven.artifact.versioning.VersionRange;
26  import org.apache.maven.project.DefaultDependencyResolutionRequest;
27  import org.apache.maven.project.DependencyResolutionException;
28  import org.apache.maven.project.DependencyResolutionRequest;
29  import org.apache.maven.project.DependencyResolutionResult;
30  import org.apache.maven.project.MavenProject;
31  import org.apache.maven.project.ProjectBuildingRequest;
32  import org.apache.maven.project.ProjectDependenciesResolver;
33  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
34  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
35  import org.apache.maven.shared.dependency.graph.DependencyNode;
36  import org.codehaus.plexus.component.annotations.Component;
37  import org.codehaus.plexus.component.annotations.Requirement;
38  import org.codehaus.plexus.logging.AbstractLogEnabled;
39  import org.eclipse.aether.RepositorySystemSession;
40  import org.eclipse.aether.graph.Dependency;
41  import org.eclipse.aether.version.VersionConstraint;
42  
43  import java.util.ArrayList;
44  import java.util.Collection;
45  import java.util.Collections;
46  import java.util.HashSet;
47  import java.util.List;
48  import java.util.Set;
49  
50  /**
51   * Wrapper around Eclipse Aether dependency resolver, used in Maven 3.1.
52   *
53   * @see ProjectDependenciesResolver
54   * @author Hervé Boutemy
55   * @since 2.1
56   */
57  @Component( role = DependencyGraphBuilder.class, hint = "maven31" )
58  public class Maven31DependencyGraphBuilder
59      extends AbstractLogEnabled
60      implements DependencyGraphBuilder
61  {
62      @Requirement
63      private ProjectDependenciesResolver resolver;
64  
65      @Requirement
66      private ArtifactFactory factory;
67  
68      /**
69       * Builds the dependency graph for Maven 3.1+.
70       *
71       * @param project the project
72       * @param filter artifact filter (can be <code>null</code>)
73       * @return DependencyNode containing the dependency graph.
74       * @throws DependencyGraphBuilderException if some of the dependencies could not be resolved.
75       */
76      public DependencyNode buildDependencyGraph( MavenProject project, ArtifactFilter filter )
77          throws DependencyGraphBuilderException
78      {
79          return buildDependencyGraph( project, filter, null );
80      }
81  
82      /**
83       * Builds the dependency graph for Maven 3.1+, eventually hacking for collecting projects from
84       * reactor not yet built.
85       *
86       * @param project the project
87       * @param filter artifact filter (can be <code>null</code>)
88       * @param reactorProjects Collection of those projects contained in the reactor (can be <code>null</code>).
89       * @return DependencyNode containing the dependency graph.
90       * @throws DependencyGraphBuilderException if some of the dependencies could not be resolved.
91       */
92      public DependencyNode buildDependencyGraph( MavenProject project, ArtifactFilter filter,
93                                                  Collection<MavenProject> reactorProjects )
94          throws DependencyGraphBuilderException
95      {
96          ProjectBuildingRequest projectBuildingRequest =
97              (ProjectBuildingRequest) Invoker.invoke( project, "getProjectBuildingRequest" );
98  
99          RepositorySystemSession session =
100             (RepositorySystemSession) Invoker.invoke( projectBuildingRequest, "getRepositorySession" );
101 
102         /*
103          * if ( Boolean.TRUE != ( (Boolean) session.getConfigProperties().get(
104          * DependencyManagerUtils.NODE_DATA_PREMANAGED_VERSION ) ) ) { DefaultRepositorySystemSession newSession = new
105          * DefaultRepositorySystemSession( session ); newSession.setConfigProperty(
106          * DependencyManagerUtils.NODE_DATA_PREMANAGED_VERSION, true ); session = newSession; }
107          */
108 
109         final DependencyResolutionRequest request = new DefaultDependencyResolutionRequest();
110         request.setMavenProject( project );
111         Invoker.invoke( request, "setRepositorySession", RepositorySystemSession.class, session );
112 
113         final DependencyResolutionResult result = resolveDependencies( request, reactorProjects );
114         org.eclipse.aether.graph.DependencyNode graph =
115             (org.eclipse.aether.graph.DependencyNode) Invoker.invoke( DependencyResolutionResult.class, result,
116                                                                       "getDependencyGraph" );
117 
118         return buildDependencyNode( null, graph, project.getArtifact(), filter );
119     }
120 
121     private DependencyResolutionResult resolveDependencies( DependencyResolutionRequest request,
122                                                             Collection<MavenProject> reactorProjects )
123         throws DependencyGraphBuilderException
124     {
125         try
126         {
127             return resolver.resolve( request );
128         }
129         catch ( DependencyResolutionException e )
130         {
131             if ( reactorProjects == null )
132             {
133                 throw new DependencyGraphBuilderException( "Could not resolve following dependencies: "
134                     + e.getResult().getUnresolvedDependencies(), e );
135             }
136 
137             // try collecting from reactor
138             return collectDependenciesFromReactor( e, reactorProjects );
139         }
140     }
141 
142     private DependencyResolutionResult collectDependenciesFromReactor( DependencyResolutionException e,
143                                                                        Collection<MavenProject> reactorProjects )
144         throws DependencyGraphBuilderException
145     {
146         DependencyResolutionResult result = e.getResult();
147 
148         List<Dependency> reactorDeps = getReactorDependencies( reactorProjects, result.getUnresolvedDependencies() );
149         result.getUnresolvedDependencies().removeAll( reactorDeps );
150         Invoker.invoke( result.getResolvedDependencies(), "addAll", Collection.class, reactorDeps );
151 
152         if ( !result.getUnresolvedDependencies().isEmpty() )
153         {
154             throw new DependencyGraphBuilderException( "Could not resolve nor collect following dependencies: "
155                 + result.getUnresolvedDependencies(), e );
156         }
157 
158         return result;
159     }
160 
161     private List<Dependency> getReactorDependencies( Collection<MavenProject> reactorProjects, List<?> dependencies )
162     {
163         Set<ArtifactKey> reactorProjectsIds = new HashSet<ArtifactKey>();
164         for ( MavenProject project : reactorProjects )
165         {
166             reactorProjectsIds.add( new ArtifactKey( project ) );
167         }
168 
169         List<Dependency> reactorDeps = new ArrayList<Dependency>();
170         for ( Object untypedDependency : dependencies )
171         {
172             Dependency dependency = (Dependency) untypedDependency;
173             org.eclipse.aether.artifact.Artifact depArtifact = dependency.getArtifact();
174 
175             ArtifactKey key =
176                 new ArtifactKey( depArtifact.getGroupId(), depArtifact.getArtifactId(), depArtifact.getVersion() );
177 
178             if ( reactorProjectsIds.contains( key ) )
179             {
180                 reactorDeps.add( dependency );
181             }
182         }
183 
184         return reactorDeps;
185     }
186 
187     private Artifact getDependencyArtifact( Dependency dep )
188     {
189         org.eclipse.aether.artifact.Artifact artifact = dep.getArtifact();
190 
191         return factory.createDependencyArtifact( artifact.getGroupId(), artifact.getArtifactId(),
192                                                  VersionRange.createFromVersion( artifact.getVersion() ),
193                                                  artifact.getProperty( "type", artifact.getExtension() ),
194                                                  artifact.getClassifier(), dep.getScope(), dep.isOptional() );
195     }
196 
197     private DependencyNode buildDependencyNode( DependencyNode parent, org.eclipse.aether.graph.DependencyNode node,
198                                                 Artifact artifact, ArtifactFilter filter )
199     {
200         String premanagedVersion = null; // DependencyManagerUtils.getPremanagedVersion( node );
201         String premanagedScope = null; // DependencyManagerUtils.getPremanagedScope( node );
202 
203         DefaultDependencyNode current =
204             new DefaultDependencyNode( parent, artifact, premanagedVersion, premanagedScope,
205                                        getVersionSelectedFromRange( node.getVersionConstraint() ) );
206 
207         List<DependencyNode> nodes = new ArrayList<DependencyNode>( node.getChildren().size() );
208         for ( org.eclipse.aether.graph.DependencyNode child : node.getChildren() )
209         {
210             Artifact childArtifact = getDependencyArtifact( child.getDependency() );
211 
212             if ( ( filter == null ) || filter.include( childArtifact ) )
213             {
214                 nodes.add( buildDependencyNode( current, child, childArtifact, filter ) );
215             }
216         }
217 
218         current.setChildren( Collections.unmodifiableList( nodes ) );
219 
220         return current;
221     }
222 
223     private String getVersionSelectedFromRange( VersionConstraint constraint )
224     {
225         if ( ( constraint == null ) || ( constraint.getVersion() != null ) )
226         {
227             return null;
228         }
229 
230         return constraint.getRange().toString();
231     }
232 }