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