View Javadoc
1   /*******************************************************************************
2    * Portions created by Sebastian Thomschke are copyright (c) 2005-2014 Sebastian
3    * Thomschke.
4    *
5    * All Rights Reserved. This program and the accompanying materials
6    * are made available under the terms of the Eclipse Public License v1.0
7    * which accompanies this distribution, and is available at
8    * http://www.eclipse.org/legal/epl-v10.html
9    *
10   * Contributors:
11   *     Sebastian Thomschke - initial implementation.
12   *******************************************************************************/
13  package net.sf.oval.guard;
14  
15  import java.lang.reflect.Constructor;
16  import java.lang.reflect.Method;
17  import java.util.Collection;
18  import java.util.Iterator;
19  import java.util.LinkedHashSet;
20  import java.util.LinkedList;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Set;
24  import java.util.WeakHashMap;
25  
26  import net.sf.oval.Check;
27  import net.sf.oval.CheckExclusion;
28  import net.sf.oval.ConstraintViolation;
29  import net.sf.oval.Validator;
30  import net.sf.oval.configuration.Configurer;
31  import net.sf.oval.context.ConstructorParameterContext;
32  import net.sf.oval.context.MethodEntryContext;
33  import net.sf.oval.context.MethodExitContext;
34  import net.sf.oval.context.MethodParameterContext;
35  import net.sf.oval.context.MethodReturnValueContext;
36  import net.sf.oval.context.OValContext;
37  import net.sf.oval.exception.ConstraintsViolatedException;
38  import net.sf.oval.exception.InvalidConfigurationException;
39  import net.sf.oval.exception.OValException;
40  import net.sf.oval.exception.ValidationFailedException;
41  import net.sf.oval.expression.ExpressionLanguage;
42  import net.sf.oval.internal.ClassChecks;
43  import net.sf.oval.internal.ContextCache;
44  import net.sf.oval.internal.Log;
45  import net.sf.oval.internal.ParameterChecks;
46  import net.sf.oval.internal.util.ArrayUtils;
47  import net.sf.oval.internal.util.Assert;
48  import net.sf.oval.internal.util.IdentitySet;
49  import net.sf.oval.internal.util.Invocable;
50  import net.sf.oval.internal.util.ReflectionUtils;
51  import net.sf.oval.internal.util.ThreadLocalList;
52  import net.sf.oval.internal.util.ThreadLocalWeakHashMap;
53  
54  /**
55   * Extended version of the validator to realize programming by contract.
56   *
57   * @author Sebastian Thomschke
58   */
59  public class Guard extends Validator
60  {
61  	/**
62  	 * <b>Note:</b> Only required until AspectJ allows throwing of checked exceptions
63  	 */
64  	protected static final class GuardMethodPreResult
65  	{
66  		protected final boolean checkInvariants;
67  		protected final Method method;
68  		protected final Object[] args;
69  		protected final ClassChecks cc;
70  		protected final List<ConstraintViolation> violations;
71  		protected final Map<PostCheck, Object> postCheckOldValues;
72  		protected final Object guardedObject;
73  
74  		public GuardMethodPreResult(final Object guardedObject, final Method method, final Object[] args, final ClassChecks cc,
75  				final boolean checkInvariants, final Map<PostCheck, Object> postCheckOldValues, final List<ConstraintViolation> violations)
76  		{
77  			this.guardedObject = guardedObject;
78  			this.method = method;
79  			this.args = args;
80  			this.cc = cc;
81  			this.checkInvariants = checkInvariants;
82  			this.postCheckOldValues = postCheckOldValues;
83  			this.violations = violations;
84  		}
85  	}
86  
87  	/**
88  	 * <b>Note:</b> Only required until AspectJ allows throwing of checked exceptions
89  	 */
90  	protected static final GuardMethodPreResult DO_NOT_PROCEED = new GuardMethodPreResult(null, null, null, null, false, null, null);
91  
92  	private static final Log LOG = Log.getLog(Guard.class);
93  
94  	/**
95  	 * string based on validated object hashcode + method hashcode for currently validated method return values
96  	 */
97  	private static final ThreadLocalList<String> currentlyCheckingMethodReturnValues = new ThreadLocalList<String>();
98  
99  	/**
100 	 * string based on validated object hashcode + method hashcode for currently validated method pre-conditions
101 	 */
102 	private static final ThreadLocalList<String> currentlyCheckingPreConditions = new ThreadLocalList<String>();
103 
104 	/**
105 	 * string based on validated object hashcode + method hashcode for currently validated method post-conditions
106 	 */
107 	private static final ThreadLocalList<String> currentlyCheckingPostConditions = new ThreadLocalList<String>();
108 
109 	private boolean isActivated = true;
110 	private boolean isInvariantsEnabled = true;
111 	private boolean isPreConditionsEnabled = true;
112 	private boolean isPostConditionsEnabled = true;
113 
114 	/**
115 	 * Flag that indicates if any listeners were registered at any time. Used for improved performance.
116 	 */
117 	private boolean isListenersFeatureUsed = false;
118 	/**
119 	 * Flag that indicates if exception suppressing was used at any time. Used for improved performance.
120 	 */
121 	private boolean isProbeModeFeatureUsed = false;
122 
123 	private final Set<ConstraintsViolatedListener> listeners = new IdentitySet<ConstraintsViolatedListener>(4);
124 
125 	private final Map<Class< ? >, Set<ConstraintsViolatedListener>> listenersByClass = new WeakHashMap<Class< ? >, Set<ConstraintsViolatedListener>>(
126 			4);
127 
128 	private final Map<Object, Set<ConstraintsViolatedListener>> listenersByObject = new WeakHashMap<Object, Set<ConstraintsViolatedListener>>(
129 			4);
130 
131 	/**
132 	 * Objects for OVal suppresses occurring ConstraintViolationExceptions for pre condition violations on setter methods
133 	 * for the current thread.
134 	 */
135 	private final ThreadLocalWeakHashMap<Object, ProbeModeListener> objectsInProbeMode = new ThreadLocalWeakHashMap<Object, ProbeModeListener>();
136 
137 	/**
138 	 * Constructs a new guard object and uses a new instance of AnnotationsConfigurer
139 	 */
140 	public Guard()
141 	{
142 		super();
143 	}
144 
145 	public Guard(final Collection<Configurer> configurers)
146 	{
147 		super(configurers);
148 	}
149 
150 	public Guard(final Configurer... configurers)
151 	{
152 		super(configurers);
153 	}
154 
155 	private List<CheckExclusion> _getActiveExclusions(final Set<CheckExclusion> exclusions)
156 	{
157 		final List<CheckExclusion> activeExclusions = new LinkedList<CheckExclusion>(exclusions);
158 		for (final Iterator<CheckExclusion> it = activeExclusions.iterator(); it.hasNext();)
159 		{
160 			final CheckExclusion exclusion = it.next();
161 			if (!isAnyProfileEnabled(exclusion.getProfiles(), null)) it.remove();
162 		}
163 		return activeExclusions.size() == 0 ? null : activeExclusions;
164 	}
165 
166 	private void _validateParameterChecks(final ParameterChecks checks, final Object validatedObject, final Object valueToValidate,
167 			final OValContext context, final List<ConstraintViolation> violations)
168 	{
169 		// determine the active exclusions based on the active profiles
170 		final List<CheckExclusion> activeExclusions = checks.hasExclusions() ? _getActiveExclusions(checks.checkExclusions) : null;
171 
172 		// check the constraints
173 		for (final Check check : checks.checks)
174 		{
175 			boolean skip = false;
176 
177 			if (activeExclusions != null)
178 				for (final CheckExclusion exclusion : activeExclusions)
179 					if (exclusion.isActive(validatedObject, valueToValidate, this)
180 							&& exclusion.isCheckExcluded(check, validatedObject, valueToValidate, context, this))
181 					{
182 						// skip if this check should be excluded
183 						skip = true;
184 						continue;
185 					}
186 			if (!skip) checkConstraint(violations, check, validatedObject, valueToValidate, context, null, false);
187 		}
188 	}
189 
190 	/**
191 	 * Registers constraint checks for the given constructor parameter
192 	 *
193 	 * @param ctor
194 	 * @param paramIndex
195 	 * @param exclusions
196 	 * @throws IllegalArgumentException if <code>method == null</code> or <code>exclusions == null</code> or exclusions is empty
197 	 * @throws InvalidConfigurationException if the declaring class is not guarded or the parameterIndex is out of range
198 	 */
199 	public void addCheckExclusions(final Constructor< ? > ctor, final int paramIndex, final CheckExclusion... exclusions)
200 			throws IllegalArgumentException, InvalidConfigurationException
201 	{
202 		Assert.argumentNotNull("ctor", ctor);
203 		Assert.argumentNotEmpty("exclusions", exclusions);
204 
205 		getClassChecks(ctor.getDeclaringClass()).addConstructorParameterCheckExclusions(ctor, paramIndex, exclusions);
206 	}
207 
208 	/**
209 	 * Registers constraint checks for the given method parameter
210 	 *
211 	 * @param method
212 	 * @param paramIndex
213 	 * @param exclusions
214 	 * @throws IllegalArgumentException if <code>method == null</code> or <code>exclusions == null</code> or exclusions is empty
215 	 * @throws InvalidConfigurationException if the declaring class is not guarded or the parameterIndex is out of range
216 	 */
217 	public void addCheckExclusions(final Method method, final int paramIndex, final CheckExclusion... exclusions)
218 			throws IllegalArgumentException, InvalidConfigurationException
219 	{
220 		Assert.argumentNotNull("method", method);
221 		Assert.argumentNotEmpty("exclusions", exclusions);
222 
223 		getClassChecks(method.getDeclaringClass()).addMethodParameterCheckExclusions(method, paramIndex, exclusions);
224 	}
225 
226 	/**
227 	 * Registers constraint checks for the given constructor parameter
228 	 *
229 	 * @param ctor
230 	 * @param paramIndex
231 	 * @param checks
232 	 * @throws IllegalArgumentException if <code>constructor == null</code> or <code>checks == null</code> or checks is
233 	 *             empty
234 	 * @throws InvalidConfigurationException if the declaring class is not guarded or the parameterIndex is out of range
235 	 */
236 	public void addChecks(final Constructor< ? > ctor, final int paramIndex, final Check... checks) throws IllegalArgumentException,
237 			InvalidConfigurationException
238 	{
239 		Assert.argumentNotNull("ctor", ctor);
240 		Assert.argumentNotEmpty("checks", checks);
241 
242 		getClassChecks(ctor.getDeclaringClass()).addConstructorParameterChecks(ctor, paramIndex, checks);
243 	}
244 
245 	/**
246 	 * Registers constraint checks for the given method's return value
247 	 *
248 	 * @param method
249 	 * @param checks
250 	 * @throws IllegalArgumentException if <code>getter == null</code> or <code>checks == null</code> or checks is empty
251 	 * @throws InvalidConfigurationException if method does not declare a return type (void), or the declaring class is
252 	 *             not guarded
253 	 */
254 	@Override
255 	public void addChecks(final Method method, final Check... checks) throws IllegalArgumentException, InvalidConfigurationException
256 	{
257 		Assert.argumentNotNull("method", method);
258 		Assert.argumentNotEmpty("checks", checks);
259 
260 		getClassChecks(method.getDeclaringClass()).addMethodReturnValueChecks(method, null, checks);
261 	}
262 
263 	/**
264 	 * Registers constraint checks for the given method parameter
265 	 *
266 	 * @param method
267 	 * @param paramIndex
268 	 * @param checks
269 	 * @throws IllegalArgumentException if <code>method == null</code> or <code>checks == null</code> or checks is empty
270 	 * @throws InvalidConfigurationException if the declaring class is not guarded or the parameterIndex is out of range
271 	 */
272 	public void addChecks(final Method method, final int paramIndex, final Check... checks) throws IllegalArgumentException,
273 			InvalidConfigurationException
274 	{
275 		Assert.argumentNotNull("method", method);
276 		Assert.argumentNotEmpty("checks", checks);
277 
278 		getClassChecks(method.getDeclaringClass()).addMethodParameterChecks(method, paramIndex, checks);
279 	}
280 
281 	/**
282 	 * Registers post condition checks to a method's return value
283 	 *
284 	 * @param method
285 	 * @param checks
286 	 * @throws IllegalArgumentException if <code>method == null</code> or <code>checks == null</code> or checks is empty
287 	 * @throws InvalidConfigurationException if the declaring class is not guarded
288 	 */
289 	public void addChecks(final Method method, final PostCheck... checks) throws IllegalArgumentException, InvalidConfigurationException
290 	{
291 		Assert.argumentNotNull("method", method);
292 		Assert.argumentNotEmpty("checks", checks);
293 
294 		getClassChecks(method.getDeclaringClass()).addMethodPostChecks(method, checks);
295 	}
296 
297 	/**
298 	 * Registers pre condition checks to a method's return value
299 	 *
300 	 * @param method
301 	 * @param checks
302 	 * @throws IllegalArgumentException if <code>method == null</code> or <code>checks == null</code> or checks is empty
303 	 * @throws InvalidConfigurationException if the declaring class is not guarded
304 	 */
305 	public void addChecks(final Method method, final PreCheck... checks) throws IllegalArgumentException, InvalidConfigurationException
306 	{
307 		Assert.argumentNotNull("method", method);
308 		Assert.argumentNotEmpty("checks", checks);
309 
310 		getClassChecks(method.getDeclaringClass()).addMethodPreChecks(method, checks);
311 	}
312 
313 	/**
314 	 * Registers the given listener for <b>all</b> thrown ConstraintViolationExceptions
315 	 *
316 	 * @param listener the listener to register
317 	 * @return <code>true</code> if the listener was not yet registered
318 	 * @throws IllegalArgumentException if <code>listener == null</code>
319 	 */
320 	public boolean addListener(final ConstraintsViolatedListener listener) throws IllegalArgumentException
321 	{
322 		Assert.argumentNotNull("listener", listener);
323 
324 		isListenersFeatureUsed = true;
325 		return listeners.add(listener);
326 	}
327 
328 	/**
329 	 * Registers the given listener for all thrown ConstraintViolationExceptions on objects of the given class
330 	 *
331 	 * @param listener the listener to register
332 	 * @param guardedClass guarded class or interface
333 	 * @return <code>true</code> if the listener was not yet registered
334 	 * @throws IllegalArgumentException if <code>listener == null</code> or <code>guardedClass == null</code>
335 	 */
336 	public boolean addListener(final ConstraintsViolatedListener listener, final Class< ? > guardedClass) throws IllegalArgumentException
337 	{
338 		Assert.argumentNotNull("listener", listener);
339 		Assert.argumentNotNull("guardedClass", guardedClass);
340 
341 		isListenersFeatureUsed = true;
342 
343 		synchronized (listenersByClass)
344 		{
345 			Set<ConstraintsViolatedListener> classListeners = listenersByClass.get(guardedClass);
346 
347 			if (classListeners == null)
348 			{
349 				classListeners = getCollectionFactory().createSet();
350 				listenersByClass.put(guardedClass, classListeners);
351 			}
352 			return classListeners.add(listener);
353 		}
354 	}
355 
356 	/**
357 	 * Registers the given listener for all thrown ConstraintViolationExceptions on objects of the given object
358 	 *
359 	 * @param listener the listener to register
360 	 * @param guardedObject
361 	 * @return <code>true</code> if the listener was not yet registered
362 	 * @throws IllegalArgumentException if <code>listener == null</code> or <code>guardedObject == null</code>
363 	 */
364 	public boolean addListener(final ConstraintsViolatedListener listener, final Object guardedObject)
365 	{
366 		Assert.argumentNotNull("listener", listener);
367 		Assert.argumentNotNull("guardedObject", guardedObject);
368 
369 		isListenersFeatureUsed = true;
370 
371 		synchronized (listenersByObject)
372 		{
373 			Set<ConstraintsViolatedListener> objectListeners = listenersByObject.get(guardedObject);
374 
375 			if (objectListeners == null)
376 			{
377 				objectListeners = getCollectionFactory().createSet(2);
378 				listenersByObject.put(guardedObject, objectListeners);
379 			}
380 			return objectListeners.add(listener);
381 		}
382 	}
383 
384 	/**
385 	 * Evaluates the old expression
386 	 *
387 	 * @param validatedObject
388 	 * @param method
389 	 * @param args
390 	 * @return null if no violation, otherwise a list
391 	 * @throws ValidationFailedException
392 	 */
393 	protected Map<PostCheck, Object> calculateMethodPostOldValues(final Object validatedObject, final Method method, final Object[] args)
394 			throws ValidationFailedException
395 	{
396 		try
397 		{
398 			final ClassChecks cc = getClassChecks(method.getDeclaringClass());
399 			final Set<PostCheck> postChecks = cc.checksForMethodsPostExcecution.get(method);
400 
401 			// shortcut: check if any post checks for this method exist
402 			if (postChecks == null) return null;
403 
404 			final String[] parameterNames = parameterNameResolver.getParameterNames(method);
405 			final boolean hasParameters = parameterNames.length > 0;
406 
407 			final Map<PostCheck, Object> oldValues = getCollectionFactory().createMap(postChecks.size());
408 
409 			for (final PostCheck check : postChecks)
410 				if (isAnyProfileEnabled(check.getProfiles(), null) && check.getOld() != null && check.getOld().length() > 0)
411 				{
412 					final ExpressionLanguage eng = expressionLanguageRegistry.getExpressionLanguage(check.getLanguage());
413 					final Map<String, Object> values = getCollectionFactory().createMap();
414 					values.put("_this", validatedObject);
415 					if (hasParameters)
416 					{
417 						values.put("_args", args);
418 						for (int i = 0; i < args.length; i++)
419 							values.put(parameterNames[i], args[i]);
420 					}
421 					else
422 						values.put("_args", ArrayUtils.EMPTY_OBJECT_ARRAY);
423 
424 					oldValues.put(check, eng.evaluate(check.getOld(), values));
425 				}
426 
427 			return oldValues;
428 		}
429 		catch (final OValException ex)
430 		{
431 			throw new ValidationFailedException("Method post conditions validation failed. Method: " + method + " Validated object: "
432 					+ validatedObject, ex);
433 		}
434 	}
435 
436 	/**
437 	 * Disables the probe mode for the given object in the current thread.
438 	 *
439 	 * @param guardedObject the object to disable the probe mode for
440 	 * @throws IllegalArgumentException if <code>guardedObject == null</code>
441 	 * @throws IllegalStateException in case probe mode was not enabled for the given object
442 	 */
443 	public ProbeModeListener disableProbeMode(final Object guardedObject) throws IllegalArgumentException, IllegalStateException
444 	{
445 		Assert.argumentNotNull("guardedObject", guardedObject);
446 
447 		return objectsInProbeMode.get().remove(guardedObject);
448 	}
449 
450 	/**
451 	 * Enables the probe mode for the given object in the current thread. In probe mode calls to methods of an
452 	 * object are not actually executed. OVal only validates method pre-conditions and notifies
453 	 * ConstraintViolationListeners but does not throw ConstraintViolationExceptions. Methods with return values will
454 	 * return null.
455 	 *
456 	 * @param guardedObject the object to enable the probe mode for
457 	 * @throws IllegalArgumentException if <code>guardedObject == null</code>
458 	 * @throws IllegalStateException if the probe mode is already enabled
459 	 */
460 	public void enableProbeMode(final Object guardedObject) throws IllegalArgumentException, IllegalStateException
461 	{
462 		Assert.argumentNotNull("guardedObject", guardedObject);
463 
464 		if (guardedObject instanceof Class< ? >)
465 			LOG.warn("Enabling probe mode for a class looks like a programming error. Class: {1}", guardedObject);
466 		isProbeModeFeatureUsed = true;
467 
468 		if (objectsInProbeMode.get().get(guardedObject) != null) throw new IllegalStateException("The object is already in probe mode.");
469 
470 		objectsInProbeMode.get().put(guardedObject, new ProbeModeListener(guardedObject));
471 	}
472 
473 	/**
474 	 * Returns the registers constraint pre condition checks for the given method parameter
475 	 *
476 	 * @param method
477 	 * @param paramIndex
478 	 * @throws IllegalArgumentException if <code>method == null</code>
479 	 */
480 	public Check[] getChecks(final Method method, final int paramIndex) throws InvalidConfigurationException
481 	{
482 		Assert.argumentNotNull("method", method);
483 
484 		final ClassChecks cc = getClassChecks(method.getDeclaringClass());
485 
486 		final Map<Integer, ParameterChecks> checks = cc.checksForMethodParameters.get(method);
487 		if (checks == null) return null;
488 
489 		final ParameterChecks paramChecks = checks.get(paramIndex);
490 		return paramChecks == null ? null : paramChecks.checks.toArray(new Check[checks.size()]);
491 	}
492 
493 	/**
494 	 * Returns the registered post condition checks for the given method
495 	 *
496 	 * @param method
497 	 * @throws IllegalArgumentException if <code>method == null</code>
498 	 */
499 	public PostCheck[] getChecksPost(final Method method) throws IllegalArgumentException
500 	{
501 		Assert.argumentNotNull("method", method);
502 
503 		final ClassChecks cc = getClassChecks(method.getDeclaringClass());
504 
505 		final Set<PostCheck> checks = cc.checksForMethodsPostExcecution.get(method);
506 		return checks == null ? null : checks.toArray(new PostCheck[checks.size()]);
507 	}
508 
509 	/**
510 	 * Returns the registered pre condition checks for the given method.
511 	 *
512 	 * @param method
513 	 * @throws IllegalArgumentException if <code>method == null</code>
514 	 */
515 	public PreCheck[] getChecksPre(final Method method) throws IllegalArgumentException
516 	{
517 		Assert.argumentNotNull("method", method);
518 
519 		final ClassChecks cc = getClassChecks(method.getDeclaringClass());
520 
521 		final Set<PreCheck> checks = cc.checksForMethodsPreExecution.get(method);
522 		return checks == null ? null : checks.toArray(new PreCheck[checks.size()]);
523 	}
524 
525 	/**
526 	 * @return the parameterNameResolver
527 	 */
528 	public ParameterNameResolver getParameterNameResolver()
529 	{
530 		return parameterNameResolver;
531 	}
532 
533 	/**
534 	 * This method is provided for use by guard aspects.
535 	 *
536 	 * @throws ConstraintsViolatedException
537 	 * @throws ValidationFailedException
538 	 */
539 	protected void guardConstructorPost(final Object guardedObject, final Constructor< ? > ctor,
540 			@SuppressWarnings("unused") final Object[] args) throws ConstraintsViolatedException, ValidationFailedException
541 	{
542 		if (!isActivated) return;
543 
544 		final ClassChecks cc = getClassChecks(ctor.getDeclaringClass());
545 
546 		// check invariants
547 		if (isInvariantsEnabled && cc.isCheckInvariants || cc.methodsWithCheckInvariantsPost.contains(ctor))
548 		{
549 			final List<ConstraintViolation> violations = getCollectionFactory().createList();
550 			currentViolations.get().add(violations);
551 			try
552 			{
553 				validateInvariants(guardedObject, violations, null);
554 			}
555 			catch (final ValidationFailedException ex)
556 			{
557 				throw translateException(ex);
558 			}
559 			finally
560 			{
561 				currentViolations.get().removeLast();
562 			}
563 
564 			if (violations.size() > 0)
565 			{
566 				final ConstraintsViolatedException violationException = new ConstraintsViolatedException(violations);
567 				if (isListenersFeatureUsed) notifyListeners(guardedObject, violationException);
568 
569 				throw translateException(violationException);
570 			}
571 		}
572 	}
573 
574 	/**
575 	 * This method is provided for use by guard aspects.
576 	 *
577 	 * @throws ConstraintsViolatedException if anything precondition is not satisfied
578 	 * @throws ValidationFailedException
579 	 */
580 	protected void guardConstructorPre(final Object guardedObject, final Constructor< ? > ctor, final Object[] args)
581 			throws ConstraintsViolatedException, ValidationFailedException
582 	{
583 		if (!isActivated) return;
584 
585 		// constructor parameter validation
586 		if (isPreConditionsEnabled && args.length > 0)
587 		{
588 			final List<ConstraintViolation> violations;
589 			try
590 			{
591 				violations = validateConstructorParameters(guardedObject, ctor, args);
592 			}
593 			catch (final ValidationFailedException ex)
594 			{
595 				throw translateException(ex);
596 			}
597 
598 			if (violations != null)
599 			{
600 				final ConstraintsViolatedException violationException = new ConstraintsViolatedException(violations);
601 				if (isListenersFeatureUsed) notifyListeners(guardedObject, violationException);
602 
603 				throw translateException(violationException);
604 			}
605 		}
606 	}
607 
608 	/**
609 	 * This method is provided for use by guard aspects.
610 	 *
611 	 * @param guardedObject
612 	 * @param method
613 	 * @param args
614 	 * @param invocable
615 	 * @return The method return value or null if the guarded object is in probe mode.
616 	 * @throws ConstraintsViolatedException if an constraint violation occurs and the validated object is not in probe mode.
617 	 * @throws ValidationFailedException
618 	 */
619 	protected Object guardMethod(Object guardedObject, final Method method, final Object[] args, final Invocable invocable)
620 			throws Throwable
621 	{
622 		if (!isActivated) return invocable.invoke();
623 
624 		final ClassChecks cc = getClassChecks(method.getDeclaringClass());
625 
626 		final boolean checkInvariants = isInvariantsEnabled && cc.isCheckInvariants && !ReflectionUtils.isPrivate(method)
627 				&& !ReflectionUtils.isProtected(method);
628 
629 		// if static method use the declaring class as guardedObject
630 		if (guardedObject == null && ReflectionUtils.isStatic(method)) guardedObject = method.getDeclaringClass();
631 
632 		final List<ConstraintViolation> violations = getCollectionFactory().createList();
633 		currentViolations.get().add(violations);
634 
635 		try
636 		{
637 			// check invariants
638 			if (checkInvariants || cc.methodsWithCheckInvariantsPre.contains(method)) validateInvariants(guardedObject, violations, null);
639 
640 			if (isPreConditionsEnabled)
641 			{
642 				// method parameter validation
643 				if (violations.size() == 0 && args.length > 0) validateMethodParameters(guardedObject, method, args, violations);
644 
645 				// @Pre validation
646 				if (violations.size() == 0) validateMethodPre(guardedObject, method, args, violations);
647 			}
648 		}
649 		catch (final ValidationFailedException ex)
650 		{
651 			throw translateException(ex);
652 		}
653 		finally
654 		{
655 			currentViolations.get().removeLast();
656 		}
657 
658 		final ProbeModeListener pml = isProbeModeFeatureUsed ? objectsInProbeMode.get().get(guardedObject) : null;
659 		if (pml != null) pml.onMethodCall(method, args);
660 
661 		if (violations.size() > 0)
662 		{
663 			final ConstraintsViolatedException violationException = new ConstraintsViolatedException(violations);
664 			if (isListenersFeatureUsed) notifyListeners(guardedObject, violationException);
665 
666 			// don't throw an exception if the method is a setter and suppressing for precondition is enabled
667 			if (pml != null)
668 			{
669 				pml.onConstraintsViolatedException(violationException);
670 				return null;
671 			}
672 
673 			throw translateException(violationException);
674 		}
675 
676 		// abort method execution if in probe mode
677 		if (pml != null) return null;
678 
679 		final Map<PostCheck, Object> postCheckOldValues = calculateMethodPostOldValues(guardedObject, method, args);
680 
681 		final Object returnValue = invocable.invoke();
682 
683 		currentViolations.get().add(violations);
684 
685 		try
686 		{
687 			// check invariants if executed method is not private
688 			if (checkInvariants || cc.methodsWithCheckInvariantsPost.contains(method)) validateInvariants(guardedObject, violations, null);
689 
690 			if (isPostConditionsEnabled)
691 			{
692 
693 				// method return value
694 				if (violations.size() == 0) validateMethodReturnValue(guardedObject, method, returnValue, violations);
695 
696 				// @Post
697 				if (violations.size() == 0) validateMethodPost(guardedObject, method, args, returnValue, postCheckOldValues, violations);
698 			}
699 		}
700 		catch (final ValidationFailedException ex)
701 		{
702 			throw translateException(ex);
703 		}
704 		finally
705 		{
706 			currentViolations.get().removeLast();
707 		}
708 
709 		if (violations.size() > 0)
710 		{
711 			final ConstraintsViolatedException violationException = new ConstraintsViolatedException(violations);
712 			if (isListenersFeatureUsed) notifyListeners(guardedObject, violationException);
713 
714 			throw translateException(violationException);
715 		}
716 
717 		return returnValue;
718 	}
719 
720 	/**
721 	 * <b>Note:</b> Only required until AspectJ allows throwing of checked exceptions,
722 	 * then {@link #guardMethod(Object, Method, Object[], Invocable)} can be used instead
723 	 *
724 	 * This method is provided for use by guard aspects.
725 	 *
726 	 * @param returnValue
727 	 * @param preResult
728 	 * @throws ConstraintsViolatedException if an constraint violation occurs and the validated object is not in probe
729 	 *             mode.
730 	 */
731 	protected void guardMethodPost(final Object returnValue, final GuardMethodPreResult preResult) throws ConstraintsViolatedException,
732 			ValidationFailedException
733 	{
734 		if (!isActivated) return;
735 
736 		try
737 		{
738 			// check invariants if executed method is not private
739 			if (preResult.checkInvariants || preResult.cc.methodsWithCheckInvariantsPost.contains(preResult.method))
740 				validateInvariants(preResult.guardedObject, preResult.violations, null);
741 
742 			if (isPostConditionsEnabled)
743 			{
744 
745 				// method return value
746 				if (preResult.violations.size() == 0)
747 					validateMethodReturnValue(preResult.guardedObject, preResult.method, returnValue, preResult.violations);
748 
749 				// @Post
750 				if (preResult.violations.size() == 0)
751 					validateMethodPost(preResult.guardedObject, preResult.method, preResult.args, returnValue,
752 							preResult.postCheckOldValues, preResult.violations);
753 			}
754 		}
755 		catch (final ValidationFailedException ex)
756 		{
757 			throw translateException(ex);
758 		}
759 
760 		if (preResult.violations.size() > 0)
761 		{
762 			final ConstraintsViolatedException violationException = new ConstraintsViolatedException(preResult.violations);
763 			if (isListenersFeatureUsed) notifyListeners(preResult.guardedObject, violationException);
764 
765 			throw translateException(violationException);
766 		}
767 	}
768 
769 	/**
770 	 * <b>Note:</b> Only required until AspectJ allows throwing of checked exceptions, then {@link #guardMethod(Object, Method, Object[], Invocable)} can be used instead
771 	 *
772 	 * This method is provided for use by guard aspects.
773 	 *
774 	 * @param guardedObject
775 	 * @param method
776 	 * @param args
777 	 * @return Null if method guarding is deactivated or a result object that needs to be passed to {@link #guardMethodPost(Object, GuardMethodPreResult)}
778 	 * @throws ConstraintsViolatedException if an constraint violation occurs and the validated object is not in probe
779 	 *             mode.
780 	 */
781 	protected GuardMethodPreResult guardMethodPre(Object guardedObject, final Method method, final Object[] args)
782 			throws ConstraintsViolatedException, ValidationFailedException
783 	{
784 		if (!isActivated) return null;
785 
786 		final ClassChecks cc = getClassChecks(method.getDeclaringClass());
787 
788 		final boolean checkInvariants = isInvariantsEnabled && cc.isCheckInvariants && !ReflectionUtils.isPrivate(method)
789 				&& !ReflectionUtils.isProtected(method);
790 
791 		// if static method use the declaring class as guardedObject
792 		if (guardedObject == null && ReflectionUtils.isStatic(method)) guardedObject = method.getDeclaringClass();
793 
794 		final List<ConstraintViolation> violations = getCollectionFactory().createList();
795 		currentViolations.get().add(violations);
796 
797 		try
798 		{
799 			// check invariants
800 			if (checkInvariants || cc.methodsWithCheckInvariantsPre.contains(method)) validateInvariants(guardedObject, violations, null);
801 
802 			if (isPreConditionsEnabled)
803 			{
804 				// method parameter validation
805 				if (violations.size() == 0 && args.length > 0) validateMethodParameters(guardedObject, method, args, violations);
806 
807 				// @Pre validation
808 				if (violations.size() == 0) validateMethodPre(guardedObject, method, args, violations);
809 			}
810 		}
811 		catch (final ValidationFailedException ex)
812 		{
813 			throw translateException(ex);
814 		}
815 		finally
816 		{
817 			currentViolations.get().removeLast();
818 		}
819 
820 		final ProbeModeListener pml = isProbeModeFeatureUsed ? objectsInProbeMode.get().get(guardedObject) : null;
821 		if (pml != null) pml.onMethodCall(method, args);
822 
823 		if (violations.size() > 0)
824 		{
825 			final ConstraintsViolatedException violationException = new ConstraintsViolatedException(violations);
826 			if (isListenersFeatureUsed) notifyListeners(guardedObject, violationException);
827 
828 			// don't throw an exception if the method is a setter and suppressing for precondition is enabled
829 			if (pml != null)
830 			{
831 				pml.onConstraintsViolatedException(violationException);
832 				return DO_NOT_PROCEED;
833 			}
834 
835 			throw translateException(violationException);
836 		}
837 
838 		// abort method execution if in probe mode
839 		if (pml != null) return DO_NOT_PROCEED;
840 
841 		final Map<PostCheck, Object> postCheckOldValues = calculateMethodPostOldValues(guardedObject, method, args);
842 
843 		return new GuardMethodPreResult(guardedObject, method, args, cc, checkInvariants, postCheckOldValues, violations);
844 	}
845 
846 	/**
847 	 * @param listener
848 	 * @return <code>true</code> if the listener is registered
849 	 * @throws IllegalArgumentException if <code>listener == null</code>
850 	 */
851 	public boolean hasListener(final ConstraintsViolatedListener listener) throws IllegalArgumentException
852 	{
853 		Assert.argumentNotNull("listener", listener);
854 
855 		return listeners.contains(listener);
856 	}
857 
858 	/**
859 	 * @param listener
860 	 * @param guardedClass guarded class or interface
861 	 * @return <code>true</code> if the listener is registered
862 	 * @throws IllegalArgumentException if <code>listener == null</code> or <code>guardedClass == null</code>
863 	 */
864 	public boolean hasListener(final ConstraintsViolatedListener listener, final Class< ? > guardedClass) throws IllegalArgumentException
865 	{
866 		Assert.argumentNotNull("listener", listener);
867 		Assert.argumentNotNull("guardedClass", guardedClass);
868 
869 		final Set<ConstraintsViolatedListener> classListeners = listenersByClass.get(guardedClass);
870 
871 		if (classListeners == null) return false;
872 
873 		return classListeners.contains(listener);
874 	}
875 
876 	/**
877 	 * @param listener
878 	 * @param guardedObject
879 	 * @return <code>true</code> if the listener is registered
880 	 * @throws IllegalArgumentException if <code>listener == null</code> or <code>guardedObject == null</code>
881 	 */
882 	public boolean hasListener(final ConstraintsViolatedListener listener, final Object guardedObject) throws IllegalArgumentException
883 	{
884 		Assert.argumentNotNull("listener", listener);
885 		Assert.argumentNotNull("guardedObject", guardedObject);
886 
887 		final Set<ConstraintsViolatedListener> objectListeners = listenersByObject.get(guardedObject);
888 
889 		if (objectListeners == null) return false;
890 
891 		return objectListeners.contains(listener);
892 	}
893 
894 	/**
895 	 * @return the isEnabled
896 	 */
897 	public boolean isActivated()
898 	{
899 		return isActivated;
900 	}
901 
902 	/**
903 	 * Determines if the probe mode is enabled for the given object in the current thread. In probe mode calls to
904 	 * methods of an object are not actually executed. OVal only validates method pre-conditions and notifies
905 	 * ConstraintViolationListeners but does not throw ConstraintViolationExceptions. Methods with return values will
906 	 * return null.
907 	 *
908 	 * @param guardedObject
909 	 * @return true if exceptions are suppressed
910 	 */
911 	public boolean isInProbeMode(final Object guardedObject)
912 	{
913 		// guardedObject may be null if isInProbeMode is called when validating pre conditions of a static method
914 		if (guardedObject == null) return false;
915 
916 		return objectsInProbeMode.get().containsKey(guardedObject);
917 	}
918 
919 	/**
920 	 * Determines if invariants are checked prior and after every call to a non-private method or constructor.
921 	 *
922 	 * @return the isInvariantChecksActivated
923 	 */
924 	public boolean isInvariantsEnabled()
925 	{
926 		return isInvariantsEnabled;
927 	}
928 
929 	/**
930 	 * Determines if invariants are checked prior and after every call to a non-private method or constructor.
931 	 *
932 	 * @param guardedClass the guarded class
933 	 * @return the isInvariantChecksActivated
934 	 */
935 	public boolean isInvariantsEnabled(final Class< ? > guardedClass)
936 	{
937 		return getClassChecks(guardedClass).isCheckInvariants;
938 	}
939 
940 	/**
941 	 * @return the isPostChecksActivated
942 	 */
943 	public boolean isPostConditionsEnabled()
944 	{
945 		return isPostConditionsEnabled;
946 	}
947 
948 	/**
949 	 * @return the isPreChecksActivated
950 	 */
951 	public boolean isPreConditionsEnabled()
952 	{
953 		return isPreConditionsEnabled;
954 	}
955 
956 	/**
957 	 * notifies all registered validation listener about the occurred constraint violation exception
958 	 */
959 	protected void notifyListeners(final Object guardedObject, final ConstraintsViolatedException ex)
960 	{
961 		// happens for static methods
962 		if (guardedObject == null) return;
963 
964 		final LinkedHashSet<ConstraintsViolatedListener> listenersToNotify = new LinkedHashSet<ConstraintsViolatedListener>();
965 
966 		// get the object listeners
967 		{
968 			final Set<ConstraintsViolatedListener> objectListeners = listenersByObject.get(guardedObject);
969 			if (objectListeners != null) listenersToNotify.addAll(objectListeners);
970 		}
971 
972 		// get the class listeners
973 		{
974 			final Set<ConstraintsViolatedListener> classListeners = listenersByClass.get(guardedObject.getClass());
975 			if (classListeners != null) listenersToNotify.addAll(classListeners);
976 		}
977 
978 		// get the interface listeners
979 		{
980 			for (final Class< ? > interfaze : guardedObject.getClass().getInterfaces())
981 			{
982 				final Set<ConstraintsViolatedListener> interfaceListeners = listenersByClass.get(interfaze);
983 				if (interfaceListeners != null) listenersToNotify.addAll(interfaceListeners);
984 			}
985 		}
986 
987 		// get the global listeners
988 		listenersToNotify.addAll(listeners);
989 
990 		// notify the listeners
991 		for (final ConstraintsViolatedListener listener : listenersToNotify)
992 			try
993 			{
994 				listener.onConstraintsViolatedException(ex);
995 			}
996 			catch (final RuntimeException rex)
997 			{
998 				LOG.warn("Notifying listener '{1}' failed.", listener, rex);
999 			}
1000 
1001 	}
1002 
1003 	/**
1004 	 * Removes constraint check exclusions from the given constructor parameter
1005 	 *
1006 	 * @param ctor
1007 	 * @param paramIndex
1008 	 * @param exclusions
1009 	 * @throws InvalidConfigurationException if the declaring class is not guarded or the parameterIndex is out of range
1010 	 */
1011 	public void removeCheckExclusions(final Constructor< ? > ctor, final int paramIndex, final CheckExclusion... exclusions)
1012 			throws InvalidConfigurationException
1013 	{
1014 		Assert.argumentNotNull("ctor", ctor);
1015 		Assert.argumentNotEmpty("exclusions", exclusions);
1016 
1017 		getClassChecks(ctor.getDeclaringClass()).removeConstructorParameterCheckExclusions(ctor, paramIndex, exclusions);
1018 	}
1019 
1020 	/**
1021 	 * Removes constraint check exclusions from the given method parameter
1022 	 *
1023 	 * @param method
1024 	 * @param paramIndex
1025 	 * @param exclusions
1026 	 * @throws InvalidConfigurationException if the declaring class is not guarded or the parameterIndex is out of range
1027 	 */
1028 	public void removeCheckExclusions(final Method method, final int paramIndex, final CheckExclusion... exclusions)
1029 			throws InvalidConfigurationException
1030 	{
1031 		Assert.argumentNotNull("method", method);
1032 		Assert.argumentNotEmpty("exclusions", exclusions);
1033 
1034 		getClassChecks(method.getDeclaringClass()).removeMethodParameterCheckExclusions(method, paramIndex, exclusions);
1035 	}
1036 
1037 	/**
1038 	 * Removes constraint checks from the given constructor parameter
1039 	 *
1040 	 * @param ctor
1041 	 * @param paramIndex
1042 	 * @param checks
1043 	 * @throws InvalidConfigurationException if the declaring class is not guarded or the parameterIndex is out of range
1044 	 */
1045 	public void removeChecks(final Constructor< ? > ctor, final int paramIndex, final Check... checks) throws InvalidConfigurationException
1046 	{
1047 		Assert.argumentNotNull("ctor", ctor);
1048 		Assert.argumentNotEmpty("checks", checks);
1049 
1050 		getClassChecks(ctor.getDeclaringClass()).removeConstructorParameterChecks(ctor, paramIndex, checks);
1051 	}
1052 
1053 	/**
1054 	 * Removes constraint checks for the given method parameter
1055 	 *
1056 	 * @param method
1057 	 * @param paramIndex
1058 	 * @param checks
1059 	 * @throws IllegalArgumentException if <code>constructor == null</code> or <code>checks == null</code> or checks is
1060 	 *             empty
1061 	 * @throws InvalidConfigurationException if the parameterIndex is out of range
1062 	 */
1063 	public void removeChecks(final Method method, final int paramIndex, final Check... checks) throws InvalidConfigurationException
1064 	{
1065 		Assert.argumentNotNull("method", method);
1066 		Assert.argumentNotEmpty("checks", checks);
1067 
1068 		getClassChecks(method.getDeclaringClass()).removeMethodParameterChecks(method, paramIndex, checks);
1069 	}
1070 
1071 	/**
1072 	 * Registers post condition checks to a method's return value
1073 	 *
1074 	 * @param method
1075 	 * @param checks
1076 	 * @throws IllegalArgumentException if <code>method == null</code> or <code>checks == null</code> or checks is empty
1077 	 * @throws InvalidConfigurationException if the declaring class is not guarded
1078 	 */
1079 	public void removeChecks(final Method method, final PostCheck... checks) throws InvalidConfigurationException
1080 	{
1081 		Assert.argumentNotNull("method", method);
1082 		Assert.argumentNotEmpty("checks", checks);
1083 
1084 		getClassChecks(method.getDeclaringClass()).removeMethodPostChecks(method, checks);
1085 	}
1086 
1087 	/**
1088 	 * Registers pre condition checks to a method's return value
1089 	 *
1090 	 * @param method
1091 	 * @param checks
1092 	 * @throws IllegalArgumentException if <code>method == null</code> or <code>checks == null</code> or checks is empty
1093 	 * @throws InvalidConfigurationException if the declaring class is not guarded
1094 	 */
1095 	public void removeChecks(final Method method, final PreCheck... checks) throws InvalidConfigurationException
1096 	{
1097 		Assert.argumentNotNull("method", method);
1098 		Assert.argumentNotEmpty("checks", checks);
1099 
1100 		getClassChecks(method.getDeclaringClass()).removeMethodPreChecks(method, checks);
1101 	}
1102 
1103 	/**
1104 	 * Removes the given listener
1105 	 *
1106 	 * @param listener
1107 	 * @return <code>true</code> if the listener was registered
1108 	 * @throws IllegalArgumentException if <code>listener == null</code>
1109 	 */
1110 	public boolean removeListener(final ConstraintsViolatedListener listener) throws IllegalArgumentException
1111 	{
1112 		Assert.argumentNotNull("listener", listener);
1113 
1114 		return listeners.remove(listener);
1115 	}
1116 
1117 	/**
1118 	 * Removes the given listener
1119 	 *
1120 	 * @param listener
1121 	 * @param guardedClass guarded class or interface
1122 	 * @return <code>true</code> if the listener was registered
1123 	 * @throws IllegalArgumentException if <code>listener == null</code> or <code>guardedClass == null</code>
1124 	 */
1125 	public boolean removeListener(final ConstraintsViolatedListener listener, final Class< ? > guardedClass)
1126 			throws IllegalArgumentException
1127 	{
1128 		Assert.argumentNotNull("listener", listener);
1129 		Assert.argumentNotNull("guardedClass", guardedClass);
1130 
1131 		final Set<ConstraintsViolatedListener> currentListeners = listenersByClass.get(guardedClass);
1132 
1133 		return currentListeners == null ? false : currentListeners.remove(listener);
1134 	}
1135 
1136 	/**
1137 	 * Removes the given listener
1138 	 *
1139 	 * @param listener
1140 	 * @param guardedObject
1141 	 * @return <code>true</code> if the listener was registered
1142 	 * @throws IllegalArgumentException if <code>listener == null</code> or <code>guardedObject == null</code>
1143 	 */
1144 	public boolean removeListener(final ConstraintsViolatedListener listener, final Object guardedObject) throws IllegalArgumentException
1145 	{
1146 		Assert.argumentNotNull("listener", listener);
1147 		Assert.argumentNotNull("guardedObject", guardedObject);
1148 
1149 		final Set<ConstraintsViolatedListener> currentListeners = listenersByObject.get(guardedObject);
1150 
1151 		return currentListeners == null ? false : currentListeners.remove(listener);
1152 	}
1153 
1154 	/**
1155 	 * If set to false OVal's programming by contract features are disabled and constraints are not checked
1156 	 * automatically during runtime.
1157 	 *
1158 	 * @param isActivated the isActivated to set
1159 	 */
1160 	public void setActivated(final boolean isActivated)
1161 	{
1162 		this.isActivated = isActivated;
1163 	}
1164 
1165 	/**
1166 	 * Specifies if invariants are checked prior and after calls to non-private methods and constructors.
1167 	 *
1168 	 * @param isEnabled the isInvariantsEnabled to set
1169 	 */
1170 	public void setInvariantsEnabled(final boolean isEnabled)
1171 	{
1172 		isInvariantsEnabled = isEnabled;
1173 	}
1174 
1175 	/**
1176 	 * Specifies if invariants are checked prior and after calls to non-private methods and constructors.
1177 	 *
1178 	 * @param guardedClass the guarded class to turn on/off the invariant checking
1179 	 * @param isEnabled the isEnabled to set
1180 	 */
1181 	public void setInvariantsEnabled(final Class< ? > guardedClass, final boolean isEnabled)
1182 	{
1183 		getClassChecks(guardedClass).isCheckInvariants = isEnabled;
1184 	}
1185 
1186 	/**
1187 	 * @param parameterNameResolver the parameterNameResolver to set, cannot be null
1188 	 * @throws IllegalArgumentException if <code>parameterNameResolver == null</code>
1189 	 */
1190 	public void setParameterNameResolver(final ParameterNameResolver parameterNameResolver) throws IllegalArgumentException
1191 	{
1192 		Assert.argumentNotNull("parameterNameResolver", parameterNameResolver);
1193 
1194 		this.parameterNameResolver.setDelegate(parameterNameResolver);
1195 	}
1196 
1197 	/**
1198 	 * @param isEnabled the isEnabled to set
1199 	 */
1200 	public void setPostConditionsEnabled(final boolean isEnabled)
1201 	{
1202 		isPostConditionsEnabled = isEnabled;
1203 	}
1204 
1205 	/**
1206 	 * @param isEnabled the isEnabled to set
1207 	 */
1208 	public void setPreConditionsEnabled(final boolean isEnabled)
1209 	{
1210 		isPreConditionsEnabled = isEnabled;
1211 	}
1212 
1213 	/**
1214 	 * Validates the give arguments against the defined constructor parameter constraints.<br>
1215 	 *
1216 	 * @return null if no violation, otherwise a list
1217 	 * @throws ValidationFailedException
1218 	 */
1219 	protected List<ConstraintViolation> validateConstructorParameters(final Object validatedObject, final Constructor< ? > constructor,
1220 			final Object[] argsToValidate) throws ValidationFailedException
1221 	{
1222 		// create required objects for this validation cycle
1223 		final List<ConstraintViolation> violations = getCollectionFactory().createList();
1224 		currentViolations.get().add(violations);
1225 		currentlyValidatedObjects.get().add(new IdentitySet<Object>(4));
1226 
1227 		try
1228 		{
1229 			final ClassChecks cc = getClassChecks(constructor.getDeclaringClass());
1230 			final Map<Integer, ParameterChecks> parameterChecks = cc.checksForConstructorParameters.get(constructor);
1231 
1232 			// if no parameter checks exist just return null
1233 			if (parameterChecks == null) return null;
1234 
1235 			final String[] parameterNames = parameterNameResolver.getParameterNames(constructor);
1236 
1237 			for (int i = 0; i < argsToValidate.length; i++)
1238 			{
1239 				final ParameterChecks checks = parameterChecks.get(i);
1240 
1241 				if (checks != null && checks.hasChecks())
1242 				{
1243 					final Object valueToValidate = argsToValidate[i];
1244 					final ConstructorParameterContext context = new ConstructorParameterContext(constructor, i, parameterNames[i]);
1245 
1246 					_validateParameterChecks(checks, validatedObject, valueToValidate, context, violations);
1247 				}
1248 			}
1249 			return violations.size() == 0 ? null : violations;
1250 		}
1251 		catch (final OValException ex)
1252 		{
1253 			throw new ValidationFailedException("Validation of constructor parameters failed. Constructor: " + constructor
1254 					+ " Validated object: " + validatedObject.getClass().getName() + "@" + Integer.toHexString(validatedObject.hashCode()),
1255 					ex);
1256 		}
1257 		finally
1258 		{
1259 			// remove the validation cycle related objects
1260 			currentViolations.get().removeLast();
1261 			currentlyValidatedObjects.get().removeLast();
1262 		}
1263 	}
1264 
1265 	/**
1266 	 * {@inheritDoc}
1267 	 */
1268 	@Override
1269 	protected void validateInvariants(final Object guardedObject, final List<ConstraintViolation> violations, final String[] profiles)
1270 			throws IllegalArgumentException, ValidationFailedException
1271 	{
1272 		// create a new set for this validation cycle
1273 		currentlyValidatedObjects.get().add(new IdentitySet<Object>(4));
1274 		try
1275 		{
1276 			super.validateInvariants(guardedObject, violations, profiles);
1277 		}
1278 		finally
1279 		{
1280 			// remove the set
1281 			currentlyValidatedObjects.get().removeLast();
1282 		}
1283 	}
1284 
1285 	/**
1286 	 * Validates the pre conditions for a method call.<br>
1287 	 *
1288 	 * @throws ValidationFailedException
1289 	 */
1290 	protected void validateMethodParameters(final Object validatedObject, final Method method, final Object[] args,
1291 			final List<ConstraintViolation> violations) throws ValidationFailedException
1292 	{
1293 		// create a new set for this validation cycle
1294 		currentlyValidatedObjects.get().add(new IdentitySet<Object>(4));
1295 		try
1296 		{
1297 			final ClassChecks cc = getClassChecks(method.getDeclaringClass());
1298 			final Map<Integer, ParameterChecks> parameterChecks = cc.checksForMethodParameters.get(method);
1299 
1300 			if (parameterChecks == null) return;
1301 
1302 			final String[] parameterNames = parameterNameResolver.getParameterNames(method);
1303 
1304 			/*
1305 			 * parameter constraints validation
1306 			 */
1307 			if (parameterNames.length > 0) for (int i = 0; i < args.length; i++)
1308 			{
1309 				final ParameterChecks checks = parameterChecks.get(i);
1310 
1311 				if (checks != null && checks.checks.size() > 0)
1312 				{
1313 					final Object valueToValidate = args[i];
1314 					final MethodParameterContext context = new MethodParameterContext(method, i, parameterNames[i]);
1315 
1316 					_validateParameterChecks(checks, validatedObject, valueToValidate, context, violations);
1317 				}
1318 			}
1319 		}
1320 		catch (final OValException ex)
1321 		{
1322 			throw new ValidationFailedException("Method pre conditions validation failed. Method: " + method + " Validated object: "
1323 					+ validatedObject, ex);
1324 		}
1325 		finally
1326 		{
1327 			// remove the set
1328 			currentlyValidatedObjects.get().removeLast();
1329 		}
1330 	}
1331 
1332 	/**
1333 	 * Validates the post conditions for a method call.<br>
1334 	 *
1335 	 * @throws ValidationFailedException
1336 	 */
1337 	protected void validateMethodPost(final Object validatedObject, final Method method, final Object[] args, final Object returnValue,
1338 			final Map<PostCheck, Object> oldValues, final List<ConstraintViolation> violations) throws ValidationFailedException
1339 	{
1340 		final String key = System.identityHashCode(validatedObject) + " " + System.identityHashCode(method);
1341 
1342 		/*
1343 		 *  avoid circular references
1344 		 */
1345 		if (currentlyCheckingPostConditions.get().contains(key)) return;
1346 
1347 		currentlyCheckingPostConditions.get().add(key);
1348 		try
1349 		{
1350 			final ClassChecks cc = getClassChecks(method.getDeclaringClass());
1351 			final Set<PostCheck> postChecks = cc.checksForMethodsPostExcecution.get(method);
1352 
1353 			if (postChecks == null) return;
1354 
1355 			final String[] parameterNames = parameterNameResolver.getParameterNames(method);
1356 			final boolean hasParameters = parameterNames.length > 0;
1357 
1358 			final MethodExitContext context = ContextCache.getMethodExitContext(method);
1359 
1360 			for (final PostCheck check : postChecks)
1361 			{
1362 				if (!isAnyProfileEnabled(check.getProfiles(), null)) continue;
1363 
1364 				final ExpressionLanguage eng = expressionLanguageRegistry.getExpressionLanguage(check.getLanguage());
1365 				final Map<String, Object> values = getCollectionFactory().createMap();
1366 				values.put("_this", validatedObject);
1367 				values.put("_returns", returnValue);
1368 				values.put("_old", oldValues.get(check));
1369 				if (hasParameters)
1370 				{
1371 					values.put("_args", args);
1372 					for (int i = 0; i < args.length; i++)
1373 						values.put(parameterNames[i], args[i]);
1374 				}
1375 				else
1376 					values.put("_args", ArrayUtils.EMPTY_OBJECT_ARRAY);
1377 
1378 				if (!eng.evaluateAsBoolean(check.getExpression(), values))
1379 				{
1380 					final Map<String, String> messageVariables = getCollectionFactory().createMap(2);
1381 					messageVariables.put("expression", check.getExpression());
1382 					final String errorMessage = renderMessage(context, null, check.getMessage(), messageVariables);
1383 
1384 					violations.add(new ConstraintViolation(check, errorMessage, validatedObject, null, context));
1385 				}
1386 			}
1387 		}
1388 		catch (final OValException ex)
1389 		{
1390 			throw new ValidationFailedException("Method post conditions validation failed. Method: " + method + " Validated object: "
1391 					+ validatedObject, ex);
1392 		}
1393 		finally
1394 		{
1395 			currentlyCheckingPostConditions.get().remove(key);
1396 		}
1397 	}
1398 
1399 	/**
1400 	 * Validates the @Pre conditions for a method call.<br>
1401 	 *
1402 	 * @throws ValidationFailedException
1403 	 */
1404 	protected void validateMethodPre(final Object validatedObject, final Method method, final Object[] args,
1405 			final List<ConstraintViolation> violations) throws ValidationFailedException
1406 	{
1407 		final String key = System.identityHashCode(validatedObject) + " " + System.identityHashCode(method);
1408 
1409 		/*
1410 		 *  avoid circular references
1411 		 */
1412 		if (currentlyCheckingPreConditions.get().contains(key)) return;
1413 
1414 		currentlyCheckingPreConditions.get().add(key);
1415 		try
1416 		{
1417 			final ClassChecks cc = getClassChecks(method.getDeclaringClass());
1418 			final Set<PreCheck> preChecks = cc.checksForMethodsPreExecution.get(method);
1419 
1420 			if (preChecks == null) return;
1421 
1422 			final String[] parameterNames = parameterNameResolver.getParameterNames(method);
1423 			final boolean hasParameters = parameterNames.length > 0;
1424 
1425 			final MethodEntryContext context = ContextCache.getMethodEntryContext(method);
1426 
1427 			for (final PreCheck check : preChecks)
1428 			{
1429 				if (!isAnyProfileEnabled(check.getProfiles(), null)) continue;
1430 
1431 				final ExpressionLanguage eng = expressionLanguageRegistry.getExpressionLanguage(check.getLanguage());
1432 				final Map<String, Object> values = getCollectionFactory().createMap();
1433 				values.put("_this", validatedObject);
1434 				if (hasParameters)
1435 				{
1436 					values.put("_args", args);
1437 					for (int i = 0; i < args.length; i++)
1438 						values.put(parameterNames[i], args[i]);
1439 				}
1440 				else
1441 					values.put("_args", ArrayUtils.EMPTY_OBJECT_ARRAY);
1442 
1443 				if (!eng.evaluateAsBoolean(check.getExpression(), values))
1444 				{
1445 					final Map<String, String> messageVariables = getCollectionFactory().createMap(2);
1446 					messageVariables.put("expression", check.getExpression());
1447 					final String errorMessage = renderMessage(context, null, check.getMessage(), messageVariables);
1448 
1449 					violations.add(new ConstraintViolation(check, errorMessage, validatedObject, null, context));
1450 				}
1451 			}
1452 		}
1453 		catch (final OValException ex)
1454 		{
1455 			throw new ValidationFailedException("Method pre conditions validation failed. Method: " + method + " Validated object: "
1456 					+ validatedObject, ex);
1457 		}
1458 		finally
1459 		{
1460 			currentlyCheckingPreConditions.get().remove(key);
1461 		}
1462 	}
1463 
1464 	/**
1465 	 * Validates the return value checks for a method call.<br>
1466 	 *
1467 	 * @throws ValidationFailedException
1468 	 */
1469 	protected void validateMethodReturnValue(final Object validatedObject, final Method method, final Object returnValue,
1470 			final List<ConstraintViolation> violations) throws ValidationFailedException
1471 	{
1472 		final String key = System.identityHashCode(validatedObject) + " " + System.identityHashCode(method);
1473 
1474 		/*
1475 		 *  avoid circular references, e.g.
1476 		 *
1477 		 *  private String name;
1478 		 *
1479 		 *  @Assert("_this.name != null", lang="groovy")
1480 		 *  public String getName { return name; }
1481 		 *
1482 		 *  => Groovy will invoke the getter to return the value, invocations of the getter will trigger the validation of the method return values again, including the @Assert constraint
1483 		 */
1484 		if (currentlyCheckingMethodReturnValues.get().contains(key)) return;
1485 
1486 		currentlyCheckingMethodReturnValues.get().add(key);
1487 		// create a new set for this validation cycle
1488 		currentlyValidatedObjects.get().add(new IdentitySet<Object>(4));
1489 		try
1490 		{
1491 			final ClassChecks cc = getClassChecks(method.getDeclaringClass());
1492 			final Collection<Check> returnValueChecks = cc.checksForMethodReturnValues.get(method);
1493 
1494 			if (returnValueChecks == null || returnValueChecks.size() == 0) return;
1495 
1496 			final MethodReturnValueContext context = ContextCache.getMethodReturnValueContext(method);
1497 
1498 			for (final Check check : returnValueChecks)
1499 				checkConstraint(violations, check, validatedObject, returnValue, context, null, false);
1500 		}
1501 		catch (final OValException ex)
1502 		{
1503 			throw new ValidationFailedException("Method post conditions validation failed. Method: " + method + " Validated object: "
1504 					+ validatedObject, ex);
1505 		}
1506 		finally
1507 		{
1508 			currentlyCheckingMethodReturnValues.get().remove(key);
1509 
1510 			// remove the set
1511 			currentlyValidatedObjects.get().removeLast();
1512 		}
1513 	}
1514 }