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     @SuppressWarnings("checkstyle:magicnumber")
386     private <T> Map<String, T> copySafe(Map<?, ?> table, Class<T> valueType) {
387         Map<String, T> map;
388         if (table == null || table.isEmpty()) {
389             map = new HashMap<>();
390         } else {
391             map = new HashMap<>((int) (table.size() / 0.75f) + 1);
392             for (Map.Entry<?, ?> entry : table.entrySet()) {
393                 Object key = entry.getKey();
394                 if (key instanceof String) {
395                     Object value = entry.getValue();
396                     if (valueType.isInstance(value)) {
397                         map.put(key.toString(), valueType.cast(value));
398                     }
399                 }
400             }
401         }
402         return map;
403     }
404 
405     @Override
406     public Map<String, String> getSystemProperties() {
407         return systemPropertiesView;
408     }
409 
410     /**
411      * Sets the system properties to use, e.g. for processing of artifact descriptors. System properties are usually
412      * collected from the runtime environment like {@link System#getProperties()} and environment variables.
413      * <p>
414      * <em>Note:</em> System properties are of type {@code Map<String, String>} and any key-value pair in the input map
415      * that doesn't match this type will be silently ignored.
416      *
417      * @param systemProperties The system properties, may be {@code null} or empty if none.
418      * @return This session for chaining, never {@code null}.
419      */
420     public DefaultRepositorySystemSession setSystemProperties(Map<?, ?> systemProperties) {
421         verifyStateForMutation();
422         this.systemProperties = copySafe(systemProperties, String.class);
423         systemPropertiesView = Collections.unmodifiableMap(this.systemProperties);
424         return this;
425     }
426 
427     /**
428      * Sets the specified system property.
429      *
430      * @param key   The property key, must not be {@code null}.
431      * @param value The property value, may be {@code null} to remove/unset the property.
432      * @return This session for chaining, never {@code null}.
433      */
434     public DefaultRepositorySystemSession setSystemProperty(String key, String value) {
435         verifyStateForMutation();
436         if (value != null) {
437             systemProperties.put(key, value);
438         } else {
439             systemProperties.remove(key);
440         }
441         return this;
442     }
443 
444     @Override
445     public Map<String, String> getUserProperties() {
446         return userPropertiesView;
447     }
448 
449     /**
450      * Sets the user properties to use, e.g. for processing of artifact descriptors. User properties are similar to
451      * system properties but are set on the discretion of the user and hence are considered of higher priority than
452      * system properties in case of conflicts.
453      * <p>
454      * <em>Note:</em> User properties are of type {@code Map<String, String>} and any key-value pair in the input map
455      * that doesn't match this type will be silently ignored.
456      *
457      * @param userProperties The user properties, may be {@code null} or empty if none.
458      * @return This session for chaining, never {@code null}.
459      */
460     public DefaultRepositorySystemSession setUserProperties(Map<?, ?> userProperties) {
461         verifyStateForMutation();
462         this.userProperties = copySafe(userProperties, String.class);
463         userPropertiesView = Collections.unmodifiableMap(this.userProperties);
464         return this;
465     }
466 
467     /**
468      * Sets the specified user property.
469      *
470      * @param key   The property key, must not be {@code null}.
471      * @param value The property value, may be {@code null} to remove/unset the property.
472      * @return This session for chaining, never {@code null}.
473      */
474     public DefaultRepositorySystemSession setUserProperty(String key, String value) {
475         verifyStateForMutation();
476         if (value != null) {
477             userProperties.put(key, value);
478         } else {
479             userProperties.remove(key);
480         }
481         return this;
482     }
483 
484     @Override
485     public Map<String, Object> getConfigProperties() {
486         return configPropertiesView;
487     }
488 
489     /**
490      * Sets the configuration properties used to tweak internal aspects of the repository system (e.g. thread pooling,
491      * connector-specific behavior, etc.).
492      * <p>
493      * <em>Note:</em> Configuration properties are of type {@code Map<String, Object>} and any key-value pair in the
494      * input map that doesn't match this type will be silently ignored.
495      *
496      * @param configProperties The configuration properties, may be {@code null} or empty if none.
497      * @return This session for chaining, never {@code null}.
498      */
499     public DefaultRepositorySystemSession setConfigProperties(Map<?, ?> configProperties) {
500         verifyStateForMutation();
501         this.configProperties = copySafe(configProperties, Object.class);
502         configPropertiesView = Collections.unmodifiableMap(this.configProperties);
503         return this;
504     }
505 
506     /**
507      * Sets the specified configuration property.
508      *
509      * @param key   The property key, must not be {@code null}.
510      * @param value The property value, may be {@code null} to remove/unset the property.
511      * @return This session for chaining, never {@code null}.
512      */
513     public DefaultRepositorySystemSession setConfigProperty(String key, Object value) {
514         verifyStateForMutation();
515         if (value != null) {
516             configProperties.put(key, value);
517         } else {
518             configProperties.remove(key);
519         }
520         return this;
521     }
522 
523     @Override
524     public MirrorSelector getMirrorSelector() {
525         return mirrorSelector;
526     }
527 
528     /**
529      * Sets the mirror selector to use for repositories discovered in artifact descriptors. Note that this selector is
530      * not used for remote repositories which are passed as request parameters to the repository system, those
531      * repositories are supposed to denote the effective repositories.
532      *
533      * @param mirrorSelector The mirror selector to use, may be {@code null}.
534      * @return This session for chaining, never {@code null}.
535      */
536     public DefaultRepositorySystemSession setMirrorSelector(MirrorSelector mirrorSelector) {
537         verifyStateForMutation();
538         this.mirrorSelector = mirrorSelector;
539         if (this.mirrorSelector == null) {
540             this.mirrorSelector = NullMirrorSelector.INSTANCE;
541         }
542         return this;
543     }
544 
545     @Override
546     public ProxySelector getProxySelector() {
547         return proxySelector;
548     }
549 
550     /**
551      * Sets the proxy selector to use for repositories discovered in artifact descriptors. Note that this selector is
552      * not used for remote repositories which are passed as request parameters to the repository system, those
553      * repositories are supposed to have their proxy (if any) already set.
554      *
555      * @param proxySelector The proxy selector to use, may be {@code null}.
556      * @return This session for chaining, never {@code null}.
557      * @see org.eclipse.aether.repository.RemoteRepository#getProxy()
558      */
559     public DefaultRepositorySystemSession setProxySelector(ProxySelector proxySelector) {
560         verifyStateForMutation();
561         this.proxySelector = proxySelector;
562         if (this.proxySelector == null) {
563             this.proxySelector = NullProxySelector.INSTANCE;
564         }
565         return this;
566     }
567 
568     @Override
569     public AuthenticationSelector getAuthenticationSelector() {
570         return authenticationSelector;
571     }
572 
573     /**
574      * Sets the authentication selector to use for repositories discovered in artifact descriptors. Note that this
575      * selector is not used for remote repositories which are passed as request parameters to the repository system,
576      * those repositories are supposed to have their authentication (if any) already set.
577      *
578      * @param authenticationSelector The authentication selector to use, may be {@code null}.
579      * @return This session for chaining, never {@code null}.
580      * @see org.eclipse.aether.repository.RemoteRepository#getAuthentication()
581      */
582     public DefaultRepositorySystemSession setAuthenticationSelector(AuthenticationSelector authenticationSelector) {
583         verifyStateForMutation();
584         this.authenticationSelector = authenticationSelector;
585         if (this.authenticationSelector == null) {
586             this.authenticationSelector = NullAuthenticationSelector.INSTANCE;
587         }
588         return this;
589     }
590 
591     @Override
592     public ArtifactTypeRegistry getArtifactTypeRegistry() {
593         return artifactTypeRegistry;
594     }
595 
596     /**
597      * Sets the registry of artifact types recognized by this session.
598      *
599      * @param artifactTypeRegistry The artifact type registry, may be {@code null}.
600      * @return This session for chaining, never {@code null}.
601      */
602     public DefaultRepositorySystemSession setArtifactTypeRegistry(ArtifactTypeRegistry artifactTypeRegistry) {
603         verifyStateForMutation();
604         this.artifactTypeRegistry = artifactTypeRegistry;
605         if (this.artifactTypeRegistry == null) {
606             this.artifactTypeRegistry = NullArtifactTypeRegistry.INSTANCE;
607         }
608         return this;
609     }
610 
611     @Override
612     public DependencyTraverser getDependencyTraverser() {
613         return dependencyTraverser;
614     }
615 
616     /**
617      * Sets the dependency traverser to use for building dependency graphs.
618      *
619      * @param dependencyTraverser The dependency traverser to use for building dependency graphs, may be {@code null}.
620      * @return This session for chaining, never {@code null}.
621      */
622     public DefaultRepositorySystemSession setDependencyTraverser(DependencyTraverser dependencyTraverser) {
623         verifyStateForMutation();
624         this.dependencyTraverser = dependencyTraverser;
625         return this;
626     }
627 
628     @Override
629     public DependencyManager getDependencyManager() {
630         return dependencyManager;
631     }
632 
633     /**
634      * Sets the dependency manager to use for building dependency graphs.
635      *
636      * @param dependencyManager The dependency manager to use for building dependency graphs, may be {@code null}.
637      * @return This session for chaining, never {@code null}.
638      */
639     public DefaultRepositorySystemSession setDependencyManager(DependencyManager dependencyManager) {
640         verifyStateForMutation();
641         this.dependencyManager = dependencyManager;
642         return this;
643     }
644 
645     @Override
646     public DependencySelector getDependencySelector() {
647         return dependencySelector;
648     }
649 
650     /**
651      * Sets the dependency selector to use for building dependency graphs.
652      *
653      * @param dependencySelector The dependency selector to use for building dependency graphs, may be {@code null}.
654      * @return This session for chaining, never {@code null}.
655      */
656     public DefaultRepositorySystemSession setDependencySelector(DependencySelector dependencySelector) {
657         verifyStateForMutation();
658         this.dependencySelector = dependencySelector;
659         return this;
660     }
661 
662     @Override
663     public VersionFilter getVersionFilter() {
664         return versionFilter;
665     }
666 
667     /**
668      * Sets the version filter to use for building dependency graphs.
669      *
670      * @param versionFilter The version filter to use for building dependency graphs, may be {@code null} to not filter
671      *                      versions.
672      * @return This session for chaining, never {@code null}.
673      */
674     public DefaultRepositorySystemSession setVersionFilter(VersionFilter versionFilter) {
675         verifyStateForMutation();
676         this.versionFilter = versionFilter;
677         return this;
678     }
679 
680     @Override
681     public DependencyGraphTransformer getDependencyGraphTransformer() {
682         return dependencyGraphTransformer;
683     }
684 
685     /**
686      * Sets the dependency graph transformer to use for building dependency graphs.
687      *
688      * @param dependencyGraphTransformer The dependency graph transformer to use for building dependency graphs, may be
689      *                                   {@code null}.
690      * @return This session for chaining, never {@code null}.
691      */
692     public DefaultRepositorySystemSession setDependencyGraphTransformer(
693             DependencyGraphTransformer dependencyGraphTransformer) {
694         verifyStateForMutation();
695         this.dependencyGraphTransformer = dependencyGraphTransformer;
696         return this;
697     }
698 
699     @Override
700     public SessionData getData() {
701         return data;
702     }
703 
704     /**
705      * Sets the custom data associated with this session.
706      *
707      * @param data The session data, may be {@code null}.
708      * @return This session for chaining, never {@code null}.
709      */
710     public DefaultRepositorySystemSession setData(SessionData data) {
711         verifyStateForMutation();
712         this.data = data;
713         if (this.data == null) {
714             this.data = new DefaultSessionData();
715         }
716         return this;
717     }
718 
719     @Override
720     public RepositoryCache getCache() {
721         return cache;
722     }
723 
724     /**
725      * Sets the cache the repository system may use to save data for future reuse during the session.
726      *
727      * @param cache The repository cache, may be {@code null} if none.
728      * @return This session for chaining, never {@code null}.
729      */
730     public DefaultRepositorySystemSession setCache(RepositoryCache cache) {
731         verifyStateForMutation();
732         this.cache = cache;
733         return this;
734     }
735 
736     /**
737      * Marks this session as read-only such that any future attempts to call its mutators will fail with an exception.
738      * Marking an already read-only session as read-only has no effect. The session's data and cache remain writable
739      * though.
740      */
741     public void setReadOnly() {
742         readOnly = true;
743     }
744 
745     /**
746      * Verifies this instance state for mutation operations: mutated instance must not be read-only or closed.
747      */
748     private void verifyStateForMutation() {
749         if (readOnly) {
750             throw new IllegalStateException("repository system session is read-only");
751         }
752     }
753 
754     static class NullProxySelector implements ProxySelector {
755 
756         public static final ProxySelector INSTANCE = new NullProxySelector();
757 
758         public Proxy getProxy(RemoteRepository repository) {
759             requireNonNull(repository, "repository cannot be null");
760             return repository.getProxy();
761         }
762     }
763 
764     static class NullMirrorSelector implements MirrorSelector {
765 
766         public static final MirrorSelector INSTANCE = new NullMirrorSelector();
767 
768         public RemoteRepository getMirror(RemoteRepository repository) {
769             requireNonNull(repository, "repository cannot be null");
770             return null;
771         }
772     }
773 
774     static class NullAuthenticationSelector implements AuthenticationSelector {
775 
776         public static final AuthenticationSelector INSTANCE = new NullAuthenticationSelector();
777 
778         public Authentication getAuthentication(RemoteRepository repository) {
779             requireNonNull(repository, "repository cannot be null");
780             return repository.getAuthentication();
781         }
782     }
783 
784     static final class NullArtifactTypeRegistry implements ArtifactTypeRegistry {
785 
786         public static final ArtifactTypeRegistry INSTANCE = new NullArtifactTypeRegistry();
787 
788         public ArtifactType get(String typeId) {
789             return null;
790         }
791     }
792 
793     static final class NullFileTransformerManager implements FileTransformerManager {
794         public static final FileTransformerManager INSTANCE = new NullFileTransformerManager();
795 
796         @Override
797         public Collection<FileTransformer> getTransformersForArtifact(Artifact artifact) {
798             return Collections.emptyList();
799         }
800     }
801 }