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