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