View Javadoc

1   package org.apache.maven.plugins.enforcer;
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.io.IOException;
24  import java.lang.reflect.Field;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.HashMap;
30  import java.util.HashSet;
31  import java.util.Iterator;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.Set;
35  import java.util.Map.Entry;
36  
37  import org.apache.maven.BuildFailureException;
38  import org.apache.maven.artifact.Artifact;
39  import org.apache.maven.artifact.factory.ArtifactFactory;
40  import org.apache.maven.artifact.repository.ArtifactRepository;
41  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
42  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
43  import org.apache.maven.artifact.resolver.ArtifactResolver;
44  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
45  import org.apache.maven.artifact.versioning.VersionRange;
46  import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
47  import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
48  import org.apache.maven.execution.MavenSession;
49  import org.apache.maven.lifecycle.Lifecycle;
50  import org.apache.maven.lifecycle.LifecycleExecutionException;
51  import org.apache.maven.lifecycle.LifecycleExecutor;
52  import org.apache.maven.lifecycle.mapping.LifecycleMapping;
53  import org.apache.maven.model.BuildBase;
54  import org.apache.maven.model.Model;
55  import org.apache.maven.model.Plugin;
56  import org.apache.maven.model.Profile;
57  import org.apache.maven.model.ReportPlugin;
58  import org.apache.maven.plugin.InvalidPluginException;
59  import org.apache.maven.plugin.MojoExecutionException;
60  import org.apache.maven.plugin.PluginManager;
61  import org.apache.maven.plugin.PluginManagerException;
62  import org.apache.maven.plugin.PluginNotFoundException;
63  import org.apache.maven.plugin.descriptor.PluginDescriptor;
64  import org.apache.maven.plugin.logging.Log;
65  import org.apache.maven.plugin.version.PluginVersionNotFoundException;
66  import org.apache.maven.plugin.version.PluginVersionResolutionException;
67  import org.apache.maven.plugins.enforcer.utils.EnforcerRuleUtils;
68  import org.apache.maven.plugins.enforcer.utils.PluginWrapper;
69  import org.apache.maven.project.MavenProject;
70  import org.apache.maven.settings.Settings;
71  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
72  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
73  import org.codehaus.plexus.util.ReflectionUtils;
74  import org.codehaus.plexus.util.StringUtils;
75  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
76  
77  /**
78   * This rule will enforce that all plugins specified in the poms have a version declared.
79   *
80   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
81   * @version $Id: RequirePluginVersions.java 1496229 2013-06-24 21:43:56Z rfscholte $
82   */
83  public class RequirePluginVersions
84      extends AbstractNonCacheableEnforcerRule
85  {
86  
87      /** Don't allow the LATEST identifier. 
88       * 
89       * @deprecated the visibility will be reduced to private with the next major version
90       * @see {@link #setBanLatest(boolean)}
91       * @see {@link #isBanLatest()}
92       */
93      public boolean banLatest = true;
94  
95      /** Don't allow the RELEASE identifier.
96       *  
97       * @deprecated the visibility will be reduced to private with the next major version
98       * @see {@link #setBanRelease(boolean)}
99       * @see {@link #isBanRelease()}
100      */
101     public boolean banRelease = true;
102 
103     /** Don't allow snapshot plugins. 
104      * 
105      * @deprecated the visibility will be reduced to private with the next major version
106      * @see {@link #setBanSnapshots(boolean)}
107      * @see {@link #isBanSnapshots()}
108      */
109     public boolean banSnapshots = true;
110 
111     /** Don't allow timestamp snapshot plugins. 
112      * 
113      * @deprecated the visibility will be reduced to private with the next major version
114      * @see {@link #setBanTimestamps(boolean)}
115      * @see {@link #isBanTimestamps()}
116      */
117     public boolean banTimestamps = true;
118 
119     /**
120      * The comma separated list of phases that should be used to find lifecycle plugin bindings. The default value is
121      * "clean,deploy,site".
122      * 
123      * @deprecated the visibility will be reduced to private with the next major version
124      * @see {@link #setPhases(String)}
125      * @see {@link #getPhases()}
126      */
127     public String phases = "clean,deploy,site";
128 
129     /**
130      * Additional plugins to enforce have versions. These are plugins that may not be in the poms but are used anyway,
131      * like help, eclipse etc. <br>
132      * The plugins should be specified in the form: <code>group:artifactId</code>.
133      * 
134      * @deprecated the visibility will be reduced to private with the next major version
135      * @see {@link #setAdditionalPlugins(List)}
136      * @see {@link #getAdditionalPlugins()}
137      */
138     public List<String> additionalPlugins;
139 
140     /**
141      * Plugins to skip for version enforcement. The plugins should be specified in the form:
142      * <code>group:artifactId</code>. NOTE: This is deprecated, use unCheckedPluginList instead.
143      * 
144      * @deprecated the visibility will be reduced to private with the next major version
145      * @see {@link #setUnCheckedPlugins(List)}
146      * @see {@link #getUnCheckedPlugins()}
147      */
148     public List unCheckedPlugins;
149 
150     /**
151      * Same as unCheckedPlugins but as a comma list to better support properties. Sample form:
152      * <code>group:artifactId,group2:artifactId2</code>
153      * @since 1.0-beta-1
154      * 
155      * @deprecated the visibility will be reduced to private with the next major version
156      * @see {@link #setUnCheckedPlugins(List)}
157      * @see {@link #getUnCheckedPlugins()}
158      */
159     public String unCheckedPluginList;
160 
161     /** The plugin manager. */
162     private PluginManager pluginManager;
163 
164     /** The phase to lifecycle map. */
165     private Map<String, Lifecycle> phaseToLifecycleMap;
166 
167     /** The lifecycles. */
168     private Collection<Lifecycle> lifecycles;
169 
170     /** The factory. */
171     ArtifactFactory factory;
172 
173     /** The resolver. */
174     ArtifactResolver resolver;
175 
176     /** The local. */
177     ArtifactRepository local;
178 
179     /** The remote repositories. */
180     List<ArtifactRepository> remoteRepositories;
181 
182     /** The log. */
183     Log log;
184 
185     /** The session. */
186     MavenSession session;
187 
188     /** The utils. */
189     EnforcerRuleUtils utils;
190 
191     /*
192      * (non-Javadoc)
193      *
194      * @see org.apache.maven.enforcer.rule.api.EnforcerRule#execute(org.apache.maven.enforcer.rule.api.EnforcerRuleHelper)
195      */
196     public void execute( EnforcerRuleHelper helper )
197         throws EnforcerRuleException
198     {
199         log = helper.getLog();
200 
201         MavenProject project;
202         try
203         {
204             // get the various expressions out of the helper.
205 
206             project = (MavenProject) helper.evaluate( "${project}" );
207             LifecycleExecutor life;
208             life = (LifecycleExecutor) helper.getComponent( LifecycleExecutor.class );
209 
210             // The lifecycle API changed from Maven 2 to 3 so we have to do a hack to figure
211             // out which one we're using.
212             Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( "defaultLifeCycles", life.getClass() );
213             if ( field != null ) // Using Maven 3
214             {
215                 Object defaultLifeCycles = ReflectionUtils.getValueIncludingSuperclasses( "defaultLifeCycles", life );
216                 Map lifecyclesMap =
217                     (Map) ReflectionUtils.getValueIncludingSuperclasses( "lifecycles", defaultLifeCycles );
218                 lifecycles = lifecyclesMap.values();
219             }
220             else  // Using Maven 2
221             {
222                 lifecycles = (Collection) ReflectionUtils.getValueIncludingSuperclasses( "lifecycles", life );
223             }
224 
225             session = (MavenSession) helper.evaluate( "${session}" );
226             pluginManager = (PluginManager) helper.getComponent( PluginManager.class );
227             factory = (ArtifactFactory) helper.getComponent( ArtifactFactory.class );
228             resolver = (ArtifactResolver) helper.getComponent( ArtifactResolver.class );
229             local = (ArtifactRepository) helper.evaluate( "${localRepository}" );
230             remoteRepositories = project.getRemoteArtifactRepositories();
231 
232             utils = new EnforcerRuleUtils( helper );
233 
234             // get all the plugins that are bound to the specified lifecycles
235             Set<Plugin> allPlugins = getBoundPlugins( life, project, phases );
236 
237             // insert any additional plugins specified by the user.
238             allPlugins = addAdditionalPlugins( allPlugins, additionalPlugins );
239             allPlugins.addAll( getProfilePlugins( project ) );
240 
241 
242             // pull out any we should skip
243             allPlugins =
244                 (Set) removeUncheckedPlugins( combineUncheckedPlugins( unCheckedPlugins, unCheckedPluginList ),
245                                               allPlugins );
246 
247             // there's nothing to do here
248             if ( allPlugins.isEmpty() )
249             {
250                 log.info( "No plugin bindings found." );
251                 return;
252             }
253             else
254             {
255                 log.debug( "All Plugins in use: " + allPlugins );
256             }
257 
258             // get all the plugins that are mentioned in the pom (and parents)
259             List<PluginWrapper> pluginWrappers = getAllPluginEntries( project );
260 
261             // now look for the versions that aren't valid and add to a list.
262             List<Plugin> failures = new ArrayList<Plugin>();
263             for ( Plugin plugin : allPlugins )
264             {
265                 if ( !hasValidVersionSpecified( helper, plugin, pluginWrappers ) )
266                 {
267                     failures.add( plugin );
268                 }
269             }
270 
271             // if anything was found, log it then append the optional message.
272             if ( !failures.isEmpty() )
273             {
274                 StringBuilder newMsg = new StringBuilder();
275                 newMsg.append( "Some plugins are missing valid versions:" );
276                 if ( banLatest || banRelease || banSnapshots || banTimestamps )
277                 {
278                     newMsg.append( "(" );
279                     if ( banLatest )
280                     {
281                         newMsg.append( "LATEST " );
282                     }
283                     if ( banRelease )
284                     {
285                         newMsg.append( "RELEASE " );
286                     }
287                     if ( banSnapshots || banTimestamps )
288                     {
289                         newMsg.append( "SNAPSHOT " );
290                     }
291                     newMsg.append( "are not allowed )\n" );
292                 }
293                 for ( Plugin plugin : failures )
294                 {
295                     newMsg.append( plugin.getGroupId() );
296                     newMsg.append( ":" );
297                     newMsg.append( plugin.getArtifactId() );
298 
299                     try
300                     {
301                         newMsg.append( ". \tThe version currently in use is " );
302 
303                         Plugin currentPlugin = findCurrentPlugin( plugin, project );
304 
305                         if ( currentPlugin != null )
306                         {
307                             newMsg.append( currentPlugin.getVersion() );
308                         }
309                         else
310                         {
311                             newMsg.append( "unknown" );
312                         }
313                     }
314                     catch ( Exception e )
315                     {
316                         // lots can go wrong here. Don't allow any issues trying to
317                         // determine the issue stop me
318                         log.debug( "Exception while determining plugin Version.", e );
319                         newMsg.append( ". Unable to determine the plugin version." );
320                     }
321                     newMsg.append( "\n" );
322                 }
323                 String message = getMessage();
324                 if ( StringUtils.isNotEmpty( message ) )
325                 {
326                     newMsg.append( message );
327                 }
328 
329                 throw new EnforcerRuleException( newMsg.toString() );
330             }
331         }
332         catch ( ExpressionEvaluationException e )
333         {
334             throw new EnforcerRuleException( "Unable to Evaluate an Expression:" + e.getLocalizedMessage() );
335         }
336         catch ( ComponentLookupException e )
337         {
338             throw new EnforcerRuleException( "Unable to lookup a component:" + e.getLocalizedMessage() );
339         }
340         catch ( IllegalAccessException e )
341         {
342             throw new EnforcerRuleException( e.getLocalizedMessage() );
343         }
344         catch ( LifecycleExecutionException e )
345         {
346             throw new EnforcerRuleException( e.getLocalizedMessage() );
347         }
348         catch ( PluginNotFoundException e )
349         {
350             throw new EnforcerRuleException( e.getLocalizedMessage() );
351         }
352         catch ( ArtifactResolutionException e )
353         {
354             throw new EnforcerRuleException( e.getLocalizedMessage() );
355         }
356         catch ( ArtifactNotFoundException e )
357         {
358             throw new EnforcerRuleException( e.getLocalizedMessage() );
359         }
360         catch ( IOException e )
361         {
362             throw new EnforcerRuleException( e.getLocalizedMessage() );
363         }
364         catch ( XmlPullParserException e )
365         {
366             throw new EnforcerRuleException( e.getLocalizedMessage() );
367         }
368         catch ( MojoExecutionException e )
369         {
370             throw new EnforcerRuleException( e.getLocalizedMessage() );
371         }
372     }
373 
374     /**
375      * Remove the plugins that the user doesn't want to check.
376      *
377      * @param uncheckedPlugins
378      * @param plugins
379      * @throws MojoExecutionException
380      * @return
381      */
382     public Collection<Plugin> removeUncheckedPlugins( Collection<String> uncheckedPlugins, Collection<Plugin> plugins )
383         throws MojoExecutionException
384     {
385         if ( uncheckedPlugins != null && !uncheckedPlugins.isEmpty() )
386         {
387             for ( String pluginKey : uncheckedPlugins )
388             {
389                 Plugin plugin = parsePluginString( pluginKey, "UncheckedPlugins" );
390                 plugins.remove( plugin );
391             }
392         }
393         return plugins;
394     }
395 
396     /**
397      * Combines the old Collection with the new comma separated list.
398      * @param uncheckedPlugins
399      * @param uncheckedPluginsList
400      * @return
401      */
402     public Collection<String> combineUncheckedPlugins( Collection<String> uncheckedPlugins, String uncheckedPluginsList )
403     {
404         //if the comma list is empty, then there's nothing to do here.
405         if ( StringUtils.isNotEmpty( uncheckedPluginsList ) )
406         {
407             //make sure there is a collection to add to.
408             if ( uncheckedPlugins == null )
409             {
410                 uncheckedPlugins = new HashSet<String>();
411             }
412             else if ( !uncheckedPlugins.isEmpty() && log != null )
413             {
414                 log.warn( "The parameter 'unCheckedPlugins' is deprecated. Use 'unCheckedPluginList' instead" );
415             }
416 
417             uncheckedPlugins.addAll( Arrays.asList( uncheckedPluginsList.split( "," ) ) );
418         }
419         return uncheckedPlugins;
420     }
421 
422     /**
423      * Add the additional plugins if they don't exist yet.
424      *
425      * @param existing the existing
426      * @param additional the additional
427      * @return the sets the
428      * @throws MojoExecutionException the mojo execution exception
429      */
430     public Set<Plugin> addAdditionalPlugins( Set<Plugin> existing, List<String> additional )
431         throws MojoExecutionException
432     {
433         if ( additional != null )
434         {
435             for ( String pluginString : additional )
436             {
437                 Plugin plugin = parsePluginString( pluginString, "AdditionalPlugins" );
438 
439                 if ( existing == null )
440                 {
441                     existing = new HashSet<Plugin>();
442                     existing.add( plugin );
443                 }
444                 else if ( !existing.contains( plugin ) )
445                 {
446                     existing.add( plugin );
447                 }
448             }
449         }
450         return existing;
451     }
452 
453     /**
454      * Helper method to parse and inject a Plugin.
455      *
456      * @param pluginString
457      * @param field 
458      * @throws MojoExecutionException
459      * @return the plugin
460      */
461     protected Plugin parsePluginString( String pluginString, String field )
462         throws MojoExecutionException
463     {
464         if ( pluginString != null )
465         {
466             String[] pluginStrings = pluginString.split( ":" );
467             if ( pluginStrings.length == 2 )
468             {
469                 Plugin plugin = new Plugin();
470                 plugin.setGroupId( StringUtils.strip( pluginStrings[0] ) );
471                 plugin.setArtifactId( StringUtils.strip( pluginStrings[1] ) );
472 
473                 return plugin;
474             }
475             else
476             {
477                 throw new MojoExecutionException( "Invalid " + field + " string: " + pluginString );
478             }
479         }
480         else
481         {
482             throw new MojoExecutionException( "Invalid " + field + " string: " + pluginString );
483         }
484 
485     }
486 
487     /**
488      * Finds the plugins that are listed in active profiles.
489      *
490      * @param project the project
491      * @return the profile plugins
492      */
493     public Set<Plugin> getProfilePlugins( MavenProject project )
494     {
495         Set<Plugin> result = new HashSet<Plugin>();
496         @SuppressWarnings( "unchecked" )
497         List<Profile> profiles = project.getActiveProfiles();
498         if ( profiles != null && !profiles.isEmpty() )
499         {
500             for ( Profile p : profiles )
501             {
502                 BuildBase b = p.getBuild();
503                 if ( b != null )
504                 {
505                     @SuppressWarnings( "unchecked" )
506                     List<Plugin> plugins = b.getPlugins();
507                     if ( plugins != null )
508                     {
509                         result.addAll( plugins );
510                     }
511                 }
512             }
513         }
514         return result;
515     }
516 
517     /**
518      * Given a plugin, this will retrieve the matching plugin artifact from the model.
519      *
520      * @param plugin plugin to lookup
521      * @param project project to search
522      * @return matching plugin, <code>null</code> if not found.
523      */
524     protected Plugin findCurrentPlugin( Plugin plugin, MavenProject project )
525     {
526         Plugin found = null;
527         try
528         {
529             Model model = project.getModel();
530             @SuppressWarnings( "unchecked" )
531             Map<String, Plugin> plugins = model.getBuild().getPluginsAsMap();
532             found = plugins.get( plugin.getKey() );
533         }
534         catch ( NullPointerException e )
535         {
536             // nothing to do here
537         }
538 
539         if ( found == null )
540         {
541             found = resolvePlugin( plugin, project );
542         }
543 
544         return found;
545     }
546 
547     /**
548      * Resolve plugin.
549      *
550      * @param plugin the plugin
551      * @param project the project
552      * @return the plugin
553      */
554     protected Plugin resolvePlugin( Plugin plugin, MavenProject project )
555     {
556 
557         @SuppressWarnings( "unchecked" )
558         List<ArtifactRepository> pluginRepositories = project.getPluginArtifactRepositories();
559         Artifact artifact =
560             factory.createPluginArtifact( plugin.getGroupId(), plugin.getArtifactId(),
561                                           VersionRange.createFromVersion( "LATEST" ) );
562 
563         try
564         {
565             this.resolver.resolve( artifact, pluginRepositories, this.local );
566             plugin.setVersion( artifact.getVersion() );
567         }
568         catch ( ArtifactResolutionException e )
569         {
570         }
571         catch ( ArtifactNotFoundException e )
572         {
573         }
574 
575         return plugin;
576     }
577 
578     /**
579      * Gets the plugins that are bound to the defined phases. This does not find plugins bound in the pom to a phase
580      * later than the plugin is executing.
581      *
582      * @param life the life
583      * @param project the project
584      * @param thePhases the the phases
585      * @return the bound plugins
586      * @throws PluginNotFoundException the plugin not found exception
587      * @throws LifecycleExecutionException the lifecycle execution exception
588      * @throws IllegalAccessException the illegal access exception
589      */
590     protected Set<Plugin> getBoundPlugins( LifecycleExecutor life, MavenProject project, String thePhases )
591         throws PluginNotFoundException, LifecycleExecutionException, IllegalAccessException
592     {
593 
594         Set<Plugin> allPlugins = new HashSet<Plugin>();
595 
596         // lookup the bindings for all the passed in phases
597         String[] lifecyclePhases = thePhases.split( "," );
598         for ( int i = 0; i < lifecyclePhases.length; i++ )
599         {
600             String lifecyclePhase = lifecyclePhases[i];
601             if ( StringUtils.isNotEmpty( lifecyclePhase ) )
602             {
603                 try
604                 {
605                     Lifecycle lifecycle = getLifecycleForPhase( lifecyclePhase );
606                     allPlugins.addAll( getAllPlugins( project, lifecycle ) );
607                 }
608                 catch ( BuildFailureException e )
609                 {
610                     // i'm going to swallow this because the
611                     // user may have declared a phase that
612                     // doesn't exist for every module.
613                 }
614             }
615         }
616         return allPlugins;
617     }
618 
619     /*
620      * Checks to see if the version is specified for the plugin. Can optionally ban "RELEASE" or "LATEST" even if
621      * specified.
622      */
623     /**
624      * Checks for valid version specified.
625      *
626      * @param helper the helper
627      * @param source the source
628      * @param pluginWrappers the plugins
629      * @return true, if successful
630      */
631     protected boolean hasValidVersionSpecified( EnforcerRuleHelper helper, Plugin source, List<PluginWrapper> pluginWrappers )
632     {
633         boolean found = false;
634         boolean status = false;
635         for ( PluginWrapper plugin : pluginWrappers )
636         {
637             // find the matching plugin entry
638             if ( source.getArtifactId().equals( plugin.getArtifactId() )
639                 && source.getGroupId().equals( plugin.getGroupId() ) )
640             {
641                 found = true;
642                 // found the entry. now see if the version is specified
643                 String version = plugin.getVersion();
644                 try
645                 {
646                     version = (String) helper.evaluate( version );
647                 }
648                 catch ( ExpressionEvaluationException e )
649                 {
650                     return false;
651                 }
652 
653                 if ( StringUtils.isNotEmpty( version ) && !StringUtils.isWhitespace( version ) )
654                 {
655 
656                     if ( banRelease && version.equals( "RELEASE" ) )
657                     {
658                         return false;
659                     }
660 
661                     if ( banLatest && version.equals( "LATEST" ) )
662                     {
663                         return false;
664                     }
665 
666                     if ( banSnapshots && isSnapshot( version ) )
667                     {
668                         return false;
669                     }
670                     // the version was specified and not
671                     // banned. It's ok. Keep looking through the list to make
672                     // sure it's not using a banned version somewhere else.
673 
674                     status = true;
675 
676                     if ( !banRelease && !banLatest && !banSnapshots )
677                     {
678                         // no need to keep looking
679                         break;
680                     }
681                 }
682             }
683         }
684         if ( !found )
685         {
686             log.debug( "plugin " + source.getGroupId() + ":" + source.getArtifactId() + " not found" );
687         }
688         return status;
689     }
690 
691     /**
692      * Checks if is snapshot.
693      *
694      * @param baseVersion the base version
695      * @return true, if is snapshot
696      */
697     protected boolean isSnapshot( String baseVersion )
698     {
699         if ( banTimestamps )
700         {
701             return Artifact.VERSION_FILE_PATTERN.matcher( baseVersion ).matches()
702                 || baseVersion.endsWith( Artifact.SNAPSHOT_VERSION );
703         }
704         else
705         {
706             return baseVersion.endsWith( Artifact.SNAPSHOT_VERSION );
707         }
708     }
709 
710     /*
711      * Uses borrowed lifecycle code to get a list of all plugins bound to the lifecycle.
712      */
713     /**
714      * Gets the all plugins.
715      *
716      * @param project the project
717      * @param lifecycle the lifecycle
718      * @return the all plugins
719      * @throws PluginNotFoundException the plugin not found exception
720      * @throws LifecycleExecutionException the lifecycle execution exception
721      */
722     @SuppressWarnings( "unchecked" )
723     private Set<Plugin> getAllPlugins( MavenProject project, Lifecycle lifecycle )
724         throws PluginNotFoundException, LifecycleExecutionException
725 
726     {
727         log.debug( "RequirePluginVersions.getAllPlugins:" );
728 
729         Set<Plugin> plugins = new HashSet<Plugin>();
730         // first, bind those associated with the packaging
731         Map mappings = findMappingsForLifecycle( project, lifecycle );
732 
733         Iterator iter = mappings.entrySet().iterator();
734         while ( iter.hasNext() )
735         {
736             Entry entry = (Entry) iter.next();
737             log.debug( "  lifecycleMapping = " + entry.getKey() );
738             String pluginsForLifecycle = (String) entry.getValue();
739             log.debug( "  plugins = " + pluginsForLifecycle );
740             if ( StringUtils.isNotEmpty( pluginsForLifecycle ) )
741             {
742                 String pluginList[] = pluginsForLifecycle.split( "," );
743                 for ( String plugin : pluginList )
744                 {
745                     plugin = StringUtils.strip( plugin );
746                     log.debug( "    plugin = " + plugin );
747                     String tokens[] = plugin.split( ":" );
748                     log.debug( "    GAV = " + Arrays.asList( tokens ) );
749 
750                     Plugin p = new Plugin();
751                     p.setGroupId( tokens[0] );
752                     p.setArtifactId( tokens[1] );
753                     plugins.add( p );
754                 }
755             }
756         }
757 
758         List<String> mojos = findOptionalMojosForLifecycle( project, lifecycle );
759         for ( String value : mojos )
760         {
761             String tokens[] = value.split( ":" );
762 
763             Plugin plugin = new Plugin();
764             plugin.setGroupId( tokens[0] );
765             plugin.setArtifactId( tokens[1] );
766             plugins.add( plugin );
767         }
768 
769         plugins.addAll( project.getBuildPlugins() );
770 
771         return plugins;
772     }
773 
774     /*
775      * NOTE: All the code following this point was scooped from the DefaultLifecycleExecutor. There must be a better way
776      * but for now it should work.
777      */
778     /**
779      * Gets the phase to lifecycle map.
780      *
781      * @return the phase to lifecycle map
782      * @throws LifecycleExecutionException the lifecycle execution exception
783      */
784     public Map<String, Lifecycle> getPhaseToLifecycleMap()
785         throws LifecycleExecutionException
786     {
787         if ( phaseToLifecycleMap == null )
788         {
789             phaseToLifecycleMap = new HashMap<String, Lifecycle>();
790 
791             for ( Lifecycle lifecycle : lifecycles )
792             {
793                 @SuppressWarnings( "unchecked" )
794                 List<String> phases = lifecycle.getPhases(); 
795                 for ( String phase : phases )
796                 {
797                     if ( phaseToLifecycleMap.containsKey( phase ) )
798                     {
799                         Lifecycle prevLifecycle = (Lifecycle) phaseToLifecycleMap.get( phase );
800                         throw new LifecycleExecutionException( "Phase '" + phase
801                             + "' is defined in more than one lifecycle: '" + lifecycle.getId() + "' and '"
802                             + prevLifecycle.getId() + "'" );
803                     }
804                     else
805                     {
806                         phaseToLifecycleMap.put( phase, lifecycle );
807                     }
808                 }
809             }
810         }
811         return phaseToLifecycleMap;
812     }
813 
814     /**
815      * Gets the lifecycle for phase.
816      *
817      * @param phase the phase
818      * @return the lifecycle for phase
819      * @throws BuildFailureException the build failure exception
820      * @throws LifecycleExecutionException the lifecycle execution exception
821      */
822     private Lifecycle getLifecycleForPhase( String phase )
823         throws BuildFailureException, LifecycleExecutionException
824     {
825         Lifecycle lifecycle = (Lifecycle) getPhaseToLifecycleMap().get( phase );
826 
827         if ( lifecycle == null )
828         {
829             throw new BuildFailureException( "Unable to find lifecycle for phase '" + phase + "'" );
830         }
831         return lifecycle;
832     }
833 
834     /**
835      * Find mappings for lifecycle.
836      *
837      * @param project the project
838      * @param lifecycle the lifecycle
839      * @return the map
840      * @throws LifecycleExecutionException the lifecycle execution exception
841      * @throws PluginNotFoundException the plugin not found exception
842      */
843     private Map findMappingsForLifecycle( MavenProject project, Lifecycle lifecycle )
844         throws LifecycleExecutionException, PluginNotFoundException
845     {
846         String packaging = project.getPackaging();
847         Map mappings = null;
848 
849         LifecycleMapping m =
850             (LifecycleMapping) findExtension( project, LifecycleMapping.ROLE, packaging, session.getSettings(),
851                                               session.getLocalRepository() );
852         if ( m != null )
853         {
854             mappings = m.getPhases( lifecycle.getId() );
855         }
856 
857         Map defaultMappings = lifecycle.getDefaultPhases();
858 
859         if ( mappings == null )
860         {
861             try
862             {
863                 m = (LifecycleMapping) session.lookup( LifecycleMapping.ROLE, packaging );
864                 mappings = m.getPhases( lifecycle.getId() );
865             }
866             catch ( ComponentLookupException e )
867             {
868                 if ( defaultMappings == null )
869                 {
870                     throw new LifecycleExecutionException( "Cannot find lifecycle mapping for packaging: \'"
871                         + packaging + "\'.", e );
872                 }
873             }
874         }
875 
876         if ( mappings == null )
877         {
878             if ( defaultMappings == null )
879             {
880                 throw new LifecycleExecutionException( "Cannot find lifecycle mapping for packaging: \'" + packaging
881                     + "\', and there is no default" );
882             }
883             else
884             {
885                 mappings = defaultMappings;
886             }
887         }
888 
889         return mappings;
890     }
891 
892     /**
893      * Find optional mojos for lifecycle.
894      *
895      * @param project the project
896      * @param lifecycle the lifecycle
897      * @return the list
898      * @throws LifecycleExecutionException the lifecycle execution exception
899      * @throws PluginNotFoundException the plugin not found exception
900      */
901     @SuppressWarnings( "unchecked" )
902     private List<String> findOptionalMojosForLifecycle( MavenProject project, Lifecycle lifecycle )
903         throws LifecycleExecutionException, PluginNotFoundException
904     {
905         String packaging = project.getPackaging();
906         List<String> optionalMojos = null;
907 
908         LifecycleMapping m =
909             (LifecycleMapping) findExtension( project, LifecycleMapping.ROLE, packaging, session.getSettings(),
910                                               session.getLocalRepository() );
911 
912         if ( m != null )
913         {
914             optionalMojos = m.getOptionalMojos( lifecycle.getId() );
915         }
916 
917         if ( optionalMojos == null )
918         {
919             try
920             {
921                 m = (LifecycleMapping) session.lookup( LifecycleMapping.ROLE, packaging );
922                 optionalMojos = m.getOptionalMojos( lifecycle.getId() );
923             }
924             catch ( ComponentLookupException e )
925             {
926                 log.debug( "Error looking up lifecycle mapping to retrieve optional mojos. Lifecycle ID: "
927                     + lifecycle.getId() + ". Error: " + e.getMessage(), e );
928             }
929         }
930 
931         if ( optionalMojos == null )
932         {
933             optionalMojos = Collections.emptyList();
934         }
935 
936         return optionalMojos;
937     }
938 
939     /**
940      * Find extension.
941      *
942      * @param project the project
943      * @param role the role
944      * @param roleHint the role hint
945      * @param settings the settings
946      * @param localRepository the local repository
947      * @return the object
948      * @throws LifecycleExecutionException the lifecycle execution exception
949      * @throws PluginNotFoundException the plugin not found exception
950      */
951     private Object findExtension( MavenProject project, String role, String roleHint, Settings settings,
952                                   ArtifactRepository localRepository )
953         throws LifecycleExecutionException, PluginNotFoundException
954     {
955         Object pluginComponent = null;
956 
957         @SuppressWarnings( "unchecked" )
958         List<Plugin> buildPlugins = project.getBuildPlugins();
959         for ( Plugin plugin : buildPlugins )
960         {
961             if ( plugin.isExtensions() )
962             {
963                 verifyPlugin( plugin, project, settings, localRepository );
964 
965                 // TODO: if moved to the plugin manager we
966                 // already have the descriptor from above
967                 // and so do can lookup the container
968                 // directly
969                 try
970                 {
971                     pluginComponent = pluginManager.getPluginComponent( plugin, role, roleHint );
972                     
973                     if ( pluginComponent != null )
974                     {
975                         break;
976                     }
977                 }
978                 catch ( ComponentLookupException e )
979                 {
980                     log.debug( "Unable to find the lifecycle component in the extension", e );
981                 }
982                 catch ( PluginManagerException e )
983                 {
984                     throw new LifecycleExecutionException( "Error getting extensions from the plugin '"
985                         + plugin.getKey() + "': " + e.getMessage(), e );
986                 }
987             }
988         }
989         return pluginComponent;
990     }
991 
992     /**
993      * Verify plugin.
994      *
995      * @param plugin the plugin
996      * @param project the project
997      * @param settings the settings
998      * @param localRepository the local repository
999      * @return the plugin descriptor
1000      * @throws LifecycleExecutionException the lifecycle execution exception
1001      * @throws PluginNotFoundException the plugin not found exception
1002      */
1003     private PluginDescriptor verifyPlugin( Plugin plugin, MavenProject project, Settings settings,
1004                                            ArtifactRepository localRepository )
1005         throws LifecycleExecutionException, PluginNotFoundException
1006     {
1007         PluginDescriptor pluginDescriptor;
1008         try
1009         {
1010             pluginDescriptor = pluginManager.verifyPlugin( plugin, project, settings, localRepository );
1011         }
1012         catch ( PluginManagerException e )
1013         {
1014             throw new LifecycleExecutionException( "Internal error in the plugin manager getting plugin '"
1015                 + plugin.getKey() + "': " + e.getMessage(), e );
1016         }
1017         catch ( PluginVersionResolutionException e )
1018         {
1019             throw new LifecycleExecutionException( e.getMessage(), e );
1020         }
1021         catch ( InvalidVersionSpecificationException e )
1022         {
1023             throw new LifecycleExecutionException( e.getMessage(), e );
1024         }
1025         catch ( InvalidPluginException e )
1026         {
1027             throw new LifecycleExecutionException( e.getMessage(), e );
1028         }
1029         catch ( ArtifactNotFoundException e )
1030         {
1031             throw new LifecycleExecutionException( e.getMessage(), e );
1032         }
1033         catch ( ArtifactResolutionException e )
1034         {
1035             throw new LifecycleExecutionException( e.getMessage(), e );
1036         }
1037         catch ( PluginVersionNotFoundException e )
1038         {
1039             throw new LifecycleExecutionException( e.getMessage(), e );
1040         }
1041         return pluginDescriptor;
1042     }
1043 
1044     /**
1045      * Gets all plugin entries in build.plugins, build.pluginManagement.plugins, profile.build.plugins, reporting and
1046      * profile.reporting in this project and all parents
1047      *
1048      * @param project the project
1049      * @return the all plugin entries wrapped in a PluginWrapper Object
1050      * @throws ArtifactResolutionException the artifact resolution exception
1051      * @throws ArtifactNotFoundException the artifact not found exception
1052      * @throws IOException Signals that an I/O exception has occurred.
1053      * @throws XmlPullParserException the xml pull parser exception
1054      */
1055     protected List<PluginWrapper> getAllPluginEntries( MavenProject project )
1056         throws ArtifactResolutionException, ArtifactNotFoundException, IOException, XmlPullParserException
1057     {
1058         List<PluginWrapper> plugins = new ArrayList<PluginWrapper>();
1059         // get all the pom models
1060         
1061         String pomName = null;
1062         try
1063         {
1064             pomName = project.getFile().getName();
1065         }
1066         catch ( Exception e )
1067         {
1068             pomName = "pom.xml";
1069         }
1070         List<Model> models =
1071             utils.getModelsRecursively( project.getGroupId(), project.getArtifactId(), project.getVersion(),
1072                                         new File( project.getBasedir(), pomName ) );
1073 
1074         // now find all the plugin entries, either in
1075         // build.plugins or build.pluginManagement.plugins, profiles.plugins and reporting
1076         for ( Model model : models )
1077         {
1078             try
1079             {
1080                 List<Plugin> modelPlugins =  model.getBuild().getPlugins();
1081                 plugins.addAll( PluginWrapper.addAll( utils.resolvePlugins( modelPlugins ), model.getId() + ".build.plugins" ) );
1082             }
1083             catch ( NullPointerException e )
1084             {
1085                 // guess there are no plugins here.
1086             }
1087 
1088             try
1089             {
1090                 List<ReportPlugin> modelReportPlugins =  model.getReporting().getPlugins();
1091                 // add the reporting plugins
1092                 plugins.addAll( PluginWrapper.addAll( utils.resolveReportPlugins( modelReportPlugins ), model.getId() + ".reporting" ) );
1093             }
1094             catch ( NullPointerException e )
1095             {
1096                 // guess there are no plugins here.
1097             }
1098 
1099             try
1100             {
1101                 List<Plugin> modelPlugins =  model.getBuild().getPluginManagement().getPlugins();
1102                 plugins.addAll( PluginWrapper.addAll( utils.resolvePlugins( modelPlugins ),
1103                                                       model.getId() + ".build.pluginManagement.plugins" ) );
1104             }
1105             catch ( NullPointerException e )
1106             {
1107                 // guess there are no plugins here.
1108             }
1109 
1110             // Add plugins in profiles
1111             @SuppressWarnings( "unchecked" )
1112             List<Profile> profiles = model.getProfiles();
1113             for ( Profile profile : profiles )
1114             {
1115                 try
1116                 {
1117                     List<Plugin> modelPlugins =  profile.getBuild().getPlugins();
1118                     plugins.addAll( PluginWrapper.addAll( utils.resolvePlugins( modelPlugins ), model.getId()
1119                         + ".profiles.profile[" + profile.getId() + "].build.plugins" ) );
1120                 }
1121                 catch ( NullPointerException e )
1122                 {
1123                     // guess there are no plugins here.
1124                 }
1125 
1126                 try
1127                 {
1128                     List<ReportPlugin> modelReportPlugins =  profile.getReporting().getPlugins();
1129                     // add the reporting plugins
1130                     plugins.addAll( PluginWrapper.addAll( utils.resolveReportPlugins( modelReportPlugins ), model.getId()
1131                         + "profile[" + profile.getId() + "].reporting.plugins" ) );
1132                 }
1133                 catch ( NullPointerException e )
1134                 {
1135                     // guess there are no plugins here.
1136                 }
1137                 try
1138                 {
1139                     List<Plugin> modelPlugins =  profile.getBuild().getPluginManagement().getPlugins();
1140                     plugins.addAll( PluginWrapper.addAll( utils.resolvePlugins( modelPlugins ),
1141                                                           model.getId() + "profile[" + profile.getId()
1142                                                               + "].build.pluginManagement.plugins" ) );
1143                 }
1144                 catch ( NullPointerException e )
1145                 {
1146                     // guess there are no plugins here.
1147                 }
1148             }
1149         }
1150 
1151         return plugins;
1152     }
1153 
1154     /**
1155      * Checks if is ban latest.
1156      *
1157      * @return the banLatest
1158      */
1159     protected boolean isBanLatest()
1160     {
1161         return this.banLatest;
1162     }
1163 
1164     /**
1165      * Sets the ban latest.
1166      *
1167      * @param theBanLatest the banLatest to set
1168      */
1169     protected void setBanLatest( boolean theBanLatest )
1170     {
1171         this.banLatest = theBanLatest;
1172     }
1173 
1174     /**
1175      * Checks if is ban release.
1176      *
1177      * @return the banRelease
1178      */
1179     protected boolean isBanRelease()
1180     {
1181         return this.banRelease;
1182     }
1183 
1184     /**
1185      * Sets the ban release.
1186      *
1187      * @param theBanRelease the banRelease to set
1188      */
1189     protected void setBanRelease( boolean theBanRelease )
1190     {
1191         this.banRelease = theBanRelease;
1192     }
1193 
1194     /**
1195      * Gets the utils.
1196      *
1197      * @return the utils
1198      */
1199     protected EnforcerRuleUtils getUtils()
1200     {
1201         return this.utils;
1202     }
1203 
1204     /**
1205      * Sets the utils.
1206      *
1207      * @param theUtils the utils to set
1208      */
1209     protected void setUtils( EnforcerRuleUtils theUtils )
1210     {
1211         this.utils = theUtils;
1212     }
1213 
1214     /**
1215      * Checks if is ban snapshots.
1216      *
1217      * @return the banSnapshots
1218      */
1219     public boolean isBanSnapshots()
1220     {
1221         return this.banSnapshots;
1222     }
1223 
1224     /**
1225      * Sets the ban snapshots.
1226      *
1227      * @param theBanSnapshots the banSnapshots to set
1228      */
1229     public void setBanSnapshots( boolean theBanSnapshots )
1230     {
1231         this.banSnapshots = theBanSnapshots;
1232     }
1233 
1234     /**
1235      * Checks if is ban timestamps.
1236      *
1237      * @return the banTimestamps
1238      */
1239     public boolean isBanTimestamps()
1240     {
1241         return this.banTimestamps;
1242     }
1243 
1244     /**
1245      * Sets the ban timestamps.
1246      *
1247      * @param theBanTimestamps the banTimestamps to set
1248      */
1249     public void setBanTimestamps( boolean theBanTimestamps )
1250     {
1251         this.banTimestamps = theBanTimestamps;
1252     }
1253 
1254     public List getUnCheckedPlugins()
1255     {
1256         return unCheckedPlugins;
1257     }
1258 
1259     public void setUnCheckedPlugins( List unCheckedPlugins )
1260     {
1261         this.unCheckedPlugins = unCheckedPlugins;
1262     }
1263     
1264     public final void setPhases( String phases )
1265     {
1266         this.phases = phases;
1267     }
1268     
1269     public final String getPhases()
1270     {
1271         return phases;
1272     }
1273     
1274     public final void setAdditionalPlugins( List<String> additionalPlugins )
1275     {
1276         this.additionalPlugins = additionalPlugins;
1277     }
1278     
1279     public final List<String> getAdditionalPlugins()
1280     {
1281         return additionalPlugins;
1282     }
1283 }