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.SystemScopeHandler;
034import org.eclipse.aether.artifact.ArtifactTypeRegistry;
035import org.eclipse.aether.collection.DependencyGraphTransformer;
036import org.eclipse.aether.collection.DependencyManager;
037import org.eclipse.aether.collection.DependencySelector;
038import org.eclipse.aether.collection.DependencyTraverser;
039import org.eclipse.aether.collection.VersionFilter;
040import org.eclipse.aether.impl.RepositorySystemLifecycle;
041import org.eclipse.aether.repository.AuthenticationSelector;
042import org.eclipse.aether.repository.LocalRepository;
043import org.eclipse.aether.repository.LocalRepositoryManager;
044import org.eclipse.aether.repository.MirrorSelector;
045import org.eclipse.aether.repository.ProxySelector;
046import org.eclipse.aether.repository.RemoteRepository;
047import org.eclipse.aether.repository.WorkspaceReader;
048import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
049import org.eclipse.aether.resolution.ResolutionErrorPolicy;
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 SystemScopeHandler systemScopeHandler = SystemScopeHandler.LEGACY;
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 setSystemScopeHandler(SystemScopeHandler systemScopeHandler) {
357        requireNonNull(systemScopeHandler, "null systemScopeHandler");
358        this.systemScopeHandler = systemScopeHandler;
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        setSystemScopeHandler(session.getSystemScopeHandler());
451        return this;
452    }
453
454    @Override
455    public CloseableSession build() {
456        return new DefaultCloseableSession(
457                sessionIdSupplier.get(),
458                offline,
459                ignoreArtifactDescriptorRepositories,
460                resolutionErrorPolicy,
461                artifactDescriptorPolicy,
462                checksumPolicy,
463                artifactUpdatePolicy,
464                metadataUpdatePolicy,
465                localRepositoryManager,
466                localRepositories,
467                workspaceReader,
468                repositoryListener,
469                transferListener,
470                copySafe(systemProperties, String.class),
471                copySafe(userProperties, String.class),
472                copySafe(configProperties, Object.class),
473                mirrorSelector,
474                proxySelector,
475                authenticationSelector,
476                artifactTypeRegistry,
477                dependencyTraverser,
478                dependencyManager,
479                dependencySelector,
480                versionFilter,
481                dependencyGraphTransformer,
482                sessionDataSupplier.get(),
483                repositoryCacheSupplier.get(),
484                systemScopeHandler,
485                onSessionCloseHandlers,
486                repositorySystem,
487                repositorySystemLifecycle);
488    }
489
490    @SuppressWarnings("checkstyle:magicnumber")
491    private static <T> Map<String, T> copySafe(Map<?, ?> table, Class<T> valueType) {
492        Map<String, T> map;
493        if (table == null || table.isEmpty()) {
494            map = new HashMap<>();
495        } else {
496            map = new HashMap<>((int) (table.size() / 0.75f) + 1);
497            for (Map.Entry<?, ?> entry : table.entrySet()) {
498                Object key = entry.getKey();
499                if (key instanceof String) {
500                    Object value = entry.getValue();
501                    if (valueType.isInstance(value)) {
502                        map.put(key.toString(), valueType.cast(value));
503                    }
504                }
505            }
506        }
507        return map;
508    }
509}