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