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;
020
021import java.util.Collections;
022import java.util.HashMap;
023import java.util.Map;
024import java.util.function.Function;
025
026import org.eclipse.aether.artifact.ArtifactType;
027import org.eclipse.aether.artifact.ArtifactTypeRegistry;
028import org.eclipse.aether.collection.DependencyCollectionChecker;
029import org.eclipse.aether.collection.DependencyGraphTransformer;
030import org.eclipse.aether.collection.DependencyManager;
031import org.eclipse.aether.collection.DependencySelector;
032import org.eclipse.aether.collection.DependencyTraverser;
033import org.eclipse.aether.collection.VersionFilter;
034import org.eclipse.aether.repository.Authentication;
035import org.eclipse.aether.repository.AuthenticationSelector;
036import org.eclipse.aether.repository.LocalRepository;
037import org.eclipse.aether.repository.LocalRepositoryManager;
038import org.eclipse.aether.repository.MirrorSelector;
039import org.eclipse.aether.repository.Proxy;
040import org.eclipse.aether.repository.ProxySelector;
041import org.eclipse.aether.repository.RemoteRepository;
042import org.eclipse.aether.repository.RepositoryPolicy;
043import org.eclipse.aether.repository.WorkspaceReader;
044import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
045import org.eclipse.aether.resolution.ResolutionErrorPolicy;
046import org.eclipse.aether.scope.ScopeManager;
047import org.eclipse.aether.scope.SystemDependencyScope;
048import org.eclipse.aether.transfer.TransferListener;
049
050import static java.util.Objects.requireNonNull;
051
052/**
053 * A legacy repository system session. It is usable to "derive" sessions from existing session instances (using
054 * copy-constructor), but the recommended way to derive sessions is using
055 * {@link org.eclipse.aether.RepositorySystemSession.SessionBuilder#withRepositorySystemSession(RepositorySystemSession)}
056 * instead.
057 * <p>
058 * <em>Important: while the default constructor on this class is deprecated only, it is left only to guarantee
059 * backward compatibility with legacy code, but the default constructor should not be used anymore. Using that
060 * constructor will lead to resource leaks.</em>
061 * <p>
062 * <strong>Note:</strong> This class is not thread-safe. It is assumed that the mutators get only called during an
063 * initialization phase and that the session itself is not changed once initialized and being used by the repository
064 * system. It is recommended to call {@link #setReadOnly()} once the session has been fully initialized to prevent
065 * accidental manipulation of it afterward.
066 *
067 * @see RepositorySystem#createSessionBuilder()
068 * @see RepositorySystemSession.SessionBuilder
069 * @see RepositorySystemSession.CloseableSession
070 */
071public final class DefaultRepositorySystemSession implements RepositorySystemSession {
072    private boolean readOnly;
073
074    private boolean offline;
075
076    private boolean ignoreArtifactDescriptorRepositories;
077
078    private ResolutionErrorPolicy resolutionErrorPolicy;
079
080    private ArtifactDescriptorPolicy artifactDescriptorPolicy;
081
082    private String checksumPolicy;
083
084    private String artifactUpdatePolicy;
085
086    private String metadataUpdatePolicy;
087
088    private LocalRepositoryManager localRepositoryManager;
089
090    private WorkspaceReader workspaceReader;
091
092    private RepositoryListener repositoryListener;
093
094    private TransferListener transferListener;
095
096    private Map<String, String> systemProperties;
097
098    private Map<String, String> systemPropertiesView;
099
100    private Map<String, String> userProperties;
101
102    private Map<String, String> userPropertiesView;
103
104    private Map<String, Object> configProperties;
105
106    private Map<String, Object> configPropertiesView;
107
108    private MirrorSelector mirrorSelector;
109
110    private ProxySelector proxySelector;
111
112    private AuthenticationSelector authenticationSelector;
113
114    private ArtifactTypeRegistry artifactTypeRegistry;
115
116    private DependencyTraverser dependencyTraverser;
117
118    private DependencyManager dependencyManager;
119
120    private DependencySelector dependencySelector;
121
122    private VersionFilter versionFilter;
123
124    private DependencyGraphTransformer dependencyGraphTransformer;
125
126    private SessionData data;
127
128    private RepositoryCache cache;
129
130    private ScopeManager scopeManager;
131
132    private DependencyCollectionChecker dependencyCollectionChecker;
133
134    private final Function<Runnable, Boolean> onSessionEndedRegistrar;
135
136    /**
137     * Creates an uninitialized session. <em>Note:</em> The new session is not ready to use, as a bare minimum,
138     * {@link #setLocalRepositoryManager(LocalRepositoryManager)} needs to be called but usually other settings also
139     * need to be customized to achieve meaningful behavior.
140     *
141     * @deprecated This way of creating session should be avoided, is in place just to offer backward binary
142     * compatibility with Resolver 1.x using code, but offers reduced functionality.
143     * Use {@link RepositorySystem#createSessionBuilder()} instead.
144     */
145    @Deprecated
146    public DefaultRepositorySystemSession() {
147        this(h -> false);
148    }
149
150    /**
151     * Creates an uninitialized session. <em>Note:</em> The new session is not ready to use, as a bare minimum,
152     * {@link #setLocalRepositoryManager(LocalRepositoryManager)} needs to be called but usually other settings also
153     * need to be customized to achieve meaningful behavior.
154     * <p>
155     * Note: preferred way to create sessions is {@link RepositorySystem#createSessionBuilder()}, as then client code
156     * does not have to fiddle with session close callbacks. This constructor is meant more for testing purposes.
157     *
158     * @since 2.0.0
159     */
160    public DefaultRepositorySystemSession(Function<Runnable, Boolean> onSessionEndedRegistrar) {
161        systemProperties = new HashMap<>();
162        systemPropertiesView = Collections.unmodifiableMap(systemProperties);
163        userProperties = new HashMap<>();
164        userPropertiesView = Collections.unmodifiableMap(userProperties);
165        configProperties = new HashMap<>();
166        configPropertiesView = Collections.unmodifiableMap(configProperties);
167        mirrorSelector = NullMirrorSelector.INSTANCE;
168        proxySelector = PassthroughProxySelector.INSTANCE;
169        authenticationSelector = PassthroughAuthenticationSelector.INSTANCE;
170        artifactTypeRegistry = NullArtifactTypeRegistry.INSTANCE;
171        data = new DefaultSessionData();
172        this.onSessionEndedRegistrar = requireNonNull(onSessionEndedRegistrar, "onSessionEndedRegistrar");
173    }
174
175    /**
176     * Creates a shallow copy of the specified session. Actually, the copy is not completely shallow, all maps holding
177     * system/user/config properties are copied as well. In other words, invoking any mutator on the new session itself
178     * has no effect on the original session. Other mutable objects like the session data and cache (if any) are not
179     * copied and will be shared with the original session unless reconfigured.
180     *
181     * @param session The session to copy, must not be {@code null}.
182     */
183    public DefaultRepositorySystemSession(RepositorySystemSession session) {
184        requireNonNull(session, "repository system session cannot be null");
185
186        setOffline(session.isOffline());
187        setIgnoreArtifactDescriptorRepositories(session.isIgnoreArtifactDescriptorRepositories());
188        setResolutionErrorPolicy(session.getResolutionErrorPolicy());
189        setArtifactDescriptorPolicy(session.getArtifactDescriptorPolicy());
190        setChecksumPolicy(session.getChecksumPolicy());
191        setUpdatePolicy(session.getUpdatePolicy());
192        setMetadataUpdatePolicy(session.getMetadataUpdatePolicy());
193        setLocalRepositoryManager(session.getLocalRepositoryManager());
194        setWorkspaceReader(session.getWorkspaceReader());
195        setRepositoryListener(session.getRepositoryListener());
196        setTransferListener(session.getTransferListener());
197        setSystemProperties(session.getSystemProperties());
198        setUserProperties(session.getUserProperties());
199        setConfigProperties(session.getConfigProperties());
200        setMirrorSelector(session.getMirrorSelector());
201        setProxySelector(session.getProxySelector());
202        setAuthenticationSelector(session.getAuthenticationSelector());
203        setArtifactTypeRegistry(session.getArtifactTypeRegistry());
204        setDependencyTraverser(session.getDependencyTraverser());
205        setDependencyManager(session.getDependencyManager());
206        setDependencySelector(session.getDependencySelector());
207        setVersionFilter(session.getVersionFilter());
208        setDependencyGraphTransformer(session.getDependencyGraphTransformer());
209        setData(session.getData());
210        setCache(session.getCache());
211        setScopeManager(session.getScopeManager());
212        setDependencyCollectionChecker(session.getDependencyCollectionChecker());
213        this.onSessionEndedRegistrar = session::addOnSessionEndedHandler;
214    }
215
216    @Override
217    public boolean isOffline() {
218        return offline;
219    }
220
221    /**
222     * Controls whether the repository system operates in offline mode and avoids/refuses any access to remote
223     * repositories.
224     *
225     * @param offline {@code true} if the repository system is in offline mode, {@code false} otherwise.
226     * @return This session for chaining, never {@code null}.
227     */
228    public DefaultRepositorySystemSession setOffline(boolean offline) {
229        verifyStateForMutation();
230        this.offline = offline;
231        return this;
232    }
233
234    @Override
235    public boolean isIgnoreArtifactDescriptorRepositories() {
236        return ignoreArtifactDescriptorRepositories;
237    }
238
239    /**
240     * Controls whether repositories declared in artifact descriptors should be ignored during transitive dependency
241     * collection. If enabled, only the repositories originally provided with the collect request will be considered.
242     *
243     * @param ignoreArtifactDescriptorRepositories {@code true} to ignore additional repositories from artifact
244     *                                             descriptors, {@code false} to merge those with the originally
245     *                                             specified repositories.
246     * @return This session for chaining, never {@code null}.
247     */
248    public DefaultRepositorySystemSession setIgnoreArtifactDescriptorRepositories(
249            boolean ignoreArtifactDescriptorRepositories) {
250        verifyStateForMutation();
251        this.ignoreArtifactDescriptorRepositories = ignoreArtifactDescriptorRepositories;
252        return this;
253    }
254
255    @Override
256    public ResolutionErrorPolicy getResolutionErrorPolicy() {
257        return resolutionErrorPolicy;
258    }
259
260    /**
261     * Sets the policy which controls whether resolutions errors from remote repositories should be cached.
262     *
263     * @param resolutionErrorPolicy The resolution error policy for this session, may be {@code null} if resolution
264     *                              errors should generally not be cached.
265     * @return This session for chaining, never {@code null}.
266     */
267    public DefaultRepositorySystemSession setResolutionErrorPolicy(ResolutionErrorPolicy resolutionErrorPolicy) {
268        verifyStateForMutation();
269        this.resolutionErrorPolicy = resolutionErrorPolicy;
270        return this;
271    }
272
273    @Override
274    public ArtifactDescriptorPolicy getArtifactDescriptorPolicy() {
275        return artifactDescriptorPolicy;
276    }
277
278    /**
279     * Sets the policy which controls how errors related to reading artifact descriptors should be handled.
280     *
281     * @param artifactDescriptorPolicy The descriptor error policy for this session, may be {@code null} if descriptor
282     *                                 errors should generally not be tolerated.
283     * @return This session for chaining, never {@code null}.
284     */
285    public DefaultRepositorySystemSession setArtifactDescriptorPolicy(
286            ArtifactDescriptorPolicy artifactDescriptorPolicy) {
287        verifyStateForMutation();
288        this.artifactDescriptorPolicy = artifactDescriptorPolicy;
289        return this;
290    }
291
292    @Override
293    public String getChecksumPolicy() {
294        return checksumPolicy;
295    }
296
297    /**
298     * Sets the global checksum policy. If set, the global checksum policy overrides the checksum policies of the remote
299     * repositories being used for resolution.
300     *
301     * @param checksumPolicy The global checksum policy, may be {@code null}/empty to apply the per-repository policies.
302     * @return This session for chaining, never {@code null}.
303     * @see RepositoryPolicy#CHECKSUM_POLICY_FAIL
304     * @see RepositoryPolicy#CHECKSUM_POLICY_IGNORE
305     * @see RepositoryPolicy#CHECKSUM_POLICY_WARN
306     */
307    public DefaultRepositorySystemSession setChecksumPolicy(String checksumPolicy) {
308        verifyStateForMutation();
309        this.checksumPolicy = checksumPolicy;
310        return this;
311    }
312
313    @Override
314    public String getUpdatePolicy() {
315        return getArtifactUpdatePolicy();
316    }
317
318    /**
319     * Sets the global update policy. If set, the global update policy overrides the update policies of the remote
320     * repositories being used for resolution.
321     * <p>
322     * This method is meant for code that does not want to distinguish between artifact and metadata policies.
323     * Note: applications should either use get/set updatePolicy (this method and
324     * {@link RepositorySystemSession#getUpdatePolicy()}) or also distinguish between artifact and
325     * metadata update policies (and use other methods), but <em>should not mix the two!</em>
326     *
327     * @param updatePolicy The global update policy, may be {@code null}/empty to apply the per-repository policies.
328     * @return This session for chaining, never {@code null}.
329     * @see RepositoryPolicy#UPDATE_POLICY_ALWAYS
330     * @see RepositoryPolicy#UPDATE_POLICY_DAILY
331     * @see RepositoryPolicy#UPDATE_POLICY_NEVER
332     * @see #setArtifactUpdatePolicy(String)
333     * @see #setMetadataUpdatePolicy(String)
334     */
335    public DefaultRepositorySystemSession setUpdatePolicy(String updatePolicy) {
336        verifyStateForMutation();
337        setArtifactUpdatePolicy(updatePolicy);
338        setMetadataUpdatePolicy(updatePolicy);
339        return this;
340    }
341
342    @Override
343    public String getArtifactUpdatePolicy() {
344        return artifactUpdatePolicy;
345    }
346
347    /**
348     * Sets the global artifact update policy. If set, the global update policy overrides the artifact update policies
349     * of the remote repositories being used for resolution.
350     *
351     * @param artifactUpdatePolicy The global update policy, may be {@code null}/empty to apply the per-repository policies.
352     * @return This session for chaining, never {@code null}.
353     * @see RepositoryPolicy#UPDATE_POLICY_ALWAYS
354     * @see RepositoryPolicy#UPDATE_POLICY_DAILY
355     * @see RepositoryPolicy#UPDATE_POLICY_NEVER
356     * @since 2.0.0
357     */
358    public DefaultRepositorySystemSession setArtifactUpdatePolicy(String artifactUpdatePolicy) {
359        verifyStateForMutation();
360        this.artifactUpdatePolicy = artifactUpdatePolicy;
361        return this;
362    }
363
364    @Override
365    public String getMetadataUpdatePolicy() {
366        return metadataUpdatePolicy;
367    }
368
369    /**
370     * Sets the global metadata update policy. If set, the global update policy overrides the metadata update policies
371     * of the remote repositories being used for resolution.
372     *
373     * @param metadataUpdatePolicy The global update policy, may be {@code null}/empty to apply the per-repository policies.
374     * @return This session for chaining, never {@code null}.
375     * @see RepositoryPolicy#UPDATE_POLICY_ALWAYS
376     * @see RepositoryPolicy#UPDATE_POLICY_DAILY
377     * @see RepositoryPolicy#UPDATE_POLICY_NEVER
378     * @since 2.0.0
379     */
380    public DefaultRepositorySystemSession setMetadataUpdatePolicy(String metadataUpdatePolicy) {
381        verifyStateForMutation();
382        this.metadataUpdatePolicy = metadataUpdatePolicy;
383        return this;
384    }
385
386    @Override
387    public LocalRepository getLocalRepository() {
388        LocalRepositoryManager lrm = getLocalRepositoryManager();
389        return (lrm != null) ? lrm.getRepository() : null;
390    }
391
392    @Override
393    public LocalRepositoryManager getLocalRepositoryManager() {
394        return localRepositoryManager;
395    }
396
397    /**
398     * Sets the local repository manager used during this session. <em>Note:</em> Eventually, a valid session must have
399     * a local repository manager set.
400     *
401     * @param localRepositoryManager The local repository manager used during this session, may be {@code null}.
402     * @return This session for chaining, never {@code null}.
403     */
404    public DefaultRepositorySystemSession setLocalRepositoryManager(LocalRepositoryManager localRepositoryManager) {
405        verifyStateForMutation();
406        this.localRepositoryManager = localRepositoryManager;
407        return this;
408    }
409
410    @Override
411    public WorkspaceReader getWorkspaceReader() {
412        return workspaceReader;
413    }
414
415    /**
416     * Sets the workspace reader used during this session. If set, the workspace reader will usually be consulted first
417     * to resolve artifacts.
418     *
419     * @param workspaceReader The workspace reader for this session, may be {@code null} if none.
420     * @return This session for chaining, never {@code null}.
421     */
422    public DefaultRepositorySystemSession setWorkspaceReader(WorkspaceReader workspaceReader) {
423        verifyStateForMutation();
424        this.workspaceReader = workspaceReader;
425        return this;
426    }
427
428    @Override
429    public RepositoryListener getRepositoryListener() {
430        return repositoryListener;
431    }
432
433    /**
434     * Sets the listener being notified of actions in the repository system.
435     *
436     * @param repositoryListener The repository listener, may be {@code null} if none.
437     * @return This session for chaining, never {@code null}.
438     */
439    public DefaultRepositorySystemSession setRepositoryListener(RepositoryListener repositoryListener) {
440        verifyStateForMutation();
441        this.repositoryListener = repositoryListener;
442        return this;
443    }
444
445    @Override
446    public TransferListener getTransferListener() {
447        return transferListener;
448    }
449
450    /**
451     * Sets the listener being notified of uploads/downloads by the repository system.
452     *
453     * @param transferListener The transfer listener, may be {@code null} if none.
454     * @return This session for chaining, never {@code null}.
455     */
456    public DefaultRepositorySystemSession setTransferListener(TransferListener transferListener) {
457        verifyStateForMutation();
458        this.transferListener = transferListener;
459        return this;
460    }
461
462    private <T> Map<String, T> copySafe(Map<?, ?> table, Class<T> valueType) {
463        Map<String, T> map;
464        if (table == null || table.isEmpty()) {
465            map = new HashMap<>();
466        } else {
467            map = new HashMap<>((int) (table.size() / 0.75f) + 1);
468            for (Map.Entry<?, ?> entry : table.entrySet()) {
469                Object key = entry.getKey();
470                if (key instanceof String) {
471                    Object value = entry.getValue();
472                    if (valueType.isInstance(value)) {
473                        map.put(key.toString(), valueType.cast(value));
474                    }
475                }
476            }
477        }
478        return map;
479    }
480
481    @Override
482    public Map<String, String> getSystemProperties() {
483        return systemPropertiesView;
484    }
485
486    /**
487     * Sets the system properties to use, e.g. for processing of artifact descriptors. System properties are usually
488     * collected from the runtime environment like {@link System#getProperties()} and environment variables.
489     * <p>
490     * <em>Note:</em> System properties are of type {@code Map<String, String>} and any key-value pair in the input map
491     * that doesn't match this type will be silently ignored.
492     *
493     * @param systemProperties The system properties, may be {@code null} or empty if none.
494     * @return This session for chaining, never {@code null}.
495     */
496    public DefaultRepositorySystemSession setSystemProperties(Map<?, ?> systemProperties) {
497        verifyStateForMutation();
498        this.systemProperties = copySafe(systemProperties, String.class);
499        systemPropertiesView = Collections.unmodifiableMap(this.systemProperties);
500        return this;
501    }
502
503    /**
504     * Sets the specified system property.
505     *
506     * @param key   The property key, must not be {@code null}.
507     * @param value The property value, may be {@code null} to remove/unset the property.
508     * @return This session for chaining, never {@code null}.
509     */
510    public DefaultRepositorySystemSession setSystemProperty(String key, String value) {
511        verifyStateForMutation();
512        if (value != null) {
513            systemProperties.put(key, value);
514        } else {
515            systemProperties.remove(key);
516        }
517        return this;
518    }
519
520    @Override
521    public Map<String, String> getUserProperties() {
522        return userPropertiesView;
523    }
524
525    /**
526     * Sets the user properties to use, e.g. for processing of artifact descriptors. User properties are similar to
527     * system properties but are set on the discretion of the user and hence are considered of higher priority than
528     * system properties in case of conflicts.
529     * <p>
530     * <em>Note:</em> User properties are of type {@code Map<String, String>} and any key-value pair in the input map
531     * that doesn't match this type will be silently ignored.
532     *
533     * @param userProperties The user properties, may be {@code null} or empty if none.
534     * @return This session for chaining, never {@code null}.
535     */
536    public DefaultRepositorySystemSession setUserProperties(Map<?, ?> userProperties) {
537        verifyStateForMutation();
538        this.userProperties = copySafe(userProperties, String.class);
539        userPropertiesView = Collections.unmodifiableMap(this.userProperties);
540        return this;
541    }
542
543    /**
544     * Sets the specified user property.
545     *
546     * @param key   The property key, must not be {@code null}.
547     * @param value The property value, may be {@code null} to remove/unset the property.
548     * @return This session for chaining, never {@code null}.
549     */
550    public DefaultRepositorySystemSession setUserProperty(String key, String value) {
551        verifyStateForMutation();
552        if (value != null) {
553            userProperties.put(key, value);
554        } else {
555            userProperties.remove(key);
556        }
557        return this;
558    }
559
560    @Override
561    public Map<String, Object> getConfigProperties() {
562        return configPropertiesView;
563    }
564
565    /**
566     * Sets the configuration properties used to tweak internal aspects of the repository system (e.g. thread pooling,
567     * connector-specific behavior, etc.).
568     * <p>
569     * <em>Note:</em> Configuration properties are of type {@code Map<String, Object>} and any key-value pair in the
570     * input map that doesn't match this type will be silently ignored.
571     *
572     * @param configProperties The configuration properties, may be {@code null} or empty if none.
573     * @return This session for chaining, never {@code null}.
574     */
575    public DefaultRepositorySystemSession setConfigProperties(Map<?, ?> configProperties) {
576        verifyStateForMutation();
577        this.configProperties = copySafe(configProperties, Object.class);
578        configPropertiesView = Collections.unmodifiableMap(this.configProperties);
579        return this;
580    }
581
582    /**
583     * Sets the specified configuration property.
584     *
585     * @param key   The property key, must not be {@code null}.
586     * @param value The property value, may be {@code null} to remove/unset the property.
587     * @return This session for chaining, never {@code null}.
588     */
589    public DefaultRepositorySystemSession setConfigProperty(String key, Object value) {
590        verifyStateForMutation();
591        if (value != null) {
592            configProperties.put(key, value);
593        } else {
594            configProperties.remove(key);
595        }
596        return this;
597    }
598
599    @Override
600    public MirrorSelector getMirrorSelector() {
601        return mirrorSelector;
602    }
603
604    /**
605     * Sets the mirror selector to use for repositories discovered in artifact descriptors. Note that this selector is
606     * not used for remote repositories which are passed as request parameters to the repository system, those
607     * repositories are supposed to denote the effective repositories.
608     *
609     * @param mirrorSelector The mirror selector to use, may be {@code null}.
610     * @return This session for chaining, never {@code null}.
611     */
612    public DefaultRepositorySystemSession setMirrorSelector(MirrorSelector mirrorSelector) {
613        verifyStateForMutation();
614        this.mirrorSelector = mirrorSelector;
615        if (this.mirrorSelector == null) {
616            this.mirrorSelector = NullMirrorSelector.INSTANCE;
617        }
618        return this;
619    }
620
621    @Override
622    public ProxySelector getProxySelector() {
623        return proxySelector;
624    }
625
626    /**
627     * Sets the proxy selector to use for repositories discovered in artifact descriptors. Note that this selector is
628     * not used for remote repositories which are passed as request parameters to the repository system, those
629     * repositories are supposed to have their proxy (if any) already set.
630     *
631     * @param proxySelector The proxy selector to use, may be {@code null}.
632     * @return This session for chaining, never {@code null}.
633     * @see org.eclipse.aether.repository.RemoteRepository#getProxy()
634     */
635    public DefaultRepositorySystemSession setProxySelector(ProxySelector proxySelector) {
636        verifyStateForMutation();
637        this.proxySelector = proxySelector;
638        if (this.proxySelector == null) {
639            this.proxySelector = PassthroughProxySelector.INSTANCE;
640        }
641        return this;
642    }
643
644    @Override
645    public AuthenticationSelector getAuthenticationSelector() {
646        return authenticationSelector;
647    }
648
649    /**
650     * Sets the authentication selector to use for repositories discovered in artifact descriptors. Note that this
651     * selector is not used for remote repositories which are passed as request parameters to the repository system,
652     * those repositories are supposed to have their authentication (if any) already set.
653     *
654     * @param authenticationSelector The authentication selector to use, may be {@code null}.
655     * @return This session for chaining, never {@code null}.
656     * @see org.eclipse.aether.repository.RemoteRepository#getAuthentication()
657     */
658    public DefaultRepositorySystemSession setAuthenticationSelector(AuthenticationSelector authenticationSelector) {
659        verifyStateForMutation();
660        this.authenticationSelector = authenticationSelector;
661        if (this.authenticationSelector == null) {
662            this.authenticationSelector = PassthroughAuthenticationSelector.INSTANCE;
663        }
664        return this;
665    }
666
667    @Override
668    public ArtifactTypeRegistry getArtifactTypeRegistry() {
669        return artifactTypeRegistry;
670    }
671
672    /**
673     * Sets the registry of artifact types recognized by this session.
674     *
675     * @param artifactTypeRegistry The artifact type registry, may be {@code null}.
676     * @return This session for chaining, never {@code null}.
677     */
678    public DefaultRepositorySystemSession setArtifactTypeRegistry(ArtifactTypeRegistry artifactTypeRegistry) {
679        verifyStateForMutation();
680        this.artifactTypeRegistry = artifactTypeRegistry;
681        if (this.artifactTypeRegistry == null) {
682            this.artifactTypeRegistry = NullArtifactTypeRegistry.INSTANCE;
683        }
684        return this;
685    }
686
687    @Override
688    public DependencyTraverser getDependencyTraverser() {
689        return dependencyTraverser;
690    }
691
692    /**
693     * Sets the dependency traverser to use for building dependency graphs.
694     *
695     * @param dependencyTraverser The dependency traverser to use for building dependency graphs, may be {@code null}.
696     * @return This session for chaining, never {@code null}.
697     */
698    public DefaultRepositorySystemSession setDependencyTraverser(DependencyTraverser dependencyTraverser) {
699        verifyStateForMutation();
700        this.dependencyTraverser = dependencyTraverser;
701        return this;
702    }
703
704    @Override
705    public DependencyManager getDependencyManager() {
706        return dependencyManager;
707    }
708
709    /**
710     * Sets the dependency manager to use for building dependency graphs.
711     *
712     * @param dependencyManager The dependency manager to use for building dependency graphs, may be {@code null}.
713     * @return This session for chaining, never {@code null}.
714     */
715    public DefaultRepositorySystemSession setDependencyManager(DependencyManager dependencyManager) {
716        verifyStateForMutation();
717        this.dependencyManager = dependencyManager;
718        return this;
719    }
720
721    @Override
722    public DependencySelector getDependencySelector() {
723        return dependencySelector;
724    }
725
726    /**
727     * Sets the dependency selector to use for building dependency graphs.
728     *
729     * @param dependencySelector The dependency selector to use for building dependency graphs, may be {@code null}.
730     * @return This session for chaining, never {@code null}.
731     */
732    public DefaultRepositorySystemSession setDependencySelector(DependencySelector dependencySelector) {
733        verifyStateForMutation();
734        this.dependencySelector = dependencySelector;
735        return this;
736    }
737
738    @Override
739    public VersionFilter getVersionFilter() {
740        return versionFilter;
741    }
742
743    /**
744     * Sets the version filter to use for building dependency graphs.
745     *
746     * @param versionFilter The version filter to use for building dependency graphs, may be {@code null} to not filter
747     *                      versions.
748     * @return This session for chaining, never {@code null}.
749     */
750    public DefaultRepositorySystemSession setVersionFilter(VersionFilter versionFilter) {
751        verifyStateForMutation();
752        this.versionFilter = versionFilter;
753        return this;
754    }
755
756    @Override
757    public DependencyGraphTransformer getDependencyGraphTransformer() {
758        return dependencyGraphTransformer;
759    }
760
761    /**
762     * Sets the dependency graph transformer to use for building dependency graphs.
763     *
764     * @param dependencyGraphTransformer The dependency graph transformer to use for building dependency graphs, may be
765     *                                   {@code null}.
766     * @return This session for chaining, never {@code null}.
767     */
768    public DefaultRepositorySystemSession setDependencyGraphTransformer(
769            DependencyGraphTransformer dependencyGraphTransformer) {
770        verifyStateForMutation();
771        this.dependencyGraphTransformer = dependencyGraphTransformer;
772        return this;
773    }
774
775    @Override
776    public SessionData getData() {
777        return data;
778    }
779
780    /**
781     * Sets the custom data associated with this session.
782     *
783     * @param data The session data, may be {@code null}.
784     * @return This session for chaining, never {@code null}.
785     */
786    public DefaultRepositorySystemSession setData(SessionData data) {
787        verifyStateForMutation();
788        this.data = data;
789        if (this.data == null) {
790            this.data = new DefaultSessionData();
791        }
792        return this;
793    }
794
795    @Override
796    public RepositoryCache getCache() {
797        return cache;
798    }
799
800    /**
801     * Sets the cache the repository system may use to save data for future reuse during the session.
802     *
803     * @param cache The repository cache, may be {@code null} if none.
804     * @return This session for chaining, never {@code null}.
805     */
806    public DefaultRepositorySystemSession setCache(RepositoryCache cache) {
807        verifyStateForMutation();
808        this.cache = cache;
809        return this;
810    }
811
812    @Override
813    public ScopeManager getScopeManager() {
814        return scopeManager;
815    }
816
817    /**
818     * Sets the scope manager, may be {@code null}.
819     *
820     * @param scopeManager The scope manager, may be {@code null}.
821     * @return The session for chaining, never {@code null}.
822     * @since 2.0.0
823     */
824    public DefaultRepositorySystemSession setScopeManager(ScopeManager scopeManager) {
825        verifyStateForMutation();
826        this.scopeManager = scopeManager;
827        return this;
828    }
829
830    @Override
831    public SystemDependencyScope getSystemDependencyScope() {
832        if (scopeManager != null) {
833            return scopeManager.getSystemDependencyScope().orElse(null);
834        } else {
835            return SystemDependencyScope.LEGACY;
836        }
837    }
838
839    @Override
840    public DependencyCollectionChecker getDependencyCollectionChecker() {
841        return dependencyCollectionChecker;
842    }
843
844    /**
845     * Sets the dependency collection checker, may be {@code null}.
846     *
847     * @param dependencyCollectionChecker The dependency collection checker, may be {@code null}.
848     * @return The session for chaining, never {@code null}.
849     * @since 2.0.19
850     */
851    public DefaultRepositorySystemSession setDependencyCollectionChecker(
852            DependencyCollectionChecker dependencyCollectionChecker) {
853        this.dependencyCollectionChecker = dependencyCollectionChecker;
854        return this;
855    }
856
857    /**
858     * Registers onSessionEnded handler, if able to.
859     *
860     * @param handler The handler to register
861     * @return Return {@code true} if registration was possible, otherwise {@code false}.
862     */
863    @Override
864    public boolean addOnSessionEndedHandler(Runnable handler) {
865        return onSessionEndedRegistrar.apply(handler);
866    }
867
868    /**
869     * Marks this session as read-only such that any future attempts to call its mutators will fail with an exception.
870     * Marking an already read-only session as read-only has no effect. The session's data and cache remain writable
871     * though.
872     */
873    public void setReadOnly() {
874        readOnly = true;
875    }
876
877    /**
878     * Verifies this instance state for mutation operations: mutated instance must not be read-only or closed.
879     */
880    private void verifyStateForMutation() {
881        if (readOnly) {
882            throw new IllegalStateException("repository system session is read-only");
883        }
884    }
885
886    /**
887     * Simple "pass through" implementation of {@link ProxySelector} that simply returns what passed in
888     * {@link RemoteRepository} have set already, may return {@code null}.
889     */
890    static class PassthroughProxySelector implements ProxySelector {
891
892        public static final ProxySelector INSTANCE = new PassthroughProxySelector();
893
894        @Override
895        public Proxy getProxy(RemoteRepository repository) {
896            requireNonNull(repository, "repository cannot be null");
897            return repository.getProxy();
898        }
899    }
900
901    /**
902     * Simple "null" implementation of {@link MirrorSelector} that returns {@code null} for any passed
903     * in {@link RemoteRepository}.
904     */
905    static class NullMirrorSelector implements MirrorSelector {
906
907        public static final MirrorSelector INSTANCE = new NullMirrorSelector();
908
909        @Override
910        public RemoteRepository getMirror(RemoteRepository repository) {
911            requireNonNull(repository, "repository cannot be null");
912            return null;
913        }
914    }
915
916    /**
917     * Simple "pass through" implementation of {@link AuthenticationSelector} that simply returns what passed in
918     * {@link RemoteRepository} have set already, may return {@code null}.
919     */
920    static class PassthroughAuthenticationSelector implements AuthenticationSelector {
921
922        public static final AuthenticationSelector INSTANCE = new PassthroughAuthenticationSelector();
923
924        @Override
925        public Authentication getAuthentication(RemoteRepository repository) {
926            requireNonNull(repository, "repository cannot be null");
927            return repository.getAuthentication();
928        }
929    }
930
931    /**
932     * Simple "null" implementation of {@link ArtifactTypeRegistry} that returns {@code null} for any type ID.
933     */
934    static final class NullArtifactTypeRegistry implements ArtifactTypeRegistry {
935
936        public static final ArtifactTypeRegistry INSTANCE = new NullArtifactTypeRegistry();
937
938        @Override
939        public ArtifactType get(String typeId) {
940            return null;
941        }
942    }
943}