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(session, 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(session, resolutionScope));
316 }
317 return optimized;
318 }
319
320 protected List<Dependency> mergeDeps(List<Dependency> dominant, List<Dependency> recessive) {
321 List<Dependency> result;
322 if (dominant == null || dominant.isEmpty()) {
323 result = recessive;
324 } else if (recessive == null || recessive.isEmpty()) {
325 result = dominant;
326 } else {
327 int initialCapacity = dominant.size() + recessive.size();
328 result = new ArrayList<>(initialCapacity);
329 Collection<String> ids = new HashSet<>(initialCapacity, 1.0f);
330 for (Dependency dependency : dominant) {
331 ids.add(getId(dependency.getArtifact()));
332 result.add(dependency);
333 }
334 for (Dependency dependency : recessive) {
335 if (!ids.contains(getId(dependency.getArtifact()))) {
336 result.add(dependency);
337 }
338 }
339 }
340 return result;
341 }
342
343 protected static String getId(Artifact a) {
344 return a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getClassifier() + ':' + a.getExtension();
345 }
346
347 @SuppressWarnings("checkstyle:parameternumber")
348 protected static DefaultDependencyNode createDependencyNode(
349 List<Artifact> relocations,
350 PremanagedDependency preManaged,
351 VersionRangeResult rangeResult,
352 Version version,
353 Dependency d,
354 Collection<Artifact> aliases,
355 List<RemoteRepository> repos,
356 String requestContext) {
357 DefaultDependencyNode child = new DefaultDependencyNode(d);
358 preManaged.applyTo(child);
359 child.setRelocations(relocations);
360 child.setVersionConstraint(rangeResult.getVersionConstraint());
361 child.setVersion(version);
362 child.setAliases(aliases);
363 child.setRepositories(repos);
364 child.setRequestContext(requestContext);
365 return child;
366 }
367
368 protected static DefaultDependencyNode createDependencyNode(
369 List<Artifact> relocations,
370 PremanagedDependency preManaged,
371 VersionRangeResult rangeResult,
372 Version version,
373 Dependency d,
374 ArtifactDescriptorResult descriptorResult,
375 DependencyNode cycleNode) {
376 DefaultDependencyNode child = createDependencyNode(
377 relocations,
378 preManaged,
379 rangeResult,
380 version,
381 d,
382 descriptorResult.getAliases(),
383 cycleNode.getRepositories(),
384 cycleNode.getRequestContext());
385 child.setChildren(cycleNode.getChildren());
386 return child;
387 }
388
389 protected static ArtifactDescriptorRequest createArtifactDescriptorRequest(
390 String requestContext, RequestTrace requestTrace, List<RemoteRepository> repositories, Dependency d) {
391 ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest();
392 descriptorRequest.setArtifact(d.getArtifact());
393 descriptorRequest.setRepositories(repositories);
394 descriptorRequest.setRequestContext(requestContext);
395 descriptorRequest.setTrace(requestTrace);
396 return descriptorRequest;
397 }
398
399 protected static VersionRangeRequest createVersionRangeRequest(
400 String requestContext,
401 RequestTrace requestTrace,
402 List<RemoteRepository> repositories,
403 Dependency dependency) {
404 VersionRangeRequest rangeRequest = new VersionRangeRequest();
405 rangeRequest.setArtifact(dependency.getArtifact());
406 rangeRequest.setRepositories(repositories);
407 rangeRequest.setRequestContext(requestContext);
408 rangeRequest.setTrace(requestTrace);
409 return rangeRequest;
410 }
411
412 protected VersionRangeResult cachedResolveRangeResult(
413 VersionRangeRequest rangeRequest, DataPool pool, RepositorySystemSession session)
414 throws VersionRangeResolutionException {
415 Object key = pool.toKey(rangeRequest);
416 VersionRangeResult rangeResult = pool.getConstraint(key, rangeRequest);
417 if (rangeResult == null) {
418 rangeResult = versionRangeResolver.resolveVersionRange(session, rangeRequest);
419 pool.putConstraint(key, rangeResult);
420 }
421 return rangeResult;
422 }
423
424 protected static boolean isLackingDescriptor(RepositorySystemSession session, Artifact artifact) {
425 SystemDependencyScope systemDependencyScope = session.getSystemDependencyScope();
426 return systemDependencyScope != null && systemDependencyScope.getSystemPath(artifact) != null;
427 }
428
429 protected static List<RemoteRepository> getRemoteRepositories(
430 ArtifactRepository repository, List<RemoteRepository> repositories) {
431 if (repository instanceof RemoteRepository) {
432 return Collections.singletonList((RemoteRepository) repository);
433 }
434 if (repository != null) {
435 return Collections.emptyList();
436 }
437 return repositories;
438 }
439
440 protected static List<? extends Version> filterVersions(
441 Dependency dependency,
442 VersionRangeResult rangeResult,
443 VersionFilter verFilter,
444 DefaultVersionFilterContext verContext)
445 throws VersionRangeResolutionException {
446 if (rangeResult.getVersions().isEmpty()) {
447 throw new VersionRangeResolutionException(
448 rangeResult, "No versions available for " + dependency.getArtifact() + " within specified range");
449 }
450
451 List<? extends Version> versions;
452 if (verFilter != null && rangeResult.getVersionConstraint().getRange() != null) {
453 verContext.set(dependency, rangeResult);
454 try {
455 verFilter.filterVersions(verContext);
456 } catch (RepositoryException e) {
457 throw new VersionRangeResolutionException(
458 rangeResult, "Failed to filter versions for " + dependency.getArtifact(), e);
459 }
460 versions = verContext.get();
461 if (versions.isEmpty()) {
462 throw new VersionRangeResolutionException(
463 rangeResult,
464 "No acceptable versions for " + dependency.getArtifact() + ": " + rangeResult.getVersions());
465 }
466 } else {
467 versions = rangeResult.getVersions();
468 }
469 return versions;
470 }
471
472 protected ArtifactDescriptorResult resolveCachedArtifactDescriptor(
473 DataPool pool,
474 ArtifactDescriptorRequest descriptorRequest,
475 RepositorySystemSession session,
476 Dependency d,
477 Results results,
478 List<DependencyNode> nodes) {
479 DataPool.DescriptorKey key = pool.toKey(descriptorRequest);
480 ArtifactDescriptorResult descriptorResult = pool.getDescriptor(key, descriptorRequest);
481 if (descriptorResult == null) {
482 try {
483 descriptorResult = descriptorReader.readArtifactDescriptor(session, descriptorRequest);
484 for (ArtifactDecorator decorator : Utils.getArtifactDecorators(session, artifactDecoratorFactories)) {
485 descriptorResult.setArtifact(decorator.decorateArtifact(descriptorResult));
486 }
487 pool.putDescriptor(key, descriptorResult);
488 } catch (ArtifactDescriptorException e) {
489 results.addException(d, e, nodes);
490 pool.putDescriptor(key, e);
491 return null;
492 }
493 } else if (descriptorResult == DataPool.NO_DESCRIPTOR) {
494 return null;
495 }
496 return descriptorResult;
497 }
498
499
500
501
502 protected static class Results {
503
504 private final CollectResult result;
505
506 final int maxExceptions;
507
508 final int maxCycles;
509
510 String errorPath;
511
512 public Results(CollectResult result, RepositorySystemSession session) {
513 this.result = result;
514
515 maxExceptions = ConfigUtils.getInteger(session, DEFAULT_MAX_EXCEPTIONS, CONFIG_PROP_MAX_EXCEPTIONS);
516
517 maxCycles = ConfigUtils.getInteger(session, DEFAULT_MAX_CYCLES, CONFIG_PROP_MAX_CYCLES);
518 }
519
520 public CollectResult getResult() {
521 return result;
522 }
523
524 public String getErrorPath() {
525 return errorPath;
526 }
527
528 public void addException(Dependency dependency, Exception e, List<DependencyNode> nodes) {
529 if (maxExceptions < 0 || result.getExceptions().size() < maxExceptions) {
530 result.addException(e);
531 if (errorPath == null) {
532 StringBuilder buffer = new StringBuilder(256);
533 for (DependencyNode node : nodes) {
534 if (buffer.length() > 0) {
535 buffer.append(" -> ");
536 }
537 Dependency dep = node.getDependency();
538 if (dep != null) {
539 buffer.append(dep.getArtifact());
540 }
541 }
542 if (buffer.length() > 0) {
543 buffer.append(" -> ");
544 }
545 buffer.append(dependency.getArtifact());
546 errorPath = buffer.toString();
547 }
548 }
549 }
550
551 public void addCycle(List<DependencyNode> nodes, int cycleEntry, Dependency dependency) {
552 if (maxCycles < 0 || result.getCycles().size() < maxCycles) {
553 result.addCycle(new DefaultDependencyCycle(nodes, cycleEntry, dependency));
554 }
555 }
556 }
557 }