You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@struts.apache.org by "David Evans (JIRA)" <ji...@apache.org> on 2006/05/02 06:16:19 UTC

[jira] Reopened: (STR-589) Indexed field validation patch

     [ http://issues.apache.org/struts/browse/STR-589?page=all ]
     
David Evans reopened STR-589:
-----------------------------

    Assign To:     (was: Struts Developer Mailing List)

> Indexed field validation patch
> ------------------------------
>
>          Key: STR-589
>          URL: http://issues.apache.org/struts/browse/STR-589
>      Project: Struts Action 1
>         Type: Improvement

>   Components: Taglibs
>     Versions: Nightly Build
>  Environment: Operating System: All
> Platform: All
>     Reporter: Jose Quinteiro
>     Priority: Minor

>
> I need indexed field validation for my application.  I've started to work on it
> and realized it's quite a large project.  This is what I've got so far.  I still
> need to change validation-rules.xml to work with these changes, but this code
> generates field names for indexed properties.  You'll also need the patch I've
> submitted for commons-validator.
> Comments? Suggestions?  Am I even on the right path?
> Index: src/share/org/apache/struts/taglib/html/JavascriptValidatorTag.java
> ===================================================================
> RCS file:
> /home/cvspublic/jakarta-struts/src/share/org/apache/struts/taglib/html/JavascriptValidatorTag.java,v
> retrieving revision 1.2
> diff -u -3 -p -r1.2 JavascriptValidatorTag.java
> --- src/share/org/apache/struts/taglib/html/JavascriptValidatorTag.java	18 Mar 2002 02:06:41 -0000	1.2
> +++ src/share/org/apache/struts/taglib/html/JavascriptValidatorTag.java	3 May 2002 17:12:41 -0000
> @@ -56,10 +56,13 @@
>  package org.apache.struts.taglib.html;
>  
>  
> +import java.lang.reflect.Array;
>  import java.io.IOException;
>  import java.util.ArrayList;
> -import java.util.Collections; 
> -import java.util.Comparator; 
> +import java.util.Collection;
> +import java.util.Collections;
> +import java.util.Comparator;
> +import java.util.Enumeration;
>  import java.util.Iterator;
>  import java.util.List;
>  import java.util.Locale;
> @@ -76,13 +79,15 @@ import org.apache.commons.validator.Vali
>  import org.apache.commons.validator.Var;
>  import org.apache.struts.action.Action;
>  import org.apache.struts.validator.ValidatorPlugIn;
> +import org.apache.struts.util.IteratorAdapter;
>  import org.apache.struts.util.MessageResources;
> +import org.apache.struts.util.RequestUtils;
>  import org.apache.struts.util.StrutsValidatorUtil;
>  
>  
>  /**
> - * Custom tag that generates JavaScript for client side validation based 
> - * on the validation rules loaded by the <code>ValidatorPlugIn</code> 
> + * Custom tag that generates JavaScript for client side validation based
> + * on the validation rules loaded by the <code>ValidatorPlugIn</code>
>   * defined in the struts-config.xml file.
>   *
>   * @since 1.1
> @@ -92,6 +97,12 @@ public class JavascriptValidatorTag exte
>  
>  
>      // ----------------------------------------------------------- Properties
> +
> /**
> +     * The message resources for this package.
> +     */
> +    protected static MessageResources messages =
> +
> MessageResources.getMessageResources
> +
> ("org.apache.struts.taglib.html.LocalStrings");
>  
>  
>      /**
> @@ -106,18 +117,18 @@ public class JavascriptValidatorTag exte
>      protected static Locale defaultLocale = Locale.getDefault();
>  
>      /**
> -     * The name of the form that corresponds with the action name 
> +     * The name of the form that corresponds with the action name
>       * in struts-config.xml.
>      */
>      protected String formName = null;
>  
>      /**
> -     * The current page number of a multi-part form. 
> +     * The current page number of a multi-part form.
>      */
>      protected int page = 0;
>  
>      /**
> -     * This will be used as is for the JavaScript validation method name if it
> has a value.  This is 
> +     * This will be used as is for the JavaScript validation method name if it
> has a value.  This is
>       * the method name of the main JavaScript method that the form calls to
> perform validations.
>      */
>      protected String methodName = null;
> @@ -138,17 +149,17 @@ public class JavascriptValidatorTag exte
>      protected String src = null;
>      
>      /**
> -     * Gets the key (form name) that will be used 
> -     * to retrieve a set of validation rules to be 
> +     * Gets the key (form name) that will be used
> +     * to retrieve a set of validation rules to be
>       * performed on the bean passed in for validation.
>      */
>      public String getFormName() {
> -       return formName;	
> +       return formName;
>      }
>  
>      /**
> -     * Sets the key (form name) that will be used 
> -     * to retrieve a set of validation rules to be 
> +     * Sets the key (form name) that will be used
> +     * to retrieve a set of validation rules to be
>       * performed on the bean passed in for validation.
>      */
>      public void setFormName(String formName) {
> @@ -156,17 +167,17 @@ public class JavascriptValidatorTag exte
>      }
>  
>      /**
> -     * Gets the current page number of a multi-part form. 
> -     * Only field validations with a matching page numer 
> +     * Gets the current page number of a multi-part form.
> +     * Only field validations with a matching page numer
>       * will be generated that match the current page number.
>      */
>      public int getPage() {
> -       return page;	
> +       return page;
>      }
>  
>      /**
> -     * Sets the current page number of a multi-part form. 
> -     * Only field validations with a matching page numer 
> +     * Sets the current page number of a multi-part form.
> +     * Only field validations with a matching page numer
>       * will be generated that match the current page number.
>      */
>      public void setPage(int page) {
> @@ -174,19 +185,19 @@ public class JavascriptValidatorTag exte
>      }
>  
>      /**
> -     * Gets the method name that will be used for the Javascript 
> -     * validation method name if it has a value.  This overrides 
> -     * the auto-generated method name based on the key (form name) 
> +     * Gets the method name that will be used for the Javascript
> +     * validation method name if it has a value.  This overrides
> +     * the auto-generated method name based on the key (form name)
>       * passed in.
>      */
>      public String getMethod() {
> -       return methodName;	
> +       return methodName;
>      }
>  
>      /**
> -     * Sets the method name that will be used for the Javascript 
> -     * validation method name if it has a value.  This overrides 
> -     * the auto-generated method name based on the key (form name) 
> +     * Sets the method name that will be used for the Javascript
> +     * validation method name if it has a value.  This overrides
> +     * the auto-generated method name based on the key (form name)
>       * passed in.
>      */
>      public void setMethod(String methodName) {
> @@ -194,17 +205,17 @@ public class JavascriptValidatorTag exte
>      }
>      
>      /**
> -     * Gets whether or not to generate the static 
> -     * JavaScript.  If this is set to 'true', which 
> +     * Gets whether or not to generate the static
> +     * JavaScript.  If this is set to 'true', which
>       * is the default, the static JavaScript will be generated.
>      */
>      public String getStaticJavascript() {
> -       return staticJavascript;	
> +       return staticJavascript;
>      }
>  
>      /**
> -     * Sets whether or not to generate the static 
> -     * JavaScript.  If this is set to 'true', which 
> +     * Sets whether or not to generate the static
> +     * JavaScript.  If this is set to 'true', which
>       * is the default, the static JavaScript will be generated.
>      */
>      public void setStaticJavascript(String staticJavascript) {
> @@ -212,17 +223,17 @@ public class JavascriptValidatorTag exte
>      }
>  
>      /**
> -     * Gets whether or not to generate the dynamic 
> -     * JavaScript.  If this is set to 'true', which 
> +     * Gets whether or not to generate the dynamic
> +     * JavaScript.  If this is set to 'true', which
>       * is the default, the dynamic JavaScript will be generated.
>      */
>      public String getDynamicJavascript() {
> -       return dynamicJavascript;	
> +       return dynamicJavascript;
>      }
>  
>      /**
> -     * Sets whether or not to generate the dynamic 
> -     * JavaScript.  If this is set to 'true', which 
> +     * Sets whether or not to generate the dynamic
> +     * JavaScript.  If this is set to 'true', which
>       * is the default, the dynamic JavaScript will be generated.
>      */
>      public void setDynamicJavascript(String dynamicJavascript) {
> @@ -230,15 +241,15 @@ public class JavascriptValidatorTag exte
>      }
>  
>      /**
> -     * Gets the src attribute's value when defining 
> +     * Gets the src attribute's value when defining
>       * the html script element.
>      */
>      public String getSrc() {
> -       return src;	
> +       return src;
>      }
>  
>      /**
> -     * Sets the src attribute's value when defining 
> +     * Sets the src attribute's value when defining
>       * the html script element.
>      */
>      public void setSrc(String src) {
> @@ -279,7 +290,7 @@ public class JavascriptValidatorTag exte
>            for (Iterator i = form.getFields().iterator(); i.hasNext(); ) {
>               Field field = (Field)i.next();
>            
> -             for (Iterator x = field.getDependencies().iterator(); x.hasNext();
> ) {   
> +             for (Iterator x = field.getDependencies().iterator(); x.hasNext(); ) {
>               	Object o = x.next();
>               	
>               	if (o != null && !lActionMethods.contains(o)) {
> @@ -306,20 +317,20 @@ public class JavascriptValidatorTag exte
>                  ValidatorAction va1 = (ValidatorAction)o1;
>                  ValidatorAction va2 = (ValidatorAction)o2;
>            
> -
>          if ((va1.getDepends() == null || va1.getDepends().length() == 0) && 
> +
>          if ((va1.getDepends() == null || va1.getDepends().length() == 0) &&
>  	               (va2.getDepends() == null || va2.getDepends().length() == 0)) {
>                     return 0;
>                  } else if ((va1.getDepends() != null &&
> va1.getDepends().length() > 0) &&
>                             (va2.getDepends() == null ||
> va2.getDepends().length() == 0)) {
>                     return 1;
> -                } else if ((va1.getDepends() == null ||
> va1.getDepends().length() == 0) && 
> +                } else if ((va1.getDepends() == null ||
> va1.getDepends().length() == 0) &&
>                           (va2.getDepends() != null && va2.getDepends().length()
> > 0)) {
>                     return -1;
>                  } else {
>                     return va1.getDependencies().size() -
> va2.getDependencies().size();
>                  }
>               }
> -          });  	   
> +          });
>            
>            String methods = null;
>            for (Iterator i = lActions.iterator(); i.hasNext(); ) {
> @@ -347,43 +358,46 @@ public class JavascriptValidatorTag exte
>               
>               results.append("	 function " + functionName + " () { \n");
>               for (Iterator x = form.getFields().iterator(); x.hasNext(); ) {
> -                Field field = (Field)x.next();         
> +                Field field = (Field)x.next();
>  
> -                // Skip indexed fields for now until there is 
> +                // Skip indexed fields for now until there is
>                  // a good way to handle error messages (and the length of the
> list (could retrieve from scope?))
> -                if (!field.isIndexed() && field.getPage() == page &&
> field.isDependency(va.getName())) {
> +                if ( field.getPage() == page && field.isDependency(va.getName())) {
>  	   	   String message = StrutsValidatorUtil.getMessage(messages, locale, va, field);
>  	   	   message = (message != null ? message : "");
>            
> -                   jscriptVar = getNextVar(jscriptVar);
> -          
> -                   results.append("	    this." + jscriptVar + " = new Array(\"" + field.getKey()
> + "\", \"" + message + "\", ");
> -                   
> -                   results.append("new Function (\"varName\", \"");
> -                   
> -                   Map hVars = field.getVars();
> -                   // Loop through the field's variables.
> -                   for (Iterator iVars = hVars.keySet().iterator();
> iVars.hasNext(); ) {
> -                      String varKey = (String)iVars.next();
> -                      Var var = (Var)hVars.get(varKey);
> -                      String varValue = var.getValue();
> -                      String jsType = var.getJsType();
> -
>                
> -
>                if (Var.JSTYPE_INT.equalsIgnoreCase(jsType)) {
> -
>                   results.append("this." + varKey + "=" +
> ValidatorUtil.replace(varValue, "\\", "\\\\") + "; ");
> -
>                } else if (Var.JSTYPE_REGEXP.equalsIgnoreCase(jsType)) {
> -
>                   results.append("this." + varKey + "=/" +
> ValidatorUtil.replace(varValue, "\\", "\\\\") + "/; ");
> -
>                } else if (Var.JSTYPE_STRING.equalsIgnoreCase(jsType)) {
> -
>                   results.append("this." + varKey + "='" +
> ValidatorUtil.replace(varValue, "\\", "\\\\") + "'; ");
> -
>                // So everyone using the latest format doesn't need to change
> their xml files immediately.
> -
>                } else if ("mask".equalsIgnoreCase(varKey)) {
> -
>                   results.append("this." + varKey + "=/" +
> ValidatorUtil.replace(varValue, "\\", "\\\\") + "/; ");
> -
>                } else {
> -
>                   results.append("this." + varKey + "='" +
> ValidatorUtil.replace(varValue, "\\", "\\\\") + "'; ");
> -
>                }
> -                   }
> -                                               
> -                   results.append(" return this[varName];\"));\n");
> +                   generateParameterNames( results, field, message, jscriptVar );
> +//
> 			   jscriptVar = getNextVar(jscriptVar);
> +//
> +//                   results.append("	    this." + jscriptVar + " = new Array(\"" );
> +//
> 			   results.append( field.getKey() );
> +//
> 			   results.append( "\", \"" + message + "\", ");
> +//
> +//                   results.append("new Function (\"varName\", \"");
> +//
> +//                   Map hVars = field.getVars();
> +//                   // Loop through the field's variables.
> +//                   for (Iterator iVars = hVars.keySet().iterator();
> iVars.hasNext(); ) {
> +//                      String varKey = (String)iVars.next();
> +//                      Var var = (Var)hVars.get(varKey);
> +//                      String varValue = var.getValue();
> +//                      String jsType = var.getJsType();
> +//
> +//
>                if (Var.JSTYPE_INT.equalsIgnoreCase(jsType)) {
> +//
>                   results.append("this." + varKey + "=" +
> ValidatorUtil.replace(varValue, "\\", "\\\\") + "; ");
> +//
>                } else if (Var.JSTYPE_REGEXP.equalsIgnoreCase(jsType)) {
> +//
>                   results.append("this." + varKey + "=/" +
> ValidatorUtil.replace(varValue, "\\", "\\\\") + "/; ");
> +//
>                } else if (Var.JSTYPE_STRING.equalsIgnoreCase(jsType)) {
> +//
>                   results.append("this." + varKey + "='" +
> ValidatorUtil.replace(varValue, "\\", "\\\\") + "'; ");
> +//
>                // So everyone using the latest format doesn't need to change
> their xml files immediately.
> +//
>                } else if ("mask".equalsIgnoreCase(varKey)) {
> +//
>                   results.append("this." + varKey + "=/" +
> ValidatorUtil.replace(varValue, "\\", "\\\\") + "/; ");
> +//
>                } else {
> +//
>                   results.append("this." + varKey + "='" +
> ValidatorUtil.replace(varValue, "\\", "\\\\") + "'; ");
> +//
>                }
> +//                   }
> +//
> +//                   results.append(" return this[varName];\"));\n");
>                  }
>               }
>               results.append("	 } \n\n");
> @@ -444,12 +458,12 @@ public class JavascriptValidatorTag exte
>  
>         if (methodName == null || methodName.length() == 0)
>            sb.append("	 function validate" + name + "(form) {                               
>                                    \n");
> -       else              
> +       else
>            sb.append("	 function " + methodName + "(form) {                                 
>                                  \n");
>                           
>         sb.append("	      if (bCancel) \n");
>         sb.append("	 	return true; \n");
> -       sb.append("	      else \n");     
> +       sb.append("	      else \n");
>         
>         // Always return true if there aren't any Javascript validation methods
>         if (methods == null || methods.length() == 0) {
> @@ -489,12 +503,119 @@ public class JavascriptValidatorTag exte
>         sb.append("</SCRIPT>\n\n");
>         
>         return sb.toString();
> -    }    
> +    }
> +
> +
> /**
> +
>  * Hopefully creates correct parameter names for indexed fields
> +
>  */
> +
> protected void generateParameterNames( StringBuffer results,
> +
> 											 Field field, String message,
> +
> 											String jscriptVar )
> +
> 	throws JspException
> +
> {
> +
> 	jscriptVar = getNextVar(jscriptVar);
> +
> 	results.append("	    this." + jscriptVar + " = new Array(" );
> +
> 	
> +
> 	if( field.isIndexed() ) {
> +
> 		//Get the collection (worry about scope??)
> +
> 		Object collection = RequestUtils.lookup(pageContext,
> +
> 												field.getIteratorName(),
> +
> 												field.getIndexedListProperty(),
> +
> 												null );
> +
> 		if (collection == null) {
> +
> 			JspException e = new JspException(
> messages.getMessage("javascriptValidatorTag.collection"));
> +
> 			RequestUtils.saveException(pageContext, e);
> +
> 			throw e;
> +
> 		}
> +
> 		// Construct an iterator for this collection
> +
> 		Iterator iterator = null;
> +
> 		
> +
> 		if (collection.getClass().isArray()) {
> +
> 			int length = Array.getLength(collection);
> +
> 			ArrayList c = new ArrayList(length);
> +
> 			for (int i = 0; i < length; i++) {
> +
> 				c.add(Array.get(collection, i));
> +
> 			}
> +
> 			iterator = c.iterator();
> +
> 		} else if (collection instanceof Collection)
> +
> 			iterator = ((Collection) collection).iterator();
> +
> 		else if (collection instanceof Iterator)
> +
> 			iterator = (Iterator) collection;
> +
> 		else if (collection instanceof Map)
> +
> 			iterator = ((Map) collection).entrySet().iterator();
> +
> 		else if (collection instanceof Enumeration)
> +
> 			iterator = new IteratorAdapter((Enumeration)collection);
> +
> 		else {
> +
> 			JspException e = new JspException
> +
> 				(messages.getMessage("javascriptValidatorTag.iterator"));
> +
> 			RequestUtils.saveException(pageContext, e);
> +
> 			throw e;
> +
> 		}
> +
> 		
> +
> 		//And finally build the parameter names
> +
> 		for (int pos = 0; (iterator != null) && iterator.hasNext(); pos++) {
> +
> 			StringBuffer fieldName = new StringBuffer();
> +
> 			iterator.next();
> +
> 			
> +
> 			results.append( "new Array(\"" );
> +
> 			fieldName.append( field.getIndexedProperty() );
> +
> 			fieldName.append( "[" );
> +
> 			fieldName.append( pos );
> +
> 			fieldName.append( "]." );
> +
> 			fieldName.append( field.getKey() );
> +
> 			generateParameterName( results, field, message, fieldName.toString() );
> +
> 			
> +
> 			if( iterator.hasNext() ) results.append( ",\n" );
> +
> 		}
> +
> 		results.append( ")" );
> +
> 	}
> +
> 	else {
> +
> 		results.append( "\"" );
> +
> 		generateParameterName( results, field, message, field.getKey() );
> +
> 	}
> +
> 	
> +
> 	results.append( ";\n" );
> +
> }
> +
> /**
> +
>  * Hopefully creates correct parameter names for indexed fields
> +
>  */
> +
> protected static void generateParameterName( StringBuffer results,
> +
> 											 Field field, String message,
> +
> 											 String fieldName )
> +
> {
> +
> 	results.append( fieldName );
> +
> 	results.append( "\", \"" + message + "\", ");
> +
> 	results.append("new Function (\"varName\", \"");
> +
> 	
> +
> 	Map hVars = field.getVars();
> +
> 	// Loop through the field's variables.
> +
> 	for (Iterator iVars = hVars.keySet().iterator(); iVars.hasNext(); ) {
> +
> 		String varKey = (String)iVars.next();
> +
> 		Var var = (Var)hVars.get(varKey);
> +
> 		String varValue = var.getValue();
> +
> 		String jsType = var.getJsType();
> +
> 		
> +
> 		if (Var.JSTYPE_INT.equalsIgnoreCase(jsType)) {
> +
> 			results.append("this." + varKey + "=" + ValidatorUtil.replace(varValue, "\\",
> "\\\\") + "; ");
> +
> 		} else if (Var.JSTYPE_REGEXP.equalsIgnoreCase(jsType)) {
> +
> 			results.append("this." + varKey + "=/" + ValidatorUtil.replace(varValue, "\\",
> "\\\\") + "/; ");
> +
> 		} else if (Var.JSTYPE_STRING.equalsIgnoreCase(jsType)) {
> +
> 			results.append("this." + varKey + "='" + ValidatorUtil.replace(varValue, "\\",
> "\\\\") + "'; ");
> +
> 		// So everyone using the latest format doesn't need to change their xml files
> immediately.
> +
> 		} else if ("mask".equalsIgnoreCase(varKey)) {
> +
> 			results.append("this." + varKey + "=/" + ValidatorUtil.replace(varValue, "\\",
> "\\\\") + "/; ");
> +
> 		} else {
> +
> 			results.append("this." + varKey + "='" + ValidatorUtil.replace(varValue, "\\",
> "\\\\") + "'; ");
> +
> 		}
> +
> 	}
> +
> 	
> +
> 	results.append(" return this[varName];\"))");
> +
> }
>      /**
> -     * The value <code>null</code> will be returned at the end of the sequence.  
> +     * The value <code>null</code> will be returned at the end of the sequence.
>       * &nbsp;&nbsp;&nbsp; ex: "zz" will return <code>null</code>
> -    */ 
> -    private String getNextVar(String input) {
> +    */
> +    private static String getNextVar(String input) {
>         if (input == null) {
>            return "aa";
>         }
> @@ -528,7 +649,7 @@ public class JavascriptValidatorTag exte
>      /**
>       * Replaces a single character in a <code>String</code>
>      */
> -    private String replaceChar(String input, int pos, char c) {
> +    private static String replaceChar(String input, int pos, char c) {
>         if (pos == 0) {
>            return c + input.substring(pos, input.length());
>         } else if (pos == input.length()) {
> @@ -537,6 +658,9 @@ public class JavascriptValidatorTag exte
>            return input.substring(0, pos) + c + input.substring(pos,
> input.length() - 1);
>         }
>      }
> +
> +
> +
>  
>      
>  }
> Index: src/share/org/apache/struts/taglib/html/LocalStrings.properties
> ===================================================================
> RCS file:
> /home/cvspublic/jakarta-struts/src/share/org/apache/struts/taglib/html/LocalStrings.properties,v
> retrieving revision 1.14
> diff -u -3 -p -r1.14 LocalStrings.properties
> --- src/share/org/apache/struts/taglib/html/LocalStrings.properties	23 Feb 2002 07:10:30 -0000	1.14
> +++ src/share/org/apache/struts/taglib/html/LocalStrings.properties	3 May 2002 17:12:41 -0000
> @@ -23,7 +23,8 @@ imgTag.type=Object must be of type Map
>  includeTag.include=Error including page {0}: {1}
>  includeTag.lookup=Cannot find global forward named {0}
>  indexed.noEnclosingIterate=indexed=\"true\" is only valid within an enclosing
> iterate tag
> -iterateTag.iterator=Cannot create iterator for {0}
> +javascriptValidatorTag.iterator=Cannot create iterator for {0}
> +javascriptValidatorTag.collection=No collection found
>  linkTag.destination=You must specify exactly one of 'forward', 'href', or 'page'
>  linkTag.forward=Cannot locate global forwarding for {0}
>  linkTag.forwards=Cannot locate forwards mapping table

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://issues.apache.org/struts/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira