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