1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.validator;
18
19 import java.io.Serializable;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.Map;
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26
27 /***
28 * Holds a set of <code>Form</code>s stored associated with a <code>Locale</code>
29 * based on the country, language, and variant specified. Instances of this
30 * class are configured with a <formset> xml element.
31 *
32 * @version $Revision: 478334 $ $Date: 2006-11-22 21:31:54 +0000 (Wed, 22 Nov 2006) $
33 */
34 public class FormSet implements Serializable {
35
36 /*** Logging */
37 private transient Log log = LogFactory.getLog(FormSet.class);
38
39 /***
40 * Whether or not the this <code>FormSet</code> was processed for replacing
41 * variables in strings with their values.
42 */
43 private boolean processed = false;
44
45 /*** Language component of <code>Locale</code> (required). */
46 private String language = null;
47
48 /*** Country component of <code>Locale</code> (optional). */
49 private String country = null;
50
51 /*** Variant component of <code>Locale</code> (optional). */
52 private String variant = null;
53
54 /***
55 * A <code>Map</code> of <code>Form</code>s using the name field of the
56 * <code>Form</code> as the key.
57 */
58 private Map forms = new HashMap();
59
60 /***
61 * A <code>Map</code> of <code>Constant</code>s using the name field of the
62 * <code>Constant</code> as the key.
63 */
64 private Map constants = new HashMap();
65
66 /***
67 * This is the type of <code>FormSet</code>s where no locale is specified.
68 */
69 protected final static int GLOBAL_FORMSET = 1;
70
71 /***
72 * This is the type of <code>FormSet</code>s where only language locale is
73 * specified.
74 */
75 protected final static int LANGUAGE_FORMSET = 2;
76
77 /***
78 * This is the type of <code>FormSet</code>s where only language and country
79 * locale are specified.
80 */
81 protected final static int COUNTRY_FORMSET = 3;
82
83 /***
84 * This is the type of <code>FormSet</code>s where full locale has been set.
85 */
86 protected final static int VARIANT_FORMSET = 4;
87
88 /***
89 * Flag indicating if this formSet has been merged with its parent (higher
90 * rank in Locale hierarchy).
91 */
92 private boolean merged;
93
94 /***
95 * Has this formSet been merged?
96 *
97 * @return true if it has been merged
98 * @since Validator 1.2.0
99 */
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) {
154
155 pForm.merge((Form) dForms.get(key));
156 }
157 else {
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 }