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