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( "Configuring 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 populatePluginFields( mojo, mojoDescriptor, pluginRealm, pomConfiguration, expressionEvaluator );
598
599 return mojo;
600 }
601 finally
602 {
603 Thread.currentThread().setContextClassLoader( oldClassLoader );
604 container.setLookupRealm( oldLookupRealm );
605 }
606 }
607
608 private void populatePluginFields( Object mojo, MojoDescriptor mojoDescriptor, ClassRealm pluginRealm,
609 PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator )
610 throws PluginConfigurationException
611 {
612 ComponentConfigurator configurator = null;
613
614 String configuratorId = mojoDescriptor.getComponentConfigurator();
615
616 if ( StringUtils.isEmpty( configuratorId ) )
617 {
618 configuratorId = "basic";
619 }
620
621 try
622 {
623
624
625 configurator = container.lookup( ComponentConfigurator.class, configuratorId );
626
627 ConfigurationListener listener = new DebugConfigurationListener( logger );
628
629 ValidatingConfigurationListener validator =
630 new ValidatingConfigurationListener( mojo, mojoDescriptor, listener );
631
632 logger.debug(
633 "Configuring mojo '" + mojoDescriptor.getId() + "' with " + configuratorId + " configurator -->" );
634
635 configurator.configureComponent( mojo, configuration, expressionEvaluator, pluginRealm, validator );
636
637 logger.debug( "-- end configuration --" );
638
639 Collection<Parameter> missingParameters = validator.getMissingParameters();
640 if ( !missingParameters.isEmpty() )
641 {
642 if ( "basic".equals( configuratorId ) )
643 {
644 throw new PluginParameterException( mojoDescriptor, new ArrayList<>( missingParameters ) );
645 }
646 else
647 {
648
649
650
651
652 validateParameters( mojoDescriptor, configuration, expressionEvaluator );
653 }
654 }
655 }
656 catch ( ComponentConfigurationException e )
657 {
658 String message = "Unable to parse configuration of mojo " + mojoDescriptor.getId();
659 if ( e.getFailedConfiguration() != null )
660 {
661 message += " for parameter " + e.getFailedConfiguration().getName();
662 }
663 message += ": " + e.getMessage();
664
665 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), message, e );
666 }
667 catch ( ComponentLookupException e )
668 {
669 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
670 "Unable to retrieve component configurator " + configuratorId
671 + " for configuration of mojo " + mojoDescriptor.getId(), e );
672 }
673 catch ( NoClassDefFoundError e )
674 {
675 ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
676 PrintStream ps = new PrintStream( os );
677 ps.println( "A required class was missing during configuration of mojo " + mojoDescriptor.getId() + ": "
678 + e.getMessage() );
679 pluginRealm.display( ps );
680
681 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), os.toString(), e );
682 }
683 catch ( LinkageError e )
684 {
685 ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
686 PrintStream ps = new PrintStream( os );
687 ps.println(
688 "An API incompatibility was encountered during configuration of mojo " + mojoDescriptor.getId() + ": "
689 + e.getClass().getName() + ": " + e.getMessage() );
690 pluginRealm.display( ps );
691
692 throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), os.toString(), e );
693 }
694 finally
695 {
696 if ( configurator != null )
697 {
698 try
699 {
700 container.release( configurator );
701 }
702 catch ( ComponentLifecycleException e )
703 {
704 logger.debug( "Failed to release mojo configurator - ignoring." );
705 }
706 }
707 }
708 }
709
710 private void validateParameters( MojoDescriptor mojoDescriptor, PlexusConfiguration configuration,
711 ExpressionEvaluator expressionEvaluator )
712 throws ComponentConfigurationException, PluginParameterException
713 {
714 if ( mojoDescriptor.getParameters() == null )
715 {
716 return;
717 }
718
719 List<Parameter> invalidParameters = new ArrayList<>();
720
721 for ( Parameter parameter : mojoDescriptor.getParameters() )
722 {
723 if ( !parameter.isRequired() )
724 {
725 continue;
726 }
727
728 Object value = null;
729
730 PlexusConfiguration config = configuration.getChild( parameter.getName(), false );
731 if ( config != null )
732 {
733 String expression = config.getValue( null );
734
735 try
736 {
737 value = expressionEvaluator.evaluate( expression );
738
739 if ( value == null )
740 {
741 value = config.getAttribute( "default-value", null );
742 }
743 }
744 catch ( ExpressionEvaluationException e )
745 {
746 String msg = "Error evaluating the expression '" + expression + "' for configuration value '"
747 + configuration.getName() + "'";
748 throw new ComponentConfigurationException( configuration, msg, e );
749 }
750 }
751
752 if ( value == null && ( config == null || config.getChildCount() <= 0 ) )
753 {
754 invalidParameters.add( parameter );
755 }
756 }
757
758 if ( !invalidParameters.isEmpty() )
759 {
760 throw new PluginParameterException( mojoDescriptor, invalidParameters );
761 }
762 }
763
764 public void releaseMojo( Object mojo, MojoExecution mojoExecution )
765 {
766 if ( mojo != null )
767 {
768 try
769 {
770 container.release( mojo );
771 }
772 catch ( ComponentLifecycleException e )
773 {
774 String goalExecId = mojoExecution.getGoal();
775
776 if ( mojoExecution.getExecutionId() != null )
777 {
778 goalExecId += " {execution: " + mojoExecution.getExecutionId() + "}";
779 }
780
781 logger.debug( "Error releasing mojo for " + goalExecId, e );
782 }
783 }
784 }
785
786 public ExtensionRealmCache.CacheRecord setupExtensionsRealm( MavenProject project, Plugin plugin,
787 RepositorySystemSession session )
788 throws PluginManagerException
789 {
790 @SuppressWarnings( "unchecked" ) Map<String, ExtensionRealmCache.CacheRecord> pluginRealms =
791 (Map<String, ExtensionRealmCache.CacheRecord>) project.getContextValue( KEY_EXTENSIONS_REALMS );
792 if ( pluginRealms == null )
793 {
794 pluginRealms = new HashMap<>();
795 project.setContextValue( KEY_EXTENSIONS_REALMS, pluginRealms );
796 }
797
798 final String pluginKey = plugin.getId();
799
800 ExtensionRealmCache.CacheRecord extensionRecord = pluginRealms.get( pluginKey );
801 if ( extensionRecord != null )
802 {
803 return extensionRecord;
804 }
805
806 final List<RemoteRepository> repositories = project.getRemotePluginRepositories();
807
808
809 if ( plugin.getVersion() == null )
810 {
811 PluginVersionRequest versionRequest = new DefaultPluginVersionRequest( plugin, session, repositories );
812 try
813 {
814 plugin.setVersion( pluginVersionResolver.resolve( versionRequest ).getVersion() );
815 }
816 catch ( PluginVersionResolutionException e )
817 {
818 throw new PluginManagerException( plugin, e.getMessage(), e );
819 }
820 }
821
822
823 List<Artifact> artifacts;
824 PluginArtifactsCache.Key cacheKey = pluginArtifactsCache.createKey( plugin, null, repositories, session );
825 PluginArtifactsCache.CacheRecord recordArtifacts;
826 try
827 {
828 recordArtifacts = pluginArtifactsCache.get( cacheKey );
829 }
830 catch ( PluginResolutionException e )
831 {
832 throw new PluginManagerException( plugin, e.getMessage(), e );
833 }
834 if ( recordArtifacts != null )
835 {
836 artifacts = recordArtifacts.getArtifacts();
837 }
838 else
839 {
840 try
841 {
842 artifacts = resolveExtensionArtifacts( plugin, repositories, session );
843 recordArtifacts = pluginArtifactsCache.put( cacheKey, artifacts );
844 }
845 catch ( PluginResolutionException e )
846 {
847 pluginArtifactsCache.put( cacheKey, e );
848 pluginArtifactsCache.register( project, cacheKey, recordArtifacts );
849 throw new PluginManagerException( plugin, e.getMessage(), e );
850 }
851 }
852 pluginArtifactsCache.register( project, cacheKey, recordArtifacts );
853
854
855 final ExtensionRealmCache.Key extensionKey = extensionRealmCache.createKey( artifacts );
856 extensionRecord = extensionRealmCache.get( extensionKey );
857 if ( extensionRecord == null )
858 {
859 ClassRealm extensionRealm =
860 classRealmManager.createExtensionRealm( plugin, toAetherArtifacts( artifacts ) );
861
862
863
864 PluginDescriptor pluginDescriptor = null;
865 if ( plugin.isExtensions() && !artifacts.isEmpty() )
866 {
867
868
869 try
870 {
871 pluginDescriptor = extractPluginDescriptor( artifacts.get( 0 ), plugin );
872 }
873 catch ( PluginDescriptorParsingException | InvalidPluginDescriptorException e )
874 {
875
876 }
877 }
878
879 discoverPluginComponents( extensionRealm, plugin, pluginDescriptor );
880
881 ExtensionDescriptor extensionDescriptor = null;
882 Artifact extensionArtifact = artifacts.get( 0 );
883 try
884 {
885 extensionDescriptor = extensionDescriptorBuilder.build( extensionArtifact.getFile() );
886 }
887 catch ( IOException e )
888 {
889 String message = "Invalid extension descriptor for " + plugin.getId() + ": " + e.getMessage();
890 if ( logger.isDebugEnabled() )
891 {
892 logger.error( message, e );
893 }
894 else
895 {
896 logger.error( message );
897 }
898 }
899 extensionRecord = extensionRealmCache.put( extensionKey, extensionRealm, extensionDescriptor, artifacts );
900 }
901 extensionRealmCache.register( project, extensionKey, extensionRecord );
902 pluginRealms.put( pluginKey, extensionRecord );
903
904 return extensionRecord;
905 }
906
907 private List<Artifact> resolveExtensionArtifacts( Plugin extensionPlugin, List<RemoteRepository> repositories,
908 RepositorySystemSession session )
909 throws PluginResolutionException
910 {
911 DependencyNode root = pluginDependenciesResolver.resolve( extensionPlugin, null, null, repositories, session );
912 PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
913 root.accept( nlg );
914 return toMavenArtifacts( root, nlg );
915 }
916
917 }