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