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