001/*
002 * Copyright 2013 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 */
016package org.springframework.batch.core.jsr.configuration.xml;
017
018import java.util.Collection;
019import java.util.List;
020
021import org.springframework.beans.PropertyValue;
022import org.springframework.beans.factory.config.BeanDefinition;
023import org.springframework.beans.factory.config.RuntimeBeanReference;
024import org.springframework.beans.factory.support.BeanDefinitionBuilder;
025import org.springframework.beans.factory.support.BeanDefinitionRegistry;
026import org.springframework.beans.factory.support.ManagedList;
027import org.springframework.beans.factory.xml.ParserContext;
028import org.springframework.core.task.SimpleAsyncTaskExecutor;
029import org.springframework.util.xml.DomUtils;
030import org.w3c.dom.Element;
031
032/**
033 * Parses a <split /> element as defined in JSR-352.
034 *
035 * @author Michael Minella
036 * @author Chris Schaefer
037 * @since 3.0
038 */
039public class JsrSplitParser {
040        private static final String TASK_EXECUTOR_PROPERTY_NAME = "taskExecutor";
041        private static final String JSR_352_SPLIT_TASK_EXECUTOR_BEAN_NAME = "jsr352splitTaskExecutor";
042
043        private String jobFactoryRef;
044
045        public JsrSplitParser(String jobFactoryRef) {
046                this.jobFactoryRef = jobFactoryRef;
047        }
048
049        public Collection<BeanDefinition> parse(Element element, ParserContext parserContext) {
050
051                String idAttribute = element.getAttribute("id");
052
053                BeanDefinitionBuilder stateBuilder = BeanDefinitionBuilder
054                                .genericBeanDefinition("org.springframework.batch.core.jsr.job.flow.support.state.JsrSplitState");
055
056                List<Element> flowElements = DomUtils.getChildElementsByTagName(element, "flow");
057
058                if (flowElements.size() < 2) {
059                        parserContext.getReaderContext().error("A <split/> must contain at least two 'flow' elements.", element);
060                }
061
062                Collection<Object> flows = new ManagedList<Object>();
063                int i = 0;
064                for (Element nextElement : flowElements) {
065                        FlowParser flowParser = new FlowParser(idAttribute + "." + i, jobFactoryRef);
066                        flows.add(flowParser.parse(nextElement, parserContext));
067                        i++;
068                }
069
070                stateBuilder.addConstructorArgValue(flows);
071                stateBuilder.addConstructorArgValue(idAttribute);
072
073                PropertyValue propertyValue = getSplitTaskExecutorPropertyValue(parserContext.getRegistry());
074                stateBuilder.addPropertyValue(propertyValue.getName(), propertyValue.getValue());
075
076                return FlowParser.getNextElements(parserContext, null, stateBuilder.getBeanDefinition(), element);
077        }
078
079        protected PropertyValue getSplitTaskExecutorPropertyValue(BeanDefinitionRegistry beanDefinitionRegistry) {
080                PropertyValue propertyValue;
081
082                if (hasBeanDefinition(beanDefinitionRegistry, JSR_352_SPLIT_TASK_EXECUTOR_BEAN_NAME)) {
083                        propertyValue = new PropertyValue(TASK_EXECUTOR_PROPERTY_NAME, new RuntimeBeanReference(JSR_352_SPLIT_TASK_EXECUTOR_BEAN_NAME));
084                } else {
085                        propertyValue = new PropertyValue(TASK_EXECUTOR_PROPERTY_NAME, new SimpleAsyncTaskExecutor());
086                }
087
088                return propertyValue;
089        }
090
091        private boolean hasBeanDefinition(BeanDefinitionRegistry beanDefinitionRegistry, String beanName) {
092                return beanDefinitionRegistry.containsBeanDefinition(beanName);
093        }
094}