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