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