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