View Javadoc
1 /* 2 * $Header: /home/cvs/jakarta-commons/validator/src/share/org/apache/commons/validator/ValidatorResources.java,v 1.30.2.2 2004/06/22 02:24:38 husted Exp $ 3 * $Revision: 1.30.2.2 $ 4 * $Date: 2004/06/22 02:24:38 $ 5 * 6 * ==================================================================== 7 * Copyright 2001-2004 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.ArrayList; 29 import java.util.Collections; 30 import java.util.Iterator; 31 import java.util.List; 32 import java.util.Locale; 33 import java.util.Map; 34 35 import org.apache.commons.collections.FastHashMap; // DEPRECATED 36 import org.apache.commons.digester.Digester; 37 import org.apache.commons.digester.xmlrules.DigesterLoader; 38 import org.apache.commons.logging.Log; 39 import org.apache.commons.logging.LogFactory; 40 41 import org.xml.sax.SAXException; 42 43 /*** 44 * <p> 45 * General purpose class for storing <code>FormSet</code> objects based 46 * on their associated <code>Locale</code>. Instances of this class are usually 47 * configured through a validation.xml file that is parsed in a constructor. 48 * </p> 49 * 50 * <p><strong>Note</strong> - Classes that extend this class 51 * must be Serializable so that instances may be used in distributable 52 * application server environments.</p> 53 * 54 * <p> 55 * The use of FastHashMap is deprecated and will be replaced in a future 56 * release. 57 * </p> 58 */ 59 public class ValidatorResources implements Serializable { 60 61 /*** 62 * The set of public identifiers, and corresponding resource names, for 63 * the versions of the configuration file DTDs that we know about. There 64 * <strong>MUST</strong> be an even number of Strings in this list! 65 */ 66 private static final String registrations[] = { 67 "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN", 68 "/org/apache/commons/validator/resources/validator_1_0.dtd", 69 "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0.1//EN", 70 "/org/apache/commons/validator/resources/validator_1_0_1.dtd", 71 "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1//EN", 72 "/org/apache/commons/validator/resources/validator_1_1.dtd", 73 "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN", 74 "/org/apache/commons/validator/resources/validator_1_1_3.dtd" 75 }; 76 77 /*** 78 * Logger. 79 * @deprecated Subclasses should use their own logging instance. 80 */ 81 protected static Log log = LogFactory.getLog(ValidatorResources.class); 82 83 /*** 84 * <code>FastHashMap</code> of <code>FormSet</code>s stored under 85 * a <code>Locale</code> key. 86 */ 87 protected FastHashMap hFormSets = new FastHashMap(); 88 89 /*** 90 * <code>FastHashMap</code> of global constant values with 91 * the name of the constant as the key. 92 */ 93 protected FastHashMap hConstants = new FastHashMap(); 94 95 /*** 96 * <code>FastHashMap</code> of <code>ValidatorAction</code>s with 97 * the name of the <code>ValidatorAction</code> as the key. 98 */ 99 protected FastHashMap hActions = new FastHashMap(); 100 101 /*** 102 * The default locale on our server. 103 */ 104 protected static Locale defaultLocale = Locale.getDefault(); 105 106 /*** 107 * Create an empty ValidatorResources object. 108 */ 109 public ValidatorResources() { 110 super(); 111 } 112 113 /*** 114 * Create a ValidatorResources object from an InputStream. 115 * 116 * @param in InputStream to a validation.xml configuration file. It's the client's 117 * responsibility to close this stream. 118 * @throws IOException 119 * @throws SAXException if the validation XML files are not valid or well 120 * formed. 121 * @since Validator 1.1 122 */ 123 public ValidatorResources(InputStream in) throws IOException, SAXException { 124 this(new InputStream[]{in}); 125 } 126 127 /*** 128 * Create a ValidatorResources object from an InputStream. 129 * 130 * @param streams An array of InputStreams to several validation.xml 131 * configuration files that will be read in order and merged into this object. 132 * It's the client's responsibility to close these streams. 133 * @throws IOException 134 * @throws SAXException if the validation XML files are not valid or well 135 * formed. 136 * @since Validator 1.1 137 */ 138 public ValidatorResources(InputStream[] streams) 139 throws IOException, SAXException { 140 141 super(); 142 143 URL rulesUrl = this.getClass().getResource("digester-rules.xml"); 144 Digester digester = DigesterLoader.createDigester(rulesUrl); 145 digester.setNamespaceAware(true); 146 digester.setValidating(true); 147 digester.setUseContextClassLoader(true); 148 149 // register DTDs 150 for (int i = 0; i < registrations.length; i += 2) { 151 URL url = this.getClass().getResource(registrations[i + 1]); 152 if (url != null) { 153 digester.register(registrations[i], url.toString()); 154 } 155 } 156 157 for (int i = 0; i < streams.length; i++) { 158 digester.push(this); 159 digester.parse(streams[i]); 160 } 161 162 this.process(); 163 } 164 165 /*** 166 * Add a <code>FormSet</code> to this <code>ValidatorResources</code> 167 * object. It will be associated with the <code>Locale</code> of the 168 * <code>FormSet</code>. 169 * @deprecated Use addFormSet() instead. 170 */ 171 public void put(FormSet fs) { 172 this.addFormSet(fs); 173 } 174 175 /*** 176 * Add a <code>FormSet</code> to this <code>ValidatorResources</code> 177 * object. It will be associated with the <code>Locale</code> of the 178 * <code>FormSet</code>. 179 * @since Validator 1.1 180 */ 181 public void addFormSet(FormSet fs) { 182 String key = this.buildKey(fs); 183 List formsets = (List) hFormSets.get(key); 184 185 if (formsets == null) { 186 formsets = new ArrayList(); 187 hFormSets.put(key, formsets); 188 } 189 190 if (!formsets.contains(fs)) { 191 if (log.isDebugEnabled()) { 192 log.debug("Adding FormSet '" + fs.toString() + "'."); 193 } 194 formsets.add(fs); 195 } 196 } 197 198 /*** 199 * Add a global constant to the resource. 200 * @deprecated Use addConstant(String, String) instead. 201 */ 202 public void addConstant(Constant c) { 203 this.addConstantParam(c.getName(), c.getValue()); 204 } 205 206 /*** 207 * Add a global constant to the resource. 208 * @deprecated Use addConstant(String, String) instead. 209 */ 210 public void addConstantParam(String name, String value) { 211 if (name != null 212 && name.length() > 0 213 && value != null 214 && value.length() > 0) { 215 216 if (log.isDebugEnabled()) { 217 log.debug("Adding Global Constant: " + name + "," + value); 218 } 219 220 this.hConstants.put(name, value); 221 } 222 } 223 224 /*** 225 * Add a global constant to the resource. 226 */ 227 public void addConstant(String name, String value) { 228 if (log.isDebugEnabled()) { 229 log.debug("Adding Global Constant: " + name + "," + value); 230 } 231 232 this.hConstants.put(name, value); 233 } 234 235 /*** 236 * Add a <code>ValidatorAction</code> to the resource. It also creates an 237 * instance of the class based on the <code>ValidatorAction</code>s 238 * classname and retrieves the <code>Method</code> instance and sets them 239 * in the <code>ValidatorAction</code>. 240 */ 241 public void addValidatorAction(ValidatorAction va) { 242 va.init(); 243 244 this.hActions.put(va.getName(), va); 245 246 if (log.isDebugEnabled()) { 247 log.debug("Add ValidatorAction: " + va.getName() + "," + va.getClassname()); 248 } 249 } 250 251 /*** 252 * Get a <code>ValidatorAction</code> based on it's name. 253 */ 254 public ValidatorAction getValidatorAction(String key) { 255 return (ValidatorAction) hActions.get(key); 256 } 257 258 /*** 259 * Get an unmodifiable <code>Map</code> of the <code>ValidatorAction</code>s. 260 */ 261 public Map getValidatorActions() { 262 return Collections.unmodifiableMap(hActions); 263 } 264 265 /*** 266 * Builds a key to store the <code>FormSet</code> under based on it's 267 * language, country, and variant values. 268 */ 269 protected String buildKey(FormSet fs) { 270 String locale = 271 this.buildLocale(fs.getLanguage(), fs.getCountry(), fs.getVariant()); 272 273 if (locale.length() == 0) { 274 locale = defaultLocale.toString(); 275 } 276 277 return locale; 278 } 279 280 /*** 281 * Assembles a Locale code from the given parts. 282 */ 283 private String buildLocale(String lang, String country, String variant) { 284 String key = ((lang != null && lang.length() > 0) ? lang : ""); 285 key += ((country != null && country.length() > 0) ? "_" + country : ""); 286 key += ((variant != null && variant.length() > 0) ? "_" + variant : ""); 287 return key; 288 } 289 290 /*** 291 * <p>Gets a <code>Form</code> based on the name of the form and the <code>Locale</code> that 292 * most closely matches the <code>Locale</code> passed in. The order of <code>Locale</code> 293 * matching is:</p> 294 * <ol> 295 * <li>language + country + variant</li> 296 * <li>language + country</li> 297 * <li>language</li> 298 * <li>default locale</li> 299 * </ol> 300 * @deprecated Use getForm() instead. 301 */ 302 public Form get(Locale locale, Object formKey) { 303 String key = (formKey == null) ? null : formKey.toString(); 304 return this.getForm(locale, key); 305 } 306 307 /*** 308 * <p>Gets a <code>Form</code> based on the name of the form and the 309 * <code>Locale</code> that most closely matches the <code>Locale</code> 310 * passed in. The order of <code>Locale</code> matching is:</p> 311 * <ol> 312 * <li>language + country + variant</li> 313 * <li>language + country</li> 314 * <li>language</li> 315 * <li>default locale</li> 316 * </ol> 317 * @since Validator 1.1 318 */ 319 public Form getForm(Locale locale, String formKey) { 320 return this.getForm( 321 locale.getLanguage(), 322 locale.getCountry(), 323 locale.getVariant(), 324 formKey); 325 } 326 327 /*** 328 * <p>Gets a <code>Form</code> based on the name of the form and the 329 * <code>Locale</code> that most closely matches the <code>Locale</code> 330 * passed in. The order of <code>Locale</code> matching is:</p> 331 * <ol> 332 * <li>language + country + variant</li> 333 * <li>language + country</li> 334 * <li>language</li> 335 * <li>default locale</li> 336 * </ol> 337 * @deprecated Use getForm() instead. 338 */ 339 public Form get( 340 String language, 341 String country, 342 String variant, 343 Object formKey) { 344 345 String key = (formKey == null) ? null : formKey.toString(); 346 return this.getForm(language, country, variant, key); 347 } 348 349 /*** 350 * <p>Gets a <code>Form</code> based on the name of the form and the 351 * <code>Locale</code> that most closely matches the <code>Locale</code> 352 * passed in. The order of <code>Locale</code> matching is:</p> 353 * <ol> 354 * <li>language + country + variant</li> 355 * <li>language + country</li> 356 * <li>language</li> 357 * <li>default locale</li> 358 * </ol> 359 * @since Validator 1.1 360 */ 361 public Form getForm( 362 String language, 363 String country, 364 String variant, 365 String formKey) { 366 367 String key = this.buildLocale(language, country, variant); 368 369 List v = (List) hFormSets.get(key); 370 371 if (v == null) { 372 key = (language != null && language.length() > 0) ? language : ""; 373 key += (country != null && country.length() > 0) ? "_" + country : ""; 374 v = (List) hFormSets.get(key); 375 } 376 377 if (v == null) { 378 key = (language != null && language.length() > 0) ? language : ""; 379 v = (List) hFormSets.get(key); 380 } 381 382 if (v == null) { 383 key = defaultLocale.toString(); 384 v = (List) hFormSets.get(key); 385 } 386 387 if (v == null) { 388 return null; 389 } 390 391 Iterator formsets = v.iterator(); 392 while (formsets.hasNext()) { 393 FormSet set = (FormSet) formsets.next(); 394 395 if ((set != null) && (set.getForm(formKey) != null)) { 396 return set.getForm(formKey); 397 } 398 399 } 400 return null; 401 } 402 403 /*** 404 * Process the <code>ValidatorResources</code> object. Currently sets the 405 * <code>FastHashMap</code>s to the 'fast' mode and call the processes all 406 * other resources. <strong>Note</strong>: The framework calls this automatically 407 * when ValidatorResources is created from an XML file. If you create an instance 408 * of this class by hand you <strong>must</strong> call this method when finished. 409 */ 410 public void process() { 411 hFormSets.setFast(true); 412 hConstants.setFast(true); 413 hActions.setFast(true); 414 415 this.internalProcessForms(); 416 } 417 418 /*** 419 * <p>Process the <code>Form</code> objects. This clones the <code>Field</code>s 420 * that don't exist in a <code>FormSet</code> compared to the default 421 * <code>FormSet</code>.</p> 422 * @deprecated This is an internal method that client classes need not call directly. 423 */ 424 public void processForms() { 425 this.internalProcessForms(); 426 } 427 428 /*** 429 * <p>Process the <code>Form</code> objects. This clones the <code>Field</code>s 430 * that don't exist in a <code>FormSet</code> compared to the default 431 * <code>FormSet</code>.</p> 432 * TODO When processForms() is removed from the public interface, rename this 433 * private method back to "processForms". 434 */ 435 private void internalProcessForms() { 436 //hFormSets.put(buildKey(fs), fs); 437 String defaultKey = defaultLocale.toString(); 438 439 // Loop through FormSets 440 for (Iterator i = hFormSets.keySet().iterator(); i.hasNext();) { 441 String key = (String) i.next(); 442 // Skip default FormSet 443 if (key.equals(defaultKey)) { 444 continue; 445 } 446 List formsets = (List) hFormSets.get(key); 447 Iterator formsetsIterator = formsets.iterator(); 448 while (formsetsIterator.hasNext()) { 449 FormSet fs = (FormSet) formsetsIterator.next(); 450 451 // Loop through Forms and copy/clone fields from default locale 452 for (Iterator x = fs.getForms().keySet().iterator(); x.hasNext();) { 453 String formKey = (String) x.next(); 454 Form form = (Form) fs.getForms().get(formKey); 455 // Create a new Form object so the order from the default is 456 // maintained (very noticable in the JavaScript). 457 Form newForm = new Form(); 458 newForm.setName(form.getName()); 459 460 // Loop through the default locale form's fields 461 // If they don't exist in the current locale's form, then clone them. 462 Form defaultForm = get(defaultLocale, formKey); 463 464 Iterator defaultFields = defaultForm.getFields().iterator(); 465 while (defaultFields.hasNext()) { 466 Field defaultField = (Field) defaultFields.next(); 467 String fieldKey = defaultField.getKey(); 468 469 if (form.containsField(fieldKey)) { 470 newForm.addField(form.getField(fieldKey)); 471 472 } else { 473 Field field = 474 getClosestLocaleField(fs, formKey, fieldKey); 475 476 newForm.addField((Field) field.clone()); 477 } 478 } 479 480 fs.addForm(newForm); 481 } 482 } 483 } 484 485 // Process Fully Constructed FormSets 486 for (Iterator i = hFormSets.values().iterator(); i.hasNext();) { 487 List formsets = (List) i.next(); 488 Iterator formsetsIterator = formsets.iterator(); 489 while (formsetsIterator.hasNext()) { 490 FormSet fs = (FormSet) formsetsIterator.next(); 491 492 if (!fs.isProcessed()) { 493 fs.process(hConstants); 494 } 495 } 496 } 497 } 498 499 /*** 500 * Retrieves the closest matching <code>Field</code> based 501 * on <code>FormSet</code>'s locale. This is used when 502 * constructing a clone, field by field, of partial 503 * <code>FormSet</code>. 504 */ 505 protected Field getClosestLocaleField( 506 FormSet fs, 507 String formKey, 508 String fieldKey) { 509 510 Field field = null; 511 String language = fs.getLanguage(); 512 String country = fs.getCountry(); 513 String variant = fs.getVariant(); 514 515 if (!GenericValidator.isBlankOrNull(language) 516 && !GenericValidator.isBlankOrNull(country) 517 && !GenericValidator.isBlankOrNull(variant)) { 518 519 Form form = this.getForm(language, country, variant, formKey); 520 field = form.getField(fieldKey); 521 } 522 523 if (field == null) { 524 if (!GenericValidator.isBlankOrNull(language) 525 && !GenericValidator.isBlankOrNull(country)) { 526 527 Form form = this.getForm(language, country, null, formKey); 528 field = form.getField(fieldKey); 529 } 530 } 531 532 if (field == null) { 533 if (!GenericValidator.isBlankOrNull(language)) { 534 Form form = this.getForm(language, null, null, formKey); 535 field = form.getField(fieldKey); 536 } 537 } 538 539 if (field == null) { 540 Form form = this.getForm(defaultLocale, formKey); 541 field = form.getField(fieldKey); 542 } 543 544 return field; 545 } 546 547 }

This page was automatically generated by Maven