Commits

cameronbraid  committed 5cfb342

WW-668 : Externalise the JavaScript validation support from the JSP taglibs

git-svn-id: http://svn.opensymphony.com/svn/webwork/trunk@626573baa09-0c28-0410-bef9-dab3c582ae83

  • Participants
  • Parent commits a8a35de

Comments (0)

Files changed (3)

File src/java/com/opensymphony/webwork/views/jsp/ui/AbstractUITag.java

 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;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 
 /**
             // 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().registerValidateField((String) name, getParameters());
             }
         }
 
         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) {
         if ((path != null) && (path != "")) {
             if (prefix) {

File src/java/com/opensymphony/webwork/views/jsp/ui/FormTag.java

 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;
 
 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;
     String methodAttr;
     String namespaceAttr;
     String validateAttr;
-
+    JavaScriptValidationHolder javaScriptValidationHolder;
+    
     //~ Methods ////////////////////////////////////////////////////////////////
 
     public void setAction(String action) {
                 String result = UrlHelper.buildUrl(action, request, response, null);
                 addParameter("action", result);
             }
+            
+            // only create the javaScriptValidationHolder if the actionName,and class is known
+            // and the javaScriptValidationHolder hasn't been created already
+            // i.e. don'r re-create it on the second call to evaluateExtraParams
+            if (actionName != null && actionClass != null && javaScriptValidationHolder == null) {
+                javaScriptValidationHolder = new JavaScriptValidationHolder(actionName, actionClass);
+            }
         }
 
         if (enctypeAttr != null) {
         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.
-     * <p />
-     * 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;
     }
     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
      */
     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;
+    }
 }

File src/java/com/opensymphony/webwork/views/util/JavaScriptValidationHolder.java

+/*
+ * 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 registerValidateField(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));
+            }
+        }
+    }
+}