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