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