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.util.ArrayList;
23  import java.util.Hashtable;
24  import java.util.List;
25  
26  import org.apache.maven.enforcer.rule.api.EnforcerRule;
27  import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
28  import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
29  import org.apache.maven.execution.MavenSession;
30  import org.apache.maven.plugin.AbstractMojo;
31  import org.apache.maven.plugin.MojoExecutionException;
32  import org.apache.maven.plugin.logging.Log;
33  import org.apache.maven.plugins.annotations.Component;
34  import org.apache.maven.plugins.annotations.LifecyclePhase;
35  import org.apache.maven.plugins.annotations.Mojo;
36  import org.apache.maven.plugins.annotations.Parameter;
37  import org.apache.maven.plugins.annotations.ResolutionScope;
38  import org.apache.maven.project.MavenProject;
39  import org.apache.maven.project.path.PathTranslator;
40  import org.codehaus.plexus.PlexusConstants;
41  import org.codehaus.plexus.PlexusContainer;
42  import org.codehaus.plexus.context.Context;
43  import org.codehaus.plexus.context.ContextException;
44  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
45  
46  /**
47   * This goal executes the defined enforcer-rules once per
48   * module.
49   * 
50   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
51   * @version $Id: EnforceMojo.java 1411846 2012-11-20 20:29:54Z hboutemy $
52   */
53  @Mojo( name = "enforce", defaultPhase = LifecyclePhase.VALIDATE, threadSafe = true,
54                  requiresDependencyResolution = ResolutionScope.TEST )
55  public class EnforceMojo
56      extends AbstractMojo
57      implements Contextualizable
58  {
59  
60      /**
61       * Path Translator needed by the ExpressionEvaluator
62       */
63      @Component( role = PathTranslator.class )
64      protected PathTranslator translator;
65  
66      /**
67       * The MavenSession
68       */
69      @Component
70      protected MavenSession session;
71  
72      /**
73       * POM
74       */
75      @Component
76      protected MavenProject project;
77  
78      /**
79       * Flag to fail the build if a version check fails.
80       */
81      @Parameter( property = "enforcer.fail", defaultValue = "true" )
82      protected boolean fail = true;
83  
84      /**
85       * Flag to easily skip all checks
86       */
87      @Parameter( property = "enforcer.skip", defaultValue = "false" )
88      protected boolean skip = false;
89  
90      /**
91       * Fail on the first rule that doesn't pass
92       */
93      @Parameter( property = "enforcer.failFast", defaultValue = "false" )
94      protected boolean failFast = false;
95  
96      /**
97       * Array of objects that implement the EnforcerRule
98       * interface to execute.
99       */
100     @Parameter( required = true )
101     private EnforcerRule[] rules;
102     
103     /**
104      * Use this flag to disable rule result caching. This will cause
105      * all rules to execute on each project even if the rule indicates it can
106      * safely be cached.
107      */
108     @Parameter( property = "enforcer.ignoreCache", defaultValue = "false" )
109     protected boolean ignoreCache = false;
110     
111     /**
112      * This is a static variable used to persist the cached results across plugin invocations.
113      */
114     protected static Hashtable<String, EnforcerRule> cache = new Hashtable<String, EnforcerRule>();
115 
116     
117     // set by the contextualize method. Only way to get the
118     // plugin's container in 2.0.x
119     protected PlexusContainer container;
120 
121     public void contextualize ( Context context )
122         throws ContextException
123     {
124         container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
125     }
126     
127     /**
128      * Entry point to the mojo
129      */
130     public void execute ()
131         throws MojoExecutionException
132     {
133         Log log = this.getLog();
134 
135         EnforcerExpressionEvaluator evaluator = new EnforcerExpressionEvaluator( session, translator, project );
136 
137         // the entire execution can be easily skipped
138         if ( !skip )
139         {
140             // list to store exceptions
141             List<String> list = new ArrayList<String>();
142 
143             // make sure the rules exist
144             if ( rules != null && rules.length > 0 )
145             {
146                 String currentRule = "Unknown";
147 
148                 // create my helper
149                 EnforcerRuleHelper helper = new DefaultEnforcementRuleHelper( session, evaluator, log, container );
150 
151                 // if we are only warning, then disable
152                 // failFast
153                 if ( !fail )
154                 {
155                     failFast = false;
156                 }
157 
158                 // go through each rule
159                 for ( int i = 0; i < rules.length; i++ )
160                 {
161 
162                     // prevent against empty rules
163                     EnforcerRule rule = rules[i];
164                     if ( rule != null )
165                     {
166                         // store the current rule for
167                         // logging purposes
168                         currentRule = rule.getClass().getName();
169                         log.debug( "Executing rule: " + currentRule );
170                         try
171                         {
172                             if ( ignoreCache || shouldExecute( rule ) )
173                             {
174                                 // execute the rule
175                                 //noinspection SynchronizationOnLocalVariableOrMethodParameter
176                                 synchronized ( rule )
177                                 {
178                                    rule.execute( helper );
179                                 }
180                             }
181                         }
182                         catch ( EnforcerRuleException e )
183                         {
184                             // i can throw an exception
185                             // because failfast will be
186                             // false if fail is false.
187                             if ( failFast )
188                             {
189                                 throw new MojoExecutionException( currentRule + " failed with message:\n"
190                                     + e.getMessage(), e );
191                             }
192                             else
193                             {
194                                 list.add( "Rule " + i + ": " + currentRule + " failed with message:\n" + e.getMessage() );
195                                 log.debug( "Adding failure due to exception", e );
196                             }
197                         }
198                     }
199                 }
200 
201                 // if we found anything
202                 if ( !list.isEmpty() )
203                 {
204                     for ( String failure  : list )
205                     {
206                         log.warn( failure );
207                     }
208                     if ( fail )
209                     {
210                         throw new MojoExecutionException(
211                                                           "Some Enforcer rules have failed. Look above for specific messages explaining why the rule failed." );
212                     }
213                 }
214             }
215             else
216             {
217                 throw new MojoExecutionException(
218                                                   "No rules are configured. Use the skip flag if you want to disable execution." );
219             }
220         }
221         else
222         {
223             log.info( "Skipping Rule Enforcement." );
224         }
225     }
226 
227     /**
228      * This method determines if a rule should execute based
229      * on the cache
230      * 
231      * @param rule
232      * @return
233      */
234     protected boolean shouldExecute ( EnforcerRule rule )
235     {
236         if ( rule.isCacheable() )
237         {
238             Log log = this.getLog();
239             log.debug( "Rule " + rule.getClass().getName() + " is cacheable." );
240             String key = rule.getClass().getName() + " " + rule.getCacheId();
241             if ( EnforceMojo.cache.containsKey( key ) )
242             {
243                 log.debug( "Key " + key + " was found in the cache" );
244                 if ( rule.isResultValid( (EnforcerRule) cache.get( key ) ) )
245                 {
246                     log.debug( "The cached results are still valid. Skipping the rule: "+rule.getClass().getName() );
247                     return false;
248                 }
249             }
250             
251             //add it to the cache of executed rules
252             EnforceMojo.cache.put( key, rule );
253         }
254         return true;
255     }
256 
257     /**
258      * @return the fail
259      */
260     public boolean isFail ()
261     {
262         return this.fail;
263     }
264 
265     /**
266      * @param theFail the fail to set
267      */
268     public void setFail ( boolean theFail )
269     {
270         this.fail = theFail;
271     }
272 
273     /**
274      * @return the rules
275      */
276     public EnforcerRule[] getRules ()
277     {
278         return this.rules;
279     }
280 
281     /**
282      * @param theRules the rules to set
283      */
284     public void setRules ( EnforcerRule[] theRules )
285     {
286         this.rules = theRules;
287     }
288 
289     /**
290      * @return the skip
291      */
292     public boolean isSkip ()
293     {
294         return this.skip;
295     }
296 
297     /**
298      * @param theSkip the skip to set
299      */
300     public void setSkip ( boolean theSkip )
301     {
302         this.skip = theSkip;
303     }
304 
305     /**
306      * @return the failFast
307      */
308     public boolean isFailFast ()
309     {
310         return this.failFast;
311     }
312 
313     /**
314      * @param theFailFast the failFast to set
315      */
316     public void setFailFast ( boolean theFailFast )
317     {
318         this.failFast = theFailFast;
319     }
320 
321     /**
322      * @return the project
323      */
324     public MavenProject getProject ()
325     {
326         return this.project;
327     }
328 
329     /**
330      * @param theProject the project to set
331      */
332     public void setProject ( MavenProject theProject )
333     {
334         this.project = theProject;
335     }
336 
337     /**
338      * @return the session
339      */
340     public MavenSession getSession ()
341     {
342         return this.session;
343     }
344 
345     /**
346      * @param theSession the session to set
347      */
348     public void setSession ( MavenSession theSession )
349     {
350         this.session = theSession;
351     }
352 
353     /**
354      * @return the translator
355      */
356     public PathTranslator getTranslator ()
357     {
358         return this.translator;
359     }
360 
361     /**
362      * @param theTranslator the translator to set
363      */
364     public void setTranslator ( PathTranslator theTranslator )
365     {
366         this.translator = theTranslator;
367     }
368 }