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