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 java.util.Collection;
028
029import org.eclipse.aether.artifact.Artifact;
030import org.eclipse.aether.artifact.ArtifactType;
031import org.eclipse.aether.artifact.ArtifactTypeRegistry;
032import org.eclipse.aether.collection.DependencyGraphTransformer;
033import org.eclipse.aether.collection.DependencyManager;
034import org.eclipse.aether.collection.DependencySelector;
035import org.eclipse.aether.collection.DependencyTraverser;
036import org.eclipse.aether.collection.VersionFilter;
037import org.eclipse.aether.repository.Authentication;
038import org.eclipse.aether.repository.AuthenticationSelector;
039import org.eclipse.aether.repository.LocalRepository;
040import org.eclipse.aether.repository.LocalRepositoryManager;
041import org.eclipse.aether.repository.MirrorSelector;
042import org.eclipse.aether.repository.Proxy;
043import org.eclipse.aether.repository.ProxySelector;
044import org.eclipse.aether.repository.RemoteRepository;
045import org.eclipse.aether.repository.RepositoryPolicy;
046import org.eclipse.aether.repository.WorkspaceReader;
047import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
048import org.eclipse.aether.resolution.ResolutionErrorPolicy;
049import org.eclipse.aether.transfer.TransferListener;
050import org.eclipse.aether.transform.FileTransformer;
051import org.eclipse.aether.transform.FileTransformerManager;
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<String, String>();
131        systemPropertiesView = Collections.unmodifiableMap( systemProperties );
132        userProperties = new HashMap<String, String>();
133        userPropertiesView = Collections.unmodifiableMap( userProperties );
134        configProperties = new HashMap<String, Object>();
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    public boolean isOffline()
184    {
185        return offline;
186    }
187
188    /**
189     * Controls whether the repository system operates in offline mode and avoids/refuses any access to remote
190     * repositories.
191     * 
192     * @param offline {@code true} if the repository system is in offline mode, {@code false} otherwise.
193     * @return This session for chaining, never {@code null}.
194     */
195    public DefaultRepositorySystemSession setOffline( boolean offline )
196    {
197        failIfReadOnly();
198        this.offline = offline;
199        return this;
200    }
201
202    public boolean isIgnoreArtifactDescriptorRepositories()
203    {
204        return ignoreArtifactDescriptorRepositories;
205    }
206
207    /**
208     * Controls whether repositories declared in artifact descriptors should be ignored during transitive dependency
209     * collection. If enabled, only the repositories originally provided with the collect request will be considered.
210     * 
211     * @param ignoreArtifactDescriptorRepositories {@code true} to ignore additional repositories from artifact
212     *            descriptors, {@code false} to merge those with the originally specified repositories.
213     * @return This session for chaining, never {@code null}.
214     */
215    public DefaultRepositorySystemSession setIgnoreArtifactDescriptorRepositories( boolean ignoreArtifactDescriptorRepositories )
216    {
217        failIfReadOnly();
218        this.ignoreArtifactDescriptorRepositories = ignoreArtifactDescriptorRepositories;
219        return this;
220    }
221
222    public ResolutionErrorPolicy getResolutionErrorPolicy()
223    {
224        return resolutionErrorPolicy;
225    }
226
227    /**
228     * Sets the policy which controls whether resolutions errors from remote repositories should be cached.
229     * 
230     * @param resolutionErrorPolicy The resolution error policy for this session, may be {@code null} if resolution
231     *            errors should generally not be cached.
232     * @return This session for chaining, never {@code null}.
233     */
234    public DefaultRepositorySystemSession setResolutionErrorPolicy( ResolutionErrorPolicy resolutionErrorPolicy )
235    {
236        failIfReadOnly();
237        this.resolutionErrorPolicy = resolutionErrorPolicy;
238        return this;
239    }
240
241    public ArtifactDescriptorPolicy getArtifactDescriptorPolicy()
242    {
243        return artifactDescriptorPolicy;
244    }
245
246    /**
247     * Sets the policy which controls how errors related to reading artifact descriptors should be handled.
248     * 
249     * @param artifactDescriptorPolicy The descriptor error policy for this session, may be {@code null} if descriptor
250     *            errors should generally not be tolerated.
251     * @return This session for chaining, never {@code null}.
252     */
253    public DefaultRepositorySystemSession setArtifactDescriptorPolicy( ArtifactDescriptorPolicy artifactDescriptorPolicy )
254    {
255        failIfReadOnly();
256        this.artifactDescriptorPolicy = artifactDescriptorPolicy;
257        return this;
258    }
259
260    public String getChecksumPolicy()
261    {
262        return checksumPolicy;
263    }
264
265    /**
266     * Sets the global checksum policy. If set, the global checksum policy overrides the checksum policies of the remote
267     * repositories being used for resolution.
268     * 
269     * @param checksumPolicy The global checksum policy, may be {@code null}/empty to apply the per-repository policies.
270     * @return This session for chaining, never {@code null}.
271     * @see RepositoryPolicy#CHECKSUM_POLICY_FAIL
272     * @see RepositoryPolicy#CHECKSUM_POLICY_IGNORE
273     * @see RepositoryPolicy#CHECKSUM_POLICY_WARN
274     */
275    public DefaultRepositorySystemSession setChecksumPolicy( String checksumPolicy )
276    {
277        failIfReadOnly();
278        this.checksumPolicy = checksumPolicy;
279        return this;
280    }
281
282    public String getUpdatePolicy()
283    {
284        return updatePolicy;
285    }
286
287    /**
288     * Sets the global update policy. If set, the global update policy overrides the update policies of the remote
289     * repositories being used for resolution.
290     * 
291     * @param updatePolicy The global update policy, may be {@code null}/empty to apply the per-repository policies.
292     * @return This session for chaining, never {@code null}.
293     * @see RepositoryPolicy#UPDATE_POLICY_ALWAYS
294     * @see RepositoryPolicy#UPDATE_POLICY_DAILY
295     * @see RepositoryPolicy#UPDATE_POLICY_NEVER
296     */
297    public DefaultRepositorySystemSession setUpdatePolicy( String updatePolicy )
298    {
299        failIfReadOnly();
300        this.updatePolicy = updatePolicy;
301        return this;
302    }
303
304    public LocalRepository getLocalRepository()
305    {
306        LocalRepositoryManager lrm = getLocalRepositoryManager();
307        return ( lrm != null ) ? lrm.getRepository() : null;
308    }
309
310    public LocalRepositoryManager getLocalRepositoryManager()
311    {
312        return localRepositoryManager;
313    }
314
315    /**
316     * Sets the local repository manager used during this session. <em>Note:</em> Eventually, a valid session must have
317     * a local repository manager set.
318     * 
319     * @param localRepositoryManager The local repository manager used during this session, may be {@code null}.
320     * @return This session for chaining, never {@code null}.
321     */
322    public DefaultRepositorySystemSession setLocalRepositoryManager( LocalRepositoryManager localRepositoryManager )
323    {
324        failIfReadOnly();
325        this.localRepositoryManager = localRepositoryManager;
326        return this;
327    }
328
329    @Override
330    public FileTransformerManager getFileTransformerManager()
331    {
332        return fileTransformerManager;
333    }
334
335    public DefaultRepositorySystemSession setFileTransformerManager( FileTransformerManager fileTransformerManager )
336    {
337        failIfReadOnly();
338        this.fileTransformerManager = fileTransformerManager;
339        if ( this.fileTransformerManager == null )
340        {
341            this.fileTransformerManager = NullFileTransformerManager.INSTANCE;
342        }
343        return this;
344    }
345
346    public WorkspaceReader getWorkspaceReader()
347    {
348        return workspaceReader;
349    }
350
351    /**
352     * Sets the workspace reader used during this session. If set, the workspace reader will usually be consulted first
353     * to resolve artifacts.
354     * 
355     * @param workspaceReader The workspace reader for this session, may be {@code null} if none.
356     * @return This session for chaining, never {@code null}.
357     */
358    public DefaultRepositorySystemSession setWorkspaceReader( WorkspaceReader workspaceReader )
359    {
360        failIfReadOnly();
361        this.workspaceReader = workspaceReader;
362        return this;
363    }
364
365    public RepositoryListener getRepositoryListener()
366    {
367        return repositoryListener;
368    }
369
370    /**
371     * Sets the listener being notified of actions in the repository system.
372     * 
373     * @param repositoryListener The repository listener, may be {@code null} if none.
374     * @return This session for chaining, never {@code null}.
375     */
376    public DefaultRepositorySystemSession setRepositoryListener( RepositoryListener repositoryListener )
377    {
378        failIfReadOnly();
379        this.repositoryListener = repositoryListener;
380        return this;
381    }
382
383    public TransferListener getTransferListener()
384    {
385        return transferListener;
386    }
387
388    /**
389     * Sets the listener being notified of uploads/downloads by the repository system.
390     * 
391     * @param transferListener The transfer listener, may be {@code null} if none.
392     * @return This session for chaining, never {@code null}.
393     */
394    public DefaultRepositorySystemSession setTransferListener( TransferListener transferListener )
395    {
396        failIfReadOnly();
397        this.transferListener = transferListener;
398        return this;
399    }
400
401    private <T> Map<String, T> copySafe( Map<?, ?> table, Class<T> valueType )
402    {
403        Map<String, T> map;
404        if ( table == null || table.isEmpty() )
405        {
406            map = new HashMap<String, T>();
407        }
408        else
409        {
410            map = new HashMap<String, T>( (int) ( table.size() / 0.75f ) + 1 );
411            for ( Map.Entry<?, ?> entry : table.entrySet() )
412            {
413                Object key = entry.getKey();
414                if ( key instanceof String )
415                {
416                    Object value = entry.getValue();
417                    if ( valueType.isInstance( value ) )
418                    {
419                        map.put( key.toString(), valueType.cast( value ) );
420                    }
421                }
422            }
423        }
424        return map;
425    }
426
427    public Map<String, String> getSystemProperties()
428    {
429        return systemPropertiesView;
430    }
431
432    /**
433     * Sets the system properties to use, e.g. for processing of artifact descriptors. System properties are usually
434     * collected from the runtime environment like {@link System#getProperties()} and environment variables.
435     * <p>
436     * <em>Note:</em> System properties are of type {@code Map<String, String>} and any key-value pair in the input map
437     * that doesn't match this type will be silently ignored.
438     * 
439     * @param systemProperties The system properties, may be {@code null} or empty if none.
440     * @return This session for chaining, never {@code null}.
441     */
442    public DefaultRepositorySystemSession setSystemProperties( Map<?, ?> systemProperties )
443    {
444        failIfReadOnly();
445        this.systemProperties = copySafe( systemProperties, String.class );
446        systemPropertiesView = Collections.unmodifiableMap( this.systemProperties );
447        return this;
448    }
449
450    /**
451     * Sets the specified system property.
452     * 
453     * @param key The property key, must not be {@code null}.
454     * @param value The property value, may be {@code null} to remove/unset the property.
455     * @return This session for chaining, never {@code null}.
456     */
457    public DefaultRepositorySystemSession setSystemProperty( String key, String value )
458    {
459        failIfReadOnly();
460        if ( value != null )
461        {
462            systemProperties.put( key, value );
463        }
464        else
465        {
466            systemProperties.remove( key );
467        }
468        return this;
469    }
470
471    public Map<String, String> getUserProperties()
472    {
473        return userPropertiesView;
474    }
475
476    /**
477     * Sets the user properties to use, e.g. for processing of artifact descriptors. User properties are similar to
478     * system properties but are set on the discretion of the user and hence are considered of higher priority than
479     * system properties in case of conflicts.
480     * <p>
481     * <em>Note:</em> User properties are of type {@code Map<String, String>} and any key-value pair in the input map
482     * that doesn't match this type will be silently ignored.
483     * 
484     * @param userProperties The user properties, may be {@code null} or empty if none.
485     * @return This session for chaining, never {@code null}.
486     */
487    public DefaultRepositorySystemSession setUserProperties( Map<?, ?> userProperties )
488    {
489        failIfReadOnly();
490        this.userProperties = copySafe( userProperties, String.class );
491        userPropertiesView = Collections.unmodifiableMap( this.userProperties );
492        return this;
493    }
494
495    /**
496     * Sets the specified user property.
497     * 
498     * @param key The property key, must not be {@code null}.
499     * @param value The property value, may be {@code null} to remove/unset the property.
500     * @return This session for chaining, never {@code null}.
501     */
502    public DefaultRepositorySystemSession setUserProperty( String key, String value )
503    {
504        failIfReadOnly();
505        if ( value != null )
506        {
507            userProperties.put( key, value );
508        }
509        else
510        {
511            userProperties.remove( key );
512        }
513        return this;
514    }
515
516    public Map<String, Object> getConfigProperties()
517    {
518        return configPropertiesView;
519    }
520
521    /**
522     * Sets the configuration properties used to tweak internal aspects of the repository system (e.g. thread pooling,
523     * connector-specific behavior, etc.).
524     * <p>
525     * <em>Note:</em> Configuration properties are of type {@code Map<String, Object>} and any key-value pair in the
526     * input map that doesn't match this type will be silently ignored.
527     * 
528     * @param configProperties The configuration properties, may be {@code null} or empty if none.
529     * @return This session for chaining, never {@code null}.
530     */
531    public DefaultRepositorySystemSession setConfigProperties( Map<?, ?> configProperties )
532    {
533        failIfReadOnly();
534        this.configProperties = copySafe( configProperties, Object.class );
535        configPropertiesView = Collections.unmodifiableMap( this.configProperties );
536        return this;
537    }
538
539    /**
540     * Sets the specified configuration property.
541     * 
542     * @param key The property key, must not be {@code null}.
543     * @param value The property value, may be {@code null} to remove/unset the property.
544     * @return This session for chaining, never {@code null}.
545     */
546    public DefaultRepositorySystemSession setConfigProperty( String key, Object value )
547    {
548        failIfReadOnly();
549        if ( value != null )
550        {
551            configProperties.put( key, value );
552        }
553        else
554        {
555            configProperties.remove( key );
556        }
557        return this;
558    }
559
560    public MirrorSelector getMirrorSelector()
561    {
562        return mirrorSelector;
563    }
564
565    /**
566     * Sets the mirror selector to use for repositories discovered in artifact descriptors. Note that this selector is
567     * not used for remote repositories which are passed as request parameters to the repository system, those
568     * repositories are supposed to denote the effective repositories.
569     * 
570     * @param mirrorSelector The mirror selector to use, may be {@code null}.
571     * @return This session for chaining, never {@code null}.
572     */
573    public DefaultRepositorySystemSession setMirrorSelector( MirrorSelector mirrorSelector )
574    {
575        failIfReadOnly();
576        this.mirrorSelector = mirrorSelector;
577        if ( this.mirrorSelector == null )
578        {
579            this.mirrorSelector = NullMirrorSelector.INSTANCE;
580        }
581        return this;
582    }
583
584    public ProxySelector getProxySelector()
585    {
586        return proxySelector;
587    }
588
589    /**
590     * Sets the proxy selector to use for repositories discovered in artifact descriptors. Note that this selector is
591     * not used for remote repositories which are passed as request parameters to the repository system, those
592     * repositories are supposed to have their proxy (if any) already set.
593     * 
594     * @param proxySelector The proxy selector to use, may be {@code null}.
595     * @return This session for chaining, never {@code null}.
596     * @see org.eclipse.aether.repository.RemoteRepository#getProxy()
597     */
598    public DefaultRepositorySystemSession setProxySelector( ProxySelector proxySelector )
599    {
600        failIfReadOnly();
601        this.proxySelector = proxySelector;
602        if ( this.proxySelector == null )
603        {
604            this.proxySelector = NullProxySelector.INSTANCE;
605        }
606        return this;
607    }
608
609    public AuthenticationSelector getAuthenticationSelector()
610    {
611        return authenticationSelector;
612    }
613
614    /**
615     * Sets the authentication selector to use for repositories discovered in artifact descriptors. Note that this
616     * selector is not used for remote repositories which are passed as request parameters to the repository system,
617     * those repositories are supposed to have their authentication (if any) already set.
618     * 
619     * @param authenticationSelector The authentication selector to use, may be {@code null}.
620     * @return This session for chaining, never {@code null}.
621     * @see org.eclipse.aether.repository.RemoteRepository#getAuthentication()
622     */
623    public DefaultRepositorySystemSession setAuthenticationSelector( AuthenticationSelector authenticationSelector )
624    {
625        failIfReadOnly();
626        this.authenticationSelector = authenticationSelector;
627        if ( this.authenticationSelector == null )
628        {
629            this.authenticationSelector = NullAuthenticationSelector.INSTANCE;
630        }
631        return this;
632    }
633
634    public ArtifactTypeRegistry getArtifactTypeRegistry()
635    {
636        return artifactTypeRegistry;
637    }
638
639    /**
640     * Sets the registry of artifact types recognized by this session.
641     * 
642     * @param artifactTypeRegistry The artifact type registry, may be {@code null}.
643     * @return This session for chaining, never {@code null}.
644     */
645    public DefaultRepositorySystemSession setArtifactTypeRegistry( ArtifactTypeRegistry artifactTypeRegistry )
646    {
647        failIfReadOnly();
648        this.artifactTypeRegistry = artifactTypeRegistry;
649        if ( this.artifactTypeRegistry == null )
650        {
651            this.artifactTypeRegistry = NullArtifactTypeRegistry.INSTANCE;
652        }
653        return this;
654    }
655
656    public DependencyTraverser getDependencyTraverser()
657    {
658        return dependencyTraverser;
659    }
660
661    /**
662     * Sets the dependency traverser to use for building dependency graphs.
663     * 
664     * @param dependencyTraverser The dependency traverser to use for building dependency graphs, may be {@code null}.
665     * @return This session for chaining, never {@code null}.
666     */
667    public DefaultRepositorySystemSession setDependencyTraverser( DependencyTraverser dependencyTraverser )
668    {
669        failIfReadOnly();
670        this.dependencyTraverser = dependencyTraverser;
671        return this;
672    }
673
674    public DependencyManager getDependencyManager()
675    {
676        return dependencyManager;
677    }
678
679    /**
680     * Sets the dependency manager to use for building dependency graphs.
681     * 
682     * @param dependencyManager The dependency manager to use for building dependency graphs, may be {@code null}.
683     * @return This session for chaining, never {@code null}.
684     */
685    public DefaultRepositorySystemSession setDependencyManager( DependencyManager dependencyManager )
686    {
687        failIfReadOnly();
688        this.dependencyManager = dependencyManager;
689        return this;
690    }
691
692    public DependencySelector getDependencySelector()
693    {
694        return dependencySelector;
695    }
696
697    /**
698     * Sets the dependency selector to use for building dependency graphs.
699     * 
700     * @param dependencySelector The dependency selector to use for building dependency graphs, may be {@code null}.
701     * @return This session for chaining, never {@code null}.
702     */
703    public DefaultRepositorySystemSession setDependencySelector( DependencySelector dependencySelector )
704    {
705        failIfReadOnly();
706        this.dependencySelector = dependencySelector;
707        return this;
708    }
709
710    public VersionFilter getVersionFilter()
711    {
712        return versionFilter;
713    }
714
715    /**
716     * Sets the version filter to use for building dependency graphs.
717     * 
718     * @param versionFilter The version filter to use for building dependency graphs, may be {@code null} to not filter
719     *            versions.
720     * @return This session for chaining, never {@code null}.
721     */
722    public DefaultRepositorySystemSession setVersionFilter( VersionFilter versionFilter )
723    {
724        failIfReadOnly();
725        this.versionFilter = versionFilter;
726        return this;
727    }
728
729    public DependencyGraphTransformer getDependencyGraphTransformer()
730    {
731        return dependencyGraphTransformer;
732    }
733
734    /**
735     * Sets the dependency graph transformer to use for building dependency graphs.
736     * 
737     * @param dependencyGraphTransformer The dependency graph transformer to use for building dependency graphs, may be
738     *            {@code null}.
739     * @return This session for chaining, never {@code null}.
740     */
741    public DefaultRepositorySystemSession setDependencyGraphTransformer( DependencyGraphTransformer dependencyGraphTransformer )
742    {
743        failIfReadOnly();
744        this.dependencyGraphTransformer = dependencyGraphTransformer;
745        return this;
746    }
747
748    public SessionData getData()
749    {
750        return data;
751    }
752
753    /**
754     * Sets the custom data associated with this session.
755     * 
756     * @param data The session data, may be {@code null}.
757     * @return This session for chaining, never {@code null}.
758     */
759    public DefaultRepositorySystemSession setData( SessionData data )
760    {
761        failIfReadOnly();
762        this.data = data;
763        if ( this.data == null )
764        {
765            this.data = new DefaultSessionData();
766        }
767        return this;
768    }
769
770    public RepositoryCache getCache()
771    {
772        return cache;
773    }
774
775    /**
776     * Sets the cache the repository system may use to save data for future reuse during the session.
777     * 
778     * @param cache The repository cache, may be {@code null} if none.
779     * @return This session for chaining, never {@code null}.
780     */
781    public DefaultRepositorySystemSession setCache( RepositoryCache cache )
782    {
783        failIfReadOnly();
784        this.cache = cache;
785        return this;
786    }
787
788    /**
789     * Marks this session as read-only such that any future attempts to call its mutators will fail with an exception.
790     * Marking an already read-only session as read-only has no effect. The session's data and cache remain writable
791     * though.
792     */
793    public void setReadOnly()
794    {
795        readOnly = true;
796    }
797
798    private void failIfReadOnly()
799    {
800        if ( readOnly )
801        {
802            throw new IllegalStateException( "repository system session is read-only" );
803        }
804    }
805
806    static class NullProxySelector
807        implements ProxySelector
808    {
809
810        public static final ProxySelector INSTANCE = new NullProxySelector();
811
812        public Proxy getProxy( RemoteRepository repository )
813        {
814            return repository.getProxy();
815        }
816
817    }
818
819    static class NullMirrorSelector
820        implements MirrorSelector
821    {
822
823        public static final MirrorSelector INSTANCE = new NullMirrorSelector();
824
825        public RemoteRepository getMirror( RemoteRepository repository )
826        {
827            return null;
828        }
829
830    }
831
832    static class NullAuthenticationSelector
833        implements AuthenticationSelector
834    {
835
836        public static final AuthenticationSelector INSTANCE = new NullAuthenticationSelector();
837
838        public Authentication getAuthentication( RemoteRepository repository )
839        {
840            return repository.getAuthentication();
841        }
842
843    }
844
845    static final class NullArtifactTypeRegistry
846        implements ArtifactTypeRegistry
847    {
848
849        public static final ArtifactTypeRegistry INSTANCE = new NullArtifactTypeRegistry();
850
851        public ArtifactType get( String typeId )
852        {
853            return null;
854        }
855
856    }
857
858    static final class NullFileTransformerManager implements FileTransformerManager
859    {
860        public static final FileTransformerManager INSTANCE = new NullFileTransformerManager();
861
862        @Override
863        public Collection<FileTransformer> getTransformersForArtifact( Artifact artifact )
864        {
865            return Collections.emptyList();
866        }
867    }
868
869}