Index: jsp/ui/AbstractUITag.java =================================================================== RCS file: /cvs/webwork/src/java/com/opensymphony/webwork/views/jsp/ui/AbstractUITag.java,v retrieving revision 1.49 diff -u -r1.49 AbstractUITag.java --- jsp/ui/AbstractUITag.java 20 Oct 2004 09:42:03 -0000 1.49 +++ jsp/ui/AbstractUITag.java 26 Oct 2004 05:09:58 -0000 @@ -11,6 +11,7 @@ import com.opensymphony.webwork.views.jsp.ui.template.TemplateEngine; import com.opensymphony.webwork.views.jsp.ui.template.TemplateEngineManager; import com.opensymphony.webwork.views.jsp.ui.template.TemplateRenderingContext; +import com.opensymphony.webwork.views.util.JavaScriptValidationHolder; import com.opensymphony.xwork.ModelDriven; import com.opensymphony.xwork.config.ConfigurationException; import com.opensymphony.xwork.util.OgnlValueStack; @@ -24,6 +25,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; /** @@ -405,8 +407,9 @@ // register ScriptValiationAware validators for this UI tag with the form Boolean validate = (Boolean) formTag.getParameters().get("validate"); - if ((validate != null) && validate.booleanValue() && (formTag.getActionClass() != null) && (formTag.getActionName() != null) && name != null) { - findScriptingValidators(formTag, (String) name, formTag.getActionClass(), null); + if ((validate != null) && validate.booleanValue() && name != null) { + if (formTag.getJavaScriptValidationHolder() != null) + formTag.getJavaScriptValidationHolder().registerScriptValidators((String) name, getParameters()); } } @@ -425,92 +428,6 @@ } TemplateRenderingContext context = new TemplateRenderingContext(finalTemplateName, pageContext, getStack(), getParameters(), this); engine.renderTemplate(context); - } - - /** - * Finds all ScriptValidationAware validators that apply to the field covered by this tag. - * - * @param formTag the parent form tag this tag is in - * @param fieldName the name of the field to validate (used for error message key) - * @param fieldClass the Class of the object the field is for - * @param propertyName the actual property name to get validator for; if null, fieldName is used - */ - private void findScriptingValidators(FormTag formTag, String fieldName, Class fieldClass, String propertyName) { - List validators = ActionValidatorManager.getValidators(fieldClass, formTag.getActionName()); - String name = fieldName; - - if (propertyName != null) { - name = propertyName; - } - - for (Iterator iterator = validators.iterator(); iterator.hasNext();) { - Validator validator = (Validator) iterator.next(); - - if (!(validator instanceof ScriptValidationAware)) { - continue; - } - - ValidatorContext validatorContext = new DelegatingValidatorContext(fieldClass); - - if (validator instanceof FieldValidator) { - FieldValidator fieldValidator = (FieldValidator) validator; - - // JavaScriptVisitorFieldValidators must validate model, not action - if (validator instanceof JavaScriptVisitorFieldValidator) { - JavaScriptVisitorFieldValidator visitorValidator = (JavaScriptVisitorFieldValidator) validator; - String propName = null; - boolean visit; - - if (visitorValidator.getFieldName().equals("model") && ModelDriven.class.isAssignableFrom(fieldClass)) { - visit = true; - } else { - String baseName = name; - int idx = name.indexOf("."); - - if (idx != -1) { - baseName = name.substring(0, idx); - propName = name.substring(idx + 1); - } - - visit = baseName.equals(visitorValidator.getFieldName()); - } - - if (visit) { - Class realFieldClass = visitorValidator.getValidatedClass(); - - if (realFieldClass == null) { - for (Iterator iterator1 = getStack().getRoot().iterator(); iterator1.hasNext();) { - Object o = iterator1.next(); - try { - PropertyDescriptor pd = - OgnlRuntime.getPropertyDescriptor(o.getClass(), visitorValidator.getFieldName()); - realFieldClass = pd.getPropertyType(); - break; - } catch (Throwable t) { - // just keep trying - } - } - } - - if (realFieldClass != null) { - if (visitorValidator.isAppendPrefix()) { - findScriptingValidators(formTag, visitorValidator.getFieldName() + "." + name, realFieldClass, propName); - } else { - findScriptingValidators(formTag, name, realFieldClass, propName); - } - } else { - LOG.warn("Cannot figure out class of visited object"); - } - } - } else if (fieldValidator.getFieldName().equals(name)) { - validator.setValidatorContext(validatorContext); - formTag.registerValidator((ScriptValidationAware) fieldValidator, new HashMap(getParameters())); - } - } else { - validator.setValidatorContext(validatorContext); - formTag.registerValidator((ScriptValidationAware) validator, new HashMap(getParameters())); - } - } } private String setupPath(String path, boolean prefix) { Index: jsp/ui/FormTag.java =================================================================== RCS file: /cvs/webwork/src/java/com/opensymphony/webwork/views/jsp/ui/FormTag.java,v retrieving revision 1.22 diff -u -r1.22 FormTag.java --- jsp/ui/FormTag.java 18 Oct 2004 03:43:55 -0000 1.22 +++ jsp/ui/FormTag.java 26 Oct 2004 05:09:58 -0000 @@ -8,6 +8,7 @@ import com.opensymphony.webwork.config.Configuration; import com.opensymphony.webwork.validators.ScriptValidationAware; import com.opensymphony.webwork.views.jsp.TagUtils; +import com.opensymphony.webwork.views.util.JavaScriptValidationHolder; import com.opensymphony.webwork.views.util.UrlHelper; import com.opensymphony.xwork.ObjectFactory; import com.opensymphony.xwork.config.ConfigurationManager; @@ -16,6 +17,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.servlet.jsp.JspException; + import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -44,7 +47,8 @@ String methodAttr; String namespaceAttr; String validateAttr; - + JavaScriptValidationHolder javaScriptValidationHolder; + //~ Methods //////////////////////////////////////////////////////////////// public void setAction(String action) { @@ -130,6 +134,10 @@ String result = UrlHelper.buildUrl(action, request, response, null); addParameter("action", result); } + + if (actionName != null && actionClass != null) { + javaScriptValidationHolder = new JavaScriptValidationHolder(actionName, actionClass); + } } if (enctypeAttr != null) { @@ -143,41 +151,14 @@ if (validateAttr != null) { addParameter("validate", findValue(validateAttr, Boolean.class)); } - - if (fieldValidators != null) { - StringBuffer js = new StringBuffer(); - - // loop backwards so that the first elements are validated first - for (int i = 0; i < fieldValidators.size(); i++) { - ScriptValidationAware sva = (ScriptValidationAware) fieldValidators.get(i); - Map params = (Map) fieldParameters.get(i); - js.append(sva.validationScript(params)); - js.append('\n'); - } - - addParameter("javascriptValidation", js.toString()); + + if (javaScriptValidationHolder != null && javaScriptValidationHolder.hasValidators()) { + addParameter("javascriptValidation", javaScriptValidationHolder.toJavaScript()); } else { addParameter("javascriptValidation", "// cannot find any applicable validators"); } } - /** - * Registers ScriptAware validators that should be called when the form is closed to output - * necessary script. - *
- * Registration of validators is open until the first time the end of the tag is reached or - * there will be duplicate validators if the tag is cached. - */ - public void registerValidator(ScriptValidationAware sva, Map params) { - if (fieldValidators == null) { - fieldValidators = new ArrayList(); - fieldParameters = new ArrayList(); - } - - fieldValidators.add(sva); - fieldParameters.add(params); - } - protected String getDefaultTemplate() { return TEMPLATE; } @@ -185,7 +166,7 @@ protected boolean evaluateNameValue() { return false; } - + /** * Resets the attributes of this tag so that the tag may be reused. As a general rule, only * properties that are not specified as an attribute or properties that are derived need to be @@ -195,10 +176,19 @@ */ protected void reset() { super.reset(); - - if (fieldValidators != null) { - fieldValidators.clear(); - fieldParameters.clear(); + + javaScriptValidationHolder = null; + if (getActionName() != null && getActionClass() != null) { + javaScriptValidationHolder = new JavaScriptValidationHolder(getActionName(), getActionClass()); } + } + + /** + * provide access to the JavaScriptValidationHolder so that the AbstractUITag + * can trigger the registration of all validators + * @return + */ + JavaScriptValidationHolder getJavaScriptValidationHolder() { + return javaScriptValidationHolder; } } Index: util/JavaScriptValidationHolder.java =================================================================== RCS file: util/JavaScriptValidationHolder.java diff -N util/JavaScriptValidationHolder.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ util/JavaScriptValidationHolder.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,158 @@ +/* + * Created on 26/10/2004 + */ +package com.opensymphony.webwork.views.util; + +import java.beans.PropertyDescriptor; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import ognl.OgnlRuntime; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.opensymphony.webwork.ServletActionContext; +import com.opensymphony.webwork.validators.JavaScriptVisitorFieldValidator; +import com.opensymphony.webwork.validators.ScriptValidationAware; +import com.opensymphony.xwork.ModelDriven; +import com.opensymphony.xwork.util.OgnlValueStack; +import com.opensymphony.xwork.validator.ActionValidatorManager; +import com.opensymphony.xwork.validator.DelegatingValidatorContext; +import com.opensymphony.xwork.validator.FieldValidator; +import com.opensymphony.xwork.validator.Validator; +import com.opensymphony.xwork.validator.ValidatorContext; + +/** + * @author CameronBraid + */ +public class JavaScriptValidationHolder { + + public JavaScriptValidationHolder(String actionName, Class actionClass) { + this.actionName = actionName; + this.actionClass = actionClass; + } + + private static final Log LOG = LogFactory.getLog(JavaScriptValidationHolder.class); + + OgnlValueStack valueStack = ServletActionContext.getContext().getValueStack(); + Class actionClass; + String actionName; + List fieldValidators = new ArrayList(); + List fieldParameters = new ArrayList(); + + public boolean hasValidators() { + return (fieldValidators.size() > 0); + } + + public String toJavaScript() { + StringBuffer js = new StringBuffer(); + + // loop backwards so that the first elements are validated first + for (int i = 0; i < fieldValidators.size(); i++) { + ScriptValidationAware sva = (ScriptValidationAware) fieldValidators.get(i); + Map params = (Map) fieldParameters.get(i); + js.append(sva.validationScript(params)); + js.append('\n'); + } + return js.toString(); + } + + public void registerValidator(ScriptValidationAware scriptValidator, Map params) { + fieldValidators.add(scriptValidator); + fieldParameters.add(params); + } + + public void registerScriptValidators(String fieldName, Map parameters) { + registerScriptingValidators(fieldName, parameters, actionClass, null); + } + + /** + * Finds all ScriptValidationAware validators that apply to the field covered by this tag. + * + * @param fieldName the name of the field to validate (used for error message key) + * @param parameters any parameters that can be used in generating the validation message + * @param fieldClass the Class of the object the field is for + * @param propertyName the actual property name to get validator for; if null, fieldName is used + */ + protected void registerScriptingValidators(String fieldName, Map parameters, Class fieldClass, String propertyName) { + List validators = ActionValidatorManager.getValidators(fieldClass, actionName); + String name = fieldName; + + if (propertyName != null) { + name = propertyName; + } + + for (Iterator iterator = validators.iterator(); iterator.hasNext();) { + Validator validator = (Validator) iterator.next(); + + if (!(validator instanceof ScriptValidationAware)) { + continue; + } + + ValidatorContext validatorContext = new DelegatingValidatorContext(fieldClass); + + if (validator instanceof FieldValidator) { + FieldValidator fieldValidator = (FieldValidator) validator; + + // JavaScriptVisitorFieldValidators must validate model, not action + if (validator instanceof JavaScriptVisitorFieldValidator) { + JavaScriptVisitorFieldValidator visitorValidator = (JavaScriptVisitorFieldValidator) validator; + String propName = null; + boolean visit; + + if (visitorValidator.getFieldName().equals("model") && ModelDriven.class.isAssignableFrom(fieldClass)) { + visit = true; + } else { + String baseName = name; + int idx = name.indexOf("."); + + if (idx != -1) { + baseName = name.substring(0, idx); + propName = name.substring(idx + 1); + } + + visit = baseName.equals(visitorValidator.getFieldName()); + } + + if (visit) { + Class realFieldClass = visitorValidator.getValidatedClass(); + + if (realFieldClass == null) { + for (Iterator iterator1 = valueStack.getRoot().iterator(); iterator1.hasNext();) { + Object o = iterator1.next(); + try { + PropertyDescriptor pd = + OgnlRuntime.getPropertyDescriptor(o.getClass(), visitorValidator.getFieldName()); + realFieldClass = pd.getPropertyType(); + break; + } catch (Throwable t) { + // just keep trying + } + } + } + + if (realFieldClass != null) { + if (visitorValidator.isAppendPrefix()) { + registerScriptingValidators(visitorValidator.getFieldName() + "." + name, parameters, realFieldClass, propName); + } else { + registerScriptingValidators(name, parameters, realFieldClass, propName); + } + } else { + LOG.warn("Cannot figure out class of visited object"); + } + } + } else if (fieldValidator.getFieldName().equals(name)) { + validator.setValidatorContext(validatorContext); + registerValidator((ScriptValidationAware) fieldValidator, new HashMap(parameters)); + } + } else { + validator.setValidatorContext(validatorContext); + registerValidator((ScriptValidationAware) validator, new HashMap(parameters)); + } + } + } +}