Uploaded image for project: 'Commons Validator'
  1. Commons Validator
  2. VALIDATOR-125

Validator extension to support extending forms and fields

    XMLWordPrintableJSON

Details

    • Improvement
    • Status: Closed
    • Minor
    • Resolution: Duplicate
    • None
    • None
    • Framework
    • None
    • Operating System: other
      Platform: Other

    • 13612

    Description

      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(); )
        Unknown macro: {+ 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)

        Unknown macro: {+ 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>

      Attachments

        Issue Links

          Activity

            People

              Unassigned Unassigned
              tla@trivnet.com Tal Lev-Ami
              Votes:
              1 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: