001: /*
002: * Copyright 2007 Dan Shellman
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.iscreen.impl;
017:
018: import java.util.Collection;
019: import java.util.HashSet;
020: import java.util.Locale;
021: import java.util.Set;
022:
023: import org.iscreen.ConfigurationException;
024: import org.iscreen.DocumentationIterator;
025: import org.iscreen.ValidationService;
026: import org.iscreen.Validator;
027:
028: /**
029: * This base class represents a wrapper around a validator that handles the actual call
030: * to the validator. This class is subclassed by OGNL or MVEL to handle the actual
031: * interpretation of how to handle mappings, etc.
032: *
033: * @author Shellman, Dan
034: */
035: public abstract class BaseConfiguredValidator implements
036: ValidatorWrapper {
037: protected ValidationService containingService;
038: protected boolean failFastFlag = false;
039: protected String id;
040: protected ResourceValue label;
041: protected String doc;
042: protected String parsedDoc;
043: protected Set mappings = new HashSet();
044: protected String name;
045: protected BaseConfiguredValidator ref;
046: protected Set staticProperties = new HashSet();
047: protected Validator validator;
048: protected Class validatorClass;
049:
050: /**
051: * Default constructor.
052: */
053: public BaseConfiguredValidator() {
054: } //end BaseConfiguredValidator()
055:
056: /**
057: * Adds a mapping for mapping the object being validated to the
058: * beanToValidate object (that the Validator created).
059: *
060: * @param from The OGNL from expression (getter)
061: * @param to The OGNL to expression (setter)
062: */
063: public abstract void addMapping(String from, String to);
064:
065: /**
066: * Adds a "static" property to set on the underlying Validator. A
067: * "static" property is really an OGNL expression that will set
068: * some value on the Validator once (such as a constraint, service,
069: * or failure message).<br />
070: * <br />
071: * For failures, the object type should be an OgnlMessage. For
072: * a constraint or service, any object type is fine (as long as it
073: * maps to the underlying Validator property).
074: *
075: * @param property The OGNL expression to set a value
076: * @param obj The value to set, once, on the Validator to configure it.
077: */
078: public abstract void addStaticProperty(String property, Object obj);
079:
080: /**
081: * Maps the appropriate properties from one object to another.
082: *
083: *
084: * @param from The object to map from.
085: * @param to The object to map to.
086: */
087: protected abstract void executeMappings(Object from, Object to);
088:
089: /**
090: * Creates the Validator and configures it. Multiple calls will NOT
091: * construct a new Validator each call, but will return the same
092: * instance created the first time.
093: *
094: * @return Returns a created and configured Validator.
095: */
096: public abstract Validator getConfiguredValidator();
097:
098: /**
099: * Retrieves the Collection of fields (the 'getter' OGNL expressions)
100: * that are used in mapping properties from the JavaBean/Object being
101: * validated to the validation bean.
102: *
103: * @return Returns the Collection of fields.
104: */
105: protected abstract Collection getFields();
106:
107: /**
108: * Gets the id of this wrapper. If one hasn't been set, the
109: * validator this references will be returned. However, if there
110: * is no id, then an empty string is returned.
111: *
112: * @return Returns the id of this wrapper.
113: */
114: public String getId() {
115: if (id != null) {
116: return id;
117: } else if (ref != null) {
118: return ref.getId();
119: }
120:
121: return "";
122: } //end getId()
123:
124: /**
125: * Gets the value of the label for this Validator wrapper.
126: * Based upon the locale, the value of the label *may*
127: * be different (if a static one was set, then it
128: * won't be different from what was set).
129: *
130: * @return Returns the value of the label, based on
131: * the current locale.
132: */
133: public String getLabel(Locale locale) {
134: if (label != null) {
135: return label.getValue(locale);
136: }
137:
138: if (ref != null) {
139: return ref.getLabel(locale);
140: }
141:
142: //TODO: Should be this an empty string or null?
143: return "";
144: } //end getLabel()
145:
146: /**
147: * Gets the Set of mappings for this Validator and any Validator
148: * this Validator references.
149: *
150: * @return Returns the Set of mappings for this Validator.
151: */
152: public Set getMappings() {
153: Set allMappings = new HashSet();
154:
155: allMappings.addAll(mappings);
156: if (ref != null) {
157: allMappings.addAll(ref.getMappings());
158: }
159:
160: return allMappings;
161: } //end getMappings()
162:
163: public String getName() {
164: if (name != null) {
165: return name;
166: } else if (ref != null) {
167: return ref.getName();
168: }
169:
170: return "";
171: } //end getName()
172:
173: /**
174: * Retrieves the Set of static properties (which are OgnlPropertyMapping
175: * objects). This method is used to retrieve not only this wrapper's
176: * Set of static properties (see the addStaticProperty() method for
177: * what a static property is), but to also get the properties from
178: * any wrapper that this wrapper references, returning a combined
179: * Set (it's a Set to ensure that there are no duplicates based upon
180: * the property, or OGNL expression, of the OgnlPropertyMapping objects).
181: *
182: * @return Returns the Set of "static" properties for this wrapper and
183: * any referenced wrapper (no duplicates, though).
184: */
185: public Set getStaticProperties() {
186: Set set = new HashSet();
187:
188: set.addAll(staticProperties);
189: if (ref != null) {
190: set.addAll(ref.getStaticProperties());
191: }
192:
193: return set;
194: } //end getStaticProperties()
195:
196: /**
197: * Returns the Class of the Validator this class is wrapping (this may
198: * retrieve the Class from another wrapper this wrapper references).
199: *
200: * @return Returns the Validator this class is wrapping.
201: */
202: public Class getValidatorClass() {
203: if (validatorClass != null) {
204: return validatorClass;
205: }
206:
207: if (ref != null) {
208: return ref.getValidatorClass();
209: }
210:
211: throw new ConfigurationException(
212: "No class name defined for validator with id "
213: + getId() + " in Validation Set named "
214: + getServiceId());
215: } //end getValidatorClass()
216:
217: /**
218: * Whether this wrapper should report to the validation service
219: * not to continue validating if this wrapper finds a failure.
220: *
221: * @return Returns if a failure will result in no further validations.
222: */
223: public boolean isFailFast() {
224: return failFastFlag;
225: }
226:
227: /**
228: * Sets the class name of the Validator this class is wrapping.
229: *
230: * @param className The class name of the Validator
231: */
232: public void setClassName(String className) {
233: if (className != null && !className.trim().equals("")) {
234: try {
235: validatorClass = Class.forName(className);
236: } catch (ClassNotFoundException e) {
237: throw new ConfigurationException(
238: "Invalid validator class named " + className, e);
239: }
240: } else {
241: validatorClass = null;
242: }
243: } //end setClassName()
244:
245: /**
246: * Sets whether this wrapper should report to the validation service
247: * not to continue validating if this wrapper finds a failure.
248: *
249: * @param flag If true, a failure will result in no further validations.
250: */
251: public void setFailFast(boolean flag) {
252: failFastFlag = flag;
253: } //end setFailFast()
254:
255: /**
256: * Sets the id of this wrapper. A Validator may or may not
257: * have an id. If this wrapper represents a configured validator
258: * that's configured as part of a validation set, then it won't
259: * have an id.
260: *
261: * @param theId The id of this wrapper.
262: */
263: public void setId(String theId) {
264: id = theId;
265: } //end setId()
266:
267: /**
268: * Sets the Label for this Validator wrapper. This label is
269: * based upon a Resource and a key into that resource.
270: *
271: * @param resource The Resource the label's value is in
272: * @param key The key to the label's value
273: */
274: public void setLabel(Resource resource, String key) {
275: label = new ResourceValue(resource, key);
276: } //end setLabel()
277:
278: /**
279: * Sets the label for this Validator wrapper. This label
280: * is a static string.
281: *
282: * @param labelValue The value of the label.
283: */
284: public void setLabel(String labelValue) {
285: label = new ResourceValue(labelValue);
286: } //end setLabel()
287:
288: /**
289: * Sets the name of the validator. This name is a non-unique identifier
290: * used to report back on validation failures the validator that
291: * was involved in the failure.
292: *
293: * @param theName The name of the validator.
294: */
295: public void setName(String theName) {
296: name = theName;
297: } //end setName()
298:
299: /**
300: * Sets the documentation for this configured validator.
301: *
302: * @param documentation The documentation for this validator.
303: */
304: public void setDoc(String documentation) {
305: doc = documentation;
306: } //end setDoc()
307:
308: /**
309: * Retrieves the documentation (parsed and updated) for this validator.
310: *
311: * @return Returns the documentation for this validator.
312: */
313: public DocumentationIterator getDoc() {
314: DocumentationIterator it = new DocumentationIterator();
315: String convertedDoc;
316:
317: if (parsedDoc != null) {
318: it.addItem(parsedDoc, getName());
319: } else {
320: String rawDoc;
321:
322: rawDoc = getRawDoc();
323: if (rawDoc != null) {
324: ContextBean bean = new ContextBean();
325:
326: bean.setValidator(getConfiguredValidator());
327: bean.setLabel(getLabel(Locale.getDefault()));
328: bean.setFields(getFields());
329:
330: parsedDoc = convertDoc(bean, rawDoc);
331: it.addItem(parsedDoc, getName());
332: }
333: }
334:
335: return it;
336: } //end getDoc()
337:
338: /**
339: * Sets a wrapper this wrapper may reference. Consider this reference
340: * as a delegated parent.
341: *
342: * @param configuredValidatorRef The delegated parent of this wrapper.
343: */
344: public void setRef(BaseConfiguredValidator configuredValidatorRef) {
345: ref = configuredValidatorRef;
346: } //end setRef()
347:
348: /**
349: * Sets the ValidationService (ValidationSet) that contains this
350: * Validator wrapper.
351: *
352: * @param service The ValidationService that contains this wrapper.
353: */
354: public void setValidationService(ValidationService service) {
355: containingService = service;
356: } //end setValidationService()
357:
358: public boolean validate(InternalValidatorContext context,
359: ContextBean contextBean, Object obj) {
360: boolean continueFlag = true;
361: Validator configuredValidator;
362: Object beanToValidate;
363: int failureCount = 0;
364:
365: failureCount = context.getFailureCount();
366:
367: //Update the OGNL contextBean object with those properties it's supposed to have.
368: contextBean.setLabel(getLabel(context.getLocale()));
369: contextBean.setFields(getFields());
370:
371: configuredValidator = getConfiguredValidator();
372: contextBean.setValidator(configuredValidator);
373: beanToValidate = configuredValidator.constructBeanToValidate();
374:
375: //Map the bean being validated to the bean that is actually sent to the
376: //validator. Then, validate it.
377: executeMappings(obj, beanToValidate);
378: configuredValidator.validate(context, beanToValidate);
379:
380: //If there were failures and the fail-fast flag is set, then return
381: //false so that no more validation will continue.
382: if (failFastFlag && context.getFailureCount() > failureCount) {
383: continueFlag = false;
384: }
385:
386: //Make sure to null this out so that it can't be accessed outside
387: //of the context of the actual validation by the validator.
388: contextBean.setValidator(null);
389:
390: return continueFlag;
391: } //end validate()
392:
393: // ***
394: // Protected methods
395: // ***
396:
397: protected String getServiceId() {
398: if (containingService != null) {
399: return containingService.getServiceName();
400: }
401:
402: return "UNKNOWN";
403: } //end getServiceId()
404:
405: /**
406: * Convert the documentation text using the embedded markers.
407: *
408: * @param contextBean The context bean (root) for converting the doc.
409: * @param unconvertedDoc The raw documentation text.
410: *
411: * @return Returns the converted documentation text.
412: */
413: protected abstract String convertDoc(Object contextBean,
414: String unconvertedDoc);
415:
416: /**
417: * Retrieves the raw documentation for this. The referenced validator is
418: * also checked, if necessary.
419: *
420: * @return Returns the raw documentation.
421: */
422: protected String getRawDoc() {
423: if (doc != null) {
424: return doc;
425: } else if (ref != null) {
426: return ref.getRawDoc();
427: }
428:
429: return null;
430: } //end getRawDoc()
431: } //end BaseConfiguredValidator
|