Form.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.validator;

  18. import java.io.Serializable;
  19. import java.util.ArrayList;
  20. import java.util.Collections;
  21. import java.util.Iterator;
  22. import java.util.List;
  23. import java.util.Map;

  24. import org.apache.commons.collections.FastHashMap; // DEPRECATED

  25. /**
  26.  * <p>
  27.  * This contains a set of validation rules for a form/JavaBean. The information
  28.  * is contained in a list of <code>Field</code> objects. Instances of this class
  29.  * are configured with a &lt;form&gt; xml element.
  30.  * </p>
  31.  * <p>
  32.  * The use of FastHashMap is deprecated and will be replaced in a future
  33.  * release.
  34.  * </p>
  35.  */
  36. //TODO mutable non-private fields
  37. public class Form implements Serializable {

  38.     private static final long serialVersionUID = 6445211789563796371L;

  39.     /** The name/key the set of validation rules is stored under. */
  40.     protected String name;

  41.     /**
  42.      * List of <code>Field</code>s. Used to maintain the order they were added
  43.      * in although individual <code>Field</code>s can be retrieved using <code>Map</code>
  44.      * of <code>Field</code>s.
  45.      */
  46.     protected List<Field> lFields = new ArrayList<>();

  47.     /**
  48.      * Map of <code>Field</code>s keyed on their property value.
  49.      *
  50.      * @deprecated   Subclasses should use getFieldMap() instead.
  51.      */
  52.     @Deprecated
  53.     protected FastHashMap hFields = new FastHashMap(); // <String, Field>

  54.     /**
  55.      * The name/key of the form which this form extends from.
  56.      *
  57.      * @since 1.2.0
  58.      */
  59.     protected String inherit;

  60.     /**
  61.      * Whether or not the this <code>Form</code> was processed for replacing
  62.      * variables in strings with their values.
  63.      */
  64.     private boolean processed;

  65.     /**
  66.      * Add a <code>Field</code> to the <code>Form</code>.
  67.      *
  68.      * @param f  The field
  69.      */
  70.     public void addField(final Field f) {
  71.         this.lFields.add(f);
  72.         getFieldMap().put(f.getKey(), f);
  73.     }

  74.     /**
  75.      * Returns true if this Form contains a Field with the given name.
  76.      *
  77.      * @param fieldName  The field name
  78.      * @return           True if this form contains the field by the given name
  79.      * @since 1.1
  80.      */
  81.     public boolean containsField(final String fieldName) {
  82.         return getFieldMap().containsKey(fieldName);
  83.     }

  84.     /**
  85.      * Gets the name/key of the parent set of validation rules.
  86.      *
  87.      * @return   The extends value
  88.      * @since 1.2.0
  89.      */
  90.     public String getExtends() {
  91.         return inherit;
  92.     }

  93.     /**
  94.      * Returns the Field with the given name or null if this Form has no such
  95.      * field.
  96.      *
  97.      * @param fieldName  The field name
  98.      * @return           The field value
  99.      * @since 1.1
  100.      */
  101.     public Field getField(final String fieldName) {
  102.         return getFieldMap().get(fieldName);
  103.     }

  104.     /**
  105.      * Returns a Map of String field keys to Field objects.
  106.      *
  107.      * @return   The fieldMap value
  108.      * @since 1.2.0
  109.      */
  110.     @SuppressWarnings("unchecked") // FastHashMap is not generic
  111.     protected Map<String, Field> getFieldMap() {
  112.         return hFields;
  113.     }

  114.     /**
  115.      * A <code>List</code> of <code>Field</code>s is returned as an unmodifiable
  116.      * <code>List</code>.
  117.      *
  118.      * @return   The fields value
  119.      */
  120.     public List<Field> getFields() {
  121.         return Collections.unmodifiableList(lFields);
  122.     }

  123.     /**
  124.      * Gets the name/key of the set of validation rules.
  125.      *
  126.      * @return   The name value
  127.      */
  128.     public String getName() {
  129.         return name;
  130.     }

  131.     /**
  132.      * Gets extends flag.
  133.      *
  134.      * @return   The extending value
  135.      * @since 1.2.0
  136.      */
  137.     public boolean isExtending() {
  138.         return inherit != null;
  139.     }

  140.     /**
  141.      * Whether or not the this <code>Form</code> was processed for replacing
  142.      * variables in strings with their values.
  143.      *
  144.      * @return   The processed value
  145.      * @since 1.2.0
  146.      */
  147.     public boolean isProcessed() {
  148.         return processed;
  149.     }

  150.     /**
  151.      * Merges the given form into this one. For any field in <code>depends</code>
  152.      * not present in this form, include it. <code>depends</code> has precedence
  153.      * in the way the fields are ordered.
  154.      *
  155.      * @param depends  the form we want to merge
  156.      * @since 1.2.0
  157.      */
  158.     protected void merge(final Form depends) {

  159.         final List<Field> templFields = new ArrayList<>();
  160.         @SuppressWarnings("unchecked") // FastHashMap is not generic
  161.         final
  162.         Map<String, Field> temphFields = new FastHashMap();
  163.         for (final Field defaultField : depends.getFields()) {
  164.             if (defaultField != null) {
  165.                 final String fieldKey = defaultField.getKey();
  166.                 if (!this.containsField(fieldKey)) {
  167.                     templFields.add(defaultField);
  168.                     temphFields.put(fieldKey, defaultField);
  169.                 }
  170.                 else {
  171.                     final Field old = getField(fieldKey);
  172.                     getFieldMap().remove(fieldKey);
  173.                     lFields.remove(old);
  174.                     templFields.add(old);
  175.                     temphFields.put(fieldKey, old);
  176.                 }
  177.             }
  178.         }
  179.         lFields.addAll(0, templFields);
  180.         getFieldMap().putAll(temphFields);
  181.     }

  182.     /**
  183.      * Processes all of the <code>Form</code>'s <code>Field</code>s.
  184.      *
  185.      * @param globalConstants  A map of global constants
  186.      * @param constants        Local constants
  187.      * @param forms            Map of forms
  188.      * @since 1.2.0
  189.      */
  190.     protected void process(final Map<String, String> globalConstants, final Map<String, String> constants, final Map<String, Form> forms) {
  191.         if (isProcessed()) {
  192.             return;
  193.         }

  194.         int n = 0; //we want the fields from its parent first
  195.         if (isExtending()) {
  196.             final Form parent = forms.get(inherit);
  197.             if (parent != null) {
  198.                 if (!parent.isProcessed()) {
  199.                     // we want to go all the way up the tree
  200.                     parent.process(constants, globalConstants, forms);
  201.                 }
  202.                 for (final Field f : parent.getFields()) {
  203.                     // we want to be able to override any fields we like
  204.                     if (getFieldMap().get(f.getKey()) == null) {
  205.                         lFields.add(n, f);
  206.                         getFieldMap().put(f.getKey(), f);
  207.                         n++;
  208.                     }
  209.                 }
  210.             }
  211.         }
  212.         hFields.setFast(true);
  213.         // no need to reprocess parent's fields, we iterate from 'n'
  214.         for (final Iterator<Field> i = lFields.listIterator(n); i.hasNext(); ) {
  215.             final Field f = i.next();
  216.             f.process(globalConstants, constants);
  217.         }

  218.         processed = true;
  219.     }

  220.     /**
  221.      * Sets the name/key of the parent set of validation rules.
  222.      *
  223.      * @param inherit  The new extends value
  224.      * @since 1.2.0
  225.      */
  226.     public void setExtends(final String inherit) {
  227.         this.inherit = inherit;
  228.     }

  229.     /**
  230.      * Sets the name/key of the set of validation rules.
  231.      *
  232.      * @param name  The new name value
  233.      */
  234.     public void setName(final String name) {
  235.         this.name = name;
  236.     }

  237.     /**
  238.      * Returns a string representation of the object.
  239.      *
  240.      * @return string representation
  241.      */
  242.     @Override
  243.     public String toString() {
  244.         final StringBuilder results = new StringBuilder();

  245.         results.append("Form: ");
  246.         results.append(name);
  247.         results.append("\n");

  248.         for (final Field lField : lFields) {
  249.             results.append("\tField: \n");
  250.             results.append(lField);
  251.             results.append("\n");
  252.         }

  253.         return results.toString();
  254.     }

  255.     /**
  256.      * Validate all Fields in this Form on the given page and below.
  257.      *
  258.      * @param params               A Map of parameter class names to parameter
  259.      *      values to pass into validation methods.
  260.      * @param actions              A Map of validator names to ValidatorAction
  261.      *      objects.
  262.      * @param page                 Fields on pages higher than this will not be
  263.      *      validated.
  264.      * @return                     A ValidatorResults object containing all
  265.      *      validation messages.
  266.      * @throws ValidatorException
  267.      */
  268.     ValidatorResults validate(final Map<String, Object> params, final Map<String, ValidatorAction> actions, final int page)
  269.         throws ValidatorException {
  270.         return validate(params, actions, page, null);
  271.     }

  272.     /**
  273.      * Validate all Fields in this Form on the given page and below.
  274.      *
  275.      * @param params               A Map of parameter class names to parameter
  276.      *      values to pass into validation methods.
  277.      * @param actions              A Map of validator names to ValidatorAction
  278.      *      objects.
  279.      * @param page                 Fields on pages higher than this will not be
  280.      *      validated.
  281.      * @return                     A ValidatorResults object containing all
  282.      *      validation messages.
  283.      * @throws ValidatorException
  284.      * @since 1.2.0
  285.      */
  286.     ValidatorResults validate(final Map<String, Object> params, final Map<String, ValidatorAction> actions, final int page, final String fieldName)
  287.             throws ValidatorException {
  288.         final ValidatorResults results = new ValidatorResults();
  289.         params.put(Validator.VALIDATOR_RESULTS_PARAM, results);

  290.         // Only validate a single field if specified
  291.         if (fieldName != null) {
  292.             final Field field = getFieldMap().get(fieldName);

  293.             if (field == null) {
  294.                 throw new ValidatorException("Unknown field " + fieldName + " in form " + getName());
  295.             }
  296.             params.put(Validator.FIELD_PARAM, field);

  297.             if (field.getPage() <= page) {
  298.                 results.merge(field.validate(params, actions));
  299.             }
  300.         } else {
  301.             for (final Field field : this.lFields) {

  302.                 params.put(Validator.FIELD_PARAM, field);

  303.                 if (field.getPage() <= page) {
  304.                     results.merge(field.validate(params, actions));
  305.                 }
  306.             }
  307.         }

  308.         return results;
  309.     }
  310. }