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