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