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