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.FilteringDependencyVisitor;
96  import org.eclipse.aether.util.graph.visitor.LevelOrderDependencyNodeConsumerVisitor;
97  import org.eclipse.aether.util.graph.visitor.PostorderDependencyNodeConsumerVisitor;
98  import org.eclipse.aether.util.graph.visitor.PreorderDependencyNodeConsumerVisitor;
99  import org.eclipse.aether.util.repository.ChainedLocalRepositoryManager;
100 
101 import static java.util.Objects.requireNonNull;
102 import static java.util.stream.Collectors.toList;
103 
104 /**
105  *
106  */
107 @Singleton
108 @Named
109 public class DefaultRepositorySystem implements RepositorySystem {
110     private final AtomicBoolean shutdown;
111 
112     private final AtomicInteger sessionIdCounter;
113 
114     private final VersionResolver versionResolver;
115 
116     private final VersionRangeResolver versionRangeResolver;
117 
118     private final ArtifactResolver artifactResolver;
119 
120     private final MetadataResolver metadataResolver;
121 
122     private final ArtifactDescriptorReader artifactDescriptorReader;
123 
124     private final DependencyCollector dependencyCollector;
125 
126     private final Installer installer;
127 
128     private final Deployer deployer;
129 
130     private final LocalRepositoryProvider localRepositoryProvider;
131 
132     private final SyncContextFactory syncContextFactory;
133 
134     private final RemoteRepositoryManager remoteRepositoryManager;
135 
136     private final RepositorySystemLifecycle repositorySystemLifecycle;
137 
138     private final Map<String, ArtifactDecoratorFactory> artifactDecoratorFactories;
139 
140     private final RepositorySystemValidator repositorySystemValidator;
141 
142     @SuppressWarnings("checkstyle:parameternumber")
143     @Inject
144     public DefaultRepositorySystem(
145             VersionResolver versionResolver,
146             VersionRangeResolver versionRangeResolver,
147             ArtifactResolver artifactResolver,
148             MetadataResolver metadataResolver,
149             ArtifactDescriptorReader artifactDescriptorReader,
150             DependencyCollector dependencyCollector,
151             Installer installer,
152             Deployer deployer,
153             LocalRepositoryProvider localRepositoryProvider,
154             SyncContextFactory syncContextFactory,
155             RemoteRepositoryManager remoteRepositoryManager,
156             RepositorySystemLifecycle repositorySystemLifecycle,
157             Map<String, ArtifactDecoratorFactory> artifactDecoratorFactories,
158             RepositorySystemValidator repositorySystemValidator) {
159         this.shutdown = new AtomicBoolean(false);
160         this.sessionIdCounter = new AtomicInteger(0);
161         this.versionResolver = requireNonNull(versionResolver, "version resolver cannot be null");
162         this.versionRangeResolver = requireNonNull(versionRangeResolver, "version range resolver cannot be null");
163         this.artifactResolver = requireNonNull(artifactResolver, "artifact resolver cannot be null");
164         this.metadataResolver = requireNonNull(metadataResolver, "metadata resolver cannot be null");
165         this.artifactDescriptorReader =
166                 requireNonNull(artifactDescriptorReader, "artifact descriptor reader cannot be null");
167         this.dependencyCollector = requireNonNull(dependencyCollector, "dependency collector cannot be null");
168         this.installer = requireNonNull(installer, "installer cannot be null");
169         this.deployer = requireNonNull(deployer, "deployer cannot be null");
170         this.localRepositoryProvider =
171                 requireNonNull(localRepositoryProvider, "local repository provider cannot be null");
172         this.syncContextFactory = requireNonNull(syncContextFactory, "sync context factory cannot be null");
173         this.remoteRepositoryManager =
174                 requireNonNull(remoteRepositoryManager, "remote repository provider cannot be null");
175         this.repositorySystemLifecycle =
176                 requireNonNull(repositorySystemLifecycle, "repository system lifecycle cannot be null");
177         this.artifactDecoratorFactories =
178                 requireNonNull(artifactDecoratorFactories, "artifact decorator factories cannot be null");
179         this.repositorySystemValidator =
180                 requireNonNull(repositorySystemValidator, "repository system validator cannot be null");
181     }
182 
183     @Override
184     public VersionResult resolveVersion(RepositorySystemSession session, VersionRequest request)
185             throws VersionResolutionException {
186         validateSession(session);
187         requireNonNull(request, "request cannot be null");
188         repositorySystemValidator.validateVersionRequest(session, request);
189         return versionResolver.resolveVersion(session, request);
190     }
191 
192     @Override
193     public VersionRangeResult resolveVersionRange(RepositorySystemSession session, VersionRangeRequest request)
194             throws VersionRangeResolutionException {
195         validateSession(session);
196         requireNonNull(request, "request cannot be null");
197         repositorySystemValidator.validateVersionRangeRequest(session, request);
198         return versionRangeResolver.resolveVersionRange(session, request);
199     }
200 
201     @Override
202     public ArtifactDescriptorResult readArtifactDescriptor(
203             RepositorySystemSession session, ArtifactDescriptorRequest request) throws ArtifactDescriptorException {
204         validateSession(session);
205         requireNonNull(request, "request cannot be null");
206         repositorySystemValidator.validateArtifactDescriptorRequest(session, request);
207         ArtifactDescriptorResult descriptorResult = artifactDescriptorReader.readArtifactDescriptor(session, request);
208         for (ArtifactDecorator decorator : Utils.getArtifactDecorators(session, artifactDecoratorFactories)) {
209             descriptorResult.setArtifact(decorator.decorateArtifact(descriptorResult));
210         }
211         return descriptorResult;
212     }
213 
214     @Override
215     public ArtifactResult resolveArtifact(RepositorySystemSession session, ArtifactRequest request)
216             throws ArtifactResolutionException {
217         validateSession(session);
218         requireNonNull(request, "request cannot be null");
219         repositorySystemValidator.validateArtifactRequests(session, Collections.singleton(request));
220         return artifactResolver.resolveArtifact(session, request);
221     }
222 
223     @Override
224     public List<ArtifactResult> resolveArtifacts(
225             RepositorySystemSession session, Collection<? extends ArtifactRequest> requests)
226             throws ArtifactResolutionException {
227         validateSession(session);
228         requireNonNull(requests, "requests cannot be null");
229         repositorySystemValidator.validateArtifactRequests(session, requests);
230         return artifactResolver.resolveArtifacts(session, requests);
231     }
232 
233     @Override
234     public List<MetadataResult> resolveMetadata(
235             RepositorySystemSession session, Collection<? extends MetadataRequest> requests) {
236         validateSession(session);
237         requireNonNull(requests, "requests cannot be null");
238         repositorySystemValidator.validateMetadataRequests(session, requests);
239         return metadataResolver.resolveMetadata(session, requests);
240     }
241 
242     @Override
243     public CollectResult collectDependencies(RepositorySystemSession session, CollectRequest request)
244             throws DependencyCollectionException {
245         validateSession(session);
246         requireNonNull(request, "request cannot be null");
247         repositorySystemValidator.validateCollectRequest(session, request);
248         return dependencyCollector.collectDependencies(session, request);
249     }
250 
251     @Override
252     public DependencyResult resolveDependencies(RepositorySystemSession session, DependencyRequest request)
253             throws DependencyResolutionException {
254         validateSession(session);
255         requireNonNull(request, "request cannot be null");
256         repositorySystemValidator.validateDependencyRequest(session, request);
257         RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
258 
259         DependencyResult result = new DependencyResult(request);
260 
261         DependencyCollectionException dce = null;
262         ArtifactResolutionException are = null;
263 
264         if (request.getRoot() != null) {
265             result.setRoot(request.getRoot());
266         } else if (request.getCollectRequest() != null) {
267             CollectResult collectResult;
268             try {
269                 request.getCollectRequest().setTrace(trace);
270                 collectResult = dependencyCollector.collectDependencies(session, request.getCollectRequest());
271             } catch (DependencyCollectionException e) {
272                 dce = e;
273                 collectResult = e.getResult();
274             }
275             result.setRoot(collectResult.getRoot());
276             result.setCycles(collectResult.getCycles());
277             result.setCollectExceptions(collectResult.getExceptions());
278         } else {
279             throw new NullPointerException("dependency node and collect request cannot be null");
280         }
281 
282         final List<DependencyNode> dependencyNodes =
283                 doFlattenDependencyNodes(session, result.getRoot(), request.getFilter());
284 
285         final List<ArtifactRequest> requests = dependencyNodes.stream()
286                 .map(n -> {
287                     if (n.getDependency() != null) {
288                         ArtifactRequest artifactRequest = new ArtifactRequest(n);
289                         artifactRequest.setTrace(trace);
290                         return artifactRequest;
291                     } else {
292                         return null;
293                     }
294                 })
295                 .filter(Objects::nonNull)
296                 .collect(Collectors.toList());
297         List<ArtifactResult> results;
298         try {
299             results = artifactResolver.resolveArtifacts(session, requests);
300         } catch (ArtifactResolutionException e) {
301             are = e;
302             results = e.getResults();
303         }
304         result.setDependencyNodeResults(dependencyNodes);
305         result.setArtifactResults(results);
306 
307         updateNodesWithResolvedArtifacts(results);
308 
309         if (dce != null) {
310             throw new DependencyResolutionException(result, dce);
311         } else if (are != null) {
312             throw new DependencyResolutionException(result, are);
313         }
314 
315         return result;
316     }
317 
318     @Override
319     public List<DependencyNode> flattenDependencyNodes(
320             RepositorySystemSession session, DependencyNode root, DependencyFilter dependencyFilter) {
321         validateSession(session);
322         requireNonNull(root, "root cannot be null");
323 
324         return doFlattenDependencyNodes(session, root, dependencyFilter);
325     }
326 
327     private List<DependencyNode> doFlattenDependencyNodes(
328             RepositorySystemSession session, DependencyNode root, DependencyFilter dependencyFilter) {
329         final ArrayList<DependencyNode> dependencyNodes = new ArrayList<>();
330         if (root != null) {
331             DependencyVisitor builder = getDependencyVisitor(session, dependencyNodes::add);
332             DependencyVisitor visitor =
333                     (dependencyFilter != null) ? new FilteringDependencyVisitor(builder, dependencyFilter) : builder;
334             root.accept(visitor);
335         }
336         return dependencyNodes;
337     }
338 
339     private DependencyVisitor getDependencyVisitor(
340             RepositorySystemSession session, Consumer<DependencyNode> nodeConsumer) {
341         String strategy = ConfigUtils.getString(
342                 session,
343                 ConfigurationProperties.REPOSITORY_SYSTEM_DEPENDENCY_VISITOR_PREORDER,
344                 ConfigurationProperties.REPOSITORY_SYSTEM_DEPENDENCY_VISITOR);
345         switch (strategy) {
346             case PreorderDependencyNodeConsumerVisitor.NAME:
347                 return new PreorderDependencyNodeConsumerVisitor(nodeConsumer);
348             case PostorderDependencyNodeConsumerVisitor.NAME:
349                 return new PostorderDependencyNodeConsumerVisitor(nodeConsumer);
350             case LevelOrderDependencyNodeConsumerVisitor.NAME:
351                 return new LevelOrderDependencyNodeConsumerVisitor(nodeConsumer);
352             default:
353                 throw new IllegalArgumentException("Invalid dependency visitor strategy: " + strategy);
354         }
355     }
356 
357     private void updateNodesWithResolvedArtifacts(List<ArtifactResult> results) {
358         for (ArtifactResult result : results) {
359             Artifact artifact = result.getArtifact();
360             if (artifact != null) {
361                 result.getRequest().getDependencyNode().setArtifact(artifact);
362             }
363         }
364     }
365 
366     @Override
367     public InstallResult install(RepositorySystemSession session, InstallRequest request) throws InstallationException {
368         validateSession(session);
369         requireNonNull(request, "request cannot be null");
370         repositorySystemValidator.validateInstallRequest(session, request);
371         return installer.install(session, request);
372     }
373 
374     @Override
375     public DeployResult deploy(RepositorySystemSession session, DeployRequest request) throws DeploymentException {
376         validateSession(session);
377         requireNonNull(request, "request cannot be null");
378         repositorySystemValidator.validateDeployRequest(session, request);
379         return deployer.deploy(session, request);
380     }
381 
382     @Override
383     public LocalRepositoryManager newLocalRepositoryManager(
384             RepositorySystemSession session, LocalRepository localRepository) {
385         requireNonNull(session, "session cannot be null");
386         requireNonNull(localRepository, "localRepository cannot be null");
387         validateSystem();
388         repositorySystemValidator.validateLocalRepositories(session, Collections.singleton(localRepository));
389         return createLocalRepositoryManager(session, localRepository);
390     }
391 
392     @Override
393     public LocalRepositoryManager newLocalRepositoryManager(
394             RepositorySystemSession session, LocalRepository... localRepositories) {
395         requireNonNull(session, "session cannot be null");
396         requireNonNull(localRepositories, "localRepositories cannot be null");
397         validateSystem();
398         repositorySystemValidator.validateLocalRepositories(session, Arrays.asList(localRepositories));
399         return createLocalRepositoryManager(session, Arrays.asList(localRepositories));
400     }
401 
402     @Override
403     public LocalRepositoryManager newLocalRepositoryManager(
404             RepositorySystemSession session, List<LocalRepository> localRepositories) {
405         requireNonNull(session, "session cannot be null");
406         requireNonNull(localRepositories, "localRepositories cannot be null");
407         validateSystem();
408         repositorySystemValidator.validateLocalRepositories(session, localRepositories);
409         return createLocalRepositoryManager(session, localRepositories);
410     }
411 
412     private LocalRepositoryManager createLocalRepositoryManager(
413             RepositorySystemSession session, List<LocalRepository> localRepositories) {
414         if (localRepositories.isEmpty()) {
415             throw new IllegalArgumentException("empty localRepositories");
416         } else if (localRepositories.size() == 1) {
417             return createLocalRepositoryManager(session, localRepositories.get(0));
418         } else {
419             LocalRepositoryManager head = createLocalRepositoryManager(session, localRepositories.get(0));
420             List<LocalRepositoryManager> tail = localRepositories.subList(1, localRepositories.size()).stream()
421                     .map(l -> createLocalRepositoryManager(session, l))
422                     .collect(toList());
423             return new ChainedLocalRepositoryManager(head, tail, session);
424         }
425     }
426 
427     private LocalRepositoryManager createLocalRepositoryManager(
428             RepositorySystemSession session, LocalRepository localRepository) {
429         try {
430             return localRepositoryProvider.newLocalRepositoryManager(session, localRepository);
431         } catch (NoLocalRepositoryManagerException e) {
432             throw new IllegalArgumentException(e.getMessage(), e);
433         }
434     }
435 
436     @Override
437     public SyncContext newSyncContext(RepositorySystemSession session, boolean shared) {
438         validateSession(session);
439         return syncContextFactory.newInstance(session, shared);
440     }
441 
442     @Override
443     public List<RemoteRepository> newResolutionRepositories(
444             RepositorySystemSession session, List<RemoteRepository> repositories) {
445         validateSession(session);
446         validateRepositories(repositories);
447         repositorySystemValidator.validateRemoteRepositories(session, repositories);
448         repositories = remoteRepositoryManager.aggregateRepositories(session, new ArrayList<>(), repositories, true);
449         return repositories;
450     }
451 
452     @Override
453     public RemoteRepository newDeploymentRepository(RepositorySystemSession session, RemoteRepository repository) {
454         validateSession(session);
455         requireNonNull(repository, "repository cannot be null");
456         repositorySystemValidator.validateRemoteRepositories(session, Collections.singletonList(repository));
457         RemoteRepository.Builder builder = new RemoteRepository.Builder(repository);
458         Authentication auth = session.getAuthenticationSelector().getAuthentication(repository);
459         builder.setAuthentication(auth);
460         Proxy proxy = session.getProxySelector().getProxy(repository);
461         builder.setProxy(proxy);
462         return builder.build();
463     }
464 
465     @Override
466     public void addOnSystemEndedHandler(Runnable handler) {
467         validateSystem();
468         repositorySystemLifecycle.addOnSystemEndedHandler(handler);
469     }
470 
471     @Override
472     public RepositorySystemSession.SessionBuilder createSessionBuilder() {
473         validateSystem();
474         return new DefaultSessionBuilder(
475                 this, repositorySystemLifecycle, () -> "id-" + sessionIdCounter.incrementAndGet());
476     }
477 
478     @Override
479     public void shutdown() {
480         if (shutdown.compareAndSet(false, true)) {
481             repositorySystemLifecycle.systemEnded();
482         }
483     }
484 
485     private void validateSession(RepositorySystemSession session) {
486         requireNonNull(session, "repository system session cannot be null");
487         invalidSession(session.getLocalRepositoryManager(), "local repository manager");
488         invalidSession(session.getSystemProperties(), "system properties");
489         invalidSession(session.getUserProperties(), "user properties");
490         invalidSession(session.getConfigProperties(), "config properties");
491         invalidSession(session.getMirrorSelector(), "mirror selector");
492         invalidSession(session.getProxySelector(), "proxy selector");
493         invalidSession(session.getAuthenticationSelector(), "authentication selector");
494         invalidSession(session.getArtifactTypeRegistry(), "artifact type registry");
495         invalidSession(session.getData(), "data");
496         validateSystem();
497     }
498 
499     private void validateSystem() {
500         if (shutdown.get()) {
501             throw new IllegalStateException("repository system is already shut down");
502         }
503     }
504 
505     private void validateRepositories(List<RemoteRepository> repositories) {
506         requireNonNull(repositories, "repositories cannot be null");
507         for (RemoteRepository repository : repositories) {
508             requireNonNull(repository, "repository cannot be null");
509         }
510     }
511 
512     private void invalidSession(Object obj, String name) {
513         requireNonNull(obj, "repository system session's " + name + " cannot be null");
514     }
515 }