001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.validator; 018 019 import java.io.Serializable; 020 import java.util.Collections; 021 import java.util.HashMap; 022 import java.util.Iterator; 023 import java.util.Map; 024 import org.apache.commons.logging.Log; 025 import org.apache.commons.logging.LogFactory; 026 027 /** 028 * Holds a set of <code>Form</code>s stored associated with a <code>Locale</code> 029 * based on the country, language, and variant specified. Instances of this 030 * class are configured with a <formset> xml element. 031 * 032 * @version $Revision: 493905 $ $Date: 2007-01-08 03:11:38 +0100 (Mo, 08. Jan 2007) $ 033 */ 034 public class FormSet implements Serializable { 035 036 /** Logging */ 037 private transient Log log = LogFactory.getLog(FormSet.class); 038 039 /** 040 * Whether or not the this <code>FormSet</code> was processed for replacing 041 * variables in strings with their values. 042 */ 043 private boolean processed = false; 044 045 /** Language component of <code>Locale</code> (required). */ 046 private String language = null; 047 048 /** Country component of <code>Locale</code> (optional). */ 049 private String country = null; 050 051 /** Variant component of <code>Locale</code> (optional). */ 052 private String variant = null; 053 054 /** 055 * A <code>Map</code> of <code>Form</code>s using the name field of the 056 * <code>Form</code> as the key. 057 */ 058 private Map forms = new HashMap(); 059 060 /** 061 * A <code>Map</code> of <code>Constant</code>s using the name field of the 062 * <code>Constant</code> as the key. 063 */ 064 private Map constants = new HashMap(); 065 066 /** 067 * This is the type of <code>FormSet</code>s where no locale is specified. 068 */ 069 protected final static int GLOBAL_FORMSET = 1; 070 071 /** 072 * This is the type of <code>FormSet</code>s where only language locale is 073 * specified. 074 */ 075 protected final static int LANGUAGE_FORMSET = 2; 076 077 /** 078 * This is the type of <code>FormSet</code>s where only language and country 079 * locale are specified. 080 */ 081 protected final static int COUNTRY_FORMSET = 3; 082 083 /** 084 * This is the type of <code>FormSet</code>s where full locale has been set. 085 */ 086 protected final static int VARIANT_FORMSET = 4; 087 088 /** 089 * Flag indicating if this formSet has been merged with its parent (higher 090 * rank in Locale hierarchy). 091 */ 092 private boolean merged; 093 094 /** 095 * Has this formSet been merged? 096 * 097 * @return true if it has been merged 098 * @since Validator 1.2.0 099 */ 100 protected boolean isMerged() { 101 return merged; 102 } 103 104 /** 105 * Returns the type of <code>FormSet</code>:<code>GLOBAL_FORMSET</code>, 106 * <code>LANGUAGE_FORMSET</code>,<code>COUNTRY_FORMSET</code> or <code>VARIANT_FORMSET</code> 107 * . 108 * 109 * @return The type value 110 * @since Validator 1.2.0 111 * @throws NullPointerException if there is inconsistency in the locale 112 * definition (not sure about this) 113 */ 114 protected int getType() { 115 if (getVariant() != null) { 116 if (getLanguage() == null || getCountry() == null) { 117 throw new NullPointerException( 118 "When variant is specified, country and language must be specified."); 119 } 120 return VARIANT_FORMSET; 121 } 122 else if (getCountry() != null) { 123 if (getLanguage() == null) { 124 throw new NullPointerException( 125 "When country is specified, language must be specified."); 126 } 127 return COUNTRY_FORMSET; 128 } 129 else if (getLanguage() != null) { 130 return LANGUAGE_FORMSET; 131 } 132 else { 133 return GLOBAL_FORMSET; 134 } 135 } 136 137 /** 138 * Merges the given <code>FormSet</code> into this one. If any of <code>depends</code> 139 * s <code>Forms</code> are not in this <code>FormSet</code> then, include 140 * them, else merge both <code>Forms</code>. Theoretically we should only 141 * merge a "parent" formSet. 142 * 143 * @param depends FormSet to be merged 144 * @since Validator 1.2.0 145 */ 146 protected void merge(FormSet depends) { 147 if (depends != null) { 148 Map pForms = getForms(); 149 Map dForms = depends.getForms(); 150 for (Iterator it = dForms.keySet().iterator(); it.hasNext(); ) { 151 Object key = it.next(); 152 Form pForm = (Form) pForms.get(key); 153 if (pForm != null) {//merge, but principal 'rules', don't overwrite 154 // anything 155 pForm.merge((Form) dForms.get(key)); 156 } 157 else {//just add 158 addForm((Form) dForms.get(key)); 159 } 160 } 161 } 162 merged = true; 163 } 164 165 /** 166 * Whether or not the this <code>FormSet</code> was processed for replacing 167 * variables in strings with their values. 168 * 169 * @return The processed value 170 */ 171 public boolean isProcessed() { 172 return processed; 173 } 174 175 /** 176 * Gets the equivalent of the language component of <code>Locale</code>. 177 * 178 * @return The language value 179 */ 180 public String getLanguage() { 181 return language; 182 } 183 184 /** 185 * Sets the equivalent of the language component of <code>Locale</code>. 186 * 187 * @param language The new language value 188 */ 189 public void setLanguage(String language) { 190 this.language = language; 191 } 192 193 /** 194 * Gets the equivalent of the country component of <code>Locale</code>. 195 * 196 * @return The country value 197 */ 198 public String getCountry() { 199 return country; 200 } 201 202 /** 203 * Sets the equivalent of the country component of <code>Locale</code>. 204 * 205 * @param country The new country value 206 */ 207 public void setCountry(String country) { 208 this.country = country; 209 } 210 211 /** 212 * Gets the equivalent of the variant component of <code>Locale</code>. 213 * 214 * @return The variant value 215 */ 216 public String getVariant() { 217 return variant; 218 } 219 220 /** 221 * Sets the equivalent of the variant component of <code>Locale</code>. 222 * 223 * @param variant The new variant value 224 */ 225 public void setVariant(String variant) { 226 this.variant = variant; 227 } 228 229 /** 230 * Add a <code>Constant</code> to the locale level. 231 * 232 * @param name The constant name 233 * @param value The constant value 234 */ 235 public void addConstant(String name, String value) { 236 237 if (constants.containsKey(name)) { 238 getLog().error("Constant '" + name + "' already exists in FormSet[" 239 + this.displayKey() + "] - ignoring."); 240 241 } else { 242 constants.put(name, value); 243 } 244 245 } 246 247 /** 248 * Add a <code>Form</code> to the <code>FormSet</code>. 249 * 250 * @param f The form 251 */ 252 public void addForm(Form f) { 253 254 String formName = f.getName(); 255 if (forms.containsKey(formName)) { 256 getLog().error("Form '" + formName + "' already exists in FormSet[" 257 + this.displayKey() + "] - ignoring."); 258 259 } else { 260 forms.put(f.getName(), f); 261 } 262 263 } 264 265 /** 266 * Retrieve a <code>Form</code> based on the form name. 267 * 268 * @param formName The form name 269 * @return The form 270 */ 271 public Form getForm(String formName) { 272 return (Form) this.forms.get(formName); 273 } 274 275 /** 276 * A <code>Map</code> of <code>Form</code>s is returned as an unmodifiable 277 * <code>Map</code> with the key based on the form name. 278 * 279 * @return The forms map 280 */ 281 public Map getForms() { 282 return Collections.unmodifiableMap(forms); 283 } 284 285 /** 286 * Processes all of the <code>Form</code>s. 287 * 288 * @param globalConstants Global constants 289 */ 290 synchronized void process(Map globalConstants) { 291 for (Iterator i = forms.values().iterator(); i.hasNext(); ) { 292 Form f = (Form) i.next(); 293 f.process(globalConstants, constants, forms); 294 } 295 296 processed = true; 297 } 298 299 /** 300 * Returns a string representation of the object's key. 301 * 302 * @return A string representation of the key 303 */ 304 public String displayKey() { 305 StringBuffer results = new StringBuffer(); 306 if (language != null && language.length() > 0) { 307 results.append("language="); 308 results.append(language); 309 } 310 if (country != null && country.length() > 0) { 311 if (results.length() > 0) { 312 results.append(", "); 313 } 314 results.append("country="); 315 results.append(country); 316 } 317 if (variant != null && variant.length() > 0) { 318 if (results.length() > 0) { 319 results.append(", "); 320 } 321 results.append("variant="); 322 results.append(variant ); 323 } 324 if (results.length() == 0) { 325 results.append("default"); 326 } 327 328 return results.toString(); 329 } 330 331 /** 332 * Returns a string representation of the object. 333 * 334 * @return A string representation 335 */ 336 public String toString() { 337 StringBuffer results = new StringBuffer(); 338 339 results.append("FormSet: language="); 340 results.append(language); 341 results.append(" country="); 342 results.append(country); 343 results.append(" variant="); 344 results.append(variant); 345 results.append("\n"); 346 347 for (Iterator i = getForms().values().iterator(); i.hasNext(); ) { 348 results.append(" "); 349 results.append(i.next()); 350 results.append("\n"); 351 } 352 353 return results.toString(); 354 } 355 356 /** 357 * Accessor method for Log instance. 358 * 359 * The Log instance variable is transient and 360 * accessing it through this method ensures it 361 * is re-initialized when this instance is 362 * de-serialized. 363 * 364 * @return The Log instance. 365 */ 366 private Log getLog() { 367 if (log == null) { 368 log = LogFactory.getLog(FormSet.class); 369 } 370 return log; 371 } 372 }