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