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