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.Collections;
22  import java.util.HashMap;
23  import java.util.Map;
24  
25  import org.eclipse.aether.artifact.ArtifactType;
26  import org.eclipse.aether.artifact.ArtifactTypeRegistry;
27  import org.eclipse.aether.collection.DependencyGraphTransformer;
28  import org.eclipse.aether.collection.DependencyManager;
29  import org.eclipse.aether.collection.DependencySelector;
30  import org.eclipse.aether.collection.DependencyTraverser;
31  import org.eclipse.aether.collection.VersionFilter;
32  import org.eclipse.aether.repository.Authentication;
33  import org.eclipse.aether.repository.AuthenticationSelector;
34  import org.eclipse.aether.repository.LocalRepository;
35  import org.eclipse.aether.repository.LocalRepositoryManager;
36  import org.eclipse.aether.repository.MirrorSelector;
37  import org.eclipse.aether.repository.Proxy;
38  import org.eclipse.aether.repository.ProxySelector;
39  import org.eclipse.aether.repository.RemoteRepository;
40  import org.eclipse.aether.repository.RepositoryPolicy;
41  import org.eclipse.aether.repository.WorkspaceReader;
42  import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
43  import org.eclipse.aether.resolution.ResolutionErrorPolicy;
44  import org.eclipse.aether.transfer.TransferListener;
45  
46  import static java.util.Objects.requireNonNull;
47  
48  /**
49   * A simple repository system session.
50   * <p>
51   * <strong>Note:</strong> This class is not thread-safe. It is assumed that the mutators get only called during an
52   * initialization phase and that the session itself is not changed once initialized and being used by the repository
53   * system. It is recommended to call {@link #setReadOnly()} once the session has been fully initialized to prevent
54   * accidental manipulation of it afterwards.
55   */
56  public final class DefaultRepositorySystemSession implements RepositorySystemSession {
57  
58      private boolean readOnly;
59  
60      private boolean offline;
61  
62      private boolean ignoreArtifactDescriptorRepositories;
63  
64      private ResolutionErrorPolicy resolutionErrorPolicy;
65  
66      private ArtifactDescriptorPolicy artifactDescriptorPolicy;
67  
68      private String checksumPolicy;
69  
70      private String artifactUpdatePolicy;
71  
72      private String metadataUpdatePolicy;
73  
74      private LocalRepositoryManager localRepositoryManager;
75  
76      private WorkspaceReader workspaceReader;
77  
78      private RepositoryListener repositoryListener;
79  
80      private TransferListener transferListener;
81  
82      private Map<String, String> systemProperties;
83  
84      private Map<String, String> systemPropertiesView;
85  
86      private Map<String, String> userProperties;
87  
88      private Map<String, String> userPropertiesView;
89  
90      private Map<String, Object> configProperties;
91  
92      private Map<String, Object> configPropertiesView;
93  
94      private MirrorSelector mirrorSelector;
95  
96      private ProxySelector proxySelector;
97  
98      private AuthenticationSelector authenticationSelector;
99  
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 }