View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.lifecycle.internal;
20  
21  import java.util.HashSet;
22  import java.util.LinkedHashMap;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Set;
26  
27  import org.apache.maven.lifecycle.DefaultLifecycles;
28  import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer;
29  import org.apache.maven.lifecycle.Lifecycle;
30  import org.apache.maven.lifecycle.mapping.LifecycleMapping;
31  import org.apache.maven.lifecycle.mapping.LifecycleMojo;
32  import org.apache.maven.lifecycle.mapping.LifecyclePhase;
33  import org.apache.maven.model.InputLocation;
34  import org.apache.maven.model.InputSource;
35  import org.apache.maven.model.Plugin;
36  import org.apache.maven.model.PluginExecution;
37  import org.codehaus.plexus.component.annotations.Component;
38  import org.codehaus.plexus.component.annotations.Requirement;
39  import org.codehaus.plexus.logging.Logger;
40  import org.codehaus.plexus.util.StringUtils;
41  import org.codehaus.plexus.util.xml.Xpp3Dom;
42  
43  /**
44   * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
45   *
46   * @since 3.0
47   * @author Benjamin Bentmann
48   * @author Jason van Zyl
49   * @author jdcasey
50   * @author Kristian Rosenvold (extracted class only)
51   */
52  @Component(role = LifeCyclePluginAnalyzer.class)
53  public class DefaultLifecyclePluginAnalyzer implements LifeCyclePluginAnalyzer {
54  
55      @Requirement(role = LifecycleMapping.class)
56      private Map<String, LifecycleMapping> lifecycleMappings;
57  
58      @Requirement
59      private DefaultLifecycles defaultLifeCycles;
60  
61      @Requirement
62      private Logger logger;
63  
64      public DefaultLifecyclePluginAnalyzer() {}
65  
66      // These methods deal with construction intact Plugin object that look like they come from a standard
67      // <plugin/> block in a Maven POM. We have to do some wiggling to pull the sources of information
68      // together and this really shows the problem of constructing a sensible default configuration but
69      // it's all encapsulated here so it appears normalized to the POM builder.
70  
71      // We are going to take the project packaging and find all plugins in the default lifecycle and create
72      // fully populated Plugin objects, including executions with goals and default configuration taken
73      // from the plugin.xml inside a plugin.
74      //
75  
76      public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging) {
77          if (logger.isDebugEnabled()) {
78              logger.debug("Looking up lifecycle mappings for packaging " + packaging + " from "
79                      + Thread.currentThread().getContextClassLoader());
80          }
81  
82          LifecycleMapping lifecycleMappingForPackaging = lifecycleMappings.get(packaging);
83  
84          if (lifecycleMappingForPackaging == null) {
85              return null;
86          }
87  
88          Map<Plugin, Plugin> plugins = new LinkedHashMap<>();
89  
90          for (Lifecycle lifecycle : defaultLifeCycles.getLifeCycles()) {
91              org.apache.maven.lifecycle.mapping.Lifecycle lifecycleConfiguration =
92                      lifecycleMappingForPackaging.getLifecycles().get(lifecycle.getId());
93  
94              Map<String, LifecyclePhase> phaseToGoalMapping = null;
95  
96              if (lifecycleConfiguration != null) {
97                  phaseToGoalMapping = lifecycleConfiguration.getLifecyclePhases();
98              } else if (lifecycle.getDefaultLifecyclePhases() != null) {
99                  phaseToGoalMapping = lifecycle.getDefaultLifecyclePhases();
100             }
101 
102             if (phaseToGoalMapping != null) {
103                 for (Map.Entry<String, LifecyclePhase> goalsForLifecyclePhase : phaseToGoalMapping.entrySet()) {
104                     String phase = goalsForLifecyclePhase.getKey();
105                     LifecyclePhase goals = goalsForLifecyclePhase.getValue();
106                     if (goals != null) {
107                         parseLifecyclePhaseDefinitions(plugins, phase, goals);
108                     }
109                 }
110             }
111         }
112 
113         return plugins.keySet();
114     }
115 
116     private void parseLifecyclePhaseDefinitions(Map<Plugin, Plugin> plugins, String phase, LifecyclePhase goals) {
117         String modelId = "org.apache.maven:maven-core:"
118                 + this.getClass().getPackage().getImplementationVersion() + ":default-lifecycle-bindings";
119         InputSource inputSource = new InputSource();
120         inputSource.setModelId(modelId);
121         InputLocation location = new InputLocation(-1, -1, inputSource);
122         location.setLocation(0, location);
123 
124         List<LifecycleMojo> mojos = goals.getMojos();
125         if (mojos != null) {
126 
127             for (int i = 0; i < mojos.size(); i++) {
128                 LifecycleMojo mojo = mojos.get(i);
129 
130                 GoalSpec gs = parseGoalSpec(mojo.getGoal());
131 
132                 if (gs == null) {
133                     logger.warn("Ignored invalid goal specification '" + mojo.getGoal()
134                             + "' from lifecycle mapping for phase " + phase);
135                     continue;
136                 }
137 
138                 Plugin plugin = new Plugin();
139                 plugin.setGroupId(gs.groupId);
140                 plugin.setArtifactId(gs.artifactId);
141                 plugin.setVersion(gs.version);
142 
143                 plugin.setLocation("", location);
144                 plugin.setLocation("groupId", location);
145                 plugin.setLocation("artifactId", location);
146                 plugin.setLocation("version", location);
147 
148                 Plugin existing = plugins.get(plugin);
149                 if (existing != null) {
150                     if (existing.getVersion() == null) {
151                         existing.setVersion(plugin.getVersion());
152                         existing.setLocation("version", location);
153                     }
154                     plugin = existing;
155                 } else {
156                     plugins.put(plugin, plugin);
157                 }
158 
159                 PluginExecution execution = new PluginExecution();
160                 execution.setId(getExecutionId(plugin, gs.goal));
161                 execution.setPhase(phase);
162                 execution.setPriority(i - mojos.size());
163                 execution.getGoals().add(gs.goal);
164 
165                 execution.setLocation("", location);
166                 execution.setLocation("id", location);
167                 execution.setLocation("phase", location);
168                 execution.setLocation("goals", location);
169 
170                 Xpp3Dom lifecycleConfiguration = mojo.getConfiguration();
171                 if (lifecycleConfiguration != null) {
172                     execution.setConfiguration(new Xpp3Dom(lifecycleConfiguration));
173                 }
174 
175                 plugin.setDependencies(mojo.getDependencies());
176                 plugin.getExecutions().add(execution);
177             }
178         }
179     }
180 
181     private GoalSpec parseGoalSpec(String goalSpec) {
182         GoalSpec gs = new GoalSpec();
183 
184         String[] p = StringUtils.split(goalSpec.trim(), ":");
185 
186         if (p.length == 3) {
187             // <groupId>:<artifactId>:<goal>
188             gs.groupId = p[0];
189             gs.artifactId = p[1];
190             gs.goal = p[2];
191         } else if (p.length == 4) {
192             // <groupId>:<artifactId>:<version>:<goal>
193             gs.groupId = p[0];
194             gs.artifactId = p[1];
195             gs.version = p[2];
196             gs.goal = p[3];
197         } else {
198             // invalid
199             gs = null;
200         }
201 
202         return gs;
203     }
204 
205     private String getExecutionId(Plugin plugin, String goal) {
206         Set<String> existingIds = new HashSet<>();
207         for (PluginExecution execution : plugin.getExecutions()) {
208             existingIds.add(execution.getId());
209         }
210 
211         String base = "default-" + goal;
212         String id = base;
213 
214         for (int index = 1; existingIds.contains(id); index++) {
215             id = base + '-' + index;
216         }
217 
218         return id;
219     }
220 
221     static class GoalSpec {
222 
223         String groupId;
224 
225         String artifactId;
226 
227         String version;
228 
229         String goal;
230     }
231 }