001/*
002 * Copyright 2002-2015 the original author or authors.
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 *      https://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
017package org.springframework.scheduling.config;
018
019import org.w3c.dom.Element;
020
021import org.springframework.aop.config.AopNamespaceUtils;
022import org.springframework.beans.factory.config.BeanDefinition;
023import org.springframework.beans.factory.config.BeanDefinitionHolder;
024import org.springframework.beans.factory.parsing.BeanComponentDefinition;
025import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
026import org.springframework.beans.factory.support.BeanDefinitionBuilder;
027import org.springframework.beans.factory.support.BeanDefinitionRegistry;
028import org.springframework.beans.factory.xml.BeanDefinitionParser;
029import org.springframework.beans.factory.xml.ParserContext;
030import org.springframework.util.StringUtils;
031
032/**
033 * Parser for the 'annotation-driven' element of the 'task' namespace.
034 *
035 * @author Mark Fisher
036 * @author Juergen Hoeller
037 * @author Ramnivas Laddad
038 * @author Chris Beams
039 * @author Stephane Nicoll
040 * @since 3.0
041 */
042public class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
043
044        private static final String ASYNC_EXECUTION_ASPECT_CLASS_NAME =
045                        "org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect";
046
047
048        @Override
049        public BeanDefinition parse(Element element, ParserContext parserContext) {
050                Object source = parserContext.extractSource(element);
051
052                // Register component for the surrounding <task:annotation-driven> element.
053                CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
054                parserContext.pushContainingComponent(compDefinition);
055
056                // Nest the concrete post-processor bean in the surrounding component.
057                BeanDefinitionRegistry registry = parserContext.getRegistry();
058
059                String mode = element.getAttribute("mode");
060                if ("aspectj".equals(mode)) {
061                        // mode="aspectj"
062                        registerAsyncExecutionAspect(element, parserContext);
063                }
064                else {
065                        // mode="proxy"
066                        if (registry.containsBeanDefinition(TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)) {
067                                parserContext.getReaderContext().error(
068                                                "Only one AsyncAnnotationBeanPostProcessor may exist within the context.", source);
069                        }
070                        else {
071                                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
072                                                "org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor");
073                                builder.getRawBeanDefinition().setSource(source);
074                                String executor = element.getAttribute("executor");
075                                if (StringUtils.hasText(executor)) {
076                                        builder.addPropertyReference("executor", executor);
077                                }
078                                String exceptionHandler = element.getAttribute("exception-handler");
079                                if (StringUtils.hasText(exceptionHandler)) {
080                                        builder.addPropertyReference("exceptionHandler", exceptionHandler);
081                                }
082                                if (Boolean.valueOf(element.getAttribute(AopNamespaceUtils.PROXY_TARGET_CLASS_ATTRIBUTE))) {
083                                        builder.addPropertyValue("proxyTargetClass", true);
084                                }
085                                registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME);
086                        }
087                }
088
089                if (registry.containsBeanDefinition(TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
090                        parserContext.getReaderContext().error(
091                                        "Only one ScheduledAnnotationBeanPostProcessor may exist within the context.", source);
092                }
093                else {
094                        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
095                                        "org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor");
096                        builder.getRawBeanDefinition().setSource(source);
097                        String scheduler = element.getAttribute("scheduler");
098                        if (StringUtils.hasText(scheduler)) {
099                                builder.addPropertyReference("scheduler", scheduler);
100                        }
101                        registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME);
102                }
103
104                // Finally register the composite component.
105                parserContext.popAndRegisterContainingComponent();
106
107                return null;
108        }
109
110        private void registerAsyncExecutionAspect(Element element, ParserContext parserContext) {
111                if (!parserContext.getRegistry().containsBeanDefinition(TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)) {
112                        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ASYNC_EXECUTION_ASPECT_CLASS_NAME);
113                        builder.setFactoryMethod("aspectOf");
114                        String executor = element.getAttribute("executor");
115                        if (StringUtils.hasText(executor)) {
116                                builder.addPropertyReference("executor", executor);
117                        }
118                        String exceptionHandler = element.getAttribute("exception-handler");
119                        if (StringUtils.hasText(exceptionHandler)) {
120                                builder.addPropertyReference("exceptionHandler", exceptionHandler);
121                        }
122                        parserContext.registerBeanComponent(new BeanComponentDefinition(builder.getBeanDefinition(),
123                                        TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME));
124                }
125        }
126
127        private static void registerPostProcessor(
128                        ParserContext parserContext, BeanDefinitionBuilder builder, String beanName) {
129
130                builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
131                parserContext.getRegistry().registerBeanDefinition(beanName, builder.getBeanDefinition());
132                BeanDefinitionHolder holder = new BeanDefinitionHolder(builder.getBeanDefinition(), beanName);
133                parserContext.registerComponent(new BeanComponentDefinition(holder));
134        }
135
136}