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