FormSet.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.Collections;
  20. import java.util.HashMap;
  21. import java.util.Map;
  22. import java.util.Map.Entry;

  23. import org.apache.commons.logging.Log;
  24. import org.apache.commons.logging.LogFactory;

  25. /**
  26.  * Holds a set of <code>Form</code>s stored associated with a <code>Locale</code>
  27.  * based on the country, language, and variant specified. Instances of this
  28.  * class are configured with a &lt;formset&gt; xml element.
  29.  */
  30. public class FormSet implements Serializable {

  31.     private static final long serialVersionUID = -8936513232763306055L;

  32.     /**
  33.      * This is the type of <code>FormSet</code>s where no locale is specified.
  34.      */
  35.     protected final static int GLOBAL_FORMSET = 1;

  36.     /**
  37.      * This is the type of <code>FormSet</code>s where only language locale is
  38.      * specified.
  39.      */
  40.     protected final static int LANGUAGE_FORMSET = 2;

  41.     /**
  42.      * This is the type of <code>FormSet</code>s where only language and country
  43.      * locale are specified.
  44.      */
  45.     protected final static int COUNTRY_FORMSET = 3;

  46.     /**
  47.      * This is the type of <code>FormSet</code>s where full locale has been set.
  48.      */
  49.     protected final static int VARIANT_FORMSET = 4;

  50.     /** Logging */
  51.     private transient Log log = LogFactory.getLog(FormSet.class);

  52.     /**
  53.      * Whether or not the this <code>FormSet</code> was processed for replacing
  54.      * variables in strings with their values.
  55.      */
  56.     private boolean processed;

  57.     /** Language component of <code>Locale</code> (required). */
  58.     private String language;

  59.     /** Country component of <code>Locale</code> (optional). */
  60.     private String country;

  61.     /** Variant component of <code>Locale</code> (optional). */
  62.     private String variant;

  63.     /**
  64.      * A <code>Map</code> of <code>Form</code>s using the name field of the
  65.      * <code>Form</code> as the key.
  66.      */
  67.     private final Map<String, Form> forms = new HashMap<>();

  68.     /**
  69.      * A <code>Map</code> of <code>Constant</code>s using the name field of the
  70.      * <code>Constant</code> as the key.
  71.      */
  72.     private final Map<String, String> constants = new HashMap<>();

  73.     /**
  74.      * Flag indicating if this formSet has been merged with its parent (higher
  75.      * rank in Locale hierarchy).
  76.      */
  77.     private boolean merged;

  78.     /**
  79.      * Add a <code>Constant</code> to the locale level.
  80.      *
  81.      * @param name   The constant name
  82.      * @param value  The constant value
  83.      */
  84.     public void addConstant(final String name, final String value) {
  85.         if (constants.containsKey(name)) {
  86.             getLog().error("Constant '" + name + "' already exists in FormSet[" + this.displayKey() + "] - ignoring.");
  87.         } else {
  88.             constants.put(name, value);
  89.         }
  90.     }

  91.     /**
  92.      * Add a <code>Form</code> to the <code>FormSet</code>.
  93.      *
  94.      * @param f  The form
  95.      */
  96.     public void addForm(final Form f) {

  97.         final String formName = f.getName();
  98.         if (forms.containsKey(formName)) {
  99.             getLog().error("Form '" + formName + "' already exists in FormSet[" + this.displayKey() + "] - ignoring.");

  100.         } else {
  101.             forms.put(f.getName(), f);
  102.         }

  103.     }

  104.     /**
  105.      * Returns a string representation of the object's key.
  106.      *
  107.      * @return   A string representation of the key
  108.      */
  109.     public String displayKey() {
  110.         final StringBuilder results = new StringBuilder();
  111.         if (language != null && !language.isEmpty()) {
  112.             results.append("language=");
  113.             results.append(language);
  114.         }
  115.         if (country != null && !country.isEmpty()) {
  116.             if (results.length() > 0) {
  117.                 results.append(", ");
  118.             }
  119.             results.append("country=");
  120.             results.append(country);
  121.         }
  122.         if (variant != null && !variant.isEmpty()) {
  123.             if (results.length() > 0) {
  124.                 results.append(", ");
  125.             }
  126.             results.append("variant=");
  127.             results.append(variant);
  128.         }
  129.         if (results.length() == 0) {
  130.             results.append("default");
  131.         }

  132.         return results.toString();
  133.     }

  134.     /**
  135.      * Gets the equivalent of the country component of <code>Locale</code>.
  136.      *
  137.      * @return   The country value
  138.      */
  139.     public String getCountry() {
  140.         return country;
  141.     }

  142.     /**
  143.      * Retrieve a <code>Form</code> based on the form name.
  144.      *
  145.      * @param formName  The form name
  146.      * @return          The form
  147.      */
  148.     public Form getForm(final String formName) {
  149.         return this.forms.get(formName);
  150.     }

  151.     /**
  152.      * A <code>Map</code> of <code>Form</code>s is returned as an unmodifiable
  153.      * <code>Map</code> with the key based on the form name.
  154.      *
  155.      * @return   The forms map
  156.      */
  157.     public Map<String, Form> getForms() {
  158.         return Collections.unmodifiableMap(forms);
  159.     }

  160.     /**
  161.      * Gets the equivalent of the language component of <code>Locale</code>.
  162.      *
  163.      * @return   The language value
  164.      */
  165.     public String getLanguage() {
  166.         return language;
  167.     }

  168.     /**
  169.      * Accessor method for Log instance.
  170.      *
  171.      * The Log instance variable is transient and
  172.      * accessing it through this method ensures it
  173.      * is re-initialized when this instance is
  174.      * de-serialized.
  175.      *
  176.      * @return The Log instance.
  177.      */
  178.     private Log getLog() {
  179.         if (log == null) {
  180.             log = LogFactory.getLog(FormSet.class);
  181.         }
  182.         return log;
  183.     }

  184.     /**
  185.      * Returns the type of <code>FormSet</code>:<code>GLOBAL_FORMSET</code>,
  186.      * <code>LANGUAGE_FORMSET</code>,<code>COUNTRY_FORMSET</code> or <code>VARIANT_FORMSET</code>
  187.      * .
  188.      *
  189.      * @return                       The type value
  190.      * @since 1.2.0
  191.      * @throws NullPointerException  if there is inconsistency in the locale
  192.      *      definition (not sure about this)
  193.      */
  194.     protected int getType() {
  195.         if (getVariant() != null) {
  196.             if (getLanguage() == null || getCountry() == null) {
  197.                 throw new NullPointerException("When variant is specified, country and language must be specified.");
  198.             }
  199.             return VARIANT_FORMSET;
  200.         }
  201.         if (getCountry() != null) {
  202.             if (getLanguage() == null) {
  203.                 throw new NullPointerException("When country is specified, language must be specified.");
  204.             }
  205.             return COUNTRY_FORMSET;
  206.         }
  207.         if (getLanguage() != null) {
  208.             return LANGUAGE_FORMSET;
  209.         }
  210.         return GLOBAL_FORMSET;
  211.     }

  212.     /**
  213.      * Gets the equivalent of the variant component of <code>Locale</code>.
  214.      *
  215.      * @return   The variant value
  216.      */
  217.     public String getVariant() {
  218.         return variant;
  219.     }

  220.     /**
  221.      * Has this formSet been merged?
  222.      *
  223.      * @return   true if it has been merged
  224.      * @since 1.2.0
  225.      */
  226.     protected boolean isMerged() {
  227.         return merged;
  228.     }

  229.     /**
  230.      * Whether or not the this <code>FormSet</code> was processed for replacing
  231.      * variables in strings with their values.
  232.      *
  233.      * @return   The processed value
  234.      */
  235.     public boolean isProcessed() {
  236.         return processed;
  237.     }

  238.     /**
  239.      * Merges the given <code>FormSet</code> into this one. If any of <code>depends</code>
  240.      * s <code>Forms</code> are not in this <code>FormSet</code> then, include
  241.      * them, else merge both <code>Forms</code>. Theoretically we should only
  242.      * merge a "parent" formSet.
  243.      *
  244.      * @param depends  FormSet to be merged
  245.      * @since 1.2.0
  246.      */
  247.     protected void merge(final FormSet depends) {
  248.         if (depends != null) {
  249.             final Map<String, Form> pForms = getForms();
  250.             final Map<String, Form> dForms = depends.getForms();
  251.             for (final Entry<String, Form> entry : dForms.entrySet()) {
  252.                 final String key = entry.getKey();
  253.                 final Form pForm = pForms.get(key);
  254.                 if (pForm != null) { // merge, but principal 'rules', don't overwrite
  255.                     // anything
  256.                     pForm.merge(entry.getValue());
  257.                 } else { // just add
  258.                     addForm(entry.getValue());
  259.                 }
  260.             }
  261.         }
  262.         merged = true;
  263.     }

  264.     /**
  265.      * Processes all of the <code>Form</code>s.
  266.      *
  267.      * @param globalConstants  Global constants
  268.      */
  269.     synchronized void process(final Map<String, String> globalConstants) {
  270.         for (final Form f : forms.values()) {
  271.             f.process(globalConstants, constants, forms);
  272.         }

  273.         processed = true;
  274.     }

  275.     /**
  276.      * Sets the equivalent of the country component of <code>Locale</code>.
  277.      *
  278.      * @param country  The new country value
  279.      */
  280.     public void setCountry(final String country) {
  281.         this.country = country;
  282.     }

  283.     /**
  284.      * Sets the equivalent of the language component of <code>Locale</code>.
  285.      *
  286.      * @param language  The new language value
  287.      */
  288.     public void setLanguage(final String language) {
  289.         this.language = language;
  290.     }

  291.     /**
  292.      * Sets the equivalent of the variant component of <code>Locale</code>.
  293.      *
  294.      * @param variant  The new variant value
  295.      */
  296.     public void setVariant(final String variant) {
  297.         this.variant = variant;
  298.     }

  299.     /**
  300.      * Returns a string representation of the object.
  301.      *
  302.      * @return   A string representation
  303.      */
  304.     @Override
  305.     public String toString() {
  306.         final StringBuilder results = new StringBuilder();

  307.         results.append("FormSet: language=");
  308.         results.append(language);
  309.         results.append("  country=");
  310.         results.append(country);
  311.         results.append("  variant=");
  312.         results.append(variant);
  313.         results.append("\n");

  314.         for (final Object name : getForms().values()) {
  315.             results.append("   ");
  316.             results.append(name);
  317.             results.append("\n");
  318.         }

  319.         return results.toString();
  320.     }
  321. }