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