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