View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.shared.dependency.graph.internal;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.List;
27  
28  import org.apache.maven.RepositoryUtils;
29  import org.apache.maven.artifact.Artifact;
30  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
31  import org.apache.maven.project.DefaultDependencyResolutionRequest;
32  import org.apache.maven.project.DependencyResolutionException;
33  import org.apache.maven.project.DependencyResolutionRequest;
34  import org.apache.maven.project.DependencyResolutionResult;
35  import org.apache.maven.project.MavenProject;
36  import org.apache.maven.project.ProjectBuildingRequest;
37  import org.apache.maven.project.ProjectDependenciesResolver;
38  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
39  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
40  import org.apache.maven.shared.dependency.graph.DependencyNode;
41  import org.eclipse.aether.DefaultRepositorySystemSession;
42  import org.eclipse.aether.RepositorySystemSession;
43  import org.eclipse.aether.graph.Dependency;
44  import org.eclipse.aether.graph.DependencyFilter;
45  import org.eclipse.aether.graph.Exclusion;
46  import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
47  import org.eclipse.aether.version.VersionConstraint;
48  
49  import static org.eclipse.aether.util.graph.manager.DependencyManagerUtils.NODE_DATA_PREMANAGED_VERSION;
50  
51  /**
52   * Wrapper around Eclipse Aether dependency resolver, used in Maven 3.1.
53   *
54   * @see ProjectDependenciesResolver
55   * @author Hervé Boutemy
56   * @since 2.1
57   */
58  @Named
59  public class DefaultDependencyGraphBuilder implements DependencyGraphBuilder {
60      private final ProjectDependenciesResolver resolver;
61  
62      @Inject
63      public DefaultDependencyGraphBuilder(ProjectDependenciesResolver resolver) {
64          this.resolver = resolver;
65      }
66  
67      /**
68       * Builds the dependency graph for Maven 3.1+.
69       *
70       * @param buildingRequest the buildingRequest
71       * @param filter artifact filter (can be <code>null</code>)
72       * @return DependencyNode containing the dependency graph.
73       * @throws DependencyGraphBuilderException if some of the dependencies could not be resolved.
74       */
75      @Override
76      public DependencyNode buildDependencyGraph(ProjectBuildingRequest buildingRequest, ArtifactFilter filter)
77              throws DependencyGraphBuilderException {
78          MavenProject project = buildingRequest.getProject();
79  
80          RepositorySystemSession session = buildingRequest.getRepositorySession();
81  
82          if (Boolean.TRUE != session.getConfigProperties().get(NODE_DATA_PREMANAGED_VERSION)) {
83              DefaultRepositorySystemSession newSession = new DefaultRepositorySystemSession(session);
84              newSession.setConfigProperty(NODE_DATA_PREMANAGED_VERSION, true);
85              session = newSession;
86          }
87  
88          final DependencyResolutionRequest request = new DefaultDependencyResolutionRequest();
89          request.setMavenProject(project);
90          request.setRepositorySession(session);
91          // only download the poms, not the artifacts
92          DependencyFilter collectFilter = (node, parents) -> false;
93          request.setResolutionFilter(collectFilter);
94  
95          final DependencyResolutionResult result = resolveDependencies(request);
96  
97          org.eclipse.aether.graph.DependencyNode graph = result.getDependencyGraph();
98  
99          return buildDependencyNode(null, graph, project.getArtifact(), filter);
100     }
101 
102     private DependencyResolutionResult resolveDependencies(DependencyResolutionRequest request)
103             throws DependencyGraphBuilderException {
104         try {
105             return resolver.resolve(request);
106         } catch (DependencyResolutionException e) {
107             throw new DependencyGraphBuilderException(
108                     "Could not resolve following dependencies: " + e.getResult().getUnresolvedDependencies(), e);
109         }
110     }
111 
112     private Artifact getDependencyArtifact(Dependency dep) {
113         org.eclipse.aether.artifact.Artifact artifact = dep.getArtifact();
114 
115         Artifact mavenArtifact = RepositoryUtils.toArtifact(artifact);
116 
117         mavenArtifact.setScope(dep.getScope());
118         mavenArtifact.setOptional(dep.isOptional());
119 
120         return mavenArtifact;
121     }
122 
123     private DependencyNode buildDependencyNode(
124             DependencyNode parent,
125             org.eclipse.aether.graph.DependencyNode node,
126             Artifact artifact,
127             ArtifactFilter filter) {
128         String premanagedVersion = DependencyManagerUtils.getPremanagedVersion(node);
129         String premanagedScope = DependencyManagerUtils.getPremanagedScope(node);
130 
131         List<org.apache.maven.model.Exclusion> exclusions = null;
132         Boolean optional = artifact.isOptional();
133         if (node.getDependency() != null) {
134             exclusions = new ArrayList<>(node.getDependency().getExclusions().size());
135             for (Exclusion exclusion : node.getDependency().getExclusions()) {
136                 org.apache.maven.model.Exclusion modelExclusion = new org.apache.maven.model.Exclusion();
137                 modelExclusion.setGroupId(exclusion.getGroupId());
138                 modelExclusion.setArtifactId(exclusion.getArtifactId());
139                 exclusions.add(modelExclusion);
140             }
141         }
142 
143         DefaultDependencyNode current = new DefaultDependencyNode(
144                 parent,
145                 artifact,
146                 premanagedVersion,
147                 premanagedScope,
148                 getVersionSelectedFromRange(node.getVersionConstraint()),
149                 optional,
150                 exclusions);
151 
152         List<DependencyNode> nodes = new ArrayList<>(node.getChildren().size());
153         for (org.eclipse.aether.graph.DependencyNode child : node.getChildren()) {
154             Artifact childArtifact = getDependencyArtifact(child.getDependency());
155 
156             if ((filter == null) || filter.include(childArtifact)) {
157                 nodes.add(buildDependencyNode(current, child, childArtifact, filter));
158             }
159         }
160 
161         current.setChildren(Collections.unmodifiableList(nodes));
162 
163         return current;
164     }
165 
166     private String getVersionSelectedFromRange(VersionConstraint constraint) {
167         if ((constraint == null) || (constraint.getVersion() != null)) {
168             return null;
169         }
170 
171         return constraint.getRange().toString();
172     }
173 }