001: /**
002: * $Id: AnnotationValidatorPlugIn.java,v 1.1 2006/06/07 06:20:13 pieterdegr Exp $
003: * Copyright (C) 2005 carambacomponents.org
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */package org.caramba.validator;
019:
020: import org.apache.commons.lang.StringUtils;
021: import org.apache.commons.logging.Log;
022: import org.apache.commons.logging.LogFactory;
023: import org.caramba.CarambaServlet;
024: import org.caramba.annotations.AnnotationUtil;
025: import org.caramba.annotations.ComponentId;
026: import org.caramba.components.Component;
027: import org.caramba.config.CarambaConfig;
028: import org.caramba.config.PageConfig;
029: import org.caramba.config.PanelConfig;
030: import org.caramba.plugin.PlugIn;
031: import org.caramba.util.PropertyUtil;
032:
033: import javax.servlet.ServletException;
034: import java.lang.annotation.Annotation;
035: import java.lang.reflect.Field;
036: import java.lang.reflect.InvocationTargetException;
037: import java.lang.reflect.Method;
038: import java.util.List;
039:
040: /**
041: * @author Pieter Degraeuwe
042: */
043: public class AnnotationValidatorPlugIn implements PlugIn {
044:
045: /**
046: * Commons Logging instance.
047: */
048: private static final transient Log log = LogFactory
049: .getLog(AnnotationValidatorPlugIn.class);
050:
051: /**
052: * The {@link org.caramba.CarambaServlet} owning this application.
053: */
054: private CarambaServlet servlet = null;
055:
056: // ------------------------------------------------------------- Properties
057:
058: /**
059: * A comma delimitted list of Validator resources.
060: */
061: private ValidatorConfig validatorConfig = new ValidatorConfig();
062:
063: /**
064: * Initialize and load our resources.
065: *
066: * @param servlet The CarambaServlet for our application
067: * @param carambaConfig The CarambaConfig for our owning module
068: * @throws javax.servlet.ServletException if we cannot configure ourselves correctly
069: */
070: public void init(CarambaServlet servlet, CarambaConfig carambaConfig)
071: throws ServletException {
072: try {
073: PageConfig[] pageConfigs = carambaConfig.getPageConfigs();
074: for (int i = 0; i < pageConfigs.length; i++) {
075: PageConfig pageConfig = pageConfigs[i];
076: String className = pageConfig.getClassName();
077: Class<?> aClass = Class.forName(className);
078:
079: List<Field> fields = AnnotationUtil
080: .getAllDeclaredFields(aClass);
081: for (int j = 0; j < fields.size(); j++) {
082: Field field = fields.get(j);
083: if (Component.class.isAssignableFrom(field
084: .getType())) {
085: ComponentId componentIdAnnotation = field
086: .getAnnotation(ComponentId.class);
087: String componentId = field.getName();
088: if (componentIdAnnotation != null) {
089: componentId = componentIdAnnotation.value();
090: }
091: ValidatorSet vs = getValidatorSet(field);
092: if (vs != null) {
093: validatorConfig.addPageValidatorSet(
094: pageConfig.getName(), componentId,
095: vs);
096: pageConfig
097: .addPageLifeCycleListener(new EnableComponentValidationListener(
098: componentId));
099: }
100:
101: ValidateBeforeClickEvent validateAllBeforeFireEventAnnotation = field
102: .getAnnotation(ValidateBeforeClickEvent.class);
103: if (validateAllBeforeFireEventAnnotation != null) {
104: pageConfig
105: .addPageLifeCycleListener(new AddAbsorbingValidationTrigger(
106: componentId,
107: validateAllBeforeFireEventAnnotation
108: .validatingComponentIds()));
109:
110: }
111:
112: }
113: }
114: }
115: PanelConfig[] panelConfigs = carambaConfig
116: .getPanelConfigs();
117: for (int i = 0; i < panelConfigs.length; i++) {
118: PanelConfig panelConfig = panelConfigs[i];
119: String className = panelConfig.getClassName();
120: Field[] fields = Class.forName(className)
121: .getDeclaredFields();
122: for (int j = 0; j < fields.length; j++) {
123: Field field = fields[j];
124: if (Component.class.isAssignableFrom(field
125: .getType())) {
126: ComponentId componentIdAnnotation = field
127: .getAnnotation(ComponentId.class);
128: String componentId = field.getName();
129: if (componentIdAnnotation != null) {
130: componentId = componentIdAnnotation.value();
131: }
132: ValidatorSet vs = getValidatorSet(field);
133: if (vs != null) {
134: validatorConfig.addPanelValidatorSet(
135: panelConfig.getName(), componentId,
136: vs);
137: panelConfig
138: .addComponentLifeCycleListener(new EnableComponentValidationListener(
139: componentId));
140: }
141:
142: ValidateBeforeClickEvent validateAllBeforeFireEventAnnotation = field
143: .getAnnotation(ValidateBeforeClickEvent.class);
144: if (validateAllBeforeFireEventAnnotation != null) {
145: panelConfig
146: .addComponentLifeCycleListener(new AddAbsorbingValidationTrigger(
147: componentId,
148: validateAllBeforeFireEventAnnotation
149: .validatingComponentIds()));
150:
151: }
152:
153: }
154: }
155: }
156:
157: } catch (ClassNotFoundException e) {
158: e.printStackTrace();
159: }
160: servlet.getServletContext().setAttribute(
161: ValidatorUtil.VALIDATOR_CONFIG_ATTRIBUTE,
162: validatorConfig);
163: log.info("ValidatorConfig saved to servletContext");
164: }
165:
166: public ValidatorSet getValidatorSet(Field pField) {
167: ValidatorSet vs = new ValidatorSet();
168: Annotation[] annotations = pField.getAnnotations();
169:
170: ValidatorSettings settingsAnnotation = pField
171: .getAnnotation(ValidatorSettings.class);
172: for (int i = 0; i < annotations.length; i++) {
173: if (settingsAnnotation != null) {
174: vs.setErrorsId(settingsAnnotation.errorsId());
175: }
176: Annotation annotation = annotations[i];
177: Validator validator = createValidatorFromAnnotation(pField,
178: annotation, settingsAnnotation);
179: //IF this annotation did result in a validator, check if this validator did override errorsId or fieldNameKey
180:
181: if (validator != null) {
182: overrideIfNeeded(vs, annotation);
183: vs.addValidator(validator);
184: }
185: }
186: return vs.getValidators().size() > 0 ? vs : null;
187: }
188:
189: private void overrideIfNeeded(ValidatorSet pVs,
190: Annotation pAnnotation) {
191: try {
192: Method errorsIdMethod = pAnnotation.getClass().getMethod(
193: "errorsId");
194: String errorsId = (String) errorsIdMethod
195: .invoke(pAnnotation);
196: if (StringUtils.isNotEmpty(errorsId)) {
197: pVs.setErrorsId(errorsId);
198: }
199:
200: } catch (NoSuchMethodException e) {
201: e.printStackTrace();
202: } catch (IllegalAccessException e) {
203: e.printStackTrace();
204: } catch (InvocationTargetException e) {
205: e.printStackTrace();
206: }
207: }
208:
209: private String getAnnotationStringValue(Annotation pAnnotation,
210: String pValueName) {
211: String value = null;
212: try {
213: Method fieldNameKeyMethod = pAnnotation.getClass()
214: .getMethod(pValueName);
215: value = (String) fieldNameKeyMethod.invoke(pAnnotation);
216: } catch (Exception e) {
217: //
218: }
219: return value;
220: }
221:
222: private Boolean getAnnotationBooleanValue(Annotation pAnnotation,
223: String pValueName) {
224: Boolean value = null;
225: try {
226: Method fieldNameKeyMethod = pAnnotation.getClass()
227: .getMethod(pValueName);
228: value = (Boolean) fieldNameKeyMethod.invoke(pAnnotation);
229: } catch (Exception e) {
230: //
231: }
232: return value;
233: }
234:
235: /**
236: * Creates the required {@link Validator} instance for the given field, Annotation and ValidatorSettings.
237: * Override this method if you want to automatically support other Validator annotations than the default ones.
238: * Currently supported Validators: {@link Required},{@link MaxLength},{@link NumberRange},{@link MinLength},{@link RegexPattern},{@link Date},{@link CustomValidator}
239: *
240: * @param pField the field for which the validator must be created
241: * @param pAnnotation the annotation for which the Validator must be created
242: * @param pSettingsAnnotation the ValidatorSettings annotation (may be null)
243: * @return
244: */
245: protected Validator createValidatorFromAnnotation(Field pField,
246: Annotation pAnnotation,
247: ValidatorSettings pSettingsAnnotation) {
248: Validator retval = null;
249: String fieldNameKey = null;
250: String messageKey = null;
251:
252: Class aClass = pAnnotation.annotationType();
253: if (aClass.equals(Required.class)) {
254: RequiredValidator requiredValidator = new RequiredValidator();
255: retval = requiredValidator;
256: } else if (aClass.equals(MaxLength.class)) {
257: MaxLength maxLengthAnnotation = (MaxLength) pAnnotation;
258: MaxLengthValidator tmp = new MaxLengthValidator();
259: tmp.setMaxLength(maxLengthAnnotation.maxLength());
260: retval = tmp;
261: } else if (aClass.equals(MaxLength.class)) {
262: NumberRange numberRangeAnnotation = (NumberRange) pAnnotation;
263: NumberRangeValidator tmp = new NumberRangeValidator();
264: tmp.setFrom(numberRangeAnnotation.from());
265: tmp.setTo(numberRangeAnnotation.to());
266: retval = tmp;
267: } else if (aClass.equals(MinLength.class)) {
268: MinLength minLengthAnnotation = (MinLength) pAnnotation;
269: MinLengthValidator tmp = new MinLengthValidator();
270: tmp.setMinLength(minLengthAnnotation.minLength());
271: retval = tmp;
272: } else if (aClass.equals(RegexPattern.class)) {
273: RegexPattern regexPatternAnnotation = (RegexPattern) pAnnotation;
274: RegexPatternValidator tmp = new RegexPatternValidator();
275: tmp.setPattern(regexPatternAnnotation.pattern());
276: retval = tmp;
277: } else if (aClass.equals(Date.class)) {
278: Date dateAnnotation = (Date) pAnnotation;
279: DateValidator tmp = new DateValidator();
280: tmp.setPattern(dateAnnotation.pattern());
281: retval = tmp;
282: } else if (aClass.equals(MinimumNumberOfItems.class)) {
283: MinimumNumberOfItems annotation = (MinimumNumberOfItems) pAnnotation;
284: MinimumNumberOfItemsInListBoxValidator tmp = new MinimumNumberOfItemsInListBoxValidator();
285: tmp.setMinimum(annotation.minLength());
286: retval = tmp;
287: } else if (aClass.equals(MaximumNumberOfItems.class)) {
288: MaximumNumberOfItems annotation = (MaximumNumberOfItems) pAnnotation;
289: MaximumNumberOfItemsInListBoxValidator tmp = new MaximumNumberOfItemsInListBoxValidator();
290: tmp.setMaximum(annotation.maxLength());
291: retval = tmp;
292: } else if (aClass.equals(CustomValidator.class)) {
293: CustomValidator customValidatorAnnotation = (CustomValidator) pAnnotation;
294: ValidatorProperty[] validatorProperties = customValidatorAnnotation
295: .properties();
296: Class aClass1 = customValidatorAnnotation.validatorClass();
297: try {
298: Validator validator = (Validator) aClass1.newInstance();
299: retval = validator;
300: for (int i = 0; i < validatorProperties.length; i++) {
301: ValidatorProperty validatorPropertyAnnotation = validatorProperties[i];
302: PropertyUtil.setPropertyAsText(validator,
303: validatorPropertyAnnotation.name(),
304: validatorPropertyAnnotation.value());
305: }
306: } catch (InstantiationException e) {
307: e.printStackTrace();
308: } catch (IllegalAccessException e) {
309: e.printStackTrace();
310: }
311:
312: }
313:
314: if (retval != null) {
315: fieldNameKey = getAnnotationStringValue(pAnnotation,
316: "fieldNameKey");
317: messageKey = getAnnotationStringValue(pAnnotation,
318: "messageKey");
319: }
320:
321: //If the fieldNamekey is not specified (it is empty) we must try to get it from the ValidatorSettings annotation
322: if (StringUtils.isEmpty(fieldNameKey)
323: && pSettingsAnnotation != null) {
324: fieldNameKey = pSettingsAnnotation.fieldNameKey();
325: }
326:
327: if (retval != null) {
328: retval.init(messageKey, fieldNameKey);
329: }
330:
331: return retval;
332: }
333:
334: /**
335: * Gracefully shut down, releasing any resources
336: * that were allocated at initialization.
337: */
338: public void destroy() {
339: // if (log.isDebugEnabled()) {
340: // log.debug("Destroying ValidatorPlugin");
341: // }
342: // servlet = null;
343: // destroyResources();
344: }
345:
346: /**
347: * Destroy <code>ValidatorResources</code>.
348: */
349: protected void destroyResources() {
350: servlet.getServletContext().removeAttribute(
351: ValidatorUtil.VALIDATOR_CONFIG_ATTRIBUTE);
352: this.validatorConfig = null;
353: }
354:
355: }
|