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