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