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