1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.project;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.util.Collection;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Objects;
30
31 import org.apache.maven.RepositoryUtils;
32 import org.apache.maven.artifact.Artifact;
33 import org.apache.maven.model.Dependency;
34 import org.apache.maven.model.DependencyManagement;
35 import org.apache.maven.model.Exclusion;
36 import org.codehaus.plexus.util.StringUtils;
37 import org.eclipse.aether.DefaultRepositorySystemSession;
38 import org.eclipse.aether.RepositorySystem;
39 import org.eclipse.aether.RepositorySystemSession;
40 import org.eclipse.aether.RequestTrace;
41 import org.eclipse.aether.artifact.ArtifactType;
42 import org.eclipse.aether.artifact.ArtifactTypeRegistry;
43 import org.eclipse.aether.collection.CollectRequest;
44 import org.eclipse.aether.collection.DependencyCollectionException;
45 import org.eclipse.aether.graph.DependencyFilter;
46 import org.eclipse.aether.graph.DependencyNode;
47 import org.eclipse.aether.graph.DependencyVisitor;
48 import org.eclipse.aether.resolution.ArtifactResult;
49 import org.eclipse.aether.resolution.DependencyRequest;
50 import org.eclipse.aether.util.artifact.ArtifactIdUtils;
51 import org.eclipse.aether.util.artifact.JavaScopes;
52 import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56
57
58
59 @Named
60 @Singleton
61 public class DefaultProjectDependenciesResolver implements ProjectDependenciesResolver {
62 private final Logger logger = LoggerFactory.getLogger(getClass());
63 private final RepositorySystem repoSystem;
64 private final List<RepositorySessionDecorator> decorators;
65
66 @Inject
67 public DefaultProjectDependenciesResolver(
68 RepositorySystem repoSystem, List<RepositorySessionDecorator> decorators) {
69 this.repoSystem = repoSystem;
70 this.decorators = decorators;
71 }
72
73 public DependencyResolutionResult resolve(DependencyResolutionRequest request)
74 throws DependencyResolutionException {
75 final RequestTrace trace = RequestTrace.newChild(null, request);
76
77 final DefaultDependencyResolutionResult result = new DefaultDependencyResolutionResult();
78
79 final MavenProject project = request.getMavenProject();
80 final DependencyFilter filter = request.getResolutionFilter();
81 RepositorySystemSession session = request.getRepositorySession();
82 ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry();
83
84 if (logger.isDebugEnabled()
85 && session.getConfigProperties().get(DependencyManagerUtils.CONFIG_PROP_VERBOSE) == null) {
86 DefaultRepositorySystemSession verbose = new DefaultRepositorySystemSession(session);
87 verbose.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, Boolean.TRUE);
88 session = verbose;
89 }
90
91 for (RepositorySessionDecorator decorator : decorators) {
92 RepositorySystemSession decorated = decorator.decorate(project, session);
93 if (decorated != null) {
94 session = decorated;
95 }
96 }
97
98 CollectRequest collect = new CollectRequest();
99 collect.setRootArtifact(RepositoryUtils.toArtifact(project.getArtifact()));
100 collect.setRequestContext("project");
101 collect.setRepositories(project.getRemoteProjectRepositories());
102
103 if (project.getDependencyArtifacts() == null) {
104 for (Dependency dependency : project.getDependencies()) {
105 if (StringUtils.isEmpty(dependency.getGroupId())
106 || StringUtils.isEmpty(dependency.getArtifactId())
107 || StringUtils.isEmpty(dependency.getVersion())) {
108
109 continue;
110 }
111 collect.addDependency(RepositoryUtils.toDependency(dependency, stereotypes));
112 }
113 } else {
114 Map<String, Dependency> dependencies = new HashMap<>();
115 for (Dependency dependency : project.getDependencies()) {
116 String classifier = dependency.getClassifier();
117 if (classifier == null) {
118 ArtifactType type = stereotypes.get(dependency.getType());
119 if (type != null) {
120 classifier = type.getClassifier();
121 }
122 }
123 String key = ArtifactIdUtils.toVersionlessId(
124 dependency.getGroupId(), dependency.getArtifactId(), dependency.getType(), classifier);
125 dependencies.put(key, dependency);
126 }
127 for (Artifact artifact : project.getDependencyArtifacts()) {
128 String key = artifact.getDependencyConflictId();
129 Dependency dependency = dependencies.get(key);
130 Collection<Exclusion> exclusions = dependency != null ? dependency.getExclusions() : null;
131 org.eclipse.aether.graph.Dependency dep = RepositoryUtils.toDependency(artifact, exclusions);
132 if (!JavaScopes.SYSTEM.equals(dep.getScope())
133 && dep.getArtifact().getFile() != null) {
134
135 org.eclipse.aether.artifact.Artifact art = dep.getArtifact();
136 art = art.setFile(null).setVersion(art.getBaseVersion());
137 dep = dep.setArtifact(art);
138 }
139 collect.addDependency(dep);
140 }
141 }
142
143 DependencyManagement depMgmt = project.getDependencyManagement();
144 if (depMgmt != null) {
145 for (Dependency dependency : depMgmt.getDependencies()) {
146 collect.addManagedDependency(RepositoryUtils.toDependency(dependency, stereotypes));
147 }
148 }
149
150 DependencyRequest depRequest = new DependencyRequest(collect, filter);
151 depRequest.setTrace(trace);
152
153 DependencyNode node;
154 try {
155 collect.setTrace(RequestTrace.newChild(trace, depRequest));
156 node = repoSystem.collectDependencies(session, collect).getRoot();
157 result.setDependencyGraph(node);
158 } catch (DependencyCollectionException e) {
159 result.setDependencyGraph(e.getResult().getRoot());
160 result.setCollectionErrors(e.getResult().getExceptions());
161
162 throw new DependencyResolutionException(
163 result, "Could not resolve dependencies for project " + project.getId() + ": " + e.getMessage(), e);
164 }
165
166 depRequest.setRoot(node);
167
168 if (logger.isWarnEnabled()) {
169 for (DependencyNode child : node.getChildren()) {
170 if (!child.getRelocations().isEmpty()) {
171 org.eclipse.aether.artifact.Artifact relocated =
172 child.getDependency().getArtifact();
173 String message = relocated instanceof org.apache.maven.repository.internal.RelocatedArtifact
174 ? ((org.apache.maven.repository.internal.RelocatedArtifact) relocated).getMessage()
175 : null;
176 logger.warn("The artifact " + child.getRelocations().get(0) + " has been relocated to " + relocated
177 + (message != null ? ": " + message : ""));
178 }
179 }
180 }
181
182 if (logger.isDebugEnabled()) {
183 node.accept(new GraphLogger(project));
184 }
185
186 try {
187 process(result, repoSystem.resolveDependencies(session, depRequest).getArtifactResults());
188 } catch (org.eclipse.aether.resolution.DependencyResolutionException e) {
189 process(result, e.getResult().getArtifactResults());
190
191 throw new DependencyResolutionException(
192 result, "Could not resolve dependencies for project " + project.getId() + ": " + e.getMessage(), e);
193 }
194
195 return result;
196 }
197
198 private void process(DefaultDependencyResolutionResult result, Collection<ArtifactResult> results) {
199 for (ArtifactResult ar : results) {
200 DependencyNode node = ar.getRequest().getDependencyNode();
201 if (ar.isResolved()) {
202 result.addResolvedDependency(node.getDependency());
203 } else {
204 result.setResolutionErrors(node.getDependency(), ar.getExceptions());
205 }
206 }
207 }
208
209
210 class GraphLogger implements DependencyVisitor {
211
212 private final MavenProject project;
213
214 private String indent = "";
215
216 GraphLogger(MavenProject project) {
217 this.project = project;
218 }
219
220 public boolean visitEnter(DependencyNode node) {
221 StringBuilder buffer = new StringBuilder(128);
222 buffer.append(indent);
223 org.eclipse.aether.graph.Dependency dep = node.getDependency();
224 if (dep != null) {
225 org.eclipse.aether.artifact.Artifact art = dep.getArtifact();
226
227 buffer.append(art);
228 if (StringUtils.isNotEmpty(dep.getScope())) {
229 buffer.append(':').append(dep.getScope());
230 }
231
232 if (dep.isOptional()) {
233 buffer.append(" (optional)");
234 }
235
236
237
238
239 if ((node.getManagedBits() & DependencyNode.MANAGED_SCOPE) == DependencyNode.MANAGED_SCOPE) {
240 final String premanagedScope = DependencyManagerUtils.getPremanagedScope(node);
241 buffer.append(" (scope managed from ");
242 buffer.append(Objects.toString(premanagedScope, "default"));
243 buffer.append(')');
244 }
245
246 if ((node.getManagedBits() & DependencyNode.MANAGED_VERSION) == DependencyNode.MANAGED_VERSION) {
247 final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion(node);
248 buffer.append(" (version managed from ");
249 buffer.append(Objects.toString(premanagedVersion, "default"));
250 buffer.append(')');
251 }
252
253 if ((node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL) == DependencyNode.MANAGED_OPTIONAL) {
254 final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional(node);
255 buffer.append(" (optionality managed from ");
256 buffer.append(Objects.toString(premanagedOptional, "default"));
257 buffer.append(')');
258 }
259
260 if ((node.getManagedBits() & DependencyNode.MANAGED_EXCLUSIONS) == DependencyNode.MANAGED_EXCLUSIONS) {
261 final Collection<org.eclipse.aether.graph.Exclusion> premanagedExclusions =
262 DependencyManagerUtils.getPremanagedExclusions(node);
263
264 buffer.append(" (exclusions managed from ");
265 buffer.append(Objects.toString(premanagedExclusions, "default"));
266 buffer.append(')');
267 }
268
269 if ((node.getManagedBits() & DependencyNode.MANAGED_PROPERTIES) == DependencyNode.MANAGED_PROPERTIES) {
270 final Map<String, String> premanagedProperties =
271 DependencyManagerUtils.getPremanagedProperties(node);
272
273 buffer.append(" (properties managed from ");
274 buffer.append(Objects.toString(premanagedProperties, "default"));
275 buffer.append(')');
276 }
277 } else {
278 buffer.append(project.getGroupId());
279 buffer.append(':').append(project.getArtifactId());
280 buffer.append(':').append(project.getPackaging());
281 buffer.append(':').append(project.getVersion());
282 }
283
284 logger.debug(buffer.toString());
285 indent += " ";
286 return true;
287 }
288
289 public boolean visitLeave(DependencyNode node) {
290 indent = indent.substring(0, indent.length() - 3);
291 return true;
292 }
293 }
294 }