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.apache.maven.internal.impl;
20  
21  import java.io.File;
22  import java.nio.file.Path;
23  import java.util.Arrays;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.NoSuchElementException;
29  import java.util.Objects;
30  import java.util.Optional;
31  import java.util.WeakHashMap;
32  import java.util.concurrent.ConcurrentHashMap;
33  import java.util.concurrent.CopyOnWriteArrayList;
34  import java.util.function.Supplier;
35  import java.util.stream.Collectors;
36  
37  import org.apache.maven.api.Artifact;
38  import org.apache.maven.api.ArtifactCoordinates;
39  import org.apache.maven.api.Dependency;
40  import org.apache.maven.api.DependencyCoordinates;
41  import org.apache.maven.api.DependencyScope;
42  import org.apache.maven.api.DownloadedArtifact;
43  import org.apache.maven.api.Exclusion;
44  import org.apache.maven.api.Language;
45  import org.apache.maven.api.Listener;
46  import org.apache.maven.api.LocalRepository;
47  import org.apache.maven.api.Node;
48  import org.apache.maven.api.Packaging;
49  import org.apache.maven.api.PathScope;
50  import org.apache.maven.api.PathType;
51  import org.apache.maven.api.ProducedArtifact;
52  import org.apache.maven.api.Project;
53  import org.apache.maven.api.ProjectScope;
54  import org.apache.maven.api.RemoteRepository;
55  import org.apache.maven.api.Service;
56  import org.apache.maven.api.Session;
57  import org.apache.maven.api.SessionData;
58  import org.apache.maven.api.Type;
59  import org.apache.maven.api.Version;
60  import org.apache.maven.api.VersionConstraint;
61  import org.apache.maven.api.VersionRange;
62  import org.apache.maven.api.annotations.Nonnull;
63  import org.apache.maven.api.annotations.Nullable;
64  import org.apache.maven.api.model.Repository;
65  import org.apache.maven.api.services.ArtifactCoordinatesFactory;
66  import org.apache.maven.api.services.ArtifactDeployer;
67  import org.apache.maven.api.services.ArtifactDeployerException;
68  import org.apache.maven.api.services.ArtifactFactory;
69  import org.apache.maven.api.services.ArtifactInstaller;
70  import org.apache.maven.api.services.ArtifactInstallerException;
71  import org.apache.maven.api.services.ArtifactManager;
72  import org.apache.maven.api.services.ArtifactResolver;
73  import org.apache.maven.api.services.ArtifactResolverException;
74  import org.apache.maven.api.services.DependencyCoordinatesFactory;
75  import org.apache.maven.api.services.DependencyResolver;
76  import org.apache.maven.api.services.DependencyResolverException;
77  import org.apache.maven.api.services.DependencyResolverRequest;
78  import org.apache.maven.api.services.LanguageRegistry;
79  import org.apache.maven.api.services.LocalRepositoryManager;
80  import org.apache.maven.api.services.Lookup;
81  import org.apache.maven.api.services.LookupException;
82  import org.apache.maven.api.services.PackagingRegistry;
83  import org.apache.maven.api.services.PathScopeRegistry;
84  import org.apache.maven.api.services.ProjectScopeRegistry;
85  import org.apache.maven.api.services.RepositoryFactory;
86  import org.apache.maven.api.services.TypeRegistry;
87  import org.apache.maven.api.services.VersionParser;
88  import org.apache.maven.api.services.VersionRangeResolver;
89  import org.apache.maven.api.services.VersionResolver;
90  import org.eclipse.aether.DefaultRepositorySystemSession;
91  import org.eclipse.aether.RepositorySystem;
92  import org.eclipse.aether.RepositorySystemSession;
93  import org.eclipse.aether.artifact.ArtifactType;
94  
95  import static org.apache.maven.internal.impl.Utils.map;
96  import static org.apache.maven.internal.impl.Utils.nonNull;
97  
98  public abstract class AbstractSession implements InternalSession {
99  
100     protected final RepositorySystemSession session;
101     protected final RepositorySystem repositorySystem;
102     protected final List<RemoteRepository> repositories;
103     protected final Lookup lookup;
104     private final Map<Class<? extends Service>, Service> services = new ConcurrentHashMap<>();
105     private final List<Listener> listeners = new CopyOnWriteArrayList<>();
106     private final Map<org.eclipse.aether.graph.DependencyNode, Node> allNodes =
107             Collections.synchronizedMap(new WeakHashMap<>());
108     private final Map<Class<? extends Artifact>, Map<org.eclipse.aether.artifact.Artifact, Artifact>> allArtifacts =
109             new ConcurrentHashMap<>();
110     private final Map<org.eclipse.aether.repository.RemoteRepository, RemoteRepository> allRepositories =
111             Collections.synchronizedMap(new WeakHashMap<>());
112     private final Map<org.eclipse.aether.graph.Dependency, Dependency> allDependencies =
113             Collections.synchronizedMap(new WeakHashMap<>());
114 
115     public AbstractSession(
116             RepositorySystemSession session,
117             RepositorySystem repositorySystem,
118             List<RemoteRepository> repositories,
119             List<org.eclipse.aether.repository.RemoteRepository> resolverRepositories,
120             Lookup lookup) {
121         this.session = nonNull(session, "session");
122         this.repositorySystem = repositorySystem;
123         this.repositories = getRepositories(repositories, resolverRepositories);
124         this.lookup = lookup;
125     }
126 
127     @Override
128     public RemoteRepository getRemoteRepository(org.eclipse.aether.repository.RemoteRepository repository) {
129         return allRepositories.computeIfAbsent(repository, DefaultRemoteRepository::new);
130     }
131 
132     @Override
133     public Node getNode(org.eclipse.aether.graph.DependencyNode node) {
134         return getNode(node, false);
135     }
136 
137     @Override
138     public Node getNode(org.eclipse.aether.graph.DependencyNode node, boolean verbose) {
139         return allNodes.computeIfAbsent(node, n -> new DefaultNode(this, n, verbose));
140     }
141 
142     @Nonnull
143     @Override
144     public Artifact getArtifact(@Nonnull org.eclipse.aether.artifact.Artifact artifact) {
145         return getArtifact(Artifact.class, artifact);
146     }
147 
148     @SuppressWarnings("unchecked")
149     @Override
150     public <T extends Artifact> T getArtifact(Class<T> clazz, org.eclipse.aether.artifact.Artifact artifact) {
151         Map<org.eclipse.aether.artifact.Artifact, Artifact> map =
152                 allArtifacts.computeIfAbsent(clazz, c -> Collections.synchronizedMap(new WeakHashMap<>()));
153         if (clazz == Artifact.class) {
154             return (T) map.computeIfAbsent(artifact, a -> new DefaultArtifact(this, a));
155         } else if (clazz == DownloadedArtifact.class) {
156             if (artifact.getPath() == null) {
157                 throw new IllegalArgumentException("The given artifact is not resolved");
158             } else {
159                 return (T) map.computeIfAbsent(artifact, a -> new DefaultDownloadedArtifact(this, a));
160             }
161         } else if (clazz == ProducedArtifact.class) {
162             return (T) map.computeIfAbsent(artifact, a -> new DefaultProducedArtifact(this, a));
163         } else {
164             throw new IllegalArgumentException("Unsupported Artifact class: " + clazz);
165         }
166     }
167 
168     @Nonnull
169     @Override
170     public Dependency getDependency(@Nonnull org.eclipse.aether.graph.Dependency dependency) {
171         return allDependencies.computeIfAbsent(dependency, d -> new DefaultDependency(this, d));
172     }
173 
174     @Override
175     public List<org.eclipse.aether.repository.RemoteRepository> toRepositories(List<RemoteRepository> repositories) {
176         return repositories == null ? null : map(repositories, this::toRepository);
177     }
178 
179     @Override
180     public org.eclipse.aether.repository.RemoteRepository toRepository(RemoteRepository repository) {
181         if (repository instanceof DefaultRemoteRepository) {
182             return ((DefaultRemoteRepository) repository).getRepository();
183         } else {
184             // TODO
185             throw new UnsupportedOperationException("Not implemented yet");
186         }
187     }
188 
189     @Override
190     public org.eclipse.aether.repository.LocalRepository toRepository(LocalRepository repository) {
191         if (repository instanceof DefaultLocalRepository) {
192             return ((DefaultLocalRepository) repository).getRepository();
193         } else {
194             // TODO
195             throw new UnsupportedOperationException("Not implemented yet");
196         }
197     }
198 
199     @Override
200     public List<org.eclipse.aether.graph.Dependency> toDependencies(
201             Collection<DependencyCoordinates> dependencies, boolean managed) {
202         return dependencies == null ? null : map(dependencies, d -> toDependency(d, managed));
203     }
204 
205     static List<RemoteRepository> getRepositories(
206             List<RemoteRepository> repositories,
207             List<org.eclipse.aether.repository.RemoteRepository> resolverRepositories) {
208         if (repositories != null) {
209             return repositories;
210         } else if (resolverRepositories != null) {
211             return map(resolverRepositories, DefaultRemoteRepository::new);
212         } else {
213             throw new IllegalArgumentException("no remote repositories provided");
214         }
215     }
216 
217     @Nonnull
218     @Override
219     public List<RemoteRepository> getRemoteRepositories() {
220         return Collections.unmodifiableList(repositories);
221     }
222 
223     @Nonnull
224     @Override
225     public SessionData getData() {
226         org.eclipse.aether.SessionData data = session.getData();
227         return new SessionData() {
228             @Override
229             public <T> void set(@Nonnull Key<T> key, @Nullable T value) {
230                 data.set(key, value);
231             }
232 
233             @Override
234             public <T> boolean replace(@Nonnull Key<T> key, @Nullable T oldValue, @Nullable T newValue) {
235                 return data.set(key, oldValue, newValue);
236             }
237 
238             @Nullable
239             @Override
240             @SuppressWarnings("unchecked")
241             public <T> T get(@Nonnull Key<T> key) {
242                 return (T) data.get(key);
243             }
244 
245             @Nullable
246             @Override
247             @SuppressWarnings("unchecked")
248             public <T> T computeIfAbsent(@Nonnull Key<T> key, @Nonnull Supplier<T> supplier) {
249                 return (T) data.computeIfAbsent(key, (Supplier<Object>) supplier);
250             }
251         };
252     }
253 
254     @Nonnull
255     @Override
256     public LocalRepository getLocalRepository() {
257         return new DefaultLocalRepository(session.getLocalRepository());
258     }
259 
260     @Nonnull
261     @Override
262     public Session withLocalRepository(@Nonnull LocalRepository localRepository) {
263         nonNull(localRepository, "localRepository");
264         if (session.getLocalRepository() != null
265                 && Objects.equals(session.getLocalRepository().getBasePath(), localRepository.getPath())) {
266             return this;
267         }
268         org.eclipse.aether.repository.LocalRepository repository = toRepository(localRepository);
269         org.eclipse.aether.repository.LocalRepositoryManager localRepositoryManager =
270                 repositorySystem.newLocalRepositoryManager(session, repository);
271 
272         RepositorySystemSession repoSession =
273                 new DefaultRepositorySystemSession(session).setLocalRepositoryManager(localRepositoryManager);
274         return newSession(repoSession, repositories);
275     }
276 
277     @Nonnull
278     @Override
279     public Session withRemoteRepositories(@Nonnull List<RemoteRepository> repositories) {
280         return newSession(session, repositories);
281     }
282 
283     protected abstract Session newSession(RepositorySystemSession session, List<RemoteRepository> repositories);
284 
285     @Nonnull
286     @Override
287     @SuppressWarnings("unchecked")
288     public <T extends Service> T getService(Class<T> clazz) throws NoSuchElementException {
289         T t = (T) services.computeIfAbsent(clazz, this::lookup);
290         if (t == null) {
291             throw new NoSuchElementException(clazz.getName());
292         }
293         return t;
294     }
295 
296     private Service lookup(Class<? extends Service> c) {
297         try {
298             return lookup.lookup(c);
299         } catch (LookupException e) {
300             throw new NoSuchElementException(c.getName(), e);
301         }
302     }
303 
304     @Nonnull
305     @Override
306     public RepositorySystemSession getSession() {
307         return session;
308     }
309 
310     @Nonnull
311     @Override
312     public RepositorySystem getRepositorySystem() {
313         return repositorySystem;
314     }
315 
316     @Override
317     public org.eclipse.aether.graph.Dependency toDependency(DependencyCoordinates dependency, boolean managed) {
318         org.eclipse.aether.graph.Dependency dep;
319         if (dependency instanceof AetherDependencyWrapper wrapper) {
320             dep = wrapper.dependency;
321         } else {
322             Type type = dependency.getType();
323             dep = new org.eclipse.aether.graph.Dependency(
324                     new org.eclipse.aether.artifact.DefaultArtifact(
325                             dependency.getGroupId(),
326                             dependency.getArtifactId(),
327                             dependency.getClassifier(),
328                             type.getExtension(),
329                             dependency.getVersionConstraint().toString(),
330                             Map.of("type", type.id()),
331                             (ArtifactType) null),
332                     dependency.getScope().id(),
333                     dependency.getOptional(),
334                     map(dependency.getExclusions(), this::toExclusion));
335         }
336         if (!managed && "".equals(dep.getScope())) {
337             dep = dep.setScope(DependencyScope.COMPILE.id());
338         }
339         return dep;
340     }
341 
342     private org.eclipse.aether.graph.Exclusion toExclusion(Exclusion exclusion) {
343         return new org.eclipse.aether.graph.Exclusion(exclusion.getGroupId(), exclusion.getArtifactId(), "*", "*");
344     }
345 
346     @Override
347     public List<org.eclipse.aether.artifact.Artifact> toArtifacts(Collection<Artifact> artifacts) {
348         return artifacts == null ? null : map(artifacts, this::toArtifact);
349     }
350 
351     @Override
352     public org.eclipse.aether.artifact.Artifact toArtifact(Artifact artifact) {
353         Path path = getService(ArtifactManager.class).getPath(artifact).orElse(null);
354         if (artifact instanceof DefaultArtifact) {
355             org.eclipse.aether.artifact.Artifact a = ((DefaultArtifact) artifact).getArtifact();
356             if (Objects.equals(path, a.getPath())) {
357                 return a;
358             }
359         }
360         return new org.eclipse.aether.artifact.DefaultArtifact(
361                 artifact.getGroupId(),
362                 artifact.getArtifactId(),
363                 artifact.getClassifier(),
364                 artifact.getExtension(),
365                 artifact.getVersion().toString(),
366                 null,
367                 path);
368     }
369 
370     @Override
371     public org.eclipse.aether.artifact.Artifact toArtifact(ArtifactCoordinates coords) {
372         if (coords instanceof DefaultArtifactCoordinates) {
373             return ((DefaultArtifactCoordinates) coords).getCoordinates();
374         }
375         return new org.eclipse.aether.artifact.DefaultArtifact(
376                 coords.getGroupId(),
377                 coords.getArtifactId(),
378                 coords.getClassifier(),
379                 coords.getExtension(),
380                 coords.getVersionConstraint().toString(),
381                 null,
382                 (File) null);
383     }
384 
385     @Override
386     public void registerListener(@Nonnull Listener listener) {
387         listeners.add(nonNull(listener));
388     }
389 
390     @Override
391     public void unregisterListener(@Nonnull Listener listener) {
392         listeners.remove(nonNull(listener));
393     }
394 
395     @Nonnull
396     @Override
397     public Collection<Listener> getListeners() {
398         return Collections.unmodifiableCollection(listeners);
399     }
400 
401     //
402     // Shortcut implementations
403     //
404 
405     /**
406      * Shortcut for <code>getService(RepositoryFactory.class).createLocal(...)</code>
407      *
408      * @see RepositoryFactory#createLocal(Path)
409      */
410     @Override
411     public LocalRepository createLocalRepository(Path path) {
412         return getService(RepositoryFactory.class).createLocal(path);
413     }
414 
415     /**
416      * Shortcut for <code>getService(RepositoryFactory.class).createRemote(...)</code>
417      *
418      * @see RepositoryFactory#createRemote(String, String)
419      */
420     @Nonnull
421     @Override
422     public RemoteRepository createRemoteRepository(@Nonnull String id, @Nonnull String url) {
423         return getService(RepositoryFactory.class).createRemote(id, url);
424     }
425 
426     /**
427      * Shortcut for <code>getService(RepositoryFactory.class).createRemote(...)</code>
428      *
429      * @see RepositoryFactory#createRemote(Repository)
430      */
431     @Nonnull
432     @Override
433     public RemoteRepository createRemoteRepository(@Nonnull Repository repository) {
434         return getService(RepositoryFactory.class).createRemote(repository);
435     }
436 
437     /**
438      * Shortcut for <code>getService(ArtifactCoordinatesFactory.class).create(...)</code>
439      *
440      * @see ArtifactFactory#create(Session, String, String, String, String)
441      */
442     @Override
443     public ArtifactCoordinates createArtifactCoordinates(
444             String groupId, String artifactId, String version, String extension) {
445         return getService(ArtifactCoordinatesFactory.class).create(this, groupId, artifactId, version, extension);
446     }
447 
448     /**
449      * Shortcut for <code>getService(ArtifactCoordinatesFactory.class).create(...)</code>
450      *
451      * @see ArtifactCoordinatesFactory#create(Session, String)
452      */
453     @Override
454     public ArtifactCoordinates createArtifactCoordinates(String coordString) {
455         return getService(ArtifactCoordinatesFactory.class).create(this, coordString);
456     }
457 
458     /**
459      * Shortcut for <code>getService(ArtifactCoordinatesFactory.class).create(...)</code>
460      *
461      * @see ArtifactCoordinatesFactory#create(Session, String, String, String, String, String, String)
462      */
463     @Override
464     public ArtifactCoordinates createArtifactCoordinates(
465             String groupId, String artifactId, String version, String classifier, String extension, String type) {
466         return getService(ArtifactCoordinatesFactory.class)
467                 .create(this, groupId, artifactId, version, classifier, extension, type);
468     }
469 
470     /**
471      * Shortcut for <code>getService(ArtifactCoordinatesFactory.class).create(...)</code>
472      *
473      * @see ArtifactCoordinatesFactory#create(Session, String, String, String, String, String, String)
474      */
475     @Override
476     public ArtifactCoordinates createArtifactCoordinates(Artifact artifact) {
477         return getService(ArtifactCoordinatesFactory.class)
478                 .create(
479                         this,
480                         artifact.getGroupId(),
481                         artifact.getArtifactId(),
482                         artifact.getVersion().asString(),
483                         artifact.getClassifier(),
484                         artifact.getExtension(),
485                         null);
486     }
487 
488     /**
489      * Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
490      *
491      * @see ArtifactFactory#create(Session, String, String, String, String)
492      */
493     @Override
494     public Artifact createArtifact(String groupId, String artifactId, String version, String extension) {
495         return getService(ArtifactFactory.class).create(this, groupId, artifactId, version, extension);
496     }
497 
498     /**
499      * Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
500      *
501      * @see ArtifactFactory#create(Session, String, String, String, String, String, String)
502      */
503     @Override
504     public Artifact createArtifact(
505             String groupId, String artifactId, String version, String classifier, String extension, String type) {
506         return getService(ArtifactFactory.class)
507                 .create(this, groupId, artifactId, version, classifier, extension, type);
508     }
509 
510     /**
511      * Shortcut for <code>getService(ArtifactFactory.class).createProduced(...)</code>
512      *
513      * @see ArtifactFactory#createProduced(Session, String, String, String, String)
514      */
515     @Override
516     public ProducedArtifact createProducedArtifact(
517             String groupId, String artifactId, String version, String extension) {
518         return getService(ArtifactFactory.class).createProduced(this, groupId, artifactId, version, extension);
519     }
520 
521     /**
522      * Shortcut for <code>getService(ArtifactFactory.class).createProduced(...)</code>
523      *
524      * @see ArtifactFactory#createProduced(Session, String, String, String, String, String, String)
525      */
526     @Override
527     public ProducedArtifact createProducedArtifact(
528             String groupId, String artifactId, String version, String classifier, String extension, String type) {
529         return getService(ArtifactFactory.class)
530                 .createProduced(this, groupId, artifactId, version, classifier, extension, type);
531     }
532 
533     /**
534      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
535      *
536      * @throws ArtifactResolverException if the artifact resolution failed
537      * @see ArtifactResolver#resolve(Session, Collection)
538      */
539     @Override
540     public DownloadedArtifact resolveArtifact(ArtifactCoordinates coordinates) {
541         return getService(ArtifactResolver.class)
542                 .resolve(this, Collections.singletonList(coordinates))
543                 .getArtifacts()
544                 .iterator()
545                 .next();
546     }
547 
548     /**
549      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
550      *
551      * @throws ArtifactResolverException if the artifact resolution failed
552      * @see ArtifactResolver#resolve(Session, Collection)
553      */
554     @Override
555     public DownloadedArtifact resolveArtifact(ArtifactCoordinates coordinates, List<RemoteRepository> repositories) {
556         return getService(ArtifactResolver.class)
557                 .resolve(this, Collections.singletonList(coordinates), repositories)
558                 .getArtifacts()
559                 .iterator()
560                 .next();
561     }
562 
563     /**
564      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
565      *
566      * @throws ArtifactResolverException if the artifact resolution failed
567      * @see ArtifactResolver#resolve(Session, Collection)
568      */
569     @Override
570     public Collection<DownloadedArtifact> resolveArtifacts(ArtifactCoordinates... coordinates) {
571         return resolveArtifacts(Arrays.asList(coordinates));
572     }
573 
574     /**
575      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
576      *
577      * @throws ArtifactResolverException if the artifact resolution failed
578      * @see ArtifactResolver#resolve(Session, Collection)
579      */
580     @Override
581     public Collection<DownloadedArtifact> resolveArtifacts(Collection<? extends ArtifactCoordinates> coordinates) {
582         return getService(ArtifactResolver.class).resolve(this, coordinates).getArtifacts();
583     }
584 
585     /**
586      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
587      *
588      * @throws ArtifactResolverException if the artifact resolution failed
589      * @see ArtifactResolver#resolve(Session, Collection)
590      */
591     @Override
592     public Collection<DownloadedArtifact> resolveArtifacts(
593             Collection<? extends ArtifactCoordinates> coordinates, List<RemoteRepository> repositories) {
594         return getService(ArtifactResolver.class)
595                 .resolve(this, coordinates, repositories)
596                 .getArtifacts();
597     }
598 
599     /**
600      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
601      *
602      * @throws ArtifactResolverException if the artifact resolution failed
603      * @see ArtifactResolver#resolve(Session, Collection)
604      */
605     @Override
606     public DownloadedArtifact resolveArtifact(Artifact artifact) {
607         ArtifactCoordinates coordinates =
608                 getService(ArtifactCoordinatesFactory.class).create(this, artifact);
609         return resolveArtifact(coordinates);
610     }
611 
612     /**
613      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
614      *
615      * @throws ArtifactResolverException if the artifact resolution failed
616      * @see ArtifactResolver#resolve(Session, Collection)
617      */
618     @Override
619     public DownloadedArtifact resolveArtifact(Artifact artifact, List<RemoteRepository> repositories) {
620         ArtifactCoordinates coordinates =
621                 getService(ArtifactCoordinatesFactory.class).create(this, artifact);
622         return resolveArtifact(coordinates, repositories);
623     }
624 
625     @Override
626     public Collection<DownloadedArtifact> resolveArtifacts(Artifact... artifacts) {
627         ArtifactCoordinatesFactory acf = getService(ArtifactCoordinatesFactory.class);
628         List<ArtifactCoordinates> coords =
629                 Arrays.stream(artifacts).map(a -> acf.create(this, a)).collect(Collectors.toList());
630         return resolveArtifacts(coords);
631     }
632 
633     /**
634      * Shortcut for {@code getService(ArtifactInstaller.class).install(...)}
635      *
636      * @throws ArtifactInstallerException if the artifacts installation failed
637      * @see ArtifactInstaller#install(Session, Collection)
638      */
639     @Override
640     public void installArtifacts(Artifact... artifacts) {
641         installArtifacts(Arrays.asList(artifacts));
642     }
643 
644     /**
645      * Shortcut for {@code getService(ArtifactInstaller.class).install(...)}
646      *
647      * @throws ArtifactInstallerException if the artifacts installation failed
648      * @see ArtifactInstaller#install(Session, Collection)
649      */
650     @Override
651     public void installArtifacts(Collection<Artifact> artifacts) {
652         getService(ArtifactInstaller.class).install(this, artifacts);
653     }
654 
655     /**
656      * Shortcut for <code>getService(ArtifactDeployer.class).deploy(...)</code>
657      *
658      * @throws ArtifactDeployerException if the artifacts deployment failed
659      * @see ArtifactDeployer#deploy(Session, RemoteRepository, Collection)
660      */
661     @Override
662     public void deployArtifact(RemoteRepository repository, Artifact... artifacts) {
663         getService(ArtifactDeployer.class).deploy(this, repository, Arrays.asList(artifacts));
664     }
665 
666     /**
667      * Shortcut for <code>getService(ArtifactManager.class).setPath(...)</code>
668      *
669      * @see ArtifactManager#setPath(ProducedArtifact, Path)
670      */
671     @Override
672     public void setArtifactPath(@Nonnull ProducedArtifact artifact, @Nonnull Path path) {
673         getService(ArtifactManager.class).setPath(artifact, path);
674     }
675 
676     /**
677      * Shortcut for <code>getService(ArtifactManager.class).getPath(...)</code>
678      *
679      * @see ArtifactManager#getPath(Artifact)
680      */
681     @Nonnull
682     @Override
683     public Optional<Path> getArtifactPath(@Nonnull Artifact artifact) {
684         return getService(ArtifactManager.class).getPath(artifact);
685     }
686 
687     /**
688      * Shortcut for <code>getService(VersionParser.class).isSnapshot(...)</code>
689      *
690      * @see VersionParser#isSnapshot(String)
691      */
692     @Override
693     public boolean isVersionSnapshot(@Nonnull String version) {
694         return getService(VersionParser.class).isSnapshot(version);
695     }
696 
697     /**
698      * Shortcut for <code>getService(DependencyFactory.class).create(...)</code>
699      *
700      * @see DependencyCoordinatesFactory#create(Session, ArtifactCoordinates)
701      */
702     @Nonnull
703     @Override
704     public DependencyCoordinates createDependencyCoordinates(@Nonnull ArtifactCoordinates coordinates) {
705         return getService(DependencyCoordinatesFactory.class).create(this, coordinates);
706     }
707 
708     /**
709      * Shortcut for <code>getService(DependencyFactory.class).create(...)</code>
710      *
711      * @see DependencyCoordinatesFactory#create(Session, ArtifactCoordinates)
712      */
713     @Nonnull
714     @Override
715     public DependencyCoordinates createDependencyCoordinates(@Nonnull Dependency dependency) {
716         return getService(DependencyCoordinatesFactory.class).create(this, dependency);
717     }
718 
719     /**
720      * Shortcut for <code>getService(DependencyResolver.class).collect(...)</code>
721      *
722      * @throws DependencyResolverException if the dependency collection failed
723      * @see DependencyResolver#collect(Session, Artifact, PathScope)
724      */
725     @Nonnull
726     @Override
727     public Node collectDependencies(@Nonnull Artifact artifact, @Nonnull PathScope scope) {
728         return getService(DependencyResolver.class)
729                 .collect(this, artifact, scope)
730                 .getRoot();
731     }
732 
733     /**
734      * Shortcut for <code>getService(DependencyResolver.class).collect(...)</code>
735      *
736      * @throws DependencyResolverException if the dependency collection failed
737      * @see DependencyResolver#collect(Session, Project, PathScope)
738      */
739     @Nonnull
740     @Override
741     public Node collectDependencies(@Nonnull Project project, @Nonnull PathScope scope) {
742         return getService(DependencyResolver.class)
743                 .collect(this, project, scope)
744                 .getRoot();
745     }
746 
747     /**
748      * Shortcut for <code>getService(DependencyResolver.class).collect(...)</code>
749      *
750      * @throws DependencyResolverException if the dependency collection failed
751      * @see DependencyResolver#collect(Session, DependencyCoordinates, PathScope)
752      */
753     @Nonnull
754     @Override
755     public Node collectDependencies(@Nonnull DependencyCoordinates dependency, @Nonnull PathScope scope) {
756         Node root = getService(DependencyResolver.class)
757                 .collect(this, dependency, scope)
758                 .getRoot();
759         return root.getChildren().iterator().next();
760     }
761 
762     @Nonnull
763     @Override
764     public List<Node> flattenDependencies(@Nonnull Node node, @Nonnull PathScope scope) {
765         return getService(DependencyResolver.class).flatten(this, node, scope);
766     }
767 
768     @Override
769     public List<Path> resolveDependencies(DependencyCoordinates dependency) {
770         return getService(DependencyResolver.class).resolve(this, dependency).getPaths();
771     }
772 
773     @Override
774     public List<Path> resolveDependencies(List<DependencyCoordinates> dependencies) {
775         return getService(DependencyResolver.class).resolve(this, dependencies).getPaths();
776     }
777 
778     @Override
779     public List<Path> resolveDependencies(Project project, PathScope scope) {
780         return getService(DependencyResolver.class)
781                 .resolve(this, project, scope)
782                 .getPaths();
783     }
784 
785     @Override
786     public Map<PathType, List<Path>> resolveDependencies(
787             @Nonnull DependencyCoordinates dependency,
788             @Nonnull PathScope scope,
789             @Nonnull Collection<PathType> desiredTypes) {
790         return getService(DependencyResolver.class)
791                 .resolve(DependencyResolverRequest.builder()
792                         .session(this)
793                         .requestType(DependencyResolverRequest.RequestType.RESOLVE)
794                         .dependency(dependency)
795                         .pathScope(scope)
796                         .pathTypeFilter(desiredTypes)
797                         .build())
798                 .getDispatchedPaths();
799     }
800 
801     @Override
802     public Map<PathType, List<Path>> resolveDependencies(
803             @Nonnull Project project, @Nonnull PathScope scope, @Nonnull Collection<PathType> desiredTypes) {
804         return getService(DependencyResolver.class)
805                 .resolve(DependencyResolverRequest.builder()
806                         .session(this)
807                         .requestType(DependencyResolverRequest.RequestType.RESOLVE)
808                         .project(project)
809                         .pathScope(scope)
810                         .pathTypeFilter(desiredTypes)
811                         .build())
812                 .getDispatchedPaths();
813     }
814 
815     @Override
816     public Path getPathForLocalArtifact(@Nonnull Artifact artifact) {
817         return getService(LocalRepositoryManager.class).getPathForLocalArtifact(this, getLocalRepository(), artifact);
818     }
819 
820     @Override
821     public Path getPathForRemoteArtifact(RemoteRepository remote, Artifact artifact) {
822         return getService(LocalRepositoryManager.class)
823                 .getPathForRemoteArtifact(this, getLocalRepository(), remote, artifact);
824     }
825 
826     @Override
827     public Version parseVersion(String version) {
828         return getService(VersionParser.class).parseVersion(version);
829     }
830 
831     @Override
832     public VersionRange parseVersionRange(String versionRange) {
833         return getService(VersionParser.class).parseVersionRange(versionRange);
834     }
835 
836     @Override
837     public VersionConstraint parseVersionConstraint(String versionConstraint) {
838         return getService(VersionParser.class).parseVersionConstraint(versionConstraint);
839     }
840 
841     @Override
842     public Version resolveVersion(ArtifactCoordinates artifact) {
843         return getService(VersionResolver.class).resolve(this, artifact).getVersion();
844     }
845 
846     @Override
847     public List<Version> resolveVersionRange(ArtifactCoordinates artifact) {
848         return getService(VersionRangeResolver.class).resolve(this, artifact).getVersions();
849     }
850 
851     @Override
852     public List<Version> resolveVersionRange(ArtifactCoordinates artifact, List<RemoteRepository> repositories) {
853         return getService(VersionRangeResolver.class)
854                 .resolve(this, artifact, repositories)
855                 .getVersions();
856     }
857 
858     @Override
859     public Type requireType(String id) {
860         return getService(TypeRegistry.class).require(id);
861     }
862 
863     @Override
864     public Language requireLanguage(String id) {
865         return getService(LanguageRegistry.class).require(id);
866     }
867 
868     @Override
869     public Packaging requirePackaging(String id) {
870         return getService(PackagingRegistry.class).require(id);
871     }
872 
873     @Override
874     public ProjectScope requireProjectScope(String id) {
875         return getService(ProjectScopeRegistry.class).require(id);
876     }
877 
878     @Override
879     public DependencyScope requireDependencyScope(String id) {
880         return DependencyScope.forId(nonNull(id, "id"));
881     }
882 
883     @Override
884     public PathScope requirePathScope(String id) {
885         return getService(PathScopeRegistry.class).require(id);
886     }
887 }