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.ArrayList;
22  import java.util.Collection;
23  import java.util.StringTokenizer;
24  
25  import org.apache.maven.execution.MavenSession;
26  import org.apache.maven.model.Plugin;
27  import org.apache.maven.plugin.BuildPluginManager;
28  import org.apache.maven.plugin.InvalidPluginDescriptorException;
29  import org.apache.maven.plugin.MojoNotFoundException;
30  import org.apache.maven.plugin.PluginDescriptorParsingException;
31  import org.apache.maven.plugin.PluginNotFoundException;
32  import org.apache.maven.plugin.PluginResolutionException;
33  import org.apache.maven.plugin.descriptor.MojoDescriptor;
34  import org.apache.maven.plugin.prefix.DefaultPluginPrefixRequest;
35  import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
36  import org.apache.maven.plugin.prefix.PluginPrefixRequest;
37  import org.apache.maven.plugin.prefix.PluginPrefixResolver;
38  import org.apache.maven.plugin.prefix.PluginPrefixResult;
39  import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
40  import org.apache.maven.plugin.version.PluginVersionRequest;
41  import org.apache.maven.plugin.version.PluginVersionResolutionException;
42  import org.apache.maven.plugin.version.PluginVersionResolver;
43  import org.apache.maven.project.MavenProject;
44  import org.codehaus.plexus.component.annotations.Component;
45  import org.codehaus.plexus.component.annotations.Requirement;
46  import org.codehaus.plexus.configuration.PlexusConfiguration;
47  import org.codehaus.plexus.logging.Logger;
48  import org.codehaus.plexus.util.xml.Xpp3Dom;
49  
50  /**
51   * <p>
52   * Resolves dependencies for the artifacts in context of the lifecycle build
53   * </p>
54   * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
55   *
56   * @since 3.0
57   * @author Benjamin Bentmann
58   * @author Jason van Zyl
59   * @author jdcasey
60   * @author Kristian Rosenvold (extracted class only)
61   */
62  @Component(role = MojoDescriptorCreator.class)
63  public class MojoDescriptorCreator {
64  
65      @Requirement
66      private Logger logger;
67  
68      @Requirement
69      private PluginVersionResolver pluginVersionResolver;
70  
71      @Requirement
72      private BuildPluginManager pluginManager;
73  
74      @Requirement
75      private PluginPrefixResolver pluginPrefixResolver;
76  
77      @Requirement
78      private LifecyclePluginResolver lifecyclePluginResolver;
79  
80      public MojoDescriptorCreator() {}
81  
82      public MojoDescriptorCreator(
83              PluginVersionResolver pluginVersionResolver,
84              BuildPluginManager pluginManager,
85              PluginPrefixResolver pluginPrefixResolver,
86              LifecyclePluginResolver lifecyclePluginResolver) {
87          this.pluginVersionResolver = pluginVersionResolver;
88          this.pluginManager = pluginManager;
89          this.pluginPrefixResolver = pluginPrefixResolver;
90          this.lifecyclePluginResolver = lifecyclePluginResolver;
91      }
92  
93      private Plugin findPlugin(String groupId, String artifactId, Collection<Plugin> plugins) {
94          for (Plugin plugin : plugins) {
95              if (artifactId.equals(plugin.getArtifactId()) && groupId.equals(plugin.getGroupId())) {
96                  return plugin;
97              }
98          }
99  
100         return null;
101     }
102 
103     public static Xpp3Dom convert(MojoDescriptor mojoDescriptor) {
104         Xpp3Dom dom = new Xpp3Dom("configuration");
105 
106         PlexusConfiguration c = mojoDescriptor.getMojoConfiguration();
107 
108         PlexusConfiguration[] ces = c.getChildren();
109 
110         if (ces != null) {
111             for (PlexusConfiguration ce : ces) {
112                 String value = ce.getValue(null);
113                 String defaultValue = ce.getAttribute("default-value", null);
114                 if (value != null || defaultValue != null) {
115                     Xpp3Dom e = new Xpp3Dom(ce.getName());
116                     e.setValue(value);
117                     if (defaultValue != null) {
118                         e.setAttribute("default-value", defaultValue);
119                     }
120                     dom.addChild(e);
121                 }
122             }
123         }
124 
125         return dom;
126     }
127 
128     // org.apache.maven.plugins:maven-remote-resources-plugin:1.0:process@executionId
129 
130     public MojoDescriptor getMojoDescriptor(String task, MavenSession session, MavenProject project)
131             throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
132                     MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
133                     PluginVersionResolutionException {
134         String goal = null;
135 
136         Plugin plugin = null;
137 
138         StringTokenizer tok = new StringTokenizer(task, ":");
139 
140         int numTokens = tok.countTokens();
141 
142         if (numTokens >= 4) {
143             // We have everything that we need
144             //
145             // org.apache.maven.plugins:maven-remote-resources-plugin:1.0:process
146             //
147             // groupId
148             // artifactId
149             // version
150             // goal
151             //
152             plugin = new Plugin();
153             plugin.setGroupId(tok.nextToken());
154             plugin.setArtifactId(tok.nextToken());
155             plugin.setVersion(tok.nextToken());
156             goal = tok.nextToken();
157 
158             // This won't be valid, but it constructs something easy to read in the error message
159             while (tok.hasMoreTokens()) {
160                 goal += ":" + tok.nextToken();
161             }
162         } else if (numTokens == 3) {
163             // groupId:artifactId:goal or pluginPrefix:version:goal (since Maven 3.9.0)
164 
165             String firstToken = tok.nextToken();
166             // groupId or pluginPrefix? heuristics: groupId contains dot (.) but not pluginPrefix
167             if (firstToken.contains(".")) {
168                 // We have everything that we need except the version
169                 //
170                 // org.apache.maven.plugins:maven-remote-resources-plugin:???:process
171                 //
172                 // groupId
173                 // artifactId
174                 // ???
175                 // goal
176                 //
177                 plugin = new Plugin();
178                 plugin.setGroupId(firstToken);
179                 plugin.setArtifactId(tok.nextToken());
180             } else {
181                 // pluginPrefix:version:goal, like remote-resources:3.5.0:process
182                 plugin = findPluginForPrefix(firstToken, session);
183                 plugin.setVersion(tok.nextToken());
184             }
185             goal = tok.nextToken();
186         } else if (numTokens <= 2) {
187             // We have a prefix and goal
188             //
189             // idea:idea
190             //
191             String prefix = tok.nextToken();
192 
193             if (numTokens == 2) {
194                 goal = tok.nextToken();
195             } else {
196                 // goal was missing - pass through to MojoNotFoundException
197                 goal = "";
198             }
199 
200             // This is the case where someone has executed a single goal from the command line
201             // of the form:
202             //
203             // mvn remote-resources:process
204             //
205             // From the metadata stored on the server which has been created as part of a standard
206             // Maven plugin deployment we will find the right PluginDescriptor from the remote
207             // repository.
208 
209             plugin = findPluginForPrefix(prefix, session);
210         }
211 
212         int executionIdx = goal.indexOf('@');
213         if (executionIdx > 0) {
214             goal = goal.substring(0, executionIdx);
215         }
216 
217         injectPluginDeclarationFromProject(plugin, project);
218 
219         // If there is no version to be found then we need to look in the repository metadata for
220         // this plugin and see what's specified as the latest release.
221         //
222         if (plugin.getVersion() == null) {
223             resolvePluginVersion(plugin, session, project);
224         }
225 
226         return pluginManager.getMojoDescriptor(
227                 plugin, goal, project.getRemotePluginRepositories(), session.getRepositorySession());
228     }
229 
230     // TODO take repo mans into account as one may be aggregating prefixes of many
231     // TODO collect at the root of the repository, read the one at the root, and fetch remote if something is missing
232     // or the user forces the issue
233 
234     public Plugin findPluginForPrefix(String prefix, MavenSession session) throws NoPluginFoundForPrefixException {
235         // [prefix]:[goal]
236 
237         if (session.getCurrentProject() != null) {
238             try {
239                 lifecyclePluginResolver.resolveMissingPluginVersions(session.getCurrentProject(), session);
240             } catch (PluginVersionResolutionException e) {
241                 // not critical here
242                 logger.debug(e.getMessage(), e);
243             }
244         }
245 
246         PluginPrefixRequest prefixRequest = new DefaultPluginPrefixRequest(prefix, session);
247         PluginPrefixResult prefixResult = pluginPrefixResolver.resolve(prefixRequest);
248 
249         Plugin plugin = new Plugin();
250         plugin.setGroupId(prefixResult.getGroupId());
251         plugin.setArtifactId(prefixResult.getArtifactId());
252 
253         return plugin;
254     }
255 
256     private void resolvePluginVersion(Plugin plugin, MavenSession session, MavenProject project)
257             throws PluginVersionResolutionException {
258         PluginVersionRequest versionRequest = new DefaultPluginVersionRequest(
259                 plugin, session.getRepositorySession(), project.getRemotePluginRepositories());
260         plugin.setVersion(pluginVersionResolver.resolve(versionRequest).getVersion());
261     }
262 
263     private void injectPluginDeclarationFromProject(Plugin plugin, MavenProject project) {
264         Plugin pluginInPom = findPlugin(plugin, project.getBuildPlugins());
265 
266         if (pluginInPom == null && project.getPluginManagement() != null) {
267             pluginInPom = findPlugin(plugin, project.getPluginManagement().getPlugins());
268         }
269 
270         if (pluginInPom != null) {
271             if (plugin.getVersion() == null) {
272                 plugin.setVersion(pluginInPom.getVersion());
273             }
274 
275             plugin.setDependencies(new ArrayList<>(pluginInPom.getDependencies()));
276         }
277     }
278 
279     private Plugin findPlugin(Plugin plugin, Collection<Plugin> plugins) {
280         return findPlugin(plugin.getGroupId(), plugin.getArtifactId(), plugins);
281     }
282 }