1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugin.internal;
20
21 import java.io.BufferedInputStream;
22 import java.io.ByteArrayOutputStream;
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.PrintStream;
28 import java.io.Reader;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.Collections;
32 import java.util.HashMap;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Objects;
37 import java.util.jar.JarFile;
38 import java.util.zip.ZipEntry;
39
40 import org.apache.maven.RepositoryUtils;
41 import org.apache.maven.artifact.Artifact;
42 import org.apache.maven.classrealm.ClassRealmManager;
43 import org.apache.maven.execution.MavenSession;
44 import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
45 import org.apache.maven.model.Plugin;
46 import org.apache.maven.monitor.logging.DefaultLog;
47 import org.apache.maven.plugin.ContextEnabled;
48 import org.apache.maven.plugin.DebugConfigurationListener;
49 import org.apache.maven.plugin.ExtensionRealmCache;
50 import org.apache.maven.plugin.InvalidPluginDescriptorException;
51 import org.apache.maven.plugin.MavenPluginManager;
52 import org.apache.maven.plugin.MavenPluginValidator;
53 import org.apache.maven.plugin.Mojo;
54 import org.apache.maven.plugin.MojoExecution;
55 import org.apache.maven.plugin.MojoNotFoundException;
56 import org.apache.maven.plugin.PluginArtifactsCache;
57 import org.apache.maven.plugin.PluginConfigurationException;
58 import org.apache.maven.plugin.PluginContainerException;
59 import org.apache.maven.plugin.PluginDescriptorCache;
60 import org.apache.maven.plugin.PluginDescriptorParsingException;
61 import org.apache.maven.plugin.PluginIncompatibleException;
62 import org.apache.maven.plugin.PluginManagerException;
63 import org.apache.maven.plugin.PluginParameterException;
64 import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
65 import org.apache.maven.plugin.PluginRealmCache;
66 import org.apache.maven.plugin.PluginResolutionException;
67 import org.apache.maven.plugin.descriptor.MojoDescriptor;
68 import org.apache.maven.plugin.descriptor.Parameter;
69 import org.apache.maven.plugin.descriptor.PluginDescriptor;
70 import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
71 import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
72 import org.apache.maven.plugin.version.PluginVersionRequest;
73 import org.apache.maven.plugin.version.PluginVersionResolutionException;
74 import org.apache.maven.plugin.version.PluginVersionResolver;
75 import org.apache.maven.project.ExtensionDescriptor;
76 import org.apache.maven.project.ExtensionDescriptorBuilder;
77 import org.apache.maven.project.MavenProject;
78 import org.apache.maven.rtinfo.RuntimeInformation;
79 import org.apache.maven.session.scope.internal.SessionScopeModule;
80 import org.codehaus.plexus.DefaultPlexusContainer;
81 import org.codehaus.plexus.PlexusContainer;
82 import org.codehaus.plexus.classworlds.realm.ClassRealm;
83 import org.codehaus.plexus.component.annotations.Component;
84 import org.codehaus.plexus.component.annotations.Requirement;
85 import org.codehaus.plexus.component.composition.CycleDetectedInComponentGraphException;
86 import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
87 import org.codehaus.plexus.component.configurator.ComponentConfigurator;
88 import org.codehaus.plexus.component.configurator.ConfigurationListener;
89 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
90 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
91 import org.codehaus.plexus.component.repository.ComponentDescriptor;
92 import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
93 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
94 import org.codehaus.plexus.configuration.PlexusConfiguration;
95 import org.codehaus.plexus.configuration.PlexusConfigurationException;
96 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
97 import org.codehaus.plexus.logging.Logger;
98 import org.codehaus.plexus.logging.LoggerManager;
99 import org.codehaus.plexus.util.ReaderFactory;
100 import org.codehaus.plexus.util.StringUtils;
101 import org.codehaus.plexus.util.xml.Xpp3Dom;
102 import org.eclipse.aether.RepositorySystemSession;
103 import org.eclipse.aether.graph.DependencyFilter;
104 import org.eclipse.aether.graph.DependencyNode;
105 import org.eclipse.aether.repository.RemoteRepository;
106 import org.eclipse.aether.util.filter.AndDependencyFilter;
107 import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
108
109
110
111
112
113
114
115
116
117 @Component(role = MavenPluginManager.class)
118 public class DefaultMavenPluginManager implements MavenPluginManager {
119
120
121
122
123
124
125
126
127
128
129 public static final String KEY_EXTENSIONS_REALMS = DefaultMavenPluginManager.class.getName() + "/extensionsRealms";
130
131 @Requirement
132 private Logger logger;
133
134 @Requirement
135 private LoggerManager loggerManager;
136
137 @Requirement
138 private PlexusContainer container;
139
140 @Requirement
141 private ClassRealmManager classRealmManager;
142
143 @Requirement
144 private PluginDescriptorCache pluginDescriptorCache;
145
146 @Requirement
147 private PluginRealmCache pluginRealmCache;
148
149 @Requirement
150 private PluginDependenciesResolver pluginDependenciesResolver;
151
152 @Requirement
153 private RuntimeInformation runtimeInformation;
154
155 @Requirement
156 private ExtensionRealmCache extensionRealmCache;
157
158 @Requirement
159 private PluginVersionResolver pluginVersionResolver;
160
161 @Requirement
162 private PluginArtifactsCache pluginArtifactsCache;
163
164 @Requirement
165 private List<MavenPluginConfigurationValidator> configurationValidators;
166
167 private ExtensionDescriptorBuilder extensionDescriptorBuilder = new ExtensionDescriptorBuilder();
168
169 private PluginDescriptorBuilder builder = new PluginDescriptorBuilder();
170
171 public PluginDescriptor getPluginDescriptor(
172 Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session)
173 throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException {
174 PluginDescriptorCache.Key cacheKey = pluginDescriptorCache.createKey(plugin, repositories, session);
175
176 PluginDescriptor pluginDescriptor = pluginDescriptorCache.get(cacheKey, () -> {
177 org.eclipse.aether.artifact.Artifact artifact =
178 pluginDependenciesResolver.resolve(plugin, repositories, session);
179
180 Artifact pluginArtifact = RepositoryUtils.toArtifact(artifact);
181
182 PluginDescriptor descriptor = extractPluginDescriptor(pluginArtifact, plugin);
183
184 if (StringUtils.isBlank(descriptor.getRequiredMavenVersion())) {
185
186 descriptor.setRequiredMavenVersion(artifact.getProperty("requiredMavenVersion", null));
187 }
188
189 return descriptor;
190 });
191
192 pluginDescriptor.setPlugin(plugin);
193
194 return pluginDescriptor;
195 }
196
197 private PluginDescriptor extractPluginDescriptor(Artifact pluginArtifact, Plugin plugin)
198 throws PluginDescriptorParsingException, InvalidPluginDescriptorException {
199 PluginDescriptor pluginDescriptor = null;
200
201 File pluginFile = pluginArtifact.getFile();
202
203 try {
204 if (pluginFile.isFile()) {
205 try (JarFile pluginJar = new JarFile(pluginFile, false)) {
206 ZipEntry pluginDescriptorEntry = pluginJar.getEntry(getPluginDescriptorLocation());
207
208 if (pluginDescriptorEntry != null) {
209 InputStream is = pluginJar.getInputStream(pluginDescriptorEntry);
210
211 pluginDescriptor = parsePluginDescriptor(is, plugin, pluginFile.getAbsolutePath());
212 }
213 }
214 } else {
215 File pluginXml = new File(pluginFile, getPluginDescriptorLocation());
216
217 if (pluginXml.isFile()) {
218 try (InputStream is = new BufferedInputStream(new FileInputStream(pluginXml))) {
219 pluginDescriptor = parsePluginDescriptor(is, plugin, pluginXml.getAbsolutePath());
220 }
221 }
222 }
223
224 if (pluginDescriptor == null) {
225 throw new IOException("No plugin descriptor found at " + getPluginDescriptorLocation());
226 }
227 } catch (IOException e) {
228 throw new PluginDescriptorParsingException(plugin, pluginFile.getAbsolutePath(), e);
229 }
230
231 MavenPluginValidator validator = new MavenPluginValidator(pluginArtifact);
232
233 validator.validate(pluginDescriptor);
234
235 if (validator.hasErrors()) {
236 throw new InvalidPluginDescriptorException(
237 "Invalid plugin descriptor for " + plugin.getId() + " (" + pluginFile + ")", validator.getErrors());
238 }
239
240 pluginDescriptor.setPluginArtifact(pluginArtifact);
241
242 return pluginDescriptor;
243 }
244
245 private String getPluginDescriptorLocation() {
246 return "META-INF/maven/plugin.xml";
247 }
248
249 private PluginDescriptor parsePluginDescriptor(InputStream is, Plugin plugin, String descriptorLocation)
250 throws PluginDescriptorParsingException {
251 try {
252 Reader reader = ReaderFactory.newXmlReader(is);
253
254 PluginDescriptor pluginDescriptor = builder.build(reader, descriptorLocation);
255
256 return pluginDescriptor;
257 } catch (IOException | PlexusConfigurationException e) {
258 throw new PluginDescriptorParsingException(plugin, descriptorLocation, e);
259 }
260 }
261
262 public MojoDescriptor getMojoDescriptor(
263 Plugin plugin, String goal, List<RemoteRepository> repositories, RepositorySystemSession session)
264 throws MojoNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
265 InvalidPluginDescriptorException {
266 PluginDescriptor pluginDescriptor = getPluginDescriptor(plugin, repositories, session);
267
268 MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo(goal);
269
270 if (mojoDescriptor == null) {
271 throw new MojoNotFoundException(goal, pluginDescriptor);
272 }
273
274 return mojoDescriptor;
275 }
276
277 public void checkRequiredMavenVersion(PluginDescriptor pluginDescriptor) throws PluginIncompatibleException {
278 String requiredMavenVersion = pluginDescriptor.getRequiredMavenVersion();
279 if (StringUtils.isNotBlank(requiredMavenVersion)) {
280 try {
281 if (!runtimeInformation.isMavenVersion(requiredMavenVersion)) {
282 throw new PluginIncompatibleException(
283 pluginDescriptor.getPlugin(),
284 "The plugin " + pluginDescriptor.getId() + " requires Maven version "
285 + requiredMavenVersion);
286 }
287 } catch (RuntimeException e) {
288 logger.warn("Could not verify plugin's Maven prerequisite: " + e.getMessage());
289 }
290 }
291 }
292
293 public void setupPluginRealm(
294 PluginDescriptor pluginDescriptor,
295 MavenSession session,
296 ClassLoader parent,
297 List<String> imports,
298 DependencyFilter filter)
299 throws PluginResolutionException, PluginContainerException {
300 Plugin plugin = pluginDescriptor.getPlugin();
301 MavenProject project = session.getCurrentProject();
302
303 if (plugin.isExtensions()) {
304 ExtensionRealmCache.CacheRecord extensionRecord;
305 try {
306 RepositorySystemSession repositorySession = session.getRepositorySession();
307 extensionRecord = setupExtensionsRealm(project, plugin, repositorySession);
308 } catch (PluginManagerException e) {
309
310
311 throw new IllegalStateException(e);
312 }
313
314 ClassRealm pluginRealm = extensionRecord.getRealm();
315 List<Artifact> pluginArtifacts = extensionRecord.getArtifacts();
316
317 for (ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents()) {
318 componentDescriptor.setRealm(pluginRealm);
319 }
320
321 pluginDescriptor.setClassRealm(pluginRealm);
322 pluginDescriptor.setArtifacts(pluginArtifacts);
323 } else {
324 Map<String, ClassLoader> foreignImports = calcImports(project, parent, imports);
325
326 PluginRealmCache.Key cacheKey = pluginRealmCache.createKey(
327 plugin,
328 parent,
329 foreignImports,
330 filter,
331 project.getRemotePluginRepositories(),
332 session.getRepositorySession());
333
334 PluginRealmCache.CacheRecord cacheRecord = pluginRealmCache.get(cacheKey, () -> {
335 createPluginRealm(pluginDescriptor, session, parent, foreignImports, filter);
336
337 return new PluginRealmCache.CacheRecord(
338 pluginDescriptor.getClassRealm(), pluginDescriptor.getArtifacts());
339 });
340
341 pluginDescriptor.setClassRealm(cacheRecord.getRealm());
342 pluginDescriptor.setArtifacts(new ArrayList<>(cacheRecord.getArtifacts()));
343 for (ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents()) {
344 componentDescriptor.setRealm(cacheRecord.getRealm());
345 }
346
347 pluginRealmCache.register(project, cacheKey, cacheRecord);
348 }
349 }
350
351 private void createPluginRealm(
352 PluginDescriptor pluginDescriptor,
353 MavenSession session,
354 ClassLoader parent,
355 Map<String, ClassLoader> foreignImports,
356 DependencyFilter filter)
357 throws PluginResolutionException, PluginContainerException {
358 Plugin plugin = Objects.requireNonNull(pluginDescriptor.getPlugin(), "pluginDescriptor.plugin cannot be null");
359
360 Artifact pluginArtifact = Objects.requireNonNull(
361 pluginDescriptor.getPluginArtifact(), "pluginDescriptor.pluginArtifact cannot be null");
362
363 MavenProject project = session.getCurrentProject();
364
365 final ClassRealm pluginRealm;
366 final List<Artifact> pluginArtifacts;
367
368 RepositorySystemSession repositorySession = session.getRepositorySession();
369 DependencyFilter dependencyFilter = project.getExtensionDependencyFilter();
370 dependencyFilter = AndDependencyFilter.newInstance(dependencyFilter, filter);
371
372 DependencyNode root = pluginDependenciesResolver.resolve(
373 plugin,
374 RepositoryUtils.toArtifact(pluginArtifact),
375 dependencyFilter,
376 project.getRemotePluginRepositories(),
377 repositorySession);
378
379 PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
380 root.accept(nlg);
381
382 pluginArtifacts = toMavenArtifacts(root, nlg);
383
384 pluginRealm = classRealmManager.createPluginRealm(
385 plugin, parent, null, foreignImports, toAetherArtifacts(pluginArtifacts));
386
387 discoverPluginComponents(pluginRealm, plugin, pluginDescriptor);
388
389 pluginDescriptor.setClassRealm(pluginRealm);
390 pluginDescriptor.setArtifacts(pluginArtifacts);
391 }
392
393 private void discoverPluginComponents(
394 final ClassRealm pluginRealm, Plugin plugin, PluginDescriptor pluginDescriptor)
395 throws PluginContainerException {
396 try {
397 if (pluginDescriptor != null) {
398 for (ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents()) {
399 componentDescriptor.setRealm(pluginRealm);
400 container.addComponentDescriptor(componentDescriptor);
401 }
402 }
403
404 ((DefaultPlexusContainer) container)
405 .discoverComponents(
406 pluginRealm, new SessionScopeModule(container), new MojoExecutionScopeModule(container));
407 } catch (ComponentLookupException | CycleDetectedInComponentGraphException e) {
408 throw new PluginContainerException(
409 plugin,
410 pluginRealm,
411 "Error in component graph of plugin " + plugin.getId() + ": " + e.getMessage(),
412 e);
413 }
414 }
415
416 private List<org.eclipse.aether.artifact.Artifact> toAetherArtifacts(final List<Artifact> pluginArtifacts) {
417 return new ArrayList<>(RepositoryUtils.toArtifacts(pluginArtifacts));
418 }
419
420 private List<Artifact> toMavenArtifacts(DependencyNode root, PreorderNodeListGenerator nlg) {
421 List<Artifact> artifacts = new ArrayList<>(nlg.getNodes().size());
422 RepositoryUtils.toArtifacts(artifacts, Collections.singleton(root), Collections.<String>emptyList(), null);
423 for (Iterator<Artifact> it = artifacts.iterator(); it.hasNext(); ) {
424 Artifact artifact = it.next();
425 if (artifact.getFile() == null) {
426 it.remove();
427 }
428 }
429 return Collections.unmodifiableList(artifacts);
430 }
431
432 private Map<String, ClassLoader> calcImports(MavenProject project, ClassLoader parent, List<String> imports) {
433 Map<String, ClassLoader> foreignImports = new HashMap<>();
434
435 ClassLoader projectRealm = project.getClassRealm();
436 if (projectRealm != null) {
437 foreignImports.put("", projectRealm);
438 } else {
439 foreignImports.put("", classRealmManager.getMavenApiRealm());
440 }
441
442 if (parent != null && imports != null) {
443 for (String parentImport : imports) {
444 foreignImports.put(parentImport, parent);
445 }
446 }
447
448 return foreignImports;
449 }
450
451 public <T> T getConfiguredMojo(Class<T> mojoInterface, MavenSession session, MojoExecution mojoExecution)
452 throws PluginConfigurationException, PluginContainerException {
453 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
454
455 PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
456
457 ClassRealm pluginRealm = pluginDescriptor.getClassRealm();
458
459 if (pluginRealm == null) {
460 try {
461 setupPluginRealm(pluginDescriptor, session, null, null, null);
462 } catch (PluginResolutionException e) {
463 String msg = "Cannot setup plugin realm [mojoDescriptor=" + mojoDescriptor.getId()
464 + ", pluginDescriptor=" + pluginDescriptor.getId() + "]";
465 throw new PluginConfigurationException(pluginDescriptor, msg, e);
466 }
467 pluginRealm = pluginDescriptor.getClassRealm();
468 }
469
470 if (logger.isDebugEnabled()) {
471 logger.debug("Loading mojo " + mojoDescriptor.getId() + " from plugin realm " + pluginRealm);
472 }
473
474
475
476
477 ClassRealm oldLookupRealm = container.setLookupRealm(pluginRealm);
478
479 ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
480 Thread.currentThread().setContextClassLoader(pluginRealm);
481
482 try {
483 T mojo;
484
485 try {
486 mojo = container.lookup(mojoInterface, mojoDescriptor.getRoleHint());
487 } catch (ComponentLookupException e) {
488 Throwable cause = e.getCause();
489 while (cause != null
490 && !(cause instanceof LinkageError)
491 && !(cause instanceof ClassNotFoundException)) {
492 cause = cause.getCause();
493 }
494
495 if ((cause instanceof NoClassDefFoundError) || (cause instanceof ClassNotFoundException)) {
496 ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
497 PrintStream ps = new PrintStream(os);
498 ps.println("Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '"
499 + pluginDescriptor.getId() + "'. A required class is missing: "
500 + cause.getMessage());
501 pluginRealm.display(ps);
502
503 throw new PluginContainerException(mojoDescriptor, pluginRealm, os.toString(), cause);
504 } else if (cause instanceof LinkageError) {
505 ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
506 PrintStream ps = new PrintStream(os);
507 ps.println("Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '"
508 + pluginDescriptor.getId() + "' due to an API incompatibility: "
509 + e.getClass().getName() + ": " + cause.getMessage());
510 pluginRealm.display(ps);
511
512 throw new PluginContainerException(mojoDescriptor, pluginRealm, os.toString(), cause);
513 }
514
515 throw new PluginContainerException(
516 mojoDescriptor,
517 pluginRealm,
518 "Unable to load the mojo '" + mojoDescriptor.getGoal()
519 + "' (or one of its required components) from the plugin '"
520 + pluginDescriptor.getId() + "'",
521 e);
522 }
523
524 if (mojo instanceof ContextEnabled) {
525 MavenProject project = session.getCurrentProject();
526
527 Map<String, Object> pluginContext = session.getPluginContext(pluginDescriptor, project);
528
529 if (pluginContext != null) {
530 pluginContext.put("project", project);
531
532 pluginContext.put("pluginDescriptor", pluginDescriptor);
533
534 ((ContextEnabled) mojo).setPluginContext(pluginContext);
535 }
536 }
537
538 if (mojo instanceof Mojo) {
539 Logger mojoLogger = loggerManager.getLoggerForComponent(mojoDescriptor.getImplementation());
540 ((Mojo) mojo).setLog(new DefaultLog(mojoLogger));
541 }
542
543 Xpp3Dom dom = mojoExecution.getConfiguration();
544
545 PlexusConfiguration pomConfiguration;
546
547 if (dom == null) {
548 pomConfiguration = new XmlPlexusConfiguration("configuration");
549 } else {
550 pomConfiguration = new XmlPlexusConfiguration(dom);
551 }
552
553 ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator(session, mojoExecution);
554
555 for (MavenPluginConfigurationValidator validator : configurationValidators) {
556 validator.validate(mojoDescriptor, pomConfiguration, expressionEvaluator);
557 }
558
559 populateMojoExecutionFields(
560 mojo,
561 mojoExecution.getExecutionId(),
562 mojoDescriptor,
563 pluginRealm,
564 pomConfiguration,
565 expressionEvaluator);
566
567 return mojo;
568 } finally {
569 Thread.currentThread().setContextClassLoader(oldClassLoader);
570 container.setLookupRealm(oldLookupRealm);
571 }
572 }
573
574 private void populateMojoExecutionFields(
575 Object mojo,
576 String executionId,
577 MojoDescriptor mojoDescriptor,
578 ClassRealm pluginRealm,
579 PlexusConfiguration configuration,
580 ExpressionEvaluator expressionEvaluator)
581 throws PluginConfigurationException {
582 ComponentConfigurator configurator = null;
583
584 String configuratorId = mojoDescriptor.getComponentConfigurator();
585
586 if (StringUtils.isEmpty(configuratorId)) {
587 configuratorId = "basic";
588 }
589
590 try {
591
592
593 configurator = container.lookup(ComponentConfigurator.class, configuratorId);
594
595 ConfigurationListener listener = new DebugConfigurationListener(logger);
596
597 ValidatingConfigurationListener validator =
598 new ValidatingConfigurationListener(mojo, mojoDescriptor, listener);
599
600 logger.debug("Configuring mojo execution '" + mojoDescriptor.getId() + ':' + executionId + "' with "
601 + configuratorId + " configurator -->");
602
603 configurator.configureComponent(mojo, configuration, expressionEvaluator, pluginRealm, validator);
604
605 logger.debug("-- end configuration --");
606
607 Collection<Parameter> missingParameters = validator.getMissingParameters();
608 if (!missingParameters.isEmpty()) {
609 if ("basic".equals(configuratorId)) {
610 throw new PluginParameterException(mojoDescriptor, new ArrayList<>(missingParameters));
611 } else {
612
613
614
615
616 validateParameters(mojoDescriptor, configuration, expressionEvaluator);
617 }
618 }
619 } catch (ComponentConfigurationException e) {
620 String message = "Unable to parse configuration of mojo " + mojoDescriptor.getId();
621 if (e.getFailedConfiguration() != null) {
622 message += " for parameter " + e.getFailedConfiguration().getName();
623 }
624 message += ": " + e.getMessage();
625
626 throw new PluginConfigurationException(mojoDescriptor.getPluginDescriptor(), message, e);
627 } catch (ComponentLookupException e) {
628 throw new PluginConfigurationException(
629 mojoDescriptor.getPluginDescriptor(),
630 "Unable to retrieve component configurator " + configuratorId + " for configuration of mojo "
631 + mojoDescriptor.getId(),
632 e);
633 } catch (NoClassDefFoundError e) {
634 ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
635 PrintStream ps = new PrintStream(os);
636 ps.println("A required class was missing during configuration of mojo " + mojoDescriptor.getId() + ": "
637 + e.getMessage());
638 pluginRealm.display(ps);
639
640 throw new PluginConfigurationException(mojoDescriptor.getPluginDescriptor(), os.toString(), e);
641 } catch (LinkageError e) {
642 ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
643 PrintStream ps = new PrintStream(os);
644 ps.println("An API incompatibility was encountered during configuration of mojo " + mojoDescriptor.getId()
645 + ": " + e.getClass().getName() + ": " + e.getMessage());
646 pluginRealm.display(ps);
647
648 throw new PluginConfigurationException(mojoDescriptor.getPluginDescriptor(), os.toString(), e);
649 } finally {
650 if (configurator != null) {
651 try {
652 container.release(configurator);
653 } catch (ComponentLifecycleException e) {
654 logger.debug("Failed to release mojo configurator - ignoring.");
655 }
656 }
657 }
658 }
659
660 private void validateParameters(
661 MojoDescriptor mojoDescriptor, PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator)
662 throws ComponentConfigurationException, PluginParameterException {
663 if (mojoDescriptor.getParameters() == null) {
664 return;
665 }
666
667 List<Parameter> invalidParameters = new ArrayList<>();
668
669 for (Parameter parameter : mojoDescriptor.getParameters()) {
670 if (!parameter.isRequired()) {
671 continue;
672 }
673
674 Object value = null;
675
676 PlexusConfiguration config = configuration.getChild(parameter.getName(), false);
677 if (config != null) {
678 String expression = config.getValue(null);
679
680 try {
681 value = expressionEvaluator.evaluate(expression);
682
683 if (value == null) {
684 value = config.getAttribute("default-value", null);
685 }
686 } catch (ExpressionEvaluationException e) {
687 String msg = "Error evaluating the expression '" + expression + "' for configuration value '"
688 + configuration.getName() + "'";
689 throw new ComponentConfigurationException(configuration, msg, e);
690 }
691 }
692
693 if (value == null && (config == null || config.getChildCount() <= 0)) {
694 invalidParameters.add(parameter);
695 }
696 }
697
698 if (!invalidParameters.isEmpty()) {
699 throw new PluginParameterException(mojoDescriptor, invalidParameters);
700 }
701 }
702
703 public void releaseMojo(Object mojo, MojoExecution mojoExecution) {
704 if (mojo != null) {
705 try {
706 container.release(mojo);
707 } catch (ComponentLifecycleException e) {
708 String goalExecId = mojoExecution.getGoal();
709
710 if (mojoExecution.getExecutionId() != null) {
711 goalExecId += " {execution: " + mojoExecution.getExecutionId() + "}";
712 }
713
714 logger.debug("Error releasing mojo for " + goalExecId, e);
715 }
716 }
717 }
718
719 public ExtensionRealmCache.CacheRecord setupExtensionsRealm(
720 MavenProject project, Plugin plugin, RepositorySystemSession session) throws PluginManagerException {
721 @SuppressWarnings("unchecked")
722 Map<String, ExtensionRealmCache.CacheRecord> pluginRealms =
723 (Map<String, ExtensionRealmCache.CacheRecord>) project.getContextValue(KEY_EXTENSIONS_REALMS);
724 if (pluginRealms == null) {
725 pluginRealms = new HashMap<>();
726 project.setContextValue(KEY_EXTENSIONS_REALMS, pluginRealms);
727 }
728
729 final String pluginKey = plugin.getId();
730
731 ExtensionRealmCache.CacheRecord extensionRecord = pluginRealms.get(pluginKey);
732 if (extensionRecord != null) {
733 return extensionRecord;
734 }
735
736 final List<RemoteRepository> repositories = project.getRemotePluginRepositories();
737
738
739 if (plugin.getVersion() == null) {
740 PluginVersionRequest versionRequest = new DefaultPluginVersionRequest(plugin, session, repositories);
741 try {
742 plugin.setVersion(pluginVersionResolver.resolve(versionRequest).getVersion());
743 } catch (PluginVersionResolutionException e) {
744 throw new PluginManagerException(plugin, e.getMessage(), e);
745 }
746 }
747
748
749 List<Artifact> artifacts;
750 PluginArtifactsCache.Key cacheKey = pluginArtifactsCache.createKey(plugin, null, repositories, session);
751 PluginArtifactsCache.CacheRecord recordArtifacts;
752 try {
753 recordArtifacts = pluginArtifactsCache.get(cacheKey);
754 } catch (PluginResolutionException e) {
755 throw new PluginManagerException(plugin, e.getMessage(), e);
756 }
757 if (recordArtifacts != null) {
758 artifacts = recordArtifacts.getArtifacts();
759 } else {
760 try {
761 artifacts = resolveExtensionArtifacts(plugin, repositories, session);
762 recordArtifacts = pluginArtifactsCache.put(cacheKey, artifacts);
763 } catch (PluginResolutionException e) {
764 pluginArtifactsCache.put(cacheKey, e);
765 pluginArtifactsCache.register(project, cacheKey, recordArtifacts);
766 throw new PluginManagerException(plugin, e.getMessage(), e);
767 }
768 }
769 pluginArtifactsCache.register(project, cacheKey, recordArtifacts);
770
771
772 final ExtensionRealmCache.Key extensionKey = extensionRealmCache.createKey(artifacts);
773 extensionRecord = extensionRealmCache.get(extensionKey);
774 if (extensionRecord == null) {
775 ClassRealm extensionRealm = classRealmManager.createExtensionRealm(plugin, toAetherArtifacts(artifacts));
776
777
778
779 PluginDescriptor pluginDescriptor = null;
780 if (plugin.isExtensions() && !artifacts.isEmpty()) {
781
782
783 try {
784 pluginDescriptor = extractPluginDescriptor(artifacts.get(0), plugin);
785 } catch (PluginDescriptorParsingException | InvalidPluginDescriptorException e) {
786
787 }
788 }
789
790 discoverPluginComponents(extensionRealm, plugin, pluginDescriptor);
791
792 ExtensionDescriptor extensionDescriptor = null;
793 Artifact extensionArtifact = artifacts.get(0);
794 try {
795 extensionDescriptor = extensionDescriptorBuilder.build(extensionArtifact.getFile());
796 } catch (IOException e) {
797 String message = "Invalid extension descriptor for " + plugin.getId() + ": " + e.getMessage();
798 if (logger.isDebugEnabled()) {
799 logger.error(message, e);
800 } else {
801 logger.error(message);
802 }
803 }
804 extensionRecord = extensionRealmCache.put(extensionKey, extensionRealm, extensionDescriptor, artifacts);
805 }
806 extensionRealmCache.register(project, extensionKey, extensionRecord);
807 pluginRealms.put(pluginKey, extensionRecord);
808
809 return extensionRecord;
810 }
811
812 private List<Artifact> resolveExtensionArtifacts(
813 Plugin extensionPlugin, List<RemoteRepository> repositories, RepositorySystemSession session)
814 throws PluginResolutionException {
815 DependencyNode root = pluginDependenciesResolver.resolve(extensionPlugin, null, null, repositories, session);
816 PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
817 root.accept(nlg);
818 return toMavenArtifacts(root, nlg);
819 }
820 }