[ http://issues.apache.org/jira/browse/VALIDATOR-125?page=all ]

Niall Pemberton updated VALIDATOR-125:
--------------------------------------

    Component/s: Framework

> Validator extension to support extending forms and fields
> ---------------------------------------------------------
>
>                 Key: VALIDATOR-125
>                 URL: http://issues.apache.org/jira/browse/VALIDATOR-125
>             Project: Commons Validator
>          Issue Type: Improvement
>          Components: Framework
>         Environment: Operating System: other
> Platform: Other
>            Reporter: Tal Lev-Ami
>            Priority: Minor
>
> Problem:
> In large progject many fields need to be validated and the same field can 
> appear in multiple forms. This create "code" duplication when the field 
> definitions must be redeclared for each form. In some cases two forms are 
> almost
> identical with difference of a field or two. 
> Solution:
> 1. Add a new attribute to the form tag - extends. The form referenced in the
> extends attribute is considered the "super-form" of the new form. This is
> very similar to the way that a form in a formset with a specific locale can
> extend a form in the default formset. Locale search order is kept when
> searching the extended form.
> 2. Add a new attribute to the field tag - uses. The format of the attribute
> is <formname>.<fieldname> A field that specifies this attribute is replaced
> with the field called "fieldname" in the form called "formname". Locale
> search order is kept.
> Implementation:
> Extends the ValidationResources.processForms() to rebuild all the forms
> taking the uses and extend fields into account.
> Open Issues:
> How can error handling be performed inside the validator package (e.g. the
> form or field extended do not exist)?
> Patch (works but does not report errors):
> Index: src/share/org/apache/commons/validator/Field.java
> ===================================================================
> RCS file: /home/cvspublic/jakarta-
> commons/validator/src/share/org/apache/commons/validator/Field.java,v
> retrieving revision 1.5
> diff -u -r1.5 Field.java
> --- src/share/org/apache/commons/validator/Field.java 30 Mar 2002 04:33:17 -
> 0000  1.5
> +++ src/share/org/apache/commons/validator/Field.java 14 Oct 2002 17:36:50 -
> 0000
> @@ -102,6 +102,7 @@
>      protected String indexedListProperty = null;
>      protected String key = null;
>      protected String depends = null;
> +    protected String uses = null;
>      protected int page = 0;
>      protected int fieldOrder = 0;
>      
> @@ -414,6 +415,25 @@
>      public void setKey(String key) {
>         this.key = key;
>      }
> +
> +     /**
> +      * Returns the name of the field to use.
> +      * of this field.
> +      * @return String
> +      */
> +     public String getUses() {
> +             return uses;
> +     }
> +
> +     /**
> +      * Set the name of the field to use. All the attributes, args, vars, 
> etc.
> +      * will be taken from that field except the name of the property.
> +      * @param uses The field to use.
> +      */
> +     public void setUses(String uses) {
> +             this.uses = uses;
> +     }
> +
>      
>      /**
>       * If there is a value specified for the indexedProperty field then 
> @@ -625,6 +645,7 @@
>         results.append("\t\tdepends=             " + depends    + "\n");
>         results.append("\t\tpage=                " + page    + "\n");
>         results.append("\t\tfieldOrder=          " + fieldOrder    + "\n");
> +       results.append("\t\tuses=                " + uses    + "\n");
>  
>         if (hVars != null) {
>            results.append("\t\tVars:\n");
> @@ -640,5 +661,4 @@
>       
>         return results.toString();
>      }
> -    
>  }
> Index: src/share/org/apache/commons/validator/Form.java
> ===================================================================
> RCS file: /home/cvspublic/jakarta-
> commons/validator/src/share/org/apache/commons/validator/Form.java,v
> retrieving revision 1.3
> diff -u -r1.3 Form.java
> --- src/share/org/apache/commons/validator/Form.java  30 Mar 2002 04:33:17 -
> 0000  1.3
> +++ src/share/org/apache/commons/validator/Form.java  14 Oct 2002 17:36:49 -
> 0000
> @@ -86,6 +86,11 @@
>       * stored under.
>      */
>      protected String name = null;
> +    
> +    /**
> +     * The form this form extends
> +     */
> +    protected String extend = null;
>  
>      /**
>       * List of <code>Field</code>s.  Used to maintain 
> @@ -100,6 +105,7 @@
>      */
>      protected FastHashMap hFields = new FastHashMap();
>  
> +    
>      /**
>       * Gets the name/key of the set of validation rules.
>      */
> @@ -161,6 +167,10 @@
>         
>         results.append("Form: ");
>         results.append(name);
> +       if (extend != null) {
> +               results.append(" extends ");
> +               results.append(extend);
> +       }
>         results.append("\n");
>  
>         for (Iterator i = lFields.iterator(); i.hasNext(); ) {
> @@ -172,4 +182,21 @@
>         return results.toString();
>      }
>       
> +     /**
> +      * Returns the extended form.
> +      * @return String
> +      */
> +     public String getExtends() {
> +             return extend;
> +     }
> +
> +     /**
> +      * Sets the form to extend. All the attributes of the form that are not
> +      * specifically define in this form are imported.
> +      * @param extend The extended form
> +      */
> +     public void setExtends(String extend) {
> +             this.extend = extend;
> +     }
> +
>  }
> Index: src/share/org/apache/commons/validator/ValidatorResources.java
> ===================================================================
> RCS file: /home/cvspublic/jakarta-
> commons/validator/src/share/org/apache/commons/validator/ValidatorResources.java
> ,v
> retrieving revision 1.6
> diff -u -r1.6 ValidatorResources.java
> --- src/share/org/apache/commons/validator/ValidatorResources.java    30 Mar 
> 2002 04:33:17 -0000   1.6
> +++ src/share/org/apache/commons/validator/ValidatorResources.java    14 Oct 
> 2002 17:36:49 -0000
> @@ -112,6 +112,11 @@
>      * The default locale on our server.
>     */
>     protected static Locale defaultLocale = Locale.getDefault();
> +   
> +   /**
> +    * The maximum nesting depth for extends and uses
> +    */
> +   protected static int MAX_DEPTH = 30;
>  
>     /**
>      * Add a <code>FormSet</code> to this <code>ValidatorResources</code>
> @@ -305,15 +310,74 @@
>     }
>  
>     /**
> -    * <p>Process the <code>Form</code> objects.  This clones the 
> <code>Field</code>s 
> -    * that don't exist in a <code>FormSet</code> compared to the default 
> -    * <code>FormSet</code>.</p>
> +    * <p>Process the <code>Form</code> objects. This handles locale support 
> and
> +    * "extends" and "uses" support.<br/>Locale is supported by cloning the 
> +    * <code>Field</code>s that don't exist in a <code>FormSet</code> 
> compared 
> +    * to the default <code>FormSet</code>.<br/>Extends is supported by 
> +    * importing all the attributes of the extended form recusively.<br/>Uses 
> is 
> +    * supported by cloning the used field and overriding its property name.
> +    * </p>
>     */
>     public void processForms() {
>        //hFormSets.put(buildKey(fs), fs);
>        String defaultKey = defaultLocale.toString();
> +
> +       // First handle extends, it must be done before uses and locale are 
> +       // handled.
> +      for (Iterator i = hFormSets.keySet().iterator(); i.hasNext(); ) {
> +             String key = (String)i.next();
> +             FormSet fs = (FormSet)hFormSets.get(key);
> +        for (Iterator x = fs.getForms().keySet().iterator(); x.hasNext(); ) {
> +           String formKey = (String)x.next();
> +           Form form = (Form)fs.getForms().get(formKey);
> +         
> +                // If the form extends another form, create a new form that 
> is
> +                // a merge of this form and the exteded one.        
> +           if (form.getExtends() != null) {
> +                Form newForm = new Form();
> +            newForm.setName(form.getName());
> +               mergeFormExtends(fs, form, newForm);
> +                fs.addForm(newForm);
> +           }            
> +         }
> +       }         
> +
> +       // Handle uses
> +      for (Iterator i = hFormSets.keySet().iterator(); i.hasNext(); ) {
> +             String key = (String)i.next();
> +             FormSet fs = (FormSet)hFormSets.get(key);
> +        for (Iterator x = fs.getForms().keySet().iterator(); x.hasNext(); ) {
> +           String formKey = (String)x.next();
> +           Form form = (Form)fs.getForms().get(formKey);
> +
> +           Form newForm = new Form();
> +           newForm.setName(form.getName());
> +           
> +           for (Iterator fields = form.getFields().iterator(); fields.hasNext
> (); ) {
> +              Field field = (Field) fields.next();
> +              String fieldKey = field.getKey();
> +
> +              if (field.getUses() != null) {
> +                              Field usedField = getUsedField(fs, field);
> +                              if (usedField != null) { 
> +                                     usedField = (Field)usedField.clone();
> +                                     usedField.setProperty(field.getProperty
> ());
> +                                     // Key must be reset.
> +                                     usedField.setKey(field.getKey());
> +                    newForm.addField(usedField);
> +                              } else {
> +                                     //[:TODO:] How should error handling be 
> done?
> +                              }
> +              } else {
> +                      newForm.addField((Field)form.getFieldMap().get
> (fieldKey));                  
> +              }
> +           }
> +            
> +           fs.addForm(newForm);
> +         }
> +       }         
>        
> -      // Loop through FormSets
> +      // Handle Locale. Loop through FormSets
>        for (Iterator i = hFormSets.keySet().iterator(); i.hasNext(); ) {
>           String key = (String)i.next();
>           FormSet fs = (FormSet)hFormSets.get(key);
> @@ -335,17 +399,7 @@
>              // If they don't exist in the current locale's form, then clone 
> them.
>              Form defaultForm = get(defaultLocale, formKey);
>  
> -            for (Iterator defaultFields = 
> defaultForm.getFields().iterator(); 
> defaultFields.hasNext(); ) {
> -               Field defaultField = (Field)defaultFields.next();
> -               String fieldKey = defaultField.getKey();
> -
> -               if (form.getFieldMap().containsKey(fieldKey)) {
> -                  newForm.addField((Field)form.getFieldMap().get(fieldKey));
> -               } else {
> -                  Field field = getClosestLocaleField(fs, formKey, fieldKey);
> -                  newForm.addField((Field)field.clone());   
> -               }
> -            }
> +                     mergeForms(fs, defaultForm, form, newForm);
>              
>              fs.addForm(newForm);
>           }
> @@ -360,6 +414,89 @@
>           }
>        }
>   
> +   }
> +
> +   /** 
> +    * Merge the origForm with the form it extends into newForm
> +    */
> +   protected void mergeFormExtends(FormSet fs, Form origForm, Form newForm) {
> +       mergeFormExtends(fs, origForm, origForm, newForm, 0);
> +   }
> +
> +   /** 
> +    * Recursively merge currentForm and the form it extends with origForm 
> into
> +    * newForm.
> +    */
> +   private void mergeFormExtends(FormSet fs, Form currentForm, 
> +                                                               Form 
> origForm, Form newForm, int depth) {
> +       if (depth > MAX_DEPTH) {
> +             //[:TODO:] How should error handling be done?                   
>       
> +             return; 
> +       }                                                                     
> +      mergeForms(fs, currentForm, origForm, newForm);
> +      if (currentForm.getExtends() != null) {
> +              Form extendedForm = get(fs.getCountry(), fs.getLanguage(),
> +                               fs.getVariant(), currentForm.getExtends());
> +         if (extendedForm != null) {
> +            mergeFormExtends(fs, extendedForm, origForm, newForm, depth + 1);
> +         } else {
> +                     //[:TODO:] How should error handling be done?
> +              }
> +      }
> +   }
> +
> +   /**
> +    * Clone all the fields of baseForm that are not in origForm into newForm
> +    */
> +   protected void mergeForms(FormSet fs, Form baseForm, Form origForm, Form 
> newForm) {
> +       String baseFormKey = baseForm.getName();
> +       for (Iterator baseFields = baseForm.getFields().iterator(); 
> baseFields.hasNext(); ) {
> +          Field baseField = (Field)baseFields.next();
> +          String fieldKey = baseField.getKey();
> +
> +              // If the origForm already contained the field, clone is from 
> there
> +              // Otherwise take the closet field based on the locale from 
> the 
> +              // baseForm
> +          if (origForm.getFieldMap().containsKey(fieldKey)) {
> +             newForm.addField((Field)origForm.getFieldMap().get(fieldKey));
> +          } else {
> +             Field field = getClosestLocaleField(fs, baseFormKey, fieldKey);
> +             newForm.addField((Field)field.clone());   
> +          }
> +       }     
> +   }
> +
> +   /**
> +    * Parse the uses attribute of field the return the pointed field.
> +    * Done recursively incase the used field uses another field.
> +    */
> +   protected Field getUsedField(FormSet fs, Field field) {
> +      return getUsedField(fs, field, 0);
> +   }
> +
> +   /**
> +    * Parse the uses attribute of field the return the pointed field.
> +    * Done recursively incase the used field uses another field.
> +    */
> +   protected Field getUsedField(FormSet fs, Field field, int depth) {
> +       if (depth > MAX_DEPTH) {
> +             //[:TODO:] How should error handling be done?                   
>       
> +             return null;            
> +       }
> +       String uses = field.getUses();
> +       int sepIndex = uses.indexOf(".");
> +       String usedFormKey = uses.substring(0, sepIndex);
> +       String usedFieldKey = uses.substring(sepIndex + 1);
> +       Field usedField = getClosestLocaleField(fs, usedFormKey, 
> usedFieldKey);
> +       if (usedField == null) {
> +             //[:TODO:] How should error handling be done?                   
>       
> +             return null;
> +      }
> +       
> +       if (usedField.getUses() != null) {
> +             usedField = getUsedField(fs, usedField, depth + 1);
> +       }
> +       return usedField;
>     }
>  
>     /**
> Index: src/test/org/apache/commons/validator/validator-name-required.xml
> ===================================================================
> RCS file: /home/cvspublic/jakarta-
> commons/validator/src/test/org/apache/commons/validator/validator-name-
> required.xml,v
> retrieving revision 1.2
> diff -u -r1.2 validator-name-required.xml
> --- src/test/org/apache/commons/validator/validator-name-required.xml 13 Mar 
> 2002 05:39:32 -0000   1.2
> +++ src/test/org/apache/commons/validator/validator-name-required.xml 14 Oct 
> 2002 17:36:49 -0000
> @@ -6,15 +6,24 @@
>                   
> methodParams="java.lang.Object,org.apache.commons.validator.Field"/>
>     </global>
>     <formset>
> -      <form    name="nameForm">
> -         <field    property="firstName"
> -                depends="required">
> -                  <arg0 key="nameForm.firstname.displayname"/>
> -         </field>    
> +     <form name = "baseForm">
>           <field    property="lastName"
>                  depends="required">
>                    <arg0 key="nameForm.lastname.displayname"/>
>           </field>
> +     </form>
> +      <form    name="baseOtherForm">
> +         <field    property="firstName1"
> +                depends="required">
> +                  <arg0 key="nameForm.firstname.displayname"/>
> +         </field>    
> +      </form>
> +      <form    name="otherForm" extends="baseOtherForm">
> +      </form>
> +      <form    name="interForm" extends="baseForm">
> +      </form>
> +      <form    name="nameForm"  extends="interForm">
> +         <field property="firstName" uses="otherForm.firstName1"/>
>        </form>
>     </formset>   
>  </form-validation>

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

        

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to