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.maven.RepositoryUtils;
23 import org.apache.maven.artifact.Artifact;
24 import org.apache.maven.classrealm.ClassRealmManager;
25 import org.apache.maven.execution.MavenSession;
26 import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
27 import org.apache.maven.model.Plugin;
28 import org.apache.maven.monitor.logging.DefaultLog;
29 import org.apache.maven.plugin.ContextEnabled;
30 import org.apache.maven.plugin.DebugConfigurationListener;
31 import org.apache.maven.plugin.ExtensionRealmCache;
32 import org.apache.maven.plugin.InvalidPluginDescriptorException;
33 import org.apache.maven.plugin.MavenPluginManager;
34 import org.apache.maven.plugin.MavenPluginValidator;
35 import org.apache.maven.plugin.Mojo;
36 import org.apache.maven.plugin.MojoExecution;
37 import org.apache.maven.plugin.MojoNotFoundException;
38 import org.apache.maven.plugin.PluginArtifactsCache;
39 import org.apache.maven.plugin.PluginConfigurationException;
40 import org.apache.maven.plugin.PluginContainerException;
41 import org.apache.maven.plugin.PluginDescriptorCache;
42 import org.apache.maven.plugin.PluginDescriptorParsingException;
43 import org.apache.maven.plugin.PluginIncompatibleException;
44 import org.apache.maven.plugin.PluginManagerException;
45 import org.apache.maven.plugin.PluginParameterException;
46 import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
47 import org.apache.maven.plugin.PluginRealmCache;
48 import org.apache.maven.plugin.PluginResolutionException;
49 import org.apache.maven.plugin.descriptor.MojoDescriptor;
50 import org.apache.maven.plugin.descriptor.Parameter;
51 import org.apache.maven.plugin.descriptor.PluginDescriptor;
52 import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
53 import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
54 import org.apache.maven.plugin.version.PluginVersionRequest;
55 import org.apache.maven.plugin.version.PluginVersionResolutionException;
56 import org.apache.maven.plugin.version.PluginVersionResolver;
57 import org.apache.maven.project.ExtensionDescriptor;
58 import org.apache.maven.project.ExtensionDescriptorBuilder;
59 import org.apache.maven.project.MavenProject;
60 import org.apache.maven.rtinfo.RuntimeInformation;
61 import org.apache.maven.session.scope.internal.SessionScopeModule;
62 import org.codehaus.plexus.DefaultPlexusContainer;
63 import org.codehaus.plexus.PlexusContainer;
64 import org.codehaus.plexus.classworlds.realm.ClassRealm;
65 import org.codehaus.plexus.component.annotations.Component;
66 import org.codehaus.plexus.component.annotations.Requirement;
67 import org.codehaus.plexus.component.composition.CycleDetectedInComponentGraphException;
68 import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
69 import org.codehaus.plexus.component.configurator.ComponentConfigurator;
70 import org.codehaus.plexus.component.configurator.ConfigurationListener;
71 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
72 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
73 import org.codehaus.plexus.component.repository.ComponentDescriptor;
74 import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
75 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
76 import org.codehaus.plexus.configuration.PlexusConfiguration;
77 import org.codehaus.plexus.configuration.PlexusConfigurationException;
78 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
79 import org.codehaus.plexus.logging.Logger;
80 import org.codehaus.plexus.logging.LoggerManager;
81 import org.codehaus.plexus.util.ReaderFactory;
82 import org.codehaus.plexus.util.StringUtils;
83 import org.codehaus.plexus.util.xml.Xpp3Dom;
84 import org.eclipse.aether.RepositorySystemSession;
85 import org.eclipse.aether.graph.DependencyFilter;
86 import org.eclipse.aether.graph.DependencyNode;
87 import org.eclipse.aether.repository.RemoteRepository;
88 import org.eclipse.aether.util.filter.AndDependencyFilter;
89 import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
90
91 import java.io.BufferedInputStream;
92 import java.io.ByteArrayOutputStream;
93 import java.io.File;
94 import java.io.FileInputStream;
95 import java.io.IOException;
96 import java.io.InputStream;
97 import java.io.PrintStream;
98 import java.io.Reader;
99 import java.util.ArrayList;
100 import java.util.Collection;
101 import java.util.Collections;
102 import java.util.HashMap;
103 import java.util.Iterator;
104 import java.util.List;
105 import java.util.Map;
106 import java.util.Objects;
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.getRealm();
343 List<Artifact> pluginArtifacts = extensionRecord.getArtifacts();
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.getRealm() );
366 pluginDescriptor.setArtifacts( new ArrayList<>( cacheRecord.getArtifacts() ) );
367 for ( ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents() )
368 {
369 componentDescriptor.setRealm( cacheRecord.getRealm() );
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 =
389 Objects.requireNonNull( pluginDescriptor.getPlugin(), "pluginDescriptor.plugin cannot be null" );
390
391 Artifact pluginArtifact = Objects.requireNonNull( pluginDescriptor.getPluginArtifact(),
392 "pluginDescriptor.pluginArtifact cannot be null" );
393
394 MavenProject project = session.getCurrentProject();
395
396 final ClassRealm pluginRealm;
397 final List<Artifact> pluginArtifacts;
398
399 RepositorySystemSession repositorySession = session.getRepositorySession();
400 DependencyFilter dependencyFilter = project.getExtensionDependencyFilter();
401 dependencyFilter = AndDependencyFilter.newInstance( dependencyFilter, filter );
402
403 DependencyNode root =
404 pluginDependenciesResolver.resolve( plugin, RepositoryUtils.toArtifact( pluginArtifact ), dependencyFilter,
405 project.getRemotePluginRepositories(), repositorySession );
406
407 PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
408 root.accept( nlg );
409
410 pluginArtifacts = toMavenArtifacts( root, nlg );
411
412 pluginRealm = classRealmManager.createPluginRealm( plugin, parent, null, foreignImports,
413 toAetherArtifacts( pluginArtifacts ) );
414
415 discoverPluginComponents( pluginRealm, plugin, pluginDescriptor );
416
417 pluginDescriptor.setClassRealm( pluginRealm );
418 pluginDescriptor.setArtifacts( pluginArtifacts );
419 }
420
421 private void discoverPluginComponents( final ClassRealm pluginRealm, Plugin plugin,
422 PluginDescriptor pluginDescriptor )
423 throws PluginContainerException
424 {
425 try
426 {
427 if ( pluginDescriptor != null )
428 {
429 for ( ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents() )
430 {
431 componentDescriptor.setRealm( pluginRealm );
432 container.addComponentDescriptor( componentDescriptor );
433 }
434 }
435
436 ( (DefaultPlexusContainer) container ).discoverComponents( pluginRealm, new SessionScopeModule( container ),
437 new MojoExecutionScopeModule( container ) );
438 }
439 catch ( ComponentLookupException | CycleDetectedInComponentGraphException e )
440 {
441 throw new PluginContainerException( plugin, pluginRealm,
442 "Error in component graph of plugin " + plugin.getId() + ": "
443 + e.getMessage(), e );
444 }
445 }
446
447 private List<org.eclipse.aether.artifact.Artifact> toAetherArtifacts( final List<Artifact> pluginArtifacts )
448 {
449 return new ArrayList<>( RepositoryUtils.toArtifacts( pluginArtifacts ) );
450 }
451
452 private List<Artifact> toMavenArtifacts( DependencyNode root, PreorderNodeListGenerator nlg )
453 {
454 List<Artifact> artifacts = new ArrayList<>( nlg.getNodes().size() );
455 RepositoryUtils.toArtifacts( artifacts, Collections.singleton( root ), Collections.<String>emptyList(), null );
456 for ( Iterator<Artifact> it = artifacts.iterator(); it.hasNext(); )
457 {
458 Artifact artifact = it.next();
459 if ( artifact.getFile() == null )
460 {
461 it.remove();
462 }
463 }
464 return Collections.unmodifiableList( artifacts );
465 }
466
467 private Map<String, ClassLoader> calcImports( MavenProject project, ClassLoader parent, List<String> imports )
468 {
469 Map<String, ClassLoader> foreignImports = new HashMap<>();
470
471 ClassLoader projectRealm = project.getClassRealm();
472 if ( projectRealm != null )
473 {
474 foreignImports.put( "", projectRealm );
475 }
476 else
477 {
478 foreignImports.put( "", classRealmManager.getMavenApiRealm() );
479 }
480
481 if ( parent != null && imports != null )
482 {
483 for ( String parentImport : imports )
484 {
485 foreignImports.put( parentImport, parent );
486 }
487 }
488
489 return foreignImports;
490 }
491
492 public <T> T getConfiguredMojo( Class<T> mojoInterface, MavenSession session, MojoExecution mojoExecution )
493 throws PluginConfigurationException, PluginContainerException
494 {
495 MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
496
497 PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
498
499 ClassRealm pluginRealm = pluginDescriptor.getClassRealm();
500
501 if ( logger.isDebugEnabled() )
502 {
503 logger.debug( "Loading mojo " + mojoDescriptor.getId() + " from plugin realm " + pluginRealm );
504 }
505
506
507
508
509 ClassRealm oldLookupRealm = container.setLookupRealm( pluginRealm );
510
511 ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
512 Thread.currentThread().setContextClassLoader( pluginRealm );
513
514 try
515 {
516 T mojo;
517
518 try
519 {
520 mojo = container.lookup( mojoInterface, mojoDescriptor.getRoleHint() );
521 }
522 catch ( ComponentLookupException e )
523 {
524 Throwable cause = e.getCause();
525 while ( cause != null && !( cause instanceof LinkageError )
526 && !( cause instanceof ClassNotFoundException ) )
527 {
528 cause = cause.getCause();
529 }
530
531 if ( ( cause instanceof NoClassDefFoundError ) || ( cause instanceof ClassNotFoundException ) )
532 {
533 ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
534 PrintStream ps = new PrintStream( os );
535 ps.println( "Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '"
536 + pluginDescriptor.getId() + "'. A required class is missing: "
537 + cause.getMessage() );
538 pluginRealm.display( ps );
539
540 throw new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), cause );
541 }
542 else if ( cause instanceof LinkageError )
543 {
544 ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
545 PrintStream ps = new PrintStream( os );
546 ps.println( "Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '"
547 + pluginDescriptor.getId() + "' due to an API incompatibility: "
548 + e.getClass().getName() + ": " + cause.getMessage() );
549 pluginRealm.display( ps );
550
551 throw new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), cause );
552 }
553
554 throw new PluginContainerException( mojoDescriptor, pluginRealm,
555 "Unable to load the mojo '" + mojoDescriptor.getGoal()
556 + "' (or one of its required components) from the plugin '"
557 + pluginDescriptor.getId() + "'", e );
558 }
559
560 if ( mojo instanceof ContextEnabled )
561 {
562 MavenProject project = session.getCurrentProject();
563
564 Map<String, Object> pluginContext = session.getPluginContext( pluginDescriptor, project );
565
566 if ( pluginContext != null )
567 {
568 pluginContext.put( "project", project );
569
570 pluginContext.put( "pluginDescriptor", pluginDescriptor );
571
572 ( (ContextEnabled) mojo ).setPluginContext( pluginContext );
573 }
574 }
575
576 if ( mojo instanceof Mojo )
577 {
578 Logger mojoLogger = loggerManager.getLoggerForComponent( mojoDescriptor.getImplementation() );
579 ( (Mojo) mojo ).setLog( new DefaultLog( mojoLogger ) );
580 }
581
582 Xpp3Dom dom = mojoExecution.getConfiguration();
583
584 PlexusConfiguration pomConfiguration;
585
586 if ( dom == null )
587 {
588 pomConfiguration = new XmlPlexusConfiguration( "configuration" );
589 }
590 else
591 {
592 pomConfiguration = new XmlPlexusConfiguration( dom );
593 }
594
595 ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator( session, mojoExecution );
596
597 populateMojoExecutionFields( mojo, mojoExecution.getExecutionId(), mojoDescriptor, pluginRealm,
598 pomConfiguration, expressionEvaluator );
599
600 return mojo;
601 }
602 finally
603 {
604 Thread.currentThread().setContextClassLoader( oldClassLoader );
605 container.setLookupRealm( oldLookupRealm );
606 }
607 }
608
609 private void populateMojoExecutionFields( Object mojo, String executionId, MojoDescriptor mojoDescriptor,
610 ClassRealm pluginRealm, PlexusConfiguration configuration,
611 ExpressionEvaluator expressionEvaluator )
612 throws PluginConfigurationException
613 {
614 ComponentConfigurator configurator = null;
615
616 String configuratorId = mojoDescriptor.getComponentConfigurator();
617
618 if ( StringUtils.isEmpty( configuratorId ) )
619 {
620 configuratorId = "basic";
621 }
622
623 try
624 {
625
626
627 configurator = container.lookup( ComponentConfigurator.class, configuratorId );
628
629 ConfigurationListener listener = new DebugConfigurationListener( logger );
630
631 ValidatingConfigurationListener validator =
632 new ValidatingConfigurationListener( mojo, mojoDescriptor, listener );
633
634 logger.debug( "Configuring mojo execution '" + mojoDescriptor.getId() + ':' + executionId + "' with "
635 + configuratorId + " configurator -->" );
636
637 configurator.configureComponent( mojo, configuration, expressionEvaluator, pluginRealm, validator );
638
639 logger.debug( "-- end configuration --" );
640
641 Collection<Parameter> missingParameters = validator.getMissingParameters();
642 if ( !missingParameters.isEmpty() )
643 {
644 if ( "basic".equals( configuratorId ) )
645 {
646 throw new PluginParameterException( mojoDescriptor, new ArrayList<>( missingParameters ) );
647 }
648 else
649 {
650
651
652
653
654 validateParameters( mojoDescriptor, configuration, expressionEvaluator );
655 }
656 }
657 }
658 catch ( ComponentConfigurationException e )
659 {
660 String message = "Unable to parse configuration of mojo " + mojoDescriptor.getId();
661 if ( e.getFailedConfiguration() != null )
662 {
663 message += " for parameter " + e.getFailedConfiguration().getName();
664 }
665 message += ": " + e.getMessage();
666
667 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), message, e );
668 }
669 catch ( ComponentLookupException e )
670 {
671 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
672 "Unable to retrieve component configurator " + configuratorId
673 + " for configuration of mojo " + mojoDescriptor.getId(), e );
674 }
675 catch ( NoClassDefFoundError e )
676 {
677 ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
678 PrintStream ps = new PrintStream( os );
679 ps.println( "A required class was missing during configuration of mojo " + mojoDescriptor.getId() + ": "
680 + e.getMessage() );
681 pluginRealm.display( ps );
682
683 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), os.toString(), e );
684 }
685 catch ( LinkageError e )
686 {
687 ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
688 PrintStream ps = new PrintStream( os );
689 ps.println(
690 "An API incompatibility was encountered during configuration of mojo " + mojoDescriptor.getId() + ": "
691 + e.getClass().getName() + ": " + e.getMessage() );
692 pluginRealm.display( ps );
693
694 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), os.toString(), e );
695 }
696 finally
697 {
698 if ( configurator != null )
699 {
700 try
701 {
702 container.release( configurator );
703 }
704 catch ( ComponentLifecycleException e )
705 {
706 logger.debug( "Failed to release mojo configurator - ignoring." );
707 }
708 }
709 }
710 }
711
712 private void validateParameters( MojoDescriptor mojoDescriptor, PlexusConfiguration configuration,
713 ExpressionEvaluator expressionEvaluator )
714 throws ComponentConfigurationException, PluginParameterException
715 {
716 if ( mojoDescriptor.getParameters() == null )
717 {
718 return;
719 }
720
721 List<Parameter> invalidParameters = new ArrayList<>();
722
723 for ( Parameter parameter : mojoDescriptor.getParameters() )
724 {
725 if ( !parameter.isRequired() )
726 {
727 continue;
728 }
729
730 Object value = null;
731
732 PlexusConfiguration config = configuration.getChild( parameter.getName(), false );
733 if ( config != null )
734 {
735 String expression = config.getValue( null );
736
737 try
738 {
739 value = expressionEvaluator.evaluate( expression );
740
741 if ( value == null )
742 {
743 value = config.getAttribute( "default-value", null );
744 }
745 }
746 catch ( ExpressionEvaluationException e )
747 {
748 String msg = "Error evaluating the expression '" + expression + "' for configuration value '"
749 + configuration.getName() + "'";
750 throw new ComponentConfigurationException( configuration, msg, e );
751 }
752 }
753
754 if ( value == null && ( config == null || config.getChildCount() <= 0 ) )
755 {
756 invalidParameters.add( parameter );
757 }
758 }
759
760 if ( !invalidParameters.isEmpty() )
761 {
762 throw new PluginParameterException( mojoDescriptor, invalidParameters );
763 }
764 }
765
766 public void releaseMojo( Object mojo, MojoExecution mojoExecution )
767 {
768 if ( mojo != null )
769 {
770 try
771 {
772 container.release( mojo );
773 }
774 catch ( ComponentLifecycleException e )
775 {
776 String goalExecId = mojoExecution.getGoal();
777
778 if ( mojoExecution.getExecutionId() != null )
779 {
780 goalExecId += " {execution: " + mojoExecution.getExecutionId() + "}";
781 }
782
783 logger.debug( "Error releasing mojo for " + goalExecId, e );
784 }
785 }
786 }
787
788 public ExtensionRealmCache.CacheRecord setupExtensionsRealm( MavenProject project, Plugin plugin,
789 RepositorySystemSession session )
790 throws PluginManagerException
791 {
792 @SuppressWarnings( "unchecked" ) Map<String, ExtensionRealmCache.CacheRecord> pluginRealms =
793 (Map<String, ExtensionRealmCache.CacheRecord>) project.getContextValue( KEY_EXTENSIONS_REALMS );
794 if ( pluginRealms == null )
795 {
796 pluginRealms = new HashMap<>();
797 project.setContextValue( KEY_EXTENSIONS_REALMS, pluginRealms );
798 }
799
800 final String pluginKey = plugin.getId();
801
802 ExtensionRealmCache.CacheRecord extensionRecord = pluginRealms.get( pluginKey );
803 if ( extensionRecord != null )
804 {
805 return extensionRecord;
806 }
807
808 final List<RemoteRepository> repositories = project.getRemotePluginRepositories();
809
810
811 if ( plugin.getVersion() == null )
812 {
813 PluginVersionRequest versionRequest = new DefaultPluginVersionRequest( plugin, session, repositories );
814 try
815 {
816 plugin.setVersion( pluginVersionResolver.resolve( versionRequest ).getVersion() );
817 }
818 catch ( PluginVersionResolutionException e )
819 {
820 throw new PluginManagerException( plugin, e.getMessage(), e );
821 }
822 }
823
824
825 List<Artifact> artifacts;
826 PluginArtifactsCache.Key cacheKey = pluginArtifactsCache.createKey( plugin, null, repositories, session );
827 PluginArtifactsCache.CacheRecord recordArtifacts;
828 try
829 {
830 recordArtifacts = pluginArtifactsCache.get( cacheKey );
831 }
832 catch ( PluginResolutionException e )
833 {
834 throw new PluginManagerException( plugin, e.getMessage(), e );
835 }
836 if ( recordArtifacts != null )
837 {
838 artifacts = recordArtifacts.getArtifacts();
839 }
840 else
841 {
842 try
843 {
844 artifacts = resolveExtensionArtifacts( plugin, repositories, session );
845 recordArtifacts = pluginArtifactsCache.put( cacheKey, artifacts );
846 }
847 catch ( PluginResolutionException e )
848 {
849 pluginArtifactsCache.put( cacheKey, e );
850 pluginArtifactsCache.register( project, cacheKey, recordArtifacts );
851 throw new PluginManagerException( plugin, e.getMessage(), e );
852 }
853 }
854 pluginArtifactsCache.register( project, cacheKey, recordArtifacts );
855
856
857 final ExtensionRealmCache.Key extensionKey = extensionRealmCache.createKey( artifacts );
858 extensionRecord = extensionRealmCache.get( extensionKey );
859 if ( extensionRecord == null )
860 {
861 ClassRealm extensionRealm =
862 classRealmManager.createExtensionRealm( plugin, toAetherArtifacts( artifacts ) );
863
864
865
866 PluginDescriptor pluginDescriptor = null;
867 if ( plugin.isExtensions() && !artifacts.isEmpty() )
868 {
869
870
871 try
872 {
873 pluginDescriptor = extractPluginDescriptor( artifacts.get( 0 ), plugin );
874 }
875 catch ( PluginDescriptorParsingException | InvalidPluginDescriptorException e )
876 {
877
878 }
879 }
880
881 discoverPluginComponents( extensionRealm, plugin, pluginDescriptor );
882
883 ExtensionDescriptor extensionDescriptor = null;
884 Artifact extensionArtifact = artifacts.get( 0 );
885 try
886 {
887 extensionDescriptor = extensionDescriptorBuilder.build( extensionArtifact.getFile() );
888 }
889 catch ( IOException e )
890 {
891 String message = "Invalid extension descriptor for " + plugin.getId() + ": " + e.getMessage();
892 if ( logger.isDebugEnabled() )
893 {
894 logger.error( message, e );
895 }
896 else
897 {
898 logger.error( message );
899 }
900 }
901 extensionRecord = extensionRealmCache.put( extensionKey, extensionRealm, extensionDescriptor, artifacts );
902 }
903 extensionRealmCache.register( project, extensionKey, extensionRecord );
904 pluginRealms.put( pluginKey, extensionRecord );
905
906 return extensionRecord;
907 }
908
909 private List<Artifact> resolveExtensionArtifacts( Plugin extensionPlugin, List<RemoteRepository> repositories,
910 RepositorySystemSession session )
911 throws PluginResolutionException
912 {
913 DependencyNode root = pluginDependenciesResolver.resolve( extensionPlugin, null, null, repositories, session );
914 PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
915 root.accept( nlg );
916 return toMavenArtifacts( root, nlg );
917 }
918
919 }