View Javadoc

1   package org.apache.maven.lifecycle;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Stack;
30  import java.util.StringTokenizer;
31  
32  import org.apache.maven.BuildFailureException;
33  import org.apache.maven.ConfigurationInterpolationException;
34  import org.apache.maven.ConfigurationInterpolator;
35  import org.apache.maven.artifact.handler.ArtifactHandler;
36  import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
37  import org.apache.maven.artifact.repository.ArtifactRepository;
38  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
39  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
40  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
41  import org.apache.maven.execution.MavenSession;
42  import org.apache.maven.execution.ReactorManager;
43  import org.apache.maven.extension.ExtensionManager;
44  import org.apache.maven.lifecycle.mapping.LifecycleMapping;
45  import org.apache.maven.model.Extension;
46  import org.apache.maven.model.Plugin;
47  import org.apache.maven.model.PluginExecution;
48  import org.apache.maven.model.ReportPlugin;
49  import org.apache.maven.model.ReportSet;
50  import org.apache.maven.monitor.event.EventDispatcher;
51  import org.apache.maven.monitor.event.MavenEvents;
52  import org.apache.maven.plugin.InvalidPluginException;
53  import org.apache.maven.plugin.MojoExecution;
54  import org.apache.maven.plugin.MojoExecutionException;
55  import org.apache.maven.plugin.MojoFailureException;
56  import org.apache.maven.plugin.PluginConfigurationException;
57  import org.apache.maven.plugin.PluginManager;
58  import org.apache.maven.plugin.PluginManagerException;
59  import org.apache.maven.plugin.PluginNotFoundException;
60  import org.apache.maven.plugin.descriptor.MojoDescriptor;
61  import org.apache.maven.plugin.descriptor.PluginDescriptor;
62  import org.apache.maven.plugin.lifecycle.Execution;
63  import org.apache.maven.plugin.lifecycle.Phase;
64  import org.apache.maven.plugin.version.PluginVersionNotFoundException;
65  import org.apache.maven.plugin.version.PluginVersionResolutionException;
66  import org.apache.maven.project.MavenProject;
67  import org.apache.maven.project.MavenProjectBuilder;
68  import org.apache.maven.project.artifact.InvalidDependencyVersionException;
69  import org.apache.maven.project.interpolation.ModelInterpolationException;
70  import org.apache.maven.project.interpolation.ModelInterpolator;
71  import org.apache.maven.reporting.MavenReport;
72  import org.apache.maven.settings.Settings;
73  import org.codehaus.plexus.PlexusConstants;
74  import org.codehaus.plexus.PlexusContainer;
75  import org.codehaus.plexus.PlexusContainerException;
76  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
77  import org.codehaus.plexus.configuration.PlexusConfiguration;
78  import org.codehaus.plexus.context.Context;
79  import org.codehaus.plexus.context.ContextException;
80  import org.codehaus.plexus.logging.AbstractLogEnabled;
81  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
82  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
83  import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
84  import org.codehaus.plexus.util.StringUtils;
85  import org.codehaus.plexus.util.xml.Xpp3Dom;
86  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
87  
88  /**
89   * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
90   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
91   * @version $Id: DefaultLifecycleExecutor.java 752168 2009-03-10 17:22:20Z jdcasey $
92   * @todo because of aggregation, we ended up with cli-ish stuff in here (like line() and the project logging, without much of the event handling)
93   */
94  public class DefaultLifecycleExecutor
95      extends AbstractLogEnabled
96      implements LifecycleExecutor, Initializable, Contextualizable
97  {
98      // ----------------------------------------------------------------------
99      // Components
100     // ----------------------------------------------------------------------
101 
102     private PluginManager pluginManager;
103 
104     private ExtensionManager extensionManager;
105 
106     private List lifecycles;
107 
108     private ArtifactHandlerManager artifactHandlerManager;
109 
110     private List defaultReports;
111 
112     private Map phaseToLifecycleMap;
113 
114     private MavenProjectBuilder mavenProjectBuilder;
115 
116     private ModelInterpolator modelInterpolator;
117     
118     private ConfigurationInterpolator configInterpolator;
119 
120     // ----------------------------------------------------------------------
121     //
122     // ----------------------------------------------------------------------
123 
124     /**
125      * Execute a task. Each task may be a phase in the lifecycle or the
126      * execution of a mojo.
127      *
128      * @param session
129      * @param rm
130      * @param dispatcher
131      */
132     public void execute( MavenSession session, ReactorManager rm, EventDispatcher dispatcher )
133         throws BuildFailureException, LifecycleExecutionException
134     {
135         // TODO: This is dangerous, particularly when it's just a collection of loose-leaf projects being built
136         // within the same reactor (using an inclusion pattern to gather them up)...
137         MavenProject rootProject = rm.getTopLevelProject();
138 
139         List goals = session.getGoals();
140 
141         if ( goals.isEmpty() && rootProject != null )
142         {
143             String goal = rootProject.getDefaultGoal();
144 
145             if ( goal != null )
146             {
147                 goals = Collections.singletonList( goal );
148             }
149         }
150 
151         if ( goals.isEmpty() )
152         {
153             StringBuffer buffer = new StringBuffer( 1024 );
154 
155             buffer.append( "\n\n" );
156             buffer.append( "You must specify at least one goal or lifecycle phase to perform build steps.\n" );
157             buffer.append( "The following list illustrates some commonly used build commands:\n\n" );
158             buffer.append( "  mvn clean\n" );
159             buffer.append( "    Deletes any build output (e.g. class files or JARs).\n" );
160             buffer.append( "  mvn test\n" );
161             buffer.append( "    Runs the unit tests for the project.\n" );
162             buffer.append( "  mvn install\n" );
163             buffer.append( "    Copies the project artifacts into your local repository.\n" );
164             buffer.append( "  mvn deploy\n" );
165             buffer.append( "    Copies the project artifacts into the remote repository.\n" );
166             buffer.append( "  mvn site\n" );
167             buffer.append( "    Creates project documentation (e.g. reports or Javadoc).\n\n" );
168             buffer.append( "Please see\n" );
169             buffer.append( "http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html\n" );
170             buffer.append( "for a complete description of available lifecycle phases.\n\n" );
171             buffer.append( "Use \"mvn --help\" to show general usage information about Maven's command line.\n\n" );
172 
173             throw new BuildFailureException( buffer.toString() );
174         }
175 
176         List taskSegments = segmentTaskListByAggregationNeeds( goals, session, rootProject );
177 
178         // TODO: probably don't want to do all this up front
179         findExtensions( session );
180 
181         executeTaskSegments( taskSegments, rm, session, rootProject, dispatcher );
182     }
183 
184     private void findExtensions( MavenSession session )
185         throws LifecycleExecutionException
186     {
187         // TODO: MNG-4081. What about extensions within the current reactor??
188         for ( Iterator i = session.getSortedProjects().iterator(); i.hasNext(); )
189         {
190             MavenProject project = (MavenProject) i.next();
191 
192             for ( Iterator j = project.getBuildExtensions().iterator(); j.hasNext(); )
193             {
194                 Extension extension = (Extension) j.next();
195                 try
196                 {
197                     getLogger().debug( "Adding extension: " + extension );
198                     extensionManager.addExtension( extension, project, session.getLocalRepository() );
199                 }
200                 catch ( PlexusContainerException e )
201                 {
202                     throw new LifecycleExecutionException( "Unable to initialise extensions", e );
203                 }
204                 catch ( ArtifactResolutionException e )
205                 {
206                     throw new LifecycleExecutionException( e.getMessage(), e );
207                 }
208                 catch ( ArtifactNotFoundException e )
209                 {
210                     throw new LifecycleExecutionException( e.getMessage(), e );
211                 }
212             }
213 
214             extensionManager.registerWagons();
215 
216             try
217             {
218                 Map handlers = findArtifactTypeHandlers( project, session.getSettings(), session.getLocalRepository() );
219 
220                 artifactHandlerManager.addHandlers( handlers );
221             }
222             catch ( PluginNotFoundException e )
223             {
224                 throw new LifecycleExecutionException( e.getMessage(), e );
225             }
226         }
227     }
228 
229     private void executeTaskSegments( List taskSegments, ReactorManager rm, MavenSession session,
230                                       MavenProject rootProject, EventDispatcher dispatcher )
231         throws LifecycleExecutionException, BuildFailureException
232     {
233         for ( Iterator it = taskSegments.iterator(); it.hasNext(); )
234         {
235             TaskSegment segment = (TaskSegment) it.next();
236 
237             if ( segment.aggregate() )
238             {
239                 if ( !rm.isBlackListed( rootProject ) )
240                 {
241                     line();
242 
243                     getLogger().info( "Building " + rootProject.getName() );
244 
245                     getLogger().info( "  " + segment );
246 
247                     line();
248 
249                     // !! This is ripe for refactoring to an aspect.
250                     // Event monitoring.
251                     String event = MavenEvents.PROJECT_EXECUTION;
252 
253                     long buildStartTime = System.currentTimeMillis();
254 
255                     String target = rootProject.getId() + " ( " + segment + " )";
256 
257                     dispatcher.dispatchStart( event, target );
258 
259                     try
260                     {
261                         session.setCurrentProject( rootProject );
262 
263                         // only call once, with the top-level project (assumed to be provided as a parameter)...
264                         for ( Iterator goalIterator = segment.getTasks().iterator(); goalIterator.hasNext(); )
265                         {
266                             String task = (String) goalIterator.next();
267 
268                             executeGoalAndHandleFailures( task, session, rootProject, dispatcher, event, rm, buildStartTime,
269                                                           target );
270                         }
271 
272                         rm.registerBuildSuccess( rootProject, System.currentTimeMillis() - buildStartTime );
273 
274                     }
275                     finally
276                     {
277                         session.setCurrentProject( null );
278                     }
279 
280                     dispatcher.dispatchEnd( event, target );
281                 }
282                 else
283                 {
284                     line();
285 
286                     getLogger().info( "SKIPPING " + rootProject.getName() );
287 
288                     getLogger().info( "  " + segment );
289 
290                     getLogger().info(
291                         "This project has been banned from further executions due to previous failures." );
292 
293                     line();
294                 }
295             }
296             else
297             {
298                 List sortedProjects = session.getSortedProjects();
299 
300                 // iterate over projects, and execute on each...
301                 for ( Iterator projectIterator = sortedProjects.iterator(); projectIterator.hasNext(); )
302                 {
303                     MavenProject currentProject = (MavenProject) projectIterator.next();
304 
305                     if ( !rm.isBlackListed( currentProject ) )
306                     {
307                         line();
308 
309                         getLogger().info( "Building " + currentProject.getName() );
310 
311                         getLogger().info( "  " + segment );
312 
313                         line();
314 
315                         // !! This is ripe for refactoring to an aspect.
316                         // Event monitoring.
317                         String event = MavenEvents.PROJECT_EXECUTION;
318 
319                         long buildStartTime = System.currentTimeMillis();
320 
321                         String target = currentProject.getId() + " ( " + segment + " )";
322                         dispatcher.dispatchStart( event, target );
323 
324                         try
325                         {
326                             session.setCurrentProject( currentProject );
327 
328                             for ( Iterator goalIterator = segment.getTasks().iterator(); goalIterator.hasNext(); )
329                             {
330                                 String task = (String) goalIterator.next();
331 
332                                 executeGoalAndHandleFailures( task, session, currentProject, dispatcher, event, rm,
333                                                               buildStartTime, target );
334                             }
335 
336                         }
337                         finally
338                         {
339                             session.setCurrentProject( null );
340                         }
341 
342                         rm.registerBuildSuccess( currentProject, System.currentTimeMillis() - buildStartTime );
343 
344                         dispatcher.dispatchEnd( event, target );
345                     }
346                     else
347                     {
348                         line();
349 
350                         getLogger().info( "SKIPPING " + currentProject.getName() );
351 
352                         getLogger().info( "  " + segment );
353 
354                         getLogger().info(
355                             "This project has been banned from further executions due to previous failures." );
356 
357                         line();
358                     }
359                 }
360             }
361         }
362     }
363 
364     private void executeGoalAndHandleFailures( String task, MavenSession session, MavenProject project,
365                                                EventDispatcher dispatcher, String event, ReactorManager rm,
366                                                long buildStartTime, String target )
367         throws BuildFailureException, LifecycleExecutionException
368     {
369         try
370         {
371             executeGoal( task, session, project );
372         }
373         catch ( LifecycleExecutionException e )
374         {
375             dispatcher.dispatchError( event, target, e );
376 
377             if ( handleExecutionFailure( rm, project, e, task, buildStartTime ) )
378             {
379                 throw e;
380             }
381         }
382         catch ( BuildFailureException e )
383         {
384             dispatcher.dispatchError( event, target, e );
385 
386             if ( handleExecutionFailure( rm, project, e, task, buildStartTime ) )
387             {
388                 throw e;
389             }
390         }
391     }
392 
393     private boolean handleExecutionFailure( ReactorManager rm, MavenProject project, Exception e, String task,
394                                             long buildStartTime )
395     {
396         rm.registerBuildFailure( project, e, task, System.currentTimeMillis() - buildStartTime );
397 
398         if ( ReactorManager.FAIL_FAST.equals( rm.getFailureBehavior() ) )
399         {
400             return true;
401         }
402         else if ( ReactorManager.FAIL_AT_END.equals( rm.getFailureBehavior() ) )
403         {
404             rm.blackList( project );
405         }
406         // if NEVER, don't blacklist
407         return false;
408     }
409 
410     private List segmentTaskListByAggregationNeeds( List tasks, MavenSession session, MavenProject project )
411         throws LifecycleExecutionException, BuildFailureException
412     {
413         List segments = new ArrayList();
414 
415         if ( project != null )
416         {
417 
418             TaskSegment currentSegment = null;
419             for ( Iterator it = tasks.iterator(); it.hasNext(); )
420             {
421                 String task = (String) it.next();
422 
423                 // if it's a phase, then we don't need to check whether it's an aggregator.
424                 // simply add it to the current task partition.
425                 if ( getPhaseToLifecycleMap().containsKey( task ) )
426                 {
427                     if ( currentSegment != null && currentSegment.aggregate() )
428                     {
429                         segments.add( currentSegment );
430                         currentSegment = null;
431                     }
432 
433                     if ( currentSegment == null )
434                     {
435                         currentSegment = new TaskSegment();
436                     }
437 
438                     currentSegment.add( task );
439                 }
440                 else
441                 {
442                     MojoDescriptor mojo = null;
443                     try
444                     {
445                         // definitely a CLI goal, can use prefix
446                         mojo = getMojoDescriptor( task, session, project, task, true, false );
447                     }
448                     catch ( PluginNotFoundException e )
449                     {
450                         // TODO: shouldn't hit this, investigate using the same resolution logic as otheres for plugins in the reactor
451                         getLogger().info(
452                             "Cannot find mojo descriptor for: \'" + task + "\' - Treating as non-aggregator." );
453                         getLogger().debug( "", e );
454                     }
455 
456                     // if the mojo descriptor was found, determine aggregator status according to:
457                     // 1. whether the mojo declares itself an aggregator
458                     // 2. whether the mojo DOES NOT require a project to function (implicitly avoid reactor)
459                     if ( mojo != null && ( mojo.isAggregator() || !mojo.isProjectRequired() ) )
460                     {
461                         if ( currentSegment != null && !currentSegment.aggregate() )
462                         {
463                             segments.add( currentSegment );
464                             currentSegment = null;
465                         }
466 
467                         if ( currentSegment == null )
468                         {
469                             currentSegment = new TaskSegment( true );
470                         }
471 
472                         currentSegment.add( task );
473                     }
474                     else
475                     {
476                         if ( currentSegment != null && currentSegment.aggregate() )
477                         {
478                             segments.add( currentSegment );
479                             currentSegment = null;
480                         }
481 
482                         if ( currentSegment == null )
483                         {
484                             currentSegment = new TaskSegment();
485                         }
486 
487                         currentSegment.add( task );
488                     }
489                 }
490             }
491 
492             segments.add( currentSegment );
493         }
494         else
495         {
496             TaskSegment segment = new TaskSegment( false );
497             for ( Iterator i = tasks.iterator(); i.hasNext(); )
498             {
499                 segment.add( (String) i.next() );
500             }
501             segments.add( segment );
502         }
503 
504         return segments;
505     }
506 
507     private void executeGoal( String task, MavenSession session, MavenProject project )
508         throws LifecycleExecutionException, BuildFailureException
509     {
510         try
511         {
512             Stack forkEntryPoints = new Stack();
513             if ( getPhaseToLifecycleMap().containsKey( task ) )
514             {
515                 Lifecycle lifecycle = getLifecycleForPhase( task );
516 
517                 // we have a lifecycle phase, so lets bind all the necessary goals
518                 Map lifecycleMappings = constructLifecycleMappings( session, task, project, lifecycle );
519                 executeGoalWithLifecycle( task, forkEntryPoints, session, lifecycleMappings, project, lifecycle );
520             }
521             else
522             {
523                 executeStandaloneGoal( task, forkEntryPoints, session, project );
524             }
525         }
526         catch ( PluginNotFoundException e )
527         {
528             throw new BuildFailureException( "A required plugin was not found: " + e.getMessage(), e );
529         }
530     }
531 
532     private void executeGoalWithLifecycle( String task, Stack forkEntryPoints, MavenSession session,
533                                            Map lifecycleMappings, MavenProject project, Lifecycle lifecycle )
534         throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException
535     {
536         List goals = processGoalChain( task, lifecycleMappings, lifecycle );
537 
538         if ( !goals.isEmpty() )
539         {
540             executeGoals( goals, forkEntryPoints, session, project );
541         }
542         else
543         {
544             getLogger().info( "No goals needed for project - skipping" );
545         }
546     }
547 
548     private void executeStandaloneGoal( String task, Stack forkEntryPoints, MavenSession session, MavenProject project )
549         throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException
550     {
551         // guaranteed to come from the CLI and not be part of a phase
552         MojoDescriptor mojoDescriptor = getMojoDescriptor( task, session, project, task, true, false );
553         executeGoals( Collections.singletonList( new MojoExecution( mojoDescriptor ) ), forkEntryPoints, session,
554                       project );
555     }
556 
557     private void executeGoals( List goals, Stack forkEntryPoints, MavenSession session, MavenProject project )
558         throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException
559     {
560         for ( Iterator i = goals.iterator(); i.hasNext(); )
561         {
562             MojoExecution mojoExecution = (MojoExecution) i.next();
563 
564             MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
565             
566             PlexusConfiguration configuration = mojoDescriptor.getMojoConfiguration();
567             boolean usesReactorProjects = mojoDescriptor.isAggregator() || usesSessionOrReactorProjects( configuration );
568             
569             if ( usesReactorProjects )
570             {
571                 calculateAllConcreteStates( session );
572             }
573             else
574             {
575                 calculateConcreteState( project, session, true );
576             }
577             
578             calculateConcreteConfiguration( mojoExecution, project, session );
579             
580             List reportExecutions = null;
581             if ( mojoDescriptor.isRequiresReports() )
582             {
583                 reportExecutions = getReportExecutions( project, forkEntryPoints, mojoExecution, session );
584             }
585             
586             boolean hasFork = false;
587             if ( mojoDescriptor.getExecutePhase() != null || mojoDescriptor.getExecuteGoal() != null )
588             {
589                 hasFork = true;
590             }
591             else if ( reportExecutions != null )
592             {
593                 for ( Iterator it = reportExecutions.iterator(); it.hasNext(); )
594                 {
595                     MojoExecution reportExecution = (MojoExecution) it.next();
596                     MojoDescriptor reportDescriptor = reportExecution.getMojoDescriptor();
597                     if ( reportDescriptor.getExecutePhase() != null || reportDescriptor.getExecuteGoal() != null )
598                     {
599                         hasFork = true;
600                     }
601                 }
602             }
603             
604             if ( hasFork )
605             {
606                 // NOTE: This must always happen, regardless of treatment of reactorProjects below, because
607                 // if we're in a forked execution right now, the current project will itself be an execution project of
608                 // something in the reactorProjects list, and won't have a next-stage executionProject created
609                 // for it otherwise, which leaves the project == null for the upcoming forked execution.
610                 createExecutionProject( project, session, true );
611                 
612                 if ( usesReactorProjects )
613                 {
614                     List reactorProjects = session.getSortedProjects();
615                     for ( Iterator it = reactorProjects.iterator(); it.hasNext(); )
616                     {
617                         MavenProject reactorProject = (MavenProject) it.next();
618                         createExecutionProject( reactorProject, session, false );
619                     }
620                 }
621             }
622 
623             if ( mojoDescriptor.getExecutePhase() != null || mojoDescriptor.getExecuteGoal() != null )
624             {
625                 forkEntryPoints.push( mojoDescriptor );
626 
627                 forkLifecycle( mojoDescriptor, forkEntryPoints, session, project );
628 
629                 forkEntryPoints.pop();
630             }
631             
632             if ( mojoDescriptor.isRequiresReports() )
633             {
634                 List reports = getReports( reportExecutions, project, mojoExecution, session );
635 
636                 mojoExecution.setReports( reports );
637 
638                 for ( Iterator j = mojoExecution.getForkedExecutions().iterator(); j.hasNext(); )
639                 {
640                     MojoExecution forkedExecution = (MojoExecution) j.next();
641                     MojoDescriptor descriptor = forkedExecution.getMojoDescriptor();
642 
643                     if ( descriptor.getExecutePhase() != null )
644                     {
645                         forkEntryPoints.push( descriptor );
646 
647                         forkLifecycle( descriptor, forkEntryPoints, session, project );
648 
649                         forkEntryPoints.pop();
650                     }
651                 }
652             }
653             
654             if ( hasFork )
655             {
656                 // NOTE: This must always happen, regardless of treatment of reactorProjects below, because
657                 // if we're in a forked execution right now, the current project will itself be an execution project of
658                 // something in the reactorProjects list, and may not have had its own executionProject instance reset to 
659                 // a concrete state again after the previous forked executions.
660                 calculateConcreteState( project.getExecutionProject(), session, true );
661                 
662                 // FIXME: Would be nice to find a way to cause the execution project to stay in a concrete state...
663                 // TODO: Test this! It should be fixed, but I don't want to destabilize until I have the issue I'm working on fixed.
664                 if ( usesReactorProjects )
665                 {
666                     calculateAllConcreteStates( session );
667                     List reactorProjects = session.getSortedProjects();
668                     for ( Iterator it = reactorProjects.iterator(); it.hasNext(); )
669                     {
670                         MavenProject reactorProject = (MavenProject) it.next();
671                         calculateConcreteState( reactorProject.getExecutionProject(), session, false );
672                     }
673                 }
674             }
675 
676             try
677             {
678                 pluginManager.executeMojo( project, mojoExecution, session );
679             }
680             catch ( PluginManagerException e )
681             {
682                 throw new LifecycleExecutionException( "Internal error in the plugin manager executing goal '" +
683                     mojoDescriptor.getId() + "': " + e.getMessage(), e );
684             }
685             catch ( ArtifactNotFoundException e )
686             {
687                 throw new LifecycleExecutionException( e.getMessage(), e );
688             }
689             catch ( InvalidDependencyVersionException e )
690             {
691                 throw new LifecycleExecutionException( e.getMessage(), e );
692             }
693             catch ( ArtifactResolutionException e )
694             {
695                 throw new LifecycleExecutionException( e.getMessage(), e );
696             }
697             catch ( MojoFailureException e )
698             {
699                 throw new BuildFailureException( e.getMessage(), e );
700             }
701             catch ( MojoExecutionException e )
702             {
703                 throw new LifecycleExecutionException( e.getMessage(), e );
704             }
705             catch ( PluginConfigurationException e )
706             {
707                 throw new LifecycleExecutionException( e.getMessage(), e );
708             }
709         }
710     }
711     
712     private void createExecutionProject( MavenProject project, MavenSession session, boolean processProjectReferences )
713         throws LifecycleExecutionException
714     {
715         MavenProject executionProject = new MavenProject( project );
716         
717         calculateConcreteState( executionProject, session, processProjectReferences );
718         
719         project.setExecutionProject( executionProject );
720     }
721 
722     private boolean usesSessionOrReactorProjects( PlexusConfiguration configuration )
723     {
724         String value = configuration != null ? String.valueOf( configuration ) : null;
725         
726         if ( value != null )
727         {
728             if ( value.indexOf( "${session" ) > -1 || value.indexOf( "${reactorProjects}" ) > -1 )
729             {
730                 return true;
731             }
732         }
733         
734         return false;
735     }
736 
737     private void calculateConcreteConfiguration( MojoExecution mojoExecution, MavenProject project, MavenSession session )
738         throws LifecycleExecutionException
739     {
740         if ( mojoExecution.getConfiguration() == null )
741         {
742             return;
743         }
744         
745         try
746         {
747             mojoExecution.setConfiguration( (Xpp3Dom) configInterpolator.interpolate(
748                                                                                       mojoExecution.getConfiguration(),
749                                                                                       project,
750                                                                                       session.getProjectBuilderConfiguration() ) );
751         }
752         catch ( ConfigurationInterpolationException e )
753         {
754             throw new LifecycleExecutionException( "Error interpolating configuration for: '" + mojoExecution.getMojoDescriptor().getRoleHint() +
755                                                    "' (execution: '" + mojoExecution.getExecutionId() + "')", e );
756         }
757     }
758     
759     private void calculateAllConcreteStates( MavenSession session )
760         throws LifecycleExecutionException
761     {
762         List projects = session.getSortedProjects();
763         if ( projects != null )
764         {
765             for ( Iterator it = projects.iterator(); it.hasNext(); )
766             {
767                 calculateConcreteState( (MavenProject) it.next(), session, false );
768             }
769         }
770     }
771 
772     private void calculateConcreteState( MavenProject project, MavenSession session, boolean processReferences )
773         throws LifecycleExecutionException
774     {
775         if ( mavenProjectBuilder != null && project != null )
776         {
777             try
778             {
779                 mavenProjectBuilder.calculateConcreteState( project, session.getProjectBuilderConfiguration(), processReferences );
780             }
781             catch ( ModelInterpolationException e )
782             {
783                 throw new LifecycleExecutionException( "Failed to calculate concrete state for project: " + project,
784                                                          e );
785             }
786         }
787     }
788     
789 //    private void restoreAllDynamicStates( MavenSession session )
790 //        throws LifecycleExecutionException
791 //    {
792 //        List reactorProjects = session.getSortedProjects();
793 //        if ( reactorProjects != null )
794 //        {
795 //            for ( Iterator it = reactorProjects.iterator(); it.hasNext(); )
796 //            {
797 //                MavenProject project = (MavenProject) it.next();
798 //                restoreDynamicState( project, session, false );
799 //            }
800 //        }
801 //    }
802 //
803 //    private void restoreDynamicState( MavenProject project, MavenSession session, boolean processReferences )
804 //        throws LifecycleExecutionException
805 //    {
806 //        try
807 //        {
808 //            mavenProjectBuilder.restoreDynamicState( project, session.getProjectBuilderConfiguration(), processReferences );
809 //        }
810 //        catch ( ModelInterpolationException e )
811 //        {
812 //            throw new LifecycleExecutionException( "Failed to restore dynamic state for project: " + project, e );
813 //        }
814 //    }
815 
816     private List getReportExecutions( MavenProject project, Stack forkEntryPoints, MojoExecution mojoExecution, MavenSession session )
817         throws LifecycleExecutionException, PluginNotFoundException
818     {
819         List reportPlugins = project.getReportPlugins();
820 
821         if ( project.getModel().getReports() != null )
822         {
823             getLogger().error(
824                 "Plugin contains a <reports/> section: this is IGNORED - please use <reporting/> instead." );
825         }
826 
827         if ( project.getReporting() == null || !project.getReporting().isExcludeDefaults() )
828         {
829             if ( reportPlugins == null )
830             {
831                 reportPlugins = new ArrayList();
832             }
833             else
834             {
835                 reportPlugins = new ArrayList( reportPlugins );
836             }
837 
838             for ( Iterator i = defaultReports.iterator(); i.hasNext(); )
839             {
840                 String report = (String) i.next();
841 
842                 StringTokenizer tok = new StringTokenizer( report, ":" );
843                 int count = tok.countTokens();
844                 if ( count != 2 && count != 3 )
845                 {
846                     getLogger().warn( "Invalid default report ignored: '" + report + "' (must be groupId:artifactId[:version])" );
847                 }
848                 else
849                 {
850                     String groupId = tok.nextToken();
851                     String artifactId = tok.nextToken();
852                     String version = tok.hasMoreTokens() ? tok.nextToken() : null;
853 
854                     boolean found = false;
855                     for ( Iterator j = reportPlugins.iterator(); j.hasNext() && !found; )
856                     {
857                         ReportPlugin reportPlugin = (ReportPlugin) j.next();
858                         if ( reportPlugin.getGroupId().equals( groupId ) &&
859                             reportPlugin.getArtifactId().equals( artifactId ) )
860                         {
861                             found = true;
862                         }
863                     }
864 
865                     if ( !found )
866                     {
867                         ReportPlugin reportPlugin = new ReportPlugin();
868                         reportPlugin.setGroupId( groupId );
869                         reportPlugin.setArtifactId( artifactId );
870                         reportPlugin.setVersion( version );
871                         reportPlugins.add( reportPlugin );
872                     }
873                 }
874             }
875         }
876 
877         List reports = new ArrayList();
878         if ( reportPlugins != null )
879         {
880             for ( Iterator it = reportPlugins.iterator(); it.hasNext(); )
881             {
882                 ReportPlugin reportPlugin = (ReportPlugin) it.next();
883 
884                 List reportSets = reportPlugin.getReportSets();
885 
886                 if ( reportSets == null || reportSets.isEmpty() )
887                 {
888                     reports.addAll( getReportExecutions( reportPlugin, forkEntryPoints, null, project, session, mojoExecution ) );
889                 }
890                 else
891                 {
892                     for ( Iterator j = reportSets.iterator(); j.hasNext(); )
893                     {
894                         ReportSet reportSet = (ReportSet) j.next();
895 
896                         reports.addAll( getReportExecutions( reportPlugin, forkEntryPoints, reportSet, project, session, mojoExecution ) );
897                     }
898                 }
899             }
900         }
901         return reports;
902     }
903     
904     private List getReportExecutions( ReportPlugin reportPlugin,
905                              Stack forkEntryPoints,
906                              ReportSet reportSet,
907                              MavenProject project,
908                              MavenSession session,
909                              MojoExecution mojoExecution )
910         throws LifecycleExecutionException, PluginNotFoundException
911     {
912         PluginDescriptor pluginDescriptor = verifyReportPlugin( reportPlugin, project, session );
913 
914         List reports = new ArrayList();
915         for ( Iterator i = pluginDescriptor.getMojos().iterator(); i.hasNext(); )
916         {
917             MojoDescriptor mojoDescriptor = (MojoDescriptor) i.next();
918             if ( forkEntryPoints.contains( mojoDescriptor ) )
919             {
920                 getLogger().debug( "Omitting report: " + mojoDescriptor.getFullGoalName() + " from reports list. It initiated part of the fork currently executing." );
921                 continue;
922             }
923 
924             // TODO: check ID is correct for reports
925             // if the POM configured no reports, give all from plugin
926             if ( reportSet == null || reportSet.getReports().contains( mojoDescriptor.getGoal() ) )
927             {
928                 String id = null;
929                 if ( reportSet != null )
930                 {
931                     id = reportSet.getId();
932                 }
933 
934                 MojoExecution reportExecution = new MojoExecution( mojoDescriptor, id );
935                 reports.add( reportExecution );
936             }
937         }
938         return reports;
939     }
940 
941     private List getReports( List reportExecutions, MavenProject project, MojoExecution mojoExecution, MavenSession session )
942         throws LifecycleExecutionException
943     {
944         List reports = new ArrayList();
945         
946         for ( Iterator it = reportExecutions.iterator(); it.hasNext(); )
947         {
948             MojoExecution reportExecution = (MojoExecution) it.next();
949             PluginDescriptor pluginDescriptor = reportExecution.getMojoDescriptor().getPluginDescriptor();
950             
951             try
952             {
953                 MavenReport reportMojo = pluginManager.getReport( project, reportExecution, session );
954 
955                 // Comes back null if it was a plugin, not a report - these are mojos in the reporting plugins that are not reports
956                 if ( reportMojo != null )
957                 {
958                     reports.add( reportMojo );
959                     mojoExecution.addMojoExecution( reportExecution );
960                 }
961             }
962             catch ( PluginManagerException e )
963             {
964                 throw new LifecycleExecutionException(
965                     "Error getting reports from the plugin '" + pluginDescriptor.getId() + "': " + e.getMessage(), e );
966             }
967             catch ( PluginConfigurationException e )
968             {
969                 throw new LifecycleExecutionException(
970                     "Error getting reports from the plugin '" + pluginDescriptor.getId() + "'", e );
971             }
972             catch ( ArtifactNotFoundException e )
973             {
974                 throw new LifecycleExecutionException( e.getMessage(), e );
975             }
976             catch ( ArtifactResolutionException e )
977             {
978                 throw new LifecycleExecutionException( e.getMessage(), e );
979             }
980         }
981         
982         return reports;
983     }
984 
985     private void forkLifecycle( MojoDescriptor mojoDescriptor, Stack ancestorLifecycleForkers, MavenSession session,
986                                 MavenProject project )
987         throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException
988     {
989         PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
990         getLogger().info( "Preparing " + pluginDescriptor.getGoalPrefix() + ":" + mojoDescriptor.getGoal() );
991 
992         if ( mojoDescriptor.isAggregator() )
993         {
994             for ( Iterator i = session.getSortedProjects().iterator(); i.hasNext(); )
995             {
996                 MavenProject reactorProject = (MavenProject) i.next();
997                 
998                 line();
999 
1000                 getLogger().info( "Building " + reactorProject.getName() );
1001 
1002                 line();
1003 
1004                 forkProjectLifecycle( mojoDescriptor, ancestorLifecycleForkers, session, reactorProject );
1005             }
1006         }
1007         else
1008         {
1009             forkProjectLifecycle( mojoDescriptor, ancestorLifecycleForkers, session, project );
1010         }
1011     }
1012 
1013     private void forkProjectLifecycle( MojoDescriptor mojoDescriptor, Stack forkEntryPoints, MavenSession session,
1014                                        MavenProject project )
1015         throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException
1016     {
1017         project = project.getExecutionProject();
1018         
1019         forkEntryPoints.push( mojoDescriptor );
1020 
1021         PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
1022 
1023         String targetPhase = mojoDescriptor.getExecutePhase();
1024 
1025         Map lifecycleMappings = null;
1026         if ( targetPhase != null )
1027         {
1028             Lifecycle lifecycle = getLifecycleForPhase( targetPhase );
1029 
1030             // Create new lifecycle
1031             lifecycleMappings = constructLifecycleMappings( session, targetPhase, project, lifecycle );
1032 
1033             String executeLifecycle = mojoDescriptor.getExecuteLifecycle();
1034             if ( executeLifecycle != null )
1035             {
1036                 org.apache.maven.plugin.lifecycle.Lifecycle lifecycleOverlay;
1037                 try
1038                 {
1039                     lifecycleOverlay = pluginDescriptor.getLifecycleMapping( executeLifecycle );
1040                 }
1041                 catch ( IOException e )
1042                 {
1043                     throw new LifecycleExecutionException( "Unable to read lifecycle mapping file: " + e.getMessage(),
1044                                                            e );
1045                 }
1046                 catch ( XmlPullParserException e )
1047                 {
1048                     throw new LifecycleExecutionException( "Unable to parse lifecycle mapping file: " + e.getMessage(),
1049                                                            e );
1050                 }
1051 
1052                 if ( lifecycleOverlay == null )
1053                 {
1054                     throw new LifecycleExecutionException( "Lifecycle '" + executeLifecycle + "' not found in plugin" );
1055                 }
1056 
1057                 for ( Iterator i = lifecycleOverlay.getPhases().iterator(); i.hasNext(); )
1058                 {
1059                     Phase phase = (Phase) i.next();
1060                     for ( Iterator j = phase.getExecutions().iterator(); j.hasNext(); )
1061                     {
1062                         Execution exec = (Execution) j.next();
1063 
1064                         for ( Iterator k = exec.getGoals().iterator(); k.hasNext(); )
1065                         {
1066                             String goal = (String) k.next();
1067 
1068                             PluginDescriptor lifecyclePluginDescriptor;
1069                             String lifecycleGoal;
1070 
1071                             // Here we are looking to see if we have a mojo from an external plugin.
1072                             // If we do then we need to lookup the plugin descriptor for the externally
1073                             // referenced plugin so that we can overly the execution into the lifecycle.
1074                             // An example of this is the corbertura plugin that needs to call the surefire
1075                             // plugin in forking mode.
1076                             //
1077                             //<phase>
1078                             //  <id>test</id>
1079                             //  <executions>
1080                             //    <execution>
1081                             //      <goals>
1082                             //        <goal>org.apache.maven.plugins:maven-surefire-plugin:test</goal>
1083                             //      </goals>
1084                             //      <configuration>
1085                             //        <classesDirectory>${project.build.directory}/generated-classes/cobertura</classesDirectory>
1086                             //        <ignoreFailures>true</ignoreFailures>
1087                             //        <forkMode>once</forkMode>
1088                             //      </configuration>
1089                             //    </execution>
1090                             //  </executions>
1091                             //</phase>
1092 
1093                             // ----------------------------------------------------------------------
1094                             //
1095                             // ----------------------------------------------------------------------
1096 
1097                             if ( goal.indexOf( ":" ) > 0 )
1098                             {
1099                                 String[] s = StringUtils.split( goal, ":" );
1100 
1101                                 String groupId = s[0];
1102                                 String artifactId = s[1];
1103                                 lifecycleGoal = s[2];
1104 
1105                                 Plugin plugin = new Plugin();
1106                                 plugin.setGroupId( groupId );
1107                                 plugin.setArtifactId( artifactId );
1108                                 lifecyclePluginDescriptor = verifyPlugin( plugin, project, session.getSettings(),
1109                                                                           session.getLocalRepository() );
1110                                 if ( lifecyclePluginDescriptor == null )
1111                                 {
1112                                     throw new LifecycleExecutionException(
1113                                         "Unable to find plugin " + groupId + ":" + artifactId );
1114                                 }
1115                             }
1116                             else
1117                             {
1118                                 lifecyclePluginDescriptor = pluginDescriptor;
1119                                 lifecycleGoal = goal;
1120                             }
1121 
1122                             Xpp3Dom configuration = (Xpp3Dom) exec.getConfiguration();
1123                             // NOTE: This seems to be duplicated below. Why??
1124                             if ( phase.getConfiguration() != null )
1125                             {
1126                                 configuration = Xpp3Dom.mergeXpp3Dom( new Xpp3Dom( (Xpp3Dom) phase.getConfiguration() ),
1127                                                                       configuration );
1128                             }
1129 
1130                             MojoDescriptor desc = getMojoDescriptor( lifecyclePluginDescriptor, lifecycleGoal );
1131                             MojoExecution mojoExecution = new MojoExecution( desc, configuration );
1132                             addToLifecycleMappings( lifecycleMappings, phase.getId(), mojoExecution,
1133                                                     session.getSettings() );
1134                         }
1135                     }
1136 
1137                     if ( phase.getConfiguration() != null )
1138                     {
1139                         // Merge in general configuration for a phase.
1140                         // TODO: this is all kind of backwards from the POMM. Let's align it all under 2.1.
1141                         //   We should create a new lifecycle executor for modelVersion >5.0.0
1142                         for ( Iterator j = lifecycleMappings.values().iterator(); j.hasNext(); )
1143                         {
1144                             List tasks = (List) j.next();
1145 
1146                             for ( Iterator k = tasks.iterator(); k.hasNext(); )
1147                             {
1148                                 MojoExecution exec = (MojoExecution) k.next();
1149 
1150                                 Xpp3Dom configuration = Xpp3Dom.mergeXpp3Dom(
1151                                     new Xpp3Dom( (Xpp3Dom) phase.getConfiguration() ), exec.getConfiguration() );
1152 
1153                                 exec.setConfiguration( configuration );
1154                             }
1155                         }
1156                     }
1157 
1158                 }
1159             }
1160 
1161             removeFromLifecycle( forkEntryPoints, lifecycleMappings );
1162         }
1163 
1164         if ( targetPhase != null )
1165         {
1166             Lifecycle lifecycle = getLifecycleForPhase( targetPhase );
1167 
1168             executeGoalWithLifecycle( targetPhase, forkEntryPoints, session, lifecycleMappings, project, lifecycle );
1169         }
1170         else
1171         {
1172             String goal = mojoDescriptor.getExecuteGoal();
1173             MojoDescriptor desc = getMojoDescriptor( pluginDescriptor, goal );
1174             executeGoals( Collections.singletonList( new MojoExecution( desc ) ), forkEntryPoints, session, project );
1175         }
1176     }
1177 
1178     private Lifecycle getLifecycleForPhase( String phase )
1179         throws BuildFailureException, LifecycleExecutionException
1180     {
1181         Lifecycle lifecycle = (Lifecycle) getPhaseToLifecycleMap().get( phase );
1182 
1183         if ( lifecycle == null )
1184         {
1185             throw new BuildFailureException( "Unable to find lifecycle for phase '" + phase + "'" );
1186         }
1187         return lifecycle;
1188     }
1189 
1190     private MojoDescriptor getMojoDescriptor( PluginDescriptor pluginDescriptor, String goal )
1191         throws LifecycleExecutionException
1192     {
1193         MojoDescriptor desc = pluginDescriptor.getMojo( goal );
1194 
1195         if ( desc == null )
1196         {
1197             String message =
1198                 "Required goal '" + goal + "' not found in plugin '" + pluginDescriptor.getGoalPrefix() + "'";
1199             int index = goal.indexOf( ':' );
1200             if ( index >= 0 )
1201             {
1202                 String prefix = goal.substring( index + 1 );
1203                 if ( prefix.equals( pluginDescriptor.getGoalPrefix() ) )
1204                 {
1205                     message = message + " (goals should not be prefixed - try '" + prefix + "')";
1206                 }
1207             }
1208             throw new LifecycleExecutionException( message );
1209         }
1210         return desc;
1211     }
1212 
1213     private void removeFromLifecycle( Stack lifecycleForkers, Map lifecycleMappings )
1214     {
1215         for ( Iterator lifecycleIterator = lifecycleMappings.values().iterator(); lifecycleIterator.hasNext(); )
1216         {
1217             List tasks = (List) lifecycleIterator.next();
1218 
1219             for ( Iterator taskIterator = tasks.iterator(); taskIterator.hasNext(); )
1220             {
1221                 MojoExecution execution = (MojoExecution) taskIterator.next();
1222 
1223                 if ( lifecycleForkers.contains( execution.getMojoDescriptor() ) )
1224                 {
1225                     taskIterator.remove();
1226                     getLogger().warn( "Removing: " + execution.getMojoDescriptor().getGoal()
1227                                       + " from forked lifecycle, to prevent recursive invocation." );
1228                 }
1229             }
1230         }
1231     }
1232 
1233     private Map constructLifecycleMappings( MavenSession session, String selectedPhase, MavenProject project,
1234                                             Lifecycle lifecycle )
1235         throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException
1236     {
1237         // first, bind those associated with the packaging
1238         Map lifecycleMappings = bindLifecycleForPackaging( session, selectedPhase, project, lifecycle );
1239 
1240         // next, loop over plugins and for any that have a phase, bind it
1241         for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext(); )
1242         {
1243             Plugin plugin = (Plugin) i.next();
1244 
1245             bindPluginToLifecycle( plugin, session, lifecycleMappings, project );
1246         }
1247 
1248         return lifecycleMappings;
1249     }
1250 
1251     private Map bindLifecycleForPackaging( MavenSession session, String selectedPhase, MavenProject project,
1252                                            Lifecycle lifecycle )
1253         throws LifecycleExecutionException, BuildFailureException, PluginNotFoundException
1254     {
1255         Map mappings = findMappingsForLifecycle( session, project, lifecycle );
1256 
1257         List optionalMojos = findOptionalMojosForLifecycle( session, project, lifecycle );
1258 
1259         Map lifecycleMappings = new HashMap();
1260 
1261         for ( Iterator i = lifecycle.getPhases().iterator(); i.hasNext(); )
1262         {
1263             String phase = (String) i.next();
1264 
1265             String phaseTasks = (String) mappings.get( phase );
1266 
1267             if ( phaseTasks != null )
1268             {
1269                 for ( StringTokenizer tok = new StringTokenizer( phaseTasks, "," ); tok.hasMoreTokens(); )
1270                 {
1271                     String goal = tok.nextToken().trim();
1272 
1273                     // Not from the CLI, don't use prefix
1274                     MojoDescriptor mojoDescriptor = getMojoDescriptor( goal, session, project, selectedPhase, false,
1275                                                                        optionalMojos.contains( goal ) );
1276 
1277                     if ( mojoDescriptor == null )
1278                     {
1279                         continue;
1280                     }
1281 
1282                     if ( mojoDescriptor.isDirectInvocationOnly() )
1283                     {
1284                         throw new LifecycleExecutionException( "Mojo: \'" + goal +
1285                             "\' requires direct invocation. It cannot be used as part of lifecycle: \'" +
1286                             project.getPackaging() + "\'." );
1287                     }
1288 
1289                     addToLifecycleMappings( lifecycleMappings, phase, new MojoExecution( mojoDescriptor ),
1290                                             session.getSettings() );
1291                 }
1292             }
1293 
1294             if ( phase.equals( selectedPhase ) )
1295             {
1296                 break;
1297             }
1298         }
1299 
1300         return lifecycleMappings;
1301     }
1302 
1303     private Map findMappingsForLifecycle( MavenSession session, MavenProject project, Lifecycle lifecycle )
1304         throws LifecycleExecutionException, PluginNotFoundException
1305     {
1306         String packaging = project.getPackaging();
1307         Map mappings = null;
1308 
1309         LifecycleMapping m = (LifecycleMapping) findExtension( project, LifecycleMapping.ROLE, packaging,
1310                                                                session.getSettings(), session.getLocalRepository() );
1311         if ( m != null )
1312         {
1313             mappings = m.getPhases( lifecycle.getId() );
1314         }
1315 
1316         Map defaultMappings = lifecycle.getDefaultPhases();
1317 
1318         if ( mappings == null )
1319         {
1320             try
1321             {
1322                 m = (LifecycleMapping) session.lookup( LifecycleMapping.ROLE, packaging );
1323                 mappings = m.getPhases( lifecycle.getId() );
1324             }
1325             catch ( ComponentLookupException e )
1326             {
1327                 if ( defaultMappings == null )
1328                 {
1329                     throw new LifecycleExecutionException(
1330                         "Cannot find lifecycle mapping for packaging: \'" + packaging + "\'.", e );
1331                 }
1332             }
1333         }
1334 
1335         if ( mappings == null )
1336         {
1337             if ( defaultMappings == null )
1338             {
1339                 throw new LifecycleExecutionException(
1340                     "Cannot find lifecycle mapping for packaging: \'" + packaging + "\', and there is no default" );
1341             }
1342             else
1343             {
1344                 mappings = defaultMappings;
1345             }
1346         }
1347 
1348         return mappings;
1349     }
1350 
1351     private List findOptionalMojosForLifecycle( MavenSession session, MavenProject project, Lifecycle lifecycle )
1352         throws LifecycleExecutionException, PluginNotFoundException
1353     {
1354         String packaging = project.getPackaging();
1355         List optionalMojos = null;
1356 
1357         LifecycleMapping m = (LifecycleMapping) findExtension( project, LifecycleMapping.ROLE, packaging, session
1358             .getSettings(), session.getLocalRepository() );
1359 
1360         if ( m != null )
1361         {
1362             optionalMojos = m.getOptionalMojos( lifecycle.getId() );
1363         }
1364 
1365         if ( optionalMojos == null )
1366         {
1367             try
1368             {
1369                 m = (LifecycleMapping) session.lookup( LifecycleMapping.ROLE, packaging );
1370                 optionalMojos = m.getOptionalMojos( lifecycle.getId() );
1371             }
1372             catch ( ComponentLookupException e )
1373             {
1374                 getLogger().debug( "Error looking up lifecycle mapping to retrieve optional mojos. Lifecycle ID: " +
1375                     lifecycle.getId() + ". Error: " + e.getMessage(), e );
1376             }
1377         }
1378 
1379         if ( optionalMojos == null )
1380         {
1381             optionalMojos = Collections.EMPTY_LIST;
1382         }
1383 
1384         return optionalMojos;
1385     }
1386 
1387     private Object findExtension( MavenProject project, String role, String roleHint, Settings settings,
1388                                   ArtifactRepository localRepository )
1389         throws LifecycleExecutionException, PluginNotFoundException
1390     {
1391         Object pluginComponent = null;
1392 
1393         for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext() && pluginComponent == null; )
1394         {
1395             Plugin plugin = (Plugin) i.next();
1396 
1397             if ( plugin.isExtensions() )
1398             {
1399                 verifyPlugin( plugin, project, settings, localRepository );
1400 
1401                 // TODO: if moved to the plugin manager we already have the descriptor from above and so do can lookup the container directly
1402                 try
1403                 {
1404                     pluginComponent = pluginManager.getPluginComponent( plugin, role, roleHint );
1405                 }
1406                 catch ( ComponentLookupException e )
1407                 {
1408                     getLogger().debug( "Unable to find the lifecycle component in the extension", e );
1409                 }
1410                 catch ( PluginManagerException e )
1411                 {
1412                     throw new LifecycleExecutionException(
1413                         "Error getting extensions from the plugin '" + plugin.getKey() + "': " + e.getMessage(), e );
1414                 }
1415             }
1416         }
1417         return pluginComponent;
1418     }
1419 
1420     /**
1421      * @todo Not particularly happy about this. Would like WagonManager and ArtifactTypeHandlerManager to be able to
1422      * lookup directly, or have them passed in
1423      */
1424     private Map findArtifactTypeHandlers( MavenProject project, Settings settings, ArtifactRepository localRepository )
1425         throws LifecycleExecutionException, PluginNotFoundException
1426     {
1427         Map map = new HashMap();
1428         for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext(); )
1429         {
1430             Plugin plugin = (Plugin) i.next();
1431 
1432             if ( plugin.isExtensions() )
1433             {
1434                 verifyPlugin( plugin, project, settings, localRepository );
1435 
1436                 // TODO: if moved to the plugin manager we already have the descriptor from above and so do can lookup the container directly
1437                 try
1438                 {
1439                     Map components = pluginManager.getPluginComponents( plugin, ArtifactHandler.ROLE );
1440                     map.putAll( components );
1441                 }
1442                 catch ( ComponentLookupException e )
1443                 {
1444                     getLogger().debug( "Unable to find the lifecycle component in the extension", e );
1445                 }
1446                 catch ( PluginManagerException e )
1447                 {
1448                     throw new LifecycleExecutionException( "Error looking up available components from plugin '" +
1449                         plugin.getKey() + "': " + e.getMessage(), e );
1450                 }
1451 
1452                 // shudder...
1453                 for ( Iterator j = map.values().iterator(); j.hasNext(); )
1454                 {
1455                     ArtifactHandler handler = (ArtifactHandler) j.next();
1456                     if ( project.getPackaging().equals( handler.getPackaging() ) )
1457                     {
1458                         project.getArtifact().setArtifactHandler( handler );
1459                     }
1460                 }
1461             }
1462         }
1463         return map;
1464     }
1465 
1466     /**
1467      * Take each mojo contained with a plugin, look to see whether it contributes to a
1468      * phase in the lifecycle and if it does place it at the end of the list of goals
1469      * to execute for that given phase.
1470      *
1471      * @param project
1472      * @param session
1473      */
1474     private void bindPluginToLifecycle( Plugin plugin, MavenSession session, Map phaseMap, MavenProject project )
1475         throws LifecycleExecutionException, PluginNotFoundException
1476     {
1477         Settings settings = session.getSettings();
1478 
1479         PluginDescriptor pluginDescriptor =
1480             verifyPlugin( plugin, project, session.getSettings(), session.getLocalRepository() );
1481 
1482         if ( pluginDescriptor.getMojos() != null && !pluginDescriptor.getMojos().isEmpty() )
1483         {
1484             // use the plugin if inherit was true in a base class, or it is in the current POM, otherwise use the default inheritence setting
1485             if ( plugin.isInheritanceApplied() || pluginDescriptor.isInheritedByDefault() )
1486             {
1487                 if ( plugin.getGoals() != null )
1488                 {
1489                     getLogger().error(
1490                         "Plugin contains a <goals/> section: this is IGNORED - please use <executions/> instead." );
1491                 }
1492 
1493                 List executions = plugin.getExecutions();
1494 
1495                 if ( executions != null )
1496                 {
1497                     for ( Iterator it = executions.iterator(); it.hasNext(); )
1498                     {
1499                         PluginExecution execution = (PluginExecution) it.next();
1500 
1501                         bindExecutionToLifecycle( pluginDescriptor, phaseMap, execution, settings );
1502                     }
1503                 }
1504             }
1505         }
1506     }
1507 
1508     private PluginDescriptor verifyPlugin( Plugin plugin, MavenProject project, Settings settings,
1509                                            ArtifactRepository localRepository )
1510         throws LifecycleExecutionException, PluginNotFoundException
1511     {
1512         PluginDescriptor pluginDescriptor;
1513         try
1514         {
1515             // TODO: MNG-4081...need to flush this plugin once we look at it, to avoid using an external
1516             // version of a plugin when a newer version will be created in the current reactor...
1517             pluginDescriptor = pluginManager.verifyPlugin( plugin, project, settings, localRepository );
1518         }
1519         catch ( PluginManagerException e )
1520         {
1521             throw new LifecycleExecutionException(
1522                 "Internal error in the plugin manager getting plugin '" + plugin.getKey() + "': " + e.getMessage(), e );
1523         }
1524         catch ( PluginVersionResolutionException e )
1525         {
1526             throw new LifecycleExecutionException( e.getMessage(), e );
1527         }
1528         catch ( InvalidVersionSpecificationException e )
1529         {
1530             throw new LifecycleExecutionException( e.getMessage(), e );
1531         }
1532         catch ( InvalidPluginException e )
1533         {
1534             throw new LifecycleExecutionException( e.getMessage(), e );
1535         }
1536         catch ( ArtifactNotFoundException e )
1537         {
1538             throw new LifecycleExecutionException( e.getMessage(), e );
1539         }
1540         catch ( ArtifactResolutionException e )
1541         {
1542             throw new LifecycleExecutionException( e.getMessage(), e );
1543         }
1544         catch ( PluginVersionNotFoundException e )
1545         {
1546             throw new LifecycleExecutionException( e.getMessage(), e );
1547         }
1548         return pluginDescriptor;
1549     }
1550 
1551     private PluginDescriptor verifyReportPlugin( ReportPlugin plugin, MavenProject project, MavenSession session )
1552         throws LifecycleExecutionException, PluginNotFoundException
1553     {
1554         PluginDescriptor pluginDescriptor;
1555         try
1556         {
1557             pluginDescriptor = pluginManager.verifyReportPlugin( plugin, project, session );
1558         }
1559         catch ( PluginManagerException e )
1560         {
1561             throw new LifecycleExecutionException(
1562                 "Internal error in the plugin manager getting report '" + plugin.getKey() + "': " + e.getMessage(), e );
1563         }
1564         catch ( PluginVersionResolutionException e )
1565         {
1566             throw new LifecycleExecutionException( e.getMessage(), e );
1567         }
1568         catch ( InvalidVersionSpecificationException e )
1569         {
1570             throw new LifecycleExecutionException( e.getMessage(), e );
1571         }
1572         catch ( InvalidPluginException e )
1573         {
1574             throw new LifecycleExecutionException( e.getMessage(), e );
1575         }
1576         catch ( ArtifactNotFoundException e )
1577         {
1578             throw new LifecycleExecutionException( e.getMessage(), e );
1579         }
1580         catch ( ArtifactResolutionException e )
1581         {
1582             throw new LifecycleExecutionException( e.getMessage(), e );
1583         }
1584         catch ( PluginVersionNotFoundException e )
1585         {
1586             throw new LifecycleExecutionException( e.getMessage(), e );
1587         }
1588         return pluginDescriptor;
1589     }
1590 
1591     private void bindExecutionToLifecycle( PluginDescriptor pluginDescriptor, Map phaseMap, PluginExecution execution,
1592                                            Settings settings )
1593         throws LifecycleExecutionException
1594     {
1595         for ( Iterator i = execution.getGoals().iterator(); i.hasNext(); )
1596         {
1597             String goal = (String) i.next();
1598 
1599             MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( goal );
1600             if ( mojoDescriptor == null )
1601             {
1602                 throw new LifecycleExecutionException(
1603                     "'" + goal + "' was specified in an execution, but not found in the plugin" );
1604             }
1605 
1606             // We have to check to see that the inheritance rules have been applied before binding this mojo.
1607             if ( execution.isInheritanceApplied() || mojoDescriptor.isInheritedByDefault() )
1608             {
1609                 MojoExecution mojoExecution = new MojoExecution( mojoDescriptor, execution.getId() );
1610 
1611                 String phase = execution.getPhase();
1612 
1613                 if ( phase == null )
1614                 {
1615                     // if the phase was not in the configuration, use the phase in the descriptor
1616                     phase = mojoDescriptor.getPhase();
1617                 }
1618 
1619                 if ( phase != null )
1620                 {
1621                     if ( mojoDescriptor.isDirectInvocationOnly() )
1622                     {
1623                         throw new LifecycleExecutionException( "Mojo: \'" + goal +
1624                             "\' requires direct invocation. It cannot be used as part of the lifecycle (it was included via the POM)." );
1625                     }
1626 
1627                     addToLifecycleMappings( phaseMap, phase, mojoExecution, settings );
1628                 }
1629             }
1630         }
1631     }
1632 
1633     private void addToLifecycleMappings( Map lifecycleMappings, String phase, MojoExecution mojoExecution,
1634                                          Settings settings )
1635     {
1636         List goals = (List) lifecycleMappings.get( phase );
1637 
1638         if ( goals == null )
1639         {
1640             goals = new ArrayList();
1641             lifecycleMappings.put( phase, goals );
1642         }
1643 
1644         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
1645         if ( settings.isOffline() && mojoDescriptor.isOnlineRequired() )
1646         {
1647             String goal = mojoDescriptor.getGoal();
1648             getLogger().warn( goal + " requires online mode, but maven is currently offline. Disabling " + goal + "." );
1649         }
1650         else
1651         {
1652             goals.add( mojoExecution );
1653         }
1654     }
1655 
1656     private List processGoalChain( String task, Map phaseMap, Lifecycle lifecycle )
1657     {
1658         List goals = new ArrayList();
1659 
1660         // only execute up to the given phase
1661         int index = lifecycle.getPhases().indexOf( task );
1662 
1663         for ( int i = 0; i <= index; i++ )
1664         {
1665             String p = (String) lifecycle.getPhases().get( i );
1666 
1667             List phaseGoals = (List) phaseMap.get( p );
1668 
1669             if ( phaseGoals != null )
1670             {
1671                 goals.addAll( phaseGoals );
1672             }
1673         }
1674         return goals;
1675     }
1676 
1677     private MojoDescriptor getMojoDescriptor( String task, MavenSession session, MavenProject project,
1678                                               String invokedVia, boolean canUsePrefix, boolean isOptionalMojo )
1679         throws BuildFailureException, LifecycleExecutionException, PluginNotFoundException
1680     {
1681         String goal;
1682         Plugin plugin = null;
1683 
1684         PluginDescriptor pluginDescriptor = null;
1685 
1686         try
1687         {
1688             StringTokenizer tok = new StringTokenizer( task, ":" );
1689             int numTokens = tok.countTokens();
1690 
1691             if ( numTokens == 2 )
1692             {
1693                 if ( !canUsePrefix )
1694                 {
1695                     String msg = "Mapped-prefix lookup of mojos are only supported from direct invocation. " +
1696                         "Please use specification of the form groupId:artifactId[:version]:goal instead. " +
1697                         "(Offending mojo: \'" + task + "\', invoked via: \'" + invokedVia + "\')";
1698                     throw new LifecycleExecutionException( msg );
1699                 }
1700 
1701                 String prefix = tok.nextToken();
1702                 goal = tok.nextToken();
1703 
1704                 // Steps for retrieving the plugin model instance:
1705                 // 1. request directly from the plugin collector by prefix
1706                 pluginDescriptor = pluginManager.getPluginDescriptorForPrefix( prefix );
1707                 if ( pluginDescriptor != null )
1708                 {
1709                     plugin = new Plugin();
1710                     plugin.setGroupId( pluginDescriptor.getGroupId() );
1711                     plugin.setArtifactId( pluginDescriptor.getArtifactId() );
1712                     plugin.setVersion( pluginDescriptor.getVersion() );
1713                 }
1714 
1715                 // 2. search plugins in the current POM
1716                 if ( plugin == null )
1717                 {
1718                     for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext(); )
1719                     {
1720                         Plugin buildPlugin = (Plugin) i.next();
1721 
1722                         PluginDescriptor desc =
1723                             verifyPlugin( buildPlugin, project, session.getSettings(), session.getLocalRepository() );
1724                         if ( prefix.equals( desc.getGoalPrefix() ) )
1725                         {
1726                             plugin = buildPlugin;
1727                             pluginDescriptor = desc;
1728                             break;
1729                         }
1730                     }
1731                 }
1732 
1733                 // 3. look in the repository via search groups
1734                 if ( plugin == null )
1735                 {
1736                     plugin = pluginManager.getPluginDefinitionForPrefix( prefix, session, project );
1737                 }
1738 
1739                 // 4. default to o.a.m.plugins and maven-<prefix>-plugin
1740                 if ( plugin == null )
1741                 {
1742                     plugin = new Plugin();
1743                     plugin.setGroupId( PluginDescriptor.getDefaultPluginGroupId() );
1744                     plugin.setArtifactId( PluginDescriptor.getDefaultPluginArtifactId( prefix ) );
1745                 }
1746             }
1747             else if ( numTokens == 3 || numTokens == 4 )
1748             {
1749                 plugin = new Plugin();
1750 
1751                 plugin.setGroupId( tok.nextToken() );
1752                 plugin.setArtifactId( tok.nextToken() );
1753 
1754                 if ( numTokens == 4 )
1755                 {
1756                     plugin.setVersion( tok.nextToken() );
1757                 }
1758 
1759                 goal = tok.nextToken();
1760             }
1761             else
1762             {
1763                 String message = "Invalid task '" + task + "': you must specify a valid lifecycle phase, or" +
1764                     " a goal in the format plugin:goal or pluginGroupId:pluginArtifactId:pluginVersion:goal";
1765                 throw new BuildFailureException( message );
1766             }
1767 
1768             if ( plugin.getVersion() == null )
1769             {
1770                 for ( Iterator i = project.getBuildPlugins().iterator(); i.hasNext(); )
1771                 {
1772                     Plugin buildPlugin = (Plugin) i.next();
1773 
1774                     if ( buildPlugin.getKey().equals( plugin.getKey() ) )
1775                     {
1776                         plugin = buildPlugin;
1777                         break;
1778                     }
1779                 }
1780 
1781                 project.injectPluginManagementInfo( plugin );
1782             }
1783 
1784             if ( pluginDescriptor == null )
1785             {
1786                 pluginDescriptor = verifyPlugin( plugin, project, session.getSettings(), session.getLocalRepository() );
1787             }
1788 
1789             // this has been simplified from the old code that injected the plugin management stuff, since
1790             // pluginManagement injection is now handled by the project method.
1791             project.addPlugin( plugin );
1792 
1793             MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( goal );
1794             if ( mojoDescriptor == null )
1795             {
1796                 if ( isOptionalMojo )
1797                 {
1798                     getLogger().info( "Skipping missing optional mojo: " + task );
1799                 }
1800                 else
1801                 {
1802                     throw new BuildFailureException( "Required goal not found: " + task + " in "
1803                         + pluginDescriptor.getId() );
1804                 }
1805             }
1806 
1807             return mojoDescriptor;
1808         }
1809         catch ( PluginNotFoundException e )
1810         {
1811             if ( isOptionalMojo )
1812             {
1813                 getLogger().info( "Skipping missing optional mojo: " + task );
1814                 getLogger().debug( "Mojo: " + task + " could not be found. Reason: " + e.getMessage(), e );
1815             }
1816             else
1817             {
1818                 throw e;
1819             }
1820         }
1821 
1822         return null;
1823     }
1824 
1825     protected void line()
1826     {
1827         getLogger().info( "------------------------------------------------------------------------" );
1828     }
1829 
1830     public Map getPhaseToLifecycleMap()
1831         throws LifecycleExecutionException
1832     {
1833         if ( phaseToLifecycleMap == null )
1834         {
1835             phaseToLifecycleMap = new HashMap();
1836 
1837             for ( Iterator i = lifecycles.iterator(); i.hasNext(); )
1838             {
1839                 Lifecycle lifecycle = (Lifecycle) i.next();
1840 
1841                 for ( Iterator p = lifecycle.getPhases().iterator(); p.hasNext(); )
1842                 {
1843                     String phase = (String) p.next();
1844 
1845                     if ( phaseToLifecycleMap.containsKey( phase ) )
1846                     {
1847                         Lifecycle prevLifecycle = (Lifecycle) phaseToLifecycleMap.get( phase );
1848                         throw new LifecycleExecutionException( "Phase '" + phase +
1849                             "' is defined in more than one lifecycle: '" + lifecycle.getId() + "' and '" +
1850                             prevLifecycle.getId() + "'" );
1851                     }
1852                     else
1853                     {
1854                         phaseToLifecycleMap.put( phase, lifecycle );
1855                     }
1856                 }
1857             }
1858         }
1859         return phaseToLifecycleMap;
1860     }
1861 
1862     private static class TaskSegment
1863     {
1864         private boolean aggregate;
1865 
1866         private List tasks = new ArrayList();
1867 
1868         TaskSegment()
1869         {
1870 
1871         }
1872 
1873         TaskSegment( boolean aggregate )
1874         {
1875             this.aggregate = aggregate;
1876         }
1877 
1878         public String toString()
1879         {
1880             StringBuffer message = new StringBuffer();
1881 
1882             message.append( " task-segment: [" );
1883 
1884             for ( Iterator it = tasks.iterator(); it.hasNext(); )
1885             {
1886                 String task = (String) it.next();
1887 
1888                 message.append( task );
1889 
1890                 if ( it.hasNext() )
1891                 {
1892                     message.append( ", " );
1893                 }
1894             }
1895 
1896             message.append( "]" );
1897 
1898             if ( aggregate )
1899             {
1900                 message.append( " (aggregator-style)" );
1901             }
1902 
1903             return message.toString();
1904         }
1905 
1906         boolean aggregate()
1907         {
1908             return aggregate;
1909         }
1910 
1911         void add( String task )
1912         {
1913             tasks.add( task );
1914         }
1915 
1916         List getTasks()
1917         {
1918             return tasks;
1919         }
1920     }
1921     
1922     public List getLifecycles()
1923     {
1924         return lifecycles;
1925     }
1926 
1927     // -------------------------------------------------------------------------
1928     // TODO: The methods and fields below are only needed for products like Hudson,
1929     // that provide their own LifecycleExecutor and component configuration that extend
1930     // default implementation, and which may become out-of-date as component requirements
1931     // are updated within Maven itself.
1932     public void initialize()
1933         throws InitializationException
1934     {
1935         if ( mavenProjectBuilder == null )
1936         {
1937             warnOfIncompleteComponentConfiguration( MavenProjectBuilder.ROLE );
1938             try
1939             {
1940                 mavenProjectBuilder = (MavenProjectBuilder) container.lookup( MavenProjectBuilder.ROLE );
1941             }
1942             catch ( ComponentLookupException e )
1943             {
1944                 throw new InitializationException( "Failed to lookup project builder after it was NOT injected via component requirement." );
1945             }
1946         }
1947         
1948         if ( modelInterpolator == null )
1949         {
1950             warnOfIncompleteComponentConfiguration( ModelInterpolator.ROLE );
1951             try
1952             {
1953                 modelInterpolator = (ModelInterpolator) container.lookup( ModelInterpolator.ROLE );
1954             }
1955             catch ( ComponentLookupException e )
1956             {
1957                 throw new InitializationException( "Failed to lookup model interpolator after it was NOT injected via component requirement." );
1958             }
1959         }
1960     }
1961     
1962     private void warnOfIncompleteComponentConfiguration( String role )
1963     {
1964         StringBuffer buffer = new StringBuffer();
1965         buffer.append( "\n************ WARNING ************" );
1966         buffer.append( "\n\nThis Maven runtime contains a LifecycleExecutor component with an incomplete configuration." );
1967         buffer.append( "\n\nLifecycleExecutor class: " ).append( getClass().getName() );
1968         buffer.append( "\nMissing component requirement: " ).append( role );
1969         buffer.append( "\n" );
1970         buffer.append( "\nNOTE: This seems to be a third-party Maven derivative you are using. If so, please" );
1971         buffer.append( "\nnotify the developers for this derivative project of the problem. The Apache Maven team is not" );
1972         buffer.append( "\nresponsible for maintaining the integrity of third-party component overrides." );
1973         buffer.append( "\n\n" );
1974         
1975         getLogger().warn( buffer.toString() );
1976     }
1977 
1978     private PlexusContainer container;
1979 
1980     public void contextualize( Context context )
1981         throws ContextException
1982     {
1983         container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
1984     }
1985 }