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