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 }