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.Objects;
29  import java.util.Optional;
30  import java.util.WeakHashMap;
31  import java.util.concurrent.CopyOnWriteArrayList;
32  import java.util.stream.Collectors;
33  
34  import org.apache.maven.api.*;
35  import org.apache.maven.api.annotations.Nonnull;
36  import org.apache.maven.api.model.Repository;
37  import org.apache.maven.api.services.*;
38  import org.apache.maven.artifact.repository.ArtifactRepository;
39  import org.apache.maven.project.MavenProject;
40  
41  import static org.apache.maven.internal.impl.Utils.map;
42  import static org.apache.maven.internal.impl.Utils.nonNull;
43  
44  public abstract class AbstractSession implements InternalSession {
45  
46      private final List<Listener> listeners = new CopyOnWriteArrayList<>();
47      private final Map<org.eclipse.aether.graph.DependencyNode, Node> allNodes =
48              Collections.synchronizedMap(new WeakHashMap<>());
49      private final Map<org.eclipse.aether.artifact.Artifact, Artifact> allArtifacts =
50              Collections.synchronizedMap(new WeakHashMap<>());
51      private final Map<org.eclipse.aether.repository.RemoteRepository, RemoteRepository> allRepositories =
52              Collections.synchronizedMap(new WeakHashMap<>());
53      private final Map<String, Project> allProjects = Collections.synchronizedMap(new WeakHashMap<>());
54      private final Map<org.eclipse.aether.graph.Dependency, Dependency> allDependencies =
55              Collections.synchronizedMap(new WeakHashMap<>());
56  
57      @Override
58      public RemoteRepository getRemoteRepository(org.eclipse.aether.repository.RemoteRepository repository) {
59          return allRepositories.computeIfAbsent(repository, DefaultRemoteRepository::new);
60      }
61  
62      @Override
63      public Node getNode(org.eclipse.aether.graph.DependencyNode node) {
64          return getNode(node, false);
65      }
66  
67      @Override
68      public Node getNode(org.eclipse.aether.graph.DependencyNode node, boolean verbose) {
69          return allNodes.computeIfAbsent(node, n -> new DefaultNode(this, n, verbose));
70      }
71  
72      @Nonnull
73      @Override
74      public Artifact getArtifact(@Nonnull org.eclipse.aether.artifact.Artifact artifact) {
75          return allArtifacts.computeIfAbsent(artifact, a -> new DefaultArtifact(this, a));
76      }
77  
78      @Nonnull
79      @Override
80      public Dependency getDependency(@Nonnull org.eclipse.aether.graph.Dependency dependency) {
81          return allDependencies.computeIfAbsent(dependency, d -> new DefaultDependency(this, d));
82      }
83  
84      @Override
85      public List<Project> getProjects(List<MavenProject> projects) {
86          return projects == null ? null : map(projects, this::getProject);
87      }
88  
89      @Override
90      public Project getProject(MavenProject project) {
91          return allProjects.computeIfAbsent(project.getId(), id -> new DefaultProject(this, project));
92      }
93  
94      @Override
95      public List<org.eclipse.aether.repository.RemoteRepository> toRepositories(List<RemoteRepository> repositories) {
96          return repositories == null ? null : map(repositories, this::toRepository);
97      }
98  
99      @Override
100     public org.eclipse.aether.repository.RemoteRepository toRepository(RemoteRepository repository) {
101         if (repository instanceof DefaultRemoteRepository) {
102             return ((DefaultRemoteRepository) repository).getRepository();
103         } else {
104             // TODO
105             throw new UnsupportedOperationException("Not implemented yet");
106         }
107     }
108 
109     @Override
110     public org.eclipse.aether.repository.LocalRepository toRepository(LocalRepository repository) {
111         if (repository instanceof DefaultLocalRepository) {
112             return ((DefaultLocalRepository) repository).getRepository();
113         } else {
114             // TODO
115             throw new UnsupportedOperationException("Not implemented yet");
116         }
117     }
118 
119     @Override
120     public List<ArtifactRepository> toArtifactRepositories(List<RemoteRepository> repositories) {
121         return repositories == null ? null : map(repositories, this::toArtifactRepository);
122     }
123 
124     @Override
125     public abstract ArtifactRepository toArtifactRepository(RemoteRepository repository);
126 
127     @Override
128     public List<org.eclipse.aether.graph.Dependency> toDependencies(
129             Collection<DependencyCoordinate> dependencies, boolean managed) {
130         return dependencies == null ? null : map(dependencies, d -> toDependency(d, managed));
131     }
132 
133     @Override
134     public abstract org.eclipse.aether.graph.Dependency toDependency(DependencyCoordinate dependency, boolean managed);
135 
136     @Override
137     public List<org.eclipse.aether.artifact.Artifact> toArtifacts(Collection<Artifact> artifacts) {
138         return artifacts == null ? null : map(artifacts, this::toArtifact);
139     }
140 
141     @Override
142     public org.eclipse.aether.artifact.Artifact toArtifact(Artifact artifact) {
143         File file = getService(ArtifactManager.class)
144                 .getPath(artifact)
145                 .map(Path::toFile)
146                 .orElse(null);
147         if (artifact instanceof DefaultArtifact) {
148             org.eclipse.aether.artifact.Artifact a = ((DefaultArtifact) artifact).getArtifact();
149             if (Objects.equals(file, a.getFile())) {
150                 return a;
151             }
152         }
153         return new org.eclipse.aether.artifact.DefaultArtifact(
154                 artifact.getGroupId(),
155                 artifact.getArtifactId(),
156                 artifact.getClassifier(),
157                 artifact.getExtension(),
158                 artifact.getVersion().toString(),
159                 null,
160                 file);
161     }
162 
163     @Override
164     public org.eclipse.aether.artifact.Artifact toArtifact(ArtifactCoordinate coord) {
165         if (coord instanceof DefaultArtifactCoordinate) {
166             return ((DefaultArtifactCoordinate) coord).getCoordinate();
167         }
168         return new org.eclipse.aether.artifact.DefaultArtifact(
169                 coord.getGroupId(),
170                 coord.getArtifactId(),
171                 coord.getClassifier(),
172                 coord.getExtension(),
173                 coord.getVersion().toString(),
174                 null,
175                 (File) null);
176     }
177 
178     @Override
179     public void registerListener(@Nonnull Listener listener) {
180         listeners.add(nonNull(listener));
181     }
182 
183     @Override
184     public void unregisterListener(@Nonnull Listener listener) {
185         listeners.remove(nonNull(listener));
186     }
187 
188     @Nonnull
189     @Override
190     public Collection<Listener> getListeners() {
191         return Collections.unmodifiableCollection(listeners);
192     }
193 
194     //
195     // Shortcut implementations
196     //
197 
198     /**
199      * Shortcut for <code>getService(RepositoryFactory.class).createLocal(...)</code>
200      *
201      * @see RepositoryFactory#createLocal(Path)
202      */
203     @Override
204     public LocalRepository createLocalRepository(Path path) {
205         return getService(RepositoryFactory.class).createLocal(path);
206     }
207 
208     /**
209      * Shortcut for <code>getService(RepositoryFactory.class).createRemote(...)</code>
210      *
211      * @see RepositoryFactory#createRemote(String, String)
212      */
213     @Nonnull
214     @Override
215     public RemoteRepository createRemoteRepository(@Nonnull String id, @Nonnull String url) {
216         return getService(RepositoryFactory.class).createRemote(id, url);
217     }
218 
219     /**
220      * Shortcut for <code>getService(RepositoryFactory.class).createRemote(...)</code>
221      *
222      * @see RepositoryFactory#createRemote(Repository)
223      */
224     @Nonnull
225     @Override
226     public RemoteRepository createRemoteRepository(@Nonnull Repository repository) {
227         return getService(RepositoryFactory.class).createRemote(repository);
228     }
229 
230     /**
231      * Shortcut for <code>getService(CoordinateFactory.class).create(...)</code>
232      *
233      * @see ArtifactFactory#create(Session, String, String, String, String)
234      */
235     @Override
236     public ArtifactCoordinate createArtifactCoordinate(
237             String groupId, String artifactId, String version, String extension) {
238         return getService(ArtifactCoordinateFactory.class).create(this, groupId, artifactId, version, extension);
239     }
240 
241     /**
242      * Shortcut for <code>getService(CoordinateFactory.class).create(...)</code>
243      *
244      * @see ArtifactCoordinateFactory#create(Session, String)
245      */
246     @Override
247     public ArtifactCoordinate createArtifactCoordinate(String coordString) {
248         return getService(ArtifactCoordinateFactory.class).create(this, coordString);
249     }
250 
251     /**
252      * Shortcut for <code>getService(CoordinateFactory.class).create(...)</code>
253      *
254      * @see ArtifactCoordinateFactory#create(Session, String, String, String, String, String, String)
255      */
256     @Override
257     public ArtifactCoordinate createArtifactCoordinate(
258             String groupId, String artifactId, String version, String classifier, String extension, String type) {
259         return getService(ArtifactCoordinateFactory.class)
260                 .create(this, groupId, artifactId, version, classifier, extension, type);
261     }
262 
263     /**
264      * Shortcut for <code>getService(CoordinateFactory.class).create(...)</code>
265      *
266      * @see ArtifactCoordinateFactory#create(Session, String, String, String, String, String, String)
267      */
268     @Override
269     public ArtifactCoordinate createArtifactCoordinate(Artifact artifact) {
270         return getService(ArtifactCoordinateFactory.class)
271                 .create(
272                         this,
273                         artifact.getGroupId(),
274                         artifact.getArtifactId(),
275                         artifact.getVersion().asString(),
276                         artifact.getClassifier(),
277                         artifact.getExtension(),
278                         null);
279     }
280 
281     /**
282      * Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
283      *
284      * @see ArtifactFactory#create(Session, String, String, String, String)
285      */
286     @Override
287     public Artifact createArtifact(String groupId, String artifactId, String version, String extension) {
288         return getService(ArtifactFactory.class).create(this, groupId, artifactId, version, extension);
289     }
290 
291     /**
292      * Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
293      *
294      * @see ArtifactFactory#create(Session, String, String, String, String, String, String)
295      */
296     @Override
297     public Artifact createArtifact(
298             String groupId, String artifactId, String version, String classifier, String extension, String type) {
299         return getService(ArtifactFactory.class)
300                 .create(this, groupId, artifactId, version, classifier, extension, type);
301     }
302 
303     /**
304      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
305      *
306      * @throws ArtifactResolverException if the artifact resolution failed
307      * @see ArtifactResolver#resolve(Session, Collection)
308      */
309     @Override
310     public Map.Entry<Artifact, Path> resolveArtifact(ArtifactCoordinate coordinate) {
311         return getService(ArtifactResolver.class)
312                 .resolve(this, Collections.singletonList(coordinate))
313                 .getArtifacts()
314                 .entrySet()
315                 .iterator()
316                 .next();
317     }
318 
319     /**
320      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
321      *
322      * @throws ArtifactResolverException if the artifact resolution failed
323      * @see ArtifactResolver#resolve(Session, Collection)
324      */
325     @Override
326     public Map<Artifact, Path> resolveArtifacts(ArtifactCoordinate... coordinates) {
327         return resolveArtifacts(Arrays.asList(coordinates));
328     }
329 
330     /**
331      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
332      *
333      * @throws ArtifactResolverException if the artifact resolution failed
334      * @see ArtifactResolver#resolve(Session, Collection)
335      */
336     @Override
337     public Map<Artifact, Path> resolveArtifacts(Collection<? extends ArtifactCoordinate> coordinates) {
338         return getService(ArtifactResolver.class).resolve(this, coordinates).getArtifacts();
339     }
340 
341     /**
342      * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
343      *
344      * @throws ArtifactResolverException if the artifact resolution failed
345      * @see ArtifactResolver#resolve(Session, Collection)
346      */
347     @Override
348     public Map.Entry<Artifact, Path> resolveArtifact(Artifact artifact) {
349         ArtifactCoordinate coordinate =
350                 getService(ArtifactCoordinateFactory.class).create(this, artifact);
351         return resolveArtifact(coordinate);
352     }
353 
354     @Override
355     public Map<Artifact, Path> resolveArtifacts(Artifact... artifacts) {
356         ArtifactCoordinateFactory acf = getService(ArtifactCoordinateFactory.class);
357         List<ArtifactCoordinate> coords =
358                 Arrays.stream(artifacts).map(a -> acf.create(this, a)).collect(Collectors.toList());
359         return resolveArtifacts(coords);
360     }
361 
362     /**
363      * Shortcut for {@code getService(ArtifactInstaller.class).install(...)}
364      *
365      * @throws ArtifactInstallerException if the artifacts installation failed
366      * @see ArtifactInstaller#install(Session, Collection)
367      */
368     @Override
369     public void installArtifacts(Artifact... artifacts) {
370         installArtifacts(Arrays.asList(artifacts));
371     }
372 
373     /**
374      * Shortcut for {@code getService(ArtifactInstaller.class).install(...)}
375      *
376      * @throws ArtifactInstallerException if the artifacts installation failed
377      * @see ArtifactInstaller#install(Session, Collection)
378      */
379     @Override
380     public void installArtifacts(Collection<Artifact> artifacts) {
381         getService(ArtifactInstaller.class).install(this, artifacts);
382     }
383 
384     /**
385      * Shortcut for <code>getService(ArtifactDeployer.class).deploy(...)</code>
386      *
387      * @throws ArtifactDeployerException if the artifacts deployment failed
388      * @see ArtifactDeployer#deploy(Session, RemoteRepository, Collection)
389      */
390     @Override
391     public void deployArtifact(RemoteRepository repository, Artifact... artifacts) {
392         getService(ArtifactDeployer.class).deploy(this, repository, Arrays.asList(artifacts));
393     }
394 
395     /**
396      * Shortcut for <code>getService(ArtifactManager.class).setPath(...)</code>
397      *
398      * @see ArtifactManager#setPath(Artifact, Path)
399      */
400     @Override
401     public void setArtifactPath(@Nonnull Artifact artifact, @Nonnull Path path) {
402         getService(ArtifactManager.class).setPath(artifact, path);
403     }
404 
405     /**
406      * Shortcut for <code>getService(ArtifactManager.class).getPath(...)</code>
407      *
408      * @see ArtifactManager#getPath(Artifact)
409      */
410     @Nonnull
411     @Override
412     public Optional<Path> getArtifactPath(@Nonnull Artifact artifact) {
413         return getService(ArtifactManager.class).getPath(artifact);
414     }
415 
416     /**
417      * Shortcut for <code>getService(VersionParser.class).isSnapshot(...)</code>
418      *
419      * @see VersionParser#isSnapshot(String)
420      */
421     @Override
422     public boolean isVersionSnapshot(@Nonnull String version) {
423         return getService(VersionParser.class).isSnapshot(version);
424     }
425 
426     /**
427      * Shortcut for <code>getService(DependencyFactory.class).create(...)</code>
428      *
429      * @see DependencyCoordinateFactory#create(Session, ArtifactCoordinate)
430      */
431     @Nonnull
432     @Override
433     public DependencyCoordinate createDependencyCoordinate(@Nonnull ArtifactCoordinate coordinate) {
434         return getService(DependencyCoordinateFactory.class).create(this, coordinate);
435     }
436 
437     /**
438      * Shortcut for <code>getService(DependencyFactory.class).create(...)</code>
439      *
440      * @see DependencyCoordinateFactory#create(Session, ArtifactCoordinate)
441      */
442     @Nonnull
443     @Override
444     public DependencyCoordinate createDependencyCoordinate(@Nonnull Dependency dependency) {
445         return getService(DependencyCoordinateFactory.class).create(this, dependency);
446     }
447 
448     /**
449      * Shortcut for <code>getService(DependencyCollector.class).collect(...)</code>
450      *
451      * @throws DependencyCollectorException if the dependency collection failed
452      * @see DependencyCollector#collect(Session, Artifact)
453      */
454     @Nonnull
455     @Override
456     public Node collectDependencies(@Nonnull Artifact artifact) {
457         return getService(DependencyCollector.class).collect(this, artifact).getRoot();
458     }
459 
460     /**
461      * Shortcut for <code>getService(DependencyCollector.class).collect(...)</code>
462      *
463      * @throws DependencyCollectorException if the dependency collection failed
464      * @see DependencyCollector#collect(Session, Project)
465      */
466     @Nonnull
467     @Override
468     public Node collectDependencies(@Nonnull Project project) {
469         return getService(DependencyCollector.class).collect(this, project).getRoot();
470     }
471 
472     /**
473      * Shortcut for <code>getService(DependencyCollector.class).collect(...)</code>
474      *
475      * @throws DependencyCollectorException if the dependency collection failed
476      * @see DependencyCollector#collect(Session, DependencyCoordinate)
477      */
478     @Nonnull
479     @Override
480     public Node collectDependencies(@Nonnull DependencyCoordinate dependency) {
481         return getService(DependencyCollector.class).collect(this, dependency).getRoot();
482     }
483 
484     @Nonnull
485     @Override
486     public List<Node> flattenDependencies(@Nonnull Node node, @Nonnull PathScope scope) {
487         return getService(DependencyResolver.class).flatten(this, node, scope);
488     }
489 
490     @Override
491     public List<Path> resolveDependencies(DependencyCoordinate dependency) {
492         return getService(DependencyResolver.class).resolve(this, dependency).getPaths();
493     }
494 
495     @Override
496     public List<Path> resolveDependencies(List<DependencyCoordinate> dependencies) {
497         return getService(DependencyResolver.class).resolve(this, dependencies).getPaths();
498     }
499 
500     @Override
501     public List<Path> resolveDependencies(Project project, PathScope scope) {
502         return getService(DependencyResolver.class)
503                 .resolve(this, project, scope)
504                 .getPaths();
505     }
506 
507     @Override
508     public Map<PathType, List<Path>> resolveDependencies(
509             @Nonnull DependencyCoordinate dependency,
510             @Nonnull PathScope scope,
511             @Nonnull Collection<PathType> desiredTypes) {
512         return getService(DependencyResolver.class)
513                 .resolve(DependencyResolverRequest.builder()
514                         .session(this)
515                         .dependency(dependency)
516                         .pathScope(scope)
517                         .pathTypeFilter(desiredTypes)
518                         .build())
519                 .getDispatchedPaths();
520     }
521 
522     @Override
523     public Map<PathType, List<Path>> resolveDependencies(
524             @Nonnull Project project, @Nonnull PathScope scope, @Nonnull Collection<PathType> desiredTypes) {
525         return getService(DependencyResolver.class)
526                 .resolve(DependencyResolverRequest.builder()
527                         .session(this)
528                         .project(project)
529                         .pathScope(scope)
530                         .pathTypeFilter(desiredTypes)
531                         .build())
532                 .getDispatchedPaths();
533     }
534 
535     @Override
536     public Path getPathForLocalArtifact(@Nonnull Artifact artifact) {
537         return getService(LocalRepositoryManager.class).getPathForLocalArtifact(this, getLocalRepository(), artifact);
538     }
539 
540     @Override
541     public Path getPathForRemoteArtifact(RemoteRepository remote, Artifact artifact) {
542         return getService(LocalRepositoryManager.class)
543                 .getPathForRemoteArtifact(this, getLocalRepository(), remote, artifact);
544     }
545 
546     @Override
547     public Version parseVersion(String version) {
548         return getService(VersionParser.class).parseVersion(version);
549     }
550 
551     @Override
552     public VersionRange parseVersionRange(String versionRange) {
553         return getService(VersionParser.class).parseVersionRange(versionRange);
554     }
555 
556     @Override
557     public VersionConstraint parseVersionConstraint(String versionConstraint) {
558         return getService(VersionParser.class).parseVersionConstraint(versionConstraint);
559     }
560 
561     @Override
562     public Version resolveVersion(ArtifactCoordinate artifact) {
563         return getService(VersionResolver.class).resolve(this, artifact).getVersion();
564     }
565 
566     @Override
567     public List<Version> resolveVersionRange(ArtifactCoordinate artifact) {
568         return getService(VersionRangeResolver.class).resolve(this, artifact).getVersions();
569     }
570 
571     @Override
572     public Type requireType(String id) {
573         return getService(TypeRegistry.class).require(id);
574     }
575 
576     @Override
577     public Language requireLanguage(String id) {
578         return getService(LanguageRegistry.class).require(id);
579     }
580 
581     @Override
582     public Packaging requirePackaging(String id) {
583         return getService(PackagingRegistry.class).require(id);
584     }
585 
586     @Override
587     public ProjectScope requireProjectScope(String id) {
588         return getService(ProjectScopeRegistry.class).require(id);
589     }
590 
591     @Override
592     public DependencyScope requireDependencyScope(String id) {
593         return DependencyScope.forId(nonNull(id, "id"));
594     }
595 
596     @Override
597     public PathScope requirePathScope(String id) {
598         return getService(PathScopeRegistry.class).require(id);
599     }
600 }