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