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