001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.eclipse.aether.internal.test.util;
020
021import java.util.Collections;
022import java.util.HashMap;
023import java.util.Map;
024import java.util.function.Consumer;
025import java.util.function.Function;
026
027import org.eclipse.aether.*;
028import org.eclipse.aether.artifact.ArtifactType;
029import org.eclipse.aether.artifact.ArtifactTypeRegistry;
030import org.eclipse.aether.collection.*;
031import org.eclipse.aether.repository.*;
032import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
033import org.eclipse.aether.resolution.ResolutionErrorPolicy;
034import org.eclipse.aether.transfer.TransferListener;
035
036import static java.util.Objects.requireNonNull;
037
038/**
039 * Test utility to create root sessions.
040 */
041public final class TestRepositorySystemSession implements RepositorySystemSession {
042    private boolean readOnly;
043
044    private boolean offline;
045
046    private boolean ignoreArtifactDescriptorRepositories;
047
048    private ResolutionErrorPolicy resolutionErrorPolicy;
049
050    private ArtifactDescriptorPolicy artifactDescriptorPolicy;
051
052    private String checksumPolicy;
053
054    private String artifactUpdatePolicy;
055
056    private String metadataUpdatePolicy;
057
058    private LocalRepositoryManager localRepositoryManager;
059
060    private WorkspaceReader workspaceReader;
061
062    private RepositoryListener repositoryListener;
063
064    private TransferListener transferListener;
065
066    private Map<String, String> systemProperties;
067
068    private Map<String, String> systemPropertiesView;
069
070    private Map<String, String> userProperties;
071
072    private Map<String, String> userPropertiesView;
073
074    private Map<String, Object> configProperties;
075
076    private Map<String, Object> configPropertiesView;
077
078    private MirrorSelector mirrorSelector;
079
080    private ProxySelector proxySelector;
081
082    private AuthenticationSelector authenticationSelector;
083
084    private ArtifactTypeRegistry artifactTypeRegistry;
085
086    private DependencyTraverser dependencyTraverser;
087
088    private DependencyManager dependencyManager;
089
090    private DependencySelector dependencySelector;
091
092    private VersionFilter versionFilter;
093
094    private DependencyGraphTransformer dependencyGraphTransformer;
095
096    private SessionData data;
097
098    private RepositoryCache cache;
099
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}