Coverage report

  %line %branch
org.apache.commons.validator.ValidatorResources$1
9% 
50% 

 1  
 /*
 2  
  * $Id: ValidatorResources.java 386637 2006-03-17 13:22:26Z niallp $
 3  
  * $Rev: 386637 $
 4  
  * $Date: 2006-03-17 13:22:26 +0000 (Fri, 17 Mar 2006) $
 5  
  *
 6  
  * ====================================================================
 7  
  * Copyright 2001-2006 The Apache Software Foundation
 8  
  *
 9  
  * Licensed under the Apache License, Version 2.0 (the "License");
 10  
  * you may not use this file except in compliance with the License.
 11  
  * You may obtain a copy of the License at
 12  
  *
 13  
  *     http://www.apache.org/licenses/LICENSE-2.0
 14  
  *
 15  
  * Unless required by applicable law or agreed to in writing, software
 16  
  * distributed under the License is distributed on an "AS IS" BASIS,
 17  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 18  
  * See the License for the specific language governing permissions and
 19  
  * limitations under the License.
 20  
  */
 21  
 
 22  
 package org.apache.commons.validator;
 23  
 
 24  
 import java.io.IOException;
 25  
 import java.io.InputStream;
 26  
 import java.io.Serializable;
 27  
 import java.net.URL;
 28  
 import java.util.Collections;
 29  
 import java.util.Iterator;
 30  
 import java.util.Locale;
 31  
 import java.util.Map;
 32  
 
 33  
 import org.apache.commons.collections.FastHashMap;
 34  
 import org.apache.commons.digester.Digester;
 35  
 import org.apache.commons.digester.Rule;
 36  
 import org.apache.commons.digester.xmlrules.DigesterLoader;
 37  
 import org.apache.commons.logging.Log;
 38  
 import org.apache.commons.logging.LogFactory;
 39  
 import org.xml.sax.SAXException;
 40  
 import org.xml.sax.Attributes;
 41  
 
 42  
 /**
 43  
  * <p>
 44  
  * General purpose class for storing <code>FormSet</code> objects based
 45  
  * on their associated <code>Locale</code>.  Instances of this class are usually
 46  
  * configured through a validation.xml file that is parsed in a constructor.
 47  
  * </p>
 48  
  *
 49  
  * <p><strong>Note</strong> - Classes that extend this class
 50  
  * must be Serializable so that instances may be used in distributable
 51  
  * application server environments.</p>
 52  
  *
 53  
  * <p>
 54  
  * The use of FastHashMap is deprecated and will be replaced in a future
 55  
  * release.
 56  
  * </p>
 57  
  */
 58  
 public class ValidatorResources implements Serializable {
 59  
 
 60  
     /**
 61  
      * The set of public identifiers, and corresponding resource names, for
 62  
      * the versions of the configuration file DTDs that we know about.  There
 63  
      * <strong>MUST</strong> be an even number of Strings in this list!
 64  
      */
 65  
     private static final String REGISTRATIONS[] = {
 66  
         "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN",
 67  
         "/org/apache/commons/validator/resources/validator_1_0.dtd",
 68  
         "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0.1//EN",
 69  
         "/org/apache/commons/validator/resources/validator_1_0_1.dtd",
 70  
         "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1//EN",
 71  
         "/org/apache/commons/validator/resources/validator_1_1.dtd",
 72  
         "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN",
 73  
         "/org/apache/commons/validator/resources/validator_1_1_3.dtd",
 74  
         "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.2.0//EN",
 75  
         "/org/apache/commons/validator/resources/validator_1_2_0.dtd",
 76  
         "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.3.0//EN",
 77  
         "/org/apache/commons/validator/resources/validator_1_3_0.dtd"
 78  
     };
 79  
 
 80  
     private transient Log log = LogFactory.getLog(ValidatorResources.class);
 81  
 
 82  
     /**
 83  
      * <code>Map</code> of <code>FormSet</code>s stored under
 84  
      * a <code>Locale</code> key.
 85  
      * @deprecated Subclasses should use getFormSets() instead.
 86  
      */
 87  
     protected FastHashMap hFormSets = new FastHashMap();
 88  
 
 89  
     /**
 90  
      * <code>Map</code> of global constant values with
 91  
      * the name of the constant as the key.
 92  
      * @deprecated Subclasses should use getConstants() instead.
 93  
      */
 94  
     protected FastHashMap hConstants = new FastHashMap();
 95  
 
 96  
     /**
 97  
      * <code>Map</code> of <code>ValidatorAction</code>s with
 98  
      * the name of the <code>ValidatorAction</code> as the key.
 99  
      * @deprecated Subclasses should use getActions() instead.
 100  
      */
 101  
     protected FastHashMap hActions = new FastHashMap();
 102  
 
 103  
     /**
 104  
      * The default locale on our server.
 105  
      */
 106  
     protected static Locale defaultLocale = Locale.getDefault();
 107  
 
 108  
     /**
 109  
      * Create an empty ValidatorResources object.
 110  
      */
 111  
     public ValidatorResources() {
 112  
         super();
 113  
     }
 114  
     
 115  
     /**
 116  
      * This is the default <code>FormSet</code> (without locale). (We probably don't need
 117  
      * the defaultLocale anymore.)
 118  
      */
 119  
     protected FormSet defaultFormSet;
 120  
     
 121  
     /**
 122  
      * Create a ValidatorResources object from an InputStream.
 123  
      *
 124  
      * @param in InputStream to a validation.xml configuration file.  It's the client's
 125  
      * responsibility to close this stream.
 126  
      * @throws IOException
 127  
      * @throws SAXException if the validation XML files are not valid or well
 128  
      * formed.
 129  
      * @throws IOException  if an I/O error occurs processing the XML files
 130  
      * @since Validator 1.1
 131  
      */
 132  
     public ValidatorResources(InputStream in) throws IOException, SAXException {
 133  
         this(new InputStream[]{in});
 134  
     }
 135  
 
 136  
     /**
 137  
      * Create a ValidatorResources object from an InputStream.
 138  
      *
 139  
      * @param streams An array of InputStreams to several validation.xml
 140  
      * configuration files that will be read in order and merged into this object.
 141  
      * It's the client's responsibility to close these streams.
 142  
      * @throws IOException
 143  
      * @throws SAXException if the validation XML files are not valid or well
 144  
      * formed.
 145  
      * @throws IOException  if an I/O error occurs processing the XML files
 146  
      * @since Validator 1.1
 147  
      */
 148  
     public ValidatorResources(InputStream[] streams)
 149  
             throws IOException, SAXException {
 150  
 
 151  
         super();
 152  
 
 153  
         Digester digester = initDigester();
 154  
         for (int i = 0; i < streams.length; i++) {
 155  
             digester.push(this);
 156  
             digester.parse(streams[i]);
 157  
         }
 158  
 
 159  
         this.process();
 160  
     }
 161  
     
 162  
     /**
 163  
      * Create a ValidatorResources object from an uri
 164  
      *
 165  
      * @param uri The location of a validation.xml configuration file. 
 166  
      * @throws IOException
 167  
      * @throws SAXException if the validation XML files are not valid or well
 168  
      * formed.
 169  
      * @throws IOException  if an I/O error occurs processing the XML files
 170  
      * @since Validator 1.2
 171  
      */
 172  
     public ValidatorResources(String uri) throws IOException, SAXException {
 173  
         this(new String[]{uri});
 174  
     }
 175  
 
 176  
     /**
 177  
      * Create a ValidatorResources object from several uris
 178  
      *
 179  
      * @param uris An array of uris to several validation.xml
 180  
      * configuration files that will be read in order and merged into this object.
 181  
      * @throws IOException
 182  
      * @throws SAXException if the validation XML files are not valid or well
 183  
      * formed.
 184  
      * @throws IOException  if an I/O error occurs processing the XML files
 185  
      * @since Validator 1.2
 186  
      */
 187  
     public ValidatorResources(String[] uris)
 188  
             throws IOException, SAXException {
 189  
 
 190  
         super();
 191  
 
 192  
         Digester digester = initDigester();
 193  
         for (int i = 0; i < uris.length; i++) {
 194  
             digester.push(this);
 195  
             digester.parse(uris[i]);
 196  
         }
 197  
 
 198  
         this.process();
 199  
     }    
 200  
     
 201  
     /**
 202  
      *  Initialize the digester.
 203  
      */
 204  
     private Digester initDigester() {
 205  
         URL rulesUrl = this.getClass().getResource("digester-rules.xml");
 206  
         Digester digester = DigesterLoader.createDigester(rulesUrl);
 207  
         digester.setNamespaceAware(true);
 208  
         digester.setValidating(true);
 209  
         digester.setUseContextClassLoader(true);
 210  
 
 211  
         // Add rules for arg0-arg3 elements
 212  
         addOldArgRules(digester);
 213  
 
 214  
         // register DTDs
 215  
         for (int i = 0; i < REGISTRATIONS.length; i += 2) {
 216  
             URL url = this.getClass().getResource(REGISTRATIONS[i + 1]);
 217  
             if (url != null) {
 218  
                 digester.register(REGISTRATIONS[i], url.toString());
 219  
             }
 220  
         }
 221  
         return digester;
 222  
     }
 223  
 
 224  
     private static final String ARGS_PATTERN 
 225  
                = "form-validation/formset/form/field/arg";
 226  
 
 227  
     /**
 228  
      * Create a <code>Rule</code> to handle <code>arg0-arg3</code>
 229  
      * elements. This will allow validation.xml files that use the
 230  
      * versions of the DTD prior to Validator 1.2.0 to continue
 231  
      * working.
 232  
      */
 233  
     private void addOldArgRules(Digester digester) {
 234  
 
 235  
         // Create a new rule to process args elements
 236  
         Rule rule = new Rule() {
 237  94
             public void begin(String namespace, String name, 
 238  
                                Attributes attributes) throws Exception {
 239  
                 // Create the Arg
 240  0
                 Arg arg = new Arg();
 241  0
                 arg.setKey(attributes.getValue("key"));
 242  0
                 arg.setName(attributes.getValue("name"));
 243  0
                 if ("false".equalsIgnoreCase(attributes.getValue("resource"))) {
 244  0
                     arg.setResource(false);
 245  
                 }
 246  
                 try {
 247  0
                     arg.setPosition(Integer.parseInt(name.substring(3)));
 248  0
                 } catch (Exception ex) {
 249  0
                     getLog().error("Error parsing Arg position: " 
 250  
                                + name + " " + arg + " " + ex);
 251  
                 }
 252  
 
 253  
                 // Add the arg to the parent field
 254  0
                 ((Field)getDigester().peek(0)).addArg(arg);
 255  0
             }
 256  
         };
 257  
 
 258  
         // Add the rule for each of the arg elements
 259  
         digester.addRule(ARGS_PATTERN + "0", rule);
 260  
         digester.addRule(ARGS_PATTERN + "1", rule);
 261  
         digester.addRule(ARGS_PATTERN + "2", rule);
 262  
         digester.addRule(ARGS_PATTERN + "3", rule);
 263  
 
 264  
     }
 265  
 
 266  
     /**
 267  
      * Add a <code>FormSet</code> to this <code>ValidatorResources</code>
 268  
      * object.  It will be associated with the <code>Locale</code> of the
 269  
      * <code>FormSet</code>.
 270  
      * @param fs The form set to add.
 271  
      * @since Validator 1.1
 272  
      */
 273  
     public void addFormSet(FormSet fs) {
 274  
         String key = this.buildKey(fs);
 275  
         if (key.length() == 0) {// there can only be one default formset
 276  
             if (getLog().isWarnEnabled() && defaultFormSet != null) {
 277  
                 // warn the user he might not get the expected results
 278  
                 getLog().warn("Overriding default FormSet definition.");
 279  
             }
 280  
             defaultFormSet = fs;
 281  
         } else {
 282  
             FormSet formset = (FormSet) hFormSets.get(key);
 283  
             if (formset == null) {// it hasn't been included yet
 284  
                 if (getLog().isDebugEnabled()) {
 285  
                     getLog().debug("Adding FormSet '" + fs.toString() + "'.");
 286  
                 }
 287  
             } else if (getLog().isWarnEnabled()) {// warn the user he might not
 288  
                                                 // get the expected results
 289  
                 getLog()
 290  
                         .warn("Overriding FormSet definition. Duplicate for locale: "
 291  
                                 + key);
 292  
             }
 293  
             hFormSets.put(key, fs);
 294  
         }
 295  
     }
 296  
 
 297  
     /**
 298  
      * Add a global constant to the resource.
 299  
      * @param name The constant name.
 300  
      * @param value The constant value.
 301  
      */
 302  
     public void addConstant(String name, String value) {
 303  
         if (getLog().isDebugEnabled()) {
 304  
             getLog().debug("Adding Global Constant: " + name + "," + value);
 305  
         }
 306  
 
 307  
         this.hConstants.put(name, value);
 308  
     }
 309  
 
 310  
     /**
 311  
      * Add a <code>ValidatorAction</code> to the resource.  It also creates an
 312  
      * instance of the class based on the <code>ValidatorAction</code>s
 313  
      * classname and retrieves the <code>Method</code> instance and sets them
 314  
      * in the <code>ValidatorAction</code>.
 315  
      * @param va The validator action.
 316  
      */
 317  
     public void addValidatorAction(ValidatorAction va) {
 318  
         va.init();
 319  
 
 320  
         this.hActions.put(va.getName(), va);
 321  
 
 322  
         if (getLog().isDebugEnabled()) {
 323  
             getLog().debug("Add ValidatorAction: " + va.getName() + "," + va.getClassname());
 324  
         }
 325  
     }
 326  
 
 327  
     /**
 328  
      * Get a <code>ValidatorAction</code> based on it's name.
 329  
      * @param key The validator action key.
 330  
      * @return The validator action.
 331  
      */
 332  
     public ValidatorAction getValidatorAction(String key) {
 333  
         return (ValidatorAction) hActions.get(key);
 334  
     }
 335  
 
 336  
     /**
 337  
      * Get an unmodifiable <code>Map</code> of the <code>ValidatorAction</code>s.
 338  
      * @return Map of validator actions.
 339  
      */
 340  
     public Map getValidatorActions() {
 341  
         return Collections.unmodifiableMap(hActions);
 342  
     }
 343  
 
 344  
     /**
 345  
      * Builds a key to store the <code>FormSet</code> under based on it's
 346  
      * language, country, and variant values.
 347  
      * @param fs The Form Set.
 348  
      * @return generated key for a formset.
 349  
      */
 350  
     protected String buildKey(FormSet fs) {
 351  
         return
 352  
                 this.buildLocale(fs.getLanguage(), fs.getCountry(), fs.getVariant());
 353  
     }
 354  
 
 355  
     /**
 356  
      * Assembles a Locale code from the given parts.
 357  
      */
 358  
     private String buildLocale(String lang, String country, String variant) {
 359  
         String key = ((lang != null && lang.length() > 0) ? lang : "");
 360  
         key += ((country != null && country.length() > 0) ? "_" + country : "");
 361  
         key += ((variant != null && variant.length() > 0) ? "_" + variant : "");
 362  
         return key;
 363  
     }
 364  
 
 365  
     /**
 366  
      * <p>Gets a <code>Form</code> based on the name of the form and the
 367  
      * <code>Locale</code> that most closely matches the <code>Locale</code>
 368  
      * passed in.  The order of <code>Locale</code> matching is:</p>
 369  
      * <ol>
 370  
      *    <li>language + country + variant</li>
 371  
      *    <li>language + country</li>
 372  
      *    <li>language</li>
 373  
      *    <li>default locale</li>
 374  
      * </ol>
 375  
      * @param locale The Locale.
 376  
      * @param formKey The key for the Form.
 377  
      * @return The validator Form.
 378  
      * @since Validator 1.1
 379  
      */
 380  
     public Form getForm(Locale locale, String formKey) {
 381  
         return this.getForm(locale.getLanguage(), locale.getCountry(), locale
 382  
                 .getVariant(), formKey);
 383  
     }
 384  
 
 385  
     /**
 386  
      * <p>Gets a <code>Form</code> based on the name of the form and the
 387  
      * <code>Locale</code> that most closely matches the <code>Locale</code>
 388  
      * passed in.  The order of <code>Locale</code> matching is:</p>
 389  
      * <ol>
 390  
      *    <li>language + country + variant</li>
 391  
      *    <li>language + country</li>
 392  
      *    <li>language</li>
 393  
      *    <li>default locale</li>
 394  
      * </ol>
 395  
      * @param language The locale's language.
 396  
      * @param country The locale's country.
 397  
      * @param variant The locale's language variant.
 398  
      * @param formKey The key for the Form.
 399  
      * @return The validator Form.
 400  
      * @since Validator 1.1
 401  
      */
 402  
     public Form getForm(String language, String country, String variant,
 403  
             String formKey) {
 404  
 
 405  
         Form form = null;
 406  
 
 407  
         // Try language/country/variant
 408  
         String key = this.buildLocale(language, country, variant);
 409  
         if (key.length() > 0) {
 410  
             FormSet formSet = (FormSet)hFormSets.get(key);
 411  
             if (formSet != null) {
 412  
                 form = formSet.getForm(formKey);
 413  
             }
 414  
         }
 415  
         String localeKey  = key;
 416  
 
 417  
 
 418  
         // Try language/country
 419  
         if (form == null) {
 420  
             key = buildLocale(language, country, null);
 421  
             if (key.length() > 0) {
 422  
                 FormSet formSet = (FormSet)hFormSets.get(key);
 423  
                 if (formSet != null) {
 424  
                     form = formSet.getForm(formKey);
 425  
                 }
 426  
             }
 427  
         }
 428  
 
 429  
         // Try language
 430  
         if (form == null) {
 431  
             key = buildLocale(language, null, class="keyword">null);
 432  
             if (key.length() > 0) {
 433  
                 FormSet formSet = (FormSet)hFormSets.get(key);
 434  
                 if (formSet != null) {
 435  
                     form = formSet.getForm(formKey);
 436  
                 }
 437  
             }
 438  
         }
 439  
 
 440  
         // Try default formset
 441  
         if (form == null) {
 442  
             form = defaultFormSet.getForm(formKey);
 443  
             key = "default";
 444  
         }
 445  
 
 446  
         if (form == null) {
 447  
             if (getLog().isWarnEnabled()) {
 448  
                 getLog().warn("Form '" + formKey + "' not found for locale '" +
 449  
                          localeKey + "'");
 450  
             }
 451  
         } else {
 452  
             if (getLog().isDebugEnabled()) {
 453  
                 getLog().debug("Form '" + formKey + "' found in formset '" +
 454  
                           key + "' for locale '" + localeKey + "'");
 455  
             }
 456  
         }
 457  
 
 458  
         return form;
 459  
 
 460  
     }
 461  
 
 462  
     /**
 463  
      * Process the <code>ValidatorResources</code> object. Currently sets the
 464  
      * <code>FastHashMap</code> s to the 'fast' mode and call the processes
 465  
      * all other resources. <strong>Note </strong>: The framework calls this
 466  
      * automatically when ValidatorResources is created from an XML file. If you
 467  
      * create an instance of this class by hand you <strong>must </strong> call
 468  
      * this method when finished.
 469  
      */
 470  
     public void process() {
 471  
         hFormSets.setFast(true);
 472  
         hConstants.setFast(true);
 473  
         hActions.setFast(true);
 474  
 
 475  
         this.processForms();
 476  
     }
 477  
     
 478  
     /**
 479  
      * <p>Process the <code>Form</code> objects.  This clones the <code>Field</code>s
 480  
      * that don't exist in a <code>FormSet</code> compared to its parent
 481  
      * <code>FormSet</code>.</p>
 482  
      */
 483  
     private void processForms() {
 484  
         if (defaultFormSet == null) {// it isn't mandatory to have a
 485  
             // default formset
 486  
             defaultFormSet = new FormSet();
 487  
         }
 488  
         defaultFormSet.process(hConstants);
 489  
         // Loop through FormSets and merge if necessary
 490  
         for (Iterator i = hFormSets.keySet().iterator(); i.hasNext();) {
 491  
             String key = (String) i.next();
 492  
             FormSet fs = (FormSet) hFormSets.get(key);
 493  
             fs.merge(getParent(fs));
 494  
         }
 495  
 
 496  
         // Process Fully Constructed FormSets
 497  
         for (Iterator i = hFormSets.values().iterator(); i.hasNext();) {
 498  
             FormSet fs = (FormSet) i.next();
 499  
             if (!fs.isProcessed()) {
 500  
                 fs.process(hConstants);
 501  
             }
 502  
         }
 503  
     }
 504  
 
 505  
     /**
 506  
      * Finds the given formSet's parent. ex: A formSet with locale en_UK_TEST1
 507  
      * has a direct parent in the formSet with locale en_UK. If it doesn't
 508  
      * exist, find the formSet with locale en, if no found get the
 509  
      * defaultFormSet.
 510  
      * 
 511  
      * @param fs
 512  
      *            the formSet we want to get the parent from
 513  
      * @return fs's parent
 514  
      */
 515  
     private FormSet getParent(FormSet fs) {
 516  
 
 517  
         FormSet parent = null;
 518  
         if (fs.getType() == FormSet.LANGUAGE_FORMSET) {
 519  
             parent = defaultFormSet;
 520  
         } else if (fs.getType() == FormSet.COUNTRY_FORMSET) {
 521  
             parent = (FormSet) hFormSets.get(buildLocale(fs.getLanguage(),
 522  
                     null, class="keyword">null));
 523  
             if (parent == null) {
 524  
                 parent = defaultFormSet;
 525  
             }
 526  
         } else if (fs.getType() == FormSet.VARIANT_FORMSET) {
 527  
             parent = (FormSet) hFormSets.get(buildLocale(fs.getLanguage(), fs
 528  
                     .getCountry(), null));
 529  
             if (parent == null) {
 530  
                 parent = (FormSet) hFormSets.get(buildLocale(fs.getLanguage(),
 531  
                         null, class="keyword">null));
 532  
                 if (parent == null) {
 533  
                     parent = defaultFormSet;
 534  
                 }
 535  
             }
 536  
         }
 537  
         return parent;
 538  
     }
 539  
 
 540  
     /**
 541  
      * <p>Gets a <code>FormSet</code> based on the language, country
 542  
      *    and variant.</p>
 543  
      * @param language The locale's language.
 544  
      * @param country The locale's country.
 545  
      * @param variant The locale's language variant.
 546  
      * @return The FormSet for a locale.
 547  
      * @since Validator 1.2
 548  
      */
 549  
     FormSet getFormSet(String language, String country, String variant) {
 550  
 
 551  
         String key = buildLocale(language, country, variant);
 552  
 
 553  
         if (key.length() == 0) {
 554  
             return defaultFormSet;
 555  
         }
 556  
 
 557  
         return (FormSet)hFormSets.get(key);
 558  
     }
 559  
 
 560  
     /**
 561  
      * Returns a Map of String locale keys to Lists of their FormSets.
 562  
      * @return Map of Form sets
 563  
      * @since Validator 1.2.0
 564  
      */
 565  
     protected Map getFormSets() {
 566  
         return hFormSets;
 567  
     }
 568  
 
 569  
     /**
 570  
      * Returns a Map of String constant names to their String values.
 571  
      * @return Map of Constants
 572  
      * @since Validator 1.2.0
 573  
      */
 574  
     protected Map getConstants() {
 575  
         return hConstants;
 576  
     }
 577  
 
 578  
     /**
 579  
      * Returns a Map of String ValidatorAction names to their ValidatorAction.
 580  
      * @return Map of Validator Actions
 581  
      * @since Validator 1.2.0
 582  
      */
 583  
     protected Map getActions() {
 584  
         return hActions;
 585  
     }
 586  
 
 587  
     /**
 588  
      * Accessor method for Log instance.
 589  
      *
 590  
      * The Log instance variable is transient and
 591  
      * accessing it through this method ensures it
 592  
      * is re-initialized when this instance is
 593  
      * de-serialized.
 594  
      *
 595  
      * @return The Log instance.
 596  
      */
 597  
     private Log getLog() {
 598  
         if (log == null) {
 599  
             log =  LogFactory.getLog(ValidatorResources.class);
 600  
         }
 601  
         return log;
 602  
     }
 603  
 
 604  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.