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.factory.ArtifactFactory;
24  import org.apache.maven.artifact.repository.ArtifactRepository;
25  import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
26  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
27  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
28  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
29  import org.apache.maven.artifact.versioning.VersionRange;
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.plugin.dependency.AbstractDependencyMojo;
34  import org.apache.maven.plugin.dependency.utils.DependencyUtil;
35  import org.apache.maven.plugin.dependency.utils.filters.ArtifactItemFilter;
36  import org.apache.maven.plugins.annotations.Component;
37  import org.apache.maven.plugins.annotations.Parameter;
38  import org.apache.maven.project.MavenProject;
39  import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
40  import org.codehaus.plexus.util.StringUtils;
41  
42  import java.io.File;
43  import java.util.Collections;
44  import java.util.List;
45  import java.util.Set;
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   * @version $Id: AbstractFromConfigurationMojo.java 1397671 2012-10-12 18:28:52Z rfscholte $
53   * @see ArtifactItem
54   */
55  public abstract class AbstractFromConfigurationMojo
56      extends AbstractDependencyMojo
57  {
58      /**
59       * Skip the execution
60       *
61       * @since 2.2
62       */
63      @Parameter( property = "mdep.skip", defaultValue = "false" )
64      private boolean skip;
65  
66      /**
67       * Default location used for mojo unless overridden in ArtifactItem
68       *
69       * @since 1.0
70       */
71      @Parameter( property = "outputDirectory", defaultValue = "${project.build.directory}/dependency" )
72      private File outputDirectory;
73  
74      /**
75       * Overwrite release artifacts
76       *
77       * @since 1.0
78       */
79      @Parameter( property = "mdep.overWriteReleases", defaultValue = "false" )
80      private boolean overWriteReleases;
81  
82      /**
83       * Overwrite snapshot artifacts
84       *
85       * @since 1.0
86       */
87      @Parameter( property = "mdep.overWriteSnapshots", defaultValue = "false" )
88      private boolean overWriteSnapshots;
89  
90      /**
91       * Overwrite if newer
92       *
93       * @since 2.0
94       */
95      @Parameter( property = "mdep.overIfNewer", defaultValue = "true" )
96      private boolean overWriteIfNewer;
97  
98      /**
99       * To search for artifacts within the reactor and ensure consistent behaviour between Maven 2 and Maven 3.
100      */
101     @Parameter( defaultValue = "${reactorProjects}", readonly = true, required = true )
102     protected List<MavenProject> reactorProjects;
103 
104     /**
105      * Collection of ArtifactItems to work on. (ArtifactItem contains groupId, artifactId, version, type, classifier,
106      * outputDirectory, destFileName and overWrite.) See <a href="./usage.html">Usage</a> for details.
107      *
108      * @since 1.0
109      */
110     @Parameter
111     private List<ArtifactItem> artifactItems;
112 
113     /**
114      * To look up ArtifactRepository implementation
115      */
116     @Component
117     private ArtifactRepositoryFactory artifactRepositoryManager;
118 
119     /**
120      * Path to override default local repository during plugin's execution. To remove all downloaded artifacts as part
121      * of the build, set this value to a location under your project's target directory
122      *
123      * @since 2.2
124      */
125     @Parameter
126     private File localRepositoryDirectory;
127 
128     /**
129      * To host and cache localRepositoryDirectory
130      */
131     private ArtifactRepository overrideLocalRepository;
132 
133     @Component
134     private ArtifactFactory artifactFactory;
135 
136     abstract ArtifactItemFilter getMarkedArtifactFilter( ArtifactItem item );
137     
138     // artifactItems is filled by either field injection or by setArtifact()
139     protected void verifyRequirements() throws MojoFailureException
140     {
141         if ( artifactItems == null || artifactItems.isEmpty() )
142         {
143             throw new MojoFailureException( "Either artifact or artifactItems is required " );
144         }
145     }
146 
147     /**
148      * Preprocesses the list of ArtifactItems. This method defaults the outputDirectory if not set and creates the
149      * output Directory if it doesn't exist.
150      *
151      * @param removeVersion remove the version from the filename.
152      * @return An ArrayList of preprocessed ArtifactItems
153      * @throws MojoExecutionException with a message if an error occurs.
154      * @see ArtifactItem
155      */
156     protected List<ArtifactItem> getProcessedArtifactItems( boolean removeVersion )
157         throws MojoExecutionException
158     {
159         if ( artifactItems == null || artifactItems.size() < 1 )
160         {
161             throw new MojoExecutionException( "There are no artifactItems configured." );
162         }
163 
164         for ( ArtifactItem artifactItem : artifactItems )
165         {
166             this.getLog().info( "Configured Artifact: " + artifactItem.toString() );
167 
168             if ( artifactItem.getOutputDirectory() == null )
169             {
170                 artifactItem.setOutputDirectory( this.outputDirectory );
171             }
172             artifactItem.getOutputDirectory().mkdirs();
173 
174             // make sure we have a version.
175             if ( StringUtils.isEmpty( artifactItem.getVersion() ) )
176             {
177                 fillMissingArtifactVersion( artifactItem );
178             }
179 
180             artifactItem.setArtifact( this.getArtifact( artifactItem ) );
181 
182             if ( StringUtils.isEmpty( artifactItem.getDestFileName() ) )
183             {
184                 artifactItem.setDestFileName(
185                     DependencyUtil.getFormattedFileName( artifactItem.getArtifact(), removeVersion ) );
186             }
187 
188             try
189             {
190                 artifactItem.setNeedsProcessing( checkIfProcessingNeeded( artifactItem ) );
191             }
192             catch ( ArtifactFilterException e )
193             {
194                 throw new MojoExecutionException( e.getMessage(), e );
195             }
196         }
197         return artifactItems;
198     }
199 
200     private boolean checkIfProcessingNeeded( ArtifactItem item )
201         throws MojoExecutionException, ArtifactFilterException
202     {
203         return StringUtils.equalsIgnoreCase( item.getOverWrite(), "true" )
204             || getMarkedArtifactFilter( item ).isArtifactIncluded( item );
205     }
206 
207     /**
208      * Resolves the Artifact from the remote repository if necessary. If no version is specified, it will be retrieved
209      * from the dependency list or from the DependencyManagement section of the pom.
210      *
211      * @param artifactItem containing information about artifact from plugin configuration.
212      * @return Artifact object representing the specified file.
213      * @throws MojoExecutionException with a message if the version can't be found in DependencyManagement.
214      */
215     protected Artifact getArtifact( ArtifactItem artifactItem )
216         throws MojoExecutionException
217     {
218         Artifact artifact;
219 
220         // Map managedVersions = createManagedVersionMap( factory, project.getId(), project.getDependencyManagement() );
221         VersionRange vr;
222         try
223         {
224             vr = VersionRange.createFromVersionSpec( artifactItem.getVersion() );
225         }
226         catch ( InvalidVersionSpecificationException e1 )
227         {
228             // TODO Auto-generated catch block
229             e1.printStackTrace();
230             vr = VersionRange.createFromVersion( artifactItem.getVersion() );
231         }
232 
233         if ( StringUtils.isEmpty( artifactItem.getClassifier() ) )
234         {
235             artifact = factory.createDependencyArtifact( artifactItem.getGroupId(), artifactItem.getArtifactId(), vr,
236                                                          artifactItem.getType(), null, Artifact.SCOPE_COMPILE );
237         }
238         else
239         {
240             artifact = factory.createDependencyArtifact( artifactItem.getGroupId(), artifactItem.getArtifactId(), vr,
241                                                          artifactItem.getType(), artifactItem.getClassifier(),
242                                                          Artifact.SCOPE_COMPILE );
243         }
244 
245         // Maven 3 will search the reactor for the artifact but Maven 2 does not
246         // to keep consistent behaviour, we search the reactor ourselves.
247         Artifact result = getArtifactFomReactor( artifact );
248         if ( result != null )
249         {
250             return result;
251         }
252 
253         try
254         {
255             // mdep-50 - rolledback for now because it's breaking some functionality.
256             /*
257              * List listeners = new ArrayList(); Set theSet = new HashSet(); theSet.add( artifact );
258              * ArtifactResolutionResult artifactResolutionResult = artifactCollector.collect( theSet, project
259              * .getArtifact(), managedVersions, this.local, project.getRemoteArtifactRepositories(),
260              * artifactMetadataSource, null, listeners ); Iterator iter =
261              * artifactResolutionResult.getArtifactResolutionNodes().iterator(); while ( iter.hasNext() ) {
262              * ResolutionNode node = (ResolutionNode) iter.next(); artifact = node.getArtifact(); }
263              */
264 
265             resolver.resolve( artifact, remoteRepos, getLocal() );
266         }
267         catch ( ArtifactResolutionException e )
268         {
269             throw new MojoExecutionException( "Unable to resolve artifact.", e );
270         }
271         catch ( ArtifactNotFoundException e )
272         {
273             throw new MojoExecutionException( "Unable to find artifact.", e );
274         }
275 
276         return artifact;
277     }
278 
279     /**
280      * Checks to see if the specified artifact is available from the reactor.
281      *
282      * @param artifact The artifact we are looking for.
283      * @return The resolved artifact that is the same as the one we were looking for or <code>null</code> if one could
284      *         not be found.
285      */
286     private Artifact getArtifactFomReactor( Artifact artifact )
287     {
288         // check project dependencies first off
289         for ( Artifact a : (Set<Artifact>) project.getArtifacts() )
290         {
291             if ( equals( artifact, a ) && hasFile( a ) )
292             {
293                 return a;
294             }
295         }
296 
297         // check reactor projects
298         for ( MavenProject p : reactorProjects == null ? Collections.<MavenProject>emptyList() : reactorProjects )
299         {
300             // check the main artifact
301             if ( equals( artifact, p.getArtifact() ) && hasFile( p.getArtifact() ) )
302             {
303                 return p.getArtifact();
304             }
305 
306             // check any side artifacts
307             for ( Artifact a : (List<Artifact>) p.getAttachedArtifacts() )
308             {
309                 if ( equals( artifact, a ) && hasFile( a ) )
310                 {
311                     return a;
312                 }
313             }
314         }
315 
316         // not available
317         return null;
318     }
319 
320     /**
321      * Returns <code>true</code> if the artifact has a file.
322      *
323      * @param artifact the artifact (may be null)
324      * @return <code>true</code> if and only if the artifact is non-null and has a file.
325      */
326     private static boolean hasFile( Artifact artifact )
327     {
328         return artifact != null && artifact.getFile() != null && artifact.getFile().isFile();
329     }
330 
331     /**
332      * Null-safe compare of two artifacts based on groupId, artifactId, version, type and classifier.
333      *
334      * @param a the first artifact.
335      * @param b the second artifact.
336      * @return <code>true</code> if and only if the two artifacts have the same groupId, artifactId, version,
337      *         type and classifier.
338      */
339     private static boolean equals( Artifact a, Artifact b )
340     {
341         return a == b || !( a == null || b == null )
342             && StringUtils.equals( a.getGroupId(), b.getGroupId() )
343             && StringUtils.equals( a.getArtifactId(), b.getArtifactId() )
344             && StringUtils.equals( a.getVersion(), b.getVersion() )
345             && StringUtils.equals( a.getType(), b.getType() )
346             && StringUtils.equals( a.getClassifier(), b.getClassifier() );
347     }
348 
349     /**
350      * Tries to find missing version from dependency list and dependency management. If found, the artifact is updated
351      * with the correct version. It will first look for an exact match on artifactId/groupId/classifier/type and if it
352      * doesn't find a match, it will try again looking for artifactId and groupId only.
353      *
354      * @param artifact representing configured file.
355      * @throws MojoExecutionException
356      */
357     private void fillMissingArtifactVersion( ArtifactItem artifact )
358         throws MojoExecutionException
359     {
360         @SuppressWarnings( "unchecked" ) List<Dependency> deps = project.getDependencies();
361         @SuppressWarnings( "unchecked" ) List<Dependency> depMngt = project.getDependencyManagement() == null
362             ? Collections.<Dependency>emptyList()
363             : project.getDependencyManagement().getDependencies();
364 
365         if ( !findDependencyVersion( artifact, deps, false )
366             && ( project.getDependencyManagement() == null || !findDependencyVersion( artifact, depMngt, false ) )
367             && !findDependencyVersion( artifact, deps, true )
368             && ( project.getDependencyManagement() == null || !findDependencyVersion( artifact, depMngt, true ) ) )
369         {
370             throw new MojoExecutionException(
371                 "Unable to find artifact version of " + artifact.getGroupId() + ":" + artifact.getArtifactId()
372                     + " in either dependency list or in project's dependency management." );
373         }
374     }
375 
376     /**
377      * Tries to find missing version from a list of dependencies. If found, the artifact is updated with the correct
378      * version.
379      *
380      * @param artifact     representing configured file.
381      * @param dependencies list of dependencies to search.
382      * @param looseMatch   only look at artifactId and groupId
383      * @return the found dependency
384      */
385     private boolean findDependencyVersion( ArtifactItem artifact, List<Dependency> dependencies, boolean looseMatch )
386     {
387         for ( Dependency dependency : dependencies )
388         {
389             if ( StringUtils.equals( dependency.getArtifactId(), artifact.getArtifactId() )
390                 && StringUtils.equals( dependency.getGroupId(), artifact.getGroupId() )
391                 && ( looseMatch || StringUtils.equals( dependency.getClassifier(), artifact.getClassifier() ) )
392                 && ( looseMatch || StringUtils.equals( dependency.getType(), artifact.getType() ) ) )
393             {
394                 artifact.setVersion( dependency.getVersion() );
395 
396                 return true;
397             }
398         }
399 
400         return false;
401     }
402 
403     /*
404      * private Map createManagedVersionMap( ArtifactFactory artifactFactory, String projectId, DependencyManagement
405      * dependencyManagement ) throws MojoExecutionException { Map map; if ( dependencyManagement != null &&
406      * dependencyManagement.getDependencies() != null ) { map = new HashMap(); for ( Iterator i =
407      * dependencyManagement.getDependencies().iterator(); i.hasNext(); ) { Dependency d = (Dependency) i.next(); try {
408      * VersionRange versionRange = VersionRange.createFromVersionSpec( d.getVersion() ); Artifact artifact =
409      * artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(), versionRange, d.getType(), d
410      * .getClassifier(), d.getScope(), d .isOptional() ); map.put( d.getManagementKey(), artifact ); } catch (
411      * InvalidVersionSpecificationException e ) { throw new MojoExecutionException( "Unable to parse version", e ); } }
412      * } else { map = Collections.EMPTY_MAP; } return map; }
413      */
414 
415     /**
416      * Override the base to
417      *
418      * @return Returns the local.
419      */
420     protected ArtifactRepository getLocal()
421     {
422         if ( this.overrideLocalRepository != null )
423         {
424             return this.overrideLocalRepository;
425         }
426 
427         ArtifactRepository local = super.getLocal();
428 
429         if ( this.localRepositoryDirectory != null )
430         {
431             // create a new local repo using existing layout, snapshots, and releases policy
432             String url = "file://" + this.localRepositoryDirectory.getAbsolutePath();
433             this.overrideLocalRepository =
434                 artifactRepositoryManager.createArtifactRepository( local.getId(), url, local.getLayout(),
435                                                                     local.getSnapshots(), local.getReleases() );
436 
437             this.getLog().debug( "Execution local repository is at: " + this.overrideLocalRepository.getBasedir() );
438         }
439         else
440         {
441             this.overrideLocalRepository = local;
442         }
443 
444         return this.overrideLocalRepository;
445     }
446 
447     /**
448      * @return Returns the artifactItems.
449      */
450     public List<ArtifactItem> getArtifactItems()
451     {
452         return this.artifactItems;
453     }
454 
455     /**
456      * @param theArtifactItems The artifactItems to set.
457      */
458     public void setArtifactItems( List<ArtifactItem> theArtifactItems )
459     {
460         this.artifactItems = theArtifactItems;
461     }
462 
463     /**
464      * @return Returns the outputDirectory.
465      */
466     public File getOutputDirectory()
467     {
468         return this.outputDirectory;
469     }
470 
471     /**
472      * @param theOutputDirectory The outputDirectory to set.
473      */
474     public void setOutputDirectory( File theOutputDirectory )
475     {
476         this.outputDirectory = theOutputDirectory;
477     }
478 
479     /**
480      * @return Returns the overWriteIfNewer.
481      */
482     public boolean isOverWriteIfNewer()
483     {
484         return this.overWriteIfNewer;
485     }
486 
487     /**
488      * @param theOverWriteIfNewer The overWriteIfNewer to set.
489      */
490     public void setOverWriteIfNewer( boolean theOverWriteIfNewer )
491     {
492         this.overWriteIfNewer = theOverWriteIfNewer;
493     }
494 
495     /**
496      * @return Returns the overWriteReleases.
497      */
498     public boolean isOverWriteReleases()
499     {
500         return this.overWriteReleases;
501     }
502 
503     /**
504      * @param theOverWriteReleases The overWriteReleases to set.
505      */
506     public void setOverWriteReleases( boolean theOverWriteReleases )
507     {
508         this.overWriteReleases = theOverWriteReleases;
509     }
510 
511     /**
512      * @return Returns the overWriteSnapshots.
513      */
514     public boolean isOverWriteSnapshots()
515     {
516         return this.overWriteSnapshots;
517     }
518 
519     /**
520      * @param theOverWriteSnapshots The overWriteSnapshots to set.
521      */
522     public void setOverWriteSnapshots( boolean theOverWriteSnapshots )
523     {
524         this.overWriteSnapshots = theOverWriteSnapshots;
525     }
526 
527     public void setLocalRepositoryDirectory( File localRepositoryDirectory )
528     {
529         this.localRepositoryDirectory = localRepositoryDirectory;
530     }
531 
532     public boolean isSkip()
533     {
534         return skip;
535     }
536 
537     public void setSkip( boolean skip )
538     {
539         this.skip = skip;
540     }
541 
542     public void setArtifact( String artifact )
543         throws MojoFailureException
544     {
545         if ( artifact != null )
546         {
547             String packaging = "jar";
548             String classifier;
549             String[] tokens = StringUtils.split( artifact, ":" );
550             if ( tokens.length < 3 || tokens.length > 5 )
551             {
552                 throw new MojoFailureException(
553                     "Invalid artifact, you must specify groupId:artifactId:version[:packaging][:classifier] "
554                         + artifact );
555             }
556             String groupId = tokens[0];
557             String artifactId = tokens[1];
558             String version = tokens[2];
559             if ( tokens.length >= 4 )
560             {
561                 packaging = tokens[3];
562             }
563             if ( tokens.length == 5 )
564             {
565                 classifier = tokens[4];
566             }
567             else
568             {
569                 classifier = null;
570             }
571     
572             Artifact toUnpack = classifier == null
573             ? artifactFactory.createBuildArtifact( groupId, artifactId, version, packaging )
574             : artifactFactory.createArtifactWithClassifier( groupId, artifactId, version, packaging, classifier );
575             
576             setArtifactItems( Collections.singletonList( new ArtifactItem( toUnpack ) ) );
577         }
578     }
579 }