Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
FormSet |
|
| 2.5555555555555554;2.556 |
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 | ||
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 java.util.Map.Entry; | |
25 | ||
26 | import org.apache.commons.logging.Log; | |
27 | import org.apache.commons.logging.LogFactory; | |
28 | ||
29 | /** | |
30 | * Holds a set of <code>Form</code>s stored associated with a <code>Locale</code> | |
31 | * based on the country, language, and variant specified. Instances of this | |
32 | * class are configured with a <formset> xml element. | |
33 | * | |
34 | * @version $Revision: 1739361 $ | |
35 | */ | |
36 | 151 | public class FormSet implements Serializable { |
37 | ||
38 | private static final long serialVersionUID = -8936513232763306055L; | |
39 | ||
40 | /** Logging */ | |
41 | 151 | private transient Log log = LogFactory.getLog(FormSet.class); |
42 | ||
43 | /** | |
44 | * Whether or not the this <code>FormSet</code> was processed for replacing | |
45 | * variables in strings with their values. | |
46 | */ | |
47 | 151 | private boolean processed = false; |
48 | ||
49 | /** Language component of <code>Locale</code> (required). */ | |
50 | 151 | private String language = null; |
51 | ||
52 | /** Country component of <code>Locale</code> (optional). */ | |
53 | 151 | private String country = null; |
54 | ||
55 | /** Variant component of <code>Locale</code> (optional). */ | |
56 | 151 | private String variant = null; |
57 | ||
58 | /** | |
59 | * A <code>Map</code> of <code>Form</code>s using the name field of the | |
60 | * <code>Form</code> as the key. | |
61 | */ | |
62 | 151 | private final Map<String, Form> forms = new HashMap<String, Form>(); |
63 | ||
64 | /** | |
65 | * A <code>Map</code> of <code>Constant</code>s using the name field of the | |
66 | * <code>Constant</code> as the key. | |
67 | */ | |
68 | 151 | private final Map<String, String> constants = new HashMap<String, String>(); |
69 | ||
70 | /** | |
71 | * This is the type of <code>FormSet</code>s where no locale is specified. | |
72 | */ | |
73 | protected final static int GLOBAL_FORMSET = 1; | |
74 | ||
75 | /** | |
76 | * This is the type of <code>FormSet</code>s where only language locale is | |
77 | * specified. | |
78 | */ | |
79 | protected final static int LANGUAGE_FORMSET = 2; | |
80 | ||
81 | /** | |
82 | * This is the type of <code>FormSet</code>s where only language and country | |
83 | * locale are specified. | |
84 | */ | |
85 | protected final static int COUNTRY_FORMSET = 3; | |
86 | ||
87 | /** | |
88 | * This is the type of <code>FormSet</code>s where full locale has been set. | |
89 | */ | |
90 | protected final static int VARIANT_FORMSET = 4; | |
91 | ||
92 | /** | |
93 | * Flag indicating if this formSet has been merged with its parent (higher | |
94 | * rank in Locale hierarchy). | |
95 | */ | |
96 | private boolean merged; | |
97 | ||
98 | /** | |
99 | * Has this formSet been merged? | |
100 | * | |
101 | * @return true if it has been merged | |
102 | * @since Validator 1.2.0 | |
103 | */ | |
104 | protected boolean isMerged() { | |
105 | 0 | return merged; |
106 | } | |
107 | ||
108 | /** | |
109 | * Returns the type of <code>FormSet</code>:<code>GLOBAL_FORMSET</code>, | |
110 | * <code>LANGUAGE_FORMSET</code>,<code>COUNTRY_FORMSET</code> or <code>VARIANT_FORMSET</code> | |
111 | * . | |
112 | * | |
113 | * @return The type value | |
114 | * @since Validator 1.2.0 | |
115 | * @throws NullPointerException if there is inconsistency in the locale | |
116 | * definition (not sure about this) | |
117 | */ | |
118 | protected int getType() { | |
119 | 85 | if (getVariant() != null) { |
120 | 45 | if (getLanguage() == null || getCountry() == null) { |
121 | 0 | throw new NullPointerException( |
122 | "When variant is specified, country and language must be specified."); | |
123 | } | |
124 | 45 | return VARIANT_FORMSET; |
125 | } | |
126 | 40 | else if (getCountry() != null) { |
127 | 30 | if (getLanguage() == null) { |
128 | 0 | throw new NullPointerException( |
129 | "When country is specified, language must be specified."); | |
130 | } | |
131 | 30 | return COUNTRY_FORMSET; |
132 | } | |
133 | 10 | else if (getLanguage() != null) { |
134 | 10 | return LANGUAGE_FORMSET; |
135 | } | |
136 | else { | |
137 | 0 | return GLOBAL_FORMSET; |
138 | } | |
139 | } | |
140 | ||
141 | /** | |
142 | * Merges the given <code>FormSet</code> into this one. If any of <code>depends</code> | |
143 | * s <code>Forms</code> are not in this <code>FormSet</code> then, include | |
144 | * them, else merge both <code>Forms</code>. Theoretically we should only | |
145 | * merge a "parent" formSet. | |
146 | * | |
147 | * @param depends FormSet to be merged | |
148 | * @since Validator 1.2.0 | |
149 | */ | |
150 | protected void merge(FormSet depends) { | |
151 | 40 | if (depends != null) { |
152 | 40 | Map<String, Form> pForms = getForms(); |
153 | 40 | Map<String, Form> dForms = depends.getForms(); |
154 | 40 | for (Iterator<Entry<String, Form>> it = dForms.entrySet().iterator(); it.hasNext(); ) { |
155 | 110 | Entry<String, Form> entry = it.next(); |
156 | 110 | String key = entry.getKey(); |
157 | 110 | Form pForm = pForms.get(key); |
158 | 110 | if (pForm != null) {//merge, but principal 'rules', don't overwrite |
159 | // anything | |
160 | 55 | pForm.merge(entry.getValue()); |
161 | } | |
162 | else {//just add | |
163 | 55 | addForm(entry.getValue()); |
164 | } | |
165 | 110 | } |
166 | } | |
167 | 40 | merged = true; |
168 | 40 | } |
169 | ||
170 | /** | |
171 | * Whether or not the this <code>FormSet</code> was processed for replacing | |
172 | * variables in strings with their values. | |
173 | * | |
174 | * @return The processed value | |
175 | */ | |
176 | public boolean isProcessed() { | |
177 | 40 | return processed; |
178 | } | |
179 | ||
180 | /** | |
181 | * Gets the equivalent of the language component of <code>Locale</code>. | |
182 | * | |
183 | * @return The language value | |
184 | */ | |
185 | public String getLanguage() { | |
186 | 276 | return language; |
187 | } | |
188 | ||
189 | /** | |
190 | * Sets the equivalent of the language component of <code>Locale</code>. | |
191 | * | |
192 | * @param language The new language value | |
193 | */ | |
194 | public void setLanguage(String language) { | |
195 | 147 | this.language = language; |
196 | 147 | } |
197 | ||
198 | /** | |
199 | * Gets the equivalent of the country component of <code>Locale</code>. | |
200 | * | |
201 | * @return The country value | |
202 | */ | |
203 | public String getCountry() { | |
204 | 251 | return country; |
205 | } | |
206 | ||
207 | /** | |
208 | * Sets the equivalent of the country component of <code>Locale</code>. | |
209 | * | |
210 | * @param country The new country value | |
211 | */ | |
212 | public void setCountry(String country) { | |
213 | 147 | this.country = country; |
214 | 147 | } |
215 | ||
216 | /** | |
217 | * Gets the equivalent of the variant component of <code>Locale</code>. | |
218 | * | |
219 | * @return The variant value | |
220 | */ | |
221 | public String getVariant() { | |
222 | 236 | return variant; |
223 | } | |
224 | ||
225 | /** | |
226 | * Sets the equivalent of the variant component of <code>Locale</code>. | |
227 | * | |
228 | * @param variant The new variant value | |
229 | */ | |
230 | public void setVariant(String variant) { | |
231 | 147 | this.variant = variant; |
232 | 147 | } |
233 | ||
234 | /** | |
235 | * Add a <code>Constant</code> to the locale level. | |
236 | * | |
237 | * @param name The constant name | |
238 | * @param value The constant value | |
239 | */ | |
240 | public void addConstant(String name, String value) { | |
241 | ||
242 | 20 | if (constants.containsKey(name)) { |
243 | 0 | getLog().error("Constant '" + name + "' already exists in FormSet[" |
244 | + this.displayKey() + "] - ignoring."); | |
245 | ||
246 | } else { | |
247 | 20 | constants.put(name, value); |
248 | } | |
249 | ||
250 | 20 | } |
251 | ||
252 | /** | |
253 | * Add a <code>Form</code> to the <code>FormSet</code>. | |
254 | * | |
255 | * @param f The form | |
256 | */ | |
257 | public void addForm(Form f) { | |
258 | ||
259 | 485 | String formName = f.getName(); |
260 | 485 | if (forms.containsKey(formName)) { |
261 | 0 | getLog().error("Form '" + formName + "' already exists in FormSet[" |
262 | + this.displayKey() + "] - ignoring."); | |
263 | ||
264 | } else { | |
265 | 485 | forms.put(f.getName(), f); |
266 | } | |
267 | ||
268 | 485 | } |
269 | ||
270 | /** | |
271 | * Retrieve a <code>Form</code> based on the form name. | |
272 | * | |
273 | * @param formName The form name | |
274 | * @return The form | |
275 | */ | |
276 | public Form getForm(String formName) { | |
277 | 176 | return this.forms.get(formName); |
278 | } | |
279 | ||
280 | /** | |
281 | * A <code>Map</code> of <code>Form</code>s is returned as an unmodifiable | |
282 | * <code>Map</code> with the key based on the form name. | |
283 | * | |
284 | * @return The forms map | |
285 | */ | |
286 | public Map<String, Form> getForms() { | |
287 | 80 | return Collections.unmodifiableMap(forms); |
288 | } | |
289 | ||
290 | /** | |
291 | * Processes all of the <code>Form</code>s. | |
292 | * | |
293 | * @param globalConstants Global constants | |
294 | */ | |
295 | synchronized void process(Map<String, String> globalConstants) { | |
296 | 151 | for (Iterator<Form> i = forms.values().iterator(); i.hasNext(); ) { |
297 | 485 | Form f = i.next(); |
298 | 485 | f.process(globalConstants, constants, forms); |
299 | 485 | } |
300 | ||
301 | 151 | processed = true; |
302 | 151 | } |
303 | ||
304 | /** | |
305 | * Returns a string representation of the object's key. | |
306 | * | |
307 | * @return A string representation of the key | |
308 | */ | |
309 | public String displayKey() { | |
310 | 0 | StringBuilder results = new StringBuilder(); |
311 | 0 | if (language != null && language.length() > 0) { |
312 | 0 | results.append("language="); |
313 | 0 | results.append(language); |
314 | } | |
315 | 0 | if (country != null && country.length() > 0) { |
316 | 0 | if (results.length() > 0) { |
317 | 0 | results.append(", "); |
318 | } | |
319 | 0 | results.append("country="); |
320 | 0 | results.append(country); |
321 | } | |
322 | 0 | if (variant != null && variant.length() > 0) { |
323 | 0 | if (results.length() > 0) { |
324 | 0 | results.append(", "); |
325 | } | |
326 | 0 | results.append("variant="); |
327 | 0 | results.append(variant ); |
328 | } | |
329 | 0 | if (results.length() == 0) { |
330 | 0 | results.append("default"); |
331 | } | |
332 | ||
333 | 0 | return results.toString(); |
334 | } | |
335 | ||
336 | /** | |
337 | * Returns a string representation of the object. | |
338 | * | |
339 | * @return A string representation | |
340 | */ | |
341 | @Override | |
342 | public String toString() { | |
343 | 0 | StringBuilder results = new StringBuilder(); |
344 | ||
345 | 0 | results.append("FormSet: language="); |
346 | 0 | results.append(language); |
347 | 0 | results.append(" country="); |
348 | 0 | results.append(country); |
349 | 0 | results.append(" variant="); |
350 | 0 | results.append(variant); |
351 | 0 | results.append("\n"); |
352 | ||
353 | 0 | for (Iterator<?> i = getForms().values().iterator(); i.hasNext(); ) { |
354 | 0 | results.append(" "); |
355 | 0 | results.append(i.next()); |
356 | 0 | results.append("\n"); |
357 | } | |
358 | ||
359 | 0 | return results.toString(); |
360 | } | |
361 | ||
362 | /** | |
363 | * Accessor method for Log instance. | |
364 | * | |
365 | * The Log instance variable is transient and | |
366 | * accessing it through this method ensures it | |
367 | * is re-initialized when this instance is | |
368 | * de-serialized. | |
369 | * | |
370 | * @return The Log instance. | |
371 | */ | |
372 | private Log getLog() { | |
373 | 0 | if (log == null) { |
374 | 0 | log = LogFactory.getLog(FormSet.class); |
375 | } | |
376 | 0 | return log; |
377 | } | |
378 | } |