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