commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bugzi...@apache.org
Subject DO NOT REPLY [Bug 13612] New: - Validator extension to support extending forms and fields
Date Mon, 14 Oct 2002 17:42:31 GMT
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=13612>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://nagoya.apache.org/bugzilla/show_bug.cgi?id=13612

Validator extension to support extending forms and fields

           Summary: Validator extension to support extending forms and
                    fields
           Product: Commons
           Version: unspecified
          Platform: Other
        OS/Version: Other
            Status: NEW
          Severity: Enhancement
          Priority: Other
         Component: Validator
        AssignedTo: commons-dev@jakarta.apache.org
        ReportedBy: tla@trivnet.com


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>

--
To unsubscribe, e-mail:   <mailto:commons-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:commons-dev-help@jakarta.apache.org>


Mime
View raw message