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