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