/**
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.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://license.openmrs.org
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */
package org.openmrs.validator;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import org.apache.commons.lang.StringUtils;
import org.openmrs.api.APIException;
import org.openmrs.api.context.Context;
import org.openmrs.util.HandlerUtil;
import org.springframework.util.Assert;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.Validator;

/**
 * This class should be used in the *Services to validate objects before saving them. <br/>
 * <br/>
 * The validators are added to this class in the spring applicationContext-service.xml file. <br/>
 * <br/>
 * Example usage:
 * 
 * <pre>
 *  public Order saveOrder(order) {
 *  	ValidateUtil.validate(order);
 *  	dao.saveOrder(order);
 *  }
 * </pre>
 * 
 * @since 1.5
 */
public class ValidateUtil {
	
	/**
	 * @deprecated in favor of using HandlerUtil to reflexively get validators
	 * @param newValidators the validators to set
	 */
	@Deprecated
	public void setValidators(List<Validator> newValidators) {
		
	}
	
	/**
	 * Fetches all validators that are registered
	 * 
	 * @param obj the object that will be validated
	 * @return list of compatibile validators
	 */
	protected static List<Validator> getValidators(Object obj) {
		List<Validator> matchingValidators = new Vector<Validator>();
		
		List<Validator> validators = HandlerUtil.getHandlersForType(Validator.class, obj.getClass());
		
		for (Validator validator : validators) {
			if (validator.supports(obj.getClass())) {
				matchingValidators.add(validator);
			}
		}
		
		return matchingValidators;
	}
	
	/**
	 * Test the given object against all validators that are registered as compatible with the
	 * object class
	 * 
	 * @param obj the object to validate
	 * @throws APIException thrown if a binding exception occurs
	 * @should throw APIException if errors occur during validation
	 */
	public static void validate(Object obj) throws APIException {
		BindException errors = new BindException(obj, "");
		
		for (Validator validator : getValidators(obj)) {
			validator.validate(obj, errors);
		}
		
		if (errors.hasErrors()) {
			Set<String> uniqueErrorMessages = new LinkedHashSet<String>();
			for (Object objerr : errors.getAllErrors()) {
				ObjectError error = (ObjectError) objerr;
				String message = Context.getMessageSourceService().getMessage(error.getCode());
				if (error instanceof FieldError) {
					message = ((FieldError) error).getField() + ": " + message;
				}
				uniqueErrorMessages.add(message);
			}
			
			String exceptionMessage = "'" + obj + "' failed to validate with reason: ";
			exceptionMessage += StringUtils.join(uniqueErrorMessages, ", ");
			throw new APIException(exceptionMessage, errors.getCause());
		}
	}
	
	/**
	 * Test the field lengths are valid
	 *
	 * @param errors
	 * @param aClass the class of the object being tested
	 * @param fields a var args that contains all of the fields from the model
	 *
	 * @should pass validation if regEx field length is not too long
	 * @should fail validation if regEx field length is too long
	 * @should fail validation if name field length is too long
	 */
	
	public static void validateFieldLengths(Errors errors, Class aClass, String... fields) {
		Assert.notNull(errors, "Errors object must not be null");
		for (String field : fields) {
			Object value = errors.getFieldValue(field);
			if (value == null || !(value instanceof String))
				return;
			int length = Context.getAdministrationService().getMaximumPropertyLength(aClass, field);
			if (((String) value).length() > length) {
				errors.rejectValue(field, "error.exceededMaxLengthOfField", new Object[] { length }, null);
			}
		}
	}
}

@@ -3561,32 +3561,407 @@
 %7D%0D%0A%09%7D%0D%0A%09%0D%0A%09/**%0D%0A
+%09 * Test the given object against all validators that are registered as compatible with the%0D%0A%09 * object class%0D%0A%09 * %0D%0A%09 * @param obj the object to validate%0D%0A%09 * @param errors the validation errors found%0D%0A%09 */%0D%0A%09public static void validate(Object obj, Errors errors) %7B%0D%0A%09%09for (Validator validator : getValidators(obj)) %7B%0D%0A%09%09%09validator.validate(obj, errors);%0D%0A%09%09%7D%0D%0A%09%7D%0D%0A%09%0D%0A%09/**%0D%0A
 %09 * Test the fie

Rename AdministrationService.validateInManualFlushMode, and refactor it and ValidateUtil