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