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