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