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.artifact.ArtifactProperties;
35 import org.eclipse.aether.collection.CollectRequest;
36 import org.eclipse.aether.collection.CollectResult;
37 import org.eclipse.aether.collection.DependencyCollectionException;
38 import org.eclipse.aether.collection.DependencyGraphTransformer;
39 import org.eclipse.aether.collection.DependencyTraverser;
40 import org.eclipse.aether.collection.VersionFilter;
41 import org.eclipse.aether.graph.DefaultDependencyNode;
42 import org.eclipse.aether.graph.Dependency;
43 import org.eclipse.aether.graph.DependencyNode;
44 import org.eclipse.aether.impl.ArtifactDescriptorReader;
45 import org.eclipse.aether.impl.DependencyCollector;
46 import org.eclipse.aether.impl.RemoteRepositoryManager;
47 import org.eclipse.aether.impl.VersionRangeResolver;
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.spi.locator.ServiceLocator;
57 import org.eclipse.aether.util.ConfigUtils;
58 import org.eclipse.aether.util.graph.transformer.TransformationContextKeys;
59 import org.eclipse.aether.version.Version;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62
63 import static java.util.Objects.requireNonNull;
64
65
66
67
68
69
70 public abstract class DependencyCollectorDelegate implements DependencyCollector {
71 protected static final String CONFIG_PROP_MAX_EXCEPTIONS = "aether.dependencyCollector.maxExceptions";
72
73 protected static final int CONFIG_PROP_MAX_EXCEPTIONS_DEFAULT = 50;
74
75 protected static final String CONFIG_PROP_MAX_CYCLES = "aether.dependencyCollector.maxCycles";
76
77 protected static final int CONFIG_PROP_MAX_CYCLES_DEFAULT = 10;
78
79 protected final Logger logger = LoggerFactory.getLogger(getClass());
80
81 protected RemoteRepositoryManager remoteRepositoryManager;
82
83 protected ArtifactDescriptorReader descriptorReader;
84
85 protected VersionRangeResolver versionRangeResolver;
86
87
88
89
90
91
92 @Deprecated
93 protected DependencyCollectorDelegate() {
94
95 }
96
97 protected DependencyCollectorDelegate(
98 RemoteRepositoryManager remoteRepositoryManager,
99 ArtifactDescriptorReader artifactDescriptorReader,
100 VersionRangeResolver versionRangeResolver) {
101 setRemoteRepositoryManager(remoteRepositoryManager);
102 setArtifactDescriptorReader(artifactDescriptorReader);
103 setVersionRangeResolver(versionRangeResolver);
104 }
105
106 public void initService(ServiceLocator locator) {
107 setRemoteRepositoryManager(locator.getService(RemoteRepositoryManager.class));
108 setArtifactDescriptorReader(locator.getService(ArtifactDescriptorReader.class));
109 setVersionRangeResolver(locator.getService(VersionRangeResolver.class));
110 }
111
112 public DependencyCollector setRemoteRepositoryManager(RemoteRepositoryManager remoteRepositoryManager) {
113 this.remoteRepositoryManager =
114 requireNonNull(remoteRepositoryManager, "remote repository manager cannot be null");
115 return this;
116 }
117
118 public DependencyCollector setArtifactDescriptorReader(ArtifactDescriptorReader artifactDescriptorReader) {
119 descriptorReader = requireNonNull(artifactDescriptorReader, "artifact descriptor reader cannot be null");
120 return this;
121 }
122
123 public DependencyCollector setVersionRangeResolver(VersionRangeResolver versionRangeResolver) {
124 this.versionRangeResolver = requireNonNull(versionRangeResolver, "version range resolver cannot be null");
125 return this;
126 }
127
128 @SuppressWarnings("checkstyle:methodlength")
129 @Override
130 public final CollectResult collectDependencies(RepositorySystemSession session, CollectRequest request)
131 throws DependencyCollectionException {
132 requireNonNull(session, "session cannot be null");
133 requireNonNull(request, "request cannot be null");
134 session = optimizeSession(session);
135
136 RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
137
138 CollectResult result = new CollectResult(request);
139
140 DependencyTraverser depTraverser = session.getDependencyTraverser();
141 VersionFilter verFilter = session.getVersionFilter();
142
143 Dependency root = request.getRoot();
144 List<RemoteRepository> repositories = request.getRepositories();
145 List<Dependency> dependencies = request.getDependencies();
146 List<Dependency> managedDependencies = request.getManagedDependencies();
147
148 Map<String, Object> stats = new LinkedHashMap<>();
149 long time1 = System.nanoTime();
150
151 DefaultDependencyNode node;
152 if (root != null) {
153 List<? extends Version> versions;
154 VersionRangeResult rangeResult;
155 try {
156 VersionRangeRequest rangeRequest = new VersionRangeRequest(
157 root.getArtifact(), request.getRepositories(), request.getRequestContext());
158 rangeRequest.setTrace(trace);
159 rangeResult = versionRangeResolver.resolveVersionRange(session, rangeRequest);
160 versions = filterVersions(root, rangeResult, verFilter, new DefaultVersionFilterContext(session));
161 } catch (VersionRangeResolutionException e) {
162 result.addException(e);
163 throw new DependencyCollectionException(result, e.getMessage());
164 }
165
166 Version version = versions.get(versions.size() - 1);
167 root = root.setArtifact(root.getArtifact().setVersion(version.toString()));
168
169 ArtifactDescriptorResult descriptorResult;
170 try {
171 ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest();
172 descriptorRequest.setArtifact(root.getArtifact());
173 descriptorRequest.setRepositories(request.getRepositories());
174 descriptorRequest.setRequestContext(request.getRequestContext());
175 descriptorRequest.setTrace(trace);
176 if (isLackingDescriptor(root.getArtifact())) {
177 descriptorResult = new ArtifactDescriptorResult(descriptorRequest);
178 } else {
179 descriptorResult = descriptorReader.readArtifactDescriptor(session, descriptorRequest);
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 return result;
267 }
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283 protected RequestTrace collectStepTrace(
284 RequestTrace trace, String context, List<DependencyNode> path, Dependency node) {
285 return RequestTrace.newChild(trace, new CollectStepDataImpl(context, path, node));
286 }
287
288 @SuppressWarnings("checkstyle:parameternumber")
289 protected abstract void doCollectDependencies(
290 RepositorySystemSession session,
291 RequestTrace trace,
292 DataPool pool,
293 DefaultDependencyCollectionContext context,
294 DefaultVersionFilterContext versionContext,
295 CollectRequest request,
296 DependencyNode node,
297 List<RemoteRepository> repositories,
298 List<Dependency> dependencies,
299 List<Dependency> managedDependencies,
300 Results results);
301
302 protected RepositorySystemSession optimizeSession(RepositorySystemSession session) {
303 DefaultRepositorySystemSession optimized = new DefaultRepositorySystemSession(session);
304 optimized.setArtifactTypeRegistry(CachingArtifactTypeRegistry.newInstance(session));
305 return optimized;
306 }
307
308 protected List<Dependency> mergeDeps(List<Dependency> dominant, List<Dependency> recessive) {
309 List<Dependency> result;
310 if (dominant == null || dominant.isEmpty()) {
311 result = recessive;
312 } else if (recessive == null || recessive.isEmpty()) {
313 result = dominant;
314 } else {
315 int initialCapacity = dominant.size() + recessive.size();
316 result = new ArrayList<>(initialCapacity);
317 Collection<String> ids = new HashSet<>(initialCapacity, 1.0f);
318 for (Dependency dependency : dominant) {
319 ids.add(getId(dependency.getArtifact()));
320 result.add(dependency);
321 }
322 for (Dependency dependency : recessive) {
323 if (!ids.contains(getId(dependency.getArtifact()))) {
324 result.add(dependency);
325 }
326 }
327 }
328 return result;
329 }
330
331 protected static String getId(Artifact a) {
332 return a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getClassifier() + ':' + a.getExtension();
333 }
334
335 @SuppressWarnings("checkstyle:parameternumber")
336 protected static DefaultDependencyNode createDependencyNode(
337 List<Artifact> relocations,
338 PremanagedDependency preManaged,
339 VersionRangeResult rangeResult,
340 Version version,
341 Dependency d,
342 Collection<Artifact> aliases,
343 List<RemoteRepository> repos,
344 String requestContext) {
345 DefaultDependencyNode child = new DefaultDependencyNode(d);
346 preManaged.applyTo(child);
347 child.setRelocations(relocations);
348 child.setVersionConstraint(rangeResult.getVersionConstraint());
349 child.setVersion(version);
350 child.setAliases(aliases);
351 child.setRepositories(repos);
352 child.setRequestContext(requestContext);
353 return child;
354 }
355
356 protected static DefaultDependencyNode createDependencyNode(
357 List<Artifact> relocations,
358 PremanagedDependency preManaged,
359 VersionRangeResult rangeResult,
360 Version version,
361 Dependency d,
362 ArtifactDescriptorResult descriptorResult,
363 DependencyNode cycleNode) {
364 DefaultDependencyNode child = createDependencyNode(
365 relocations,
366 preManaged,
367 rangeResult,
368 version,
369 d,
370 descriptorResult.getAliases(),
371 cycleNode.getRepositories(),
372 cycleNode.getRequestContext());
373 child.setChildren(cycleNode.getChildren());
374 return child;
375 }
376
377 protected static ArtifactDescriptorRequest createArtifactDescriptorRequest(
378 String requestContext, RequestTrace requestTrace, List<RemoteRepository> repositories, Dependency d) {
379 ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest();
380 descriptorRequest.setArtifact(d.getArtifact());
381 descriptorRequest.setRepositories(repositories);
382 descriptorRequest.setRequestContext(requestContext);
383 descriptorRequest.setTrace(requestTrace);
384 return descriptorRequest;
385 }
386
387 protected static VersionRangeRequest createVersionRangeRequest(
388 String requestContext,
389 RequestTrace requestTrace,
390 List<RemoteRepository> repositories,
391 Dependency dependency) {
392 VersionRangeRequest rangeRequest = new VersionRangeRequest();
393 rangeRequest.setArtifact(dependency.getArtifact());
394 rangeRequest.setRepositories(repositories);
395 rangeRequest.setRequestContext(requestContext);
396 rangeRequest.setTrace(requestTrace);
397 return rangeRequest;
398 }
399
400 protected VersionRangeResult cachedResolveRangeResult(
401 VersionRangeRequest rangeRequest, DataPool pool, RepositorySystemSession session)
402 throws VersionRangeResolutionException {
403 Object key = pool.toKey(rangeRequest);
404 VersionRangeResult rangeResult = pool.getConstraint(key, rangeRequest);
405 if (rangeResult == null) {
406 rangeResult = versionRangeResolver.resolveVersionRange(session, rangeRequest);
407 pool.putConstraint(key, rangeResult);
408 }
409 return rangeResult;
410 }
411
412 protected static boolean isLackingDescriptor(Artifact artifact) {
413 return artifact.getProperty(ArtifactProperties.LOCAL_PATH, null) != null;
414 }
415
416 protected static List<RemoteRepository> getRemoteRepositories(
417 ArtifactRepository repository, List<RemoteRepository> repositories) {
418 if (repository instanceof RemoteRepository) {
419 return Collections.singletonList((RemoteRepository) repository);
420 }
421 if (repository != null) {
422 return Collections.emptyList();
423 }
424 return repositories;
425 }
426
427 protected static List<? extends Version> filterVersions(
428 Dependency dependency,
429 VersionRangeResult rangeResult,
430 VersionFilter verFilter,
431 DefaultVersionFilterContext verContext)
432 throws VersionRangeResolutionException {
433 if (rangeResult.getVersions().isEmpty()) {
434 throw new VersionRangeResolutionException(
435 rangeResult, "No versions available for " + dependency.getArtifact() + " within specified range");
436 }
437
438 List<? extends Version> versions;
439 if (verFilter != null && rangeResult.getVersionConstraint().getRange() != null) {
440 verContext.set(dependency, rangeResult);
441 try {
442 verFilter.filterVersions(verContext);
443 } catch (RepositoryException e) {
444 throw new VersionRangeResolutionException(
445 rangeResult, "Failed to filter versions for " + dependency.getArtifact(), e);
446 }
447 versions = verContext.get();
448 if (versions.isEmpty()) {
449 throw new VersionRangeResolutionException(
450 rangeResult,
451 "No acceptable versions for " + dependency.getArtifact() + ": " + rangeResult.getVersions());
452 }
453 } else {
454 versions = rangeResult.getVersions();
455 }
456 return versions;
457 }
458
459
460
461
462 protected static class Results {
463
464 private final CollectResult result;
465
466 final int maxExceptions;
467
468 final int maxCycles;
469
470 String errorPath;
471
472 public Results(CollectResult result, RepositorySystemSession session) {
473 this.result = result;
474
475 maxExceptions =
476 ConfigUtils.getInteger(session, CONFIG_PROP_MAX_EXCEPTIONS_DEFAULT, CONFIG_PROP_MAX_EXCEPTIONS);
477
478 maxCycles = ConfigUtils.getInteger(session, CONFIG_PROP_MAX_CYCLES_DEFAULT, CONFIG_PROP_MAX_CYCLES);
479 }
480
481 public String getErrorPath() {
482 return errorPath;
483 }
484
485 public void addException(Dependency dependency, Exception e, List<DependencyNode> nodes) {
486 if (maxExceptions < 0 || result.getExceptions().size() < maxExceptions) {
487 result.addException(e);
488 if (errorPath == null) {
489 StringBuilder buffer = new StringBuilder(256);
490 for (DependencyNode node : nodes) {
491 if (buffer.length() > 0) {
492 buffer.append(" -> ");
493 }
494 Dependency dep = node.getDependency();
495 if (dep != null) {
496 buffer.append(dep.getArtifact());
497 }
498 }
499 if (buffer.length() > 0) {
500 buffer.append(" -> ");
501 }
502 buffer.append(dependency.getArtifact());
503 errorPath = buffer.toString();
504 }
505 }
506 }
507
508 public void addCycle(List<DependencyNode> nodes, int cycleEntry, Dependency dependency) {
509 if (maxCycles < 0 || result.getCycles().size() < maxCycles) {
510 result.addCycle(new DefaultDependencyCycle(nodes, cycleEntry, dependency));
511 }
512 }
513 }
514 }