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