View Javadoc

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