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