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