View Javadoc

1   package org.apache.maven.plugin.internal;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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.model.Plugin;
45  import org.apache.maven.monitor.logging.DefaultLog;
46  import org.apache.maven.plugin.ContextEnabled;
47  import org.apache.maven.plugin.DebugConfigurationListener;
48  import org.apache.maven.plugin.InvalidPluginDescriptorException;
49  import org.apache.maven.plugin.MavenPluginManager;
50  import org.apache.maven.plugin.MavenPluginValidator;
51  import org.apache.maven.plugin.Mojo;
52  import org.apache.maven.plugin.MojoExecution;
53  import org.apache.maven.plugin.MojoNotFoundException;
54  import org.apache.maven.plugin.PluginConfigurationException;
55  import org.apache.maven.plugin.PluginContainerException;
56  import org.apache.maven.plugin.PluginDescriptorCache;
57  import org.apache.maven.plugin.PluginDescriptorParsingException;
58  import org.apache.maven.plugin.PluginParameterException;
59  import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
60  import org.apache.maven.plugin.PluginRealmCache;
61  import org.apache.maven.plugin.PluginResolutionException;
62  import org.apache.maven.plugin.descriptor.MojoDescriptor;
63  import org.apache.maven.plugin.descriptor.Parameter;
64  import org.apache.maven.plugin.descriptor.PluginDescriptor;
65  import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
66  import org.apache.maven.project.MavenProject;
67  import org.codehaus.plexus.PlexusContainer;
68  import org.codehaus.plexus.classworlds.realm.ClassRealm;
69  import org.codehaus.plexus.component.annotations.Component;
70  import org.codehaus.plexus.component.annotations.Requirement;
71  import org.codehaus.plexus.component.composition.CycleDetectedInComponentGraphException;
72  import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
73  import org.codehaus.plexus.component.configurator.ComponentConfigurator;
74  import org.codehaus.plexus.component.configurator.ConfigurationListener;
75  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
76  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
77  import org.codehaus.plexus.component.repository.ComponentDescriptor;
78  import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
79  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
80  import org.codehaus.plexus.configuration.PlexusConfiguration;
81  import org.codehaus.plexus.configuration.PlexusConfigurationException;
82  import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
83  import org.codehaus.plexus.logging.Logger;
84  import org.codehaus.plexus.util.IOUtil;
85  import org.codehaus.plexus.util.ReaderFactory;
86  import org.codehaus.plexus.util.StringUtils;
87  import org.codehaus.plexus.util.xml.Xpp3Dom;
88  import org.sonatype.aether.RepositorySystemSession;
89  import org.sonatype.aether.graph.DependencyFilter;
90  import org.sonatype.aether.graph.DependencyNode;
91  import org.sonatype.aether.repository.RemoteRepository;
92  import org.sonatype.aether.util.filter.AndDependencyFilter;
93  import org.sonatype.aether.util.graph.PreorderNodeListGenerator;
94  
95  /**
96   * Provides basic services to manage Maven plugins and their mojos. This component is kept general in its design such
97   * that the plugins/mojos can be used in arbitrary contexts. In particular, the mojos can be used for ordinary build
98   * plugins as well as special purpose plugins like reports.
99   * 
100  * @since 3.0
101  * @author Benjamin Bentmann
102  */
103 @Component( role = MavenPluginManager.class )
104 public class DefaultMavenPluginManager
105     implements MavenPluginManager
106 {
107 
108     @Requirement
109     private Logger logger;
110 
111     @Requirement
112     private PlexusContainer container;
113 
114     @Requirement
115     private ClassRealmManager classRealmManager;
116 
117     @Requirement
118     private PluginDescriptorCache pluginDescriptorCache;
119 
120     @Requirement
121     private PluginRealmCache pluginRealmCache;
122 
123     @Requirement
124     private PluginDependenciesResolver pluginDependenciesResolver;
125 
126     private PluginDescriptorBuilder builder = new PluginDescriptorBuilder();
127 
128     public synchronized PluginDescriptor getPluginDescriptor( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
129         throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException
130     {
131         PluginDescriptorCache.Key cacheKey = pluginDescriptorCache.createKey( plugin, repositories, session );
132 
133         PluginDescriptor pluginDescriptor = pluginDescriptorCache.get( cacheKey );
134 
135         if ( pluginDescriptor == null )
136         {
137             Artifact pluginArtifact =
138                 RepositoryUtils.toArtifact( pluginDependenciesResolver.resolve( plugin, repositories, session ) );
139 
140             pluginDescriptor = extractPluginDescriptor( pluginArtifact, plugin );
141 
142             pluginDescriptorCache.put( cacheKey, pluginDescriptor );
143         }
144 
145         pluginDescriptor.setPlugin( plugin );
146 
147         return pluginDescriptor;
148     }
149 
150     private PluginDescriptor extractPluginDescriptor( Artifact pluginArtifact, Plugin plugin )
151         throws PluginDescriptorParsingException, InvalidPluginDescriptorException
152     {
153         PluginDescriptor pluginDescriptor = null;
154 
155         File pluginFile = pluginArtifact.getFile();
156 
157         try
158         {
159             if ( pluginFile.isFile() )
160             {
161                 JarFile pluginJar = new JarFile( pluginFile, false );
162                 try
163                 {
164                     ZipEntry pluginDescriptorEntry = pluginJar.getEntry( getPluginDescriptorLocation() );
165 
166                     if ( pluginDescriptorEntry != null )
167                     {
168                         InputStream is = pluginJar.getInputStream( pluginDescriptorEntry );
169 
170                         pluginDescriptor = parsePluginDescriptor( is, plugin, pluginFile.getAbsolutePath() );
171                     }
172                 }
173                 finally
174                 {
175                     pluginJar.close();
176                 }
177             }
178             else
179             {
180                 File pluginXml = new File( pluginFile, getPluginDescriptorLocation() );
181 
182                 if ( pluginXml.isFile() )
183                 {
184                     InputStream is = new BufferedInputStream( new FileInputStream( pluginXml ) );
185                     try
186                     {
187                         pluginDescriptor = parsePluginDescriptor( is, plugin, pluginXml.getAbsolutePath() );
188                     }
189                     finally
190                     {
191                         IOUtil.close( is );
192                     }
193                 }
194             }
195 
196             if ( pluginDescriptor == null )
197             {
198                 throw new IOException( "No plugin descriptor found at " + getPluginDescriptorLocation() );
199             }
200         }
201         catch ( IOException e )
202         {
203             throw new PluginDescriptorParsingException( plugin, pluginFile.getAbsolutePath(), e );
204         }
205 
206         MavenPluginValidator validator = new MavenPluginValidator( pluginArtifact );
207 
208         validator.validate( pluginDescriptor );
209 
210         if ( validator.hasErrors() )
211         {
212             throw new InvalidPluginDescriptorException( "Invalid plugin descriptor for " + plugin.getId() + " ("
213                 + pluginFile + ")", validator.getErrors() );
214         }
215 
216         pluginDescriptor.setPluginArtifact( pluginArtifact );
217 
218         return pluginDescriptor;
219     }
220 
221     private String getPluginDescriptorLocation()
222     {
223         return "META-INF/maven/plugin.xml";
224     }
225 
226     private PluginDescriptor parsePluginDescriptor( InputStream is, Plugin plugin, String descriptorLocation )
227         throws PluginDescriptorParsingException
228     {
229         try
230         {
231             Reader reader = ReaderFactory.newXmlReader( is );
232 
233             PluginDescriptor pluginDescriptor = builder.build( reader, descriptorLocation );
234 
235             return pluginDescriptor;
236         }
237         catch ( IOException e )
238         {
239             throw new PluginDescriptorParsingException( plugin, descriptorLocation, e );
240         }
241         catch ( PlexusConfigurationException e )
242         {
243             throw new PluginDescriptorParsingException( plugin, descriptorLocation, e );
244         }
245     }
246 
247     public MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, List<RemoteRepository> repositories,
248                                              RepositorySystemSession session )
249         throws MojoNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
250         InvalidPluginDescriptorException
251     {
252         PluginDescriptor pluginDescriptor = getPluginDescriptor( plugin, repositories, session );
253 
254         MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( goal );
255 
256         if ( mojoDescriptor == null )
257         {
258             throw new MojoNotFoundException( goal, pluginDescriptor );
259         }
260 
261         return mojoDescriptor;
262     }
263 
264     public synchronized void setupPluginRealm( PluginDescriptor pluginDescriptor, MavenSession session,
265                                                ClassLoader parent, List<String> imports, DependencyFilter filter )
266         throws PluginResolutionException, PluginContainerException
267     {
268         Plugin plugin = pluginDescriptor.getPlugin();
269 
270         MavenProject project = session.getCurrentProject();
271 
272         PluginRealmCache.Key cacheKey =
273             pluginRealmCache.createKey( plugin, parent, imports, filter, project.getRemotePluginRepositories(),
274                                         session.getRepositorySession() );
275 
276         PluginRealmCache.CacheRecord cacheRecord = pluginRealmCache.get( cacheKey );
277 
278         if ( cacheRecord != null )
279         {
280             pluginDescriptor.setClassRealm( cacheRecord.realm );
281             pluginDescriptor.setArtifacts( new ArrayList<Artifact>( cacheRecord.artifacts ) );
282         }
283         else
284         {
285             createPluginRealm( pluginDescriptor, session, parent, imports, filter );
286 
287             cacheRecord =
288                 pluginRealmCache.put( cacheKey, pluginDescriptor.getClassRealm(), pluginDescriptor.getArtifacts() );
289         }
290 
291         pluginRealmCache.register( project, cacheRecord );
292     }
293 
294     private void createPluginRealm( PluginDescriptor pluginDescriptor, MavenSession session, ClassLoader parent,
295                                     List<String> imports, DependencyFilter filter )
296         throws PluginResolutionException, PluginContainerException
297     {
298         Plugin plugin = pluginDescriptor.getPlugin();
299 
300         if ( plugin == null )
301         {
302             throw new IllegalArgumentException( "incomplete plugin descriptor, plugin missing" );
303         }
304 
305         Artifact pluginArtifact = pluginDescriptor.getPluginArtifact();
306 
307         if ( pluginArtifact == null )
308         {
309             throw new IllegalArgumentException( "incomplete plugin descriptor, plugin artifact missing" );
310         }
311 
312         MavenProject project = session.getCurrentProject();
313 
314         DependencyFilter dependencyFilter = project.getExtensionDependencyFilter();
315         dependencyFilter = AndDependencyFilter.newInstance( dependencyFilter, filter );
316 
317         DependencyNode root =
318             pluginDependenciesResolver.resolve( plugin, RepositoryUtils.toArtifact( pluginArtifact ), dependencyFilter,
319                                                 project.getRemotePluginRepositories(), session.getRepositorySession() );
320 
321         PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
322         root.accept( nlg );
323 
324         List<Artifact> exposedPluginArtifacts = new ArrayList<Artifact>( nlg.getNodes().size() );
325         RepositoryUtils.toArtifacts( exposedPluginArtifacts, Collections.singleton( root ),
326                                      Collections.<String> emptyList(), null );
327         for ( Iterator<Artifact> it = exposedPluginArtifacts.iterator(); it.hasNext(); )
328         {
329             Artifact artifact = it.next();
330             if ( artifact.getFile() == null )
331             {
332                 it.remove();
333             }
334         }
335 
336         List<org.sonatype.aether.artifact.Artifact> pluginArtifacts = nlg.getArtifacts( true );
337 
338         Map<String, ClassLoader> foreignImports = calcImports( project, parent, imports );
339 
340         ClassRealm pluginRealm =
341             classRealmManager.createPluginRealm( plugin, parent, null, foreignImports, pluginArtifacts );
342 
343         pluginDescriptor.setClassRealm( pluginRealm );
344         pluginDescriptor.setArtifacts( exposedPluginArtifacts );
345 
346         try
347         {
348             for ( ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents() )
349             {
350                 componentDescriptor.setRealm( pluginRealm );
351                 container.addComponentDescriptor( componentDescriptor );
352             }
353 
354             container.discoverComponents( pluginRealm );
355         }
356         catch ( PlexusConfigurationException e )
357         {
358             throw new PluginContainerException( plugin, pluginRealm, "Error in component graph of plugin "
359                 + plugin.getId() + ": " + e.getMessage(), e );
360         }
361         catch ( CycleDetectedInComponentGraphException e )
362         {
363             throw new PluginContainerException( plugin, pluginRealm, "Error in component graph of plugin "
364                 + plugin.getId() + ": " + e.getMessage(), e );
365         }
366     }
367 
368     private Map<String, ClassLoader> calcImports( MavenProject project, ClassLoader parent, List<String> imports )
369     {
370         Map<String, ClassLoader> foreignImports = new HashMap<String, ClassLoader>();
371 
372         ClassLoader projectRealm = project.getClassRealm();
373         if ( projectRealm != null )
374         {
375             foreignImports.put( "", projectRealm );
376         }
377         else
378         {
379             foreignImports.put( "", classRealmManager.getMavenApiRealm() );
380         }
381 
382         if ( parent != null && imports != null )
383         {
384             for ( String parentImport : imports )
385             {
386                 foreignImports.put( parentImport, parent );
387             }
388         }
389 
390         return foreignImports;
391     }
392 
393     public <T> T getConfiguredMojo( Class<T> mojoInterface, MavenSession session, MojoExecution mojoExecution )
394         throws PluginConfigurationException, PluginContainerException
395     {
396         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
397 
398         PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
399 
400         ClassRealm pluginRealm = pluginDescriptor.getClassRealm();
401 
402         if ( logger.isDebugEnabled() )
403         {
404             logger.debug( "Configuring mojo " + mojoDescriptor.getId() + " from plugin realm " + pluginRealm );
405         }
406 
407         // We are forcing the use of the plugin realm for all lookups that might occur during
408         // the lifecycle that is part of the lookup. Here we are specifically trying to keep
409         // lookups that occur in contextualize calls in line with the right realm.
410         ClassRealm oldLookupRealm = container.setLookupRealm( pluginRealm );
411         container.setLookupRealm( pluginRealm );
412 
413         ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
414         Thread.currentThread().setContextClassLoader( pluginRealm );
415 
416         try
417         {
418             T mojo;
419 
420             try
421             {
422                 mojo = container.lookup( mojoInterface, mojoDescriptor.getRoleHint() );
423             }
424             catch ( ComponentLookupException e )
425             {
426                 Throwable cause = e.getCause();
427                 while ( cause != null && !( cause instanceof LinkageError )
428                     && !( cause instanceof ClassNotFoundException ) )
429                 {
430                     cause = cause.getCause();
431                 }
432 
433                 if ( ( cause instanceof NoClassDefFoundError ) || ( cause instanceof ClassNotFoundException ) )
434                 {
435                     ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
436                     PrintStream ps = new PrintStream( os );
437                     ps.println( "Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '"
438                         + pluginDescriptor.getId() + "'. A required class is missing: " + cause.getMessage() );
439                     pluginRealm.display( ps );
440 
441                     throw new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), cause );
442                 }
443                 else if ( cause instanceof LinkageError )
444                 {
445                     ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
446                     PrintStream ps = new PrintStream( os );
447                     ps.println( "Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '"
448                         + pluginDescriptor.getId() + "' due to an API incompatibility: " + e.getClass().getName()
449                         + ": " + cause.getMessage() );
450                     pluginRealm.display( ps );
451 
452                     throw new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), cause );
453                 }
454 
455                 throw new PluginContainerException( mojoDescriptor, pluginRealm, "Unable to load the mojo '"
456                     + mojoDescriptor.getGoal() + "' (or one of its required components) from the plugin '"
457                     + pluginDescriptor.getId() + "'", e );
458             }
459 
460             if ( mojo instanceof ContextEnabled )
461             {
462                 MavenProject project = session.getCurrentProject();
463 
464                 Map<String, Object> pluginContext = session.getPluginContext( pluginDescriptor, project );
465 
466                 if ( pluginContext != null )
467                 {
468                     pluginContext.put( "project", project );
469 
470                     pluginContext.put( "pluginDescriptor", pluginDescriptor );
471 
472                     ( (ContextEnabled) mojo ).setPluginContext( pluginContext );
473                 }
474             }
475 
476             if ( mojo instanceof Mojo )
477             {
478                 ( (Mojo) mojo ).setLog( new DefaultLog( logger ) );
479             }
480 
481             Xpp3Dom dom = mojoExecution.getConfiguration();
482 
483             PlexusConfiguration pomConfiguration;
484 
485             if ( dom == null )
486             {
487                 pomConfiguration = new XmlPlexusConfiguration( "configuration" );
488             }
489             else
490             {
491                 pomConfiguration = new XmlPlexusConfiguration( dom );
492             }
493 
494             ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator( session, mojoExecution );
495 
496             populatePluginFields( mojo, mojoDescriptor, pluginRealm, pomConfiguration, expressionEvaluator );
497 
498             return mojo;
499         }
500         finally
501         {
502             Thread.currentThread().setContextClassLoader( oldClassLoader );
503             container.setLookupRealm( oldLookupRealm );
504         }
505     }
506 
507     private void populatePluginFields( Object mojo, MojoDescriptor mojoDescriptor, ClassRealm pluginRealm,
508                                        PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator )
509         throws PluginConfigurationException
510     {
511         ComponentConfigurator configurator = null;
512 
513         String configuratorId = mojoDescriptor.getComponentConfigurator();
514 
515         if ( StringUtils.isEmpty( configuratorId ) )
516         {
517             configuratorId = "basic";
518         }
519 
520         try
521         {
522             // TODO: could the configuration be passed to lookup and the configurator known to plexus via the descriptor
523             // so that this method could entirely be handled by a plexus lookup?
524             configurator = container.lookup( ComponentConfigurator.class, configuratorId );
525 
526             ConfigurationListener listener = new DebugConfigurationListener( logger );
527 
528             ValidatingConfigurationListener validator =
529                 new ValidatingConfigurationListener( mojo, mojoDescriptor, listener );
530 
531             logger.debug( "Configuring mojo '" + mojoDescriptor.getId() + "' with " + configuratorId
532                 + " configurator -->" );
533 
534             configurator.configureComponent( mojo, configuration, expressionEvaluator, pluginRealm, validator );
535 
536             logger.debug( "-- end configuration --" );
537 
538             Collection<Parameter> missingParameters = validator.getMissingParameters();
539             if ( !missingParameters.isEmpty() )
540             {
541                 if ( "basic".equals( configuratorId ) )
542                 {
543                     throw new PluginParameterException( mojoDescriptor, new ArrayList<Parameter>( missingParameters ) );
544                 }
545                 else
546                 {
547                     /*
548                      * NOTE: Other configurators like the map-oriented one don't call into the listener, so do it the
549                      * hard way.
550                      */
551                     validateParameters( mojoDescriptor, configuration, expressionEvaluator );
552                 }
553             }
554         }
555         catch ( ComponentConfigurationException e )
556         {
557             String message = "Unable to parse configuration of mojo " + mojoDescriptor.getId();
558             if ( e.getFailedConfiguration() != null )
559             {
560                 message += " for parameter " + e.getFailedConfiguration().getName();
561             }
562             message += ": " + e.getMessage();
563 
564             throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), message, e );
565         }
566         catch ( ComponentLookupException e )
567         {
568             throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
569                                                     "Unable to retrieve component configurator " + configuratorId
570                                                         + " for configuration of mojo " + mojoDescriptor.getId(), e );
571         }
572         catch ( NoClassDefFoundError e )
573         {
574             ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
575             PrintStream ps = new PrintStream( os );
576             ps.println( "A required class was missing during configuration of mojo " + mojoDescriptor.getId() + ": "
577                 + e.getMessage() );
578             pluginRealm.display( ps );
579 
580             throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), os.toString(), e );
581         }
582         catch ( LinkageError e )
583         {
584             ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
585             PrintStream ps = new PrintStream( os );
586             ps.println( "An API incompatibility was encountered during configuration of mojo " + mojoDescriptor.getId()
587                 + ": " + e.getClass().getName() + ": " + e.getMessage() );
588             pluginRealm.display( ps );
589 
590             throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), os.toString(), e );
591         }
592         finally
593         {
594             if ( configurator != null )
595             {
596                 try
597                 {
598                     container.release( configurator );
599                 }
600                 catch ( ComponentLifecycleException e )
601                 {
602                     logger.debug( "Failed to release mojo configurator - ignoring." );
603                 }
604             }
605         }
606     }
607 
608     private void validateParameters( MojoDescriptor mojoDescriptor, PlexusConfiguration configuration,
609                                      ExpressionEvaluator expressionEvaluator )
610         throws ComponentConfigurationException, PluginParameterException
611     {
612         if ( mojoDescriptor.getParameters() == null )
613         {
614             return;
615         }
616 
617         List<Parameter> invalidParameters = new ArrayList<Parameter>();
618 
619         for ( Parameter parameter : mojoDescriptor.getParameters() )
620         {
621             if ( !parameter.isRequired() )
622             {
623                 continue;
624             }
625 
626             Object value = null;
627 
628             PlexusConfiguration config = configuration.getChild( parameter.getName(), false );
629             if ( config != null )
630             {
631                 String expression = config.getValue( null );
632 
633                 try
634                 {
635                     value = expressionEvaluator.evaluate( expression );
636 
637                     if ( value == null )
638                     {
639                         value = config.getAttribute( "default-value", null );
640                     }
641                 }
642                 catch ( ExpressionEvaluationException e )
643                 {
644                     String msg =
645                         "Error evaluating the expression '" + expression + "' for configuration value '"
646                             + configuration.getName() + "'";
647                     throw new ComponentConfigurationException( configuration, msg, e );
648                 }
649             }
650 
651             if ( value == null && ( config == null || config.getChildCount() <= 0 ) )
652             {
653                 invalidParameters.add( parameter );
654             }
655         }
656 
657         if ( !invalidParameters.isEmpty() )
658         {
659             throw new PluginParameterException( mojoDescriptor, invalidParameters );
660         }
661     }
662 
663     public void releaseMojo( Object mojo, MojoExecution mojoExecution )
664     {
665         if ( mojo != null )
666         {
667             try
668             {
669                 container.release( mojo );
670             }
671             catch ( ComponentLifecycleException e )
672             {
673                 String goalExecId = mojoExecution.getGoal();
674 
675                 if ( mojoExecution.getExecutionId() != null )
676                 {
677                     goalExecId += " {execution: " + mojoExecution.getExecutionId() + "}";
678                 }
679 
680                 logger.debug( "Error releasing mojo for " + goalExecId, e );
681             }
682         }
683     }
684 
685 }