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