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