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