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