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