View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.internal.impl.collect.bf;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.io.Closeable;
26  import java.util.ArrayDeque;
27  import java.util.ArrayList;
28  import java.util.Collections;
29  import java.util.LinkedHashMap;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Optional;
33  import java.util.Queue;
34  import java.util.Set;
35  import java.util.concurrent.Callable;
36  import java.util.concurrent.ConcurrentHashMap;
37  import java.util.concurrent.ExecutionException;
38  import java.util.concurrent.ExecutorService;
39  import java.util.concurrent.Future;
40  import java.util.concurrent.TimeUnit;
41  import java.util.concurrent.TimeoutException;
42  import java.util.concurrent.atomic.AtomicReference;
43  import java.util.stream.Collectors;
44  import java.util.stream.Stream;
45  
46  import org.eclipse.aether.RepositorySystemSession;
47  import org.eclipse.aether.RequestTrace;
48  import org.eclipse.aether.artifact.Artifact;
49  import org.eclipse.aether.artifact.ArtifactType;
50  import org.eclipse.aether.artifact.DefaultArtifact;
51  import org.eclipse.aether.collection.CollectRequest;
52  import org.eclipse.aether.collection.DependencyCollectionException;
53  import org.eclipse.aether.collection.DependencyManager;
54  import org.eclipse.aether.collection.DependencySelector;
55  import org.eclipse.aether.collection.DependencyTraverser;
56  import org.eclipse.aether.collection.VersionFilter;
57  import org.eclipse.aether.graph.DefaultDependencyNode;
58  import org.eclipse.aether.graph.Dependency;
59  import org.eclipse.aether.graph.DependencyNode;
60  import org.eclipse.aether.impl.ArtifactDescriptorReader;
61  import org.eclipse.aether.impl.RemoteRepositoryManager;
62  import org.eclipse.aether.impl.VersionRangeResolver;
63  import org.eclipse.aether.internal.impl.collect.DataPool;
64  import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollectionContext;
65  import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector;
66  import org.eclipse.aether.internal.impl.collect.DefaultVersionFilterContext;
67  import org.eclipse.aether.internal.impl.collect.DependencyCollectorDelegate;
68  import org.eclipse.aether.internal.impl.collect.PremanagedDependency;
69  import org.eclipse.aether.repository.RemoteRepository;
70  import org.eclipse.aether.resolution.ArtifactDescriptorException;
71  import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
72  import org.eclipse.aether.resolution.ArtifactDescriptorResult;
73  import org.eclipse.aether.resolution.VersionRangeRequest;
74  import org.eclipse.aether.resolution.VersionRangeResult;
75  import org.eclipse.aether.util.ConfigUtils;
76  import org.eclipse.aether.util.artifact.ArtifactIdUtils;
77  import org.eclipse.aether.util.concurrency.ExecutorUtils;
78  import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
79  import org.eclipse.aether.version.Version;
80  
81  import static org.eclipse.aether.internal.impl.collect.DefaultDependencyCycle.find;
82  
83  /**
84   * Breadth-first {@link org.eclipse.aether.impl.DependencyCollector}
85   *
86   * @since 1.8.0
87   */
88  @Singleton
89  @Named(BfDependencyCollector.NAME)
90  public class BfDependencyCollector extends DependencyCollectorDelegate {
91      public static final String NAME = "bf";
92  
93      private static final String CONFIG_PROPS_PREFIX = DefaultDependencyCollector.CONFIG_PROPS_PREFIX + NAME + ".";
94  
95      /**
96       * The key in the repository session's {@link RepositorySystemSession#getConfigProperties()
97       * configuration properties} used to store a {@link Boolean} flag controlling the resolver's skip mode.
98       *
99       * @since 1.8.0
100      * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
101      * @configurationType {@link java.lang.Boolean}
102      * @configurationDefaultValue {@link #DEFAULT_SKIPPER}
103      */
104     public static final String CONFIG_PROP_SKIPPER = CONFIG_PROPS_PREFIX + "skipper";
105 
106     /**
107      * The default value for {@link #CONFIG_PROP_SKIPPER}, {@code true}.
108      *
109      * @since 1.8.0
110      */
111     public static final boolean DEFAULT_SKIPPER = true;
112 
113     /**
114      * The count of threads to be used when collecting POMs in parallel.
115      *
116      * @since 1.9.0
117      * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
118      * @configurationType {@link java.lang.Integer}
119      * @configurationDefaultValue {@link #DEFAULT_THREADS}
120      */
121     public static final String CONFIG_PROP_THREADS = CONFIG_PROPS_PREFIX + "threads";
122 
123     /**
124      * The default value for {@link #CONFIG_PROP_THREADS}, default value 5.
125      *
126      * @since 1.9.0
127      */
128     public static final int DEFAULT_THREADS = 5;
129 
130     @Inject
131     public BfDependencyCollector(
132             RemoteRepositoryManager remoteRepositoryManager,
133             ArtifactDescriptorReader artifactDescriptorReader,
134             VersionRangeResolver versionRangeResolver) {
135         super(remoteRepositoryManager, artifactDescriptorReader, versionRangeResolver);
136     }
137 
138     @SuppressWarnings("checkstyle:parameternumber")
139     @Override
140     protected void doCollectDependencies(
141             RepositorySystemSession session,
142             RequestTrace trace,
143             DataPool pool,
144             DefaultDependencyCollectionContext context,
145             DefaultVersionFilterContext versionContext,
146             CollectRequest request,
147             DependencyNode node,
148             List<RemoteRepository> repositories,
149             List<Dependency> dependencies,
150             List<Dependency> managedDependencies,
151             Results results)
152             throws DependencyCollectionException {
153         boolean useSkip = ConfigUtils.getBoolean(session, DEFAULT_SKIPPER, CONFIG_PROP_SKIPPER);
154         int nThreads = ExecutorUtils.threadCount(session, DEFAULT_THREADS, CONFIG_PROP_THREADS);
155         logger.debug("Using thread pool with {} threads to resolve descriptors.", nThreads);
156 
157         if (useSkip) {
158             logger.debug("Collector skip mode enabled");
159         }
160 
161         try (DependencyResolutionSkipper skipper = useSkip
162                         ? DependencyResolutionSkipper.defaultSkipper()
163                         : DependencyResolutionSkipper.neverSkipper();
164                 ParallelDescriptorResolver parallelDescriptorResolver = new ParallelDescriptorResolver(nThreads)) {
165             Args args = new Args(session, pool, context, versionContext, request, skipper, parallelDescriptorResolver);
166 
167             DependencySelector rootDepSelector = session.getDependencySelector() != null
168                     ? session.getDependencySelector().deriveChildSelector(context)
169                     : null;
170             DependencyManager rootDepManager = session.getDependencyManager() != null
171                     ? session.getDependencyManager().deriveChildManager(context)
172                     : null;
173             DependencyTraverser rootDepTraverser = session.getDependencyTraverser() != null
174                     ? session.getDependencyTraverser().deriveChildTraverser(context)
175                     : null;
176             VersionFilter rootVerFilter = session.getVersionFilter() != null
177                     ? session.getVersionFilter().deriveChildFilter(context)
178                     : null;
179 
180             List<DependencyNode> parents = Collections.singletonList(node);
181             for (Dependency dependency : dependencies) {
182                 RequestTrace childTrace =
183                         collectStepTrace(trace, args.request.getRequestContext(), parents, dependency);
184                 DependencyProcessingContext processingContext = new DependencyProcessingContext(
185                         rootDepSelector,
186                         rootDepManager,
187                         rootDepTraverser,
188                         rootVerFilter,
189                         childTrace,
190                         repositories,
191                         managedDependencies,
192                         parents,
193                         dependency,
194                         PremanagedDependency.create(rootDepManager, dependency, false, args.premanagedState));
195                 if (!filter(processingContext)) {
196                     processingContext.withDependency(processingContext.premanagedDependency.getManagedDependency());
197                     resolveArtifactDescriptorAsync(args, processingContext, results);
198                     args.dependencyProcessingQueue.add(processingContext);
199                 }
200             }
201 
202             while (!args.dependencyProcessingQueue.isEmpty()) {
203                 processDependency(
204                         args, results, args.dependencyProcessingQueue.remove(), Collections.emptyList(), false);
205             }
206 
207             if (args.interruptedException.get() != null) {
208                 throw new DependencyCollectionException(
209                         results.getResult(), "Collection interrupted", args.interruptedException.get());
210             }
211         }
212     }
213 
214     @SuppressWarnings("checkstyle:parameternumber")
215     private void processDependency(
216             Args args,
217             Results results,
218             DependencyProcessingContext context,
219             List<Artifact> relocations,
220             boolean disableVersionManagement) {
221         if (Thread.interrupted()) {
222             args.interruptedException.set(new InterruptedException());
223         }
224         if (args.interruptedException.get() != null) {
225             return;
226         }
227         Dependency dependency = context.dependency;
228         PremanagedDependency preManaged = context.premanagedDependency;
229 
230         boolean noDescriptor = isLackingDescriptor(args.session, dependency.getArtifact());
231         boolean traverse =
232                 !noDescriptor && (context.depTraverser == null || context.depTraverser.traverseDependency(dependency));
233 
234         Future<DescriptorResolutionResult> resolutionResultFuture = args.resolver.find(dependency.getArtifact());
235         DescriptorResolutionResult resolutionResult;
236         VersionRangeResult rangeResult;
237         try {
238             resolutionResult = resolutionResultFuture.get();
239             rangeResult = resolutionResult.rangeResult;
240         } catch (Exception e) {
241             results.addException(dependency, e, context.parents);
242             return;
243         }
244 
245         Set<Version> versions = resolutionResult.descriptors.keySet();
246         for (Version version : versions) {
247             Artifact originalArtifact = dependency.getArtifact().setVersion(version.toString());
248             Dependency d = dependency.setArtifact(originalArtifact);
249 
250             final ArtifactDescriptorResult descriptorResult = resolutionResult.descriptors.get(version);
251             if (descriptorResult != null) {
252                 d = d.setArtifact(descriptorResult.getArtifact());
253 
254                 int cycleEntry = find(context.parents, d.getArtifact());
255                 if (cycleEntry >= 0) {
256                     results.addCycle(context.parents, cycleEntry, d);
257                     DependencyNode cycleNode = context.parents.get(cycleEntry);
258                     if (cycleNode.getDependency() != null) {
259                         DefaultDependencyNode child = createDependencyNode(
260                                 relocations, preManaged, rangeResult, version, d, descriptorResult, cycleNode);
261                         context.getParent().getChildren().add(child);
262                         continue;
263                     }
264                 }
265 
266                 if (!descriptorResult.getRelocations().isEmpty()) {
267                     boolean disableVersionManagementSubsequently =
268                             originalArtifact.getGroupId().equals(d.getArtifact().getGroupId())
269                                     && originalArtifact
270                                             .getArtifactId()
271                                             .equals(d.getArtifact().getArtifactId());
272 
273                     PremanagedDependency premanagedDependency = PremanagedDependency.create(
274                             context.depManager, d, disableVersionManagementSubsequently, args.premanagedState);
275                     DependencyProcessingContext relocatedContext = new DependencyProcessingContext(
276                             context.depSelector,
277                             context.depManager,
278                             context.depTraverser,
279                             context.verFilter,
280                             context.trace,
281                             context.repositories,
282                             descriptorResult.getManagedDependencies(),
283                             context.parents,
284                             d,
285                             premanagedDependency);
286 
287                     if (!filter(relocatedContext)) {
288                         relocatedContext.withDependency(premanagedDependency.getManagedDependency());
289                         resolveArtifactDescriptorAsync(args, relocatedContext, results);
290                         processDependency(
291                                 args,
292                                 results,
293                                 relocatedContext,
294                                 descriptorResult.getRelocations(),
295                                 disableVersionManagementSubsequently);
296                     }
297 
298                     return;
299                 } else {
300                     d = args.pool.intern(d.setArtifact(args.pool.intern(d.getArtifact())));
301 
302                     List<RemoteRepository> repos =
303                             getRemoteRepositories(rangeResult.getRepository(version), context.repositories);
304 
305                     DefaultDependencyNode child = createDependencyNode(
306                             relocations,
307                             preManaged,
308                             rangeResult,
309                             version,
310                             d,
311                             descriptorResult.getAliases(),
312                             repos,
313                             args.request.getRequestContext());
314 
315                     context.getParent().getChildren().add(child);
316 
317                     boolean recurse =
318                             traverse && !descriptorResult.getDependencies().isEmpty();
319                     DependencyProcessingContext parentContext = context.withDependency(d);
320                     if (recurse) {
321                         doRecurse(args, parentContext, descriptorResult, child, results, disableVersionManagement);
322                     } else if (!args.skipper.skipResolution(child, parentContext.parents)) {
323                         List<DependencyNode> parents = new ArrayList<>(parentContext.parents.size() + 1);
324                         parents.addAll(parentContext.parents);
325                         parents.add(child);
326                         args.skipper.cache(child, parents);
327                     }
328                 }
329             } else {
330                 List<RemoteRepository> repos =
331                         getRemoteRepositories(rangeResult.getRepository(version), context.repositories);
332                 DefaultDependencyNode child = createDependencyNode(
333                         relocations,
334                         preManaged,
335                         rangeResult,
336                         version,
337                         d,
338                         null,
339                         repos,
340                         args.request.getRequestContext());
341                 context.getParent().getChildren().add(child);
342             }
343         }
344     }
345 
346     @SuppressWarnings("checkstyle:parameternumber")
347     private void doRecurse(
348             Args args,
349             DependencyProcessingContext parentContext,
350             ArtifactDescriptorResult descriptorResult,
351             DefaultDependencyNode child,
352             Results results,
353             boolean disableVersionManagement) {
354         DefaultDependencyCollectionContext context = args.collectionContext;
355         context.set(parentContext.dependency, descriptorResult.getManagedDependencies());
356 
357         DependencySelector childSelector =
358                 parentContext.depSelector != null ? parentContext.depSelector.deriveChildSelector(context) : null;
359         DependencyManager childManager =
360                 parentContext.depManager != null ? parentContext.depManager.deriveChildManager(context) : null;
361         DependencyTraverser childTraverser =
362                 parentContext.depTraverser != null ? parentContext.depTraverser.deriveChildTraverser(context) : null;
363         VersionFilter childFilter =
364                 parentContext.verFilter != null ? parentContext.verFilter.deriveChildFilter(context) : null;
365 
366         final List<RemoteRepository> childRepos = args.ignoreRepos
367                 ? parentContext.repositories
368                 : remoteRepositoryManager.aggregateRepositories(
369                         args.session, parentContext.repositories, descriptorResult.getRepositories(), true);
370 
371         Object key = args.pool.toKey(
372                 parentContext.dependency.getArtifact(),
373                 childRepos,
374                 childSelector,
375                 childManager,
376                 childTraverser,
377                 childFilter);
378 
379         List<DependencyNode> children = args.pool.getChildren(key);
380         if (children == null) {
381             boolean skipResolution = args.skipper.skipResolution(child, parentContext.parents);
382             if (!skipResolution) {
383                 List<DependencyNode> parents = new ArrayList<>(parentContext.parents.size() + 1);
384                 parents.addAll(parentContext.parents);
385                 parents.add(child);
386                 for (Dependency dependency : descriptorResult.getDependencies()) {
387                     RequestTrace childTrace = collectStepTrace(
388                             parentContext.trace, args.request.getRequestContext(), parents, dependency);
389                     PremanagedDependency premanagedDependency = PremanagedDependency.create(
390                             childManager, dependency, disableVersionManagement, args.premanagedState);
391                     DependencyProcessingContext processingContext = new DependencyProcessingContext(
392                             childSelector,
393                             childManager,
394                             childTraverser,
395                             childFilter,
396                             childTrace,
397                             childRepos,
398                             descriptorResult.getManagedDependencies(),
399                             parents,
400                             dependency,
401                             premanagedDependency);
402                     if (!filter(processingContext)) {
403                         // resolve descriptors ahead for managed dependency
404                         processingContext.withDependency(processingContext.premanagedDependency.getManagedDependency());
405                         resolveArtifactDescriptorAsync(args, processingContext, results);
406                         args.dependencyProcessingQueue.add(processingContext);
407                     }
408                 }
409                 args.pool.putChildren(key, child.getChildren());
410                 args.skipper.cache(child, parents);
411             }
412         } else {
413             child.setChildren(children);
414         }
415     }
416 
417     private boolean filter(DependencyProcessingContext context) {
418         return context.depSelector != null && !context.depSelector.selectDependency(context.dependency);
419     }
420 
421     private void resolveArtifactDescriptorAsync(Args args, DependencyProcessingContext context, Results results) {
422         Dependency dependency = context.dependency;
423         args.resolver.resolveDescriptors(dependency.getArtifact(), () -> {
424             VersionRangeRequest rangeRequest = createVersionRangeRequest(
425                     args.request.getRequestContext(), context.trace, context.repositories, dependency);
426             VersionRangeResult rangeResult = cachedResolveRangeResult(rangeRequest, args.pool, args.session);
427             List<? extends Version> versions =
428                     filterVersions(dependency, rangeResult, context.verFilter, args.versionContext);
429 
430             // resolve newer version first to maximize benefits of skipper
431             Collections.reverse(versions);
432 
433             Map<Version, ArtifactDescriptorResult> descriptors = new ConcurrentHashMap<>(versions.size());
434             Stream<? extends Version> stream = versions.size() > 1 ? versions.parallelStream() : versions.stream();
435             stream.forEach(version -> Optional.ofNullable(
436                             resolveDescriptorForVersion(args, context, results, dependency, version))
437                     .ifPresent(r -> descriptors.put(version, r)));
438 
439             DescriptorResolutionResult resolutionResult =
440                     new DescriptorResolutionResult(dependency.getArtifact(), rangeResult);
441             // keep original sequence
442             versions.forEach(version -> resolutionResult.descriptors.put(version, descriptors.get(version)));
443             // populate for versions in version range
444             resolutionResult.flatten().forEach(dr -> args.resolver.cacheVersionRangeDescriptor(dr.artifact, dr));
445 
446             return resolutionResult;
447         });
448     }
449 
450     private ArtifactDescriptorResult resolveDescriptorForVersion(
451             Args args, DependencyProcessingContext context, Results results, Dependency dependency, Version version) {
452         Artifact original = dependency.getArtifact();
453         Artifact newArtifact = new DefaultArtifact(
454                 original.getGroupId(),
455                 original.getArtifactId(),
456                 original.getClassifier(),
457                 original.getExtension(),
458                 version.toString(),
459                 original.getProperties(),
460                 (ArtifactType) null);
461         Dependency newDependency =
462                 new Dependency(newArtifact, dependency.getScope(), dependency.isOptional(), dependency.getExclusions());
463         DependencyProcessingContext newContext = context.copy();
464 
465         ArtifactDescriptorRequest descriptorRequest = createArtifactDescriptorRequest(
466                 args.request.getRequestContext(), context.trace, newContext.repositories, newDependency);
467         return isLackingDescriptor(args.session, newArtifact)
468                 ? new ArtifactDescriptorResult(descriptorRequest)
469                 : resolveCachedArtifactDescriptor(
470                         args.pool, descriptorRequest, args.session, newContext.withDependency(newDependency), results);
471     }
472 
473     private ArtifactDescriptorResult resolveCachedArtifactDescriptor(
474             DataPool pool,
475             ArtifactDescriptorRequest descriptorRequest,
476             RepositorySystemSession session,
477             DependencyProcessingContext context,
478             Results results) {
479         Object key = pool.toKey(descriptorRequest);
480         ArtifactDescriptorResult descriptorResult = pool.getDescriptor(key, descriptorRequest);
481         if (descriptorResult == null) {
482             try {
483                 descriptorResult = descriptorReader.readArtifactDescriptor(session, descriptorRequest);
484                 pool.putDescriptor(key, descriptorResult);
485             } catch (ArtifactDescriptorException e) {
486                 results.addException(context.dependency, e, context.parents);
487                 pool.putDescriptor(key, e);
488                 return null;
489             }
490 
491         } else if (descriptorResult == DataPool.NO_DESCRIPTOR) {
492             return null;
493         }
494 
495         return descriptorResult;
496     }
497 
498     static class ParallelDescriptorResolver implements Closeable {
499         private final ExecutorService executorService;
500 
501         /**
502          * Artifact ID -> Future of DescriptorResolutionResult
503          */
504         private final Map<String, Future<DescriptorResolutionResult>> results = new ConcurrentHashMap<>(256);
505 
506         ParallelDescriptorResolver(int threads) {
507             this.executorService = ExecutorUtils.threadPool(threads, getClass().getSimpleName() + "-");
508         }
509 
510         void resolveDescriptors(Artifact artifact, Callable<DescriptorResolutionResult> callable) {
511             results.computeIfAbsent(ArtifactIdUtils.toId(artifact), key -> this.executorService.submit(callable));
512         }
513 
514         void cacheVersionRangeDescriptor(Artifact artifact, DescriptorResolutionResult resolutionResult) {
515             results.computeIfAbsent(ArtifactIdUtils.toId(artifact), key -> new DoneFuture<>(resolutionResult));
516         }
517 
518         Future<DescriptorResolutionResult> find(Artifact artifact) {
519             return results.get(ArtifactIdUtils.toId(artifact));
520         }
521 
522         @Override
523         public void close() {
524             executorService.shutdown();
525         }
526     }
527 
528     static class DoneFuture<V> implements Future<V> {
529         private final V v;
530 
531         DoneFuture(V v) {
532             this.v = v;
533         }
534 
535         @Override
536         public boolean cancel(boolean mayInterruptIfRunning) {
537             return false;
538         }
539 
540         @Override
541         public boolean isCancelled() {
542             return false;
543         }
544 
545         @Override
546         public boolean isDone() {
547             return true;
548         }
549 
550         @Override
551         public V get() throws InterruptedException, ExecutionException {
552             return v;
553         }
554 
555         @Override
556         public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
557             return v;
558         }
559     }
560 
561     static class DescriptorResolutionResult {
562         Artifact artifact;
563 
564         VersionRangeResult rangeResult;
565 
566         Map<Version, ArtifactDescriptorResult> descriptors;
567 
568         DescriptorResolutionResult(Artifact artifact, VersionRangeResult rangeResult) {
569             this.artifact = artifact;
570             this.rangeResult = rangeResult;
571             this.descriptors = new LinkedHashMap<>(rangeResult.getVersions().size());
572         }
573 
574         DescriptorResolutionResult(
575                 VersionRangeResult rangeResult, Version version, ArtifactDescriptorResult descriptor) {
576             // NOTE: In case of A1 -> A2 relocation this happens:
577             // ArtifactDescriptorResult read by ArtifactDescriptorResultReader for A1
578             // will return instance that will have artifact = A2 (as RelocatedArtifact).
579             // So to properly "key" this instance, we need to use "originally requested" A1 instead!
580             // In short:
581             // ArtifactDescriptorRequest.artifact != ArtifactDescriptorResult.artifact WHEN relocation in play
582             // otherwise (no relocation), they are EQUAL.
583             this(descriptor.getRequest().getArtifact(), rangeResult);
584             this.descriptors.put(version, descriptor);
585         }
586 
587         List<DescriptorResolutionResult> flatten() {
588             if (descriptors.size() > 1) {
589                 return descriptors.entrySet().stream()
590                         .map(e -> new DescriptorResolutionResult(rangeResult, e.getKey(), e.getValue()))
591                         .collect(Collectors.toList());
592             } else {
593                 return Collections.emptyList();
594             }
595         }
596     }
597 
598     static class Args {
599 
600         final RepositorySystemSession session;
601 
602         final boolean ignoreRepos;
603 
604         final boolean premanagedState;
605 
606         final DataPool pool;
607 
608         final Queue<DependencyProcessingContext> dependencyProcessingQueue = new ArrayDeque<>(128);
609 
610         final DefaultDependencyCollectionContext collectionContext;
611 
612         final DefaultVersionFilterContext versionContext;
613 
614         final CollectRequest request;
615 
616         final DependencyResolutionSkipper skipper;
617 
618         final ParallelDescriptorResolver resolver;
619 
620         final AtomicReference<InterruptedException> interruptedException;
621 
622         Args(
623                 RepositorySystemSession session,
624                 DataPool pool,
625                 DefaultDependencyCollectionContext collectionContext,
626                 DefaultVersionFilterContext versionContext,
627                 CollectRequest request,
628                 DependencyResolutionSkipper skipper,
629                 ParallelDescriptorResolver resolver) {
630             this.session = session;
631             this.request = request;
632             this.ignoreRepos = session.isIgnoreArtifactDescriptorRepositories();
633             this.premanagedState = ConfigUtils.getBoolean(session, false, DependencyManagerUtils.CONFIG_PROP_VERBOSE);
634             this.pool = pool;
635             this.collectionContext = collectionContext;
636             this.versionContext = versionContext;
637             this.skipper = skipper;
638             this.resolver = resolver;
639             this.interruptedException = new AtomicReference<>(null);
640         }
641     }
642 }