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.Arrays; |
19 | import java.util.List; |
20 | |
21 | import org.springframework.beans.factory.config.BeanDefinition; |
22 | import org.springframework.beans.factory.parsing.CompositeComponentDefinition; |
23 | import org.springframework.beans.factory.support.BeanDefinitionBuilder; |
24 | import org.springframework.beans.factory.support.ManagedList; |
25 | import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; |
26 | import org.springframework.beans.factory.xml.ParserContext; |
27 | import org.springframework.util.StringUtils; |
28 | import org.springframework.util.xml.DomUtils; |
29 | import org.w3c.dom.Element; |
30 | |
31 | /** |
32 | * Parser for the lt;job/gt; element in the Batch namespace. Sets up and returns |
33 | * a bean definition for a {@link org.springframework.batch.core.Job}. |
34 | * |
35 | * @author Dave Syer |
36 | * |
37 | */ |
38 | public class JobParser extends AbstractSingleBeanDefinitionParser { |
39 | |
40 | private static final String MERGE_ATTR = "merge"; |
41 | |
42 | private static final JobExecutionListenerParser jobListenerParser = new JobExecutionListenerParser(); |
43 | |
44 | @Override |
45 | protected Class<JobParserJobFactoryBean> getBeanClass(Element element) { |
46 | return JobParserJobFactoryBean.class; |
47 | } |
48 | |
49 | /** |
50 | * Create a bean definition for a |
51 | * {@link org.springframework.batch.core.job.flow.FlowJob}. Nested step |
52 | * elements are delegated to an {@link InlineStepParser}. |
53 | * |
54 | * @see AbstractSingleBeanDefinitionParser#doParse(Element, ParserContext, |
55 | * BeanDefinitionBuilder) |
56 | */ |
57 | @SuppressWarnings("unchecked") |
58 | @Override |
59 | protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { |
60 | |
61 | CoreNamespaceUtils.autoregisterBeansForNamespace(parserContext, parserContext.extractSource(element)); |
62 | |
63 | String jobName = element.getAttribute("id"); |
64 | builder.addConstructorArgValue(jobName); |
65 | |
66 | boolean isAbstract = CoreNamespaceUtils.isAbstract(element); |
67 | builder.setAbstract(isAbstract); |
68 | |
69 | String parentRef = element.getAttribute("parent"); |
70 | if (StringUtils.hasText(parentRef)) { |
71 | builder.setParentName(parentRef); |
72 | } |
73 | |
74 | String repositoryAttribute = element.getAttribute("job-repository"); |
75 | if (StringUtils.hasText(repositoryAttribute)) { |
76 | builder.addPropertyReference("jobRepository", repositoryAttribute); |
77 | } |
78 | |
79 | String restartableAttribute = element.getAttribute("restartable"); |
80 | if (StringUtils.hasText(restartableAttribute)) { |
81 | builder.addPropertyValue("restartable", restartableAttribute); |
82 | } |
83 | |
84 | String incrementer = (element.getAttribute("incrementer")); |
85 | if (StringUtils.hasText(incrementer)) { |
86 | builder.addPropertyReference("jobParametersIncrementer", incrementer); |
87 | } |
88 | |
89 | if (isAbstract) { |
90 | for (String tagName : Arrays.asList("step", "decision", "split")) { |
91 | if (!DomUtils.getChildElementsByTagName(element, tagName).isEmpty()) { |
92 | parserContext.getReaderContext().error( |
93 | "The <" + tagName + "/> element may not appear on a <job/> with abstract=\"true\" [" |
94 | + jobName + "]", element); |
95 | } |
96 | } |
97 | } |
98 | else { |
99 | FlowParser flowParser = new FlowParser(jobName, jobName); |
100 | BeanDefinition flowDef = flowParser.parse(element, parserContext); |
101 | builder.addPropertyValue("flow", flowDef); |
102 | } |
103 | |
104 | List<Element> listenersElements = DomUtils.getChildElementsByTagName(element, "listeners"); |
105 | if (listenersElements.size() == 1) { |
106 | Element listenersElement = listenersElements.get(0); |
107 | CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(listenersElement.getTagName(), |
108 | parserContext.extractSource(element)); |
109 | parserContext.pushContainingComponent(compositeDef); |
110 | ManagedList listeners = new ManagedList(); |
111 | listeners.setMergeEnabled(listenersElement.hasAttribute(MERGE_ATTR) |
112 | && Boolean.valueOf(listenersElement.getAttribute(MERGE_ATTR))); |
113 | List<Element> listenerElements = (List<Element>) DomUtils.getChildElementsByTagName(listenersElement, |
114 | "listener"); |
115 | for (Element listenerElement : listenerElements) { |
116 | listeners.add(jobListenerParser.parse(listenerElement, parserContext)); |
117 | } |
118 | builder.addPropertyValue("jobExecutionListeners", listeners); |
119 | parserContext.popAndRegisterContainingComponent(); |
120 | } |
121 | else if (listenersElements.size() > 1) { |
122 | parserContext.getReaderContext().error( |
123 | "The '<listeners/>' element may not appear more than once in a single <job/>.", element); |
124 | } |
125 | |
126 | } |
127 | |
128 | } |