Return-Path: Delivered-To: apmail-jakarta-commons-dev-archive@www.apache.org Received: (qmail 1705 invoked from network); 23 Nov 2006 00:11:28 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 23 Nov 2006 00:11:27 -0000 Received: (qmail 22331 invoked by uid 500); 23 Nov 2006 00:11:35 -0000 Delivered-To: apmail-jakarta-commons-dev-archive@jakarta.apache.org Received: (qmail 22252 invoked by uid 500); 23 Nov 2006 00:11:34 -0000 Mailing-List: contact commons-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Help: List-Post: List-Id: "Jakarta Commons Developers List" Reply-To: "Jakarta Commons Developers List" Delivered-To: mailing list commons-dev@jakarta.apache.org Received: (qmail 22241 invoked by uid 99); 23 Nov 2006 00:11:34 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 22 Nov 2006 16:11:34 -0800 X-ASF-Spam-Status: No, hits=0.0 required=10.0 tests= X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO brutus.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 22 Nov 2006 16:11:24 -0800 Received: from brutus (localhost [127.0.0.1]) by brutus.apache.org (Postfix) with ESMTP id E35D47142C3 for ; Wed, 22 Nov 2006 16:11:03 -0800 (PST) Message-ID: <5459868.1164240663928.JavaMail.jira@brutus> Date: Wed, 22 Nov 2006 16:11:03 -0800 (PST) From: "Niall Pemberton (JIRA)" To: commons-dev@jakarta.apache.org Subject: [jira] Resolved: (VALIDATOR-125) Validator extension to support extending forms and fields MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-Virus-Checked: Checked by ClamAV on apache.org [ http://issues.apache.org/jira/browse/VALIDATOR-125?page=all ] Niall Pemberton resolved VALIDATOR-125. --------------------------------------- Resolution: Duplicate > 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 . 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 Fields. 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 FormSet to this ValidatorResources > @@ -305,15 +310,74 @@ > } > > /** > - *

Process the Form objects. This clones the > Fields > - * that don't exist in a FormSet compared to the default > - * FormSet.

> + *

Process the Form objects. This handles locale support and > + * "extends" and "uses" support.
Locale is supported by cloning the > + * Fields that don't exist in a FormSet compared > + * to the default FormSet.
Extends is supported by > + * importing all the attributes of the extended form recusively.
Uses > is > + * supported by cloning the used field and overriding its property name. > + *

> */ > 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"/> > > > -
> - - depends="required"> > - > - > + > depends="required"> > > > +
> +
> + + depends="required"> > + > + > +
> +
> +
> +
> +
> +
> + > >
> -- 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: commons-dev-unsubscribe@jakarta.apache.org For additional commands, e-mail: commons-dev-help@jakarta.apache.org