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             NoSuchElementException nsee = new NoSuchElementException(c.getName());
301             e.initCause(e);
302             throw nsee;
303         }
304     }
305 
306     @Nonnull
307     @Override
308     public RepositorySystemSession getSession() {
309         return session;
310     }
311 
312     @Nonnull
313     @Override
314     public RepositorySystem getRepositorySystem() {
315         return repositorySystem;
316     }
317 
318     @Override
319     public org.eclipse.aether.graph.Dependency toDependency(DependencyCoordinates dependency, boolean managed) {
320         org.eclipse.aether.graph.Dependency dep;
321         if (dependency instanceof AetherDependencyWrapper wrapper) {
322             dep = wrapper.dependency;
323         } else {
324             Type type = dependency.getType();
325             dep = new org.eclipse.aether.graph.Dependency(
326                     new org.eclipse.aether.artifact.DefaultArtifact(
327                             dependency.getGroupId(),
328                             dependency.getArtifactId(),
329                             dependency.getClassifier(),
330                             type.getExtension(),
331                             dependency.getVersionConstraint().toString(),
332                             Map.of("type", type.id()),
333                             (ArtifactType) null),
334                     dependency.getScope().id(),
335                     dependency.getOptional(),
336                     map(dependency.getExclusions(), this::toExclusion));
337         }
338         if (!managed && "".equals(dep.getScope())) {
339             dep = dep.setScope(DependencyScope.COMPILE.id());
340         }
341         return dep;
342     }
343 
344     private org.eclipse.aether.graph.Exclusion toExclusion(Exclusion exclusion) {
345         return new org.eclipse.aether.graph.Exclusion(exclusion.getGroupId(), exclusion.getArtifactId(), "*", "*");
346     }
347 
348     @Override
349     public List<org.eclipse.aether.artifact.Artifact> toArtifacts(Collection<Artifact> artifacts) {
350         return artifacts == null ? null : map(artifacts, this::toArtifact);
351     }
352 
353     @Override
354     public org.eclipse.aether.artifact.Artifact toArtifact(Artifact artifact) {
355         Path path = getService(ArtifactManager.class).getPath(artifact).orElse(null);
356         if (artifact instanceof DefaultArtifact) {
357             org.eclipse.aether.artifact.Artifact a = ((DefaultArtifact) artifact).getArtifact();
358             if (Objects.equals(path, a.getPath())) {
359                 return a;
360             }
361         }
362         return new org.eclipse.aether.artifact.DefaultArtifact(
363                 artifact.getGroupId(),
364                 artifact.getArtifactId(),
365                 artifact.getClassifier(),
366                 artifact.getExtension(),
367                 artifact.getVersion().toString(),
368                 null,
369                 path);
370     }
371 
372     @Override
373     public org.eclipse.aether.artifact.Artifact toArtifact(ArtifactCoordinates coords) {
374         if (coords instanceof DefaultArtifactCoordinates) {
375             return ((DefaultArtifactCoordinates) coords).getCoordinates();
376         }
377         return new org.eclipse.aether.artifact.DefaultArtifact(
378                 coords.getGroupId(),
379                 coords.getArtifactId(),
380                 coords.getClassifier(),
381                 coords.getExtension(),
382                 coords.getVersionConstraint().toString(),
383                 null,
384                 (File) null);
385     }
386 
387     @Override
388     public void registerListener(@Nonnull Listener listener) {
389         listeners.add(nonNull(listener));
390     }
391 
392     @Override
393     public void unregisterListener(@Nonnull Listener listener) {
394         listeners.remove(nonNull(listener));
395     }
396 
397     @Nonnull
398     @Override
399     public Collection<Listener> getListeners() {
400         return Collections.unmodifiableCollection(listeners);
401     }
402 
403     //
404     // Shortcut implementations
405     //
406 
407     /**
408      * Shortcut for <code>getService(RepositoryFactory.class).createLocal(...)</code>
409      *
410      * @see RepositoryFactory#createLocal(Path)
411      */
412     @Override
413     public LocalRepository createLocalRepository(Path path) {
414         return getService(RepositoryFactory.class).createLocal(path);
415     }
416 
417     /**
418      * Shortcut for <code>getService(RepositoryFactory.class).createRemote(...)</code>
419      *
420      * @see RepositoryFactory#createRemote(String, String)
421      */
422     @Nonnull
423     @Override
424     public RemoteRepository createRemoteRepository(@Nonnull String id, @Nonnull String url) {
425         return getService(RepositoryFactory.class).createRemote(id, url);
426     }
427 
428     /**
429      * Shortcut for <code>getService(RepositoryFactory.class).createRemote(...)</code>
430      *
431      * @see RepositoryFactory#createRemote(Repository)
432      */
433     @Nonnull
434     @Override
435     public RemoteRepository createRemoteRepository(@Nonnull Repository repository) {
436         return getService(RepositoryFactory.class).createRemote(repository);
437     }
438 
439     /**
440      * Shortcut for <code>getService(ArtifactCoordinatesFactory.class).create(...)</code>
441      *
442      * @see ArtifactFactory#create(Session, String, String, String, String)
443      */
444     @Override
445     public ArtifactCoordinates createArtifactCoordinates(
446             String groupId, String artifactId, String version, String extension) {
447         return getService(ArtifactCoordinatesFactory.class).create(this, groupId, artifactId, version, extension);
448     }
449 
450     /**
451      * Shortcut for <code>getService(ArtifactCoordinatesFactory.class).create(...)</code>
452      *
453      * @see ArtifactCoordinatesFactory#create(Session, String)
454      */
455     @Override
456     public ArtifactCoordinates createArtifactCoordinates(String coordString) {
457         return getService(ArtifactCoordinatesFactory.class).create(this, coordString);
458     }
459 
460     /**
461      * Shortcut for <code>getService(ArtifactCoordinatesFactory.class).create(...)</code>
462      *
463      * @see ArtifactCoordinatesFactory#create(Session, String, String, String, String, String, String)
464      */
465     @Override
466     public ArtifactCoordinates createArtifactCoordinates(
467             String groupId, String artifactId, String version, String classifier, String extension, String type) {
468         return getService(ArtifactCoordinatesFactory.class)
469                 .create(this, groupId, artifactId, version, classifier, extension, type);
470     }
471 
472     /**
473      * Shortcut for <code>getService(ArtifactCoordinatesFactory.class).create(...)</code>
474      *
475      * @see ArtifactCoordinatesFactory#create(Session, String, String, String, String, String, String)
476      */
477     @Override
478     public ArtifactCoordinates createArtifactCoordinates(Artifact artifact) {
479         return getService(ArtifactCoordinatesFactory.class)
480                 .create(
481                         this,
482                         artifact.getGroupId(),
483                         artifact.getArtifactId(),
484                         artifact.getVersion().asString(),
485                         artifact.getClassifier(),
486                         artifact.getExtension(),
487                         null);
488     }
489 
490     /**
491      * Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
492      *
493      * @see ArtifactFactory#create(Session, String, String, String, String)
494      */
495     @Override
496     public Artifact createArtifact(String groupId, String artifactId, String version, String extension) {
497         return getService(ArtifactFactory.class).create(this, groupId, artifactId, version, extension);
498     }
499 
500     /**
501      * Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
502      *
503      * @see ArtifactFactory#create(Session, String, String, String, String, String, String)
504      */
505     @Override
506     public Artifact createArtifact(
507             String groupId, String artifactId, String version, String classifier, String extension, String type) {
508         return getService(ArtifactFactory.class)
509                 .create(this, groupId, artifactId, version, classifier, extension, type);
510     }
511 
512     /**
513      * Shortcut for <code>getService(ArtifactFactory.class).createProduced(...)</code>
514      *
515      * @see ArtifactFactory#createProduced(Session, String, String, String, String)
516      */
517     @Override
518     public ProducedArtifact createProducedArtifact(
519             String groupId, String artifactId, String version, String extension) {
520         return getService(ArtifactFactory.class).createProduced(this, groupId, artifactId, version, extension);
521     }
522 
523     /**
524      * Shortcut for <code>getService(ArtifactFactory.class).createProduced(...)</code>
525      *
526      * @see ArtifactFactory#createProduced(Session, String, String, String, String, String, String)
527      */
528     @Override
529     public ProducedArtifact createProducedArtifact(
530             String groupId, String artifactId, String version, String classifier, String extension, String type) {
531         return getService(ArtifactFactory.class)
532                 .createProduced(this, groupId, artifactId, version, classifier, extension, type);
533     }
534 
535     /**
536      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
537      *
538      * @throws ArtifactResolverException if the artifact resolution failed
539      * @see ArtifactResolver#resolve(Session, Collection)
540      */
541     @Override
542     public DownloadedArtifact resolveArtifact(ArtifactCoordinates coordinates) {
543         return getService(ArtifactResolver.class)
544                 .resolve(this, Collections.singletonList(coordinates))
545                 .getArtifacts()
546                 .iterator()
547                 .next();
548     }
549 
550     /**
551      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
552      *
553      * @throws ArtifactResolverException if the artifact resolution failed
554      * @see ArtifactResolver#resolve(Session, Collection)
555      */
556     @Override
557     public Collection<DownloadedArtifact> resolveArtifacts(ArtifactCoordinates... coordinates) {
558         return resolveArtifacts(Arrays.asList(coordinates));
559     }
560 
561     /**
562      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
563      *
564      * @throws ArtifactResolverException if the artifact resolution failed
565      * @see ArtifactResolver#resolve(Session, Collection)
566      */
567     @Override
568     public Collection<DownloadedArtifact> resolveArtifacts(Collection<? extends ArtifactCoordinates> coordinates) {
569         return getService(ArtifactResolver.class).resolve(this, coordinates).getArtifacts();
570     }
571 
572     /**
573      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
574      *
575      * @throws ArtifactResolverException if the artifact resolution failed
576      * @see ArtifactResolver#resolve(Session, Collection)
577      */
578     @Override
579     public DownloadedArtifact resolveArtifact(Artifact artifact) {
580         ArtifactCoordinates coordinates =
581                 getService(ArtifactCoordinatesFactory.class).create(this, artifact);
582         return resolveArtifact(coordinates);
583     }
584 
585     @Override
586     public Collection<DownloadedArtifact> resolveArtifacts(Artifact... artifacts) {
587         ArtifactCoordinatesFactory acf = getService(ArtifactCoordinatesFactory.class);
588         List<ArtifactCoordinates> coords =
589                 Arrays.stream(artifacts).map(a -> acf.create(this, a)).collect(Collectors.toList());
590         return resolveArtifacts(coords);
591     }
592 
593     /**
594      * Shortcut for {@code getService(ArtifactInstaller.class).install(...)}
595      *
596      * @throws ArtifactInstallerException if the artifacts installation failed
597      * @see ArtifactInstaller#install(Session, Collection)
598      */
599     @Override
600     public void installArtifacts(Artifact... artifacts) {
601         installArtifacts(Arrays.asList(artifacts));
602     }
603 
604     /**
605      * Shortcut for {@code getService(ArtifactInstaller.class).install(...)}
606      *
607      * @throws ArtifactInstallerException if the artifacts installation failed
608      * @see ArtifactInstaller#install(Session, Collection)
609      */
610     @Override
611     public void installArtifacts(Collection<Artifact> artifacts) {
612         getService(ArtifactInstaller.class).install(this, artifacts);
613     }
614 
615     /**
616      * Shortcut for <code>getService(ArtifactDeployer.class).deploy(...)</code>
617      *
618      * @throws ArtifactDeployerException if the artifacts deployment failed
619      * @see ArtifactDeployer#deploy(Session, RemoteRepository, Collection)
620      */
621     @Override
622     public void deployArtifact(RemoteRepository repository, Artifact... artifacts) {
623         getService(ArtifactDeployer.class).deploy(this, repository, Arrays.asList(artifacts));
624     }
625 
626     /**
627      * Shortcut for <code>getService(ArtifactManager.class).setPath(...)</code>
628      *
629      * @see ArtifactManager#setPath(ProducedArtifact, Path)
630      */
631     @Override
632     public void setArtifactPath(@Nonnull ProducedArtifact artifact, @Nonnull Path path) {
633         getService(ArtifactManager.class).setPath(artifact, path);
634     }
635 
636     /**
637      * Shortcut for <code>getService(ArtifactManager.class).getPath(...)</code>
638      *
639      * @see ArtifactManager#getPath(Artifact)
640      */
641     @Nonnull
642     @Override
643     public Optional<Path> getArtifactPath(@Nonnull Artifact artifact) {
644         return getService(ArtifactManager.class).getPath(artifact);
645     }
646 
647     /**
648      * Shortcut for <code>getService(VersionParser.class).isSnapshot(...)</code>
649      *
650      * @see VersionParser#isSnapshot(String)
651      */
652     @Override
653     public boolean isVersionSnapshot(@Nonnull String version) {
654         return getService(VersionParser.class).isSnapshot(version);
655     }
656 
657     /**
658      * Shortcut for <code>getService(DependencyFactory.class).create(...)</code>
659      *
660      * @see DependencyCoordinatesFactory#create(Session, ArtifactCoordinates)
661      */
662     @Nonnull
663     @Override
664     public DependencyCoordinates createDependencyCoordinates(@Nonnull ArtifactCoordinates coordinates) {
665         return getService(DependencyCoordinatesFactory.class).create(this, coordinates);
666     }
667 
668     /**
669      * Shortcut for <code>getService(DependencyFactory.class).create(...)</code>
670      *
671      * @see DependencyCoordinatesFactory#create(Session, ArtifactCoordinates)
672      */
673     @Nonnull
674     @Override
675     public DependencyCoordinates createDependencyCoordinates(@Nonnull Dependency dependency) {
676         return getService(DependencyCoordinatesFactory.class).create(this, dependency);
677     }
678 
679     /**
680      * Shortcut for <code>getService(DependencyResolver.class).collect(...)</code>
681      *
682      * @throws DependencyResolverException if the dependency collection failed
683      * @see DependencyResolver#collect(Session, Artifact)
684      */
685     @Nonnull
686     @Override
687     public Node collectDependencies(@Nonnull Artifact artifact) {
688         return getService(DependencyResolver.class).collect(this, artifact).getRoot();
689     }
690 
691     /**
692      * Shortcut for <code>getService(DependencyResolver.class).collect(...)</code>
693      *
694      * @throws DependencyResolverException if the dependency collection failed
695      * @see DependencyResolver#collect(Session, Project)
696      */
697     @Nonnull
698     @Override
699     public Node collectDependencies(@Nonnull Project project) {
700         return getService(DependencyResolver.class).collect(this, project).getRoot();
701     }
702 
703     /**
704      * Shortcut for <code>getService(DependencyResolver.class).collect(...)</code>
705      *
706      * @throws DependencyResolverException if the dependency collection failed
707      * @see DependencyResolver#collect(Session, DependencyCoordinates)
708      */
709     @Nonnull
710     @Override
711     public Node collectDependencies(@Nonnull DependencyCoordinates dependency) {
712         Node root =
713                 getService(DependencyResolver.class).collect(this, dependency).getRoot();
714         return root.getChildren().iterator().next();
715     }
716 
717     @Nonnull
718     @Override
719     public List<Node> flattenDependencies(@Nonnull Node node, @Nonnull PathScope scope) {
720         return getService(DependencyResolver.class).flatten(this, node, scope);
721     }
722 
723     @Override
724     public List<Path> resolveDependencies(DependencyCoordinates dependency) {
725         return getService(DependencyResolver.class).resolve(this, dependency).getPaths();
726     }
727 
728     @Override
729     public List<Path> resolveDependencies(List<DependencyCoordinates> dependencies) {
730         return getService(DependencyResolver.class).resolve(this, dependencies).getPaths();
731     }
732 
733     @Override
734     public List<Path> resolveDependencies(Project project, PathScope scope) {
735         return getService(DependencyResolver.class)
736                 .resolve(this, project, scope)
737                 .getPaths();
738     }
739 
740     @Override
741     public Map<PathType, List<Path>> resolveDependencies(
742             @Nonnull DependencyCoordinates dependency,
743             @Nonnull PathScope scope,
744             @Nonnull Collection<PathType> desiredTypes) {
745         return getService(DependencyResolver.class)
746                 .resolve(DependencyResolverRequest.builder()
747                         .session(this)
748                         .requestType(DependencyResolverRequest.RequestType.RESOLVE)
749                         .dependency(dependency)
750                         .pathScope(scope)
751                         .pathTypeFilter(desiredTypes)
752                         .build())
753                 .getDispatchedPaths();
754     }
755 
756     @Override
757     public Map<PathType, List<Path>> resolveDependencies(
758             @Nonnull Project project, @Nonnull PathScope scope, @Nonnull Collection<PathType> desiredTypes) {
759         return getService(DependencyResolver.class)
760                 .resolve(DependencyResolverRequest.builder()
761                         .session(this)
762                         .requestType(DependencyResolverRequest.RequestType.RESOLVE)
763                         .project(project)
764                         .pathScope(scope)
765                         .pathTypeFilter(desiredTypes)
766                         .build())
767                 .getDispatchedPaths();
768     }
769 
770     @Override
771     public Path getPathForLocalArtifact(@Nonnull Artifact artifact) {
772         return getService(LocalRepositoryManager.class).getPathForLocalArtifact(this, getLocalRepository(), artifact);
773     }
774 
775     @Override
776     public Path getPathForRemoteArtifact(RemoteRepository remote, Artifact artifact) {
777         return getService(LocalRepositoryManager.class)
778                 .getPathForRemoteArtifact(this, getLocalRepository(), remote, artifact);
779     }
780 
781     @Override
782     public Version parseVersion(String version) {
783         return getService(VersionParser.class).parseVersion(version);
784     }
785 
786     @Override
787     public VersionRange parseVersionRange(String versionRange) {
788         return getService(VersionParser.class).parseVersionRange(versionRange);
789     }
790 
791     @Override
792     public VersionConstraint parseVersionConstraint(String versionConstraint) {
793         return getService(VersionParser.class).parseVersionConstraint(versionConstraint);
794     }
795 
796     @Override
797     public Version resolveVersion(ArtifactCoordinates artifact) {
798         return getService(VersionResolver.class).resolve(this, artifact).getVersion();
799     }
800 
801     @Override
802     public List<Version> resolveVersionRange(ArtifactCoordinates artifact) {
803         return getService(VersionRangeResolver.class).resolve(this, artifact).getVersions();
804     }
805 
806     @Override
807     public Type requireType(String id) {
808         return getService(TypeRegistry.class).require(id);
809     }
810 
811     @Override
812     public Language requireLanguage(String id) {
813         return getService(LanguageRegistry.class).require(id);
814     }
815 
816     @Override
817     public Packaging requirePackaging(String id) {
818         return getService(PackagingRegistry.class).require(id);
819     }
820 
821     @Override
822     public ProjectScope requireProjectScope(String id) {
823         return getService(ProjectScopeRegistry.class).require(id);
824     }
825 
826     @Override
827     public DependencyScope requireDependencyScope(String id) {
828         return DependencyScope.forId(nonNull(id, "id"));
829     }
830 
831     @Override
832     public PathScope requirePathScope(String id) {
833         return getService(PathScopeRegistry.class).require(id);
834     }
835 }