1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.springframework.batch.core.configuration.xml;
17
18 import java.util.Arrays;
19 import java.util.List;
20
21 import org.springframework.beans.BeanMetadataElement;
22 import org.springframework.beans.factory.config.BeanDefinition;
23 import org.springframework.beans.factory.config.BeanDefinitionHolder;
24 import org.springframework.beans.factory.config.RuntimeBeanReference;
25 import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
26 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
27 import org.springframework.beans.factory.support.ManagedList;
28 import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
29 import org.springframework.beans.factory.xml.ParserContext;
30 import org.springframework.util.StringUtils;
31 import org.springframework.util.xml.DomUtils;
32 import org.w3c.dom.Element;
33
34
35
36
37
38
39
40
41 public class JobParser extends AbstractSingleBeanDefinitionParser {
42
43 private static final String MERGE_ATTR = "merge";
44
45 private static final String REF_ATTR = "ref";
46
47 private static final String BEAN_ELE = "bean";
48
49 private static final String REF_ELE = "ref";
50
51 private static final JobExecutionListenerParser jobListenerParser = new JobExecutionListenerParser();
52
53 @Override
54 protected Class<JobParserJobFactoryBean> getBeanClass(Element element) {
55 return JobParserJobFactoryBean.class;
56 }
57
58
59
60
61
62
63
64
65
66 @SuppressWarnings("unchecked")
67 @Override
68 protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
69
70 if (!CoreNamespaceUtils.namespaceMatchesVersion(element)) {
71 parserContext.getReaderContext().error(
72 "You cannot use spring-batch-2.0.xsd with Spring Batch 2.1. Please upgrade your schema declarations "
73 + "(or use the spring-batch.xsd alias if you are feeling lucky).", element);
74 return;
75 }
76
77 CoreNamespaceUtils.autoregisterBeansForNamespace(parserContext, parserContext.extractSource(element));
78
79 String jobName = element.getAttribute("id");
80 builder.addConstructorArgValue(jobName);
81
82 boolean isAbstract = CoreNamespaceUtils.isAbstract(element);
83 builder.setAbstract(isAbstract);
84
85 String parentRef = element.getAttribute("parent");
86 if (StringUtils.hasText(parentRef)) {
87 builder.setParentName(parentRef);
88 }
89
90 String repositoryAttribute = element.getAttribute("job-repository");
91 if (StringUtils.hasText(repositoryAttribute)) {
92 builder.addPropertyReference("jobRepository", repositoryAttribute);
93 }
94
95 Element validator = DomUtils.getChildElementByTagName(element, "validator");
96 if (validator != null) {
97 builder.addPropertyValue("jobParametersValidator", parseBeanElement(validator, parserContext));
98 }
99
100 String restartableAttribute = element.getAttribute("restartable");
101 if (StringUtils.hasText(restartableAttribute)) {
102 builder.addPropertyValue("restartable", restartableAttribute);
103 }
104
105 String incrementer = (element.getAttribute("incrementer"));
106 if (StringUtils.hasText(incrementer)) {
107 builder.addPropertyReference("jobParametersIncrementer", incrementer);
108 }
109
110 if (isAbstract) {
111 for (String tagName : Arrays.asList("step", "decision", "split")) {
112 if (!DomUtils.getChildElementsByTagName(element, tagName).isEmpty()) {
113 parserContext.getReaderContext().error(
114 "The <" + tagName + "/> element may not appear on a <job/> with abstract=\"true\" ["
115 + jobName + "]", element);
116 }
117 }
118 }
119 else {
120 InlineFlowParser flowParser = new InlineFlowParser(jobName, jobName);
121 BeanDefinition flowDef = flowParser.parse(element, parserContext);
122 builder.addPropertyValue("flow", flowDef);
123 }
124
125 Element description = DomUtils.getChildElementByTagName(element, "description");
126 if (description != null) {
127 builder.getBeanDefinition().setDescription(description.getTextContent());
128 }
129
130 List<Element> listenersElements = DomUtils.getChildElementsByTagName(element, "listeners");
131 if (listenersElements.size() == 1) {
132 Element listenersElement = listenersElements.get(0);
133 CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(listenersElement.getTagName(),
134 parserContext.extractSource(element));
135 parserContext.pushContainingComponent(compositeDef);
136 ManagedList listeners = new ManagedList();
137 listeners.setMergeEnabled(listenersElement.hasAttribute(MERGE_ATTR)
138 && Boolean.valueOf(listenersElement.getAttribute(MERGE_ATTR)));
139 List<Element> listenerElements = DomUtils.getChildElementsByTagName(listenersElement, "listener");
140 for (Element listenerElement : listenerElements) {
141 listeners.add(jobListenerParser.parse(listenerElement, parserContext));
142 }
143 builder.addPropertyValue("jobExecutionListeners", listeners);
144 parserContext.popAndRegisterContainingComponent();
145 }
146 else if (listenersElements.size() > 1) {
147 parserContext.getReaderContext().error(
148 "The '<listeners/>' element may not appear more than once in a single <job/>.", element);
149 }
150
151 }
152
153 public BeanMetadataElement parseBeanElement(Element element, ParserContext parserContext) {
154 String refAttribute = element.getAttribute(REF_ATTR);
155 Element beanElement = DomUtils.getChildElementByTagName(element, BEAN_ELE);
156 Element refElement = DomUtils.getChildElementByTagName(element, REF_ELE);
157
158 if (StringUtils.hasText(refAttribute)) {
159 return new RuntimeBeanReference(refAttribute);
160 }
161 else if (beanElement != null) {
162 BeanDefinitionHolder beanDefinitionHolder = parserContext.getDelegate().parseBeanDefinitionElement(
163 beanElement);
164 parserContext.getDelegate().decorateBeanDefinitionIfRequired(beanElement, beanDefinitionHolder);
165 return beanDefinitionHolder;
166 }
167 else if (refElement != null) {
168 return (BeanMetadataElement) parserContext.getDelegate().parsePropertySubElement(refElement, null);
169 }
170
171 parserContext.getReaderContext().error(
172 "One of ref attribute or a nested bean definition or ref element must be specified", element);
173 return null;
174 }
175
176 }