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: 478334 $ $Date: 2006-11-22 21:31:54 +0000 (Wed, 22 Nov 2006) $
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: } else if (getCountry() != null) {
122: if (getLanguage() == null) {
123: throw new NullPointerException(
124: "When country is specified, language must be specified.");
125: }
126: return COUNTRY_FORMSET;
127: } else if (getLanguage() != null) {
128: return LANGUAGE_FORMSET;
129: } else {
130: return GLOBAL_FORMSET;
131: }
132: }
133:
134: /**
135: * Merges the given <code>FormSet</code> into this one. If any of <code>depends</code>
136: * s <code>Forms</code> are not in this <code>FormSet</code> then, include
137: * them, else merge both <code>Forms</code>. Theoretically we should only
138: * merge a "parent" formSet.
139: *
140: * @param depends FormSet to be merged
141: * @since Validator 1.2.0
142: */
143: protected void merge(FormSet depends) {
144: if (depends != null) {
145: Map pForms = getForms();
146: Map dForms = depends.getForms();
147: for (Iterator it = dForms.keySet().iterator(); it.hasNext();) {
148: Object key = it.next();
149: Form pForm = (Form) pForms.get(key);
150: if (pForm != null) {//merge, but principal 'rules', don't overwrite
151: // anything
152: pForm.merge((Form) dForms.get(key));
153: } else {//just add
154: addForm((Form) dForms.get(key));
155: }
156: }
157: }
158: merged = true;
159: }
160:
161: /**
162: * Whether or not the this <code>FormSet</code> was processed for replacing
163: * variables in strings with their values.
164: *
165: * @return The processed value
166: */
167: public boolean isProcessed() {
168: return processed;
169: }
170:
171: /**
172: * Gets the equivalent of the language component of <code>Locale</code>.
173: *
174: * @return The language value
175: */
176: public String getLanguage() {
177: return language;
178: }
179:
180: /**
181: * Sets the equivalent of the language component of <code>Locale</code>.
182: *
183: * @param language The new language value
184: */
185: public void setLanguage(String language) {
186: this .language = language;
187: }
188:
189: /**
190: * Gets the equivalent of the country component of <code>Locale</code>.
191: *
192: * @return The country value
193: */
194: public String getCountry() {
195: return country;
196: }
197:
198: /**
199: * Sets the equivalent of the country component of <code>Locale</code>.
200: *
201: * @param country The new country value
202: */
203: public void setCountry(String country) {
204: this .country = country;
205: }
206:
207: /**
208: * Gets the equivalent of the variant component of <code>Locale</code>.
209: *
210: * @return The variant value
211: */
212: public String getVariant() {
213: return variant;
214: }
215:
216: /**
217: * Sets the equivalent of the variant component of <code>Locale</code>.
218: *
219: * @param variant The new variant value
220: */
221: public void setVariant(String variant) {
222: this .variant = variant;
223: }
224:
225: /**
226: * Add a <code>Constant</code> to the locale level.
227: *
228: * @param name The constant name
229: * @param value The constant value
230: */
231: public void addConstant(String name, String value) {
232:
233: if (constants.containsKey(name)) {
234: getLog().error(
235: "Constant '" + name
236: + "' already exists in FormSet["
237: + this .displayKey() + "] - ignoring.");
238:
239: } else {
240: constants.put(name, value);
241: }
242:
243: }
244:
245: /**
246: * Add a <code>Form</code> to the <code>FormSet</code>.
247: *
248: * @param f The form
249: */
250: public void addForm(Form f) {
251:
252: String formName = f.getName();
253: if (forms.containsKey(formName)) {
254: getLog().error(
255: "Form '" + formName
256: + "' 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: }
|