View Javadoc
1   package org.apache.maven.lifecycle.internal;
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.Arrays;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Map;
30  
31  import org.apache.maven.execution.MavenSession;
32  import org.apache.maven.lifecycle.DefaultLifecycles;
33  import org.apache.maven.lifecycle.Lifecycle;
34  import org.apache.maven.lifecycle.LifecycleMappingDelegate;
35  import org.apache.maven.lifecycle.LifecycleNotFoundException;
36  import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
37  import org.apache.maven.lifecycle.MavenExecutionPlan;
38  import org.apache.maven.lifecycle.internal.builder.BuilderCommon;
39  import org.apache.maven.model.Plugin;
40  import org.apache.maven.model.PluginExecution;
41  import org.apache.maven.plugin.BuildPluginManager;
42  import org.apache.maven.plugin.InvalidPluginDescriptorException;
43  import org.apache.maven.plugin.MojoExecution;
44  import org.apache.maven.plugin.MojoNotFoundException;
45  import org.apache.maven.plugin.PluginDescriptorParsingException;
46  import org.apache.maven.plugin.PluginNotFoundException;
47  import org.apache.maven.plugin.PluginResolutionException;
48  import org.apache.maven.plugin.descriptor.MojoDescriptor;
49  import org.apache.maven.plugin.descriptor.Parameter;
50  import org.apache.maven.plugin.descriptor.PluginDescriptor;
51  import org.apache.maven.plugin.lifecycle.Execution;
52  import org.apache.maven.plugin.lifecycle.Phase;
53  import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
54  import org.apache.maven.plugin.version.PluginVersionResolutionException;
55  import org.apache.maven.plugin.version.PluginVersionResolver;
56  import org.apache.maven.project.MavenProject;
57  import org.codehaus.plexus.component.annotations.Component;
58  import org.codehaus.plexus.component.annotations.Requirement;
59  import org.codehaus.plexus.util.StringUtils;
60  import org.codehaus.plexus.util.xml.Xpp3Dom;
61  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
62  
63  /**
64   * @since 3.0
65   * @author Benjamin Bentmann
66   * @author Kristian Rosenvold (Extract class)
67   *         <p/>
68   *         NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
69   */
70  @Component( role = LifecycleExecutionPlanCalculator.class )
71  public class DefaultLifecycleExecutionPlanCalculator
72      implements LifecycleExecutionPlanCalculator
73  {
74      @Requirement
75      private PluginVersionResolver pluginVersionResolver;
76  
77      @Requirement
78      private BuildPluginManager pluginManager;
79  
80      @Requirement
81      private DefaultLifecycles defaultLifeCycles;
82  
83      @Requirement
84      private MojoDescriptorCreator mojoDescriptorCreator;
85  
86      @Requirement
87      private LifecyclePluginResolver lifecyclePluginResolver;
88  
89      @Requirement( hint = DefaultLifecycleMappingDelegate.HINT )
90      private LifecycleMappingDelegate standardDelegate;
91  
92      @Requirement
93      private Map<String, LifecycleMappingDelegate> delegates;
94  
95      @SuppressWarnings( { "UnusedDeclaration" } )
96      public DefaultLifecycleExecutionPlanCalculator()
97      {
98      }
99  
100     public DefaultLifecycleExecutionPlanCalculator( BuildPluginManager pluginManager,
101                                                     DefaultLifecycles defaultLifeCycles,
102                                                     MojoDescriptorCreator mojoDescriptorCreator,
103                                                     LifecyclePluginResolver lifecyclePluginResolver )
104     {
105         this.pluginManager = pluginManager;
106         this.defaultLifeCycles = defaultLifeCycles;
107         this.mojoDescriptorCreator = mojoDescriptorCreator;
108         this.lifecyclePluginResolver = lifecyclePluginResolver;
109     }
110 
111     public MavenExecutionPlan calculateExecutionPlan( MavenSession session, MavenProject project, List<Object> tasks, boolean setup )
112         throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
113         PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
114         NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException
115     {
116         lifecyclePluginResolver.resolveMissingPluginVersions( project, session );
117 
118         final List<MojoExecution> executions = calculateMojoExecutions( session, project, tasks );
119 
120         if ( setup )
121         {
122             setupMojoExecutions( session, project, executions );
123         }
124 
125         final List<ExecutionPlanItem> planItem = ExecutionPlanItem.createExecutionPlanItems( project, executions );
126 
127         return new MavenExecutionPlan( planItem, defaultLifeCycles );
128     }
129 
130     public MavenExecutionPlan calculateExecutionPlan( MavenSession session, MavenProject project, List<Object> tasks )
131         throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
132         PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
133         NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException
134     {
135         return calculateExecutionPlan( session, project, tasks, true );
136     }
137 
138     private void setupMojoExecutions( MavenSession session, MavenProject project, List<MojoExecution> mojoExecutions )
139         throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
140         MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException,
141         LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
142     {
143         for ( MojoExecution mojoExecution : mojoExecutions )
144         {
145             setupMojoExecution( session, project, mojoExecution );
146         }
147     }
148 
149     public void setupMojoExecution( MavenSession session, MavenProject project, MojoExecution mojoExecution )
150         throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
151         MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException,
152         LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
153     {
154         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
155 
156         if ( mojoDescriptor == null )
157         {
158             mojoDescriptor =
159                 pluginManager.getMojoDescriptor( mojoExecution.getPlugin(), mojoExecution.getGoal(),
160                                                  project.getRemotePluginRepositories(),
161                                                  session.getRepositorySession() );
162 
163             mojoExecution.setMojoDescriptor( mojoDescriptor );
164         }
165 
166         populateMojoExecutionConfiguration( project, mojoExecution,
167                                             MojoExecution.Source.CLI.equals( mojoExecution.getSource() ) );
168 
169         finalizeMojoConfiguration( mojoExecution );
170 
171         calculateForkedExecutions( mojoExecution, session, project, new HashSet<MojoDescriptor>() );
172     }
173     
174     public List<MojoExecution> calculateMojoExecutions( MavenSession session, MavenProject project,
175                                                          List<Object> tasks )
176         throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
177         MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
178         PluginVersionResolutionException, LifecyclePhaseNotFoundException
179     {
180         final List<MojoExecution> mojoExecutions = new ArrayList<MojoExecution>();
181 
182         for ( Object task : tasks )
183         {
184             if ( task instanceof GoalTask )
185             {
186                 String pluginGoal = ( (GoalTask) task ).pluginGoal;
187 
188                 MojoDescriptor mojoDescriptor = mojoDescriptorCreator.getMojoDescriptor( pluginGoal, session, project );
189 
190                 MojoExecution mojoExecution =
191                     new MojoExecution( mojoDescriptor, "default-cli", MojoExecution.Source.CLI );
192 
193                 mojoExecutions.add( mojoExecution );
194             }
195             else if ( task instanceof LifecycleTask )
196             {
197                 String lifecyclePhase = ( (LifecycleTask) task ).getLifecyclePhase();
198 
199                 Map<String, List<MojoExecution>> phaseToMojoMapping =
200                     calculateLifecycleMappings( session, project, lifecyclePhase );
201 
202                 for ( List<MojoExecution> mojoExecutionsFromLifecycle : phaseToMojoMapping.values() )
203                 {
204                     mojoExecutions.addAll( mojoExecutionsFromLifecycle );
205                 }
206             }
207             else
208             {
209                 throw new IllegalStateException( "unexpected task " + task );
210             }
211         }
212         return mojoExecutions;
213     }
214 
215     private Map<String, List<MojoExecution>> calculateLifecycleMappings( MavenSession session, MavenProject project,
216                                                                          String lifecyclePhase )
217         throws LifecyclePhaseNotFoundException, PluginNotFoundException, PluginResolutionException,
218         PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException
219     {
220         /*
221          * Determine the lifecycle that corresponds to the given phase.
222          */
223 
224         Lifecycle lifecycle = defaultLifeCycles.get( lifecyclePhase );
225 
226         if ( lifecycle == null )
227         {
228             throw new LifecyclePhaseNotFoundException( "Unknown lifecycle phase \"" + lifecyclePhase
229                 + "\". You must specify a valid lifecycle phase" + " or a goal in the format <plugin-prefix>:<goal> or"
230                 + " <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: "
231                 + defaultLifeCycles.getLifecyclePhaseList() + ".", lifecyclePhase );
232         }
233 
234         LifecycleMappingDelegate delegate;
235         if ( Arrays.binarySearch( DefaultLifecycles.STANDARD_LIFECYCLES, lifecycle.getId() ) >= 0 )
236         {
237             delegate = standardDelegate;
238         }
239         else
240         {
241             delegate = delegates.get( lifecycle.getId() );
242             if ( delegate == null )
243             {
244                 delegate = standardDelegate;
245             }
246         }
247 
248         return delegate.calculateLifecycleMappings( session, project, lifecycle, lifecyclePhase );
249     }
250 
251     private void populateMojoExecutionConfiguration( MavenProject project, MojoExecution mojoExecution,
252                                                      boolean allowPluginLevelConfig )
253     {
254         String g = mojoExecution.getGroupId();
255 
256         String a = mojoExecution.getArtifactId();
257 
258         Plugin plugin = findPlugin( g, a, project.getBuildPlugins() );
259 
260         if ( plugin == null && project.getPluginManagement() != null )
261         {
262             plugin = findPlugin( g, a, project.getPluginManagement().getPlugins() );
263         }
264 
265         if ( plugin != null )
266         {
267             PluginExecution pluginExecution =
268                 findPluginExecution( mojoExecution.getExecutionId(), plugin.getExecutions() );
269 
270             Xpp3Dom pomConfiguration = null;
271 
272             if ( pluginExecution != null )
273             {
274                 pomConfiguration = (Xpp3Dom) pluginExecution.getConfiguration();
275             }
276             else if ( allowPluginLevelConfig )
277             {
278                 pomConfiguration = (Xpp3Dom) plugin.getConfiguration();
279             }
280 
281             Xpp3Dom mojoConfiguration = ( pomConfiguration != null ) ? new Xpp3Dom( pomConfiguration ) : null;
282 
283             mojoConfiguration = Xpp3Dom.mergeXpp3Dom( mojoExecution.getConfiguration(), mojoConfiguration );
284 
285             mojoExecution.setConfiguration( mojoConfiguration );
286         }
287     }
288 
289     private Plugin findPlugin( String groupId, String artifactId, Collection<Plugin> plugins )
290     {
291         for ( Plugin plugin : plugins )
292         {
293             if ( artifactId.equals( plugin.getArtifactId() ) && groupId.equals( plugin.getGroupId() ) )
294             {
295                 return plugin;
296             }
297         }
298 
299         return null;
300     }
301 
302     private PluginExecution findPluginExecution( String executionId, Collection<PluginExecution> executions )
303     {
304         if ( StringUtils.isNotEmpty( executionId ) )
305         {
306             for ( PluginExecution execution : executions )
307             {
308                 if ( executionId.equals( execution.getId() ) )
309                 {
310                     return execution;
311                 }
312             }
313         }
314 
315         return null;
316     }
317 
318     /**
319      * Post-processes the effective configuration for the specified mojo execution. This step discards all parameters
320      * from the configuration that are not applicable to the mojo and injects the default values for any missing
321      * parameters.
322      *
323      * @param mojoExecution The mojo execution whose configuration should be finalized, must not be {@code null}.
324      */
325     private void finalizeMojoConfiguration( MojoExecution mojoExecution )
326     {
327         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
328 
329         Xpp3Dom executionConfiguration = mojoExecution.getConfiguration();
330         if ( executionConfiguration == null )
331         {
332             executionConfiguration = new Xpp3Dom( "configuration" );
333         }
334 
335         Xpp3Dom defaultConfiguration = getMojoConfiguration( mojoDescriptor );
336 
337         Xpp3Dom finalConfiguration = new Xpp3Dom( "configuration" );
338 
339         if ( mojoDescriptor.getParameters() != null )
340         {
341             for ( Parameter parameter : mojoDescriptor.getParameters() )
342             {
343                 Xpp3Dom parameterConfiguration = executionConfiguration.getChild( parameter.getName() );
344 
345                 if ( parameterConfiguration == null )
346                 {
347                     parameterConfiguration = executionConfiguration.getChild( parameter.getAlias() );
348                 }
349 
350                 Xpp3Dom parameterDefaults = defaultConfiguration.getChild( parameter.getName() );
351 
352                 parameterConfiguration =
353                     Xpp3Dom.mergeXpp3Dom( parameterConfiguration, parameterDefaults, Boolean.TRUE );
354 
355                 if ( parameterConfiguration != null )
356                 {
357                     parameterConfiguration = new Xpp3Dom( parameterConfiguration, parameter.getName() );
358 
359                     if ( StringUtils.isEmpty( parameterConfiguration.getAttribute( "implementation" ) )
360                         && StringUtils.isNotEmpty( parameter.getImplementation() ) )
361                     {
362                         parameterConfiguration.setAttribute( "implementation", parameter.getImplementation() );
363                     }
364 
365                     finalConfiguration.addChild( parameterConfiguration );
366                 }
367             }
368         }
369 
370         mojoExecution.setConfiguration( finalConfiguration );
371     }
372 
373     private Xpp3Dom getMojoConfiguration( MojoDescriptor mojoDescriptor )
374     {
375         return MojoDescriptorCreator.convert( mojoDescriptor );
376     }
377 
378     public void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session )
379         throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
380         PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
381         LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
382     {
383         calculateForkedExecutions( mojoExecution, session, session.getCurrentProject(), new HashSet<MojoDescriptor>() );
384     }
385 
386     private void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session, MavenProject project,
387                                             Collection<MojoDescriptor> alreadyForkedExecutions )
388         throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
389         PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
390         LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
391     {
392         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
393 
394         if ( !mojoDescriptor.isForking() )
395         {
396             return;
397         }
398 
399         if ( !alreadyForkedExecutions.add( mojoDescriptor ) )
400         {
401             return;
402         }
403 
404         List<MavenProject> forkedProjects =
405             LifecycleDependencyResolver.getProjects( project, session, mojoDescriptor.isAggregator() );
406 
407         for ( MavenProject forkedProject : forkedProjects )
408         {
409             if ( forkedProject != project )
410             {
411                 lifecyclePluginResolver.resolveMissingPluginVersions( forkedProject, session );
412             }
413 
414             List<MojoExecution> forkedExecutions;
415 
416             if ( StringUtils.isNotEmpty( mojoDescriptor.getExecutePhase() ) )
417             {
418                 forkedExecutions =
419                     calculateForkedLifecycle( mojoExecution, session, forkedProject, alreadyForkedExecutions );
420             }
421             else
422             {
423                 forkedExecutions =
424                     calculateForkedGoal( mojoExecution, session, forkedProject, alreadyForkedExecutions );
425             }
426 
427             mojoExecution.setForkedExecutions( BuilderCommon.getKey( forkedProject ), forkedExecutions );
428         }
429 
430         alreadyForkedExecutions.remove( mojoDescriptor );
431     }
432 
433     private List<MojoExecution> calculateForkedLifecycle( MojoExecution mojoExecution, MavenSession session,
434                                                           MavenProject project,
435                                                           Collection<MojoDescriptor> alreadyForkedExecutions )
436         throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
437         PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
438         LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
439     {
440         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
441 
442         String forkedPhase = mojoDescriptor.getExecutePhase();
443 
444         Map<String, List<MojoExecution>> lifecycleMappings =
445             calculateLifecycleMappings( session, project, forkedPhase );
446 
447         for ( List<MojoExecution> forkedExecutions : lifecycleMappings.values() )
448         {
449             for ( MojoExecution forkedExecution : forkedExecutions )
450             {
451                 if ( forkedExecution.getMojoDescriptor() == null )
452                 {
453                     MojoDescriptor forkedMojoDescriptor =
454                         pluginManager.getMojoDescriptor( forkedExecution.getPlugin(), forkedExecution.getGoal(),
455                                                          project.getRemotePluginRepositories(),
456                                                          session.getRepositorySession() );
457 
458                     forkedExecution.setMojoDescriptor( forkedMojoDescriptor );
459                 }
460 
461                 populateMojoExecutionConfiguration( project, forkedExecution, false );
462             }
463         }
464 
465         injectLifecycleOverlay( lifecycleMappings, mojoExecution, session, project );
466 
467         List<MojoExecution> mojoExecutions = new ArrayList<MojoExecution>();
468 
469         for ( List<MojoExecution> forkedExecutions : lifecycleMappings.values() )
470         {
471             for ( MojoExecution forkedExecution : forkedExecutions )
472             {
473                 if ( !alreadyForkedExecutions.contains( forkedExecution.getMojoDescriptor() ) )
474                 {
475                     finalizeMojoConfiguration( forkedExecution );
476 
477                     calculateForkedExecutions( forkedExecution, session, project, alreadyForkedExecutions );
478 
479                     mojoExecutions.add( forkedExecution );
480                 }
481             }
482         }
483 
484         return mojoExecutions;
485     }
486 
487     private void injectLifecycleOverlay( Map<String, List<MojoExecution>> lifecycleMappings,
488                                          MojoExecution mojoExecution, MavenSession session, MavenProject project )
489         throws PluginDescriptorParsingException, LifecycleNotFoundException, MojoNotFoundException,
490         PluginNotFoundException, PluginResolutionException, NoPluginFoundForPrefixException,
491         InvalidPluginDescriptorException, PluginVersionResolutionException
492     {
493         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
494 
495         PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
496 
497         String forkedLifecycle = mojoDescriptor.getExecuteLifecycle();
498 
499         if ( StringUtils.isEmpty( forkedLifecycle ) )
500         {
501             return;
502         }
503 
504         org.apache.maven.plugin.lifecycle.Lifecycle lifecycleOverlay;
505 
506         try
507         {
508             lifecycleOverlay = pluginDescriptor.getLifecycleMapping( forkedLifecycle );
509         }
510         catch ( IOException e )
511         {
512             throw new PluginDescriptorParsingException( pluginDescriptor.getPlugin(), pluginDescriptor.getSource(), e );
513         }
514         catch ( XmlPullParserException e )
515         {
516             throw new PluginDescriptorParsingException( pluginDescriptor.getPlugin(), pluginDescriptor.getSource(), e );
517         }
518 
519         if ( lifecycleOverlay == null )
520         {
521             throw new LifecycleNotFoundException( forkedLifecycle );
522         }
523 
524         for ( Phase phase : lifecycleOverlay.getPhases() )
525         {
526             List<MojoExecution> forkedExecutions = lifecycleMappings.get( phase.getId() );
527 
528             if ( forkedExecutions != null )
529             {
530                 for ( Execution execution : phase.getExecutions() )
531                 {
532                     for ( String goal : execution.getGoals() )
533                     {
534                         MojoDescriptor forkedMojoDescriptor;
535 
536                         if ( goal.indexOf( ':' ) < 0 )
537                         {
538                             forkedMojoDescriptor = pluginDescriptor.getMojo( goal );
539                             if ( forkedMojoDescriptor == null )
540                             {
541                                 throw new MojoNotFoundException( goal, pluginDescriptor );
542                             }
543                         }
544                         else
545                         {
546                             forkedMojoDescriptor = mojoDescriptorCreator.getMojoDescriptor( goal, session, project );
547                         }
548 
549                         MojoExecution forkedExecution =
550                             new MojoExecution( forkedMojoDescriptor, mojoExecution.getExecutionId() );
551 
552                         Xpp3Dom forkedConfiguration = (Xpp3Dom) execution.getConfiguration();
553 
554                         forkedExecution.setConfiguration( forkedConfiguration );
555 
556                         populateMojoExecutionConfiguration( project, forkedExecution, true );
557 
558                         forkedExecutions.add( forkedExecution );
559                     }
560                 }
561 
562                 Xpp3Dom phaseConfiguration = (Xpp3Dom) phase.getConfiguration();
563 
564                 if ( phaseConfiguration != null )
565                 {
566                     for ( MojoExecution forkedExecution : forkedExecutions )
567                     {
568                         Xpp3Dom forkedConfiguration = forkedExecution.getConfiguration();
569 
570                         forkedConfiguration = Xpp3Dom.mergeXpp3Dom( phaseConfiguration, forkedConfiguration );
571 
572                         forkedExecution.setConfiguration( forkedConfiguration );
573                     }
574                 }
575             }
576         }
577     }
578     // org.apache.maven.plugins:maven-remote-resources-plugin:1.0:process
579     //TODO: take repo mans into account as one may be aggregating prefixes of many
580     //TODO: collect at the root of the repository, read the one at the root, and fetch remote if something is missing
581     //      or the user forces the issue
582 
583     private List<MojoExecution> calculateForkedGoal( MojoExecution mojoExecution, MavenSession session,
584                                                      MavenProject project,
585                                                      Collection<MojoDescriptor> alreadyForkedExecutions )
586         throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
587         PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
588         LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
589     {
590         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
591 
592         PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
593 
594         String forkedGoal = mojoDescriptor.getExecuteGoal();
595 
596         MojoDescriptor forkedMojoDescriptor = pluginDescriptor.getMojo( forkedGoal );
597         if ( forkedMojoDescriptor == null )
598         {
599             throw new MojoNotFoundException( forkedGoal, pluginDescriptor );
600         }
601 
602         if ( alreadyForkedExecutions.contains( forkedMojoDescriptor ) )
603         {
604             return Collections.emptyList();
605         }
606 
607         MojoExecution forkedExecution = new MojoExecution( forkedMojoDescriptor, forkedGoal );
608 
609         populateMojoExecutionConfiguration( project, forkedExecution, true );
610 
611         finalizeMojoConfiguration( forkedExecution );
612 
613         calculateForkedExecutions( forkedExecution, session, project, alreadyForkedExecutions );
614 
615         return Collections.singletonList( forkedExecution );
616     }
617 
618 
619 }