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