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