001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.eclipse.aether.internal.impl.session;
020
021import java.nio.file.Path;
022import java.util.*;
023import java.util.function.Supplier;
024
025import org.eclipse.aether.DefaultSessionData;
026import org.eclipse.aether.RepositoryCache;
027import org.eclipse.aether.RepositoryListener;
028import org.eclipse.aether.RepositorySystem;
029import org.eclipse.aether.RepositorySystemSession;
030import org.eclipse.aether.RepositorySystemSession.CloseableSession;
031import org.eclipse.aether.RepositorySystemSession.SessionBuilder;
032import org.eclipse.aether.SessionData;
033import org.eclipse.aether.artifact.ArtifactTypeRegistry;
034import org.eclipse.aether.collection.DependencyGraphTransformer;
035import org.eclipse.aether.collection.DependencyManager;
036import org.eclipse.aether.collection.DependencySelector;
037import org.eclipse.aether.collection.DependencyTraverser;
038import org.eclipse.aether.collection.VersionFilter;
039import org.eclipse.aether.impl.RepositorySystemLifecycle;
040import org.eclipse.aether.repository.AuthenticationSelector;
041import org.eclipse.aether.repository.LocalRepository;
042import org.eclipse.aether.repository.LocalRepositoryManager;
043import org.eclipse.aether.repository.MirrorSelector;
044import org.eclipse.aether.repository.ProxySelector;
045import org.eclipse.aether.repository.RemoteRepository;
046import org.eclipse.aether.repository.WorkspaceReader;
047import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
048import org.eclipse.aether.resolution.ResolutionErrorPolicy;
049import org.eclipse.aether.scope.ScopeManager;
050import org.eclipse.aether.transfer.TransferListener;
051
052import static java.util.Objects.requireNonNull;
053import static java.util.stream.Collectors.toList;
054
055/**
056 * A default implementation of session builder. Is not immutable nor thread-safe.
057 */
058public final class DefaultSessionBuilder implements SessionBuilder {
059    private static final MirrorSelector NULL_MIRROR_SELECTOR = r -> null;
060
061    private static final ProxySelector PASS_THROUGH_PROXY_SELECTOR = RemoteRepository::getProxy;
062
063    private static final AuthenticationSelector PASS_THROUGH_AUTHENTICATION_SELECTOR =
064            RemoteRepository::getAuthentication;
065
066    private static final ArtifactTypeRegistry NULL_ARTIFACT_TYPE_REGISTRY = t -> null;
067
068    private static final Supplier<SessionData> DEFAULT_SESSION_DATA_SUPPLIER = DefaultSessionData::new;
069
070    private static final Supplier<RepositoryCache> DEFAULT_REPOSITORY_CACHE_SUPPLIER = () -> null;
071
072    private final RepositorySystem repositorySystem;
073
074    private final RepositorySystemLifecycle repositorySystemLifecycle;
075
076    private final Supplier<String> sessionIdSupplier;
077
078    private boolean offline;
079
080    private boolean ignoreArtifactDescriptorRepositories;
081
082    private ResolutionErrorPolicy resolutionErrorPolicy;
083
084    private ArtifactDescriptorPolicy artifactDescriptorPolicy;
085
086    private String checksumPolicy;
087
088    private String artifactUpdatePolicy;
089
090    private String metadataUpdatePolicy;
091
092    private LocalRepositoryManager localRepositoryManager;
093
094    private Collection<LocalRepository> localRepositories;
095
096    private WorkspaceReader workspaceReader;
097
098    private final ArrayList<RepositoryListener> repositoryListener = new ArrayList<>();
099
100    private final ArrayList<TransferListener> transferListener = new ArrayList<>();
101
102    private Map<String, String> systemProperties = new HashMap<>();
103
104    private Map<String, String> userProperties = new HashMap<>();
105
106    private Map<String, Object> configProperties = new HashMap<>();
107
108    private MirrorSelector mirrorSelector = NULL_MIRROR_SELECTOR;
109
110    private ProxySelector proxySelector = PASS_THROUGH_PROXY_SELECTOR;
111
112    private AuthenticationSelector authenticationSelector = PASS_THROUGH_AUTHENTICATION_SELECTOR;
113
114    private ArtifactTypeRegistry artifactTypeRegistry = NULL_ARTIFACT_TYPE_REGISTRY;
115
116    private DependencyTraverser dependencyTraverser;
117
118    private DependencyManager dependencyManager;
119
120    private DependencySelector dependencySelector;
121
122    private VersionFilter versionFilter;
123
124    private DependencyGraphTransformer dependencyGraphTransformer;
125
126    private Supplier<SessionData> sessionDataSupplier = DEFAULT_SESSION_DATA_SUPPLIER;
127
128    private Supplier<RepositoryCache> repositoryCacheSupplier = DEFAULT_REPOSITORY_CACHE_SUPPLIER;
129
130    private ScopeManager scopeManager;
131
132    private final ArrayList<Runnable> onSessionCloseHandlers = new ArrayList<>();
133
134    /**
135     * Constructor for "top level" builders.
136     */
137    public DefaultSessionBuilder(
138            RepositorySystem repositorySystem,
139            RepositorySystemLifecycle repositorySystemLifecycle,
140            Supplier<String> sessionIdSupplier) {
141        this.repositorySystem = requireNonNull(repositorySystem);
142        this.repositorySystemLifecycle = requireNonNull(repositorySystemLifecycle);
143        this.sessionIdSupplier = requireNonNull(sessionIdSupplier);
144    }
145
146    @Override
147    public DefaultSessionBuilder setOffline(boolean offline) {
148        this.offline = offline;
149        return this;
150    }
151
152    @Override
153    public DefaultSessionBuilder setIgnoreArtifactDescriptorRepositories(boolean ignoreArtifactDescriptorRepositories) {
154        this.ignoreArtifactDescriptorRepositories = ignoreArtifactDescriptorRepositories;
155        return this;
156    }
157
158    @Override
159    public DefaultSessionBuilder setResolutionErrorPolicy(ResolutionErrorPolicy resolutionErrorPolicy) {
160        this.resolutionErrorPolicy = resolutionErrorPolicy;
161        return this;
162    }
163
164    @Override
165    public DefaultSessionBuilder setArtifactDescriptorPolicy(ArtifactDescriptorPolicy artifactDescriptorPolicy) {
166        this.artifactDescriptorPolicy = artifactDescriptorPolicy;
167        return this;
168    }
169
170    @Override
171    public DefaultSessionBuilder setChecksumPolicy(String checksumPolicy) {
172        this.checksumPolicy = checksumPolicy;
173        return this;
174    }
175
176    @Override
177    public DefaultSessionBuilder setUpdatePolicy(String updatePolicy) {
178        setArtifactUpdatePolicy(updatePolicy);
179        setMetadataUpdatePolicy(updatePolicy);
180        return this;
181    }
182
183    @Override
184    public DefaultSessionBuilder setArtifactUpdatePolicy(String artifactUpdatePolicy) {
185        this.artifactUpdatePolicy = artifactUpdatePolicy;
186        return this;
187    }
188
189    @Override
190    public DefaultSessionBuilder setMetadataUpdatePolicy(String metadataUpdatePolicy) {
191        this.metadataUpdatePolicy = metadataUpdatePolicy;
192        return this;
193    }
194
195    @Override
196    public DefaultSessionBuilder setLocalRepositoryManager(LocalRepositoryManager localRepositoryManager) {
197        this.localRepositoryManager = localRepositoryManager;
198        return this;
199    }
200
201    @Override
202    public DefaultSessionBuilder setWorkspaceReader(WorkspaceReader workspaceReader) {
203        this.workspaceReader = workspaceReader;
204        return this;
205    }
206
207    @Override
208    public DefaultSessionBuilder setRepositoryListener(RepositoryListener repositoryListener) {
209        this.repositoryListener.clear();
210        if (repositoryListener != null) {
211            this.repositoryListener.add(repositoryListener);
212        }
213        return this;
214    }
215
216    @Override
217    public DefaultSessionBuilder setTransferListener(TransferListener transferListener) {
218        this.transferListener.clear();
219        if (transferListener != null) {
220            this.transferListener.add(transferListener);
221        }
222        return this;
223    }
224
225    @Override
226    public DefaultSessionBuilder setSystemProperties(Map<?, ?> systemProperties) {
227        this.systemProperties = copySafe(systemProperties, String.class);
228        return this;
229    }
230
231    @Override
232    public DefaultSessionBuilder setSystemProperty(String key, String value) {
233        if (value != null) {
234            systemProperties.put(key, value);
235        } else {
236            systemProperties.remove(key);
237        }
238        return this;
239    }
240
241    @Override
242    public DefaultSessionBuilder setUserProperties(Map<?, ?> userProperties) {
243        this.userProperties = copySafe(userProperties, String.class);
244        return this;
245    }
246
247    @Override
248    public DefaultSessionBuilder setUserProperty(String key, String value) {
249        if (value != null) {
250            userProperties.put(key, value);
251        } else {
252            userProperties.remove(key);
253        }
254        return this;
255    }
256
257    @Override
258    public DefaultSessionBuilder setConfigProperties(Map<?, ?> configProperties) {
259        this.configProperties = copySafe(configProperties, Object.class);
260        return this;
261    }
262
263    @Override
264    public DefaultSessionBuilder setConfigProperty(String key, Object value) {
265        if (value != null) {
266            configProperties.put(key, value);
267        } else {
268            configProperties.remove(key);
269        }
270        return this;
271    }
272
273    @Override
274    public DefaultSessionBuilder setMirrorSelector(MirrorSelector mirrorSelector) {
275        this.mirrorSelector = mirrorSelector;
276        if (this.mirrorSelector == null) {
277            this.mirrorSelector = NULL_MIRROR_SELECTOR;
278        }
279        return this;
280    }
281
282    @Override
283    public DefaultSessionBuilder setProxySelector(ProxySelector proxySelector) {
284        this.proxySelector = proxySelector;
285        if (this.proxySelector == null) {
286            this.proxySelector = PASS_THROUGH_PROXY_SELECTOR;
287        }
288        return this;
289    }
290
291    @Override
292    public DefaultSessionBuilder setAuthenticationSelector(AuthenticationSelector authenticationSelector) {
293        this.authenticationSelector = authenticationSelector;
294        if (this.authenticationSelector == null) {
295            this.authenticationSelector = PASS_THROUGH_AUTHENTICATION_SELECTOR;
296        }
297        return this;
298    }
299
300    @Override
301    public DefaultSessionBuilder setArtifactTypeRegistry(ArtifactTypeRegistry artifactTypeRegistry) {
302        this.artifactTypeRegistry = artifactTypeRegistry;
303        if (this.artifactTypeRegistry == null) {
304            this.artifactTypeRegistry = NULL_ARTIFACT_TYPE_REGISTRY;
305        }
306        return this;
307    }
308
309    @Override
310    public DefaultSessionBuilder setDependencyTraverser(DependencyTraverser dependencyTraverser) {
311        this.dependencyTraverser = dependencyTraverser;
312        return this;
313    }
314
315    @Override
316    public DefaultSessionBuilder setDependencyManager(DependencyManager dependencyManager) {
317        this.dependencyManager = dependencyManager;
318        return this;
319    }
320
321    @Override
322    public DefaultSessionBuilder setDependencySelector(DependencySelector dependencySelector) {
323        this.dependencySelector = dependencySelector;
324        return this;
325    }
326
327    @Override
328    public DefaultSessionBuilder setVersionFilter(VersionFilter versionFilter) {
329        this.versionFilter = versionFilter;
330        return this;
331    }
332
333    @Override
334    public DefaultSessionBuilder setDependencyGraphTransformer(DependencyGraphTransformer dependencyGraphTransformer) {
335        this.dependencyGraphTransformer = dependencyGraphTransformer;
336        return this;
337    }
338
339    @Override
340    public DefaultSessionBuilder setData(SessionData data) {
341        return setSessionDataSupplier(() -> data);
342    }
343
344    @Override
345    public DefaultSessionBuilder setSessionDataSupplier(Supplier<SessionData> dataSupplier) {
346        requireNonNull(dataSupplier, "null dataSupplier");
347        this.sessionDataSupplier = dataSupplier;
348        return this;
349    }
350
351    @Override
352    public DefaultSessionBuilder setCache(RepositoryCache cache) {
353        return setRepositoryCacheSupplier(() -> cache);
354    }
355
356    @Override
357    public DefaultSessionBuilder setScopeManager(ScopeManager scopeManager) {
358        this.scopeManager = scopeManager;
359        return this;
360    }
361
362    @Override
363    public SessionBuilder addOnSessionEndedHandler(Runnable handler) {
364        requireNonNull(handler, "null handler");
365        onSessionCloseHandlers.add(handler);
366        return this;
367    }
368
369    @Override
370    public DefaultSessionBuilder setRepositoryCacheSupplier(Supplier<RepositoryCache> cacheSupplier) {
371        requireNonNull(cacheSupplier, "null cacheSupplier");
372        this.repositoryCacheSupplier = cacheSupplier;
373        return this;
374    }
375
376    @Override
377    public SessionBuilder withLocalRepositoryBaseDirectories(Path... baseDirectories) {
378        return withLocalRepositoryBaseDirectories(Arrays.asList(baseDirectories));
379    }
380
381    @Override
382    public SessionBuilder withLocalRepositoryBaseDirectories(Collection<Path> baseDirectories) {
383        requireNonNull(baseDirectories, "null baseDirectories");
384        return withLocalRepositories(
385                baseDirectories.stream().map(LocalRepository::new).collect(toList()));
386    }
387
388    @Override
389    public SessionBuilder withLocalRepositories(LocalRepository... localRepositories) {
390        return withLocalRepositories(Arrays.asList(localRepositories));
391    }
392
393    @Override
394    public SessionBuilder withLocalRepositories(Collection<LocalRepository> localRepositories) {
395        requireNonNull(localRepositories, "null localRepositories");
396        this.localRepositories = localRepositories;
397        return this;
398    }
399
400    @Override
401    public SessionBuilder withRepositoryListener(RepositoryListener... repositoryListeners) {
402        return withRepositoryListener(Arrays.asList(repositoryListeners));
403    }
404
405    @Override
406    public SessionBuilder withRepositoryListener(Collection<RepositoryListener> repositoryListeners) {
407        this.repositoryListener.addAll(repositoryListeners);
408        return this;
409    }
410
411    @Override
412    public SessionBuilder withTransferListener(TransferListener... transferListeners) {
413        return withTransferListener(Arrays.asList(transferListeners));
414    }
415
416    @Override
417    public SessionBuilder withTransferListener(Collection<TransferListener> transferListeners) {
418        this.transferListener.addAll(transferListeners);
419        return this;
420    }
421
422    @Override
423    public SessionBuilder withRepositorySystemSession(RepositorySystemSession session) {
424        requireNonNull(session, "repository system session cannot be null");
425        setOffline(session.isOffline());
426        setIgnoreArtifactDescriptorRepositories(session.isIgnoreArtifactDescriptorRepositories());
427        setResolutionErrorPolicy(session.getResolutionErrorPolicy());
428        setArtifactDescriptorPolicy(session.getArtifactDescriptorPolicy());
429        setChecksumPolicy(session.getChecksumPolicy());
430        setUpdatePolicy(session.getUpdatePolicy());
431        setMetadataUpdatePolicy(session.getMetadataUpdatePolicy());
432        setLocalRepositoryManager(session.getLocalRepositoryManager());
433        setWorkspaceReader(session.getWorkspaceReader());
434        setRepositoryListener(session.getRepositoryListener());
435        setTransferListener(session.getTransferListener());
436        setSystemProperties(session.getSystemProperties());
437        setUserProperties(session.getUserProperties());
438        setConfigProperties(session.getConfigProperties());
439        setMirrorSelector(session.getMirrorSelector());
440        setProxySelector(session.getProxySelector());
441        setAuthenticationSelector(session.getAuthenticationSelector());
442        setArtifactTypeRegistry(session.getArtifactTypeRegistry());
443        setDependencyTraverser(session.getDependencyTraverser());
444        setDependencyManager(session.getDependencyManager());
445        setDependencySelector(session.getDependencySelector());
446        setVersionFilter(session.getVersionFilter());
447        setDependencyGraphTransformer(session.getDependencyGraphTransformer());
448        setData(session.getData());
449        setCache(session.getCache());
450        return this;
451    }
452
453    @Override
454    public CloseableSession build() {
455        return new DefaultCloseableSession(
456                sessionIdSupplier.get(),
457                offline,
458                ignoreArtifactDescriptorRepositories,
459                resolutionErrorPolicy,
460                artifactDescriptorPolicy,
461                checksumPolicy,
462                artifactUpdatePolicy,
463                metadataUpdatePolicy,
464                localRepositoryManager,
465                localRepositories,
466                workspaceReader,
467                repositoryListener,
468                transferListener,
469                copySafe(systemProperties, String.class),
470                copySafe(userProperties, String.class),
471                copySafe(configProperties, Object.class),
472                mirrorSelector,
473                proxySelector,
474                authenticationSelector,
475                artifactTypeRegistry,
476                dependencyTraverser,
477                dependencyManager,
478                dependencySelector,
479                versionFilter,
480                dependencyGraphTransformer,
481                sessionDataSupplier.get(),
482                repositoryCacheSupplier.get(),
483                scopeManager,
484                onSessionCloseHandlers,
485                repositorySystem,
486                repositorySystemLifecycle);
487    }
488
489    @SuppressWarnings("checkstyle:magicnumber")
490    private static <T> Map<String, T> copySafe(Map<?, ?> table, Class<T> valueType) {
491        Map<String, T> map;
492        if (table == null || table.isEmpty()) {
493            map = new HashMap<>();
494        } else {
495            map = new HashMap<>((int) (table.size() / 0.75f) + 1);
496            for (Map.Entry<?, ?> entry : table.entrySet()) {
497                Object key = entry.getKey();
498                if (key instanceof String) {
499                    Object value = entry.getValue();
500                    if (valueType.isInstance(value)) {
501                        map.put(key.toString(), valueType.cast(value));
502                    }
503                }
504            }
505        }
506        return map;
507    }
508}