You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by "Niall Pemberton (JIRA)" <ji...@apache.org> on 2006/07/19 15:31:30 UTC
[jira] Reopened: (VALIDATOR-125) Validator extension to support
extending forms and fields
[ http://issues.apache.org/jira/browse/VALIDATOR-125?page=all ]
Niall Pemberton reopened VALIDATOR-125:
---------------------------------------
> 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
> 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: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org