1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.internal.impl.collect;
20
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.HashSet;
25 import java.util.LinkedHashMap;
26 import java.util.List;
27 import java.util.Map;
28
29 import org.eclipse.aether.DefaultRepositorySystemSession;
30 import org.eclipse.aether.RepositoryException;
31 import org.eclipse.aether.RepositorySystemSession;
32 import org.eclipse.aether.RequestTrace;
33 import org.eclipse.aether.artifact.Artifact;
34 import org.eclipse.aether.collection.CollectRequest;
35 import org.eclipse.aether.collection.CollectResult;
36 import org.eclipse.aether.collection.DependencyCollectionException;
37 import org.eclipse.aether.collection.DependencyGraphTransformer;
38 import org.eclipse.aether.collection.DependencyTraverser;
39 import org.eclipse.aether.collection.VersionFilter;
40 import org.eclipse.aether.graph.DefaultDependencyNode;
41 import org.eclipse.aether.graph.Dependency;
42 import org.eclipse.aether.graph.DependencyNode;
43 import org.eclipse.aether.impl.ArtifactDescriptorReader;
44 import org.eclipse.aether.impl.DependencyCollector;
45 import org.eclipse.aether.impl.RemoteRepositoryManager;
46 import org.eclipse.aether.impl.VersionRangeResolver;
47 import org.eclipse.aether.impl.scope.InternalScopeManager;
48 import org.eclipse.aether.repository.ArtifactRepository;
49 import org.eclipse.aether.repository.RemoteRepository;
50 import org.eclipse.aether.resolution.ArtifactDescriptorException;
51 import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
52 import org.eclipse.aether.resolution.ArtifactDescriptorResult;
53 import org.eclipse.aether.resolution.VersionRangeRequest;
54 import org.eclipse.aether.resolution.VersionRangeResolutionException;
55 import org.eclipse.aether.resolution.VersionRangeResult;
56 import org.eclipse.aether.scope.ResolutionScope;
57 import org.eclipse.aether.scope.SystemDependencyScope;
58 import org.eclipse.aether.util.ConfigUtils;
59 import org.eclipse.aether.util.graph.transformer.TransformationContextKeys;
60 import org.eclipse.aether.version.Version;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 import static java.util.Objects.requireNonNull;
65
66
67
68
69
70
71 public abstract class DependencyCollectorDelegate implements DependencyCollector {
72
73
74
75
76
77
78
79
80 public static final String CONFIG_PROP_MAX_EXCEPTIONS =
81 DefaultDependencyCollector.CONFIG_PROPS_PREFIX + "maxExceptions";
82
83 public static final int DEFAULT_MAX_EXCEPTIONS = 50;
84
85
86
87
88
89
90
91
92 public static final String CONFIG_PROP_MAX_CYCLES = DefaultDependencyCollector.CONFIG_PROPS_PREFIX + "maxCycles";
93
94 public static final int DEFAULT_MAX_CYCLES = 10;
95
96 protected final Logger logger = LoggerFactory.getLogger(getClass());
97
98 protected final RemoteRepositoryManager remoteRepositoryManager;
99
100 protected final ArtifactDescriptorReader descriptorReader;
101
102 protected final VersionRangeResolver versionRangeResolver;
103
104 protected DependencyCollectorDelegate(
105 RemoteRepositoryManager remoteRepositoryManager,
106 ArtifactDescriptorReader artifactDescriptorReader,
107 VersionRangeResolver versionRangeResolver) {
108 this.remoteRepositoryManager =
109 requireNonNull(remoteRepositoryManager, "remote repository manager cannot be null");
110 this.descriptorReader = requireNonNull(artifactDescriptorReader, "artifact descriptor reader cannot be null");
111 this.versionRangeResolver = requireNonNull(versionRangeResolver, "version range resolver cannot be null");
112 }
113
114 @SuppressWarnings("checkstyle:methodlength")
115 @Override
116 public final CollectResult collectDependencies(RepositorySystemSession session, CollectRequest request)
117 throws DependencyCollectionException {
118 requireNonNull(session, "session cannot be null");
119 requireNonNull(request, "request cannot be null");
120
121 InternalScopeManager scopeManager = (InternalScopeManager) session.getScopeManager();
122 session = setUpSession(session, request, scopeManager);
123
124 RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
125
126 CollectResult result = new CollectResult(request);
127
128 DependencyTraverser depTraverser = session.getDependencyTraverser();
129 VersionFilter verFilter = session.getVersionFilter();
130
131 Dependency root = request.getRoot();
132 List<RemoteRepository> repositories = request.getRepositories();
133 List<Dependency> dependencies = request.getDependencies();
134 List<Dependency> managedDependencies = request.getManagedDependencies();
135
136 Map<String, Object> stats = new LinkedHashMap<>();
137 long time1 = System.nanoTime();
138
139 DefaultDependencyNode node;
140 if (root != null) {
141 List<? extends Version> versions;
142 VersionRangeResult rangeResult;
143 try {
144 VersionRangeRequest rangeRequest = new VersionRangeRequest(
145 root.getArtifact(), request.getRepositories(), request.getRequestContext());
146 rangeRequest.setTrace(trace);
147 rangeResult = versionRangeResolver.resolveVersionRange(session, rangeRequest);
148 versions = filterVersions(root, rangeResult, verFilter, new DefaultVersionFilterContext(session));
149 } catch (VersionRangeResolutionException e) {
150 result.addException(e);
151 throw new DependencyCollectionException(result, e.getMessage());
152 }
153
154 Version version = versions.get(versions.size() - 1);
155 root = root.setArtifact(root.getArtifact().setVersion(version.toString()));
156
157 ArtifactDescriptorResult descriptorResult;
158 try {
159 ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest();
160 descriptorRequest.setArtifact(root.getArtifact());
161 descriptorRequest.setRepositories(request.getRepositories());
162 descriptorRequest.setRequestContext(request.getRequestContext());
163 descriptorRequest.setTrace(trace);
164 if (isLackingDescriptor(session, root.getArtifact())) {
165 descriptorResult = new ArtifactDescriptorResult(descriptorRequest);
166 } else {
167 descriptorResult = descriptorReader.readArtifactDescriptor(session, descriptorRequest);
168 }
169 } catch (ArtifactDescriptorException e) {
170 result.addException(e);
171 throw new DependencyCollectionException(result, e.getMessage());
172 }
173
174 root = root.setArtifact(descriptorResult.getArtifact());
175
176 if (!session.isIgnoreArtifactDescriptorRepositories()) {
177 repositories = remoteRepositoryManager.aggregateRepositories(
178 session, repositories, descriptorResult.getRepositories(), true);
179 }
180 dependencies = mergeDeps(dependencies, descriptorResult.getDependencies());
181 managedDependencies = mergeDeps(managedDependencies, descriptorResult.getManagedDependencies());
182
183 node = new DefaultDependencyNode(root);
184 node.setRequestContext(request.getRequestContext());
185 node.setRelocations(descriptorResult.getRelocations());
186 node.setVersionConstraint(rangeResult.getVersionConstraint());
187 node.setVersion(version);
188 node.setAliases(descriptorResult.getAliases());
189 node.setRepositories(request.getRepositories());
190 } else {
191 node = new DefaultDependencyNode(request.getRootArtifact());
192 node.setRequestContext(request.getRequestContext());
193 node.setRepositories(request.getRepositories());
194 }
195
196 result.setRoot(node);
197
198 boolean traverse = root == null || depTraverser == null || depTraverser.traverseDependency(root);
199 String errorPath = null;
200 if (traverse && !dependencies.isEmpty()) {
201 DataPool pool = new DataPool(session);
202
203 DefaultDependencyCollectionContext context = new DefaultDependencyCollectionContext(
204 session, request.getRootArtifact(), root, managedDependencies);
205
206 DefaultVersionFilterContext versionContext = new DefaultVersionFilterContext(session);
207
208 Results results = new Results(result, session);
209
210 doCollectDependencies(
211 session,
212 trace,
213 pool,
214 context,
215 versionContext,
216 request,
217 node,
218 repositories,
219 dependencies,
220 managedDependencies,
221 results);
222
223 errorPath = results.getErrorPath();
224 }
225
226 long time2 = System.nanoTime();
227
228 DependencyGraphTransformer transformer = session.getDependencyGraphTransformer();
229 if (transformer != null) {
230 try {
231 DefaultDependencyGraphTransformationContext context =
232 new DefaultDependencyGraphTransformationContext(session);
233 context.put(TransformationContextKeys.STATS, stats);
234 result.setRoot(transformer.transformGraph(node, context));
235 } catch (RepositoryException e) {
236 result.addException(e);
237 }
238 }
239
240 long time3 = System.nanoTime();
241 if (logger.isDebugEnabled()) {
242 stats.put(getClass().getSimpleName() + ".collectTime", time2 - time1);
243 stats.put(getClass().getSimpleName() + ".transformTime", time3 - time2);
244 logger.debug("Dependency collection stats {}", stats);
245 }
246
247 if (errorPath != null) {
248 throw new DependencyCollectionException(result, "Failed to collect dependencies at " + errorPath);
249 }
250 if (!result.getExceptions().isEmpty()) {
251 throw new DependencyCollectionException(result);
252 }
253
254 if (request.getResolutionScope() != null) {
255 return scopeManager.postProcess(request.getResolutionScope(), result);
256 } else {
257 return result;
258 }
259 }
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275 protected RequestTrace collectStepTrace(
276 RequestTrace trace, String context, List<DependencyNode> path, Dependency node) {
277 return RequestTrace.newChild(trace, new CollectStepDataImpl(context, path, node));
278 }
279
280 @SuppressWarnings("checkstyle:parameternumber")
281 protected abstract void doCollectDependencies(
282 RepositorySystemSession session,
283 RequestTrace trace,
284 DataPool pool,
285 DefaultDependencyCollectionContext context,
286 DefaultVersionFilterContext versionContext,
287 CollectRequest request,
288 DependencyNode node,
289 List<RemoteRepository> repositories,
290 List<Dependency> dependencies,
291 List<Dependency> managedDependencies,
292 Results results)
293 throws DependencyCollectionException;
294
295 protected RepositorySystemSession setUpSession(
296 RepositorySystemSession session, CollectRequest collectRequest, InternalScopeManager scopeManager) {
297 DefaultRepositorySystemSession optimized = new DefaultRepositorySystemSession(session);
298 optimized.setArtifactTypeRegistry(CachingArtifactTypeRegistry.newInstance(session));
299
300 ResolutionScope resolutionScope = collectRequest.getResolutionScope();
301 if (resolutionScope != null) {
302 requireNonNull(scopeManager, "ScopeManager is not set on session");
303 optimized.setDependencySelector(scopeManager.getDependencySelector(resolutionScope));
304 optimized.setDependencyGraphTransformer(scopeManager.getDependencyGraphTransformer(resolutionScope));
305 }
306 return optimized;
307 }
308
309 protected List<Dependency> mergeDeps(List<Dependency> dominant, List<Dependency> recessive) {
310 List<Dependency> result;
311 if (dominant == null || dominant.isEmpty()) {
312 result = recessive;
313 } else if (recessive == null || recessive.isEmpty()) {
314 result = dominant;
315 } else {
316 int initialCapacity = dominant.size() + recessive.size();
317 result = new ArrayList<>(initialCapacity);
318 Collection<String> ids = new HashSet<>(initialCapacity, 1.0f);
319 for (Dependency dependency : dominant) {
320 ids.add(getId(dependency.getArtifact()));
321 result.add(dependency);
322 }
323 for (Dependency dependency : recessive) {
324 if (!ids.contains(getId(dependency.getArtifact()))) {
325 result.add(dependency);
326 }
327 }
328 }
329 return result;
330 }
331
332 protected static String getId(Artifact a) {
333 return a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getClassifier() + ':' + a.getExtension();
334 }
335
336 @SuppressWarnings("checkstyle:parameternumber")
337 protected static DefaultDependencyNode createDependencyNode(
338 List<Artifact> relocations,
339 PremanagedDependency preManaged,
340 VersionRangeResult rangeResult,
341 Version version,
342 Dependency d,
343 Collection<Artifact> aliases,
344 List<RemoteRepository> repos,
345 String requestContext) {
346 DefaultDependencyNode child = new DefaultDependencyNode(d);
347 preManaged.applyTo(child);
348 child.setRelocations(relocations);
349 child.setVersionConstraint(rangeResult.getVersionConstraint());
350 child.setVersion(version);
351 child.setAliases(aliases);
352 child.setRepositories(repos);
353 child.setRequestContext(requestContext);
354 return child;
355 }
356
357 protected static DefaultDependencyNode createDependencyNode(
358 List<Artifact> relocations,
359 PremanagedDependency preManaged,
360 VersionRangeResult rangeResult,
361 Version version,
362 Dependency d,
363 ArtifactDescriptorResult descriptorResult,
364 DependencyNode cycleNode) {
365 DefaultDependencyNode child = createDependencyNode(
366 relocations,
367 preManaged,
368 rangeResult,
369 version,
370 d,
371 descriptorResult.getAliases(),
372 cycleNode.getRepositories(),
373 cycleNode.getRequestContext());
374 child.setChildren(cycleNode.getChildren());
375 return child;
376 }
377
378 protected static ArtifactDescriptorRequest createArtifactDescriptorRequest(
379 String requestContext, RequestTrace requestTrace, List<RemoteRepository> repositories, Dependency d) {
380 ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest();
381 descriptorRequest.setArtifact(d.getArtifact());
382 descriptorRequest.setRepositories(repositories);
383 descriptorRequest.setRequestContext(requestContext);
384 descriptorRequest.setTrace(requestTrace);
385 return descriptorRequest;
386 }
387
388 protected static VersionRangeRequest createVersionRangeRequest(
389 String requestContext,
390 RequestTrace requestTrace,
391 List<RemoteRepository> repositories,
392 Dependency dependency) {
393 VersionRangeRequest rangeRequest = new VersionRangeRequest();
394 rangeRequest.setArtifact(dependency.getArtifact());
395 rangeRequest.setRepositories(repositories);
396 rangeRequest.setRequestContext(requestContext);
397 rangeRequest.setTrace(requestTrace);
398 return rangeRequest;
399 }
400
401 protected VersionRangeResult cachedResolveRangeResult(
402 VersionRangeRequest rangeRequest, DataPool pool, RepositorySystemSession session)
403 throws VersionRangeResolutionException {
404 Object key = pool.toKey(rangeRequest);
405 VersionRangeResult rangeResult = pool.getConstraint(key, rangeRequest);
406 if (rangeResult == null) {
407 rangeResult = versionRangeResolver.resolveVersionRange(session, rangeRequest);
408 pool.putConstraint(key, rangeResult);
409 }
410 return rangeResult;
411 }
412
413 protected static boolean isLackingDescriptor(RepositorySystemSession session, Artifact artifact) {
414 SystemDependencyScope systemDependencyScope = session.getSystemDependencyScope();
415 return systemDependencyScope != null && systemDependencyScope.getSystemPath(artifact) != null;
416 }
417
418 protected static List<RemoteRepository> getRemoteRepositories(
419 ArtifactRepository repository, List<RemoteRepository> repositories) {
420 if (repository instanceof RemoteRepository) {
421 return Collections.singletonList((RemoteRepository) repository);
422 }
423 if (repository != null) {
424 return Collections.emptyList();
425 }
426 return repositories;
427 }
428
429 protected static List<? extends Version> filterVersions(
430 Dependency dependency,
431 VersionRangeResult rangeResult,
432 VersionFilter verFilter,
433 DefaultVersionFilterContext verContext)
434 throws VersionRangeResolutionException {
435 if (rangeResult.getVersions().isEmpty()) {
436 throw new VersionRangeResolutionException(
437 rangeResult, "No versions available for " + dependency.getArtifact() + " within specified range");
438 }
439
440 List<? extends Version> versions;
441 if (verFilter != null && rangeResult.getVersionConstraint().getRange() != null) {
442 verContext.set(dependency, rangeResult);
443 try {
444 verFilter.filterVersions(verContext);
445 } catch (RepositoryException e) {
446 throw new VersionRangeResolutionException(
447 rangeResult, "Failed to filter versions for " + dependency.getArtifact(), e);
448 }
449 versions = verContext.get();
450 if (versions.isEmpty()) {
451 throw new VersionRangeResolutionException(
452 rangeResult,
453 "No acceptable versions for " + dependency.getArtifact() + ": " + rangeResult.getVersions());
454 }
455 } else {
456 versions = rangeResult.getVersions();
457 }
458 return versions;
459 }
460
461
462
463
464 protected static class Results {
465
466 private final CollectResult result;
467
468 final int maxExceptions;
469
470 final int maxCycles;
471
472 String errorPath;
473
474 public Results(CollectResult result, RepositorySystemSession session) {
475 this.result = result;
476
477 maxExceptions = ConfigUtils.getInteger(session, DEFAULT_MAX_EXCEPTIONS, CONFIG_PROP_MAX_EXCEPTIONS);
478
479 maxCycles = ConfigUtils.getInteger(session, DEFAULT_MAX_CYCLES, CONFIG_PROP_MAX_CYCLES);
480 }
481
482 public CollectResult getResult() {
483 return result;
484 }
485
486 public String getErrorPath() {
487 return errorPath;
488 }
489
490 public void addException(Dependency dependency, Exception e, List<DependencyNode> nodes) {
491 if (maxExceptions < 0 || result.getExceptions().size() < maxExceptions) {
492 result.addException(e);
493 if (errorPath == null) {
494 StringBuilder buffer = new StringBuilder(256);
495 for (DependencyNode node : nodes) {
496 if (buffer.length() > 0) {
497 buffer.append(" -> ");
498 }
499 Dependency dep = node.getDependency();
500 if (dep != null) {
501 buffer.append(dep.getArtifact());
502 }
503 }
504 if (buffer.length() > 0) {
505 buffer.append(" -> ");
506 }
507 buffer.append(dependency.getArtifact());
508 errorPath = buffer.toString();
509 }
510 }
511 }
512
513 public void addCycle(List<DependencyNode> nodes, int cycleEntry, Dependency dependency) {
514 if (maxCycles < 0 || result.getCycles().size() < maxCycles) {
515 result.addCycle(new DefaultDependencyCycle(nodes, cycleEntry, dependency));
516 }
517 }
518 }
519 }