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