View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether;
20  
21  import java.util.Collection;
22  import java.util.Collections;
23  import java.util.HashMap;
24  import java.util.Map;
25  
26  import org.eclipse.aether.artifact.Artifact;
27  import org.eclipse.aether.artifact.ArtifactType;
28  import org.eclipse.aether.artifact.ArtifactTypeRegistry;
29  import org.eclipse.aether.collection.DependencyGraphTransformer;
30  import org.eclipse.aether.collection.DependencyManager;
31  import org.eclipse.aether.collection.DependencySelector;
32  import org.eclipse.aether.collection.DependencyTraverser;
33  import org.eclipse.aether.collection.VersionFilter;
34  import org.eclipse.aether.repository.Authentication;
35  import org.eclipse.aether.repository.AuthenticationSelector;
36  import org.eclipse.aether.repository.LocalRepository;
37  import org.eclipse.aether.repository.LocalRepositoryManager;
38  import org.eclipse.aether.repository.MirrorSelector;
39  import org.eclipse.aether.repository.Proxy;
40  import org.eclipse.aether.repository.ProxySelector;
41  import org.eclipse.aether.repository.RemoteRepository;
42  import org.eclipse.aether.repository.RepositoryPolicy;
43  import org.eclipse.aether.repository.WorkspaceReader;
44  import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
45  import org.eclipse.aether.resolution.ResolutionErrorPolicy;
46  import org.eclipse.aether.transfer.TransferListener;
47  import org.eclipse.aether.transform.FileTransformer;
48  import org.eclipse.aether.transform.FileTransformerManager;
49  
50  import static java.util.Objects.requireNonNull;
51  
52  /**
53   * A simple repository system session.
54   * <p>
55   * <strong>Note:</strong> This class is not thread-safe. It is assumed that the mutators get only called during an
56   * initialization phase and that the session itself is not changed once initialized and being used by the repository
57   * system. It is recommended to call {@link #setReadOnly()} once the session has been fully initialized to prevent
58   * accidental manipulation of it afterwards.
59   */
60  public final class DefaultRepositorySystemSession implements RepositorySystemSession {
61  
62      private boolean readOnly;
63  
64      private boolean offline;
65  
66      private boolean ignoreArtifactDescriptorRepositories;
67  
68      private ResolutionErrorPolicy resolutionErrorPolicy;
69  
70      private ArtifactDescriptorPolicy artifactDescriptorPolicy;
71  
72      private String checksumPolicy;
73  
74      private String updatePolicy;
75  
76      private LocalRepositoryManager localRepositoryManager;
77  
78      private FileTransformerManager fileTransformerManager;
79  
80      private WorkspaceReader workspaceReader;
81  
82      private RepositoryListener repositoryListener;
83  
84      private TransferListener transferListener;
85  
86      private Map<String, String> systemProperties;
87  
88      private Map<String, String> systemPropertiesView;
89  
90      private Map<String, String> userProperties;
91  
92      private Map<String, String> userPropertiesView;
93  
94      private Map<String, Object> configProperties;
95  
96      private Map<String, Object> configPropertiesView;
97  
98      private MirrorSelector mirrorSelector;
99  
100     private ProxySelector proxySelector;
101 
102     private AuthenticationSelector authenticationSelector;
103 
104     private ArtifactTypeRegistry artifactTypeRegistry;
105 
106     private DependencyTraverser dependencyTraverser;
107 
108     private DependencyManager dependencyManager;
109 
110     private DependencySelector dependencySelector;
111 
112     private VersionFilter versionFilter;
113 
114     private DependencyGraphTransformer dependencyGraphTransformer;
115 
116     private SessionData data;
117 
118     private RepositoryCache cache;
119 
120     /**
121      * Creates an uninitialized session. <em>Note:</em> The new session is not ready to use, as a bare minimum,
122      * {@link #setLocalRepositoryManager(LocalRepositoryManager)} needs to be called but usually other settings also
123      * need to be customized to achieve meaningful behavior.
124      */
125     public DefaultRepositorySystemSession() {
126         systemProperties = new HashMap<>();
127         systemPropertiesView = Collections.unmodifiableMap(systemProperties);
128         userProperties = new HashMap<>();
129         userPropertiesView = Collections.unmodifiableMap(userProperties);
130         configProperties = new HashMap<>();
131         configPropertiesView = Collections.unmodifiableMap(configProperties);
132         mirrorSelector = NullMirrorSelector.INSTANCE;
133         proxySelector = NullProxySelector.INSTANCE;
134         authenticationSelector = NullAuthenticationSelector.INSTANCE;
135         artifactTypeRegistry = NullArtifactTypeRegistry.INSTANCE;
136         fileTransformerManager = NullFileTransformerManager.INSTANCE;
137         data = new DefaultSessionData();
138     }
139 
140     /**
141      * Creates a shallow copy of the specified session. Actually, the copy is not completely shallow, all maps holding
142      * system/user/config properties are copied as well. In other words, invoking any mutator on the new session itself
143      * has no effect on the original session. Other mutable objects like the session data and cache (if any) are not
144      * copied and will be shared with the original session unless reconfigured.
145      *
146      * @param session The session to copy, must not be {@code null}.
147      */
148     public DefaultRepositorySystemSession(RepositorySystemSession session) {
149         requireNonNull(session, "repository system session cannot be null");
150 
151         setOffline(session.isOffline());
152         setIgnoreArtifactDescriptorRepositories(session.isIgnoreArtifactDescriptorRepositories());
153         setResolutionErrorPolicy(session.getResolutionErrorPolicy());
154         setArtifactDescriptorPolicy(session.getArtifactDescriptorPolicy());
155         setChecksumPolicy(session.getChecksumPolicy());
156         setUpdatePolicy(session.getUpdatePolicy());
157         setLocalRepositoryManager(session.getLocalRepositoryManager());
158         setWorkspaceReader(session.getWorkspaceReader());
159         setRepositoryListener(session.getRepositoryListener());
160         setTransferListener(session.getTransferListener());
161         setSystemProperties(session.getSystemProperties());
162         setUserProperties(session.getUserProperties());
163         setConfigProperties(session.getConfigProperties());
164         setMirrorSelector(session.getMirrorSelector());
165         setProxySelector(session.getProxySelector());
166         setAuthenticationSelector(session.getAuthenticationSelector());
167         setArtifactTypeRegistry(session.getArtifactTypeRegistry());
168         setDependencyTraverser(session.getDependencyTraverser());
169         setDependencyManager(session.getDependencyManager());
170         setDependencySelector(session.getDependencySelector());
171         setVersionFilter(session.getVersionFilter());
172         setDependencyGraphTransformer(session.getDependencyGraphTransformer());
173         setFileTransformerManager(session.getFileTransformerManager());
174         setData(session.getData());
175         setCache(session.getCache());
176     }
177 
178     @Override
179     public boolean isOffline() {
180         return offline;
181     }
182 
183     /**
184      * Controls whether the repository system operates in offline mode and avoids/refuses any access to remote
185      * repositories.
186      *
187      * @param offline {@code true} if the repository system is in offline mode, {@code false} otherwise.
188      * @return This session for chaining, never {@code null}.
189      */
190     public DefaultRepositorySystemSession setOffline(boolean offline) {
191         verifyStateForMutation();
192         this.offline = offline;
193         return this;
194     }
195 
196     @Override
197     public boolean isIgnoreArtifactDescriptorRepositories() {
198         return ignoreArtifactDescriptorRepositories;
199     }
200 
201     /**
202      * Controls whether repositories declared in artifact descriptors should be ignored during transitive dependency
203      * collection. If enabled, only the repositories originally provided with the collect request will be considered.
204      *
205      * @param ignoreArtifactDescriptorRepositories {@code true} to ignore additional repositories from artifact
206      *                                             descriptors, {@code false} to merge those with the originally
207      *                                             specified repositories.
208      * @return This session for chaining, never {@code null}.
209      */
210     public DefaultRepositorySystemSession setIgnoreArtifactDescriptorRepositories(
211             boolean ignoreArtifactDescriptorRepositories) {
212         verifyStateForMutation();
213         this.ignoreArtifactDescriptorRepositories = ignoreArtifactDescriptorRepositories;
214         return this;
215     }
216 
217     @Override
218     public ResolutionErrorPolicy getResolutionErrorPolicy() {
219         return resolutionErrorPolicy;
220     }
221 
222     /**
223      * Sets the policy which controls whether resolutions errors from remote repositories should be cached.
224      *
225      * @param resolutionErrorPolicy The resolution error policy for this session, may be {@code null} if resolution
226      *                              errors should generally not be cached.
227      * @return This session for chaining, never {@code null}.
228      */
229     public DefaultRepositorySystemSession setResolutionErrorPolicy(ResolutionErrorPolicy resolutionErrorPolicy) {
230         verifyStateForMutation();
231         this.resolutionErrorPolicy = resolutionErrorPolicy;
232         return this;
233     }
234 
235     @Override
236     public ArtifactDescriptorPolicy getArtifactDescriptorPolicy() {
237         return artifactDescriptorPolicy;
238     }
239 
240     /**
241      * Sets the policy which controls how errors related to reading artifact descriptors should be handled.
242      *
243      * @param artifactDescriptorPolicy The descriptor error policy for this session, may be {@code null} if descriptor
244      *                                 errors should generally not be tolerated.
245      * @return This session for chaining, never {@code null}.
246      */
247     public DefaultRepositorySystemSession setArtifactDescriptorPolicy(
248             ArtifactDescriptorPolicy artifactDescriptorPolicy) {
249         verifyStateForMutation();
250         this.artifactDescriptorPolicy = artifactDescriptorPolicy;
251         return this;
252     }
253 
254     @Override
255     public String getChecksumPolicy() {
256         return checksumPolicy;
257     }
258 
259     /**
260      * Sets the global checksum policy. If set, the global checksum policy overrides the checksum policies of the remote
261      * repositories being used for resolution.
262      *
263      * @param checksumPolicy The global checksum policy, may be {@code null}/empty to apply the per-repository policies.
264      * @return This session for chaining, never {@code null}.
265      * @see RepositoryPolicy#CHECKSUM_POLICY_FAIL
266      * @see RepositoryPolicy#CHECKSUM_POLICY_IGNORE
267      * @see RepositoryPolicy#CHECKSUM_POLICY_WARN
268      */
269     public DefaultRepositorySystemSession setChecksumPolicy(String checksumPolicy) {
270         verifyStateForMutation();
271         this.checksumPolicy = checksumPolicy;
272         return this;
273     }
274 
275     @Override
276     public String getUpdatePolicy() {
277         return updatePolicy;
278     }
279 
280     /**
281      * Sets the global update policy. If set, the global update policy overrides the update policies of the remote
282      * repositories being used for resolution.
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      */
290     public DefaultRepositorySystemSession setUpdatePolicy(String updatePolicy) {
291         verifyStateForMutation();
292         this.updatePolicy = updatePolicy;
293         return this;
294     }
295 
296     @Override
297     public LocalRepository getLocalRepository() {
298         LocalRepositoryManager lrm = getLocalRepositoryManager();
299         return (lrm != null) ? lrm.getRepository() : null;
300     }
301 
302     public LocalRepositoryManager getLocalRepositoryManager() {
303         return localRepositoryManager;
304     }
305 
306     /**
307      * Sets the local repository manager used during this session. <em>Note:</em> Eventually, a valid session must have
308      * a local repository manager set.
309      *
310      * @param localRepositoryManager The local repository manager used during this session, may be {@code null}.
311      * @return This session for chaining, never {@code null}.
312      */
313     public DefaultRepositorySystemSession setLocalRepositoryManager(LocalRepositoryManager localRepositoryManager) {
314         verifyStateForMutation();
315         this.localRepositoryManager = localRepositoryManager;
316         return this;
317     }
318 
319     @Override
320     public FileTransformerManager getFileTransformerManager() {
321         return fileTransformerManager;
322     }
323 
324     public DefaultRepositorySystemSession setFileTransformerManager(FileTransformerManager fileTransformerManager) {
325         verifyStateForMutation();
326         this.fileTransformerManager = fileTransformerManager;
327         if (this.fileTransformerManager == null) {
328             this.fileTransformerManager = NullFileTransformerManager.INSTANCE;
329         }
330         return this;
331     }
332 
333     @Override
334     public WorkspaceReader getWorkspaceReader() {
335         return workspaceReader;
336     }
337 
338     /**
339      * Sets the workspace reader used during this session. If set, the workspace reader will usually be consulted first
340      * to resolve artifacts.
341      *
342      * @param workspaceReader The workspace reader for this session, may be {@code null} if none.
343      * @return This session for chaining, never {@code null}.
344      */
345     public DefaultRepositorySystemSession setWorkspaceReader(WorkspaceReader workspaceReader) {
346         verifyStateForMutation();
347         this.workspaceReader = workspaceReader;
348         return this;
349     }
350 
351     @Override
352     public RepositoryListener getRepositoryListener() {
353         return repositoryListener;
354     }
355 
356     /**
357      * Sets the listener being notified of actions in the repository system.
358      *
359      * @param repositoryListener The repository listener, may be {@code null} if none.
360      * @return This session for chaining, never {@code null}.
361      */
362     public DefaultRepositorySystemSession setRepositoryListener(RepositoryListener repositoryListener) {
363         verifyStateForMutation();
364         this.repositoryListener = repositoryListener;
365         return this;
366     }
367 
368     @Override
369     public TransferListener getTransferListener() {
370         return transferListener;
371     }
372 
373     /**
374      * Sets the listener being notified of uploads/downloads by the repository system.
375      *
376      * @param transferListener The transfer listener, may be {@code null} if none.
377      * @return This session for chaining, never {@code null}.
378      */
379     public DefaultRepositorySystemSession setTransferListener(TransferListener transferListener) {
380         verifyStateForMutation();
381         this.transferListener = transferListener;
382         return this;
383     }
384 
385     private <T> Map<String, T> copySafe(Map<?, ?> table, Class<T> valueType) {
386         Map<String, T> map;
387         if (table == null || table.isEmpty()) {
388             map = new HashMap<>();
389         } else {
390             map = new HashMap<>((int) (table.size() / 0.75f) + 1);
391             for (Map.Entry<?, ?> entry : table.entrySet()) {
392                 Object key = entry.getKey();
393                 if (key instanceof String) {
394                     Object value = entry.getValue();
395                     if (valueType.isInstance(value)) {
396                         map.put(key.toString(), valueType.cast(value));
397                     }
398                 }
399             }
400         }
401         return map;
402     }
403 
404     @Override
405     public Map<String, String> getSystemProperties() {
406         return systemPropertiesView;
407     }
408 
409     /**
410      * Sets the system properties to use, e.g. for processing of artifact descriptors. System properties are usually
411      * collected from the runtime environment like {@link System#getProperties()} and environment variables.
412      * <p>
413      * <em>Note:</em> System properties are of type {@code Map<String, String>} and any key-value pair in the input map
414      * that doesn't match this type will be silently ignored.
415      *
416      * @param systemProperties The system properties, may be {@code null} or empty if none.
417      * @return This session for chaining, never {@code null}.
418      */
419     public DefaultRepositorySystemSession setSystemProperties(Map<?, ?> systemProperties) {
420         verifyStateForMutation();
421         this.systemProperties = copySafe(systemProperties, String.class);
422         systemPropertiesView = Collections.unmodifiableMap(this.systemProperties);
423         return this;
424     }
425 
426     /**
427      * Sets the specified system property.
428      *
429      * @param key   The property key, must not be {@code null}.
430      * @param value The property value, may be {@code null} to remove/unset the property.
431      * @return This session for chaining, never {@code null}.
432      */
433     public DefaultRepositorySystemSession setSystemProperty(String key, String value) {
434         verifyStateForMutation();
435         if (value != null) {
436             systemProperties.put(key, value);
437         } else {
438             systemProperties.remove(key);
439         }
440         return this;
441     }
442 
443     @Override
444     public Map<String, String> getUserProperties() {
445         return userPropertiesView;
446     }
447 
448     /**
449      * Sets the user properties to use, e.g. for processing of artifact descriptors. User properties are similar to
450      * system properties but are set on the discretion of the user and hence are considered of higher priority than
451      * system properties in case of conflicts.
452      * <p>
453      * <em>Note:</em> User properties are of type {@code Map<String, String>} and any key-value pair in the input map
454      * that doesn't match this type will be silently ignored.
455      *
456      * @param userProperties The user properties, may be {@code null} or empty if none.
457      * @return This session for chaining, never {@code null}.
458      */
459     public DefaultRepositorySystemSession setUserProperties(Map<?, ?> userProperties) {
460         verifyStateForMutation();
461         this.userProperties = copySafe(userProperties, String.class);
462         userPropertiesView = Collections.unmodifiableMap(this.userProperties);
463         return this;
464     }
465 
466     /**
467      * Sets the specified user property.
468      *
469      * @param key   The property key, must not be {@code null}.
470      * @param value The property value, may be {@code null} to remove/unset the property.
471      * @return This session for chaining, never {@code null}.
472      */
473     public DefaultRepositorySystemSession setUserProperty(String key, String value) {
474         verifyStateForMutation();
475         if (value != null) {
476             userProperties.put(key, value);
477         } else {
478             userProperties.remove(key);
479         }
480         return this;
481     }
482 
483     @Override
484     public Map<String, Object> getConfigProperties() {
485         return configPropertiesView;
486     }
487 
488     /**
489      * Sets the configuration properties used to tweak internal aspects of the repository system (e.g. thread pooling,
490      * connector-specific behavior, etc.).
491      * <p>
492      * <em>Note:</em> Configuration properties are of type {@code Map<String, Object>} and any key-value pair in the
493      * input map that doesn't match this type will be silently ignored.
494      *
495      * @param configProperties The configuration properties, may be {@code null} or empty if none.
496      * @return This session for chaining, never {@code null}.
497      */
498     public DefaultRepositorySystemSession setConfigProperties(Map<?, ?> configProperties) {
499         verifyStateForMutation();
500         this.configProperties = copySafe(configProperties, Object.class);
501         configPropertiesView = Collections.unmodifiableMap(this.configProperties);
502         return this;
503     }
504 
505     /**
506      * Sets the specified configuration property.
507      *
508      * @param key   The property key, must not be {@code null}.
509      * @param value The property value, may be {@code null} to remove/unset the property.
510      * @return This session for chaining, never {@code null}.
511      */
512     public DefaultRepositorySystemSession setConfigProperty(String key, Object value) {
513         verifyStateForMutation();
514         if (value != null) {
515             configProperties.put(key, value);
516         } else {
517             configProperties.remove(key);
518         }
519         return this;
520     }
521 
522     @Override
523     public MirrorSelector getMirrorSelector() {
524         return mirrorSelector;
525     }
526 
527     /**
528      * Sets the mirror selector to use for repositories discovered in artifact descriptors. Note that this selector is
529      * not used for remote repositories which are passed as request parameters to the repository system, those
530      * repositories are supposed to denote the effective repositories.
531      *
532      * @param mirrorSelector The mirror selector to use, may be {@code null}.
533      * @return This session for chaining, never {@code null}.
534      */
535     public DefaultRepositorySystemSession setMirrorSelector(MirrorSelector mirrorSelector) {
536         verifyStateForMutation();
537         this.mirrorSelector = mirrorSelector;
538         if (this.mirrorSelector == null) {
539             this.mirrorSelector = NullMirrorSelector.INSTANCE;
540         }
541         return this;
542     }
543 
544     @Override
545     public ProxySelector getProxySelector() {
546         return proxySelector;
547     }
548 
549     /**
550      * Sets the proxy selector to use for repositories discovered in artifact descriptors. Note that this selector is
551      * not used for remote repositories which are passed as request parameters to the repository system, those
552      * repositories are supposed to have their proxy (if any) already set.
553      *
554      * @param proxySelector The proxy selector to use, may be {@code null}.
555      * @return This session for chaining, never {@code null}.
556      * @see org.eclipse.aether.repository.RemoteRepository#getProxy()
557      */
558     public DefaultRepositorySystemSession setProxySelector(ProxySelector proxySelector) {
559         verifyStateForMutation();
560         this.proxySelector = proxySelector;
561         if (this.proxySelector == null) {
562             this.proxySelector = NullProxySelector.INSTANCE;
563         }
564         return this;
565     }
566 
567     @Override
568     public AuthenticationSelector getAuthenticationSelector() {
569         return authenticationSelector;
570     }
571 
572     /**
573      * Sets the authentication selector to use for repositories discovered in artifact descriptors. Note that this
574      * selector is not used for remote repositories which are passed as request parameters to the repository system,
575      * those repositories are supposed to have their authentication (if any) already set.
576      *
577      * @param authenticationSelector The authentication selector to use, may be {@code null}.
578      * @return This session for chaining, never {@code null}.
579      * @see org.eclipse.aether.repository.RemoteRepository#getAuthentication()
580      */
581     public DefaultRepositorySystemSession setAuthenticationSelector(AuthenticationSelector authenticationSelector) {
582         verifyStateForMutation();
583         this.authenticationSelector = authenticationSelector;
584         if (this.authenticationSelector == null) {
585             this.authenticationSelector = NullAuthenticationSelector.INSTANCE;
586         }
587         return this;
588     }
589 
590     @Override
591     public ArtifactTypeRegistry getArtifactTypeRegistry() {
592         return artifactTypeRegistry;
593     }
594 
595     /**
596      * Sets the registry of artifact types recognized by this session.
597      *
598      * @param artifactTypeRegistry The artifact type registry, may be {@code null}.
599      * @return This session for chaining, never {@code null}.
600      */
601     public DefaultRepositorySystemSession setArtifactTypeRegistry(ArtifactTypeRegistry artifactTypeRegistry) {
602         verifyStateForMutation();
603         this.artifactTypeRegistry = artifactTypeRegistry;
604         if (this.artifactTypeRegistry == null) {
605             this.artifactTypeRegistry = NullArtifactTypeRegistry.INSTANCE;
606         }
607         return this;
608     }
609 
610     @Override
611     public DependencyTraverser getDependencyTraverser() {
612         return dependencyTraverser;
613     }
614 
615     /**
616      * Sets the dependency traverser to use for building dependency graphs.
617      *
618      * @param dependencyTraverser The dependency traverser to use for building dependency graphs, may be {@code null}.
619      * @return This session for chaining, never {@code null}.
620      */
621     public DefaultRepositorySystemSession setDependencyTraverser(DependencyTraverser dependencyTraverser) {
622         verifyStateForMutation();
623         this.dependencyTraverser = dependencyTraverser;
624         return this;
625     }
626 
627     @Override
628     public DependencyManager getDependencyManager() {
629         return dependencyManager;
630     }
631 
632     /**
633      * Sets the dependency manager to use for building dependency graphs.
634      *
635      * @param dependencyManager The dependency manager to use for building dependency graphs, may be {@code null}.
636      * @return This session for chaining, never {@code null}.
637      */
638     public DefaultRepositorySystemSession setDependencyManager(DependencyManager dependencyManager) {
639         verifyStateForMutation();
640         this.dependencyManager = dependencyManager;
641         return this;
642     }
643 
644     @Override
645     public DependencySelector getDependencySelector() {
646         return dependencySelector;
647     }
648 
649     /**
650      * Sets the dependency selector to use for building dependency graphs.
651      *
652      * @param dependencySelector The dependency selector to use for building dependency graphs, may be {@code null}.
653      * @return This session for chaining, never {@code null}.
654      */
655     public DefaultRepositorySystemSession setDependencySelector(DependencySelector dependencySelector) {
656         verifyStateForMutation();
657         this.dependencySelector = dependencySelector;
658         return this;
659     }
660 
661     @Override
662     public VersionFilter getVersionFilter() {
663         return versionFilter;
664     }
665 
666     /**
667      * Sets the version filter to use for building dependency graphs.
668      *
669      * @param versionFilter The version filter to use for building dependency graphs, may be {@code null} to not filter
670      *                      versions.
671      * @return This session for chaining, never {@code null}.
672      */
673     public DefaultRepositorySystemSession setVersionFilter(VersionFilter versionFilter) {
674         verifyStateForMutation();
675         this.versionFilter = versionFilter;
676         return this;
677     }
678 
679     @Override
680     public DependencyGraphTransformer getDependencyGraphTransformer() {
681         return dependencyGraphTransformer;
682     }
683 
684     /**
685      * Sets the dependency graph transformer to use for building dependency graphs.
686      *
687      * @param dependencyGraphTransformer The dependency graph transformer to use for building dependency graphs, may be
688      *                                   {@code null}.
689      * @return This session for chaining, never {@code null}.
690      */
691     public DefaultRepositorySystemSession setDependencyGraphTransformer(
692             DependencyGraphTransformer dependencyGraphTransformer) {
693         verifyStateForMutation();
694         this.dependencyGraphTransformer = dependencyGraphTransformer;
695         return this;
696     }
697 
698     @Override
699     public SessionData getData() {
700         return data;
701     }
702 
703     /**
704      * Sets the custom data associated with this session.
705      *
706      * @param data The session data, may be {@code null}.
707      * @return This session for chaining, never {@code null}.
708      */
709     public DefaultRepositorySystemSession setData(SessionData data) {
710         verifyStateForMutation();
711         this.data = data;
712         if (this.data == null) {
713             this.data = new DefaultSessionData();
714         }
715         return this;
716     }
717 
718     @Override
719     public RepositoryCache getCache() {
720         return cache;
721     }
722 
723     /**
724      * Sets the cache the repository system may use to save data for future reuse during the session.
725      *
726      * @param cache The repository cache, may be {@code null} if none.
727      * @return This session for chaining, never {@code null}.
728      */
729     public DefaultRepositorySystemSession setCache(RepositoryCache cache) {
730         verifyStateForMutation();
731         this.cache = cache;
732         return this;
733     }
734 
735     /**
736      * Marks this session as read-only such that any future attempts to call its mutators will fail with an exception.
737      * Marking an already read-only session as read-only has no effect. The session's data and cache remain writable
738      * though.
739      */
740     public void setReadOnly() {
741         readOnly = true;
742     }
743 
744     /**
745      * Verifies this instance state for mutation operations: mutated instance must not be read-only or closed.
746      */
747     private void verifyStateForMutation() {
748         if (readOnly) {
749             throw new IllegalStateException("repository system session is read-only");
750         }
751     }
752 
753     static class NullProxySelector implements ProxySelector {
754 
755         public static final ProxySelector INSTANCE = new NullProxySelector();
756 
757         public Proxy getProxy(RemoteRepository repository) {
758             requireNonNull(repository, "repository cannot be null");
759             return repository.getProxy();
760         }
761     }
762 
763     static class NullMirrorSelector implements MirrorSelector {
764 
765         public static final MirrorSelector INSTANCE = new NullMirrorSelector();
766 
767         public RemoteRepository getMirror(RemoteRepository repository) {
768             requireNonNull(repository, "repository cannot be null");
769             return null;
770         }
771     }
772 
773     static class NullAuthenticationSelector implements AuthenticationSelector {
774 
775         public static final AuthenticationSelector INSTANCE = new NullAuthenticationSelector();
776 
777         public Authentication getAuthentication(RemoteRepository repository) {
778             requireNonNull(repository, "repository cannot be null");
779             return repository.getAuthentication();
780         }
781     }
782 
783     static final class NullArtifactTypeRegistry implements ArtifactTypeRegistry {
784 
785         public static final ArtifactTypeRegistry INSTANCE = new NullArtifactTypeRegistry();
786 
787         public ArtifactType get(String typeId) {
788             return null;
789         }
790     }
791 
792     static final class NullFileTransformerManager implements FileTransformerManager {
793         public static final FileTransformerManager INSTANCE = new NullFileTransformerManager();
794 
795         @Override
796         public Collection<FileTransformer> getTransformersForArtifact(Artifact artifact) {
797             return Collections.emptyList();
798         }
799     }
800 }