View Javadoc

1   
2   package org.apache.maven.plugin;
3   
4   /*
5    * Licensed to the Apache Software Foundation (ASF) under one
6    * or more contributor license agreements.  See the NOTICE file
7    * distributed with this work for additional information
8    * regarding copyright ownership.  The ASF licenses this file
9    * to you under the Apache License, Version 2.0 (the
10   * "License"); you may not use this file except in compliance
11   * with the License.  You may obtain a copy of the License at
12   *
13   *  http://www.apache.org/licenses/LICENSE-2.0
14   *
15   * Unless required by applicable law or agreed to in writing,
16   * software distributed under the License is distributed on an
17   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18   * KIND, either express or implied.  See the License for the
19   * specific language governing permissions and limitations
20   * under the License.
21   */
22  
23  import java.io.File;
24  import java.net.URL;
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.Collections;
28  import java.util.HashMap;
29  import java.util.HashSet;
30  import java.util.Iterator;
31  import java.util.LinkedHashMap;
32  import java.util.LinkedHashSet;
33  import java.util.List;
34  import java.util.Map;
35  import java.util.Set;
36  
37  import org.apache.maven.MavenArtifactFilterManager;
38  import org.apache.maven.artifact.Artifact;
39  import org.apache.maven.artifact.factory.ArtifactFactory;
40  import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
41  import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
42  import org.apache.maven.artifact.metadata.ResolutionGroup;
43  import org.apache.maven.artifact.repository.ArtifactRepository;
44  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
45  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
46  import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
47  import org.apache.maven.artifact.resolver.ArtifactResolver;
48  import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
49  import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
50  import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
51  import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
52  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
53  import org.apache.maven.artifact.versioning.VersionRange;
54  import org.apache.maven.execution.MavenSession;
55  import org.apache.maven.execution.RuntimeInformation;
56  import org.apache.maven.model.Plugin;
57  import org.apache.maven.model.ReportPlugin;
58  import org.apache.maven.monitor.event.EventDispatcher;
59  import org.apache.maven.monitor.event.MavenEvents;
60  import org.apache.maven.monitor.logging.DefaultLog;
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.plugin.logging.Log;
66  import org.apache.maven.plugin.version.PluginVersionManager;
67  import org.apache.maven.plugin.version.PluginVersionNotFoundException;
68  import org.apache.maven.plugin.version.PluginVersionResolutionException;
69  import org.apache.maven.project.MavenProject;
70  import org.apache.maven.project.MavenProjectBuilder;
71  import org.apache.maven.project.ProjectBuildingException;
72  import org.apache.maven.project.artifact.InvalidDependencyVersionException;
73  import org.apache.maven.project.artifact.MavenMetadataSource;
74  import org.apache.maven.project.path.PathTranslator;
75  import org.apache.maven.reporting.MavenReport;
76  import org.apache.maven.settings.Settings;
77  import org.codehaus.classworlds.ClassRealm;
78  import org.codehaus.classworlds.NoSuchRealmException;
79  import org.codehaus.plexus.PlexusConstants;
80  import org.codehaus.plexus.PlexusContainer;
81  import org.codehaus.plexus.PlexusContainerException;
82  import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
83  import org.codehaus.plexus.component.configurator.ComponentConfigurator;
84  import org.codehaus.plexus.component.configurator.ConfigurationListener;
85  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
86  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
87  import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
88  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
89  import org.codehaus.plexus.configuration.PlexusConfiguration;
90  import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
91  import org.codehaus.plexus.context.Context;
92  import org.codehaus.plexus.context.ContextException;
93  import org.codehaus.plexus.logging.AbstractLogEnabled;
94  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
95  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
96  import org.codehaus.plexus.util.StringUtils;
97  import org.codehaus.plexus.util.xml.Xpp3Dom;
98  
99  public class DefaultPluginManager
100     extends AbstractLogEnabled
101     implements PluginManager, Initializable, Contextualizable
102 {
103     protected PlexusContainer container;
104 
105     protected PluginDescriptorBuilder pluginDescriptorBuilder;
106 
107     protected ArtifactFilter artifactFilter;
108 
109     private Log mojoLogger;
110 
111     private Map resolvedCoreArtifactFiles = new HashMap();
112 
113     // component requirements
114     protected PathTranslator pathTranslator;
115 
116     protected MavenPluginCollector pluginCollector;
117 
118     protected PluginVersionManager pluginVersionManager;
119 
120     protected ArtifactFactory artifactFactory;
121 
122     protected ArtifactResolver artifactResolver;
123 
124     protected ArtifactMetadataSource artifactMetadataSource;
125 
126     protected RuntimeInformation runtimeInformation;
127 
128     protected MavenProjectBuilder mavenProjectBuilder;
129 
130     protected PluginMappingManager pluginMappingManager;
131 
132     // END component requirements
133 
134     public DefaultPluginManager()
135     {
136         pluginDescriptorBuilder = new PluginDescriptorBuilder();
137     }
138 
139     // ----------------------------------------------------------------------
140     //
141     // ----------------------------------------------------------------------
142 
143     public PluginDescriptor getPluginDescriptorForPrefix( String prefix )
144     {
145         return pluginCollector.getPluginDescriptorForPrefix( prefix );
146     }
147 
148     public Plugin getPluginDefinitionForPrefix( String prefix,
149                                                 MavenSession session,
150                                                 MavenProject project )
151     {
152         // TODO: since this is only used in the lifecycle executor, maybe it should be moved there? There is no other
153         // use for the mapping manager in here
154         return pluginMappingManager.getByPrefix( prefix, session.getSettings().getPluginGroups(),
155                                                  project.getPluginArtifactRepositories(),
156                                                  session.getLocalRepository() );
157     }
158 
159     public PluginDescriptor verifyPlugin( Plugin plugin,
160                                           MavenProject project,
161                                           Settings settings,
162                                           ArtifactRepository localRepository )
163         throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
164         InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException,
165         PluginVersionNotFoundException
166     {
167         // TODO: this should be possibly outside
168         // All version-resolution logic has been moved to DefaultPluginVersionManager.
169         if ( plugin.getVersion() == null )
170         {
171             String version = pluginVersionManager.resolvePluginVersion( plugin.getGroupId(), plugin.getArtifactId(),
172                                                                         project, settings, localRepository );
173             plugin.setVersion( version );
174         }
175 
176         return verifyVersionedPlugin( plugin, project, localRepository );
177     }
178 
179     private PluginDescriptor verifyVersionedPlugin( Plugin plugin,
180                                                     MavenProject project,
181                                                     ArtifactRepository localRepository )
182         throws PluginVersionResolutionException, ArtifactNotFoundException, ArtifactResolutionException,
183         InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException
184     {
185         // TODO: this might result in an artifact "RELEASE" being resolved continuously
186         // FIXME: need to find out how a plugin gets marked as 'installed'
187         // and no ChildContainer exists. The check for that below fixes
188         // the 'Can't find plexus container for plugin: xxx' error.
189         try
190         {
191             VersionRange versionRange = VersionRange.createFromVersionSpec( plugin.getVersion() );
192 
193             List remoteRepositories = new ArrayList();
194             remoteRepositories.addAll( project.getPluginArtifactRepositories() );
195             remoteRepositories.addAll( project.getRemoteArtifactRepositories() );
196 
197             checkRequiredMavenVersion( plugin, localRepository, remoteRepositories );
198 
199             Artifact pluginArtifact =
200                 artifactFactory.createPluginArtifact( plugin.getGroupId(), plugin.getArtifactId(), versionRange );
201 
202             pluginArtifact = project.replaceWithActiveArtifact( pluginArtifact );
203 
204             artifactResolver.resolve( pluginArtifact, project.getPluginArtifactRepositories(), localRepository );
205 
206             PlexusContainer pluginContainer = container.getChildContainer( plugin.getKey() );
207 
208             File pluginFile = pluginArtifact.getFile();
209 
210             if ( !pluginCollector.isPluginInstalled( plugin ) || ( pluginContainer == null ) )
211             {
212                 addPlugin( plugin, pluginArtifact, project, localRepository );
213             }
214             else if ( pluginFile.lastModified() > pluginContainer.getCreationDate().getTime() )
215             {
216                 getLogger().info(
217                     "Reloading plugin container for: " + plugin.getKey() + ". The plugin artifact has changed." );
218 
219                 pluginContainer.dispose();
220 
221                 pluginCollector.flushPluginDescriptor( plugin );
222 
223                 addPlugin( plugin, pluginArtifact, project, localRepository );
224             }
225 
226             project.addPlugin( plugin );
227         }
228         catch ( ArtifactNotFoundException e )
229         {
230             String groupId = plugin.getGroupId();
231             String artifactId = plugin.getArtifactId();
232             String version = plugin.getVersion();
233 
234             if ( ( groupId == null ) || ( artifactId == null ) || ( version == null ) )
235             {
236                 throw new PluginNotFoundException( e );
237             }
238             else if ( groupId.equals( e.getGroupId() ) && artifactId.equals( e.getArtifactId() ) &&
239                 version.equals( e.getVersion() ) && "maven-plugin".equals( e.getType() ) )
240             {
241                 throw new PluginNotFoundException( e );
242             }
243             else
244             {
245                 throw e;
246             }
247         }
248 
249         return pluginCollector.getPluginDescriptor( plugin );
250     }
251 
252     /**
253      * @todo would be better to store this in the plugin descriptor, but then it won't be available to the version
254      * manager which executes before the plugin is instantiated
255      */
256     private void checkRequiredMavenVersion( Plugin plugin,
257                                             ArtifactRepository localRepository,
258                                             List remoteRepositories )
259         throws PluginVersionResolutionException, InvalidPluginException
260     {
261         try
262         {
263             Artifact artifact = artifactFactory.createProjectArtifact( plugin.getGroupId(), plugin.getArtifactId(),
264                                                                        plugin.getVersion() );
265             MavenProject project =
266                 mavenProjectBuilder.buildFromRepository( artifact, remoteRepositories, localRepository, false );
267             // if we don't have the required Maven version, then ignore an update
268             if ( ( project.getPrerequisites() != null ) && ( project.getPrerequisites().getMaven() != null ) )
269             {
270                 DefaultArtifactVersion requiredVersion =
271                     new DefaultArtifactVersion( project.getPrerequisites().getMaven() );
272                 if ( runtimeInformation.getApplicationVersion().compareTo( requiredVersion ) < 0 )
273                 {
274                     throw new PluginVersionResolutionException( plugin.getGroupId(), plugin.getArtifactId(),
275                                                                 "Plugin requires Maven version " + requiredVersion );
276                 }
277             }
278         }
279         catch ( ProjectBuildingException e )
280         {
281             throw new InvalidPluginException(
282                 "Unable to build project for plugin '" + plugin.getKey() + "': " + e.getMessage(), e );
283         }
284     }
285 
286     protected void addPlugin( Plugin plugin,
287                               Artifact pluginArtifact,
288                               MavenProject project,
289                               ArtifactRepository localRepository )
290         throws PluginManagerException, InvalidPluginException
291     {
292         PlexusContainer child;
293 
294         try
295         {
296             child = container.createChildContainer( plugin.getKey(),
297                                                     Collections.singletonList( pluginArtifact.getFile() ),
298                                                     Collections.EMPTY_MAP,
299                                                     Collections.singletonList( pluginCollector ) );
300             try
301             {
302                 child.getContainerRealm().importFrom( "plexus.core", "org.codehaus.plexus.util.xml.Xpp3Dom" );
303                 child.getContainerRealm().importFrom( "plexus.core", "org.codehaus.plexus.util.xml.pull" );
304 
305                 // MNG-2878
306                 child.getContainerRealm().importFrom( "plexus.core", "/default-report.xml" );
307             }
308             catch ( NoSuchRealmException e )
309             {
310                 // won't happen
311             }
312         }
313         catch ( PlexusContainerException e )
314         {
315             throw new PluginManagerException(
316                 "Failed to create plugin container for plugin '" + plugin + "': " + e.getMessage(), e );
317         }
318 
319         // this plugin's descriptor should have been discovered in the child creation, so we should be able to
320         // circle around and set the artifacts and class realm
321         PluginDescriptor addedPlugin = pluginCollector.getPluginDescriptor( plugin );
322 
323         if ( addedPlugin == null )
324         {
325             throw new IllegalStateException( "The PluginDescriptor for the plugin " + plugin + " was not found." );
326         }
327 
328         addedPlugin.setClassRealm( child.getContainerRealm() );
329 
330         // we're only setting the plugin's artifact itself as the artifact list, to allow it to be retrieved
331         // later when the plugin is first invoked. Retrieving this artifact will in turn allow us to
332         // transitively resolve its dependencies, and add them to the plugin container...
333         addedPlugin.setArtifacts( Collections.singletonList( pluginArtifact ) );
334 
335         try
336         {
337             // the only Plugin instance which will have dependencies is the one specified in the project.
338             // We need to look for a Plugin instance there, in case the instance we're using didn't come from
339             // the project.
340             Plugin projectPlugin = (Plugin) project.getBuild().getPluginsAsMap().get( plugin.getKey() );
341 
342             if ( projectPlugin == null )
343             {
344                 projectPlugin = plugin;
345             }
346 
347             Set artifacts = MavenMetadataSource.createArtifacts( artifactFactory, projectPlugin.getDependencies(), null,
348                                                                  null, project );
349 
350 //            Set artifacts =
351 //                MavenMetadataSource.createArtifacts( artifactFactory, plugin.getDependencies(), null, null, project );
352 
353             addedPlugin.setIntroducedDependencyArtifacts( artifacts );
354         }
355         catch ( InvalidDependencyVersionException e )
356         {
357             throw new InvalidPluginException( "Plugin '" + plugin + "' is invalid: " + e.getMessage(), e );
358         }
359     }
360 
361     // ----------------------------------------------------------------------
362     // Mojo execution
363     // ----------------------------------------------------------------------
364 
365     public void executeMojo( MavenProject project,
366                              MojoExecution mojoExecution,
367                              MavenSession session )
368         throws ArtifactResolutionException, MojoExecutionException, MojoFailureException, ArtifactNotFoundException,
369         InvalidDependencyVersionException, PluginManagerException, PluginConfigurationException
370     {
371         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
372 
373         // NOTE: I'm putting these checks in here, since this is the central point of access for
374         // anything that wants to execute a mojo.
375         if ( mojoDescriptor.isProjectRequired() && !session.isUsingPOMsFromFilesystem() )
376         {
377             throw new MojoExecutionException( "Cannot execute mojo: " + mojoDescriptor.getGoal() +
378                 ". It requires a project with an existing pom.xml, but the build is not using one." );
379         }
380 
381         if ( mojoDescriptor.isOnlineRequired() && session.getSettings().isOffline() )
382         {
383             // TODO: Should we error out, or simply warn and skip??
384             throw new MojoExecutionException( "Mojo: " + mojoDescriptor.getGoal() +
385                 " requires online mode for execution. Maven is currently offline." );
386         }
387 
388         if ( mojoDescriptor.isDependencyResolutionRequired() != null )
389         {
390             Collection projects;
391 
392             if ( mojoDescriptor.isAggregator() )
393             {
394                 projects = session.getSortedProjects();
395             }
396             else
397             {
398                 projects = Collections.singleton( project );
399             }
400 
401             for ( Iterator i = projects.iterator(); i.hasNext(); )
402             {
403                 MavenProject p = (MavenProject) i.next();
404 
405                 resolveTransitiveDependencies( session, artifactResolver,
406                                                mojoDescriptor.isDependencyResolutionRequired(), artifactFactory, p, mojoDescriptor.isAggregator() );
407             }
408 
409             downloadDependencies( project, session, artifactResolver );
410         }
411 
412         String goalName = mojoDescriptor.getFullGoalName();
413 
414         Mojo plugin;
415 
416         PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
417         String goalId = mojoDescriptor.getGoal();
418         String groupId = pluginDescriptor.getGroupId();
419         String artifactId = pluginDescriptor.getArtifactId();
420         String executionId = mojoExecution.getExecutionId();
421         Xpp3Dom dom = project.getGoalConfiguration( groupId, artifactId, executionId, goalId );
422         Xpp3Dom reportDom = project.getReportConfiguration( groupId, artifactId, executionId );
423         dom = Xpp3Dom.mergeXpp3Dom( dom, reportDom );
424         if ( mojoExecution.getConfiguration() != null )
425         {
426             dom = Xpp3Dom.mergeXpp3Dom( dom, mojoExecution.getConfiguration() );
427         }
428 
429         plugin = getConfiguredMojo( session, dom, project, false, mojoExecution );
430 
431         // Event monitoring.
432         String event = MavenEvents.MOJO_EXECUTION;
433         EventDispatcher dispatcher = session.getEventDispatcher();
434 
435         String goalExecId = goalName;
436 
437         if ( mojoExecution.getExecutionId() != null )
438         {
439             goalExecId += " {execution: " + mojoExecution.getExecutionId() + "}";
440         }
441 
442         dispatcher.dispatchStart( event, goalExecId );
443 
444         ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
445 
446         try
447         {
448             Thread.currentThread().setContextClassLoader(
449                 mojoDescriptor.getPluginDescriptor().getClassRealm().getClassLoader() );
450 
451             plugin.execute();
452 
453             dispatcher.dispatchEnd( event, goalExecId );
454         }
455         catch ( MojoExecutionException e )
456         {
457             session.getEventDispatcher().dispatchError( event, goalExecId, e );
458 
459             throw e;
460         }
461         catch ( MojoFailureException e )
462         {
463             session.getEventDispatcher().dispatchError( event, goalExecId, e );
464 
465             throw e;
466         }
467         catch ( LinkageError e )
468         {
469             if ( getLogger().isFatalErrorEnabled() )
470             {
471                 getLogger().fatalError(
472                                         plugin.getClass().getName() + "#execute() caused a linkage error ("
473                                             + e.getClass().getName() + ") and may be out-of-date. Check the realms:" );
474 
475                 ClassRealm pluginRealm = mojoDescriptor.getPluginDescriptor().getClassRealm();
476                 StringBuffer sb = new StringBuffer();
477                 sb.append( "Plugin realm = " + pluginRealm.getId() ).append( '\n' );
478                 for ( int i = 0; i < pluginRealm.getConstituents().length; i++ )
479                 {
480                     sb.append( "urls[" + i + "] = " + pluginRealm.getConstituents()[i] );
481                     if ( i != ( pluginRealm.getConstituents().length - 1 ) )
482                     {
483                         sb.append( '\n' );
484                     }
485                 }
486                 getLogger().fatalError( sb.toString() );
487 
488                 ClassRealm containerRealm = container.getContainerRealm();
489                 sb = new StringBuffer();
490                 sb.append( "Container realm = " + containerRealm.getId() ).append( '\n' );
491                 for ( int i = 0; i < containerRealm.getConstituents().length; i++ )
492                 {
493                     sb.append( "urls[" + i + "] = " + containerRealm.getConstituents()[i] );
494                     if ( i != ( containerRealm.getConstituents().length - 1 ) )
495                     {
496                         sb.append( '\n' );
497                     }
498                 }
499                 getLogger().fatalError( sb.toString() );
500             }
501 
502             session.getEventDispatcher().dispatchError( event, goalExecId, e );
503 
504             throw e;
505         }
506         finally
507         {
508 
509             Thread.currentThread().setContextClassLoader( oldClassLoader );
510 
511             try
512             {
513                 PlexusContainer pluginContainer = getPluginContainer( mojoDescriptor.getPluginDescriptor() );
514 
515                 pluginContainer.release( plugin );
516             }
517             catch ( ComponentLifecycleException e )
518             {
519                 if ( getLogger().isErrorEnabled() )
520                 {
521                     getLogger().error( "Error releasing plugin - ignoring.", e );
522                 }
523             }
524         }
525     }
526 
527     public MavenReport getReport( MavenProject project,
528                                   MojoExecution mojoExecution,
529                                   MavenSession session )
530         throws ArtifactNotFoundException, PluginConfigurationException, PluginManagerException,
531         ArtifactResolutionException
532     {
533         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
534         PluginDescriptor descriptor = mojoDescriptor.getPluginDescriptor();
535         Xpp3Dom dom = project.getReportConfiguration( descriptor.getGroupId(), descriptor.getArtifactId(),
536                                                       mojoExecution.getExecutionId() );
537         if ( mojoExecution.getConfiguration() != null )
538         {
539             dom = Xpp3Dom.mergeXpp3Dom( dom, mojoExecution.getConfiguration() );
540         }
541 
542         return (MavenReport) getConfiguredMojo( session, dom, project, true, mojoExecution );
543     }
544 
545     public PluginDescriptor verifyReportPlugin( ReportPlugin reportPlugin,
546                                                 MavenProject project,
547                                                 MavenSession session )
548         throws PluginVersionResolutionException, ArtifactResolutionException, ArtifactNotFoundException,
549         InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException,
550         PluginVersionNotFoundException
551     {
552         String version = reportPlugin.getVersion();
553 
554         if ( version == null )
555         {
556             version = pluginVersionManager.resolveReportPluginVersion( reportPlugin.getGroupId(),
557                                                                        reportPlugin.getArtifactId(), project,
558                                                                        session.getSettings(),
559                                                                        session.getLocalRepository() );
560             reportPlugin.setVersion( version );
561         }
562 
563         Plugin forLookup = new Plugin();
564 
565         forLookup.setGroupId( reportPlugin.getGroupId() );
566         forLookup.setArtifactId( reportPlugin.getArtifactId() );
567         forLookup.setVersion( version );
568 
569         return verifyVersionedPlugin( forLookup, project, session.getLocalRepository() );
570     }
571 
572     private PlexusContainer getPluginContainer( PluginDescriptor pluginDescriptor )
573         throws PluginManagerException
574     {
575         String pluginKey = pluginDescriptor.getPluginLookupKey();
576 
577         PlexusContainer pluginContainer = container.getChildContainer( pluginKey );
578 
579         if ( pluginContainer == null )
580         {
581             throw new PluginManagerException( "Cannot find Plexus container for plugin: " + pluginKey );
582         }
583 
584         return pluginContainer;
585     }
586 
587     private Mojo getConfiguredMojo( MavenSession session,
588                                     Xpp3Dom dom,
589                                     MavenProject project,
590                                     boolean report,
591                                     MojoExecution mojoExecution )
592         throws PluginConfigurationException, ArtifactNotFoundException, PluginManagerException,
593         ArtifactResolutionException
594     {
595         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
596 
597         PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
598 
599         PlexusContainer pluginContainer = getPluginContainer( pluginDescriptor );
600 
601         // if this is the first time this plugin has been used, the plugin's container will only
602         // contain the plugin's artifact in isolation; we need to finish resolving the plugin's
603         // dependencies, and add them to the container.
604         ensurePluginContainerIsComplete( pluginDescriptor, pluginContainer, project, session );
605 
606         Mojo plugin;
607         try
608         {
609             plugin = (Mojo) pluginContainer.lookup( Mojo.ROLE, mojoDescriptor.getRoleHint() );
610             if ( report && !( plugin instanceof MavenReport ) )
611             {
612                 // TODO: the mojoDescriptor should actually capture this information so we don't get this far
613                 return null;
614             }
615         }
616         catch ( ComponentLookupException e )
617         {
618             throw new PluginManagerException( "Unable to find the mojo '" + mojoDescriptor.getRoleHint() +
619                 "' in the plugin '" + pluginDescriptor.getPluginLookupKey() + "'", e );
620         }
621 
622         if ( plugin instanceof ContextEnabled )
623         {
624             Map pluginContext = session.getPluginContext( pluginDescriptor, project );
625 
626             ( (ContextEnabled) plugin ).setPluginContext( pluginContext );
627         }
628 
629         plugin.setLog( mojoLogger );
630 
631         XmlPlexusConfiguration pomConfiguration;
632         if ( dom == null )
633         {
634             pomConfiguration = new XmlPlexusConfiguration( "configuration" );
635         }
636         else
637         {
638             pomConfiguration = new XmlPlexusConfiguration( dom );
639         }
640 
641         // Validate against non-editable (@readonly) parameters, to make sure users aren't trying to
642         // override in the POM.
643         validatePomConfiguration( mojoDescriptor, pomConfiguration );
644 
645         PlexusConfiguration mergedConfiguration = mergeMojoConfiguration( pomConfiguration, mojoDescriptor );
646 
647         // TODO: plexus changes to make this more like the component descriptor so this can be used instead
648         //            PlexusConfiguration mergedConfiguration = mergeConfiguration( pomConfiguration,
649         //                                                                          mojoDescriptor.getConfiguration() );
650 
651         ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator( session, mojoExecution,
652                                                                                           pathTranslator, getLogger(),
653                                                                                           project,
654                                                                                           session.getExecutionProperties() );
655 
656         PlexusConfiguration extractedMojoConfiguration =
657             extractMojoConfiguration( mergedConfiguration, mojoDescriptor );
658 
659         checkRequiredParameters( mojoDescriptor, extractedMojoConfiguration, expressionEvaluator );
660 
661         populatePluginFields( plugin, mojoDescriptor, extractedMojoConfiguration, pluginContainer,
662                               expressionEvaluator );
663         return plugin;
664     }
665 
666     private void ensurePluginContainerIsComplete( PluginDescriptor pluginDescriptor,
667                                                   PlexusContainer pluginContainer,
668                                                   MavenProject project,
669                                                   MavenSession session )
670         throws ArtifactNotFoundException, PluginManagerException, ArtifactResolutionException
671     {
672         // if the plugin's already been used once, don't re-do this step...
673         // otherwise, we have to finish resolving the plugin's classpath and start the container.
674         if ( ( pluginDescriptor.getArtifacts() != null ) && ( pluginDescriptor.getArtifacts().size() == 1 ) )
675         {
676             Artifact pluginArtifact = (Artifact) pluginDescriptor.getArtifacts().get( 0 );
677 
678             ArtifactRepository localRepository = session.getLocalRepository();
679 
680             ResolutionGroup resolutionGroup;
681             try
682             {
683                 resolutionGroup = artifactMetadataSource.retrieve( pluginArtifact, localRepository,
684                                                                    project.getPluginArtifactRepositories() );
685             }
686             catch ( ArtifactMetadataRetrievalException e )
687             {
688                 throw new ArtifactResolutionException( "Unable to download metadata from repository for plugin '" +
689                     pluginArtifact.getId() + "': " + e.getMessage(), pluginArtifact, e );
690             }
691 
692             checkPlexusUtils( resolutionGroup, artifactFactory );
693 
694             // [jdcasey; 20-March-2008]:
695             // This is meant to eliminate the introduction of duplicated artifacts.
696             // Since much of the reasoning for reversing the order of introduction of
697             // plugin dependencies rests on the notion that we need to be able to
698             // introduce upgraded versions of plugin dependencies on a case-by-case
699             // basis, we need to remove the original version prior to artifact
700             // resolution. This is consistent with recent thinking on duplicated
701             // dependency specifications within a POM, where that case should
702             // throw a model validation exception.
703             //
704             // Here, we just want to remove any chance that the ArtifactCollector
705             // could make a bad choice, and use the old version in spite of our
706             // explicit preference otherwise.
707 
708             // First, we're going to accumulate plugin dependencies in an ordered map,
709             // keyed by dependencyConflictId (the ordered map is meant to preserve relative
710             // ordering of the dependencies that do make the cut).
711             Map dependencyMap = new LinkedHashMap();
712 
713             // Next, we need to accumulate all dependencies in a List, to make it
714             // simpler to iterate through them all and add them to the map.
715             List all = new ArrayList();
716 
717             // plugin-level dependencies from the consuming POM override dependencies
718             // from the plugin's own POM.
719             all.addAll( pluginDescriptor.getIntroducedDependencyArtifacts() );
720 
721             // add in the deps from the plugin POM now.
722             all.addAll( resolutionGroup.getArtifacts() );
723 
724             for ( Iterator it = all.iterator(); it.hasNext(); )
725             {
726                 Artifact artifact = (Artifact) it.next();
727                 String conflictId = artifact.getDependencyConflictId();
728 
729                 // if the map already contains this dependencyConflictId, it constitutes an
730                 // overridden dependency. Don't use the old one (we know it's old from the
731                 // order in which dependencies were added to this list).
732                 if ( !dependencyMap.containsKey( conflictId ) )
733                 {
734                     dependencyMap.put( conflictId, artifact );
735                 }
736             }
737 
738             // Create an ordered set of dependencies from the ordered map we used above, to feed into the resolver.
739             Set dependencies = new LinkedHashSet( dependencyMap.values() );
740 
741             if ( getLogger().isDebugEnabled() )
742             {
743                 // list all dependencies to be used by this plugin (first-level deps, not transitive ones).
744                 getLogger().debug( "Plugin dependencies for:\n\n" + pluginDescriptor.getId()
745                                    + "\n\nare:\n\n"
746                                    + StringUtils.join( dependencies.iterator(), "\n" ) + "\n\n" );
747             }
748 
749             List repositories = new ArrayList();
750             repositories.addAll( resolutionGroup.getResolutionRepositories() );
751             repositories.addAll( project.getRemoteArtifactRepositories() );
752 
753             /* get plugin managed versions */
754             Map pluginManagedDependencies = new HashMap();
755             try
756             {
757                 MavenProject pluginProject =
758                     mavenProjectBuilder.buildFromRepository( pluginArtifact, project.getRemoteArtifactRepositories(),
759                                                              localRepository );
760                 if ( pluginProject != null )
761                 {
762                     pluginManagedDependencies = pluginProject.getManagedVersionMap();
763                 }
764             }
765             catch ( ProjectBuildingException e )
766             {
767                 // this can't happen, it would have blowed up at artifactMetadataSource.retrieve()
768             }
769 
770             ArtifactResolutionResult result = artifactResolver.resolveTransitively( dependencies, pluginArtifact,
771                                                                                     pluginManagedDependencies,
772                                                                                     localRepository, repositories,
773                                                                                     artifactMetadataSource,
774                                                                                     artifactFilter );
775 
776             Set resolved = result.getArtifacts();
777 
778             for ( Iterator it = resolved.iterator(); it.hasNext(); )
779             {
780                 Artifact artifact = (Artifact) it.next();
781 
782                 if ( !artifact.equals( pluginArtifact ) )
783                 {
784                     artifact = project.replaceWithActiveArtifact( artifact );
785 
786                     try
787                     {
788                         pluginContainer.addJarResource( artifact.getFile() );
789                     }
790                     catch ( PlexusContainerException e )
791                     {
792                         throw new PluginManagerException( "Error adding plugin dependency '" +
793                             artifact.getDependencyConflictId() + "' into plugin manager: " + e.getMessage(), e );
794                     }
795                 }
796             }
797 
798             pluginDescriptor.setClassRealm( pluginContainer.getContainerRealm() );
799 
800             List unresolved = new ArrayList( dependencies );
801 
802             unresolved.removeAll( resolved );
803 
804             if ( getLogger().isDebugEnabled() )
805             {
806                 // list all artifacts that were filtered out during the resolution process.
807                 // these are already present in the core container.
808                 getLogger().debug( " The following artifacts were filtered out for plugin: "
809                                    + pluginDescriptor.getId()
810                                    + " because they're already in the core of Maven:\n\n"
811                                    + StringUtils.join( unresolved.iterator(), "\n" )
812                                    + "\n\nThese will use the artifact files already in the core ClassRealm instead, to allow them to be included in PluginDescriptor.getArtifacts().\n\n" );
813             }
814 
815             // Grab a file for all filtered artifacts, even if it means resolving them. This
816             // is necessary in order to present a full complement of a plugin's transitive
817             // dependencies to anyone who calls PluginDescriptor.getArtifacts().
818             resolveCoreArtifacts( unresolved, localRepository, resolutionGroup.getResolutionRepositories() );
819 
820             // Re-join resolved and filtered-but-now-resolved artifacts.
821             // NOTE: The process of filtering then re-adding some artifacts will
822             // result in different ordering within the PluginDescriptor.getArtifacts()
823             // List than should have happened if none had been filtered. All filtered
824             // artifacts will be listed last...
825             List allResolved = new ArrayList( resolved.size() + unresolved.size() );
826 
827             allResolved.addAll( resolved );
828             allResolved.addAll( unresolved );
829 
830             pluginDescriptor.setArtifacts( allResolved );
831         }
832     }
833 
834     public static void checkPlexusUtils( ResolutionGroup resolutionGroup, ArtifactFactory artifactFactory )
835     {
836         // ----------------------------------------------------------------------------
837         // If the plugin already declares a dependency on plexus-utils then we're all
838         // set as the plugin author is aware of its use. If we don't have a dependency
839         // on plexus-utils then we must protect users from stupid plugin authors who
840         // did not declare a direct dependency on plexus-utils because the version
841         // Maven uses is hidden from downstream use. We will also bump up any
842         // anything below 1.1 to 1.1 as this mimics the behaviour in 2.0.5 where
843         // plexus-utils 1.1 was being forced into use.
844         // ----------------------------------------------------------------------------
845 
846         VersionRange vr = null;
847 
848         try
849         {
850             vr = VersionRange.createFromVersionSpec( "[1.1,)" );
851         }
852         catch ( InvalidVersionSpecificationException e )
853         {
854             // Won't happen
855         }
856 
857         boolean plexusUtilsPresent = false;
858 
859         for ( Iterator i = resolutionGroup.getArtifacts().iterator(); i.hasNext(); )
860         {
861             Artifact a = (Artifact) i.next();
862 
863             if ( a.getArtifactId().equals( "plexus-utils" ) &&
864                 vr.containsVersion( new DefaultArtifactVersion( a.getVersion() ) ) )
865             {
866                 plexusUtilsPresent = true;
867 
868                 break;
869             }
870         }
871 
872         if ( !plexusUtilsPresent )
873         {
874             // We will add plexus-utils as every plugin was getting this anyway from Maven itself. We will set the
875             // version to the latest version we know that works as of the 2.0.6 release. We set the scope to runtime
876             // as this is what's implicitly happening in 2.0.6.
877 
878             resolutionGroup.getArtifacts().add( artifactFactory.createArtifact( "org.codehaus.plexus",
879                                                                                 "plexus-utils", "1.1",
880                                                                                 Artifact.SCOPE_RUNTIME, "jar" ) );
881         }
882     }
883 
884     private void resolveCoreArtifacts( List unresolved,
885                                        ArtifactRepository localRepository,
886                                        List resolutionRepositories )
887         throws ArtifactResolutionException, ArtifactNotFoundException
888     {
889         for ( Iterator it = unresolved.iterator(); it.hasNext(); )
890         {
891             Artifact artifact = (Artifact) it.next();
892 
893             File artifactFile = (File) resolvedCoreArtifactFiles.get( artifact.getId() );
894 
895             if ( artifactFile == null )
896             {
897                 String resource =
898                     "/META-INF/maven/" + artifact.getGroupId() + "/" + artifact.getArtifactId() + "/pom.xml";
899 
900                 URL resourceUrl = container.getContainerRealm().getResource( resource );
901 
902                 if ( resourceUrl == null )
903                 {
904                     artifactResolver.resolve( artifact, resolutionRepositories, localRepository );
905 
906                     artifactFile = artifact.getFile();
907                 }
908                 else
909                 {
910                     String artifactPath = resourceUrl.getPath();
911 
912                     if ( artifactPath.startsWith( "file:" ) )
913                     {
914                         artifactPath = artifactPath.substring( "file:".length() );
915                     }
916 
917                     artifactPath = artifactPath.substring( 0, artifactPath.length() - resource.length() );
918 
919                     if ( artifactPath.endsWith( "/" ) )
920                     {
921                         artifactPath = artifactPath.substring( 0, artifactPath.length() - 1 );
922                     }
923 
924                     if ( artifactPath.endsWith( "!" ) )
925                     {
926                         artifactPath = artifactPath.substring( 0, artifactPath.length() - 1 );
927                     }
928 
929                     artifactFile = new File( artifactPath ).getAbsoluteFile();
930                 }
931 
932                 resolvedCoreArtifactFiles.put( artifact.getId(), artifactFile );
933             }
934 
935             artifact.setFile( artifactFile );
936         }
937     }
938 
939     private PlexusConfiguration extractMojoConfiguration( PlexusConfiguration mergedConfiguration,
940                                                           MojoDescriptor mojoDescriptor )
941     {
942         Map parameterMap = mojoDescriptor.getParameterMap();
943 
944         PlexusConfiguration[] mergedChildren = mergedConfiguration.getChildren();
945 
946         XmlPlexusConfiguration extractedConfiguration = new XmlPlexusConfiguration( "configuration" );
947 
948         for ( int i = 0; i < mergedChildren.length; i++ )
949         {
950             PlexusConfiguration child = mergedChildren[i];
951 
952             if ( parameterMap.containsKey( child.getName() ) )
953             {
954                 extractedConfiguration.addChild( copyConfiguration( child ) );
955             }
956             else
957             {
958                 // TODO: I defy anyone to find these messages in the '-X' output! Do we need a new log level?
959                 // ideally, this would be elevated above the true debug output, but below the default INFO level...
960                 // [BP] (2004-07-18): need to understand the context more but would prefer this could be either WARN or
961                 // removed - shouldn't need DEBUG to diagnose a problem most of the time.
962                 getLogger().debug( "*** WARNING: Configuration \'" + child.getName() + "\' is not used in goal \'" +
963                     mojoDescriptor.getFullGoalName() + "; this may indicate a typo... ***" );
964             }
965         }
966 
967         return extractedConfiguration;
968     }
969 
970     private void checkRequiredParameters( MojoDescriptor goal,
971                                           PlexusConfiguration configuration,
972                                           ExpressionEvaluator expressionEvaluator )
973         throws PluginConfigurationException
974     {
975         // TODO: this should be built in to the configurator, as we presently double process the expressions
976 
977         List parameters = goal.getParameters();
978 
979         if ( parameters == null )
980         {
981             return;
982         }
983 
984         List invalidParameters = new ArrayList();
985 
986         for ( int i = 0; i < parameters.size(); i++ )
987         {
988             Parameter parameter = (Parameter) parameters.get( i );
989 
990             if ( parameter.isRequired() )
991             {
992                 // the key for the configuration map we're building.
993                 String key = parameter.getName();
994 
995                 Object fieldValue = null;
996                 String expression = null;
997                 PlexusConfiguration value = configuration.getChild( key, false );
998                 try
999                 {
1000                     if ( value != null )
1001                     {
1002                         expression = value.getValue( null );
1003 
1004                         fieldValue = expressionEvaluator.evaluate( expression );
1005 
1006                         if ( fieldValue == null )
1007                         {
1008                             fieldValue = value.getAttribute( "default-value", null );
1009                         }
1010                     }
1011 
1012                     if ( ( fieldValue == null ) && StringUtils.isNotEmpty( parameter.getAlias() ) )
1013                     {
1014                         value = configuration.getChild( parameter.getAlias(), false );
1015                         if ( value != null )
1016                         {
1017                             expression = value.getValue( null );
1018                             fieldValue = expressionEvaluator.evaluate( expression );
1019                             if ( fieldValue == null )
1020                             {
1021                                 fieldValue = value.getAttribute( "default-value", null );
1022                             }
1023                         }
1024                     }
1025                 }
1026                 catch ( ExpressionEvaluationException e )
1027                 {
1028                     throw new PluginConfigurationException( goal.getPluginDescriptor(), e.getMessage(), e );
1029                 }
1030 
1031                 // only mark as invalid if there are no child nodes
1032                 if ( ( fieldValue == null ) && ( ( value == null ) || ( value.getChildCount() == 0 ) ) )
1033                 {
1034                     parameter.setExpression( expression );
1035                     invalidParameters.add( parameter );
1036                 }
1037             }
1038         }
1039 
1040         if ( !invalidParameters.isEmpty() )
1041         {
1042             throw new PluginParameterException( goal, invalidParameters );
1043         }
1044     }
1045 
1046     private void validatePomConfiguration( MojoDescriptor goal,
1047                                            PlexusConfiguration pomConfiguration )
1048         throws PluginConfigurationException
1049     {
1050         List parameters = goal.getParameters();
1051 
1052         if ( parameters == null )
1053         {
1054             return;
1055         }
1056 
1057         for ( int i = 0; i < parameters.size(); i++ )
1058         {
1059             Parameter parameter = (Parameter) parameters.get( i );
1060 
1061             // the key for the configuration map we're building.
1062             String key = parameter.getName();
1063 
1064             PlexusConfiguration value = pomConfiguration.getChild( key, false );
1065 
1066             if ( ( value == null ) && StringUtils.isNotEmpty( parameter.getAlias() ) )
1067             {
1068                 key = parameter.getAlias();
1069                 value = pomConfiguration.getChild( key, false );
1070             }
1071 
1072             if ( value != null )
1073             {
1074                 // Make sure the parameter is either editable/configurable, or else is NOT specified in the POM
1075                 if ( !parameter.isEditable() )
1076                 {
1077                     StringBuffer errorMessage = new StringBuffer()
1078                         .append( "ERROR: Cannot override read-only parameter: " );
1079                     errorMessage.append( key );
1080                     errorMessage.append( " in goal: " ).append( goal.getFullGoalName() );
1081 
1082                     throw new PluginConfigurationException( goal.getPluginDescriptor(), errorMessage.toString() );
1083                 }
1084 
1085                 String deprecated = parameter.getDeprecated();
1086                 if ( StringUtils.isNotEmpty( deprecated ) )
1087                 {
1088                     getLogger().warn( "DEPRECATED [" + parameter.getName() + "]: " + deprecated );
1089                 }
1090             }
1091         }
1092     }
1093 
1094     private PlexusConfiguration mergeMojoConfiguration( XmlPlexusConfiguration fromPom,
1095                                                         MojoDescriptor mojoDescriptor )
1096     {
1097         XmlPlexusConfiguration result = new XmlPlexusConfiguration( fromPom.getName() );
1098         result.setValue( fromPom.getValue( null ) );
1099 
1100         if ( mojoDescriptor.getParameters() != null )
1101         {
1102             PlexusConfiguration fromMojo = mojoDescriptor.getMojoConfiguration();
1103 
1104             for ( Iterator it = mojoDescriptor.getParameters().iterator(); it.hasNext(); )
1105             {
1106                 Parameter parameter = (Parameter) it.next();
1107 
1108                 String paramName = parameter.getName();
1109                 String alias = parameter.getAlias();
1110                 String implementation = parameter.getImplementation();
1111 
1112                 PlexusConfiguration pomConfig = fromPom.getChild( paramName );
1113                 PlexusConfiguration aliased = null;
1114 
1115                 if ( alias != null )
1116                 {
1117                     aliased = fromPom.getChild( alias );
1118                 }
1119 
1120                 PlexusConfiguration mojoConfig = fromMojo.getChild( paramName, false );
1121 
1122                 // first we'll merge configurations from the aliased and real params.
1123                 // TODO: Is this the right thing to do?
1124                 if ( aliased != null )
1125                 {
1126                     if ( pomConfig == null )
1127                     {
1128                         pomConfig = new XmlPlexusConfiguration( paramName );
1129                     }
1130 
1131                     pomConfig = buildTopDownMergedConfiguration( pomConfig, aliased );
1132                 }
1133 
1134                 PlexusConfiguration toAdd = null;
1135 
1136                 if ( pomConfig != null )
1137                 {
1138                     pomConfig = buildTopDownMergedConfiguration( pomConfig, mojoConfig );
1139 
1140                     if ( StringUtils.isNotEmpty( pomConfig.getValue( null ) ) || ( pomConfig.getChildCount() > 0 ) )
1141                     {
1142                         toAdd = pomConfig;
1143                     }
1144                 }
1145 
1146                 if ( ( toAdd == null ) && ( mojoConfig != null ) )
1147                 {
1148                     toAdd = copyConfiguration( mojoConfig );
1149                 }
1150 
1151                 if ( toAdd != null )
1152                 {
1153                     if ( ( implementation != null ) && ( toAdd.getAttribute( "implementation", null ) == null ) )
1154                     {
1155 
1156                         XmlPlexusConfiguration implementationConf = new XmlPlexusConfiguration( paramName );
1157 
1158                         implementationConf.setAttribute( "implementation", parameter.getImplementation() );
1159 
1160                         toAdd = buildTopDownMergedConfiguration( toAdd, implementationConf );
1161                     }
1162 
1163                     result.addChild( toAdd );
1164                 }
1165             }
1166         }
1167         return result;
1168     }
1169 
1170     private XmlPlexusConfiguration buildTopDownMergedConfiguration( PlexusConfiguration dominant,
1171                                                                     PlexusConfiguration recessive )
1172     {
1173         XmlPlexusConfiguration result = new XmlPlexusConfiguration( dominant.getName() );
1174 
1175         String value = dominant.getValue( null );
1176 
1177         if ( StringUtils.isEmpty( value ) && ( recessive != null ) )
1178         {
1179             value = recessive.getValue( null );
1180         }
1181 
1182         if ( StringUtils.isNotEmpty( value ) )
1183         {
1184             result.setValue( value );
1185         }
1186 
1187         String[] attributeNames = dominant.getAttributeNames();
1188 
1189         for ( int i = 0; i < attributeNames.length; i++ )
1190         {
1191             String attributeValue = dominant.getAttribute( attributeNames[i], null );
1192 
1193             result.setAttribute( attributeNames[i], attributeValue );
1194         }
1195 
1196         if ( recessive != null )
1197         {
1198             attributeNames = recessive.getAttributeNames();
1199 
1200             for ( int i = 0; i < attributeNames.length; i++ )
1201             {
1202                 String attributeValue = recessive.getAttribute( attributeNames[i], null );
1203                 // TODO: recessive seems to be dominant here?
1204                 result.setAttribute( attributeNames[i], attributeValue );
1205             }
1206         }
1207 
1208         PlexusConfiguration[] children = dominant.getChildren();
1209 
1210         for ( int i = 0; i < children.length; i++ )
1211         {
1212             PlexusConfiguration childDom = children[i];
1213             PlexusConfiguration childRec = recessive == null ? null : recessive.getChild( childDom.getName(), false );
1214 
1215             if ( childRec != null )
1216             {
1217                 result.addChild( buildTopDownMergedConfiguration( childDom, childRec ) );
1218             }
1219             else
1220             {   // FIXME: copy, or use reference?
1221                 result.addChild( copyConfiguration( childDom ) );
1222             }
1223         }
1224 
1225         return result;
1226     }
1227 
1228     public static PlexusConfiguration copyConfiguration( PlexusConfiguration src )
1229     {
1230         // TODO: shouldn't be necessary
1231         XmlPlexusConfiguration dom = new XmlPlexusConfiguration( src.getName() );
1232         dom.setValue( src.getValue( null ) );
1233 
1234         String[] attributeNames = src.getAttributeNames();
1235         for ( int i = 0; i < attributeNames.length; i++ )
1236         {
1237             String attributeName = attributeNames[i];
1238             dom.setAttribute( attributeName, src.getAttribute( attributeName, null ) );
1239         }
1240 
1241         PlexusConfiguration[] children = src.getChildren();
1242         for ( int i = 0; i < children.length; i++ )
1243         {
1244             dom.addChild( copyConfiguration( children[i] ) );
1245         }
1246 
1247         return dom;
1248     }
1249 
1250     // ----------------------------------------------------------------------
1251     // Mojo Parameter Handling
1252     // ----------------------------------------------------------------------
1253 
1254     private void populatePluginFields( Mojo plugin,
1255                                        MojoDescriptor mojoDescriptor,
1256                                        PlexusConfiguration configuration,
1257                                        PlexusContainer pluginContainer,
1258                                        ExpressionEvaluator expressionEvaluator )
1259         throws PluginConfigurationException
1260     {
1261         ComponentConfigurator configurator = null;
1262 
1263         try
1264         {
1265             String configuratorId = mojoDescriptor.getComponentConfigurator();
1266 
1267             // TODO: could the configuration be passed to lookup and the configurator known to plexus via the descriptor
1268             // so that this meethod could entirely be handled by a plexus lookup?
1269             if ( StringUtils.isNotEmpty( configuratorId ) )
1270             {
1271                 configurator =
1272                     (ComponentConfigurator) pluginContainer.lookup( ComponentConfigurator.ROLE, configuratorId );
1273             }
1274             else
1275             {
1276                 configurator = (ComponentConfigurator) pluginContainer.lookup( ComponentConfigurator.ROLE );
1277             }
1278 
1279             ConfigurationListener listener = new DebugConfigurationListener( getLogger() );
1280 
1281             getLogger().debug( "Configuring mojo '" + mojoDescriptor.getId() + "' -->" );
1282             configurator.configureComponent( plugin, configuration, expressionEvaluator,
1283                                              pluginContainer.getContainerRealm(), listener );
1284             getLogger().debug( "-- end configuration --" );
1285         }
1286         catch ( ComponentConfigurationException e )
1287         {
1288             throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
1289                                                     "Unable to parse the created DOM for plugin configuration", e );
1290         }
1291         catch ( ComponentLookupException e )
1292         {
1293             throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
1294                                                     "Unable to retrieve component configurator for plugin configuration",
1295                                                     e );
1296         }
1297         catch ( LinkageError e )
1298         {
1299             if ( getLogger().isFatalErrorEnabled() )
1300             {
1301                 getLogger().fatalError(
1302                                         configurator.getClass().getName() + "#configureComponent(...) caused a linkage error ("
1303                                             + e.getClass().getName() + ") and may be out-of-date. Check the realms:" );
1304 
1305                 ClassRealm pluginRealm = mojoDescriptor.getPluginDescriptor().getClassRealm();
1306                 StringBuffer sb = new StringBuffer();
1307                 sb.append( "Plugin realm = " + pluginRealm.getId() ).append( '\n' );
1308                 for ( int i = 0; i < pluginRealm.getConstituents().length; i++ )
1309                 {
1310                     sb.append( "urls[" + i + "] = " + pluginRealm.getConstituents()[i] );
1311                     if ( i != ( pluginRealm.getConstituents().length - 1 ) )
1312                     {
1313                         sb.append( '\n' );
1314                     }
1315                 }
1316                 getLogger().fatalError( sb.toString() );
1317 
1318                 ClassRealm containerRealm = container.getContainerRealm();
1319                 sb = new StringBuffer();
1320                 sb.append( "Container realm = " + containerRealm.getId() ).append( '\n' );
1321                 for ( int i = 0; i < containerRealm.getConstituents().length; i++ )
1322                 {
1323                     sb.append( "urls[" + i + "] = " + containerRealm.getConstituents()[i] );
1324                     if ( i != ( containerRealm.getConstituents().length - 1 ) )
1325                     {
1326                         sb.append( '\n' );
1327                     }
1328                 }
1329                 getLogger().fatalError( sb.toString() );
1330             }
1331 
1332             throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
1333                                                     e.getClass().getName() + ": " + e.getMessage(), e );
1334         }
1335         finally
1336         {
1337             if ( configurator != null )
1338             {
1339                 try
1340                 {
1341                     pluginContainer.release( configurator );
1342                 }
1343                 catch ( ComponentLifecycleException e )
1344                 {
1345                     getLogger().debug( "Failed to release plugin container - ignoring." );
1346                 }
1347             }
1348         }
1349     }
1350 
1351     public static String createPluginParameterRequiredMessage( MojoDescriptor mojo,
1352                                                                Parameter parameter,
1353                                                                String expression )
1354     {
1355         StringBuffer message = new StringBuffer();
1356 
1357         message.append( "The '" );
1358         message.append( parameter.getName() );
1359         message.append( "' parameter is required for the execution of the " );
1360         message.append( mojo.getFullGoalName() );
1361         message.append( " mojo and cannot be null." );
1362         if ( expression != null )
1363         {
1364             message.append( " The retrieval expression was: " ).append( expression );
1365         }
1366 
1367         return message.toString();
1368     }
1369 
1370     // ----------------------------------------------------------------------
1371     // Lifecycle
1372     // ----------------------------------------------------------------------
1373 
1374     public void contextualize( Context context )
1375         throws ContextException
1376     {
1377         container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
1378 
1379         mojoLogger = new DefaultLog( container.getLoggerManager().getLoggerForComponent( Mojo.ROLE ) );
1380     }
1381 
1382     public void initialize()
1383     {
1384         artifactFilter = MavenArtifactFilterManager.createStandardFilter();
1385     }
1386 
1387     // ----------------------------------------------------------------------
1388     // Artifact resolution
1389     // ----------------------------------------------------------------------
1390 
1391     private void resolveTransitiveDependencies( MavenSession context,
1392                                                 ArtifactResolver artifactResolver,
1393                                                 String scope,
1394                                                 ArtifactFactory artifactFactory,
1395                                                 MavenProject project, boolean isAggregator )
1396         throws ArtifactResolutionException, ArtifactNotFoundException, InvalidDependencyVersionException
1397     {
1398         ArtifactFilter filter = new ScopeArtifactFilter( scope );
1399 
1400         // TODO: such a call in MavenMetadataSource too - packaging not really the intention of type
1401         Artifact artifact = artifactFactory.createBuildArtifact( project.getGroupId(), project.getArtifactId(),
1402                                                                  project.getVersion(), project.getPackaging() );
1403 
1404         // TODO: we don't need to resolve over and over again, as long as we are sure that the parameters are the same
1405         // check this with yourkit as a hot spot.
1406         // Don't recreate if already created - for effeciency, and because clover plugin adds to it
1407         if ( project.getDependencyArtifacts() == null )
1408         {
1409             project.setDependencyArtifacts( project.createArtifacts( artifactFactory, null, null ) );
1410         }
1411         
1412         Set resolvedArtifacts;
1413         try
1414         {
1415             ArtifactResolutionResult result = artifactResolver.resolveTransitively( project.getDependencyArtifacts(),
1416                                                                                 artifact,
1417                                                                                 project.getManagedVersionMap(),
1418                                                                                 context.getLocalRepository(),
1419                                                                                 project.getRemoteArtifactRepositories(),
1420                                                                                 artifactMetadataSource, filter );
1421             resolvedArtifacts = result.getArtifacts();
1422         }
1423         catch (MultipleArtifactsNotFoundException me)
1424         {
1425             /*only do this if we are an aggregating plugin: MNG-2277
1426             if the dependency doesn't yet exist but is in the reactor, then 
1427             all we can do is warn and skip it. A better fix can be inserted into 2.1*/
1428             if (isAggregator && checkMissingArtifactsInReactor( context.getSortedProjects(), me.getMissingArtifacts() ))
1429             {
1430                 resolvedArtifacts = new HashSet(me.getResolvedArtifacts());
1431             }
1432             else
1433             {
1434                 //we can't find all the artifacts in the reactor so bubble the exception up.
1435                 throw me;
1436             }
1437         }
1438         project.setArtifacts( resolvedArtifacts );
1439     }
1440 
1441     /**
1442      * This method is checking to see if the artifacts that can't be resolved are all
1443      * part of this reactor. This is done to prevent a chicken or egg scenario with
1444      * fresh projects that have a plugin that is an aggregator and requires dependencies. See
1445      * MNG-2277 for more info.
1446      * @param projects the sibling projects in the reactor
1447      * @param missing the artifacts that can't be found
1448      * @return true if ALL missing artifacts are found in the reactor.
1449      */
1450     private boolean checkMissingArtifactsInReactor(Collection projects, Collection missing)
1451     {
1452         Collection foundInReactor = new HashSet();
1453         Iterator iter = missing.iterator();
1454         while (iter.hasNext())
1455         {
1456             Artifact mArtifact = (Artifact) iter.next();
1457             Iterator pIter = projects.iterator();
1458             while (pIter.hasNext())
1459             {
1460                 MavenProject p = (MavenProject) pIter.next();
1461                 if (p.getArtifactId().equals( mArtifact.getArtifactId()) &&
1462                     p.getGroupId().equals( mArtifact.getGroupId()) &&
1463                     p.getVersion().equals( mArtifact.getVersion()))
1464                 {
1465                     //TODO: the packaging could be different, but the exception doesn't contain that info
1466                     //most likely it would be produced by the project we just found in the reactor since all
1467                     //the other info matches. Assume it's ok.
1468                     getLogger().warn( "The dependency: "+ p.getId()+" can't be resolved but has been found in the reactor.\nThis dependency has been excluded from the plugin execution. You should rerun this mojo after executing mvn install.\n" );
1469                     
1470                     //found it, move on.
1471                     foundInReactor.add( p );
1472                     break;
1473                 }   
1474             }
1475         }
1476         
1477         //if all of them have been found, we can continue.
1478         return foundInReactor.size() == missing.size();
1479     }
1480     
1481     
1482     // ----------------------------------------------------------------------
1483     // Artifact downloading
1484     // ----------------------------------------------------------------------
1485 
1486     private void downloadDependencies( MavenProject project,
1487                                        MavenSession context,
1488                                        ArtifactResolver artifactResolver )
1489         throws ArtifactResolutionException, ArtifactNotFoundException
1490     {
1491         ArtifactRepository localRepository = context.getLocalRepository();
1492         List remoteArtifactRepositories = project.getRemoteArtifactRepositories();
1493 
1494         for ( Iterator it = project.getArtifacts().iterator(); it.hasNext(); )
1495         {
1496             Artifact artifact = (Artifact) it.next();
1497 
1498             artifactResolver.resolve( artifact, remoteArtifactRepositories, localRepository );
1499         }
1500     }
1501 
1502     public Object getPluginComponent( Plugin plugin,
1503                                       String role,
1504                                       String roleHint )
1505         throws PluginManagerException, ComponentLookupException
1506     {
1507         PluginDescriptor pluginDescriptor = pluginCollector.getPluginDescriptor( plugin );
1508 
1509         PlexusContainer pluginContainer = getPluginContainer( pluginDescriptor );
1510 
1511         return pluginContainer.lookup( role, roleHint );
1512     }
1513 
1514     public Map getPluginComponents( Plugin plugin,
1515                                     String role )
1516         throws ComponentLookupException, PluginManagerException
1517     {
1518         PluginDescriptor pluginDescriptor = pluginCollector.getPluginDescriptor( plugin );
1519 
1520         PlexusContainer pluginContainer = getPluginContainer( pluginDescriptor );
1521 
1522         return pluginContainer.lookupMap( role );
1523     }
1524 }