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