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