package org.springmodules.validation.bean.conf.loader.annotation; import java.beans.PropertyDescriptor; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springmodules.validation.bean.conf.loader.annotation.handler.ClassValidationAnnotationHandler; import org.springmodules.validation.bean.conf.loader.annotation.handler.MethodValidationAnnotationHandler; import org.springmodules.validation.bean.conf.loader.annotation.handler.PropertyValidationAnnotationHandler; import org.springmodules.validation.util.cel.ConditionExpressionBased; import org.springmodules.validation.util.cel.ConditionExpressionParser; import org.springmodules.validation.util.cel.valang.ValangConditionExpressionParser; import org.springmodules.validation.util.context.BasicContextAware; import org.springmodules.validation.util.fel.FunctionExpressionBased; import org.springmodules.validation.util.fel.FunctionExpressionParser; import org.springmodules.validation.util.fel.parser.ValangFunctionExpressionParser; /** * A simple implementation of {@link ValidationAnnotationHandlerRegistry} that enableds registration of annotation * handlers. * * @author Uri Boness */ public class SimpleValidationAnnotationHandlerRegistry extends BasicContextAware implements ValidationAnnotationHandlerRegistry, InitializingBean, ConditionExpressionBased, FunctionExpressionBased { private final static Log logger = LogFactory.getLog(SimpleValidationAnnotationHandlerRegistry.class); private List<ClassValidationAnnotationHandler> classHandlers; private List<PropertyValidationAnnotationHandler> propertyHandlers; private List<MethodValidationAnnotationHandler> methodHandlers; private boolean conditionExpressionParserSet = false; private ConditionExpressionParser conditionExpressionParser; private boolean functionExpressionParserSet = false; private FunctionExpressionParser functionExpressionParser; /** * Constructs a new DefaultValidationAnnotationHandlerRegistry. */ public SimpleValidationAnnotationHandlerRegistry() { classHandlers = new ArrayList<ClassValidationAnnotationHandler>(); propertyHandlers = new ArrayList<PropertyValidationAnnotationHandler>(); methodHandlers = new ArrayList<MethodValidationAnnotationHandler>(); conditionExpressionParser = new ValangConditionExpressionParser(); functionExpressionParser = new ValangFunctionExpressionParser(); } /** * @see org.springmodules.validation.bean.conf.loader.annotation.ValidationAnnotationHandlerRegistry#findClassHanlder(java.lang.annotation.Annotation, Class) */ public ClassValidationAnnotationHandler findClassHanlder(Annotation annotation, Class clazz) { for (ClassValidationAnnotationHandler handler : classHandlers) { if (handler.supports(annotation, clazz)) { return handler; } } return null; } /** * @see ValidationAnnotationHandlerRegistry#findPropertyHanlder(java.lang.annotation.Annotation, Class, java.beans.PropertyDescriptor) */ public PropertyValidationAnnotationHandler findPropertyHanlder(Annotation annotation, Class clazz, PropertyDescriptor descriptor) { for (PropertyValidationAnnotationHandler handler : propertyHandlers) { if (handler.supports(annotation, clazz, descriptor)) { return handler; } } return null; } /** * @see ValidationAnnotationHandlerRegistry#findMethodHandler(java.lang.annotation.Annotation, Class, java.lang.reflect.Method) */ public MethodValidationAnnotationHandler findMethodHandler(Annotation annotation, Class clazz, Method method) { for (MethodValidationAnnotationHandler handler : methodHandlers) { if (handler.supports(annotation, clazz, method)) { return handler; } } return null; } //=============================================== Setter/Getter ==================================================== /** * Registers the given class validation annotation handler with this registry. The newly added handler will have * precedence over the already registered handlers, that is, for every annotation, this handler will be checked * for support before the already registered handlers. * * @param handler The class validation annoation handler to be registered. */ public void registerClassHandler(ClassValidationAnnotationHandler handler) { classHandlers.add(0, handler); } /** * Registers the given class validation annoation handlers to the registry. These handlers will have precedence * over the already registered handlers, that is, for every annotation, these handlers will be check for suppport * before the already registered ones. The order of the given handler list is important for it determines the * precedence of the handlers within this list. * * @param handlers The extra class validation annotation handlers to register with this registry. */ public void setExtraClassHandlers(List<ClassValidationAnnotationHandler> handlers) { Collections.reverse(handlers); for (ClassValidationAnnotationHandler handler : handlers) { registerClassHandler(handler); } } /** * Registers the given property validation annoation handler with this registry. The newly added handler will have * precedence over the already registered handlers, that is, for every annotation, this handler will be checked * for support before the already registered handlers. * * @param handler The property validation annoation handler to be registered. */ public void registerPropertyHandler(PropertyValidationAnnotationHandler handler) { propertyHandlers.add(0, handler); } /** * Registers the given property validation annoation handlers to the registry. These handlers will have precedence * over the already registered handlers, that is, for every annotation, these handlers will be check for suppport * before the already registered ones. The order of the given handler list is important for it determines the * precedence of the handlers within this list. * * @param handlers The extra property validation annotation handlers to register with this registry. */ public void setExtraPropertyHandlers(List<PropertyValidationAnnotationHandler> handlers) { Collections.reverse(handlers); for (PropertyValidationAnnotationHandler handler : handlers) { registerPropertyHandler(handler); } } /** * Registers the given method validation annotation handler with this registry. The newly added handler will have * precedence over the already registered handlers, that is, for every annotation, this handler wil be checked * for support before the already registered ones. * * @param handler The method validation annotation handler to be registered. */ public void registerMethodHandler(MethodValidationAnnotationHandler handler) { methodHandlers.add(0, handler); } /** * Registers the given method validation annoation handlers to the registry. These handlers will have precedence * over the already registered handlers, that is, for every annotation, these handlers will be check for suppport * before the already registered ones. The order of the given handler list is important for it determines the * precedence of the handlers within this list. * * @param handlers The extra method validation annotation handlers to register with this registry. */ public void setExtraMethodHandlers(List<MethodValidationAnnotationHandler> handlers) { Collections.reverse(handlers); for (MethodValidationAnnotationHandler handler : handlers) { registerMethodHandler(handler); } } /** * @see org.springmodules.validation.util.cel.ConditionExpressionBased#setConditionExpressionParser(org.springmodules.validation.util.cel.ConditionExpressionParser) */ public void setConditionExpressionParser(ConditionExpressionParser conditionExpressionParser) { this.conditionExpressionParser = conditionExpressionParser; } /** * @see org.springmodules.validation.util.fel.FunctionExpressionBased#setFunctionExpressionParser(org.springmodules.validation.util.fel.FunctionExpressionParser) */ public void setFunctionExpressionParser(FunctionExpressionParser functionExpressionParser) { this.functionExpressionParser = functionExpressionParser; } public void afterPropertiesSet() throws Exception { findConditionExpressionParserInApplicationContext(); findFunctionExpressionParserInApplicationContext(); for (ClassValidationAnnotationHandler handler : classHandlers) { setExpressionParsers(handler); initLifecycle(handler); } for (PropertyValidationAnnotationHandler handler : propertyHandlers) { setExpressionParsers(handler); initLifecycle(handler); } } //=============================================== Helper Methods =================================================== protected void setExpressionParsers(Object object) { if (ConditionExpressionBased.class.isInstance(object) && conditionExpressionParser != null) { ((ConditionExpressionBased) object).setConditionExpressionParser(conditionExpressionParser); } if (FunctionExpressionBased.class.isInstance(object) && functionExpressionParser != null) { ((FunctionExpressionBased) object).setFunctionExpressionParser(functionExpressionParser); } } protected void findConditionExpressionParserInApplicationContext() { if (conditionExpressionParserSet) { return; } ConditionExpressionParser parser = (ConditionExpressionParser) findObjectInApplicationContext(ConditionExpressionParser.class); if (parser == null) { return; } conditionExpressionParser = parser; } protected void findFunctionExpressionParserInApplicationContext() { if (functionExpressionParserSet) { return; } FunctionExpressionParser parser = (FunctionExpressionParser) findObjectInApplicationContext(FunctionExpressionParser.class); if (parser == null) { return; } functionExpressionParser = parser; } protected Object findObjectInApplicationContext(Class clazz) { if (applicationContext == null) { return null; } String[] names = applicationContext.getBeanNamesForType(clazz); if (names.length == 0) { return null; } if (names.length > 1) { SimpleValidationAnnotationHandlerRegistry.logger.warn("Multiple bean of type '" + clazz.getName() + "' are defined in the application context." + "Only the first encountered one will be used"); } return applicationContext.getBean(names[0]); } }