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.Iterator;
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 1127643 2011-05-25 19:24:38Z krosenvold $
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 cache = new Hashtable();
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             ArrayList list = new ArrayList();
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                     Iterator iter = list.iterator();
217                     while ( iter.hasNext() )
218                     {
219                         String failure = (String) iter.next();
220                         log.warn( failure );
221                     }
222                     if ( fail )
223                     {
224                         throw new MojoExecutionException(
225                                                           "Some Enforcer rules have failed. Look above for specific messages explaining why the rule failed." );
226                     }
227                 }
228             }
229             else
230             {
231                 throw new MojoExecutionException(
232                                                   "No rules are configured. Use the skip flag if you want to disable execution." );
233             }
234         }
235         else
236         {
237             log.info( "Skipping Rule Enforcement." );
238         }
239     }
240 
241     /**
242      * This method determines if a rule should execute based
243      * on the cache
244      * 
245      * @param rule
246      * @return
247      */
248     protected boolean shouldExecute ( EnforcerRule rule )
249     {
250         if ( rule.isCacheable() )
251         {
252             Log log = this.getLog();
253             log.debug( "Rule " + rule.getClass().getName() + " is cacheable." );
254             String key = rule.getClass().getName() + " " + rule.getCacheId();
255             if ( EnforceMojo.cache.containsKey( key ) )
256             {
257                 log.debug( "Key " + key + " was found in the cache" );
258                 if ( rule.isResultValid( (EnforcerRule) cache.get( key ) ) )
259                 {
260                     log.debug( "The cached results are still valid. Skipping the rule: "+rule.getClass().getName() );
261                     return false;
262                 }
263             }
264             
265             //add it to the cache of executed rules
266             EnforceMojo.cache.put( key, rule );
267         }
268         return true;
269     }
270 
271     /**
272      * @return the fail
273      */
274     public boolean isFail ()
275     {
276         return this.fail;
277     }
278 
279     /**
280      * @param theFail the fail to set
281      */
282     public void setFail ( boolean theFail )
283     {
284         this.fail = theFail;
285     }
286 
287     /**
288      * @return the rules
289      */
290     public EnforcerRule[] getRules ()
291     {
292         return this.rules;
293     }
294 
295     /**
296      * @param theRules the rules to set
297      */
298     public void setRules ( EnforcerRule[] theRules )
299     {
300         this.rules = theRules;
301     }
302 
303     /**
304      * @return the skip
305      */
306     public boolean isSkip ()
307     {
308         return this.skip;
309     }
310 
311     /**
312      * @param theSkip the skip to set
313      */
314     public void setSkip ( boolean theSkip )
315     {
316         this.skip = theSkip;
317     }
318 
319     /**
320      * @return the failFast
321      */
322     public boolean isFailFast ()
323     {
324         return this.failFast;
325     }
326 
327     /**
328      * @param theFailFast the failFast to set
329      */
330     public void setFailFast ( boolean theFailFast )
331     {
332         this.failFast = theFailFast;
333     }
334 
335     /**
336      * @return the project
337      */
338     public MavenProject getProject ()
339     {
340         return this.project;
341     }
342 
343     /**
344      * @param theProject the project to set
345      */
346     public void setProject ( MavenProject theProject )
347     {
348         this.project = theProject;
349     }
350 
351     /**
352      * @return the session
353      */
354     public MavenSession getSession ()
355     {
356         return this.session;
357     }
358 
359     /**
360      * @param theSession the session to set
361      */
362     public void setSession ( MavenSession theSession )
363     {
364         this.session = theSession;
365     }
366 
367     /**
368      * @return the translator
369      */
370     public PathTranslator getTranslator ()
371     {
372         return this.translator;
373     }
374 
375     /**
376      * @param theTranslator the translator to set
377      */
378     public void setTranslator ( PathTranslator theTranslator )
379     {
380         this.translator = theTranslator;
381     }
382 }