001    /*******************************************************************************
002     * Portions created by Sebastian Thomschke are copyright (c) 2005-2011 Sebastian
003     * Thomschke.
004     * 
005     * All Rights Reserved. This program and the accompanying materials
006     * are made available under the terms of the Eclipse Public License v1.0
007     * which accompanies this distribution, and is available at
008     * http://www.eclipse.org/legal/epl-v10.html
009     * 
010     * Contributors:
011     *     Sebastian Thomschke - initial implementation.
012     *******************************************************************************/
013    package net.sf.oval.internal;
014    
015    import static net.sf.oval.Validator.getCollectionFactory;
016    
017    import java.lang.reflect.AccessibleObject;
018    import java.lang.reflect.Constructor;
019    import java.lang.reflect.Field;
020    import java.lang.reflect.Method;
021    import java.util.Collection;
022    import java.util.Map;
023    import java.util.Set;
024    
025    import net.sf.oval.Check;
026    import net.sf.oval.CheckExclusion;
027    import net.sf.oval.exception.InvalidConfigurationException;
028    import net.sf.oval.guard.IsGuarded;
029    import net.sf.oval.guard.ParameterNameResolver;
030    import net.sf.oval.guard.PostCheck;
031    import net.sf.oval.guard.PreCheck;
032    import net.sf.oval.internal.util.ArrayUtils;
033    import net.sf.oval.internal.util.LinkedSet;
034    import net.sf.oval.internal.util.ReflectionUtils;
035    
036    /**
037     * This class holds the instantiated checks for a single class.
038     * 
039     * <b>Note:</b> For performance reasons the collections are made public (intended for read-access only).
040     * Modifications to the collections should be done through the appropriate methods addXXX, removeXXX, clearXXX methods.
041     * 
042     * @author Sebastian Thomschke
043     */
044    public final class ClassChecks
045    {
046            private static final String GUARDING_MAY_NOT_BE_ACTIVATED_MESSAGE = //
047            " Class does not implement IsGuarded interface. This indicates, " + // 
048                            "that constraints guarding may not activated for this class.";
049    
050            private static final Log LOG = Log.getLog(ClassChecks.class);
051    
052            /**
053             * checks on constructors' parameter values
054             */
055            public final Map<Constructor< ? >, Map<Integer, ParameterChecks>> checksForConstructorParameters = getCollectionFactory()
056                            .createMap(2);
057    
058            /**
059             * checks on fields' value
060             */
061            public final Map<Field, Set<Check>> checksForFields = getCollectionFactory().createMap();
062    
063            /**
064             * checks on methods' parameter values
065             */
066            public final Map<Method, Map<Integer, ParameterChecks>> checksForMethodParameters = getCollectionFactory()
067                            .createMap();
068    
069            /**
070             * checks on methods' return value
071             */
072            public final Map<Method, Set<Check>> checksForMethodReturnValues = getCollectionFactory().createMap();
073    
074            public final Map<Method, Set<PostCheck>> checksForMethodsPostExcecution = getCollectionFactory().createMap();
075    
076            public final Map<Method, Set<PreCheck>> checksForMethodsPreExecution = getCollectionFactory().createMap();
077    
078            /**
079             * compound constraints / object level invariants
080             */
081            public final Set<Check> checksForObject = new LinkedSet<Check>(2);
082    
083            public final Class< ? > clazz;
084    
085            /**
086             * all non-static fields that have value constraints.
087             * Validator loops over this set during validation.
088             */
089            public final Set<Field> constrainedFields = new LinkedSet<Field>();
090    
091            /**
092             * all non-static non-void, non-parameterized methods marked as invariant that have return value constraints.
093             * Validator loops over this set during validation.
094             */
095            public final Set<Method> constrainedMethods = new LinkedSet<Method>();
096    
097            /**
098             * all non-static fields that have value constraints.
099             * Validator loops over this set during validation.
100             */
101            public final Set<Field> constrainedStaticFields = new LinkedSet<Field>();
102    
103            /**
104             * all static non-void, non-parameterized methods marked as invariant that have return value constraints.
105             * Validator loops over this set during validation.
106             */
107            public final Set<Method> constrainedStaticMethods = new LinkedSet<Method>();
108    
109            public boolean isCheckInvariants;
110    
111            public final Set<AccessibleObject> methodsWithCheckInvariantsPost = getCollectionFactory().createSet();
112    
113            public final Set<Method> methodsWithCheckInvariantsPre = getCollectionFactory().createSet();
114    
115            private final ParameterNameResolver parameterNameResolver;
116    
117            /**
118             * package constructor used by the Validator class
119             * 
120             * @param clazz
121             */
122            public ClassChecks(final Class< ? > clazz, final ParameterNameResolver parameterNameResolver)
123            {
124                    LOG.debug("Initializing constraints configuration for class {1}", clazz);
125    
126                    this.clazz = clazz;
127                    this.parameterNameResolver = parameterNameResolver;
128            }
129    
130            private void _addConstructorParameterCheckExclusions(final Constructor< ? > constructor, final int parameterIndex,
131                            final Object exclusions) throws InvalidConfigurationException
132            {
133                    final ParameterChecks checksOfConstructorParameter = _getChecksOfConstructorParameter(constructor,
134                                    parameterIndex);
135    
136                    if (exclusions instanceof Collection< ? >)
137                    {
138                            @SuppressWarnings("unchecked")
139                            final Collection<CheckExclusion> exclusionsColl = (Collection<CheckExclusion>) exclusions;
140                            checksOfConstructorParameter.checkExclusions.addAll(exclusionsColl);
141                    }
142                    else
143                            ArrayUtils.addAll(checksOfConstructorParameter.checkExclusions, (CheckExclusion[]) exclusions);
144            }
145    
146            @SuppressWarnings("unchecked")
147            private void _addConstructorParameterChecks(final Constructor< ? > constructor, final int parameterIndex,
148                            final Object checks) throws InvalidConfigurationException
149            {
150                    if (LOG.isDebug() && !IsGuarded.class.isAssignableFrom(clazz))
151                            LOG.warn("Constructor parameter constraints may not be validated." + GUARDING_MAY_NOT_BE_ACTIVATED_MESSAGE);
152    
153                    final ParameterChecks checksOfConstructorParameter = _getChecksOfConstructorParameter(constructor,
154                                    parameterIndex);
155    
156                    if (checks instanceof Collection)
157                            for (final Check check : (Collection<Check>) checks)
158                            {
159                                    checksOfConstructorParameter.checks.add(check);
160                                    if (check.getContext() == null) check.setContext(checksOfConstructorParameter.context);
161                            }
162                    else
163                            for (final Check check : (Check[]) checks)
164                            {
165                                    checksOfConstructorParameter.checks.add(check);
166                                    if (check.getContext() == null) check.setContext(checksOfConstructorParameter.context);
167                            }
168            }
169    
170            @SuppressWarnings("unchecked")
171            private void _addFieldChecks(final Field field, final Object checks)
172            {
173                    synchronized (checksForFields)
174                    {
175                            Set<Check> checksOfField = checksForFields.get(field);
176                            if (checksOfField == null)
177                            {
178                                    checksOfField = new LinkedSet<Check>(2);
179                                    checksForFields.put(field, checksOfField);
180                                    if (ReflectionUtils.isStatic(field))
181                                            constrainedStaticFields.add(field);
182                                    else
183                                            constrainedFields.add(field);
184                            }
185    
186                            if (checks instanceof Collection)
187                                    for (final Check check : (Collection<Check>) checks)
188                                    {
189                                            checksOfField.add(check);
190                                            if (check.getContext() == null) check.setContext(ContextCache.getFieldContext(field));
191                                    }
192                            else
193                                    for (final Check check : (Check[]) checks)
194                                    {
195                                            checksOfField.add(check);
196                                            if (check.getContext() == null) check.setContext(ContextCache.getFieldContext(field));
197                                    }
198                    }
199            }
200    
201            private void _addMethodParameterCheckExclusions(final Method method, final int parameterIndex,
202                            final Object exclusions) throws InvalidConfigurationException
203            {
204                    final ParameterChecks checksOfMethodParameter = _getChecksOfMethodParameter(method, parameterIndex);
205    
206                    if (exclusions instanceof Collection< ? >)
207                    {
208                            @SuppressWarnings("unchecked")
209                            final Collection<CheckExclusion> exclusionsColl = (Collection<CheckExclusion>) exclusions;
210                            checksOfMethodParameter.checkExclusions.addAll(exclusionsColl);
211                    }
212                    else
213                            ArrayUtils.addAll(checksOfMethodParameter.checkExclusions, (CheckExclusion[]) exclusions);
214            }
215    
216            @SuppressWarnings("unchecked")
217            private void _addMethodParameterChecks(final Method method, final int parameterIndex, final Object checks)
218                            throws InvalidConfigurationException
219            {
220                    if (LOG.isDebug() && !IsGuarded.class.isAssignableFrom(clazz))
221                            LOG.warn("Method parameter constraints may not be validated." + GUARDING_MAY_NOT_BE_ACTIVATED_MESSAGE);
222    
223                    final ParameterChecks checksOfMethodParameter = _getChecksOfMethodParameter(method, parameterIndex);
224    
225                    if (checks instanceof Collection)
226                            for (final Check check : (Collection<Check>) checks)
227                            {
228                                    if (check.getContext() == null) check.setContext(checksOfMethodParameter.context);
229                                    checksOfMethodParameter.checks.add(check);
230                            }
231                    else
232                            for (final Check check : (Check[]) checks)
233                            {
234                                    if (check.getContext() == null) check.setContext(checksOfMethodParameter.context);
235                                    checksOfMethodParameter.checks.add(check);
236                            }
237            }
238    
239            @SuppressWarnings("unchecked")
240            private void _addMethodPostChecks(final Method method, final Object checks) throws InvalidConfigurationException
241            {
242                    if (LOG.isDebug() && !IsGuarded.class.isAssignableFrom(clazz))
243                            LOG.warn("Method post-conditions may not be validated." + GUARDING_MAY_NOT_BE_ACTIVATED_MESSAGE);
244    
245                    synchronized (checksForMethodsPostExcecution)
246                    {
247                            Set<PostCheck> postChecks = checksForMethodsPostExcecution.get(method);
248                            if (postChecks == null)
249                            {
250                                    postChecks = new LinkedSet<PostCheck>(2);
251                                    checksForMethodsPostExcecution.put(method, postChecks);
252                            }
253    
254                            if (checks instanceof Collection)
255                                    for (final PostCheck check : (Collection<PostCheck>) checks)
256                                    {
257                                            postChecks.add(check);
258                                            if (check.getContext() == null) check.setContext(ContextCache.getMethodExitContext(method));
259                                    }
260                            else
261                                    for (final PostCheck check : (PostCheck[]) checks)
262                                    {
263                                            postChecks.add(check);
264                                            if (check.getContext() == null) check.setContext(ContextCache.getMethodExitContext(method));
265                                    }
266                    }
267            }
268    
269            @SuppressWarnings("unchecked")
270            private void _addMethodPreChecks(final Method method, final Object checks) throws InvalidConfigurationException
271            {
272                    if (LOG.isDebug() && !IsGuarded.class.isAssignableFrom(clazz))
273                            LOG.warn("Method pre-conditions may not be validated." + GUARDING_MAY_NOT_BE_ACTIVATED_MESSAGE);
274    
275                    synchronized (checksForMethodsPreExecution)
276                    {
277                            Set<PreCheck> preChecks = checksForMethodsPreExecution.get(method);
278                            if (preChecks == null)
279                            {
280                                    preChecks = new LinkedSet<PreCheck>(2);
281                                    checksForMethodsPreExecution.put(method, preChecks);
282                            }
283    
284                            if (checks instanceof Collection)
285                                    for (final PreCheck check : (Collection<PreCheck>) checks)
286                                    {
287                                            preChecks.add(check);
288                                            if (check.getContext() == null) check.setContext(ContextCache.getMethodEntryContext(method));
289                                    }
290                            else
291                                    for (final PreCheck check : (PreCheck[]) checks)
292                                    {
293                                            preChecks.add(check);
294                                            if (check.getContext() == null) check.setContext(ContextCache.getMethodEntryContext(method));
295                                    }
296                    }
297            }
298    
299            @SuppressWarnings("unchecked")
300            private void _addMethodReturnValueChecks(final Method method, final Boolean isInvariant, final Object checks)
301                            throws InvalidConfigurationException
302            {
303                    // ensure the method has a return type
304                    if (method.getReturnType() == Void.TYPE)
305                            throw new InvalidConfigurationException("Adding return value constraints for method " + method
306                                            + " is not possible. The method is declared as void and does not return any values.");
307    
308                    if (ReflectionUtils.isVoidMethod(method))
309                            throw new InvalidConfigurationException("Cannot apply method return value constraints for void method "
310                                            + method);
311    
312                    final boolean hasParameters = method.getParameterTypes().length > 0;
313    
314                    if (LOG.isDebug() && hasParameters && !IsGuarded.class.isAssignableFrom(clazz))
315                            LOG.warn("Method return value constraints may not be validated." + GUARDING_MAY_NOT_BE_ACTIVATED_MESSAGE);
316    
317                    final boolean isInvariant2 = isInvariant == null ? constrainedMethods.contains(method) : isInvariant;
318    
319                    if (LOG.isDebug() && !isInvariant2 && !IsGuarded.class.isAssignableFrom(clazz))
320                            LOG.warn("Method return value constraints may not be validated." + GUARDING_MAY_NOT_BE_ACTIVATED_MESSAGE);
321    
322                    synchronized (checksForMethodReturnValues)
323                    {
324                            if (!hasParameters && isInvariant2)
325                            {
326                                    if (ReflectionUtils.isStatic(method))
327                                            constrainedStaticMethods.add(method);
328                                    else
329                                            constrainedMethods.add(method);
330                            }
331                            else if (ReflectionUtils.isStatic(method))
332                                    constrainedStaticMethods.remove(method);
333                            else
334                                    constrainedMethods.remove(method);
335    
336                            Set<Check> methodChecks = checksForMethodReturnValues.get(method);
337                            if (methodChecks == null)
338                            {
339                                    methodChecks = new LinkedSet<Check>(2);
340                                    checksForMethodReturnValues.put(method, methodChecks);
341                            }
342    
343                            if (checks instanceof Collection)
344                                    for (final Check check : (Collection<Check>) checks)
345                                    {
346                                            methodChecks.add(check);
347                                            if (check.getContext() == null) check.setContext(ContextCache.getMethodReturnValueContext(method));
348                                    }
349                            else
350                                    for (final Check check : (Check[]) checks)
351                                    {
352                                            methodChecks.add(check);
353                                            if (check.getContext() == null) check.setContext(ContextCache.getMethodReturnValueContext(method));
354                                    }
355                    }
356            }
357    
358            private ParameterChecks _getChecksOfConstructorParameter(final Constructor< ? > ctor, final int paramIndex)
359            {
360                    final int paramCount = ctor.getParameterTypes().length;
361    
362                    if (paramIndex < 0 || paramIndex >= paramCount)
363                            throw new InvalidConfigurationException("Parameter Index " + paramIndex + " is out of range (0-"
364                                            + (paramCount - 1) + ")");
365    
366                    synchronized (checksForConstructorParameters)
367                    {
368                            // retrieve the currently registered checks for all parameters of the specified constructor
369                            Map<Integer, ParameterChecks> checksOfConstructorByParameter = checksForConstructorParameters.get(ctor);
370                            if (checksOfConstructorByParameter == null)
371                            {
372                                    checksOfConstructorByParameter = getCollectionFactory().createMap(paramCount);
373                                    checksForConstructorParameters.put(ctor, checksOfConstructorByParameter);
374                            }
375    
376                            // retrieve the checks for the specified parameter
377                            ParameterChecks checksOfConstructorParameter = checksOfConstructorByParameter.get(paramIndex);
378                            if (checksOfConstructorParameter == null)
379                            {
380                                    checksOfConstructorParameter = new ParameterChecks(ctor, paramIndex,
381                                                    parameterNameResolver.getParameterNames(ctor)[paramIndex]);
382                                    checksOfConstructorByParameter.put(paramIndex, checksOfConstructorParameter);
383                            }
384    
385                            return checksOfConstructorParameter;
386                    }
387            }
388    
389            private ParameterChecks _getChecksOfMethodParameter(final Method method, final int paramIndex)
390            {
391                    final int paramCount = method.getParameterTypes().length;
392    
393                    if (paramIndex < 0 || paramIndex >= paramCount)
394                            throw new InvalidConfigurationException("Parameter index " + paramIndex + " is out of range (0-"
395                                            + (paramCount - 1) + ")");
396    
397                    synchronized (checksForMethodParameters)
398                    {
399                            // retrieve the currently registered checks for all parameters of the specified method
400                            Map<Integer, ParameterChecks> checksOfMethodByParameter = checksForMethodParameters.get(method);
401                            if (checksOfMethodByParameter == null)
402                            {
403                                    checksOfMethodByParameter = getCollectionFactory().createMap(paramCount);
404                                    checksForMethodParameters.put(method, checksOfMethodByParameter);
405                            }
406    
407                            // retrieve the checks for the specified parameter
408                            ParameterChecks checksOfMethodParameter = checksOfMethodByParameter.get(paramIndex);
409                            if (checksOfMethodParameter == null)
410                            {
411                                    checksOfMethodParameter = new ParameterChecks(method, paramIndex,
412                                                    parameterNameResolver.getParameterNames(method)[paramIndex]);
413                                    checksOfMethodByParameter.put(paramIndex, checksOfMethodParameter);
414                            }
415    
416                            return checksOfMethodParameter;
417                    }
418            }
419    
420            /**
421             * adds constraint check exclusions to a constructor parameter 
422             *  
423             * @param constructor
424             * @param parameterIndex
425             * @param exclusions
426             * @throws InvalidConfigurationException if the declaring class is not guarded by GuardAspect 
427             */
428            public void addConstructorParameterCheckExclusions(final Constructor< ? > constructor, final int parameterIndex,
429                            final CheckExclusion... exclusions) throws InvalidConfigurationException
430            {
431                    _addConstructorParameterCheckExclusions(constructor, parameterIndex, exclusions);
432            }
433    
434            /**
435             * adds constraint check exclusions to a constructor parameter 
436             *  
437             * @param constructor
438             * @param parameterIndex
439             * @param exclusions
440             * @throws InvalidConfigurationException if the declaring class is not guarded by GuardAspect 
441             */
442            public void addConstructorParameterCheckExclusions(final Constructor< ? > constructor, final int parameterIndex,
443                            final Collection<CheckExclusion> exclusions) throws InvalidConfigurationException
444            {
445                    _addConstructorParameterCheckExclusions(constructor, parameterIndex, exclusions);
446            }
447    
448            /**
449             * adds constraint checks to a constructor parameter 
450             *  
451             * @param constructor
452             * @param parameterIndex
453             * @param checks
454             * @throws InvalidConfigurationException if the declaring class is not guarded by GuardAspect 
455             */
456            public void addConstructorParameterChecks(final Constructor< ? > constructor, final int parameterIndex,
457                            final Check... checks) throws InvalidConfigurationException
458            {
459                    _addConstructorParameterChecks(constructor, parameterIndex, checks);
460            }
461    
462            /**
463             * adds constraint checks to a constructor parameter 
464             *  
465             * @param constructor
466             * @param parameterIndex
467             * @param checks
468             * @throws InvalidConfigurationException if the declaring class is not guarded by GuardAspect 
469             */
470            public void addConstructorParameterChecks(final Constructor< ? > constructor, final int parameterIndex,
471                            final Collection<Check> checks) throws InvalidConfigurationException
472            {
473                    _addConstructorParameterChecks(constructor, parameterIndex, checks);
474            }
475    
476            /**
477             * adds check constraints to a field 
478             *  
479             * @param field
480             * @param checks 
481             */
482            public void addFieldChecks(final Field field, final Check... checks) throws InvalidConfigurationException
483            {
484                    _addFieldChecks(field, checks);
485            }
486    
487            /**
488             * adds check constraints to a field 
489             *  
490             * @param field
491             * @param checks 
492             */
493            public void addFieldChecks(final Field field, final Collection<Check> checks) throws InvalidConfigurationException
494            {
495                    _addFieldChecks(field, checks);
496            }
497    
498            /**
499             * adds constraint check exclusions to a method parameter 
500             *  
501             * @param method
502             * @param parameterIndex
503             * @param exclusions
504             * @throws InvalidConfigurationException if the declaring class is not guarded by GuardAspect 
505             */
506            public void addMethodParameterCheckExclusions(final Method method, final int parameterIndex,
507                            final CheckExclusion... exclusions) throws InvalidConfigurationException
508            {
509                    _addMethodParameterCheckExclusions(method, parameterIndex, exclusions);
510            }
511    
512            /**
513             * adds constraint check exclusions to a method parameter 
514             *  
515             * @param method
516             * @param parameterIndex
517             * @param exclusions
518             * @throws InvalidConfigurationException if the declaring class is not guarded by GuardAspect 
519             */
520            public void addMethodParameterCheckExclusions(final Method method, final int parameterIndex,
521                            final Collection<CheckExclusion> exclusions) throws InvalidConfigurationException
522            {
523                    _addMethodParameterCheckExclusions(method, parameterIndex, exclusions);
524            }
525    
526            /**
527             * adds constraint checks to a method parameter 
528             *  
529             * @param method
530             * @param parameterIndex
531             * @param checks
532             * @throws InvalidConfigurationException if the declaring class is not guarded by GuardAspect
533             */
534            public void addMethodParameterChecks(final Method method, final int parameterIndex, final Check... checks)
535                            throws InvalidConfigurationException
536            {
537                    _addMethodParameterChecks(method, parameterIndex, checks);
538            }
539    
540            /**
541             * adds constraint checks to a method parameter 
542             *  
543             * @param method
544             * @param parameterIndex
545             * @param checks
546             * @throws InvalidConfigurationException if the declaring class is not guarded by GuardAspect
547             */
548            public void addMethodParameterChecks(final Method method, final int parameterIndex, final Collection<Check> checks)
549                            throws InvalidConfigurationException
550            {
551                    _addMethodParameterChecks(method, parameterIndex, checks);
552            }
553    
554            /**
555             * adds constraint checks to a method's return value
556             * @param method
557             * @param checks
558             * @throws InvalidConfigurationException if the declaring class is not guarded by GuardAspect
559             */
560            public void addMethodPostChecks(final Method method, final Collection<PostCheck> checks)
561                            throws InvalidConfigurationException
562            {
563                    _addMethodPostChecks(method, checks);
564            }
565    
566            /**
567             * adds constraint checks to a method's return value
568             * @param method
569             * @param checks
570             * @throws InvalidConfigurationException if the declaring class is not guarded by GuardAspect
571             */
572            public void addMethodPostChecks(final Method method, final PostCheck... checks)
573                            throws InvalidConfigurationException
574            {
575                    _addMethodPostChecks(method, checks);
576            }
577    
578            /**
579             * @param method
580             * @param checks
581             * @throws InvalidConfigurationException if the declaring class is not guarded by GuardAspect
582             */
583            public void addMethodPreChecks(final Method method, final Collection<PreCheck> checks)
584                            throws InvalidConfigurationException
585            {
586                    _addMethodPreChecks(method, checks);
587            }
588    
589            /**
590             * @param method
591             * @param checks
592             * @throws InvalidConfigurationException if the declaring class is not guarded by GuardAspect
593             */
594            public void addMethodPreChecks(final Method method, final PreCheck... checks) throws InvalidConfigurationException
595            {
596                    _addMethodPreChecks(method, checks);
597            }
598    
599            /**
600             * adds constraint checks to a method's return value
601             * @param method
602             * @param isInvariant determines if the return value should be checked when the object is validated, can be null
603             * @param checks
604             */
605            public void addMethodReturnValueChecks(final Method method, final Boolean isInvariant, final Check... checks)
606                            throws InvalidConfigurationException
607            {
608                    _addMethodReturnValueChecks(method, isInvariant, checks);
609            }
610    
611            /**
612             * adds constraint checks to a method's return value
613             * @param method
614             * @param isInvariant determines if the return value should be checked when the object is validated, can be null
615             * @param checks
616             */
617            public void addMethodReturnValueChecks(final Method method, final Boolean isInvariant,
618                            final Collection<Check> checks) throws InvalidConfigurationException
619            {
620                    _addMethodReturnValueChecks(method, isInvariant, checks);
621            }
622    
623            /**
624             * adds check constraints on object level (invariants) 
625             *  
626             * @param checks 
627             */
628            public void addObjectChecks(final Check... checks)
629            {
630                    synchronized (checksForObject)
631                    {
632                            for (final Check check : checks)
633                            {
634                                    if (check.getContext() == null) check.setContext(ContextCache.getClassContext(clazz));
635                                    checksForObject.add(check);
636                            }
637                    }
638            }
639    
640            /**
641             * adds check constraints on object level (invariants) 
642             *  
643             * @param checks 
644             */
645            public void addObjectChecks(final Collection<Check> checks)
646            {
647                    synchronized (checksForObject)
648                    {
649                            for (final Check check : checks)
650                            {
651                                    if (check.getContext() == null) check.setContext(ContextCache.getClassContext(clazz));
652                                    checksForObject.add(check);
653                            }
654                    }
655            }
656    
657            public synchronized void clear()
658            {
659                    LOG.debug("Clearing all checks for class {1}", clazz);
660    
661                    checksForObject.clear();
662                    checksForMethodsPostExcecution.clear();
663                    checksForMethodsPreExecution.clear();
664                    checksForConstructorParameters.clear();
665                    checksForFields.clear();
666                    checksForMethodReturnValues.clear();
667                    checksForMethodParameters.clear();
668                    constrainedFields.clear();
669                    constrainedStaticFields.clear();
670                    constrainedMethods.clear();
671                    constrainedStaticMethods.clear();
672            }
673    
674            public void clearConstructorChecks(final Constructor< ? > constructor)
675            {
676                    clearConstructorParameterChecks(constructor);
677            }
678    
679            public void clearConstructorParameterChecks(final Constructor< ? > constructor)
680            {
681                    synchronized (checksForConstructorParameters)
682                    {
683                            checksForConstructorParameters.remove(constructor);
684                    }
685            }
686    
687            public void clearConstructorParameterChecks(final Constructor< ? > constructor, final int parameterIndex)
688            {
689                    synchronized (checksForConstructorParameters)
690                    {
691                            // retrieve the currently registered checks for all parameters of the specified method
692                            final Map<Integer, ParameterChecks> checksOfConstructorByParameter = checksForConstructorParameters
693                                            .get(constructor);
694                            if (checksOfConstructorByParameter == null) return;
695    
696                            // retrieve the checks for the specified parameter
697                            final ParameterChecks checksOfMethodParameter = checksOfConstructorByParameter.get(parameterIndex);
698                            if (checksOfMethodParameter == null) return;
699    
700                            checksOfConstructorByParameter.remove(parameterIndex);
701                    }
702            }
703    
704            public void clearFieldChecks(final Field field)
705            {
706                    synchronized (checksForFields)
707                    {
708                            checksForFields.remove(field);
709                            constrainedFields.remove(field);
710                            constrainedStaticFields.remove(field);
711                    }
712            }
713    
714            public synchronized void clearMethodChecks(final Method method)
715            {
716                    clearMethodParameterChecks(method);
717                    clearMethodReturnValueChecks(method);
718                    clearMethodPreChecks(method);
719                    clearMethodPostChecks(method);
720            }
721    
722            public void clearMethodParameterChecks(final Method method)
723            {
724                    synchronized (checksForMethodParameters)
725                    {
726                            checksForMethodParameters.remove(method);
727                    }
728            }
729    
730            public void clearMethodParameterChecks(final Method method, final int parameterIndex)
731            {
732                    synchronized (checksForMethodParameters)
733                    {
734                            // retrieve the currently registered checks for all parameters of the specified method
735                            final Map<Integer, ParameterChecks> checksOfMethodByParameter = checksForMethodParameters.get(method);
736                            if (checksOfMethodByParameter == null) return;
737    
738                            // retrieve the checks for the specified parameter
739                            final ParameterChecks checksOfMethodParameter = checksOfMethodByParameter.get(parameterIndex);
740                            if (checksOfMethodParameter == null) return;
741    
742                            checksOfMethodByParameter.remove(parameterIndex);
743                    }
744            }
745    
746            public void clearMethodPostChecks(final Method method)
747            {
748                    synchronized (checksForMethodsPostExcecution)
749                    {
750                            checksForMethodsPostExcecution.remove(method);
751                    }
752            }
753    
754            public void clearMethodPreChecks(final Method method)
755            {
756                    synchronized (checksForMethodsPreExecution)
757                    {
758                            checksForMethodsPreExecution.remove(method);
759                    }
760            }
761    
762            public void clearMethodReturnValueChecks(final Method method)
763            {
764                    synchronized (checksForMethodReturnValues)
765                    {
766                            checksForMethodReturnValues.remove(method);
767                            constrainedMethods.remove(method);
768                            constrainedStaticMethods.remove(method);
769                    }
770            }
771    
772            public void clearObjectChecks()
773            {
774                    synchronized (checksForObject)
775                    {
776                            checksForObject.clear();
777                    }
778            }
779    
780            public void removeConstructorParameterCheckExclusions(final Constructor< ? > constructor, final int parameterIndex,
781                            final CheckExclusion... exclusions)
782            {
783                    synchronized (checksForConstructorParameters)
784                    {
785                            // retrieve the currently registered checks for all parameters of the specified method
786                            final Map<Integer, ParameterChecks> checksOfConstructorByParameter = checksForConstructorParameters
787                                            .get(constructor);
788                            if (checksOfConstructorByParameter == null) return;
789    
790                            // retrieve the checks for the specified parameter
791                            final ParameterChecks checksOfConstructorParameter = checksOfConstructorByParameter.get(parameterIndex);
792                            if (checksOfConstructorParameter == null) return;
793    
794                            for (final CheckExclusion exclusion : exclusions)
795                                    checksOfConstructorParameter.checkExclusions.remove(exclusion);
796    
797                            if (checksOfConstructorParameter.isEmpty()) checksOfConstructorByParameter.remove(parameterIndex);
798                    }
799            }
800    
801            public void removeConstructorParameterChecks(final Constructor< ? > constructor, final int parameterIndex,
802                            final Check... checks)
803            {
804                    synchronized (checksForConstructorParameters)
805                    {
806                            // retrieve the currently registered checks for all parameters of the specified method
807                            final Map<Integer, ParameterChecks> checksOfConstructorByParameter = checksForConstructorParameters
808                                            .get(constructor);
809                            if (checksOfConstructorByParameter == null) return;
810    
811                            // retrieve the checks for the specified parameter
812                            final ParameterChecks checksOfConstructorParameter = checksOfConstructorByParameter.get(parameterIndex);
813                            if (checksOfConstructorParameter == null) return;
814    
815                            for (final Check check : checks)
816                                    checksOfConstructorParameter.checks.remove(check);
817    
818                            if (checksOfConstructorParameter.isEmpty()) checksOfConstructorByParameter.remove(parameterIndex);
819                    }
820            }
821    
822            public void removeFieldChecks(final Field field, final Check... checks)
823            {
824                    synchronized (checksForFields)
825                    {
826                            final Set<Check> checksOfField = checksForFields.get(field);
827    
828                            if (checksOfField == null) return;
829    
830                            for (final Check check : checks)
831                                    checksOfField.remove(check);
832    
833                            if (checksOfField.size() == 0)
834                            {
835                                    checksForFields.remove(field);
836                                    constrainedFields.remove(field);
837                                    constrainedStaticFields.remove(field);
838                            }
839                    }
840            }
841    
842            public void removeMethodParameterCheckExclusions(final Method method, final int parameterIndex,
843                            final CheckExclusion... exclusions)
844            {
845                    if (parameterIndex < 0 || parameterIndex > method.getParameterTypes().length)
846                            throw new InvalidConfigurationException("ParameterIndex is out of range");
847    
848                    synchronized (checksForMethodParameters)
849                    {
850                            // retrieve the currently registered checks for all parameters of the specified method
851                            final Map<Integer, ParameterChecks> checksOfMethodByParameter = checksForMethodParameters.get(method);
852                            if (checksOfMethodByParameter == null) return;
853    
854                            // retrieve the checks for the specified parameter
855                            final ParameterChecks checksOfMethodParameter = checksOfMethodByParameter.get(parameterIndex);
856                            if (checksOfMethodParameter == null) return;
857    
858                            for (final CheckExclusion exclusion : exclusions)
859                                    checksOfMethodParameter.checkExclusions.remove(exclusion);
860    
861                            if (checksOfMethodParameter.isEmpty()) checksOfMethodByParameter.remove(parameterIndex);
862                    }
863            }
864    
865            public void removeMethodParameterChecks(final Method method, final int parameterIndex, final Check... checks)
866                            throws InvalidConfigurationException
867            {
868                    if (parameterIndex < 0 || parameterIndex > method.getParameterTypes().length)
869                            throw new InvalidConfigurationException("ParameterIndex is out of range");
870    
871                    synchronized (checksForMethodParameters)
872                    {
873                            // retrieve the currently registered checks for all parameters of the specified method
874                            final Map<Integer, ParameterChecks> checksOfMethodByParameter = checksForMethodParameters.get(method);
875                            if (checksOfMethodByParameter == null) return;
876    
877                            // retrieve the checks for the specified parameter
878                            final ParameterChecks checksOfMethodParameter = checksOfMethodByParameter.get(parameterIndex);
879                            if (checksOfMethodParameter == null) return;
880    
881                            for (final Check check : checks)
882                                    checksOfMethodParameter.checks.remove(check);
883    
884                            if (checksOfMethodParameter.isEmpty()) checksOfMethodByParameter.remove(parameterIndex);
885                    }
886            }
887    
888            public void removeMethodPostChecks(final Method method, final PostCheck... checks)
889            {
890                    synchronized (checksForMethodsPostExcecution)
891                    {
892                            final Set<PostCheck> checksforMethod = checksForMethodsPostExcecution.get(method);
893    
894                            if (checksforMethod == null) return;
895    
896                            for (final PostCheck check : checks)
897                                    checksforMethod.remove(check);
898    
899                            if (checksforMethod.size() == 0) checksForMethodsPostExcecution.remove(method);
900                    }
901            }
902    
903            public void removeMethodPreChecks(final Method method, final PreCheck... checks)
904            {
905                    synchronized (checksForMethodsPreExecution)
906                    {
907                            final Set<PreCheck> checksforMethod = checksForMethodsPreExecution.get(method);
908    
909                            if (checksforMethod == null) return;
910    
911                            for (final PreCheck check : checks)
912                                    checksforMethod.remove(check);
913    
914                            if (checksforMethod.size() == 0) checksForMethodsPreExecution.remove(method);
915                    }
916            }
917    
918            public void removeMethodReturnValueChecks(final Method method, final Check... checks)
919            {
920                    synchronized (checksForMethodReturnValues)
921                    {
922                            final Set<Check> checksOfMethod = checksForMethodReturnValues.get(method);
923    
924                            if (checksOfMethod == null) return;
925    
926                            for (final Check check : checks)
927                                    checksOfMethod.remove(check);
928    
929                            if (checksOfMethod.size() == 0)
930                            {
931                                    checksForMethodReturnValues.remove(method);
932                                    constrainedMethods.remove(method);
933                                    constrainedStaticMethods.remove(method);
934                            }
935                    }
936            }
937    
938            public void removeObjectChecks(final Check... checks)
939            {
940                    synchronized (checksForObject)
941                    {
942                            for (final Check check : checks)
943                                    checksForObject.remove(check);
944                    }
945            }
946    }