View Javadoc
1   package org.apache.maven.lifecycle.internal;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.LinkedHashMap;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.TreeMap;
27  
28  import javax.inject.Inject;
29  import javax.inject.Named;
30  import javax.inject.Singleton;
31  
32  import org.apache.maven.execution.MavenSession;
33  import org.apache.maven.lifecycle.Lifecycle;
34  import org.apache.maven.lifecycle.LifecycleMappingDelegate;
35  import org.apache.maven.model.Plugin;
36  import org.apache.maven.model.PluginExecution;
37  import org.apache.maven.plugin.BuildPluginManager;
38  import org.apache.maven.plugin.InvalidPluginDescriptorException;
39  import org.apache.maven.plugin.MojoExecution;
40  import org.apache.maven.plugin.MojoNotFoundException;
41  import org.apache.maven.plugin.PluginDescriptorParsingException;
42  import org.apache.maven.plugin.PluginNotFoundException;
43  import org.apache.maven.plugin.PluginResolutionException;
44  import org.apache.maven.plugin.descriptor.MojoDescriptor;
45  import org.apache.maven.project.MavenProject;
46  
47  /**
48   * Lifecycle mapping delegate component interface. Calculates project build execution plan given {@link Lifecycle} and
49   * lifecycle phase. Standard lifecycles use plugin execution {@code <phase>} or mojo default lifecycle phase to
50   * calculate the execution plan, but custom lifecycles can use alternative mapping strategies.
51   */
52  @Named( DefaultLifecycleMappingDelegate.HINT )
53  @Singleton
54  public class DefaultLifecycleMappingDelegate
55      implements LifecycleMappingDelegate
56  {
57      public static final String HINT = "default";
58  
59      private final BuildPluginManager pluginManager;
60  
61      @Inject
62      public DefaultLifecycleMappingDelegate( BuildPluginManager pluginManager )
63      {
64          this.pluginManager = pluginManager;
65      }
66  
67      public Map<String, List<MojoExecution>> calculateLifecycleMappings( MavenSession session, MavenProject project,
68                                                                          Lifecycle lifecycle, String lifecyclePhase )
69          throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
70          MojoNotFoundException, InvalidPluginDescriptorException
71      {
72          /*
73           * Initialize mapping from lifecycle phase to bound mojos. The key set of this map denotes the phases the caller
74           * is interested in, i.e. all phases up to and including the specified phase.
75           */
76  
77          Map<String, Map<Integer, List<MojoExecution>>> mappings =
78              new LinkedHashMap<>();
79  
80          for ( String phase : lifecycle.getPhases() )
81          {
82              Map<Integer, List<MojoExecution>> phaseBindings = new TreeMap<>();
83  
84              mappings.put( phase, phaseBindings );
85  
86              if ( phase.equals( lifecyclePhase ) )
87              {
88                  break;
89              }
90          }
91  
92          /*
93           * Grab plugin executions that are bound to the selected lifecycle phases from project. The effective model of
94           * the project already contains the plugin executions induced by the project's packaging type. Remember, all
95           * phases of interest and only those are in the lifecycle mapping, if a phase has no value in the map, we are
96           * not interested in any of the executions bound to it.
97           */
98  
99          for ( Plugin plugin : project.getBuild().getPlugins() )
100         {
101             for ( PluginExecution execution : plugin.getExecutions() )
102             {
103                 // if the phase is specified then I don't have to go fetch the plugin yet and pull it down
104                 // to examine the phase it is associated to.
105                 if ( execution.getPhase() != null )
106                 {
107                     Map<Integer, List<MojoExecution>> phaseBindings = mappings.get( execution.getPhase() );
108                     if ( phaseBindings != null )
109                     {
110                         for ( String goal : execution.getGoals() )
111                         {
112                             MojoExecution mojoExecution = new MojoExecution( plugin, goal, execution.getId() );
113                             mojoExecution.setLifecyclePhase( execution.getPhase() );
114                             addMojoExecution( phaseBindings, mojoExecution, execution.getPriority() );
115                         }
116                     }
117                 }
118                 // if not then I need to grab the mojo descriptor and look at the phase that is specified
119                 else
120                 {
121                     for ( String goal : execution.getGoals() )
122                     {
123                         MojoDescriptor mojoDescriptor =
124                             pluginManager.getMojoDescriptor( plugin, goal, project.getRemotePluginRepositories(),
125                                                              session.getRepositorySession() );
126 
127                         Map<Integer, List<MojoExecution>> phaseBindings = mappings.get( mojoDescriptor.getPhase() );
128                         if ( phaseBindings != null )
129                         {
130                             MojoExecution mojoExecution = new MojoExecution( mojoDescriptor, execution.getId() );
131                             mojoExecution.setLifecyclePhase( mojoDescriptor.getPhase() );
132                             addMojoExecution( phaseBindings, mojoExecution, execution.getPriority() );
133                         }
134                     }
135                 }
136             }
137         }
138 
139         Map<String, List<MojoExecution>> lifecycleMappings = new LinkedHashMap<>();
140 
141         for ( Map.Entry<String, Map<Integer, List<MojoExecution>>> entry : mappings.entrySet() )
142         {
143             List<MojoExecution> mojoExecutions = new ArrayList<>();
144 
145             for ( List<MojoExecution> executions : entry.getValue().values() )
146             {
147                 mojoExecutions.addAll( executions );
148             }
149 
150             lifecycleMappings.put( entry.getKey(), mojoExecutions );
151         }
152 
153         return lifecycleMappings;
154 
155     }
156 
157     private void addMojoExecution( Map<Integer, List<MojoExecution>> phaseBindings, MojoExecution mojoExecution,
158                                    int priority )
159     {
160         List<MojoExecution> mojoExecutions = phaseBindings.computeIfAbsent( priority, k -> new ArrayList<>() );
161 
162         mojoExecutions.add( mojoExecution );
163     }
164 
165 }