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