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.bf;
020
021import javax.inject.Inject;
022import javax.inject.Named;
023import javax.inject.Singleton;
024
025import java.io.Closeable;
026import java.util.ArrayDeque;
027import java.util.ArrayList;
028import java.util.Arrays;
029import java.util.Collections;
030import java.util.LinkedHashMap;
031import java.util.List;
032import java.util.Map;
033import java.util.Optional;
034import java.util.Queue;
035import java.util.Set;
036import java.util.concurrent.Callable;
037import java.util.concurrent.CompletableFuture;
038import java.util.concurrent.ConcurrentHashMap;
039import java.util.concurrent.Future;
040import java.util.concurrent.atomic.AtomicReference;
041import java.util.function.Supplier;
042import java.util.stream.Collectors;
043import java.util.stream.Stream;
044
045import org.eclipse.aether.RepositorySystemSession;
046import org.eclipse.aether.RequestTrace;
047import org.eclipse.aether.artifact.Artifact;
048import org.eclipse.aether.collection.CollectRequest;
049import org.eclipse.aether.collection.DependencyCollectionException;
050import org.eclipse.aether.collection.DependencyManager;
051import org.eclipse.aether.collection.DependencySelector;
052import org.eclipse.aether.collection.DependencyTraverser;
053import org.eclipse.aether.collection.VersionFilter;
054import org.eclipse.aether.graph.DefaultDependencyNode;
055import org.eclipse.aether.graph.Dependency;
056import org.eclipse.aether.graph.DependencyNode;
057import org.eclipse.aether.impl.ArtifactDescriptorReader;
058import org.eclipse.aether.impl.RemoteRepositoryManager;
059import org.eclipse.aether.impl.VersionRangeResolver;
060import org.eclipse.aether.internal.impl.collect.DataPool;
061import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollectionContext;
062import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector;
063import org.eclipse.aether.internal.impl.collect.DefaultVersionFilterContext;
064import org.eclipse.aether.internal.impl.collect.DependencyCollectorDelegate;
065import org.eclipse.aether.internal.impl.collect.PremanagedDependency;
066import org.eclipse.aether.repository.RemoteRepository;
067import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
068import org.eclipse.aether.resolution.ArtifactDescriptorResult;
069import org.eclipse.aether.resolution.VersionRangeRequest;
070import org.eclipse.aether.resolution.VersionRangeResult;
071import org.eclipse.aether.spi.artifact.decorator.ArtifactDecoratorFactory;
072import org.eclipse.aether.util.ConfigUtils;
073import org.eclipse.aether.util.artifact.ArtifactIdUtils;
074import org.eclipse.aether.util.concurrency.SmartExecutor;
075import org.eclipse.aether.util.concurrency.SmartExecutorUtils;
076import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
077import org.eclipse.aether.version.Version;
078
079import static org.eclipse.aether.internal.impl.collect.DefaultDependencyCycle.find;
080
081/**
082 * Breadth-first {@link org.eclipse.aether.impl.DependencyCollector}
083 *
084 * @since 1.8.0
085 */
086@Singleton
087@Named(BfDependencyCollector.NAME)
088public class BfDependencyCollector extends DependencyCollectorDelegate {
089    public static final String NAME = "bf";
090
091    private static final String CONFIG_PROPS_PREFIX = DefaultDependencyCollector.CONFIG_PROPS_PREFIX + NAME + ".";
092
093    /**
094     * The key in the repository session's {@link RepositorySystemSession#getConfigProperties()
095     * configuration properties} used to store a {@link String} flag controlling the resolver's skip mode.
096     * Supported modes are "versionless" (default), "versioned" and "false" to not use skipper. The first two modes
097     * are defining "function" how to map artifact coordinates to (String) key while deciding "skip" logic.
098     * The "versionless" uses {@code G:A:C:E} coordinate elements only (without version), while "versioned" uses
099     * 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                if (rootDepSelector != null && !rootDepSelector.selectDependency(dependency)) {
201                    continue;
202                }
203                RequestTrace childTrace =
204                        collectStepTrace(trace, args.request.getRequestContext(), parents, dependency);
205                DependencyProcessingContext processingContext = new DependencyProcessingContext(
206                        rootDepSelector,
207                        rootDepManager,
208                        rootDepTraverser,
209                        rootVerFilter,
210                        childTrace,
211                        repositories,
212                        managedDependencies,
213                        parents,
214                        dependency,
215                        PremanagedDependency.create(rootDepManager, dependency, false, args.premanagedState));
216                processingContext.withDependency(processingContext.premanagedDependency.getManagedDependency());
217                resolveArtifactDescriptorAsync(args, processingContext, results);
218                args.dependencyProcessingQueue.add(processingContext);
219            }
220
221            while (!args.dependencyProcessingQueue.isEmpty()) {
222                processDependency(
223                        args, results, args.dependencyProcessingQueue.remove(), Collections.emptyList(), false);
224            }
225
226            if (args.interruptedException.get() != null) {
227                throw new DependencyCollectionException(
228                        results.getResult(), "Collection interrupted", args.interruptedException.get());
229            }
230        }
231    }
232
233    @SuppressWarnings("checkstyle:parameternumber")
234    private void processDependency(
235            Args args,
236            Results results,
237            DependencyProcessingContext context,
238            List<Artifact> relocations,
239            boolean disableVersionManagement) {
240        if (Thread.interrupted()) {
241            args.interruptedException.set(new InterruptedException());
242        }
243        if (args.interruptedException.get() != null) {
244            return;
245        }
246        Dependency dependency = context.dependency;
247        PremanagedDependency preManaged = context.premanagedDependency;
248
249        boolean noDescriptor = isLackingDescriptor(args.session, dependency.getArtifact());
250        boolean traverse =
251                !noDescriptor && (context.depTraverser == null || context.depTraverser.traverseDependency(dependency));
252
253        Future<DescriptorResolutionResult> resolutionResultFuture = args.resolver.find(dependency.getArtifact());
254        DescriptorResolutionResult resolutionResult;
255        VersionRangeResult rangeResult;
256        try {
257            resolutionResult = resolutionResultFuture.get();
258            rangeResult = resolutionResult.rangeResult;
259        } catch (Exception e) {
260            results.addException(dependency, e, context.parents);
261            return;
262        }
263
264        Set<Version> versions = resolutionResult.descriptors.keySet();
265        for (Version version : versions) {
266            Artifact originalArtifact = dependency.getArtifact().setVersion(version.toString());
267            Dependency d = dependency.setArtifact(originalArtifact);
268
269            final ArtifactDescriptorResult descriptorResult = resolutionResult.descriptors.get(version);
270            if (descriptorResult != null) {
271                d = d.setArtifact(descriptorResult.getArtifact());
272
273                int cycleEntry = find(context.parents, d.getArtifact());
274                if (cycleEntry >= 0) {
275                    results.addCycle(context.parents, cycleEntry, d);
276                    DependencyNode cycleNode = context.parents.get(cycleEntry);
277                    if (cycleNode.getDependency() != null) {
278                        DefaultDependencyNode child = createDependencyNode(
279                                relocations, preManaged, rangeResult, version, d, descriptorResult, cycleNode);
280                        context.getParent().getChildren().add(child);
281                        continue;
282                    }
283                }
284
285                if (!descriptorResult.getRelocations().isEmpty()) {
286                    if (context.depSelector == null || context.depSelector.selectDependency(d)) {
287                        boolean disableVersionManagementSubsequently = originalArtifact
288                                        .getGroupId()
289                                        .equals(d.getArtifact().getGroupId())
290                                && originalArtifact
291                                        .getArtifactId()
292                                        .equals(d.getArtifact().getArtifactId());
293
294                        PremanagedDependency premanagedDependency = PremanagedDependency.create(
295                                context.depManager, d, disableVersionManagementSubsequently, args.premanagedState);
296                        DependencyProcessingContext relocatedContext = new DependencyProcessingContext(
297                                context.depSelector,
298                                context.depManager,
299                                context.depTraverser,
300                                context.verFilter,
301                                context.trace,
302                                context.repositories,
303                                descriptorResult.getManagedDependencies(),
304                                context.parents,
305                                d,
306                                premanagedDependency);
307
308                        relocatedContext.withDependency(premanagedDependency.getManagedDependency());
309                        resolveArtifactDescriptorAsync(args, relocatedContext, results);
310                        processDependency(
311                                args,
312                                results,
313                                relocatedContext,
314                                descriptorResult.getRelocations(),
315                                disableVersionManagementSubsequently);
316                    }
317                    return;
318                } else {
319                    d = args.pool.intern(d.setArtifact(args.pool.intern(d.getArtifact())));
320
321                    List<RemoteRepository> repos =
322                            getRemoteRepositories(rangeResult.getRepository(version), context.repositories);
323
324                    DefaultDependencyNode child = createDependencyNode(
325                            relocations,
326                            preManaged,
327                            rangeResult,
328                            version,
329                            d,
330                            descriptorResult.getAliases(),
331                            repos,
332                            args.request.getRequestContext());
333
334                    context.getParent().getChildren().add(child);
335
336                    boolean recurse =
337                            traverse && !descriptorResult.getDependencies().isEmpty();
338                    DependencyProcessingContext parentContext = context.withDependency(d);
339                    if (recurse) {
340                        doRecurse(args, parentContext, descriptorResult, child, results, disableVersionManagement);
341                    } else if (!args.skipper.skipResolution(child, parentContext.parents)) {
342                        List<DependencyNode> parents = new ArrayList<>(parentContext.parents.size() + 1);
343                        parents.addAll(parentContext.parents);
344                        parents.add(child);
345                        args.skipper.cache(child, parents);
346                    }
347                }
348            } else {
349                List<RemoteRepository> repos =
350                        getRemoteRepositories(rangeResult.getRepository(version), context.repositories);
351                DefaultDependencyNode child = createDependencyNode(
352                        relocations,
353                        preManaged,
354                        rangeResult,
355                        version,
356                        d,
357                        null,
358                        repos,
359                        args.request.getRequestContext());
360                context.getParent().getChildren().add(child);
361            }
362        }
363    }
364
365    @SuppressWarnings("checkstyle:parameternumber")
366    private void doRecurse(
367            Args args,
368            DependencyProcessingContext parentContext,
369            ArtifactDescriptorResult descriptorResult,
370            DefaultDependencyNode child,
371            Results results,
372            boolean disableVersionManagement) {
373        DefaultDependencyCollectionContext context = args.collectionContext.get();
374        args.collectionContext.compareAndSet(
375                context, context.set(parentContext.dependency, descriptorResult.getManagedDependencies()));
376        context = args.collectionContext.get();
377
378        DependencySelector childSelector =
379                parentContext.depSelector != null ? parentContext.depSelector.deriveChildSelector(context) : null;
380        DependencyManager childManager =
381                parentContext.depManager != null ? parentContext.depManager.deriveChildManager(context) : null;
382        DependencyTraverser childTraverser =
383                parentContext.depTraverser != null ? parentContext.depTraverser.deriveChildTraverser(context) : null;
384        VersionFilter childFilter =
385                parentContext.verFilter != null ? parentContext.verFilter.deriveChildFilter(context) : null;
386
387        final List<RemoteRepository> childRepos = args.ignoreRepos
388                ? parentContext.repositories
389                : remoteRepositoryManager.aggregateRepositories(
390                        args.session, parentContext.repositories, descriptorResult.getRepositories(), true);
391
392        Object key = args.pool.toKey(
393                parentContext.dependency.getArtifact(),
394                childRepos,
395                childSelector,
396                childManager,
397                childTraverser,
398                childFilter);
399
400        List<DependencyNode> children = args.pool.getChildren(key);
401        if (children == null) {
402            boolean skipResolution = args.skipper.skipResolution(child, parentContext.parents);
403            if (!skipResolution) {
404                List<DependencyNode> parents = new ArrayList<>(parentContext.parents.size() + 1);
405                parents.addAll(parentContext.parents);
406                parents.add(child);
407                for (Dependency dependency : descriptorResult.getDependencies()) {
408                    if (childSelector != null && !childSelector.selectDependency(dependency)) {
409                        continue;
410                    }
411                    RequestTrace childTrace = collectStepTrace(
412                            parentContext.trace, args.request.getRequestContext(), parents, dependency);
413                    PremanagedDependency premanagedDependency = PremanagedDependency.create(
414                            childManager, dependency, disableVersionManagement, args.premanagedState);
415                    DependencyProcessingContext processingContext = new DependencyProcessingContext(
416                            childSelector,
417                            childManager,
418                            childTraverser,
419                            childFilter,
420                            childTrace,
421                            childRepos,
422                            descriptorResult.getManagedDependencies(),
423                            parents,
424                            dependency,
425                            premanagedDependency);
426                    // resolve descriptors ahead for managed dependency
427                    processingContext.withDependency(processingContext.premanagedDependency.getManagedDependency());
428                    resolveArtifactDescriptorAsync(args, processingContext, results);
429                    args.dependencyProcessingQueue.add(processingContext);
430                }
431                args.pool.putChildren(key, child.getChildren());
432                args.skipper.cache(child, parents);
433            }
434        } else {
435            child.setChildren(children);
436        }
437    }
438
439    private void resolveArtifactDescriptorAsync(Args args, DependencyProcessingContext context, Results results) {
440        Dependency dependency = context.dependency;
441        args.resolver.resolveDescriptors(dependency.getArtifact(), () -> {
442            VersionRangeRequest rangeRequest = createVersionRangeRequest(
443                    args.request.getRequestContext(), context.trace, context.repositories, dependency);
444            VersionRangeResult rangeResult = cachedResolveRangeResult(rangeRequest, args.pool, args.session);
445            List<? extends Version> versions =
446                    filterVersions(dependency, rangeResult, context.verFilter, args.versionContext);
447
448            // resolve newer version first to maximize benefits of skipper
449            Collections.reverse(versions);
450
451            Map<Version, ArtifactDescriptorResult> descriptors = new ConcurrentHashMap<>(versions.size());
452            Stream<? extends Version> stream = versions.size() > 1 ? versions.parallelStream() : versions.stream();
453            stream.forEach(version -> Optional.ofNullable(
454                            resolveDescriptorForVersion(args, context, results, dependency, version))
455                    .ifPresent(r -> descriptors.put(version, r)));
456
457            DescriptorResolutionResult resolutionResult =
458                    new DescriptorResolutionResult(dependency.getArtifact(), rangeResult);
459            // keep original sequence
460            versions.forEach(version -> resolutionResult.descriptors.put(version, descriptors.get(version)));
461            // populate for versions in version range
462            resolutionResult.flatten().forEach(dr -> args.resolver.cacheVersionRangeDescriptor(dr.artifact, dr));
463
464            return resolutionResult;
465        });
466    }
467
468    private ArtifactDescriptorResult resolveDescriptorForVersion(
469            Args args, DependencyProcessingContext context, Results results, Dependency dependency, Version version) {
470        Artifact original = dependency.getArtifact();
471        Artifact newArtifact = original.setVersion(version.toString());
472        Dependency newDependency =
473                new Dependency(newArtifact, dependency.getScope(), dependency.isOptional(), dependency.getExclusions());
474        DependencyProcessingContext newContext = context.copy();
475
476        ArtifactDescriptorRequest descriptorRequest = createArtifactDescriptorRequest(
477                args.request.getRequestContext(), context.trace, newContext.repositories, newDependency);
478        return isLackingDescriptor(args.session, newArtifact)
479                ? new ArtifactDescriptorResult(descriptorRequest)
480                : resolveCachedArtifactDescriptor(
481                        args.pool,
482                        descriptorRequest,
483                        args.session,
484                        newContext.withDependency(newDependency).dependency,
485                        results,
486                        context.parents);
487    }
488
489    static class ParallelDescriptorResolver implements Closeable {
490        private final SmartExecutor smartExecutor;
491
492        /**
493         * Artifact ID -> Future of DescriptorResolutionResult
494         */
495        private final Map<String, Future<DescriptorResolutionResult>> results = new ConcurrentHashMap<>(256);
496
497        ParallelDescriptorResolver(SmartExecutor smartExecutor) {
498            this.smartExecutor = smartExecutor;
499        }
500
501        void resolveDescriptors(Artifact artifact, Callable<DescriptorResolutionResult> callable) {
502            results.computeIfAbsent(ArtifactIdUtils.toId(artifact), key -> smartExecutor.submit(callable));
503        }
504
505        void cacheVersionRangeDescriptor(Artifact artifact, DescriptorResolutionResult resolutionResult) {
506            results.computeIfAbsent(
507                    ArtifactIdUtils.toId(artifact), key -> CompletableFuture.completedFuture(resolutionResult));
508        }
509
510        Future<DescriptorResolutionResult> find(Artifact artifact) {
511            return results.get(ArtifactIdUtils.toId(artifact));
512        }
513
514        @Override
515        public void close() {
516            smartExecutor.close();
517        }
518    }
519
520    static class DescriptorResolutionResult {
521        Artifact artifact;
522
523        VersionRangeResult rangeResult;
524
525        Map<Version, ArtifactDescriptorResult> descriptors;
526
527        DescriptorResolutionResult(Artifact artifact, VersionRangeResult rangeResult) {
528            this.artifact = artifact;
529            this.rangeResult = rangeResult;
530            this.descriptors = new LinkedHashMap<>(rangeResult.getVersions().size());
531        }
532
533        DescriptorResolutionResult(
534                VersionRangeResult rangeResult, Version version, ArtifactDescriptorResult descriptor) {
535            // NOTE: In case of A1 -> A2 relocation this happens:
536            // ArtifactDescriptorResult read by ArtifactDescriptorResultReader for A1
537            // will return instance that will have artifact = A2 (as RelocatedArtifact).
538            // So to properly "key" this instance, we need to use "originally requested" A1 instead!
539            // In short:
540            // ArtifactDescriptorRequest.artifact != ArtifactDescriptorResult.artifact WHEN relocation in play
541            // otherwise (no relocation), they are EQUAL.
542            this(descriptor.getRequest().getArtifact(), rangeResult);
543            this.descriptors.put(version, descriptor);
544        }
545
546        List<DescriptorResolutionResult> flatten() {
547            if (descriptors.size() > 1) {
548                return descriptors.entrySet().stream()
549                        .map(e -> new DescriptorResolutionResult(rangeResult, e.getKey(), e.getValue()))
550                        .collect(Collectors.toList());
551            } else {
552                return Collections.emptyList();
553            }
554        }
555    }
556
557    static class Args {
558
559        final RepositorySystemSession session;
560
561        final boolean ignoreRepos;
562
563        final boolean premanagedState;
564
565        final DataPool pool;
566
567        final Queue<DependencyProcessingContext> dependencyProcessingQueue = new ArrayDeque<>(128);
568
569        final AtomicReference<DefaultDependencyCollectionContext> collectionContext;
570
571        final DefaultVersionFilterContext versionContext;
572
573        final CollectRequest request;
574
575        final DependencyResolutionSkipper skipper;
576
577        final ParallelDescriptorResolver resolver;
578
579        final AtomicReference<InterruptedException> interruptedException;
580
581        Args(
582                RepositorySystemSession session,
583                DataPool pool,
584                DefaultDependencyCollectionContext collectionContext,
585                DefaultVersionFilterContext versionContext,
586                CollectRequest request,
587                DependencyResolutionSkipper skipper,
588                ParallelDescriptorResolver resolver) {
589            this.session = session;
590            this.request = request;
591            this.ignoreRepos = session.isIgnoreArtifactDescriptorRepositories();
592            this.premanagedState = ConfigUtils.getBoolean(session, false, DependencyManagerUtils.CONFIG_PROP_VERBOSE);
593            this.pool = pool;
594            this.collectionContext = new AtomicReference<>(collectionContext);
595            this.versionContext = versionContext;
596            this.skipper = skipper;
597            this.resolver = resolver;
598            this.interruptedException = new AtomicReference<>(null);
599        }
600    }
601}