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.constraint;
014    
015    import static net.sf.oval.Validator.getCollectionFactory;
016    
017    import java.lang.reflect.Field;
018    import java.lang.reflect.Method;
019    import java.util.Map;
020    
021    import net.sf.oval.Validator;
022    import net.sf.oval.configuration.annotation.AbstractAnnotationCheck;
023    import net.sf.oval.context.OValContext;
024    import net.sf.oval.exception.FieldNotFoundException;
025    import net.sf.oval.exception.InvokingMethodFailedException;
026    import net.sf.oval.exception.MethodNotFoundException;
027    import net.sf.oval.internal.ContextCache;
028    import net.sf.oval.internal.util.ReflectionUtils;
029    
030    /**
031     * @author Sebastian Thomschke
032     */
033    public class NotEqualToFieldCheck extends AbstractAnnotationCheck<NotEqualToField>
034    {
035            private static final long serialVersionUID = 1L;
036    
037            private boolean useGetter;
038    
039            private String fieldName;
040    
041            private Class< ? > declaringClass;
042    
043            /**
044             * {@inheritDoc}
045             */
046            @Override
047            public void configure(final NotEqualToField constraintAnnotation)
048            {
049                    super.configure(constraintAnnotation);
050                    setFieldName(constraintAnnotation.value());
051                    setDeclaringClass(constraintAnnotation.declaringClass());
052                    setUseGetter(constraintAnnotation.useGetter());
053            }
054    
055            /**
056             * {@inheritDoc}
057             */
058            @Override
059            protected Map<String, String> createMessageVariables()
060            {
061                    final Map<String, String> messageVariables = getCollectionFactory().createMap(2);
062                    messageVariables.put("fieldName", fieldName);
063                    messageVariables.put("declaringClass", declaringClass == null || declaringClass == Void.class ? null
064                                    : declaringClass.getName());
065                    messageVariables.put("useGetter", Boolean.toString(useGetter));
066                    return messageVariables;
067            }
068    
069            /**
070             * @return the declaringClass
071             */
072            public Class< ? > getDeclaringClass()
073            {
074                    return declaringClass;
075            }
076    
077            /**
078             * @return the fieldName
079             */
080            public String getFieldName()
081            {
082                    return fieldName;
083            }
084    
085            /**
086             * {@inheritDoc}
087             */
088            public boolean isSatisfied(final Object validatedObject, final Object valueToValidate, final OValContext context,
089                            final Validator validator)
090            {
091                    if (valueToValidate == null) return true;
092    
093                    final Class< ? > clazz = validatedObject.getClass();
094    
095                    final Object valueToCompare;
096                    if (useGetter)
097                    {
098                            final Method getter = ReflectionUtils.getGetterRecursive(clazz, fieldName);
099                            if (getter == null)
100                                    throw new MethodNotFoundException("Getter for field <" + fieldName + "> not found in class <" + clazz
101                                                    + "> or it's super classes.");
102    
103                            try
104                            {
105                                    valueToCompare = getter.invoke(validatedObject);
106                            }
107                            catch (final Exception ex)
108                            {
109                                    throw new InvokingMethodFailedException(getter.getName(), validatedObject,
110                                                    ContextCache.getMethodReturnValueContext(getter), ex);
111                            }
112                    }
113                    else
114                    {
115                            final Field field = ReflectionUtils.getFieldRecursive(clazz, fieldName);
116    
117                            if (field == null)
118                                    throw new FieldNotFoundException("Field <" + fieldName + "> not found in class <" + clazz
119                                                    + "> or it's super classes.");
120    
121                            valueToCompare = ReflectionUtils.getFieldValue(field, validatedObject);
122                    }
123    
124                    if (valueToCompare == null) return true;
125    
126                    return !valueToValidate.equals(valueToCompare);
127            }
128    
129            /**
130             * @return the useGetter
131             */
132            public boolean isUseGetter()
133            {
134                    return useGetter;
135            }
136    
137            /**
138             * @param declaringClass the declaringClass to set
139             */
140            public void setDeclaringClass(final Class< ? > declaringClass)
141            {
142                    this.declaringClass = declaringClass == Void.class ? null : declaringClass;
143                    requireMessageVariablesRecreation();
144            }
145    
146            /**
147             * @param fieldName the fieldName to set
148             */
149            public void setFieldName(final String fieldName)
150            {
151                    this.fieldName = fieldName;
152                    requireMessageVariablesRecreation();
153            }
154    
155            /**
156             * @param useGetter the useGetter to set
157             */
158            public void setUseGetter(final boolean useGetter)
159            {
160                    this.useGetter = useGetter;
161                    requireMessageVariablesRecreation();
162            }
163    }