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.NoSuchElementException;
29 import java.util.Set;
30 import java.util.function.Function;
31 import java.util.stream.Collectors;
32
33 import org.apache.maven.RepositoryUtils;
34 import org.apache.maven.api.Service;
35 import org.apache.maven.api.Session;
36 import org.apache.maven.api.cli.extensions.CoreExtension;
37 import org.apache.maven.api.model.Plugin;
38 import org.apache.maven.api.services.ArtifactCoordinatesFactory;
39 import org.apache.maven.api.services.ArtifactManager;
40 import org.apache.maven.api.services.ArtifactResolver;
41 import org.apache.maven.api.services.Interpolator;
42 import org.apache.maven.api.services.InterpolatorException;
43 import org.apache.maven.api.services.RepositoryFactory;
44 import org.apache.maven.api.services.VersionParser;
45 import org.apache.maven.api.services.VersionRangeResolver;
46 import org.apache.maven.execution.DefaultMavenExecutionResult;
47 import org.apache.maven.execution.MavenExecutionRequest;
48 import org.apache.maven.execution.MavenSession;
49 import org.apache.maven.extension.internal.CoreExports;
50 import org.apache.maven.extension.internal.CoreExtensionEntry;
51 import org.apache.maven.internal.impl.DefaultArtifactCoordinatesFactory;
52 import org.apache.maven.internal.impl.DefaultArtifactManager;
53 import org.apache.maven.internal.impl.DefaultArtifactResolver;
54 import org.apache.maven.internal.impl.DefaultModelVersionParser;
55 import org.apache.maven.internal.impl.DefaultRepositoryFactory;
56 import org.apache.maven.internal.impl.DefaultSession;
57 import org.apache.maven.internal.impl.DefaultVersionParser;
58 import org.apache.maven.internal.impl.DefaultVersionRangeResolver;
59 import org.apache.maven.internal.impl.InternalSession;
60 import org.apache.maven.internal.impl.model.DefaultInterpolator;
61 import org.apache.maven.plugin.PluginResolutionException;
62 import org.apache.maven.plugin.internal.DefaultPluginDependenciesResolver;
63 import org.apache.maven.resolver.MavenChainedWorkspaceReader;
64 import org.apache.maven.resolver.RepositorySystemSessionFactory;
65 import org.codehaus.plexus.DefaultPlexusContainer;
66 import org.codehaus.plexus.PlexusContainer;
67 import org.codehaus.plexus.classworlds.ClassWorld;
68 import org.codehaus.plexus.classworlds.realm.ClassRealm;
69 import org.eclipse.aether.RepositorySystem;
70 import org.eclipse.aether.RepositorySystemSession;
71 import org.eclipse.aether.RepositorySystemSession.CloseableSession;
72 import org.eclipse.aether.artifact.Artifact;
73 import org.eclipse.aether.graph.DependencyFilter;
74 import org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider;
75 import org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager;
76 import org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer;
77 import org.eclipse.aether.repository.RemoteRepository;
78 import org.eclipse.aether.repository.WorkspaceReader;
79 import org.eclipse.aether.resolution.ArtifactResult;
80 import org.eclipse.aether.resolution.DependencyResult;
81 import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
82 import org.eclipse.aether.util.version.GenericVersionScheme;
83 import org.eclipse.sisu.Nullable;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
86
87
88
89
90 @Deprecated
91 @Named
92 public class BootstrapCoreExtensionManager {
93 public static final String STRATEGY_PARENT_FIRST = "parent-first";
94 public static final String STRATEGY_PLUGIN = "plugin";
95 public static final String STRATEGY_SELF_FIRST = "self-first";
96
97 private final Logger log = LoggerFactory.getLogger(getClass());
98
99 private final DefaultPluginDependenciesResolver pluginDependenciesResolver;
100
101 private final RepositorySystemSessionFactory repositorySystemSessionFactory;
102
103 private final CoreExports coreExports;
104
105 private final ClassWorld classWorld;
106
107 private final ClassRealm parentRealm;
108
109 private final WorkspaceReader ideWorkspaceReader;
110
111 private final RepositorySystem repoSystem;
112
113 @Inject
114 public BootstrapCoreExtensionManager(
115 DefaultPluginDependenciesResolver pluginDependenciesResolver,
116 RepositorySystemSessionFactory repositorySystemSessionFactory,
117 CoreExports coreExports,
118 PlexusContainer container,
119 @Nullable @Named("ide") WorkspaceReader ideWorkspaceReader,
120 RepositorySystem repoSystem) {
121 this.pluginDependenciesResolver = pluginDependenciesResolver;
122 this.repositorySystemSessionFactory = repositorySystemSessionFactory;
123 this.coreExports = coreExports;
124 this.classWorld = ((DefaultPlexusContainer) container).getClassWorld();
125 this.parentRealm = container.getContainerRealm();
126 this.ideWorkspaceReader = ideWorkspaceReader;
127 this.repoSystem = repoSystem;
128 }
129
130 public List<CoreExtensionEntry> loadCoreExtensions(
131 MavenExecutionRequest request, Set<String> providedArtifacts, List<CoreExtension> extensions)
132 throws Exception {
133 try (CloseableSession repoSession = repositorySystemSessionFactory
134 .newRepositorySessionBuilder(request)
135 .setWorkspaceReader(new MavenChainedWorkspaceReader(request.getWorkspaceReader(), ideWorkspaceReader))
136 .build()) {
137 MavenSession mSession = new MavenSession(repoSession, request, new DefaultMavenExecutionResult());
138 InternalSession iSession = new SimpleSession(mSession, repoSystem, null);
139 InternalSession.associate(repoSession, iSession);
140
141 List<RemoteRepository> repositories = RepositoryUtils.toRepos(request.getPluginArtifactRepositories());
142 Function<String, String> interpolator = createInterpolator(request);
143
144 return resolveCoreExtensions(repoSession, repositories, providedArtifacts, extensions, interpolator);
145 }
146 }
147
148 private List<CoreExtensionEntry> resolveCoreExtensions(
149 RepositorySystemSession repoSession,
150 List<RemoteRepository> repositories,
151 Set<String> providedArtifacts,
152 List<CoreExtension> configuration,
153 Function<String, String> interpolator)
154 throws Exception {
155 List<CoreExtensionEntry> extensions = new ArrayList<>();
156
157 DependencyFilter dependencyFilter = new ExclusionsDependencyFilter(providedArtifacts);
158
159 for (CoreExtension extension : configuration) {
160 List<Artifact> artifacts =
161 resolveExtension(extension, repoSession, repositories, dependencyFilter, interpolator);
162 if (!artifacts.isEmpty()) {
163 extensions.add(createExtension(extension, artifacts));
164 }
165 }
166
167 return Collections.unmodifiableList(extensions);
168 }
169
170 private CoreExtensionEntry createExtension(CoreExtension extension, List<Artifact> artifacts) throws Exception {
171 String realmId = "coreExtension>" + extension.getGroupId() + ":" + extension.getArtifactId() + ":"
172 + extension.getVersion();
173 final ClassRealm realm = classWorld.newRealm(realmId, null);
174 Set<String> providedArtifacts = Collections.emptySet();
175 String classLoadingStrategy = extension.getClassLoadingStrategy();
176 if (STRATEGY_PARENT_FIRST.equals(classLoadingStrategy)) {
177 realm.importFrom(parentRealm, "");
178 } else if (STRATEGY_PLUGIN.equals(classLoadingStrategy)) {
179 coreExports.getExportedPackages().forEach((p, cl) -> realm.importFrom(cl, p));
180 providedArtifacts = coreExports.getExportedArtifacts();
181 } else if (STRATEGY_SELF_FIRST.equals(classLoadingStrategy)) {
182 realm.setParentRealm(parentRealm);
183 } else {
184 throw new IllegalArgumentException("Unsupported class-loading strategy '"
185 + classLoadingStrategy + "'. Supported values are: " + STRATEGY_PARENT_FIRST
186 + ", " + STRATEGY_PLUGIN + " and " + STRATEGY_SELF_FIRST);
187 }
188 log.debug("Populating class realm {}", realm.getId());
189 for (Artifact artifact : artifacts) {
190 String id = artifact.getGroupId() + ":" + artifact.getArtifactId();
191 if (providedArtifacts.contains(id)) {
192 log.debug(" Excluded {}", id);
193 } else {
194 File file = artifact.getFile();
195 log.debug(" Included {} located at {}", id, file);
196 realm.addURL(file.toURI().toURL());
197 }
198 }
199 return CoreExtensionEntry.discoverFrom(
200 realm,
201 Collections.singleton(artifacts.get(0).getFile()),
202 extension.getGroupId() + ":" + extension.getArtifactId(),
203 extension.getConfiguration());
204 }
205
206 private List<Artifact> resolveExtension(
207 CoreExtension extension,
208 RepositorySystemSession repoSession,
209 List<RemoteRepository> repositories,
210 DependencyFilter dependencyFilter,
211 Function<String, String> interpolator)
212 throws ExtensionResolutionException {
213 try {
214
215
216
217
218 Plugin plugin = Plugin.newBuilder()
219 .groupId(interpolator.apply(extension.getGroupId()))
220 .artifactId(interpolator.apply(extension.getArtifactId()))
221 .version(interpolator.apply(extension.getVersion()))
222 .build();
223
224 DependencyResult result = pluginDependenciesResolver.resolveCoreExtension(
225 new org.apache.maven.model.Plugin(plugin), dependencyFilter, repositories, repoSession);
226 return result.getArtifactResults().stream()
227 .filter(ArtifactResult::isResolved)
228 .map(ArtifactResult::getArtifact)
229 .collect(Collectors.toList());
230 } catch (PluginResolutionException | InterpolatorException e) {
231 throw new ExtensionResolutionException(extension, e);
232 }
233 }
234
235 private static Function<String, String> createInterpolator(MavenExecutionRequest request) {
236 Interpolator interpolator = new DefaultInterpolator();
237 Function<String, String> callback = v -> {
238 String r = request.getUserProperties().getProperty(v);
239 if (r == null) {
240 r = request.getSystemProperties().getProperty(v);
241 }
242 return r != null ? r : v;
243 };
244 return v -> interpolator.interpolate(v, callback);
245 }
246
247 static class SimpleSession extends DefaultSession {
248 SimpleSession(
249 MavenSession session,
250 RepositorySystem repositorySystem,
251 List<org.apache.maven.api.RemoteRepository> repositories) {
252 super(session, repositorySystem, repositories, null, null, null);
253 }
254
255 @Override
256 protected Session newSession(
257 MavenSession mavenSession, List<org.apache.maven.api.RemoteRepository> repositories) {
258 return new SimpleSession(mavenSession, getRepositorySystem(), repositories);
259 }
260
261 @Override
262 public <T extends Service> T getService(Class<T> clazz) throws NoSuchElementException {
263 if (clazz == ArtifactCoordinatesFactory.class) {
264 return (T) new DefaultArtifactCoordinatesFactory();
265 } else if (clazz == VersionParser.class) {
266 return (T) new DefaultVersionParser(new DefaultModelVersionParser(new GenericVersionScheme()));
267 } else if (clazz == VersionRangeResolver.class) {
268 return (T) new DefaultVersionRangeResolver(repositorySystem);
269 } else if (clazz == ArtifactResolver.class) {
270 return (T) new DefaultArtifactResolver();
271 } else if (clazz == ArtifactManager.class) {
272 return (T) new DefaultArtifactManager(this);
273 } else if (clazz == RepositoryFactory.class) {
274 return (T) new DefaultRepositoryFactory(new DefaultRemoteRepositoryManager(
275 new DefaultUpdatePolicyAnalyzer(), new DefaultChecksumPolicyProvider()));
276 } else if (clazz == Interpolator.class) {
277 return (T) new DefaultInterpolator();
278
279
280 }
281 throw new NoSuchElementException("No service for " + clazz.getName());
282 }
283 }
284 }