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