View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.internal.impl;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.Objects;
32  import java.util.concurrent.atomic.AtomicBoolean;
33  import java.util.concurrent.atomic.AtomicInteger;
34  import java.util.function.Consumer;
35  import java.util.stream.Collectors;
36  
37  import org.eclipse.aether.ConfigurationProperties;
38  import org.eclipse.aether.RepositorySystem;
39  import org.eclipse.aether.RepositorySystemSession;
40  import org.eclipse.aether.RequestTrace;
41  import org.eclipse.aether.SyncContext;
42  import org.eclipse.aether.artifact.Artifact;
43  import org.eclipse.aether.collection.CollectRequest;
44  import org.eclipse.aether.collection.CollectResult;
45  import org.eclipse.aether.collection.DependencyCollectionException;
46  import org.eclipse.aether.deployment.DeployRequest;
47  import org.eclipse.aether.deployment.DeployResult;
48  import org.eclipse.aether.deployment.DeploymentException;
49  import org.eclipse.aether.graph.DependencyFilter;
50  import org.eclipse.aether.graph.DependencyNode;
51  import org.eclipse.aether.graph.DependencyVisitor;
52  import org.eclipse.aether.impl.ArtifactDescriptorReader;
53  import org.eclipse.aether.impl.ArtifactResolver;
54  import org.eclipse.aether.impl.DependencyCollector;
55  import org.eclipse.aether.impl.Deployer;
56  import org.eclipse.aether.impl.Installer;
57  import org.eclipse.aether.impl.LocalRepositoryProvider;
58  import org.eclipse.aether.impl.MetadataResolver;
59  import org.eclipse.aether.impl.RemoteRepositoryManager;
60  import org.eclipse.aether.impl.RepositorySystemLifecycle;
61  import org.eclipse.aether.impl.RepositorySystemValidator;
62  import org.eclipse.aether.impl.VersionRangeResolver;
63  import org.eclipse.aether.impl.VersionResolver;
64  import org.eclipse.aether.installation.InstallRequest;
65  import org.eclipse.aether.installation.InstallResult;
66  import org.eclipse.aether.installation.InstallationException;
67  import org.eclipse.aether.internal.impl.session.DefaultSessionBuilder;
68  import org.eclipse.aether.repository.Authentication;
69  import org.eclipse.aether.repository.LocalRepository;
70  import org.eclipse.aether.repository.LocalRepositoryManager;
71  import org.eclipse.aether.repository.NoLocalRepositoryManagerException;
72  import org.eclipse.aether.repository.Proxy;
73  import org.eclipse.aether.repository.RemoteRepository;
74  import org.eclipse.aether.resolution.ArtifactDescriptorException;
75  import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
76  import org.eclipse.aether.resolution.ArtifactDescriptorResult;
77  import org.eclipse.aether.resolution.ArtifactRequest;
78  import org.eclipse.aether.resolution.ArtifactResolutionException;
79  import org.eclipse.aether.resolution.ArtifactResult;
80  import org.eclipse.aether.resolution.DependencyRequest;
81  import org.eclipse.aether.resolution.DependencyResolutionException;
82  import org.eclipse.aether.resolution.DependencyResult;
83  import org.eclipse.aether.resolution.MetadataRequest;
84  import org.eclipse.aether.resolution.MetadataResult;
85  import org.eclipse.aether.resolution.VersionRangeRequest;
86  import org.eclipse.aether.resolution.VersionRangeResolutionException;
87  import org.eclipse.aether.resolution.VersionRangeResult;
88  import org.eclipse.aether.resolution.VersionRequest;
89  import org.eclipse.aether.resolution.VersionResolutionException;
90  import org.eclipse.aether.resolution.VersionResult;
91  import org.eclipse.aether.spi.artifact.decorator.ArtifactDecorator;
92  import org.eclipse.aether.spi.artifact.decorator.ArtifactDecoratorFactory;
93  import org.eclipse.aether.spi.synccontext.SyncContextFactory;
94  import org.eclipse.aether.util.ConfigUtils;
95  import org.eclipse.aether.util.graph.visitor.LevelOrderDependencyNodeConsumerVisitor;
96  import org.eclipse.aether.util.graph.visitor.PostorderDependencyNodeConsumerVisitor;
97  import org.eclipse.aether.util.graph.visitor.PreorderDependencyNodeConsumerVisitor;
98  import org.eclipse.aether.util.repository.ChainedLocalRepositoryManager;
99  
100 import static java.util.Objects.requireNonNull;
101 import static java.util.stream.Collectors.toList;
102 
103 /**
104  *
105  */
106 @Singleton
107 @Named
108 public class DefaultRepositorySystem implements RepositorySystem {
109     private final AtomicBoolean shutdown;
110 
111     private final AtomicInteger sessionIdCounter;
112 
113     private final VersionResolver versionResolver;
114 
115     private final VersionRangeResolver versionRangeResolver;
116 
117     private final ArtifactResolver artifactResolver;
118 
119     private final MetadataResolver metadataResolver;
120 
121     private final ArtifactDescriptorReader artifactDescriptorReader;
122 
123     private final DependencyCollector dependencyCollector;
124 
125     private final Installer installer;
126 
127     private final Deployer deployer;
128 
129     private final LocalRepositoryProvider localRepositoryProvider;
130 
131     private final SyncContextFactory syncContextFactory;
132 
133     private final RemoteRepositoryManager remoteRepositoryManager;
134 
135     private final RepositorySystemLifecycle repositorySystemLifecycle;
136 
137     private final Map<String, ArtifactDecoratorFactory> artifactDecoratorFactories;
138 
139     private final RepositorySystemValidator repositorySystemValidator;
140 
141     @SuppressWarnings("checkstyle:parameternumber")
142     @Inject
143     public DefaultRepositorySystem(
144             VersionResolver versionResolver,
145             VersionRangeResolver versionRangeResolver,
146             ArtifactResolver artifactResolver,
147             MetadataResolver metadataResolver,
148             ArtifactDescriptorReader artifactDescriptorReader,
149             DependencyCollector dependencyCollector,
150             Installer installer,
151             Deployer deployer,
152             LocalRepositoryProvider localRepositoryProvider,
153             SyncContextFactory syncContextFactory,
154             RemoteRepositoryManager remoteRepositoryManager,
155             RepositorySystemLifecycle repositorySystemLifecycle,
156             Map<String, ArtifactDecoratorFactory> artifactDecoratorFactories,
157             RepositorySystemValidator repositorySystemValidator) {
158         this.shutdown = new AtomicBoolean(false);
159         this.sessionIdCounter = new AtomicInteger(0);
160         this.versionResolver = requireNonNull(versionResolver, "version resolver cannot be null");
161         this.versionRangeResolver = requireNonNull(versionRangeResolver, "version range resolver cannot be null");
162         this.artifactResolver = requireNonNull(artifactResolver, "artifact resolver cannot be null");
163         this.metadataResolver = requireNonNull(metadataResolver, "metadata resolver cannot be null");
164         this.artifactDescriptorReader =
165                 requireNonNull(artifactDescriptorReader, "artifact descriptor reader cannot be null");
166         this.dependencyCollector = requireNonNull(dependencyCollector, "dependency collector cannot be null");
167         this.installer = requireNonNull(installer, "installer cannot be null");
168         this.deployer = requireNonNull(deployer, "deployer cannot be null");
169         this.localRepositoryProvider =
170                 requireNonNull(localRepositoryProvider, "local repository provider cannot be null");
171         this.syncContextFactory = requireNonNull(syncContextFactory, "sync context factory cannot be null");
172         this.remoteRepositoryManager =
173                 requireNonNull(remoteRepositoryManager, "remote repository provider cannot be null");
174         this.repositorySystemLifecycle =
175                 requireNonNull(repositorySystemLifecycle, "repository system lifecycle cannot be null");
176         this.artifactDecoratorFactories =
177                 requireNonNull(artifactDecoratorFactories, "artifact decorator factories cannot be null");
178         this.repositorySystemValidator =
179                 requireNonNull(repositorySystemValidator, "repository system validator cannot be null");
180     }
181 
182     @Override
183     public VersionResult resolveVersion(RepositorySystemSession session, VersionRequest request)
184             throws VersionResolutionException {
185         validateSession(session);
186         requireNonNull(request, "request cannot be null");
187         repositorySystemValidator.validateVersionRequest(session, request);
188         return versionResolver.resolveVersion(session, request);
189     }
190 
191     @Override
192     public VersionRangeResult resolveVersionRange(RepositorySystemSession session, VersionRangeRequest request)
193             throws VersionRangeResolutionException {
194         validateSession(session);
195         requireNonNull(request, "request cannot be null");
196         repositorySystemValidator.validateVersionRangeRequest(session, request);
197         return versionRangeResolver.resolveVersionRange(session, request);
198     }
199 
200     @Override
201     public ArtifactDescriptorResult readArtifactDescriptor(
202             RepositorySystemSession session, ArtifactDescriptorRequest request) throws ArtifactDescriptorException {
203         validateSession(session);
204         requireNonNull(request, "request cannot be null");
205         repositorySystemValidator.validateArtifactDescriptorRequest(session, request);
206         ArtifactDescriptorResult descriptorResult = artifactDescriptorReader.readArtifactDescriptor(session, request);
207         for (ArtifactDecorator decorator : Utils.getArtifactDecorators(session, artifactDecoratorFactories)) {
208             descriptorResult.setArtifact(decorator.decorateArtifact(descriptorResult));
209         }
210         return descriptorResult;
211     }
212 
213     @Override
214     public ArtifactResult resolveArtifact(RepositorySystemSession session, ArtifactRequest request)
215             throws ArtifactResolutionException {
216         validateSession(session);
217         requireNonNull(request, "request cannot be null");
218         repositorySystemValidator.validateArtifactRequests(session, Collections.singleton(request));
219         return artifactResolver.resolveArtifact(session, request);
220     }
221 
222     @Override
223     public List<ArtifactResult> resolveArtifacts(
224             RepositorySystemSession session, Collection<? extends ArtifactRequest> requests)
225             throws ArtifactResolutionException {
226         validateSession(session);
227         requireNonNull(requests, "requests cannot be null");
228         repositorySystemValidator.validateArtifactRequests(session, requests);
229         return artifactResolver.resolveArtifacts(session, requests);
230     }
231 
232     @Override
233     public List<MetadataResult> resolveMetadata(
234             RepositorySystemSession session, Collection<? extends MetadataRequest> requests) {
235         validateSession(session);
236         requireNonNull(requests, "requests cannot be null");
237         repositorySystemValidator.validateMetadataRequests(session, requests);
238         return metadataResolver.resolveMetadata(session, requests);
239     }
240 
241     @Override
242     public CollectResult collectDependencies(RepositorySystemSession session, CollectRequest request)
243             throws DependencyCollectionException {
244         validateSession(session);
245         requireNonNull(request, "request cannot be null");
246         repositorySystemValidator.validateCollectRequest(session, request);
247         return dependencyCollector.collectDependencies(session, request);
248     }
249 
250     @Override
251     public DependencyResult resolveDependencies(RepositorySystemSession session, DependencyRequest request)
252             throws DependencyResolutionException {
253         validateSession(session);
254         requireNonNull(request, "request cannot be null");
255         repositorySystemValidator.validateDependencyRequest(session, request);
256         RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
257 
258         DependencyResult result = new DependencyResult(request);
259 
260         DependencyCollectionException dce = null;
261         ArtifactResolutionException are = null;
262 
263         if (request.getRoot() != null) {
264             result.setRoot(request.getRoot());
265         } else if (request.getCollectRequest() != null) {
266             CollectResult collectResult;
267             try {
268                 request.getCollectRequest().setTrace(trace);
269                 collectResult = dependencyCollector.collectDependencies(session, request.getCollectRequest());
270             } catch (DependencyCollectionException e) {
271                 dce = e;
272                 collectResult = e.getResult();
273             }
274             result.setRoot(collectResult.getRoot());
275             result.setCycles(collectResult.getCycles());
276             result.setCollectExceptions(collectResult.getExceptions());
277         } else {
278             throw new NullPointerException("dependency node and collect request cannot be null");
279         }
280 
281         final List<DependencyNode> dependencyNodes =
282                 doFlattenDependencyNodes(session, result.getRoot(), request.getFilter());
283 
284         final List<ArtifactRequest> requests = dependencyNodes.stream()
285                 .map(n -> {
286                     if (n.getDependency() != null) {
287                         ArtifactRequest artifactRequest = new ArtifactRequest(n);
288                         artifactRequest.setTrace(trace);
289                         return artifactRequest;
290                     } else {
291                         return null;
292                     }
293                 })
294                 .filter(Objects::nonNull)
295                 .collect(Collectors.toList());
296         List<ArtifactResult> results;
297         try {
298             results = artifactResolver.resolveArtifacts(session, requests);
299         } catch (ArtifactResolutionException e) {
300             are = e;
301             results = e.getResults();
302         }
303         result.setDependencyNodeResults(dependencyNodes);
304         result.setArtifactResults(results);
305 
306         updateNodesWithResolvedArtifacts(results);
307 
308         if (dce != null) {
309             throw new DependencyResolutionException(result, dce);
310         } else if (are != null) {
311             throw new DependencyResolutionException(result, are);
312         }
313 
314         return result;
315     }
316 
317     @Override
318     public List<DependencyNode> flattenDependencyNodes(
319             RepositorySystemSession session, DependencyNode root, DependencyFilter dependencyFilter) {
320         validateSession(session);
321         requireNonNull(root, "root cannot be null");
322 
323         return doFlattenDependencyNodes(session, root, dependencyFilter);
324     }
325 
326     private List<DependencyNode> doFlattenDependencyNodes(
327             RepositorySystemSession session, DependencyNode root, DependencyFilter dependencyFilter) {
328         final ArrayList<DependencyNode> dependencyNodes = new ArrayList<>();
329         if (root != null) {
330             root.accept(getDependencyVisitor(session, dependencyNodes::add, dependencyFilter));
331         }
332         return dependencyNodes;
333     }
334 
335     private DependencyVisitor getDependencyVisitor(
336             RepositorySystemSession session, Consumer<DependencyNode> nodeConsumer, DependencyFilter dependencyFilter) {
337         String strategy = ConfigUtils.getString(
338                 session,
339                 ConfigurationProperties.DEFAULT_REPOSITORY_SYSTEM_DEPENDENCY_VISITOR,
340                 ConfigurationProperties.REPOSITORY_SYSTEM_DEPENDENCY_VISITOR);
341         switch (strategy) {
342             case PreorderDependencyNodeConsumerVisitor.NAME:
343                 return new PreorderDependencyNodeConsumerVisitor(nodeConsumer, dependencyFilter);
344             case PostorderDependencyNodeConsumerVisitor.NAME:
345                 return new PostorderDependencyNodeConsumerVisitor(nodeConsumer, dependencyFilter);
346             case LevelOrderDependencyNodeConsumerVisitor.NAME:
347                 return new LevelOrderDependencyNodeConsumerVisitor(nodeConsumer, dependencyFilter);
348             default:
349                 throw new IllegalArgumentException("Invalid dependency visitor strategy: " + strategy);
350         }
351     }
352 
353     private void updateNodesWithResolvedArtifacts(List<ArtifactResult> results) {
354         for (ArtifactResult result : results) {
355             Artifact artifact = result.getArtifact();
356             if (artifact != null) {
357                 result.getRequest().getDependencyNode().setArtifact(artifact);
358             }
359         }
360     }
361 
362     @Override
363     public InstallResult install(RepositorySystemSession session, InstallRequest request) throws InstallationException {
364         validateSession(session);
365         requireNonNull(request, "request cannot be null");
366         repositorySystemValidator.validateInstallRequest(session, request);
367         return installer.install(session, request);
368     }
369 
370     @Override
371     public DeployResult deploy(RepositorySystemSession session, DeployRequest request) throws DeploymentException {
372         validateSession(session);
373         requireNonNull(request, "request cannot be null");
374         repositorySystemValidator.validateDeployRequest(session, request);
375         return deployer.deploy(session, request);
376     }
377 
378     @Override
379     public LocalRepositoryManager newLocalRepositoryManager(
380             RepositorySystemSession session, LocalRepository localRepository) {
381         requireNonNull(session, "session cannot be null");
382         requireNonNull(localRepository, "localRepository cannot be null");
383         validateSystem();
384         repositorySystemValidator.validateLocalRepositories(session, Collections.singleton(localRepository));
385         return createLocalRepositoryManager(session, localRepository);
386     }
387 
388     @Override
389     public LocalRepositoryManager newLocalRepositoryManager(
390             RepositorySystemSession session, LocalRepository... localRepositories) {
391         requireNonNull(session, "session cannot be null");
392         requireNonNull(localRepositories, "localRepositories cannot be null");
393         validateSystem();
394         repositorySystemValidator.validateLocalRepositories(session, Arrays.asList(localRepositories));
395         return createLocalRepositoryManager(session, Arrays.asList(localRepositories));
396     }
397 
398     @Override
399     public LocalRepositoryManager newLocalRepositoryManager(
400             RepositorySystemSession session, List<LocalRepository> localRepositories) {
401         requireNonNull(session, "session cannot be null");
402         requireNonNull(localRepositories, "localRepositories cannot be null");
403         validateSystem();
404         repositorySystemValidator.validateLocalRepositories(session, localRepositories);
405         return createLocalRepositoryManager(session, localRepositories);
406     }
407 
408     private LocalRepositoryManager createLocalRepositoryManager(
409             RepositorySystemSession session, List<LocalRepository> localRepositories) {
410         if (localRepositories.isEmpty()) {
411             throw new IllegalArgumentException("empty localRepositories");
412         } else if (localRepositories.size() == 1) {
413             return createLocalRepositoryManager(session, localRepositories.get(0));
414         } else {
415             LocalRepositoryManager head = createLocalRepositoryManager(session, localRepositories.get(0));
416             List<LocalRepositoryManager> tail = localRepositories.subList(1, localRepositories.size()).stream()
417                     .map(l -> createLocalRepositoryManager(session, l))
418                     .collect(toList());
419             return new ChainedLocalRepositoryManager(head, tail, session);
420         }
421     }
422 
423     private LocalRepositoryManager createLocalRepositoryManager(
424             RepositorySystemSession session, LocalRepository localRepository) {
425         try {
426             return localRepositoryProvider.newLocalRepositoryManager(session, localRepository);
427         } catch (NoLocalRepositoryManagerException e) {
428             throw new IllegalArgumentException(e.getMessage(), e);
429         }
430     }
431 
432     @Override
433     public SyncContext newSyncContext(RepositorySystemSession session, boolean shared) {
434         validateSession(session);
435         return syncContextFactory.newInstance(session, shared);
436     }
437 
438     @Override
439     public List<RemoteRepository> newResolutionRepositories(
440             RepositorySystemSession session, List<RemoteRepository> repositories) {
441         validateSession(session);
442         validateRepositories(repositories);
443         repositorySystemValidator.validateRemoteRepositories(session, repositories);
444         repositories = remoteRepositoryManager.aggregateRepositories(session, new ArrayList<>(), repositories, true);
445         return repositories;
446     }
447 
448     @Override
449     public RemoteRepository newDeploymentRepository(RepositorySystemSession session, RemoteRepository repository) {
450         validateSession(session);
451         requireNonNull(repository, "repository cannot be null");
452         repositorySystemValidator.validateRemoteRepositories(session, Collections.singletonList(repository));
453         RemoteRepository.Builder builder = new RemoteRepository.Builder(repository);
454         Authentication auth = session.getAuthenticationSelector().getAuthentication(repository);
455         builder.setAuthentication(auth);
456         Proxy proxy = session.getProxySelector().getProxy(repository);
457         builder.setProxy(proxy);
458         return builder.build();
459     }
460 
461     @Override
462     public void addOnSystemEndedHandler(Runnable handler) {
463         validateSystem();
464         repositorySystemLifecycle.addOnSystemEndedHandler(handler);
465     }
466 
467     @Override
468     public RepositorySystemSession.SessionBuilder createSessionBuilder() {
469         validateSystem();
470         return new DefaultSessionBuilder(
471                 this, repositorySystemLifecycle, () -> "id-" + sessionIdCounter.incrementAndGet());
472     }
473 
474     @Override
475     public void shutdown() {
476         if (shutdown.compareAndSet(false, true)) {
477             repositorySystemLifecycle.systemEnded();
478         }
479     }
480 
481     private void validateSession(RepositorySystemSession session) {
482         requireNonNull(session, "repository system session cannot be null");
483         invalidSession(session.getLocalRepositoryManager(), "local repository manager");
484         invalidSession(session.getSystemProperties(), "system properties");
485         invalidSession(session.getUserProperties(), "user properties");
486         invalidSession(session.getConfigProperties(), "config properties");
487         invalidSession(session.getMirrorSelector(), "mirror selector");
488         invalidSession(session.getProxySelector(), "proxy selector");
489         invalidSession(session.getAuthenticationSelector(), "authentication selector");
490         invalidSession(session.getArtifactTypeRegistry(), "artifact type registry");
491         invalidSession(session.getData(), "data");
492         validateSystem();
493     }
494 
495     private void validateSystem() {
496         if (shutdown.get()) {
497             throw new IllegalStateException("repository system is already shut down");
498         }
499     }
500 
501     private void validateRepositories(List<RemoteRepository> repositories) {
502         requireNonNull(repositories, "repositories cannot be null");
503         for (RemoteRepository repository : repositories) {
504             requireNonNull(repository, "repository cannot be null");
505         }
506     }
507 
508     private void invalidSession(Object obj, String name) {
509         requireNonNull(obj, "repository system session's " + name + " cannot be null");
510     }
511 }