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