001    /*******************************************************************************
002     * Portions created by Sebastian Thomschke are copyright (c) 2005-2013 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.Method;
018    import java.util.Map;
019    
020    import net.sf.oval.ConstraintTarget;
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.InvalidConfigurationException;
025    import net.sf.oval.exception.ReflectionException;
026    import net.sf.oval.internal.util.ReflectionUtils;
027    
028    /**
029     * @author Sebastian Thomschke
030     */
031    public class ValidateWithMethodCheck extends AbstractAnnotationCheck<ValidateWithMethod>
032    {
033            private static final long serialVersionUID = 1L;
034    
035            private boolean ignoreIfNull;
036            private String methodName;
037            private Class< ? > parameterType;
038    
039            /**
040             * {@inheritDoc}
041             */
042            @Override
043            public void configure(final ValidateWithMethod constraintAnnotation)
044            {
045                    super.configure(constraintAnnotation);
046                    setMethodName(constraintAnnotation.methodName());
047                    setParameterType(constraintAnnotation.parameterType());
048                    setIgnoreIfNull(constraintAnnotation.ignoreIfNull());
049            }
050    
051            /**
052             * {@inheritDoc}
053             */
054            @Override
055            protected Map<String, String> createMessageVariables()
056            {
057                    final Map<String, String> messageVariables = getCollectionFactory().createMap(4);
058                    messageVariables.put("ignoreIfNull", Boolean.toString(ignoreIfNull));
059                    messageVariables.put("methodName", methodName);
060                    messageVariables.put("parameterType", parameterType.getName());
061                    return messageVariables;
062            }
063    
064            /**
065             * {@inheritDoc}
066             */
067            @Override
068            protected ConstraintTarget[] getAppliesToDefault()
069            {
070                    return new ConstraintTarget[]{ConstraintTarget.VALUES};
071            }
072    
073            /**
074             * @return the methodName
075             */
076            public String getMethodName()
077            {
078                    return methodName;
079            }
080    
081            /**
082             * @return the parameterType
083             */
084            public Class< ? > getParameterType()
085            {
086                    return parameterType;
087            }
088    
089            /**
090             * @return the ignoreIfNull
091             */
092            public boolean isIgnoreIfNull()
093            {
094                    return ignoreIfNull;
095            }
096    
097            /**
098             * {@inheritDoc}
099             */
100            public boolean isSatisfied(final Object validatedObject, final Object valueToValidate, final OValContext context,
101                            final Validator validator) throws ReflectionException
102            {
103                    if (valueToValidate == null && ignoreIfNull) return true;
104    
105                    final Method method = ReflectionUtils.getMethodRecursive(validatedObject.getClass(), methodName, parameterType);
106                    if (method == null)
107                            throw new InvalidConfigurationException("Method " + validatedObject.getClass().getName() + "." + methodName + "("
108                                            + parameterType + ") not found. Is [" + parameterType + "] the correct value for [parameterType]?");
109                    //explicit cast to avoid: type parameters of <T>T cannot be determined; no unique maximal instance exists for type variable T with upper bounds boolean,java.lang.Object
110                    return (Boolean) ReflectionUtils.invokeMethod(method, validatedObject, valueToValidate);
111            }
112    
113            /**
114             * @param ignoreIfNull the ignoreIfNull to set
115             */
116            public void setIgnoreIfNull(final boolean ignoreIfNull)
117            {
118                    this.ignoreIfNull = ignoreIfNull;
119                    requireMessageVariablesRecreation();
120            }
121    
122            /**
123             * @param methodName the methodName to set
124             */
125            public void setMethodName(final String methodName)
126            {
127                    this.methodName = methodName;
128                    requireMessageVariablesRecreation();
129            }
130    
131            /**
132             * @param parameterType the parameterType to set
133             */
134            public void setParameterType(final Class< ? > parameterType)
135            {
136                    this.parameterType = parameterType;
137                    requireMessageVariablesRecreation();
138            }
139    }