001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.internal.impl.collect.df; 020 021import javax.inject.Inject; 022import javax.inject.Named; 023import javax.inject.Singleton; 024 025import java.util.Collections; 026import java.util.List; 027import java.util.concurrent.atomic.AtomicReference; 028 029import org.eclipse.aether.RepositorySystemSession; 030import org.eclipse.aether.RequestTrace; 031import org.eclipse.aether.artifact.Artifact; 032import org.eclipse.aether.collection.CollectRequest; 033import org.eclipse.aether.collection.DependencyCollectionException; 034import org.eclipse.aether.collection.DependencyManager; 035import org.eclipse.aether.collection.DependencySelector; 036import org.eclipse.aether.collection.DependencyTraverser; 037import org.eclipse.aether.collection.VersionFilter; 038import org.eclipse.aether.graph.DefaultDependencyNode; 039import org.eclipse.aether.graph.Dependency; 040import org.eclipse.aether.graph.DependencyNode; 041import org.eclipse.aether.impl.ArtifactDescriptorReader; 042import org.eclipse.aether.impl.RemoteRepositoryManager; 043import org.eclipse.aether.impl.VersionRangeResolver; 044import org.eclipse.aether.internal.impl.collect.DataPool; 045import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollectionContext; 046import org.eclipse.aether.internal.impl.collect.DefaultDependencyCycle; 047import org.eclipse.aether.internal.impl.collect.DefaultVersionFilterContext; 048import org.eclipse.aether.internal.impl.collect.DependencyCollectorDelegate; 049import org.eclipse.aether.internal.impl.collect.PremanagedDependency; 050import org.eclipse.aether.repository.RemoteRepository; 051import org.eclipse.aether.resolution.ArtifactDescriptorException; 052import org.eclipse.aether.resolution.ArtifactDescriptorRequest; 053import org.eclipse.aether.resolution.ArtifactDescriptorResult; 054import org.eclipse.aether.resolution.VersionRangeRequest; 055import org.eclipse.aether.resolution.VersionRangeResolutionException; 056import org.eclipse.aether.resolution.VersionRangeResult; 057import org.eclipse.aether.util.ConfigUtils; 058import org.eclipse.aether.util.graph.manager.DependencyManagerUtils; 059import org.eclipse.aether.version.Version; 060 061/** 062 * Depth-first {@link org.eclipse.aether.impl.DependencyCollector} (the "original" default). Originally 063 * this class was located a package higher (as "default" implementation). 064 * 065 * @since 1.8.0 066 */ 067@Singleton 068@Named(DfDependencyCollector.NAME) 069public class DfDependencyCollector extends DependencyCollectorDelegate { 070 public static final String NAME = "df"; 071 072 @Inject 073 public DfDependencyCollector( 074 RemoteRepositoryManager remoteRepositoryManager, 075 ArtifactDescriptorReader artifactDescriptorReader, 076 VersionRangeResolver versionRangeResolver) { 077 super(remoteRepositoryManager, artifactDescriptorReader, versionRangeResolver); 078 } 079 080 @SuppressWarnings("checkstyle:parameternumber") 081 @Override 082 protected void doCollectDependencies( 083 RepositorySystemSession session, 084 RequestTrace trace, 085 DataPool pool, 086 DefaultDependencyCollectionContext context, 087 DefaultVersionFilterContext versionContext, 088 CollectRequest request, 089 DependencyNode node, 090 List<RemoteRepository> repositories, 091 List<Dependency> dependencies, 092 List<Dependency> managedDependencies, 093 Results results) 094 throws DependencyCollectionException { 095 NodeStack nodes = new NodeStack(); 096 nodes.push(node); 097 098 Args args = new Args(session, pool, nodes, context, versionContext, request); 099 100 process( 101 args, 102 trace, 103 results, 104 dependencies, 105 repositories, 106 session.getDependencySelector() != null 107 ? session.getDependencySelector().deriveChildSelector(context) 108 : null, 109 session.getDependencyManager() != null 110 ? session.getDependencyManager().deriveChildManager(context) 111 : null, 112 session.getDependencyTraverser() != null 113 ? session.getDependencyTraverser().deriveChildTraverser(context) 114 : null, 115 session.getVersionFilter() != null ? session.getVersionFilter().deriveChildFilter(context) : null); 116 117 if (args.interruptedException.get() != null) { 118 throw new DependencyCollectionException( 119 results.getResult(), "Collection interrupted", args.interruptedException.get()); 120 } 121 } 122 123 @SuppressWarnings("checkstyle:parameternumber") 124 private void process( 125 final Args args, 126 RequestTrace trace, 127 Results results, 128 List<Dependency> dependencies, 129 List<RemoteRepository> repositories, 130 DependencySelector depSelector, 131 DependencyManager depManager, 132 DependencyTraverser depTraverser, 133 VersionFilter verFilter) { 134 if (Thread.interrupted()) { 135 args.interruptedException.set(new InterruptedException()); 136 } 137 if (args.interruptedException.get() != null) { 138 return; 139 } 140 for (Dependency dependency : dependencies) { 141 processDependency( 142 args, trace, results, repositories, depSelector, depManager, depTraverser, verFilter, dependency); 143 } 144 } 145 146 @SuppressWarnings("checkstyle:parameternumber") 147 private void processDependency( 148 Args args, 149 RequestTrace trace, 150 Results results, 151 List<RemoteRepository> repositories, 152 DependencySelector depSelector, 153 DependencyManager depManager, 154 DependencyTraverser depTraverser, 155 VersionFilter verFilter, 156 Dependency dependency) { 157 158 List<Artifact> relocations = Collections.emptyList(); 159 processDependency( 160 args, 161 trace, 162 results, 163 repositories, 164 depSelector, 165 depManager, 166 depTraverser, 167 verFilter, 168 dependency, 169 relocations, 170 false); 171 } 172 173 @SuppressWarnings("checkstyle:parameternumber") 174 private void processDependency( 175 Args args, 176 RequestTrace parent, 177 Results results, 178 List<RemoteRepository> repositories, 179 DependencySelector depSelector, 180 DependencyManager depManager, 181 DependencyTraverser depTraverser, 182 VersionFilter verFilter, 183 Dependency dependency, 184 List<Artifact> relocations, 185 boolean disableVersionManagement) { 186 if (depSelector != null && !depSelector.selectDependency(dependency)) { 187 return; 188 } 189 190 RequestTrace trace = collectStepTrace(parent, args.request.getRequestContext(), args.nodes.nodes, dependency); 191 PremanagedDependency preManaged = 192 PremanagedDependency.create(depManager, dependency, disableVersionManagement, args.premanagedState); 193 dependency = preManaged.getManagedDependency(); 194 195 boolean noDescriptor = isLackingDescriptor(dependency.getArtifact()); 196 197 boolean traverse = !noDescriptor && (depTraverser == null || depTraverser.traverseDependency(dependency)); 198 199 List<? extends Version> versions; 200 VersionRangeResult rangeResult; 201 try { 202 VersionRangeRequest rangeRequest = 203 createVersionRangeRequest(args.request.getRequestContext(), trace, repositories, dependency); 204 205 rangeResult = cachedResolveRangeResult(rangeRequest, args.pool, args.session); 206 207 versions = filterVersions(dependency, rangeResult, verFilter, args.versionContext); 208 } catch (VersionRangeResolutionException e) { 209 results.addException(dependency, e, args.nodes.nodes); 210 return; 211 } 212 213 for (Version version : versions) { 214 Artifact originalArtifact = dependency.getArtifact().setVersion(version.toString()); 215 Dependency d = dependency.setArtifact(originalArtifact); 216 217 ArtifactDescriptorRequest descriptorRequest = 218 createArtifactDescriptorRequest(args.request.getRequestContext(), trace, repositories, d); 219 220 final ArtifactDescriptorResult descriptorResult = 221 getArtifactDescriptorResult(args, results, noDescriptor, d, descriptorRequest); 222 if (descriptorResult != null) { 223 d = d.setArtifact(descriptorResult.getArtifact()); 224 225 DependencyNode node = args.nodes.top(); 226 227 int cycleEntry = DefaultDependencyCycle.find(args.nodes.nodes, d.getArtifact()); 228 if (cycleEntry >= 0) { 229 results.addCycle(args.nodes.nodes, cycleEntry, d); 230 DependencyNode cycleNode = args.nodes.get(cycleEntry); 231 if (cycleNode.getDependency() != null) { 232 DefaultDependencyNode child = createDependencyNode( 233 relocations, preManaged, rangeResult, version, d, descriptorResult, cycleNode); 234 node.getChildren().add(child); 235 continue; 236 } 237 } 238 239 if (!descriptorResult.getRelocations().isEmpty()) { 240 boolean disableVersionManagementSubsequently = 241 originalArtifact.getGroupId().equals(d.getArtifact().getGroupId()) 242 && originalArtifact 243 .getArtifactId() 244 .equals(d.getArtifact().getArtifactId()); 245 246 processDependency( 247 args, 248 parent, 249 results, 250 repositories, 251 depSelector, 252 depManager, 253 depTraverser, 254 verFilter, 255 d, 256 descriptorResult.getRelocations(), 257 disableVersionManagementSubsequently); 258 return; 259 } else { 260 d = args.pool.intern(d.setArtifact(args.pool.intern(d.getArtifact()))); 261 262 List<RemoteRepository> repos = 263 getRemoteRepositories(rangeResult.getRepository(version), repositories); 264 265 DefaultDependencyNode child = createDependencyNode( 266 relocations, 267 preManaged, 268 rangeResult, 269 version, 270 d, 271 descriptorResult.getAliases(), 272 repos, 273 args.request.getRequestContext()); 274 275 node.getChildren().add(child); 276 277 boolean recurse = 278 traverse && !descriptorResult.getDependencies().isEmpty(); 279 if (recurse) { 280 doRecurse( 281 args, 282 parent, 283 results, 284 repositories, 285 depSelector, 286 depManager, 287 depTraverser, 288 verFilter, 289 d, 290 descriptorResult, 291 child); 292 } 293 } 294 } else { 295 DependencyNode node = args.nodes.top(); 296 List<RemoteRepository> repos = getRemoteRepositories(rangeResult.getRepository(version), repositories); 297 DefaultDependencyNode child = createDependencyNode( 298 relocations, 299 preManaged, 300 rangeResult, 301 version, 302 d, 303 null, 304 repos, 305 args.request.getRequestContext()); 306 node.getChildren().add(child); 307 } 308 } 309 } 310 311 @SuppressWarnings("checkstyle:parameternumber") 312 private void doRecurse( 313 Args args, 314 RequestTrace trace, 315 Results results, 316 List<RemoteRepository> repositories, 317 DependencySelector depSelector, 318 DependencyManager depManager, 319 DependencyTraverser depTraverser, 320 VersionFilter verFilter, 321 Dependency d, 322 ArtifactDescriptorResult descriptorResult, 323 DefaultDependencyNode child) { 324 DefaultDependencyCollectionContext context = args.collectionContext; 325 context.set(d, descriptorResult.getManagedDependencies()); 326 327 DependencySelector childSelector = depSelector != null ? depSelector.deriveChildSelector(context) : null; 328 DependencyManager childManager = depManager != null ? depManager.deriveChildManager(context) : null; 329 DependencyTraverser childTraverser = depTraverser != null ? depTraverser.deriveChildTraverser(context) : null; 330 VersionFilter childFilter = verFilter != null ? verFilter.deriveChildFilter(context) : null; 331 332 final List<RemoteRepository> childRepos = args.ignoreRepos 333 ? repositories 334 : remoteRepositoryManager.aggregateRepositories( 335 args.session, repositories, descriptorResult.getRepositories(), true); 336 337 Object key = 338 args.pool.toKey(d.getArtifact(), childRepos, childSelector, childManager, childTraverser, childFilter); 339 340 List<DependencyNode> children = args.pool.getChildren(key); 341 if (children == null) { 342 args.pool.putChildren(key, child.getChildren()); 343 344 args.nodes.push(child); 345 346 process( 347 args, 348 trace, 349 results, 350 descriptorResult.getDependencies(), 351 childRepos, 352 childSelector, 353 childManager, 354 childTraverser, 355 childFilter); 356 357 args.nodes.pop(); 358 } else { 359 child.setChildren(children); 360 } 361 } 362 363 private ArtifactDescriptorResult getArtifactDescriptorResult( 364 Args args, 365 Results results, 366 boolean noDescriptor, 367 Dependency d, 368 ArtifactDescriptorRequest descriptorRequest) { 369 return noDescriptor 370 ? new ArtifactDescriptorResult(descriptorRequest) 371 : resolveCachedArtifactDescriptor(args.pool, descriptorRequest, args.session, d, results, args); 372 } 373 374 private ArtifactDescriptorResult resolveCachedArtifactDescriptor( 375 DataPool pool, 376 ArtifactDescriptorRequest descriptorRequest, 377 RepositorySystemSession session, 378 Dependency d, 379 Results results, 380 Args args) { 381 Object key = pool.toKey(descriptorRequest); 382 ArtifactDescriptorResult descriptorResult = pool.getDescriptor(key, descriptorRequest); 383 if (descriptorResult == null) { 384 try { 385 descriptorResult = descriptorReader.readArtifactDescriptor(session, descriptorRequest); 386 pool.putDescriptor(key, descriptorResult); 387 } catch (ArtifactDescriptorException e) { 388 results.addException(d, e, args.nodes.nodes); 389 pool.putDescriptor(key, e); 390 return null; 391 } 392 393 } else if (descriptorResult == DataPool.NO_DESCRIPTOR) { 394 return null; 395 } 396 397 return descriptorResult; 398 } 399 400 static class Args { 401 402 final RepositorySystemSession session; 403 404 final boolean ignoreRepos; 405 406 final boolean premanagedState; 407 408 final DataPool pool; 409 410 final NodeStack nodes; 411 412 final DefaultDependencyCollectionContext collectionContext; 413 414 final DefaultVersionFilterContext versionContext; 415 416 final CollectRequest request; 417 418 final AtomicReference<InterruptedException> interruptedException; 419 420 Args( 421 RepositorySystemSession session, 422 DataPool pool, 423 NodeStack nodes, 424 DefaultDependencyCollectionContext collectionContext, 425 DefaultVersionFilterContext versionContext, 426 CollectRequest request) { 427 this.session = session; 428 this.request = request; 429 this.ignoreRepos = session.isIgnoreArtifactDescriptorRepositories(); 430 this.premanagedState = ConfigUtils.getBoolean(session, false, DependencyManagerUtils.CONFIG_PROP_VERBOSE); 431 this.pool = pool; 432 this.nodes = nodes; 433 this.collectionContext = collectionContext; 434 this.versionContext = versionContext; 435 this.interruptedException = new AtomicReference<>(null); 436 } 437 } 438}