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