View Javadoc
1   package org.apache.maven.plugins.dependency.fromConfiguration;
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.io.File;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.Objects;
26  
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.artifact.handler.ArtifactHandler;
29  import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
30  import org.apache.maven.model.Dependency;
31  import org.apache.maven.plugin.MojoExecutionException;
32  import org.apache.maven.plugin.MojoFailureException;
33  import org.apache.maven.plugins.annotations.Component;
34  import org.apache.maven.plugins.annotations.Parameter;
35  import org.apache.maven.plugins.dependency.AbstractDependencyMojo;
36  import org.apache.maven.plugins.dependency.utils.DependencyUtil;
37  import org.apache.maven.plugins.dependency.utils.filters.ArtifactItemFilter;
38  import org.apache.maven.project.MavenProject;
39  import org.apache.maven.project.ProjectBuildingRequest;
40  import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
41  import org.apache.maven.shared.transfer.artifact.DefaultArtifactCoordinate;
42  import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolver;
43  import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolverException;
44  import org.apache.maven.shared.transfer.repository.RepositoryManager;
45  import org.codehaus.plexus.util.StringUtils;
46  
47  /**
48   * Abstract parent class used by mojos that get Artifact information from the plugin configuration as an ArrayList of
49   * ArtifactItems
50   *
51   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
52   * @see ArtifactItem
53   */
54  public abstract class AbstractFromConfigurationMojo
55      extends AbstractDependencyMojo
56  {
57      /**
58       * Default output location used for mojo, unless overridden in ArtifactItem.
59       *
60       * @since 1.0
61       */
62      @Parameter( property = "outputDirectory", defaultValue = "${project.build.directory}/dependency" )
63      private File outputDirectory;
64  
65      /**
66       * Overwrite release artifacts
67       *
68       * @since 1.0
69       */
70      @Parameter( property = "mdep.overWriteReleases", defaultValue = "false" )
71      private boolean overWriteReleases;
72  
73      /**
74       * Overwrite snapshot artifacts
75       *
76       * @since 1.0
77       */
78      @Parameter( property = "mdep.overWriteSnapshots", defaultValue = "false" )
79      private boolean overWriteSnapshots;
80  
81      /**
82       * Overwrite if newer
83       *
84       * @since 2.0
85       */
86      @Parameter( property = "mdep.overIfNewer", defaultValue = "true" )
87      private boolean overWriteIfNewer;
88  
89      /**
90       * Collection of ArtifactItems to work on. (ArtifactItem contains groupId, artifactId, version, type, classifier,
91       * outputDirectory, destFileName, overWrite and encoding.) See <a href="./usage.html">Usage</a> for details.
92       *
93       * @since 1.0
94       */
95      @Parameter
96      private List<ArtifactItem> artifactItems;
97  
98      /**
99       * Path to override default local repository during plugin's execution. To remove all downloaded artifacts as part
100      * of the build, set this value to a location under your project's target directory
101      *
102      * @since 2.2
103      */
104     @Parameter
105     private File localRepositoryDirectory;
106 
107     @Component
108     private ArtifactResolver artifactResolver;
109 
110     @Component
111     private RepositoryManager repositoryManager;
112 
113     @Component
114     private ArtifactHandlerManager artifactHandlerManager;
115 
116     abstract ArtifactItemFilter getMarkedArtifactFilter( ArtifactItem item );
117 
118     /**
119      * artifactItems is filled by either field injection or by setArtifact().
120      * 
121      * @throws MojoFailureException in case of an error.
122      */
123     protected void verifyRequirements()
124         throws MojoFailureException
125     {
126         if ( artifactItems == null || artifactItems.isEmpty() )
127         {
128             throw new MojoFailureException( "Either artifact or artifactItems is required " );
129         }
130     }
131 
132     /**
133      * Preprocesses the list of ArtifactItems. This method defaults the outputDirectory if not set and creates the
134      * output Directory if it doesn't exist.
135      *
136      * @param processArtifactItemsRequest preprocessing instructions
137      * @return An ArrayList of preprocessed ArtifactItems
138      * @throws MojoExecutionException with a message if an error occurs.
139      * @see ArtifactItem
140      */
141     protected List<ArtifactItem> getProcessedArtifactItems( ProcessArtifactItemsRequest processArtifactItemsRequest )
142         throws MojoExecutionException
143     {
144 
145         boolean removeVersion = processArtifactItemsRequest.isRemoveVersion(),
146                         prependGroupId = processArtifactItemsRequest.isPrependGroupId(),
147                         useBaseVersion = processArtifactItemsRequest.isUseBaseVersion();
148 
149         boolean removeClassifier = processArtifactItemsRequest.isRemoveClassifier();
150 
151         if ( artifactItems == null || artifactItems.size() < 1 )
152         {
153             throw new MojoExecutionException( "There are no artifactItems configured." );
154         }
155 
156         for ( ArtifactItem artifactItem : artifactItems )
157         {
158             this.getLog().info( "Configured Artifact: " + artifactItem.toString() );
159 
160             if ( artifactItem.getOutputDirectory() == null )
161             {
162                 artifactItem.setOutputDirectory( this.outputDirectory );
163             }
164             artifactItem.getOutputDirectory().mkdirs();
165 
166             // make sure we have a version.
167             if ( StringUtils.isEmpty( artifactItem.getVersion() ) )
168             {
169                 fillMissingArtifactVersion( artifactItem );
170             }
171 
172             artifactItem.setArtifact( this.getArtifact( artifactItem ) );
173 
174             if ( StringUtils.isEmpty( artifactItem.getDestFileName() ) )
175             {
176                 artifactItem.setDestFileName( DependencyUtil.getFormattedFileName( artifactItem.getArtifact(),
177                                                                                    removeVersion, prependGroupId,
178                                                                                    useBaseVersion, removeClassifier ) );
179             }
180 
181             try
182             {
183                 artifactItem.setNeedsProcessing( checkIfProcessingNeeded( artifactItem ) );
184             }
185             catch ( ArtifactFilterException e )
186             {
187                 throw new MojoExecutionException( e.getMessage(), e );
188             }
189         }
190         return artifactItems;
191     }
192 
193     private boolean checkIfProcessingNeeded( ArtifactItem item )
194         throws MojoExecutionException, ArtifactFilterException
195     {
196         return StringUtils.equalsIgnoreCase( item.getOverWrite(), "true" )
197             || getMarkedArtifactFilter( item ).isArtifactIncluded( item );
198     }
199 
200     /**
201      * Resolves the Artifact from the remote repository if necessary. If no version is specified, it will be retrieved
202      * from the dependency list or from the DependencyManagement section of the pom.
203      *
204      * @param artifactItem containing information about artifact from plugin configuration.
205      * @return Artifact object representing the specified file.
206      * @throws MojoExecutionException with a message if the version can't be found in DependencyManagement.
207      */
208     protected Artifact getArtifact( ArtifactItem artifactItem )
209         throws MojoExecutionException
210     {
211         Artifact artifact;
212 
213         try
214         {
215             // mdep-50 - rolledback for now because it's breaking some functionality.
216             /*
217              * List listeners = new ArrayList(); Set theSet = new HashSet(); theSet.add( artifact );
218              * ArtifactResolutionResult artifactResolutionResult = artifactCollector.collect( theSet, project
219              * .getArtifact(), managedVersions, this.local, project.getRemoteArtifactRepositories(),
220              * artifactMetadataSource, null, listeners ); Iterator iter =
221              * artifactResolutionResult.getArtifactResolutionNodes().iterator(); while ( iter.hasNext() ) {
222              * ResolutionNode node = (ResolutionNode) iter.next(); artifact = node.getArtifact(); }
223              */
224 
225             ProjectBuildingRequest buildingRequest = newResolveArtifactProjectBuildingRequest();
226 
227             if ( localRepositoryDirectory != null )
228             {
229                 buildingRequest =
230                     repositoryManager.setLocalRepositoryBasedir( buildingRequest, localRepositoryDirectory );
231             }
232 
233             // Map dependency to artifact coordinate
234             DefaultArtifactCoordinate coordinate = new DefaultArtifactCoordinate();
235             coordinate.setGroupId( artifactItem.getGroupId() );
236             coordinate.setArtifactId( artifactItem.getArtifactId() );
237             coordinate.setVersion( artifactItem.getVersion() );
238             coordinate.setClassifier( artifactItem.getClassifier() );
239 
240             final String extension;
241             ArtifactHandler artifactHandler = artifactHandlerManager.getArtifactHandler( artifactItem.getType() );
242             if ( artifactHandler != null )
243             {
244                 extension = artifactHandler.getExtension();
245             }
246             else
247             {
248                 extension = artifactItem.getType();
249             }
250             coordinate.setExtension( extension );
251 
252             artifact = artifactResolver.resolveArtifact( buildingRequest, coordinate ).getArtifact();
253         }
254         catch ( ArtifactResolverException e )
255         {
256             throw new MojoExecutionException( "Unable to find/resolve artifact.", e );
257         }
258 
259         return artifact;
260     }
261 
262     /**
263      * Tries to find missing version from dependency list and dependency management. If found, the artifact is updated
264      * with the correct version. It will first look for an exact match on artifactId/groupId/classifier/type and if it
265      * doesn't find a match, it will try again looking for artifactId and groupId only.
266      *
267      * @param artifact representing configured file.
268      * @throws MojoExecutionException
269      */
270     private void fillMissingArtifactVersion( ArtifactItem artifact )
271         throws MojoExecutionException
272     {
273         MavenProject project = getProject();
274         List<Dependency> deps = project.getDependencies();
275         List<Dependency> depMngt = project.getDependencyManagement() == null ? Collections.<Dependency>emptyList()
276                         : project.getDependencyManagement().getDependencies();
277 
278         if ( !findDependencyVersion( artifact, deps, false )
279             && ( project.getDependencyManagement() == null || !findDependencyVersion( artifact, depMngt, false ) )
280             && !findDependencyVersion( artifact, deps, true )
281             && ( project.getDependencyManagement() == null || !findDependencyVersion( artifact, depMngt, true ) ) )
282         {
283             throw new MojoExecutionException( "Unable to find artifact version of " + artifact.getGroupId() + ":"
284                 + artifact.getArtifactId() + " in either dependency list or in project's dependency management." );
285         }
286     }
287 
288     /**
289      * Tries to find missing version from a list of dependencies. If found, the artifact is updated with the correct
290      * version.
291      *
292      * @param artifact representing configured file.
293      * @param dependencies list of dependencies to search.
294      * @param looseMatch only look at artifactId and groupId
295      * @return the found dependency
296      */
297     private boolean findDependencyVersion( ArtifactItem artifact, List<Dependency> dependencies, boolean looseMatch )
298     {
299         for ( Dependency dependency : dependencies )
300         {
301             if ( Objects.equals( dependency.getArtifactId(), artifact.getArtifactId() )
302                 && Objects.equals( dependency.getGroupId(), artifact.getGroupId() )
303                 && ( looseMatch || Objects.equals( dependency.getClassifier(), artifact.getClassifier() ) )
304                 && ( looseMatch || Objects.equals( dependency.getType(), artifact.getType() ) ) )
305             {
306                 artifact.setVersion( dependency.getVersion() );
307 
308                 return true;
309             }
310         }
311 
312         return false;
313     }
314 
315     /**
316      * @return Returns the artifactItems.
317      */
318     public List<ArtifactItem> getArtifactItems()
319     {
320         return this.artifactItems;
321     }
322 
323     /**
324      * @param theArtifactItems The artifactItems to set.
325      */
326     public void setArtifactItems( List<ArtifactItem> theArtifactItems )
327     {
328         this.artifactItems = theArtifactItems;
329     }
330 
331     /**
332      * @return Returns the outputDirectory.
333      */
334     public File getOutputDirectory()
335     {
336         return this.outputDirectory;
337     }
338 
339     /**
340      * @param theOutputDirectory The outputDirectory to set.
341      */
342     public void setOutputDirectory( File theOutputDirectory )
343     {
344         this.outputDirectory = theOutputDirectory;
345     }
346 
347     /**
348      * @return Returns the overWriteIfNewer.
349      */
350     public boolean isOverWriteIfNewer()
351     {
352         return this.overWriteIfNewer;
353     }
354 
355     /**
356      * @param theOverWriteIfNewer The overWriteIfNewer to set.
357      */
358     public void setOverWriteIfNewer( boolean theOverWriteIfNewer )
359     {
360         this.overWriteIfNewer = theOverWriteIfNewer;
361     }
362 
363     /**
364      * @return Returns the overWriteReleases.
365      */
366     public boolean isOverWriteReleases()
367     {
368         return this.overWriteReleases;
369     }
370 
371     /**
372      * @param theOverWriteReleases The overWriteReleases to set.
373      */
374     public void setOverWriteReleases( boolean theOverWriteReleases )
375     {
376         this.overWriteReleases = theOverWriteReleases;
377     }
378 
379     /**
380      * @return Returns the overWriteSnapshots.
381      */
382     public boolean isOverWriteSnapshots()
383     {
384         return this.overWriteSnapshots;
385     }
386 
387     /**
388      * @param theOverWriteSnapshots The overWriteSnapshots to set.
389      */
390     public void setOverWriteSnapshots( boolean theOverWriteSnapshots )
391     {
392         this.overWriteSnapshots = theOverWriteSnapshots;
393     }
394 
395     /**
396      * @param localRepositoryDirectory {@link #localRepositoryDirectory}
397      */
398     public void setLocalRepositoryDirectory( File localRepositoryDirectory )
399     {
400         this.localRepositoryDirectory = localRepositoryDirectory;
401     }
402 
403     /**
404      * @param artifact The artifact.
405      * @throws MojoFailureException in case of an error.
406      */
407     public void setArtifact( String artifact )
408         throws MojoFailureException
409     {
410         if ( artifact != null )
411         {
412             String packaging = "jar";
413             String classifier;
414             String[] tokens = StringUtils.split( artifact, ":" );
415             if ( tokens.length < 3 || tokens.length > 5 )
416             {
417                 throw new MojoFailureException( "Invalid artifact, "
418                     + "you must specify groupId:artifactId:version[:packaging[:classifier]] " + artifact );
419             }
420             String groupId = tokens[0];
421             String artifactId = tokens[1];
422             String version = tokens[2];
423             if ( tokens.length >= 4 )
424             {
425                 packaging = tokens[3];
426             }
427             if ( tokens.length == 5 )
428             {
429                 classifier = tokens[4];
430             }
431             else
432             {
433                 classifier = null;
434             }
435 
436             ArtifactItem artifactItem = new ArtifactItem();
437             artifactItem.setGroupId( groupId );
438             artifactItem.setArtifactId( artifactId );
439             artifactItem.setVersion( version );
440             artifactItem.setType( packaging );
441             artifactItem.setClassifier( classifier );
442 
443             setArtifactItems( Collections.singletonList( artifactItem ) );
444         }
445     }
446 }