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