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: * $Header:$
018: */
019: package org.apache.beehive.netui.compiler.model.validation;
020:
021: import org.apache.beehive.netui.compiler.model.XmlElementSupport;
022: import org.apache.beehive.netui.compiler.model.XmlModelWriter;
023: import org.apache.beehive.netui.compiler.model.XmlModelWriterException;
024: import org.apache.beehive.netui.compiler.JpfLanguageConstants;
025: import org.apache.beehive.netui.compiler.FatalCompileTimeException;
026: import org.w3c.dom.Element;
027:
028: import java.io.File;
029: import java.io.IOException;
030: import java.io.PrintWriter;
031: import java.util.List;
032: import java.util.Map;
033: import java.util.Locale;
034: import java.util.HashMap;
035: import java.util.ArrayList;
036: import java.util.Collection;
037: import java.util.Iterator;
038:
039: public abstract class ValidationModel extends XmlElementSupport
040: implements JpfLanguageConstants {
041: private Map _localeSets = new HashMap();
042: private LocaleSet _defaultLocaleSet = new LocaleSet();
043: private List _rulesToAddForAllLocales = new ArrayList(); // list of RuleAdd
044: private boolean _empty = true;
045: private ValidatorVersion _validatorVersion = ValidatorVersion.oneOne;
046:
047: public static class ValidatorVersion {
048: private static final int INT_ONE_ZERO = 0;
049: private static final int INT_ONE_ONE = 1;
050:
051: private int _val;
052:
053: private ValidatorVersion(int val) {
054: _val = val;
055: }
056:
057: public boolean equals(ValidatorVersion vv) {
058: return _val == vv._val;
059: }
060:
061: public static final ValidatorVersion oneZero = new ValidatorVersion(
062: INT_ONE_ZERO);
063: public static final ValidatorVersion oneOne = new ValidatorVersion(
064: INT_ONE_ONE);
065: }
066:
067: public static class RuleInfo {
068: private String _entityName;
069: private String _fieldName;
070: private String _fieldDisplayName;
071: private String _fieldDisplayNameKey;
072:
073: public RuleInfo(String entityName, String fieldName,
074: String fieldDisplayName, String fieldDisplayNameKey) {
075: _entityName = entityName;
076: _fieldName = fieldName;
077: _fieldDisplayName = fieldDisplayName;
078: _fieldDisplayNameKey = fieldDisplayNameKey;
079: }
080:
081: public String getEntityName() {
082: return _entityName;
083: }
084:
085: public String getFieldName() {
086: return _fieldName;
087: }
088:
089: public String getFieldDisplayName() {
090: return _fieldDisplayName;
091: }
092:
093: public String getFieldDisplayNameKey() {
094: return _fieldDisplayNameKey;
095: }
096: }
097:
098: private static class RuleAdd {
099: public RuleAdd(RuleInfo ruleInfo, ValidatorRule rule) {
100: this .ruleInfo = ruleInfo;
101: this .rule = rule;
102: }
103:
104: public RuleInfo ruleInfo;
105: public ValidatorRule rule;
106: }
107:
108: public ValidatorVersion getValidatorVersion() {
109: return _validatorVersion;
110: }
111:
112: public void setValidatorVersion(String validatorVersion) {
113: //
114: // default to the least common denominator (validator v1.0) unless
115: // explicitly set to v1.1.
116: //
117: if (validatorVersion != null
118: && validatorVersion
119: .equals(VALIDATOR_VERSION_ONE_ONE_STR)) {
120: _validatorVersion = ValidatorVersion.oneOne;
121: } else {
122: _validatorVersion = ValidatorVersion.oneZero;
123: }
124: }
125:
126: public void addFieldRuleForAllLocales(RuleInfo ruleInfo,
127: ValidatorRule rule) {
128: _rulesToAddForAllLocales.add(new RuleAdd(ruleInfo, rule));
129: }
130:
131: public void addFieldRule(RuleInfo ruleInfo, ValidatorRule rule,
132: Locale locale) {
133: LocaleSet localeSet = null;
134:
135: if (locale == null) // default locale
136: {
137: localeSet = _defaultLocaleSet;
138: } else {
139: localeSet = (LocaleSet) _localeSets.get(locale);
140:
141: if (localeSet == null) {
142: localeSet = new LocaleSet(locale);
143: _localeSets.put(locale, localeSet);
144: }
145:
146: //
147: // The Commons Validator uses specific locale rules for a field only if there
148: // is a rule for the same field in the default formset. Therefor, we need to
149: // keep a place holder for each locale specific field we find in the default
150: // formset entity so that the Commons Validator will behave as desired.
151: //
152: if (getField(ruleInfo, _defaultLocaleSet) == null) {
153: //
154: // create a simple placeholder for the field, without any rules
155: //
156: addFieldRule(ruleInfo, (ValidatorRule) null,
157: _defaultLocaleSet);
158: }
159: }
160:
161: addFieldRule(ruleInfo, rule, localeSet);
162: }
163:
164: private ValidatableField getField(RuleInfo ruleInfo,
165: LocaleSet localeSet) {
166: String entityName = ruleInfo.getEntityName();
167: ValidatableEntity entity = localeSet.getEntity(entityName);
168: if (entity == null) {
169: return null;
170: }
171:
172: String fieldName = ruleInfo.getFieldName();
173: return entity.getField(fieldName);
174: }
175:
176: private boolean hasFieldRule(RuleInfo ruleInfo, ValidatorRule rule,
177: LocaleSet localeSet) {
178: ValidatableField field = getField(ruleInfo, localeSet);
179: if (field == null) {
180: return false;
181: }
182:
183: return field.hasRule(rule);
184: }
185:
186: private void addFieldRule(RuleInfo ruleInfo, ValidatorRule rule,
187: LocaleSet localeSet) {
188: String entityName = ruleInfo.getEntityName();
189: ValidatableEntity entity = localeSet.getEntity(entityName);
190: if (entity == null)
191: localeSet
192: .addValidatableEntity(entity = new ValidatableEntity(
193: entityName));
194:
195: String fieldName = ruleInfo.getFieldName();
196: ValidatableField field = entity.getField(fieldName);
197: if (field == null) {
198: field = new ValidatableField(fieldName, ruleInfo
199: .getFieldDisplayName(), ruleInfo
200: .getFieldDisplayNameKey(), !getValidatorVersion()
201: .equals(ValidatorVersion.oneZero));
202: entity.addField(field);
203: }
204:
205: //
206: // A field element without rules is OK, but we don't want to add a null rule.
207: //
208: if (rule != null) {
209: field.addRule(rule);
210: }
211: }
212:
213: public void writeXml(PrintWriter writer, File mergeFile)
214: throws IOException, FatalCompileTimeException,
215: XmlModelWriterException {
216: //
217: // First, if we haven't written the all-locale rules to each locale, do so now.
218: // However, before we add a rule, check that it does not already exist. We don't
219: // want to overload a rule explicitly defined for a specific locale with
220: // an all-locale rule of the same name.
221: //
222: if (_rulesToAddForAllLocales != null) {
223: for (int i = 0; i < _rulesToAddForAllLocales.size(); i++) {
224: RuleAdd ruleAdd = (RuleAdd) _rulesToAddForAllLocales
225: .get(i);
226:
227: for (Iterator j = _localeSets.values().iterator(); j
228: .hasNext();) {
229: LocaleSet localeSet = (LocaleSet) j.next();
230: if (!hasFieldRule(ruleAdd.ruleInfo, ruleAdd.rule,
231: localeSet)) {
232: addFieldRule(ruleAdd.ruleInfo, ruleAdd.rule,
233: localeSet);
234: }
235: }
236:
237: if (!hasFieldRule(ruleAdd.ruleInfo, ruleAdd.rule,
238: _defaultLocaleSet)) {
239: addFieldRule(ruleAdd.ruleInfo, ruleAdd.rule,
240: _defaultLocaleSet);
241: }
242: }
243:
244: _rulesToAddForAllLocales = null;
245: }
246:
247: String publicID;
248: String systemID;
249:
250: if (_validatorVersion.equals(ValidatorVersion.oneZero)) {
251: publicID = "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.0//EN";
252: systemID = "http://jakarta.apache.org/commons/dtds/validator_1_0.dtd";
253: } else {
254: publicID = "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1//EN";
255: systemID = "http://jakarta.apache.org/commons/dtds/validator_1_1.dtd";
256: }
257:
258: String comment = getHeaderComment(mergeFile);
259: XmlModelWriter xw = new XmlModelWriter(mergeFile,
260: "form-validation", publicID, systemID, comment);
261: writeXML(xw, xw.getRootElement());
262: xw.simpleFastWrite(writer);
263: }
264:
265: protected void writeToElement(XmlModelWriter xw, Element element) {
266: //
267: // Now write out all the LocaleSets, which contain the forms/fields/rules.
268: //
269: writeLocaleSets(xw, element);
270: writeLocaleSet(xw, element, _defaultLocaleSet);
271: }
272:
273: protected String getHeaderComment(File mergeFile)
274: throws FatalCompileTimeException {
275: return null;
276: }
277:
278: private void writeLocaleSets(XmlModelWriter xw, Element element) {
279: //
280: // Commons Validator behavior is to build a key from the locale of a FormSet
281: // or uses the default Locale (Locale.getDefault() - the system locale) to
282: // track different elements. This implies that the
283: // without language or country attributes could be mapped to "en_US"
284: // if that's the default locale.
285: // See org.apache.commons.validator.ValidatorResources.buildKey()
286: //
287: // Therefor, to ensure the validator uses rules for of a specific
288: // locale before the FormSet with no language or country attributes (even
289: // if it is the locale of the system), write the most specific locales first.
290: //
291: List allLocales = new ArrayList(_localeSets.keySet());
292: List langCountryVariant = new ArrayList();
293: List langCountry = new ArrayList();
294: List lang = new ArrayList();
295:
296: for (java.util.Iterator ii = allLocales.iterator(); ii
297: .hasNext();) {
298: Locale locale = (Locale) ii.next();
299: if (locale.getCountry().length() > 0) {
300: if (locale.getVariant().length() > 0) {
301: langCountryVariant.add(locale);
302: } else {
303: langCountry.add(locale);
304: }
305: } else {
306: lang.add(locale);
307: }
308: }
309:
310: writeLocaleSets(xw, element, langCountryVariant);
311: writeLocaleSets(xw, element, langCountry);
312: writeLocaleSets(xw, element, lang);
313: }
314:
315: private void writeLocaleSets(XmlModelWriter xw, Element element,
316: Collection locales) {
317: for (java.util.Iterator ii = locales.iterator(); ii.hasNext();) {
318: Locale locale = (Locale) ii.next();
319: LocaleSet localeSet = (LocaleSet) _localeSets.get(locale);
320: writeLocaleSet(xw, element, localeSet);
321: }
322: }
323:
324: private void writeLocaleSet(XmlModelWriter xw, Element element,
325: LocaleSet localeSet) {
326: Locale locale = localeSet.getLocale();
327: Element formSetElement = null;
328:
329: if (locale == null) {
330: formSetElement = findChildElement(xw, element, "formset",
331: "language", null, false, null);
332: } else {
333: Element possibleMatch = findChildElement(xw, element,
334: "formset", "language", locale.getLanguage());
335: if (possibleMatch != null) {
336: String country = getElementAttribute(possibleMatch,
337: "country");
338: String variant = getElementAttribute(possibleMatch,
339: "variant");
340: String localeCountry = locale.getCountry();
341: String localeVariant = locale.getVariant();
342:
343: if (((localeCountry.length() == 0 && country == null) || localeCountry
344: .equals(country))
345: && ((localeVariant.length() == 0 && variant == null) || localeVariant
346: .equals(variant))) {
347: formSetElement = possibleMatch;
348: }
349: }
350: }
351:
352: if (formSetElement == null) {
353: formSetElement = xw.addElement(element, "formset");
354: }
355:
356: localeSet.writeXML(xw, formSetElement);
357: }
358:
359: public boolean isEmpty() {
360: return _empty;
361: }
362:
363: protected void setEmpty(boolean empty) {
364: _empty = empty;
365: }
366:
367: public abstract String getOutputFileURI();
368: }
|