View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
3    * agreements. See the NOTICE file distributed with this work for additional information regarding
4    * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
5    * "License"); you may not use this file except in compliance with the License. You may obtain a
6    * copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software distributed under the License
11   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing permissions and limitations under
13   * the License.
14   */
15  package org.apache.maven.lifecycle.internal;
16  
17  import java.io.IOException;
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.Collections;
21  import java.util.HashSet;
22  import java.util.LinkedHashMap;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.TreeMap;
26  
27  import org.apache.maven.execution.MavenSession;
28  import org.apache.maven.lifecycle.DefaultLifecycles;
29  import org.apache.maven.lifecycle.DefaultSchedules;
30  import org.apache.maven.lifecycle.Lifecycle;
31  import org.apache.maven.lifecycle.LifecycleNotFoundException;
32  import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
33  import org.apache.maven.lifecycle.MavenExecutionPlan;
34  import org.apache.maven.model.Plugin;
35  import org.apache.maven.model.PluginExecution;
36  import org.apache.maven.plugin.BuildPluginManager;
37  import org.apache.maven.plugin.InvalidPluginDescriptorException;
38  import org.apache.maven.plugin.MojoExecution;
39  import org.apache.maven.plugin.MojoNotFoundException;
40  import org.apache.maven.plugin.PluginDescriptorParsingException;
41  import org.apache.maven.plugin.PluginNotFoundException;
42  import org.apache.maven.plugin.PluginResolutionException;
43  import org.apache.maven.plugin.descriptor.MojoDescriptor;
44  import org.apache.maven.plugin.descriptor.Parameter;
45  import org.apache.maven.plugin.descriptor.PluginDescriptor;
46  import org.apache.maven.plugin.lifecycle.Execution;
47  import org.apache.maven.plugin.lifecycle.Phase;
48  import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
49  import org.apache.maven.plugin.version.PluginVersionResolutionException;
50  import org.apache.maven.plugin.version.PluginVersionResolver;
51  import org.apache.maven.project.MavenProject;
52  import org.codehaus.plexus.component.annotations.Component;
53  import org.codehaus.plexus.component.annotations.Requirement;
54  import org.codehaus.plexus.util.StringUtils;
55  import org.codehaus.plexus.util.xml.Xpp3Dom;
56  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
57  
58  /**
59   * @since 3.0
60   * @author Benjamin Bentmann
61   * @author Kristian Rosenvold (Extract class)
62   *         <p/>
63   *         NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
64   */
65  @Component( role = LifecycleExecutionPlanCalculator.class )
66  public class DefaultLifecycleExecutionPlanCalculator
67      implements LifecycleExecutionPlanCalculator
68  {
69      @Requirement
70      private PluginVersionResolver pluginVersionResolver;
71  
72      @Requirement
73      private BuildPluginManager pluginManager;
74  
75      @Requirement
76      private DefaultLifecycles defaultLifeCycles;
77  
78      @Requirement
79      private DefaultSchedules defaultSchedules;
80  
81      @Requirement
82      private MojoDescriptorCreator mojoDescriptorCreator;
83  
84      @Requirement
85      private LifecyclePluginResolver lifecyclePluginResolver;
86  
87      @SuppressWarnings( { "UnusedDeclaration" } )
88      public DefaultLifecycleExecutionPlanCalculator()
89      {
90      }
91  
92      public DefaultLifecycleExecutionPlanCalculator( BuildPluginManager pluginManager,
93                                                      DefaultLifecycles defaultLifeCycles,
94                                                      MojoDescriptorCreator mojoDescriptorCreator,
95                                                      LifecyclePluginResolver lifecyclePluginResolver,
96                                                      DefaultSchedules defaultSchedules )
97      {
98          this.pluginManager = pluginManager;
99          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 }