/*
* Copyright 2005-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.strecks.validator.strategy;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.strecks.converter.ConversionState;
import org.strecks.exceptions.ApplicationRuntimeException;
import org.strecks.util.ReflectHelper;
import org.strecks.validator.Validator;
import org.strecks.validator.internal.MethodValidators;
import org.strecks.validator.internal.OrderedProperty;
import org.strecks.validator.internal.ValidationInfo;
import org.strecks.validator.internal.ValidatorWrapper;
/**
* Default implementation of <code>ValidationHandler</code>. Validates annotations first, then
* calls wrapped form's <code>validate()</code> method, merging the results in a returned
* <code>ActionErrors</code> object.
* @author Phil Zoio
*/
public class DefaultValidationStrategy implements ValidationHandler
{
private static Log log = LogFactory.getLog(DefaultValidationStrategy.class);
public ActionErrors validate(ValidationInfo validationInfo, ActionForm form, ActionMapping mapping,
HttpServletRequest request, Map<String, Object> convertedValues)
{
Map<OrderedProperty, MethodValidators> validators = validationInfo.getValidators();
ActionErrors actionErrors = null;
Set<OrderedProperty> keySet = validators.keySet();
for (OrderedProperty orderedProperty : keySet)
{
String propertyName = orderedProperty.getPropertyName();
MethodValidators methodValidators = validators.get(orderedProperty);
Object convertedValue = null;
if (methodValidators.getRequiresConversion())
{
if (convertedValues != null)
{
convertedValue = convertedValues.get(propertyName);
}
}
List<ValidatorWrapper> list = methodValidators.getValidators();
boolean gotRawValue = false;
Object rawValue = null;
for (ValidatorWrapper wrapper : list)
{
if (!gotRawValue)
{
Method getter = wrapper.getGetterMethod();
rawValue = ReflectHelper.invokeMethod(form, getter);
gotRawValue = true;
}
boolean validate = true;
Validator validator = wrapper.getValidator();
if (wrapper.getUsesConvertedValue())
{
if (convertedValue != null)
{
if (convertedValue == ConversionState.FAILURE)
{
validate = false;
}
else if (convertedValue == ConversionState.NULL)
{
validate = true;
}
else
{
validate = validate(wrapper.getGetterMethod().getDeclaringClass(), propertyName,
convertedValue, validator);
}
}
}
else
{
validate = validate(wrapper.getGetterMethod().getDeclaringClass(), propertyName, rawValue,
validator);
}
if (!validate)
{
actionErrors = appendError(actionErrors, rawValue, propertyName, wrapper);
break;
}
}
}
ActionErrors formErrors = form.validate(mapping, request);
if (formErrors != null)
{
//thanks to Robin Young for this fix
if (actionErrors == null)
{
actionErrors = new ActionErrors();
}
actionErrors.add(formErrors);
}
return actionErrors;
}
private ActionErrors appendError(ActionErrors actionErrors, Object rawValue, String propertyName,
ValidatorWrapper wrapper)
{
List<Object> params = wrapper.getParams();
Object[] parameters = wrapper.getParameterProvider().getParameters(rawValue, params);
ActionMessage actionMessage = new ActionMessage(wrapper.getKey(), parameters);
if (actionErrors == null)
actionErrors = new ActionErrors();
actionErrors.add(propertyName, actionMessage);
if (log.isDebugEnabled())
{
log.debug("Validation failed for property " + propertyName);
}
return actionErrors;
}
@SuppressWarnings("unchecked")
boolean validate(Class containingClass, String propertyName, Object value, Validator validator)
{
try
{
boolean validate = validator.validate(value);
return validate;
}
catch (ClassCastException e)
{
Class<?> sourceType = value.getClass();
Class<? extends Validator> validatorClass = validator.getClass();
Type[] genericTypes = ReflectHelper.getGenericTypes(validatorClass, Validator.class);
String description = ReflectHelper.getTypeArrayDescription(genericTypes);
throw new ApplicationRuntimeException("Mismatch between parameterization type of validator: "
+ validatorClass.getName() + description + ", and type of property being validated: property "
+ propertyName + " in class " + containingClass.getName() + "(" + sourceType + ")");
}
}
}