View Javadoc

1   /*
2    * Copyright 2006-2008 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.springframework.batch.core.configuration.xml;
17  
18  import java.util.Collection;
19  import java.util.List;
20  
21  import org.springframework.beans.MutablePropertyValues;
22  import org.springframework.beans.factory.config.BeanDefinition;
23  import org.springframework.beans.factory.config.RuntimeBeanReference;
24  import org.springframework.beans.factory.support.AbstractBeanDefinition;
25  import org.springframework.beans.factory.support.BeanDefinitionBuilder;
26  import org.springframework.beans.factory.support.GenericBeanDefinition;
27  import org.springframework.beans.factory.support.ManagedList;
28  import org.springframework.beans.factory.xml.ParserContext;
29  import org.springframework.core.task.TaskExecutor;
30  import org.springframework.util.StringUtils;
31  import org.springframework.util.xml.DomUtils;
32  import org.w3c.dom.Element;
33  
34  /**
35   * Internal parser for the <split/> elements inside a job. A split element
36   * optionally references a bean definition for a {@link TaskExecutor} and goes
37   * on to list a set of transitions to other states with <next on="pattern"
38   * to="stepName"/>. Used by the {@link JobParser}.
39   * 
40   * @see JobParser
41   * 
42   * @author Dave Syer
43   * 
44   */
45  public class SplitParser {
46  
47  	/**
48  	 * 
49  	 */
50  	private static final String PARENT_ATTR = "parent";
51  
52  	private final String jobFactoryRef;
53  
54  	/**
55  	 * Construct a {@link InlineFlowParser} using the provided job repository
56  	 * ref.
57  	 * 
58  	 * @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean}
59  	 * from the enclosing tag
60  	 */
61  	public SplitParser(String jobFactoryRef) {
62  		this.jobFactoryRef = jobFactoryRef;
63  	}
64  
65  	/**
66  	 * Parse the split and turn it into a list of transitions.
67  	 * 
68  	 * @param element the <split/gt; element to parse
69  	 * @param parserContext the parser context for the bean factory
70  	 * @return a collection of bean definitions for
71  	 * {@link org.springframework.batch.core.job.flow.support.StateTransition}
72  	 * instances objects
73  	 */
74  	public Collection<BeanDefinition> parse(Element element, ParserContext parserContext) {
75  
76  		String idAttribute = element.getAttribute("id");
77  
78  		BeanDefinitionBuilder stateBuilder = BeanDefinitionBuilder
79  				.genericBeanDefinition("org.springframework.batch.core.job.flow.support.state.SplitState");
80  
81  		String taskExecutorBeanId = element.getAttribute("task-executor");
82  		if (StringUtils.hasText(taskExecutorBeanId)) {
83  			RuntimeBeanReference taskExecutorRef = new RuntimeBeanReference(taskExecutorBeanId);
84  			stateBuilder.addPropertyValue("taskExecutor", taskExecutorRef);
85  		}
86  
87  		@SuppressWarnings("unchecked")
88  		List<Element> flowElements = DomUtils.getChildElementsByTagName(element, "flow");
89  
90  		if (flowElements.size() < 2) {
91  			parserContext.getReaderContext().error("A <split/> must contain at least two 'flow' elements.", element);
92  		}
93  
94  		@SuppressWarnings("unchecked")
95  		Collection<Object> flows = new ManagedList();
96  		int i = 0;
97  		String prefix = idAttribute;
98  		for (Element nextElement : flowElements) {
99  			String ref = nextElement.getAttribute(PARENT_ATTR);
100 			if (StringUtils.hasText(ref)) {
101 				if (nextElement.getElementsByTagName("*").getLength() > 0) {
102 					parserContext.getReaderContext().error(
103 							"A <flow/> in a <split/> must have ref= or nested <flow/>, but not both.", nextElement);
104 				}
105 				AbstractBeanDefinition flowDefinition = new GenericBeanDefinition();
106 				flowDefinition.setParentName(ref);
107 				MutablePropertyValues propertyValues = flowDefinition.getPropertyValues();
108 				propertyValues.addPropertyValue("name", prefix + "." + i);
109 				flows.add(flowDefinition);
110 			}
111 			else {
112 				InlineFlowParser flowParser = new InlineFlowParser(prefix + "." + i, jobFactoryRef);
113 				flows.add(flowParser.parse(nextElement, parserContext));
114 			}
115 			i++;
116 		}
117 
118 		stateBuilder.addConstructorArgValue(flows);
119 		stateBuilder.addConstructorArgValue(prefix);
120 
121 		return InlineFlowParser.getNextElements(parserContext, stateBuilder.getBeanDefinition(), element);
122 
123 	}
124 
125 }