001package org.apache.maven.lifecycle.internal;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.IOException;
023import java.util.ArrayList;
024import java.util.Arrays;
025import java.util.Collection;
026import java.util.Collections;
027import java.util.HashSet;
028import java.util.List;
029import java.util.Map;
030
031import org.apache.maven.execution.MavenSession;
032import org.apache.maven.lifecycle.DefaultLifecycles;
033import org.apache.maven.lifecycle.Lifecycle;
034import org.apache.maven.lifecycle.LifecycleMappingDelegate;
035import org.apache.maven.lifecycle.LifecycleNotFoundException;
036import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
037import org.apache.maven.lifecycle.MavenExecutionPlan;
038import org.apache.maven.lifecycle.internal.builder.BuilderCommon;
039import org.apache.maven.model.Plugin;
040import org.apache.maven.model.PluginExecution;
041import org.apache.maven.plugin.BuildPluginManager;
042import org.apache.maven.plugin.InvalidPluginDescriptorException;
043import org.apache.maven.plugin.MojoExecution;
044import org.apache.maven.plugin.MojoNotFoundException;
045import org.apache.maven.plugin.PluginDescriptorParsingException;
046import org.apache.maven.plugin.PluginNotFoundException;
047import org.apache.maven.plugin.PluginResolutionException;
048import org.apache.maven.plugin.descriptor.MojoDescriptor;
049import org.apache.maven.plugin.descriptor.Parameter;
050import org.apache.maven.plugin.descriptor.PluginDescriptor;
051import org.apache.maven.plugin.lifecycle.Execution;
052import org.apache.maven.plugin.lifecycle.Phase;
053import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
054import org.apache.maven.plugin.version.PluginVersionResolutionException;
055import org.apache.maven.plugin.version.PluginVersionResolver;
056import org.apache.maven.project.MavenProject;
057import org.codehaus.plexus.component.annotations.Component;
058import org.codehaus.plexus.component.annotations.Requirement;
059import org.codehaus.plexus.util.StringUtils;
060import org.codehaus.plexus.util.xml.Xpp3Dom;
061import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
062
063/**
064 * @since 3.0
065 * @author Benjamin Bentmann
066 * @author Kristian Rosenvold (Extract class)
067 *         <p/>
068 *         NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
069 */
070@Component( role = LifecycleExecutionPlanCalculator.class )
071public class DefaultLifecycleExecutionPlanCalculator
072    implements LifecycleExecutionPlanCalculator
073{
074    @Requirement
075    private PluginVersionResolver pluginVersionResolver;
076
077    @Requirement
078    private BuildPluginManager pluginManager;
079
080    @Requirement
081    private DefaultLifecycles defaultLifeCycles;
082
083    @Requirement
084    private MojoDescriptorCreator mojoDescriptorCreator;
085
086    @Requirement
087    private LifecyclePluginResolver lifecyclePluginResolver;
088
089    @Requirement( hint = DefaultLifecycleMappingDelegate.HINT )
090    private LifecycleMappingDelegate standardDelegate;
091
092    @Requirement
093    private Map<String, LifecycleMappingDelegate> delegates;
094
095    @SuppressWarnings( { "UnusedDeclaration" } )
096    public DefaultLifecycleExecutionPlanCalculator()
097    {
098    }
099
100    public DefaultLifecycleExecutionPlanCalculator( BuildPluginManager pluginManager,
101                                                    DefaultLifecycles defaultLifeCycles,
102                                                    MojoDescriptorCreator mojoDescriptorCreator,
103                                                    LifecyclePluginResolver lifecyclePluginResolver )
104    {
105        this.pluginManager = pluginManager;
106        this.defaultLifeCycles = defaultLifeCycles;
107        this.mojoDescriptorCreator = mojoDescriptorCreator;
108        this.lifecyclePluginResolver = lifecyclePluginResolver;
109    }
110
111    public MavenExecutionPlan calculateExecutionPlan( MavenSession session, MavenProject project, List<Object> tasks, boolean setup )
112        throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
113        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
114        NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException
115    {
116        lifecyclePluginResolver.resolveMissingPluginVersions( project, session );
117
118        final List<MojoExecution> executions = calculateMojoExecutions( session, project, tasks );
119
120        if ( setup )
121        {
122            setupMojoExecutions( session, project, executions );
123        }
124
125        final List<ExecutionPlanItem> planItem = ExecutionPlanItem.createExecutionPlanItems( project, executions );
126
127        return new MavenExecutionPlan( planItem, defaultLifeCycles );
128    }
129
130    public MavenExecutionPlan calculateExecutionPlan( MavenSession session, MavenProject project, List<Object> tasks )
131        throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
132        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
133        NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException
134    {
135        return calculateExecutionPlan( session, project, tasks, true );
136    }
137
138    private void setupMojoExecutions( MavenSession session, MavenProject project, List<MojoExecution> mojoExecutions )
139        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
140        MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException,
141        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
142    {
143        for ( MojoExecution mojoExecution : mojoExecutions )
144        {
145            setupMojoExecution( session, project, mojoExecution );
146        }
147    }
148
149    public void setupMojoExecution( MavenSession session, MavenProject project, MojoExecution mojoExecution )
150        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
151        MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException,
152        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
153    {
154        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
155
156        if ( mojoDescriptor == null )
157        {
158            mojoDescriptor =
159                pluginManager.getMojoDescriptor( mojoExecution.getPlugin(), mojoExecution.getGoal(),
160                                                 project.getRemotePluginRepositories(),
161                                                 session.getRepositorySession() );
162
163            mojoExecution.setMojoDescriptor( mojoDescriptor );
164        }
165
166        populateMojoExecutionConfiguration( project, mojoExecution,
167                                            MojoExecution.Source.CLI.equals( mojoExecution.getSource() ) );
168
169        finalizeMojoConfiguration( mojoExecution );
170
171        calculateForkedExecutions( mojoExecution, session, project, new HashSet<MojoDescriptor>() );
172    }
173
174    public List<MojoExecution> calculateMojoExecutions( MavenSession session, MavenProject project,
175                                                         List<Object> tasks )
176        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
177        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
178        PluginVersionResolutionException, LifecyclePhaseNotFoundException
179    {
180        final List<MojoExecution> mojoExecutions = new ArrayList<MojoExecution>();
181
182        for ( Object task : tasks )
183        {
184            if ( task instanceof GoalTask )
185            {
186                String pluginGoal = ( (GoalTask) task ).pluginGoal;
187
188                MojoDescriptor mojoDescriptor = mojoDescriptorCreator.getMojoDescriptor( pluginGoal, session, project );
189
190                MojoExecution mojoExecution =
191                    new MojoExecution( mojoDescriptor, "default-cli", MojoExecution.Source.CLI );
192
193                mojoExecutions.add( mojoExecution );
194            }
195            else if ( task instanceof LifecycleTask )
196            {
197                String lifecyclePhase = ( (LifecycleTask) task ).getLifecyclePhase();
198
199                Map<String, List<MojoExecution>> phaseToMojoMapping =
200                    calculateLifecycleMappings( session, project, lifecyclePhase );
201
202                for ( List<MojoExecution> mojoExecutionsFromLifecycle : phaseToMojoMapping.values() )
203                {
204                    mojoExecutions.addAll( mojoExecutionsFromLifecycle );
205                }
206            }
207            else
208            {
209                throw new IllegalStateException( "unexpected task " + task );
210            }
211        }
212        return mojoExecutions;
213    }
214
215    private Map<String, List<MojoExecution>> calculateLifecycleMappings( MavenSession session, MavenProject project,
216                                                                         String lifecyclePhase )
217        throws LifecyclePhaseNotFoundException, PluginNotFoundException, PluginResolutionException,
218        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException
219    {
220        /*
221         * Determine the lifecycle that corresponds to the given phase.
222         */
223
224        Lifecycle lifecycle = defaultLifeCycles.get( lifecyclePhase );
225
226        if ( lifecycle == null )
227        {
228            throw new LifecyclePhaseNotFoundException( "Unknown lifecycle phase \"" + lifecyclePhase
229                + "\". You must specify a valid lifecycle phase" + " or a goal in the format <plugin-prefix>:<goal> or"
230                + " <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: "
231                + defaultLifeCycles.getLifecyclePhaseList() + ".", lifecyclePhase );
232        }
233
234        LifecycleMappingDelegate delegate;
235        if ( Arrays.binarySearch( DefaultLifecycles.STANDARD_LIFECYCLES, lifecycle.getId() ) >= 0 )
236        {
237            delegate = standardDelegate;
238        }
239        else
240        {
241            delegate = delegates.get( lifecycle.getId() );
242            if ( delegate == null )
243            {
244                delegate = standardDelegate;
245            }
246        }
247
248        return delegate.calculateLifecycleMappings( session, project, lifecycle, lifecyclePhase );
249    }
250
251    private void populateMojoExecutionConfiguration( MavenProject project, MojoExecution mojoExecution,
252                                                     boolean allowPluginLevelConfig )
253    {
254        String g = mojoExecution.getGroupId();
255
256        String a = mojoExecution.getArtifactId();
257
258        Plugin plugin = findPlugin( g, a, project.getBuildPlugins() );
259
260        if ( plugin == null && project.getPluginManagement() != null )
261        {
262            plugin = findPlugin( g, a, project.getPluginManagement().getPlugins() );
263        }
264
265        if ( plugin != null )
266        {
267            PluginExecution pluginExecution =
268                findPluginExecution( mojoExecution.getExecutionId(), plugin.getExecutions() );
269
270            Xpp3Dom pomConfiguration = null;
271
272            if ( pluginExecution != null )
273            {
274                pomConfiguration = (Xpp3Dom) pluginExecution.getConfiguration();
275            }
276            else if ( allowPluginLevelConfig )
277            {
278                pomConfiguration = (Xpp3Dom) plugin.getConfiguration();
279            }
280
281            Xpp3Dom mojoConfiguration = ( pomConfiguration != null ) ? new Xpp3Dom( pomConfiguration ) : null;
282
283            mojoConfiguration = Xpp3Dom.mergeXpp3Dom( mojoExecution.getConfiguration(), mojoConfiguration );
284
285            mojoExecution.setConfiguration( mojoConfiguration );
286        }
287    }
288
289    private Plugin findPlugin( String groupId, String artifactId, Collection<Plugin> plugins )
290    {
291        for ( Plugin plugin : plugins )
292        {
293            if ( artifactId.equals( plugin.getArtifactId() ) && groupId.equals( plugin.getGroupId() ) )
294            {
295                return plugin;
296            }
297        }
298
299        return null;
300    }
301
302    private PluginExecution findPluginExecution( String executionId, Collection<PluginExecution> executions )
303    {
304        if ( StringUtils.isNotEmpty( executionId ) )
305        {
306            for ( PluginExecution execution : executions )
307            {
308                if ( executionId.equals( execution.getId() ) )
309                {
310                    return execution;
311                }
312            }
313        }
314
315        return null;
316    }
317
318    /**
319     * Post-processes the effective configuration for the specified mojo execution. This step discards all parameters
320     * from the configuration that are not applicable to the mojo and injects the default values for any missing
321     * parameters.
322     *
323     * @param mojoExecution The mojo execution whose configuration should be finalized, must not be {@code null}.
324     */
325    private void finalizeMojoConfiguration( MojoExecution mojoExecution )
326    {
327        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
328
329        Xpp3Dom executionConfiguration = mojoExecution.getConfiguration();
330        if ( executionConfiguration == null )
331        {
332            executionConfiguration = new Xpp3Dom( "configuration" );
333        }
334
335        Xpp3Dom defaultConfiguration = getMojoConfiguration( mojoDescriptor );
336
337        Xpp3Dom finalConfiguration = new Xpp3Dom( "configuration" );
338
339        if ( mojoDescriptor.getParameters() != null )
340        {
341            for ( Parameter parameter : mojoDescriptor.getParameters() )
342            {
343                Xpp3Dom parameterConfiguration = executionConfiguration.getChild( parameter.getName() );
344
345                if ( parameterConfiguration == null )
346                {
347                    parameterConfiguration = executionConfiguration.getChild( parameter.getAlias() );
348                }
349
350                Xpp3Dom parameterDefaults = defaultConfiguration.getChild( parameter.getName() );
351
352                parameterConfiguration =
353                    Xpp3Dom.mergeXpp3Dom( parameterConfiguration, parameterDefaults, Boolean.TRUE );
354
355                if ( parameterConfiguration != null )
356                {
357                    parameterConfiguration = new Xpp3Dom( parameterConfiguration, parameter.getName() );
358
359                    if ( StringUtils.isEmpty( parameterConfiguration.getAttribute( "implementation" ) )
360                        && StringUtils.isNotEmpty( parameter.getImplementation() ) )
361                    {
362                        parameterConfiguration.setAttribute( "implementation", parameter.getImplementation() );
363                    }
364
365                    finalConfiguration.addChild( parameterConfiguration );
366                }
367            }
368        }
369
370        mojoExecution.setConfiguration( finalConfiguration );
371    }
372
373    private Xpp3Dom getMojoConfiguration( MojoDescriptor mojoDescriptor )
374    {
375        return MojoDescriptorCreator.convert( mojoDescriptor );
376    }
377
378    public void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session )
379        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
380        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
381        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
382    {
383        calculateForkedExecutions( mojoExecution, session, session.getCurrentProject(), new HashSet<MojoDescriptor>() );
384    }
385
386    private void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session, MavenProject project,
387                                            Collection<MojoDescriptor> alreadyForkedExecutions )
388        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
389        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
390        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
391    {
392        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
393
394        if ( !mojoDescriptor.isForking() )
395        {
396            return;
397        }
398
399        if ( !alreadyForkedExecutions.add( mojoDescriptor ) )
400        {
401            return;
402        }
403
404        List<MavenProject> forkedProjects =
405            LifecycleDependencyResolver.getProjects( project, session, mojoDescriptor.isAggregator() );
406
407        for ( MavenProject forkedProject : forkedProjects )
408        {
409            if ( forkedProject != project )
410            {
411                lifecyclePluginResolver.resolveMissingPluginVersions( forkedProject, session );
412            }
413
414            List<MojoExecution> forkedExecutions;
415
416            if ( StringUtils.isNotEmpty( mojoDescriptor.getExecutePhase() ) )
417            {
418                forkedExecutions =
419                    calculateForkedLifecycle( mojoExecution, session, forkedProject, alreadyForkedExecutions );
420            }
421            else
422            {
423                forkedExecutions =
424                    calculateForkedGoal( mojoExecution, session, forkedProject, alreadyForkedExecutions );
425            }
426
427            mojoExecution.setForkedExecutions( BuilderCommon.getKey( forkedProject ), forkedExecutions );
428        }
429
430        alreadyForkedExecutions.remove( mojoDescriptor );
431    }
432
433    private List<MojoExecution> calculateForkedLifecycle( MojoExecution mojoExecution, MavenSession session,
434                                                          MavenProject project,
435                                                          Collection<MojoDescriptor> alreadyForkedExecutions )
436        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
437        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
438        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
439    {
440        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
441
442        String forkedPhase = mojoDescriptor.getExecutePhase();
443
444        Map<String, List<MojoExecution>> lifecycleMappings =
445            calculateLifecycleMappings( session, project, forkedPhase );
446
447        for ( List<MojoExecution> forkedExecutions : lifecycleMappings.values() )
448        {
449            for ( MojoExecution forkedExecution : forkedExecutions )
450            {
451                if ( forkedExecution.getMojoDescriptor() == null )
452                {
453                    MojoDescriptor forkedMojoDescriptor =
454                        pluginManager.getMojoDescriptor( forkedExecution.getPlugin(), forkedExecution.getGoal(),
455                                                         project.getRemotePluginRepositories(),
456                                                         session.getRepositorySession() );
457
458                    forkedExecution.setMojoDescriptor( forkedMojoDescriptor );
459                }
460
461                populateMojoExecutionConfiguration( project, forkedExecution, false );
462            }
463        }
464
465        injectLifecycleOverlay( lifecycleMappings, mojoExecution, session, project );
466
467        List<MojoExecution> mojoExecutions = new ArrayList<MojoExecution>();
468
469        for ( List<MojoExecution> forkedExecutions : lifecycleMappings.values() )
470        {
471            for ( MojoExecution forkedExecution : forkedExecutions )
472            {
473                if ( !alreadyForkedExecutions.contains( forkedExecution.getMojoDescriptor() ) )
474                {
475                    finalizeMojoConfiguration( forkedExecution );
476
477                    calculateForkedExecutions( forkedExecution, session, project, alreadyForkedExecutions );
478
479                    mojoExecutions.add( forkedExecution );
480                }
481            }
482        }
483
484        return mojoExecutions;
485    }
486
487    private void injectLifecycleOverlay( Map<String, List<MojoExecution>> lifecycleMappings,
488                                         MojoExecution mojoExecution, MavenSession session, MavenProject project )
489        throws PluginDescriptorParsingException, LifecycleNotFoundException, MojoNotFoundException,
490        PluginNotFoundException, PluginResolutionException, NoPluginFoundForPrefixException,
491        InvalidPluginDescriptorException, PluginVersionResolutionException
492    {
493        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
494
495        PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
496
497        String forkedLifecycle = mojoDescriptor.getExecuteLifecycle();
498
499        if ( StringUtils.isEmpty( forkedLifecycle ) )
500        {
501            return;
502        }
503
504        org.apache.maven.plugin.lifecycle.Lifecycle lifecycleOverlay;
505
506        try
507        {
508            lifecycleOverlay = pluginDescriptor.getLifecycleMapping( forkedLifecycle );
509        }
510        catch ( IOException e )
511        {
512            throw new PluginDescriptorParsingException( pluginDescriptor.getPlugin(), pluginDescriptor.getSource(), e );
513        }
514        catch ( XmlPullParserException e )
515        {
516            throw new PluginDescriptorParsingException( pluginDescriptor.getPlugin(), pluginDescriptor.getSource(), e );
517        }
518
519        if ( lifecycleOverlay == null )
520        {
521            throw new LifecycleNotFoundException( forkedLifecycle );
522        }
523
524        for ( Phase phase : lifecycleOverlay.getPhases() )
525        {
526            List<MojoExecution> forkedExecutions = lifecycleMappings.get( phase.getId() );
527
528            if ( forkedExecutions != null )
529            {
530                for ( Execution execution : phase.getExecutions() )
531                {
532                    for ( String goal : execution.getGoals() )
533                    {
534                        MojoDescriptor forkedMojoDescriptor;
535
536                        if ( goal.indexOf( ':' ) < 0 )
537                        {
538                            forkedMojoDescriptor = pluginDescriptor.getMojo( goal );
539                            if ( forkedMojoDescriptor == null )
540                            {
541                                throw new MojoNotFoundException( goal, pluginDescriptor );
542                            }
543                        }
544                        else
545                        {
546                            forkedMojoDescriptor = mojoDescriptorCreator.getMojoDescriptor( goal, session, project );
547                        }
548
549                        MojoExecution forkedExecution =
550                            new MojoExecution( forkedMojoDescriptor, mojoExecution.getExecutionId() );
551
552                        Xpp3Dom forkedConfiguration = (Xpp3Dom) execution.getConfiguration();
553
554                        forkedExecution.setConfiguration( forkedConfiguration );
555
556                        populateMojoExecutionConfiguration( project, forkedExecution, true );
557
558                        forkedExecutions.add( forkedExecution );
559                    }
560                }
561
562                Xpp3Dom phaseConfiguration = (Xpp3Dom) phase.getConfiguration();
563
564                if ( phaseConfiguration != null )
565                {
566                    for ( MojoExecution forkedExecution : forkedExecutions )
567                    {
568                        Xpp3Dom forkedConfiguration = forkedExecution.getConfiguration();
569
570                        forkedConfiguration = Xpp3Dom.mergeXpp3Dom( phaseConfiguration, forkedConfiguration );
571
572                        forkedExecution.setConfiguration( forkedConfiguration );
573                    }
574                }
575            }
576        }
577    }
578    // org.apache.maven.plugins:maven-remote-resources-plugin:1.0:process
579    //TODO: take repo mans into account as one may be aggregating prefixes of many
580    //TODO: collect at the root of the repository, read the one at the root, and fetch remote if something is missing
581    //      or the user forces the issue
582
583    private List<MojoExecution> calculateForkedGoal( MojoExecution mojoExecution, MavenSession session,
584                                                     MavenProject project,
585                                                     Collection<MojoDescriptor> alreadyForkedExecutions )
586        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
587        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
588        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
589    {
590        MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
591
592        PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
593
594        String forkedGoal = mojoDescriptor.getExecuteGoal();
595
596        MojoDescriptor forkedMojoDescriptor = pluginDescriptor.getMojo( forkedGoal );
597        if ( forkedMojoDescriptor == null )
598        {
599            throw new MojoNotFoundException( forkedGoal, pluginDescriptor );
600        }
601
602        if ( alreadyForkedExecutions.contains( forkedMojoDescriptor ) )
603        {
604            return Collections.emptyList();
605        }
606
607        MojoExecution forkedExecution = new MojoExecution( forkedMojoDescriptor, forkedGoal );
608
609        populateMojoExecutionConfiguration( project, forkedExecution, true );
610
611        finalizeMojoConfiguration( forkedExecution );
612
613        calculateForkedExecutions( forkedExecution, session, project, alreadyForkedExecutions );
614
615        return Collections.singletonList( forkedExecution );
616    }
617
618
619}