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