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