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