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