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 org.apache.maven.lifecycle.DefaultLifecycles;
23  import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer;
24  import org.apache.maven.lifecycle.Lifecycle;
25  import org.apache.maven.lifecycle.mapping.LifecycleMapping;
26  import org.apache.maven.lifecycle.mapping.LifecycleMojo;
27  import org.apache.maven.lifecycle.mapping.LifecyclePhase;
28  import org.apache.maven.model.Plugin;
29  import org.apache.maven.model.PluginExecution;
30  import org.codehaus.plexus.component.annotations.Component;
31  import org.codehaus.plexus.component.annotations.Requirement;
32  import org.codehaus.plexus.logging.Logger;
33  import org.codehaus.plexus.util.StringUtils;
34  
35  import java.util.ArrayList;
36  import java.util.Collections;
37  import java.util.Comparator;
38  import java.util.HashSet;
39  import java.util.LinkedHashMap;
40  import java.util.List;
41  import java.util.Map;
42  import java.util.Set;
43  
44  /**
45   * @since 3.0
46   * @author Benjamin Bentmann
47   * @author Jason van Zyl
48   * @author jdcasey
49   * @author Kristian Rosenvold (extracted class only)
50   *         <p/>
51   *         NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
52   */
53  @Component( role = LifeCyclePluginAnalyzer.class )
54  public class DefaultLifecyclePluginAnalyzer
55      implements LifeCyclePluginAnalyzer
56  {
57  
58      @Requirement( role = LifecycleMapping.class )
59      private Map<String, LifecycleMapping> lifecycleMappings;
60  
61      @Requirement
62      private DefaultLifecycles defaultLifeCycles;
63  
64      @Requirement
65      private Logger logger;
66  
67      public DefaultLifecyclePluginAnalyzer()
68      {
69      }
70  
71      // These methods deal with construction intact Plugin object that look like they come from a standard
72      // <plugin/> block in a Maven POM. We have to do some wiggling to pull the sources of information
73      // together and this really shows the problem of constructing a sensible default configuration but
74      // it's all encapsulated here so it appears normalized to the POM builder.
75  
76      // We are going to take the project packaging and find all plugin in the default lifecycle and create
77      // fully populated Plugin objects, including executions with goals and default configuration taken
78      // from the plugin.xml inside a plugin.
79      //
80  
81      public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles( String packaging )
82      {
83          if ( logger.isDebugEnabled() )
84          {
85              logger.debug( "Looking up lifecyle mappings for packaging " + packaging + " from "
86                  + Thread.currentThread().getContextClassLoader() );
87          }
88  
89          LifecycleMapping lifecycleMappingForPackaging = lifecycleMappings.get( packaging );
90  
91          if ( lifecycleMappingForPackaging == null )
92          {
93              return null;
94          }
95  
96          Map<Plugin, Plugin> plugins = new LinkedHashMap<>();
97  
98          for ( Lifecycle lifecycle : getOrderedLifecycles() )
99          {
100             org.apache.maven.lifecycle.mapping.Lifecycle lifecycleConfiguration =
101                 lifecycleMappingForPackaging.getLifecycles().get( lifecycle.getId() );
102 
103             Map<String, LifecyclePhase> phaseToGoalMapping = null;
104 
105             if ( lifecycleConfiguration != null )
106             {
107                 phaseToGoalMapping = lifecycleConfiguration.getLifecyclePhases();
108             }
109             else if ( lifecycle.getDefaultLifecyclePhases() != null )
110             {
111                 phaseToGoalMapping = lifecycle.getDefaultLifecyclePhases();
112             }
113 
114             if ( phaseToGoalMapping != null )
115             {
116                 for ( Map.Entry<String, LifecyclePhase> goalsForLifecyclePhase : phaseToGoalMapping.entrySet() )
117                 {
118                     String phase = goalsForLifecyclePhase.getKey();
119                     LifecyclePhase goals = goalsForLifecyclePhase.getValue();
120                     if ( goals != null )
121                     {
122                         parseLifecyclePhaseDefinitions( plugins, phase, goals );
123                     }
124                 }
125             }
126         }
127 
128         return plugins.keySet();
129     }
130 
131     private List<Lifecycle> getOrderedLifecycles()
132     {
133         // NOTE: The lifecycle order can affect implied execution ids so we better be deterministic.
134 
135         List<Lifecycle> lifecycles = new ArrayList<>( defaultLifeCycles.getLifeCycles() );
136 
137         Collections.sort( lifecycles, new Comparator<Lifecycle>()
138         {
139 
140             public int compare( Lifecycle l1, Lifecycle l2 )
141             {
142                 return l1.getId().compareTo( l2.getId() );
143             }
144 
145         } );
146 
147         return lifecycles;
148     }
149 
150     private void parseLifecyclePhaseDefinitions( Map<Plugin, Plugin> plugins, String phase, LifecyclePhase goals )
151     {
152         List<LifecycleMojo> mojos = goals.getMojos();
153         if ( mojos != null )
154         {
155             
156             for ( int i = 0; i < mojos.size(); i++ )
157             {
158                 LifecycleMojo mojo = mojos.get( i );
159                 
160                 GoalSpec gs = parseGoalSpec( mojo.getGoal() );
161     
162                 if ( gs == null )
163                 {
164                     logger.warn( "Ignored invalid goal specification '" + mojo.getGoal()
165                             + "' from lifecycle mapping for phase " + phase );
166                     continue;
167                 }
168     
169                 Plugin plugin = new Plugin();
170                 plugin.setGroupId( gs.groupId );
171                 plugin.setArtifactId( gs.artifactId );
172                 plugin.setVersion( gs.version );
173     
174                 Plugin existing = plugins.get( plugin );
175                 if ( existing != null )
176                 {
177                     if ( existing.getVersion() == null )
178                     {
179                         existing.setVersion( plugin.getVersion() );
180                     }
181                     plugin = existing;
182                 }
183                 else
184                 {
185                     plugins.put( plugin, plugin );
186                 }
187     
188                 PluginExecution execution = new PluginExecution();
189                 execution.setId( getExecutionId( plugin, gs.goal ) );
190                 execution.setPhase( phase );
191                 execution.setPriority( i - mojos.size() );
192                 execution.getGoals().add( gs.goal );
193                 execution.setConfiguration( mojo.getConfiguration() );
194                 
195                 plugin.setDependencies( mojo.getDependencies() );
196                 plugin.getExecutions().add( execution );
197             }
198         }
199     }
200 
201     private GoalSpec parseGoalSpec( String goalSpec )
202     {
203         GoalSpec gs = new GoalSpec();
204 
205         String[] p = StringUtils.split( goalSpec.trim(), ":" );
206 
207         if ( p.length == 3 )
208         {
209             // <groupId>:<artifactId>:<goal>
210             gs.groupId = p[0];
211             gs.artifactId = p[1];
212             gs.goal = p[2];
213         }
214         else if ( p.length == 4 )
215         {
216             // <groupId>:<artifactId>:<version>:<goal>
217             gs.groupId = p[0];
218             gs.artifactId = p[1];
219             gs.version = p[2];
220             gs.goal = p[3];
221         }
222         else
223         {
224             // invalid
225             gs = null;
226         }
227 
228         return gs;
229     }
230 
231     private String getExecutionId( Plugin plugin, String goal )
232     {
233         Set<String> existingIds = new HashSet<>();
234         for ( PluginExecution execution : plugin.getExecutions() )
235         {
236             existingIds.add( execution.getId() );
237         }
238 
239         String base = "default-" + goal;
240         String id = base;
241 
242         for ( int index = 1; existingIds.contains( id ); index++ )
243         {
244             id = base + '-' + index;
245         }
246 
247         return id;
248     }
249 
250     static class GoalSpec
251     {
252 
253         String groupId;
254 
255         String artifactId;
256 
257         String version;
258 
259         String goal;
260 
261     }
262 
263 }