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