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