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