View Javadoc

1   package org.apache.maven.plugin.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 org.apache.maven.artifact.Artifact;
23  import org.apache.maven.artifact.repository.ArtifactRepository;
24  import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
25  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
26  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
27  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
28  import org.apache.maven.artifact.versioning.VersionRange;
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.plugin.dependency.AbstractDependencyMojo;
33  import org.apache.maven.plugin.dependency.utils.DependencyUtil;
34  import org.apache.maven.plugin.dependency.utils.filters.ArtifactItemFilter;
35  import org.apache.maven.plugins.annotations.Component;
36  import org.apache.maven.plugins.annotations.Parameter;
37  import org.apache.maven.project.MavenProject;
38  import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
39  import org.codehaus.plexus.util.StringUtils;
40  
41  import java.io.File;
42  import java.util.Collections;
43  import java.util.List;
44  import java.util.Set;
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   * @version $Id: AbstractFromConfigurationMojo.html 861760 2013-05-12 17:31:26Z hboutemy $
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 and overWrite.) 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       * To look up ArtifactRepository implementation
100      */
101     @Component
102     private ArtifactRepositoryFactory artifactRepositoryManager;
103 
104     /**
105      * Path to override default local repository during plugin's execution. To remove all downloaded artifacts as part
106      * of the build, set this value to a location under your project's target directory
107      *
108      * @since 2.2
109      */
110     @Parameter
111     private File localRepositoryDirectory;
112 
113     /**
114      * To host and cache localRepositoryDirectory
115      */
116     private ArtifactRepository overrideLocalRepository;
117 
118     abstract ArtifactItemFilter getMarkedArtifactFilter( ArtifactItem item );
119     
120     // artifactItems is filled by either field injection or by setArtifact()
121     protected void verifyRequirements() throws MojoFailureException
122     {
123         if ( artifactItems == null || artifactItems.isEmpty() )
124         {
125             throw new MojoFailureException( "Either artifact or artifactItems is required " );
126         }
127     }
128 
129     /**
130      * Preprocesses the list of ArtifactItems. This method defaults the outputDirectory if not set and creates the
131      * output Directory if it doesn't exist.
132      *
133      * @param removeVersion remove the version from the filename.
134      * @param prependGroupId prepend the groupId to the filename.
135      * @param useBaseVersion use the baseVersion of the artifact instead of version for the filename.
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(), prependGroupId =
145             processArtifactItemsRequest.isPrependGroupId(), useBaseVersion =
146             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         // Map managedVersions = createManagedVersionMap( factory, project.getId(), project.getDependencyManagement() );
213         VersionRange vr;
214         try
215         {
216             vr = VersionRange.createFromVersionSpec( artifactItem.getVersion() );
217         }
218         catch ( InvalidVersionSpecificationException e1 )
219         {
220             // TODO Auto-generated catch block
221             e1.printStackTrace();
222             vr = VersionRange.createFromVersion( artifactItem.getVersion() );
223         }
224 
225         if ( StringUtils.isEmpty( artifactItem.getClassifier() ) )
226         {
227             artifact = factory.createDependencyArtifact( artifactItem.getGroupId(), artifactItem.getArtifactId(), vr,
228                                                          artifactItem.getType(), null, Artifact.SCOPE_COMPILE );
229         }
230         else
231         {
232             artifact = factory.createDependencyArtifact( artifactItem.getGroupId(), artifactItem.getArtifactId(), vr,
233                                                          artifactItem.getType(), artifactItem.getClassifier(),
234                                                          Artifact.SCOPE_COMPILE );
235         }
236 
237         // Maven 3 will search the reactor for the artifact but Maven 2 does not
238         // to keep consistent behaviour, we search the reactor ourselves.
239         Artifact result = getArtifactFomReactor( artifact );
240         if ( result != null )
241         {
242             return result;
243         }
244 
245         try
246         {
247             // mdep-50 - rolledback for now because it's breaking some functionality.
248             /*
249              * List listeners = new ArrayList(); Set theSet = new HashSet(); theSet.add( artifact );
250              * ArtifactResolutionResult artifactResolutionResult = artifactCollector.collect( theSet, project
251              * .getArtifact(), managedVersions, this.local, project.getRemoteArtifactRepositories(),
252              * artifactMetadataSource, null, listeners ); Iterator iter =
253              * artifactResolutionResult.getArtifactResolutionNodes().iterator(); while ( iter.hasNext() ) {
254              * ResolutionNode node = (ResolutionNode) iter.next(); artifact = node.getArtifact(); }
255              */
256 
257             resolver.resolve( artifact, remoteRepos, getLocal() );
258         }
259         catch ( ArtifactResolutionException e )
260         {
261             throw new MojoExecutionException( "Unable to resolve artifact.", e );
262         }
263         catch ( ArtifactNotFoundException e )
264         {
265             throw new MojoExecutionException( "Unable to find artifact.", e );
266         }
267 
268         return artifact;
269     }
270 
271     /**
272      * Checks to see if the specified artifact is available from the reactor.
273      *
274      * @param artifact The artifact we are looking for.
275      * @return The resolved artifact that is the same as the one we were looking for or <code>null</code> if one could
276      *         not be found.
277      */
278     private Artifact getArtifactFomReactor( Artifact artifact )
279     {
280         // check project dependencies first off
281         for ( Artifact a : (Set<Artifact>) project.getArtifacts() )
282         {
283             if ( equals( artifact, a ) && hasFile( a ) )
284             {
285                 return a;
286             }
287         }
288 
289         // check reactor projects
290         for ( MavenProject p : reactorProjects == null ? Collections.<MavenProject>emptyList() : reactorProjects )
291         {
292             // check the main artifact
293             if ( equals( artifact, p.getArtifact() ) && hasFile( p.getArtifact() ) )
294             {
295                 return p.getArtifact();
296             }
297 
298             // check any side artifacts
299             for ( Artifact a : (List<Artifact>) p.getAttachedArtifacts() )
300             {
301                 if ( equals( artifact, a ) && hasFile( a ) )
302                 {
303                     return a;
304                 }
305             }
306         }
307 
308         // not available
309         return null;
310     }
311 
312     /**
313      * Returns <code>true</code> if the artifact has a file.
314      *
315      * @param artifact the artifact (may be null)
316      * @return <code>true</code> if and only if the artifact is non-null and has a file.
317      */
318     private static boolean hasFile( Artifact artifact )
319     {
320         return artifact != null && artifact.getFile() != null && artifact.getFile().isFile();
321     }
322 
323     /**
324      * Null-safe compare of two artifacts based on groupId, artifactId, version, type and classifier.
325      *
326      * @param a the first artifact.
327      * @param b the second artifact.
328      * @return <code>true</code> if and only if the two artifacts have the same groupId, artifactId, version,
329      *         type and classifier.
330      */
331     private static boolean equals( Artifact a, Artifact b )
332     {
333         return a == b || !( a == null || b == null )
334             && StringUtils.equals( a.getGroupId(), b.getGroupId() )
335             && StringUtils.equals( a.getArtifactId(), b.getArtifactId() )
336             && StringUtils.equals( a.getVersion(), b.getVersion() )
337             && StringUtils.equals( a.getType(), b.getType() )
338             && StringUtils.equals( a.getClassifier(), b.getClassifier() );
339     }
340 
341     /**
342      * Tries to find missing version from dependency list and dependency management. If found, the artifact is updated
343      * with the correct version. It will first look for an exact match on artifactId/groupId/classifier/type and if it
344      * doesn't find a match, it will try again looking for artifactId and groupId only.
345      *
346      * @param artifact representing configured file.
347      * @throws MojoExecutionException
348      */
349     private void fillMissingArtifactVersion( ArtifactItem artifact )
350         throws MojoExecutionException
351     {
352         @SuppressWarnings( "unchecked" ) List<Dependency> deps = project.getDependencies();
353         @SuppressWarnings( "unchecked" ) List<Dependency> depMngt = project.getDependencyManagement() == null
354             ? Collections.<Dependency>emptyList()
355             : project.getDependencyManagement().getDependencies();
356 
357         if ( !findDependencyVersion( artifact, deps, false )
358             && ( project.getDependencyManagement() == null || !findDependencyVersion( artifact, depMngt, false ) )
359             && !findDependencyVersion( artifact, deps, true )
360             && ( project.getDependencyManagement() == null || !findDependencyVersion( artifact, depMngt, true ) ) )
361         {
362             throw new MojoExecutionException(
363                 "Unable to find artifact version of " + artifact.getGroupId() + ":" + artifact.getArtifactId()
364                     + " in either dependency list or in project's dependency management." );
365         }
366     }
367 
368     /**
369      * Tries to find missing version from a list of dependencies. If found, the artifact is updated with the correct
370      * version.
371      *
372      * @param artifact     representing configured file.
373      * @param dependencies list of dependencies to search.
374      * @param looseMatch   only look at artifactId and groupId
375      * @return the found dependency
376      */
377     private boolean findDependencyVersion( ArtifactItem artifact, List<Dependency> dependencies, boolean looseMatch )
378     {
379         for ( Dependency dependency : dependencies )
380         {
381             if ( StringUtils.equals( dependency.getArtifactId(), artifact.getArtifactId() )
382                 && StringUtils.equals( dependency.getGroupId(), artifact.getGroupId() )
383                 && ( looseMatch || StringUtils.equals( dependency.getClassifier(), artifact.getClassifier() ) )
384                 && ( looseMatch || StringUtils.equals( dependency.getType(), artifact.getType() ) ) )
385             {
386                 artifact.setVersion( dependency.getVersion() );
387 
388                 return true;
389             }
390         }
391 
392         return false;
393     }
394 
395     /*
396      * private Map createManagedVersionMap( ArtifactFactory artifactFactory, String projectId, DependencyManagement
397      * dependencyManagement ) throws MojoExecutionException { Map map; if ( dependencyManagement != null &&
398      * dependencyManagement.getDependencies() != null ) { map = new HashMap(); for ( Iterator i =
399      * dependencyManagement.getDependencies().iterator(); i.hasNext(); ) { Dependency d = (Dependency) i.next(); try {
400      * VersionRange versionRange = VersionRange.createFromVersionSpec( d.getVersion() ); Artifact artifact =
401      * artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(), versionRange, d.getType(), d
402      * .getClassifier(), d.getScope(), d .isOptional() ); map.put( d.getManagementKey(), artifact ); } catch (
403      * InvalidVersionSpecificationException e ) { throw new MojoExecutionException( "Unable to parse version", e ); } }
404      * } else { map = Collections.EMPTY_MAP; } return map; }
405      */
406 
407     /**
408      * Override the base to
409      *
410      * @return Returns the local.
411      */
412     protected ArtifactRepository getLocal()
413     {
414         if ( this.overrideLocalRepository != null )
415         {
416             return this.overrideLocalRepository;
417         }
418 
419         ArtifactRepository local = super.getLocal();
420 
421         if ( this.localRepositoryDirectory != null )
422         {
423             // create a new local repo using existing layout, snapshots, and releases policy
424             String url = "file://" + this.localRepositoryDirectory.getAbsolutePath();
425             this.overrideLocalRepository =
426                 artifactRepositoryManager.createArtifactRepository( local.getId(), url, local.getLayout(),
427                                                                     local.getSnapshots(), local.getReleases() );
428 
429             this.getLog().debug( "Execution local repository is at: " + this.overrideLocalRepository.getBasedir() );
430         }
431         else
432         {
433             this.overrideLocalRepository = local;
434         }
435 
436         return this.overrideLocalRepository;
437     }
438 
439     /**
440      * @return Returns the artifactItems.
441      */
442     public List<ArtifactItem> getArtifactItems()
443     {
444         return this.artifactItems;
445     }
446 
447     /**
448      * @param theArtifactItems The artifactItems to set.
449      */
450     public void setArtifactItems( List<ArtifactItem> theArtifactItems )
451     {
452         this.artifactItems = theArtifactItems;
453     }
454 
455     /**
456      * @return Returns the outputDirectory.
457      */
458     public File getOutputDirectory()
459     {
460         return this.outputDirectory;
461     }
462 
463     /**
464      * @param theOutputDirectory The outputDirectory to set.
465      */
466     public void setOutputDirectory( File theOutputDirectory )
467     {
468         this.outputDirectory = theOutputDirectory;
469     }
470 
471     /**
472      * @return Returns the overWriteIfNewer.
473      */
474     public boolean isOverWriteIfNewer()
475     {
476         return this.overWriteIfNewer;
477     }
478 
479     /**
480      * @param theOverWriteIfNewer The overWriteIfNewer to set.
481      */
482     public void setOverWriteIfNewer( boolean theOverWriteIfNewer )
483     {
484         this.overWriteIfNewer = theOverWriteIfNewer;
485     }
486 
487     /**
488      * @return Returns the overWriteReleases.
489      */
490     public boolean isOverWriteReleases()
491     {
492         return this.overWriteReleases;
493     }
494 
495     /**
496      * @param theOverWriteReleases The overWriteReleases to set.
497      */
498     public void setOverWriteReleases( boolean theOverWriteReleases )
499     {
500         this.overWriteReleases = theOverWriteReleases;
501     }
502 
503     /**
504      * @return Returns the overWriteSnapshots.
505      */
506     public boolean isOverWriteSnapshots()
507     {
508         return this.overWriteSnapshots;
509     }
510 
511     /**
512      * @param theOverWriteSnapshots The overWriteSnapshots to set.
513      */
514     public void setOverWriteSnapshots( boolean theOverWriteSnapshots )
515     {
516         this.overWriteSnapshots = theOverWriteSnapshots;
517     }
518 
519     public void setLocalRepositoryDirectory( File localRepositoryDirectory )
520     {
521         this.localRepositoryDirectory = localRepositoryDirectory;
522     }
523 
524     public void setArtifact( String artifact )
525         throws MojoFailureException
526     {
527         if ( artifact != null )
528         {
529             String packaging = "jar";
530             String classifier;
531             String[] tokens = StringUtils.split( artifact, ":" );
532             if ( tokens.length < 3 || tokens.length > 5 )
533             {
534                 throw new MojoFailureException(
535                     "Invalid artifact, you must specify groupId:artifactId:version[:packaging][:classifier] "
536                         + artifact );
537             }
538             String groupId = tokens[0];
539             String artifactId = tokens[1];
540             String version = tokens[2];
541             if ( tokens.length >= 4 )
542             {
543                 packaging = tokens[3];
544             }
545             if ( tokens.length == 5 )
546             {
547                 classifier = tokens[4];
548             }
549             else
550             {
551                 classifier = null;
552             }
553     
554             Artifact toUnpack = classifier == null
555             ? factory.createBuildArtifact( groupId, artifactId, version, packaging )
556             : factory.createArtifactWithClassifier( groupId, artifactId, version, packaging, classifier );
557             
558             setArtifactItems( Collections.singletonList( new ArtifactItem( toUnpack ) ) );
559         }
560     }
561 }