1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.cli.internal;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23
24 import java.io.File;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Set;
29
30 import org.apache.maven.RepositoryUtils;
31 import org.apache.maven.cli.internal.extension.model.CoreExtension;
32 import org.apache.maven.execution.MavenExecutionRequest;
33 import org.apache.maven.extension.internal.CoreExports;
34 import org.apache.maven.extension.internal.CoreExtensionEntry;
35 import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
36 import org.apache.maven.model.Plugin;
37 import org.apache.maven.plugin.PluginResolutionException;
38 import org.apache.maven.plugin.internal.DefaultPluginDependenciesResolver;
39 import org.codehaus.plexus.DefaultPlexusContainer;
40 import org.codehaus.plexus.PlexusContainer;
41 import org.codehaus.plexus.classworlds.ClassWorld;
42 import org.codehaus.plexus.classworlds.realm.ClassRealm;
43 import org.codehaus.plexus.interpolation.InterpolationException;
44 import org.codehaus.plexus.interpolation.Interpolator;
45 import org.codehaus.plexus.interpolation.MapBasedValueSource;
46 import org.codehaus.plexus.interpolation.StringSearchInterpolator;
47 import org.codehaus.plexus.logging.Logger;
48 import org.eclipse.aether.RepositorySystemSession;
49 import org.eclipse.aether.artifact.Artifact;
50 import org.eclipse.aether.graph.DependencyFilter;
51 import org.eclipse.aether.graph.DependencyNode;
52 import org.eclipse.aether.repository.RemoteRepository;
53 import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
54 import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
55
56
57
58
59 @Named
60 public class BootstrapCoreExtensionManager {
61 public static final String STRATEGY_PARENT_FIRST = "parent-first";
62 public static final String STRATEGY_PLUGIN = "plugin";
63 public static final String STRATEGY_SELF_FIRST = "self-first";
64
65 private final Logger log;
66
67 private final DefaultPluginDependenciesResolver pluginDependenciesResolver;
68
69 private final DefaultRepositorySystemSessionFactory repositorySystemSessionFactory;
70
71 private final CoreExports coreExports;
72
73 private final ClassWorld classWorld;
74
75 private final ClassRealm parentRealm;
76
77 @Inject
78 public BootstrapCoreExtensionManager(
79 Logger log,
80 DefaultPluginDependenciesResolver pluginDependenciesResolver,
81 DefaultRepositorySystemSessionFactory repositorySystemSessionFactory,
82 CoreExports coreExports,
83 PlexusContainer container) {
84 this.log = log;
85 this.pluginDependenciesResolver = pluginDependenciesResolver;
86 this.repositorySystemSessionFactory = repositorySystemSessionFactory;
87 this.coreExports = coreExports;
88 this.classWorld = ((DefaultPlexusContainer) container).getClassWorld();
89 this.parentRealm = container.getContainerRealm();
90 }
91
92 public List<CoreExtensionEntry> loadCoreExtensions(
93 MavenExecutionRequest request, Set<String> providedArtifacts, List<CoreExtension> extensions)
94 throws Exception {
95 RepositorySystemSession repoSession = repositorySystemSessionFactory.newRepositorySession(request);
96 List<RemoteRepository> repositories = RepositoryUtils.toRepos(request.getPluginArtifactRepositories());
97 Interpolator interpolator = createInterpolator(request);
98
99 return resolveCoreExtensions(repoSession, repositories, providedArtifacts, extensions, interpolator);
100 }
101
102 private List<CoreExtensionEntry> resolveCoreExtensions(
103 RepositorySystemSession repoSession,
104 List<RemoteRepository> repositories,
105 Set<String> providedArtifacts,
106 List<CoreExtension> configuration,
107 Interpolator interpolator)
108 throws Exception {
109 List<CoreExtensionEntry> extensions = new ArrayList<>();
110
111 DependencyFilter dependencyFilter = new ExclusionsDependencyFilter(providedArtifacts);
112
113 for (CoreExtension extension : configuration) {
114 List<Artifact> artifacts =
115 resolveExtension(extension, repoSession, repositories, dependencyFilter, interpolator);
116 if (!artifacts.isEmpty()) {
117 extensions.add(createExtension(extension, artifacts));
118 }
119 }
120
121 return Collections.unmodifiableList(extensions);
122 }
123
124 private CoreExtensionEntry createExtension(CoreExtension extension, List<Artifact> artifacts) throws Exception {
125 String realmId = "coreExtension>" + extension.getGroupId() + ":" + extension.getArtifactId() + ":"
126 + extension.getVersion();
127 final ClassRealm realm = classWorld.newRealm(realmId, null);
128 Set<String> providedArtifacts = Collections.emptySet();
129 String classLoadingStrategy = extension.getClassLoadingStrategy();
130 if (STRATEGY_PARENT_FIRST.equals(classLoadingStrategy)) {
131 realm.importFrom(parentRealm, "");
132 } else if (STRATEGY_PLUGIN.equals(classLoadingStrategy)) {
133 coreExports.getExportedPackages().forEach((p, cl) -> realm.importFrom(cl, p));
134 providedArtifacts = coreExports.getExportedArtifacts();
135 } else if (STRATEGY_SELF_FIRST.equals(classLoadingStrategy)) {
136 realm.setParentRealm(parentRealm);
137 } else {
138 throw new IllegalArgumentException("Unsupported class-loading strategy '"
139 + classLoadingStrategy + "'. Supported values are: " + STRATEGY_PARENT_FIRST
140 + ", " + STRATEGY_PLUGIN + " and " + STRATEGY_SELF_FIRST);
141 }
142 log.debug("Populating class realm " + realm.getId());
143 for (Artifact artifact : artifacts) {
144 String id = artifact.getGroupId() + ":" + artifact.getArtifactId();
145 if (providedArtifacts.contains(id)) {
146 log.debug(" Excluded " + id);
147 } else {
148 File file = artifact.getFile();
149 log.debug(" Included " + id + " located at " + file);
150 realm.addURL(file.toURI().toURL());
151 }
152 }
153 return CoreExtensionEntry.discoverFrom(
154 realm, Collections.singleton(artifacts.get(0).getFile()));
155 }
156
157 private List<Artifact> resolveExtension(
158 CoreExtension extension,
159 RepositorySystemSession repoSession,
160 List<RemoteRepository> repositories,
161 DependencyFilter dependencyFilter,
162 Interpolator interpolator)
163 throws ExtensionResolutionException {
164 try {
165
166
167
168
169 Plugin plugin = new Plugin();
170 plugin.setGroupId(interpolator.interpolate(extension.getGroupId()));
171 plugin.setArtifactId(interpolator.interpolate(extension.getArtifactId()));
172 plugin.setVersion(interpolator.interpolate(extension.getVersion()));
173
174 DependencyNode root = pluginDependenciesResolver.resolveCoreExtension(
175 plugin, dependencyFilter, repositories, repoSession);
176 PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
177 root.accept(nlg);
178 List<Artifact> artifacts = nlg.getArtifacts(false);
179
180 return artifacts;
181 } catch (PluginResolutionException e) {
182 throw new ExtensionResolutionException(extension, e.getCause());
183 } catch (InterpolationException e) {
184 throw new ExtensionResolutionException(extension, e);
185 }
186 }
187
188 private static Interpolator createInterpolator(MavenExecutionRequest request) {
189 StringSearchInterpolator interpolator = new StringSearchInterpolator();
190 interpolator.addValueSource(new MapBasedValueSource(request.getUserProperties()));
191 interpolator.addValueSource(new MapBasedValueSource(request.getSystemProperties()));
192 return interpolator;
193 }
194 }