package lib.framework.struts; import java.util.Iterator; import java.util.Collection; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ActionMessages; import org.apache.struts.validator.Resources; import org.apache.commons.validator.Field; import org.apache.commons.validator.ValidatorAction; import org.apache.commons.validator.Validator; import org.apache.commons.validator.ValidatorResults; import org.apache.commons.validator.ValidatorException; import org.apache.commons.validator.Arg; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.beanutils.PropertyUtils; /** * * * @author Niall Pemberton */ public class ValidatorExtendsRule { /** * Commons Logging */ private static Log logger = LogFactory.getLog(ValidatorExtendsRule.class); public ValidatorExtendsRule() { } /** *

Executes validation for another set of "inherited" rules.

* * @param bean The bean validation is being performed on. * @param va The ValidatorAction that is currently being performed. * @param field The Field object associated with the current * field being validated. * @param errors The ActionMessages object to add errors to if any * validation errors occur. * @param validator The Validator instance, used to access * other field values. * @param request Current request object. * @param application The Servlet Context * @return results of the validator. */ public static Object validateExtends(Object bean, ValidatorAction va, Field field, ActionMessages errors, Validator validator, HttpServletRequest request, ServletContext application) { String fieldPrefix = field.getProperty().length() > 0 ? field.getProperty() : null; String formAndProperty = fieldPrefix == null ? validator.getFormName() : validator.getFormName() + "/" + fieldPrefix; // Get the validation key String key = field.getVarValue("extends"); if (key == null || key.length() == 0) { logger.error("'extends' var is missing for " + formAndProperty); errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("errors.extends", formAndProperty)); return Boolean.FALSE; } // Get the property value Object value = null; if (fieldPrefix == null) { value = bean; } else { try { value = PropertyUtils.getProperty(bean, field.getProperty()); } catch(Exception e) { logger.error("Error retrieving property '" + formAndProperty + "' "+e.getMessage(), e); errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("errors.extends", formAndProperty)); } } if (value == null) { logger.error("Property '" + formAndProperty + "' is NULL"); errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("errors.extends", formAndProperty)); return Boolean.FALSE; } // Initialize the validator ActionMessages newErrors = new ActionMessages(); Validator newValidator = Resources.initValidator(key, bean, application, request, newErrors, validator.getPage()); // Is it an Array/Collection? Object[] values = null; if (value instanceof Collection) { values = ((Collection)value).toArray(); } else if (value.getClass().isArray()) { values = (Object[])value; } // Execute the validator ValidatorResults results = null; if (values == null) { results = executeValidator(bean, -1, field, newValidator, errors, newErrors, fieldPrefix); } else { results = new ValidatorResults(); for (int i = 0; i < values.length; i++) { fieldPrefix = field.getProperty() + "[" + i + "]."; newValidator.setParameter(Validator.BEAN_PARAM, values[i]); ValidatorResults indexedResults = executeValidator(values[i], (i+1), field, newValidator, errors, newErrors, fieldPrefix); results.merge(indexedResults); } } return results; } /** * Executes a validator. * * @param key The key of the validator to execute * @param bean The bean validation is being performed on. * @param application The Servlet Context * @param request Current request object. * @param errors The ActionMessages object to add errors to if any * validation errors occur. * @param page Page Number. * @param prefix Prefix for error message properties. * @return results of the validator. */ private static ValidatorResults executeValidator(Object bean, int index, Field field, Validator validator, ActionMessages errors, ActionMessages newErrors, String fieldPrefix) { // Validate ValidatorResults results = null; try { results = validator.validate(); } catch (ValidatorException e) { logger.error(e.getMessage(), e); } // Get Additional Argument Arg arg = field.getArg(0); String argKey = arg == null ? null : arg.getKey(); Object argValue = null; if (argKey != null) { if ("#".equals(argKey)) { argValue = "" + index; } else { try { argValue = PropertyUtils.getProperty(bean, argKey); } catch(Exception e) { logger.error("Error retrieving property '" + argKey + "' "+e.getMessage(), e); } argValue = argValue == null || "".equals(argValue) ? "???" : argValue; } } // Merge Errors if (newErrors.size() > 0) { if (fieldPrefix == null && argValue == null) { errors.add(newErrors); } else { Iterator properties = newErrors.properties(); while (properties.hasNext()) { String property = (String)properties.next(); Iterator messages = newErrors.get(property); while (messages.hasNext()) { ActionMessage msg = (ActionMessage)messages.next(); ActionMessage newMsg = msg; String newProperty = fieldPrefix == null ? property : fieldPrefix + property; if (argValue != null) { // Add the additonal "argument" to the messages Object[] args = msg.getValues(); Object[] newArgs = args; if (argValue != null) { int length = 0; if (args != null) { for (int i = 0; i < args.length; i++) { if (args[i] != null) length = i + 1; } } if (length == 0) { newArgs = new Object[] {argValue}; } else { newArgs = new Object[length + 1]; System.arraycopy(args, 0, newArgs, 0, length); newArgs[length] = argValue; } } newMsg = new ActionMessage(msg.getKey(), newArgs); } errors.add(newProperty, newMsg); } } } } // Clear Errors newErrors.clear(); // Return results return results; } }