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