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