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