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