Skip to content

Commit 7981b71

Browse files
committed
BATCH-1999: Initial commit of JSR parsing infrastructure
1 parent 2dd1817 commit 7981b71

File tree

44 files changed

+2234
-80
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2234
-80
lines changed

spring-batch-core/pom.xml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
<artifactId>spring-batch-infrastructure</artifactId>
1919
<version>${project.version}</version>
2020
</dependency>
21+
<dependency>
22+
<groupId>javax.batch</groupId>
23+
<artifactId>javax.batch-api</artifactId>
24+
<version>1.0-b29</version>
25+
</dependency>
2126
<dependency>
2227
<groupId>org.hsqldb</groupId>
2328
<artifactId>hsqldb</artifactId>
@@ -38,10 +43,6 @@
3843
<optional>true</optional>
3944
<scope>test</scope>
4045
</dependency>
41-
<!-- <dependency> -->
42-
<!-- <groupId>org.easymock</groupId> -->
43-
<!-- <artifactId>easymock</artifactId> -->
44-
<!-- </dependency> -->
4546
<dependency>
4647
<groupId>junit</groupId>
4748
<artifactId>junit</artifactId>

spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/EnableBatchProcessing.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.lang.annotation.RetentionPolicy;
2222
import java.lang.annotation.Target;
2323

24+
import javax.sql.DataSource;
25+
2426
import org.springframework.batch.core.configuration.JobRegistry;
2527
import org.springframework.batch.core.configuration.support.ApplicationContextFactory;
2628
import org.springframework.batch.core.configuration.support.AutomaticJobRegistrar;

spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractFlowParser.java

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ private Set<String> findReachableElements(Element element) {
211211
* @param reachableElementMap
212212
* @param accumulator a collection of reachable element names
213213
*/
214-
private void findAllReachableElements(String startElement, Map<String, Set<String>> reachableElementMap,
214+
protected void findAllReachableElements(String startElement, Map<String, Set<String>> reachableElementMap,
215215
Set<String> accumulator) {
216216
Set<String> reachableIds = reachableElementMap.get(startElement);
217217
accumulator.add(startElement);
@@ -233,7 +233,7 @@ private void findAllReachableElements(String startElement, Map<String, Set<Strin
233233
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
234234
* references
235235
*/
236-
protected static Collection<BeanDefinition> getNextElements(ParserContext parserContext, BeanDefinition stateDef,
236+
public static Collection<BeanDefinition> getNextElements(ParserContext parserContext, BeanDefinition stateDef,
237237
Element element) {
238238
return getNextElements(parserContext, null, stateDef, element);
239239
}
@@ -248,7 +248,7 @@ protected static Collection<BeanDefinition> getNextElements(ParserContext parser
248248
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
249249
* references
250250
*/
251-
protected static Collection<BeanDefinition> getNextElements(ParserContext parserContext, String stepId,
251+
public static Collection<BeanDefinition> getNextElements(ParserContext parserContext, String stepId,
252252
BeanDefinition stateDef, Element element) {
253253

254254
Collection<BeanDefinition> list = new ArrayList<BeanDefinition>();
@@ -283,7 +283,7 @@ protected static Collection<BeanDefinition> getNextElements(ParserContext parser
283283
else if (hasNextAttribute) {
284284
parserContext.getReaderContext().error(
285285
"The <" + element.getNodeName() + "/> may not contain a '" + NEXT_ATTR
286-
+ "' attribute and a transition element", element);
286+
+ "' attribute and a transition element", element);
287287
}
288288

289289
return list;
@@ -390,7 +390,7 @@ private static Collection<BeanDefinition> createTransition(FlowExecutionStatus s
390390
* @return the BatchStatus corresponding to the transition name
391391
*/
392392
private static FlowExecutionStatus getBatchStatusFromEndTransitionName(String elementName) {
393-
elementName = stripNamespace(elementName);
393+
elementName = stripNamespace(elementName);
394394
if (STOP_ELE.equals(elementName)) {
395395
return FlowExecutionStatus.STOPPED;
396396
}
@@ -405,17 +405,17 @@ else if (FAIL_ELE.equals(elementName)) {
405405
}
406406
}
407407

408-
/**
409-
* Strip the namespace from the element name if it exists.
410-
*/
411-
private static String stripNamespace(String elementName){
412-
if(elementName.startsWith("batch:")){
413-
return elementName.substring(6);
414-
}
415-
else{
416-
return elementName;
417-
}
418-
}
408+
/**
409+
* Strip the namespace from the element name if it exists.
410+
*/
411+
private static String stripNamespace(String elementName){
412+
if(elementName.startsWith("batch:")){
413+
return elementName.substring(6);
414+
}
415+
else{
416+
return elementName;
417+
}
418+
}
419419

420420
/**
421421
* @param parserContext the parser context

spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/ChunkElementParser.java

Lines changed: 53 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,26 @@
1515
*/
1616
package org.springframework.batch.core.configuration.xml;
1717

18+
import java.util.List;
19+
1820
import org.springframework.batch.core.listener.StepListenerMetaData;
19-
import org.springframework.batch.core.step.item.ForceRollbackForWriteSkipException;
2021
import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
2122
import org.springframework.beans.MutablePropertyValues;
2223
import org.springframework.beans.factory.config.BeanDefinition;
2324
import org.springframework.beans.factory.config.BeanDefinitionHolder;
2425
import org.springframework.beans.factory.config.RuntimeBeanReference;
25-
import org.springframework.beans.factory.config.TypedStringValue;
2626
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
2727
import org.springframework.beans.factory.support.AbstractBeanDefinition;
2828
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
2929
import org.springframework.beans.factory.support.GenericBeanDefinition;
3030
import org.springframework.beans.factory.support.ManagedList;
3131
import org.springframework.beans.factory.support.ManagedMap;
3232
import org.springframework.beans.factory.xml.ParserContext;
33+
import org.springframework.util.CollectionUtils;
3334
import org.springframework.util.StringUtils;
3435
import org.springframework.util.xml.DomUtils;
3536
import org.w3c.dom.Element;
3637

37-
import java.util.List;
38-
3938
/**
4039
* Internal parser for the &lt;chunk/&gt; element inside a step.
4140
*
@@ -108,18 +107,18 @@ protected void parse(Element element, AbstractBeanDefinition bd, ParserContext p
108107
if (propertyValues.contains("commitInterval")) {
109108
parserContext.getReaderContext().error(
110109
"The <" + element.getNodeName() + "/> element must contain either '" + COMMIT_INTERVAL_ATTR
111-
+ "' " + "or '" + CHUNK_COMPLETION_POLICY_ATTR + "', but not both.", element);
110+
+ "' " + "or '" + CHUNK_COMPLETION_POLICY_ATTR + "', but not both.", element);
112111
}
113112
else {
114113
parserContext.getReaderContext().error(
115114
"The <" + element.getNodeName() + "/> element must contain either '" + COMMIT_INTERVAL_ATTR
116-
+ "' " + "or '" + CHUNK_COMPLETION_POLICY_ATTR + "'.", element);
115+
+ "' " + "or '" + CHUNK_COMPLETION_POLICY_ATTR + "'.", element);
117116

118117
}
119118
}
120119

121120
String skipLimit = element.getAttribute("skip-limit");
122-
ManagedMap skippableExceptions = handleExceptionElement(element, parserContext, "skippable-exception-classes");
121+
ManagedMap skippableExceptions = new ExceptionElementParser().parse(element, parserContext, "skippable-exception-classes");
123122
if (StringUtils.hasText(skipLimit)) {
124123
if (skippableExceptions == null) {
125124
skippableExceptions = new ManagedMap();
@@ -128,6 +127,12 @@ protected void parse(Element element, AbstractBeanDefinition bd, ParserContext p
128127
propertyValues.addPropertyValue("skipLimit", skipLimit);
129128
}
130129
if (skippableExceptions != null) {
130+
List<Element> exceptionClassElements = DomUtils.getChildElementsByTagName(element, "skippable-exception-classes");
131+
132+
if(!CollectionUtils.isEmpty(exceptionClassElements)) {
133+
skippableExceptions.setMergeEnabled(exceptionClassElements.get(0).hasAttribute(MERGE_ATTR)
134+
&& Boolean.valueOf(exceptionClassElements.get(0).getAttribute(MERGE_ATTR)));
135+
}
131136
// Even if there is no retryLimit, we can still accept exception
132137
// classes for an abstract parent bean definition
133138
propertyValues.addPropertyValue("skippableExceptionClasses", skippableExceptions);
@@ -137,7 +142,7 @@ protected void parse(Element element, AbstractBeanDefinition bd, ParserContext p
137142
underspecified);
138143

139144
String retryLimit = element.getAttribute("retry-limit");
140-
ManagedMap retryableExceptions = handleExceptionElement(element, parserContext, "retryable-exception-classes");
145+
ManagedMap retryableExceptions = new ExceptionElementParser().parse(element, parserContext, "retryable-exception-classes");
141146
if (StringUtils.hasText(retryLimit)) {
142147
if (retryableExceptions == null) {
143148
retryableExceptions = new ManagedMap();
@@ -146,6 +151,12 @@ protected void parse(Element element, AbstractBeanDefinition bd, ParserContext p
146151
propertyValues.addPropertyValue("retryLimit", retryLimit);
147152
}
148153
if (retryableExceptions != null) {
154+
List<Element> exceptionClassElements = DomUtils.getChildElementsByTagName(element, "retryable-exception-classes");
155+
156+
if(!CollectionUtils.isEmpty(exceptionClassElements)) {
157+
retryableExceptions.setMergeEnabled(exceptionClassElements.get(0).hasAttribute(MERGE_ATTR)
158+
&& Boolean.valueOf(exceptionClassElements.get(0).getAttribute(MERGE_ATTR)));
159+
}
149160
// Even if there is no retryLimit, we can still accept exception
150161
// classes for an abstract parent bean definition
151162
propertyValues.addPropertyValue("retryableExceptionClasses", retryableExceptions);
@@ -189,7 +200,7 @@ private void handleItemHandler(AbstractBeanDefinition enclosing, String handlerN
189200
if (StringUtils.hasText(refName)) {
190201
parserContext.getReaderContext().error(
191202
"The <" + element.getNodeName() + "/> element may not have both a '" + handlerName
192-
+ "' attribute and a <" + handlerName + "/> element.", element);
203+
+ "' attribute and a <" + handlerName + "/> element.", element);
193204
}
194205
handleItemHandlerElement(enclosing, propertyName, adapterClassName, propertyValues, children.get(0), parserContext);
195206
}
@@ -204,7 +215,7 @@ else if (StringUtils.hasText(refName)) {
204215
else if (required && !underspecified) {
205216
parserContext.getReaderContext().error(
206217
"The <" + element.getNodeName() + "/> element has neither a '" + handlerName
207-
+ "' attribute nor a <" + handlerName + "/> element.", element);
218+
+ "' attribute nor a <" + handlerName + "/> element.", element);
208219
}
209220
}
210221

@@ -220,7 +231,7 @@ private void handleItemHandlerElement(AbstractBeanDefinition enclosing, String p
220231
if (beanElements.size() + refElements.size() != 1) {
221232
parserContext.getReaderContext().error(
222233
"The <" + element.getNodeName() + "/> must have exactly one of either a <" + BEAN_ELE
223-
+ "/> element or a <" + REF_ELE + "/> element.", element);
234+
+ "/> element or a <" + REF_ELE + "/> element.", element);
224235
}
225236
else if (beanElements.size() == 1) {
226237
Element beanElement = beanElements.get(0);
@@ -313,35 +324,35 @@ private void handleStreamsElement(Element element, MutablePropertyValues propert
313324
propertyValues.addPropertyValue("streams", streamBeans);
314325
}
315326
}
316-
317-
@SuppressWarnings("unchecked")
318-
private ManagedMap handleExceptionElement(Element element, ParserContext parserContext, String exceptionListName) {
319-
List<Element> children = DomUtils.getChildElementsByTagName(element, exceptionListName);
320-
if (children.size() == 1) {
321-
ManagedMap map = new ManagedMap();
322-
Element exceptionClassesElement = children.get(0);
323-
map.setMergeEnabled(exceptionClassesElement.hasAttribute(MERGE_ATTR)
324-
&& Boolean.valueOf(exceptionClassesElement.getAttribute(MERGE_ATTR)));
325-
addExceptionClasses("include", true, exceptionClassesElement, map, parserContext);
326-
addExceptionClasses("exclude", false, exceptionClassesElement, map, parserContext);
327-
map.put(ForceRollbackForWriteSkipException.class, true);
328-
return map;
329-
}
330-
else if (children.size() > 1) {
331-
parserContext.getReaderContext().error(
332-
"The <" + exceptionListName + "/> element may not appear more than once in a single <"
333-
+ element.getNodeName() + "/>.", element);
334-
}
335-
return null;
336-
}
337-
338-
@SuppressWarnings("unchecked")
339-
private void addExceptionClasses(String elementName, boolean include, Element exceptionClassesElement,
340-
ManagedMap map, ParserContext parserContext) {
341-
for (Element child : (List<Element>) DomUtils.getChildElementsByTagName(exceptionClassesElement, elementName)) {
342-
String className = child.getAttribute("class");
343-
map.put(new TypedStringValue(className, Class.class), include);
344-
}
345-
}
346-
327+
//
328+
// @SuppressWarnings("unchecked")
329+
// private ManagedMap handleExceptionElement(Element element, ParserContext parserContext, String exceptionListName) {
330+
// List<Element> children = DomUtils.getChildElementsByTagName(element, exceptionListName);
331+
// if (children.size() == 1) {
332+
// ManagedMap map = new ManagedMap();
333+
// Element exceptionClassesElement = children.get(0);
334+
// map.setMergeEnabled(exceptionClassesElement.hasAttribute(MERGE_ATTR)
335+
// && Boolean.valueOf(exceptionClassesElement.getAttribute(MERGE_ATTR)));
336+
// addExceptionClasses("include", true, exceptionClassesElement, map, parserContext);
337+
// addExceptionClasses("exclude", false, exceptionClassesElement, map, parserContext);
338+
// map.put(ForceRollbackForWriteSkipException.class, true);
339+
// return map;
340+
// }
341+
// else if (children.size() > 1) {
342+
// parserContext.getReaderContext().error(
343+
// "The <" + exceptionListName + "/> element may not appear more than once in a single <"
344+
// + element.getNodeName() + "/>.", element);
345+
// }
346+
// return null;
347+
// }
348+
//
349+
// @SuppressWarnings("unchecked")
350+
// private void addExceptionClasses(String elementName, boolean include, Element exceptionClassesElement,
351+
// ManagedMap map, ParserContext parserContext) {
352+
// for (Element child : (List<Element>) DomUtils.getChildElementsByTagName(exceptionClassesElement, elementName)) {
353+
// String className = child.getAttribute("class");
354+
// map.put(new TypedStringValue(className, Class.class), include);
355+
// }
356+
// }
357+
//
347358
}

spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/CoreNamespaceUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public class CoreNamespaceUtils {
4747

4848
private static final String CORE_NAMESPACE_POST_PROCESSOR_CLASS_NAME = "org.springframework.batch.core.configuration.xml.CoreNamespacePostProcessor";
4949

50-
protected static void autoregisterBeansForNamespace(ParserContext parserContext, Object source) {
50+
public static void autoregisterBeansForNamespace(ParserContext parserContext, Object source) {
5151
checkForStepScope(parserContext, source);
5252
addRangePropertyEditor(parserContext);
5353
addCoreNamespacePostProcessor(parserContext);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package org.springframework.batch.core.configuration.xml;
2+
3+
import java.util.List;
4+
5+
import org.springframework.batch.core.step.item.ForceRollbackForWriteSkipException;
6+
import org.springframework.beans.factory.config.TypedStringValue;
7+
import org.springframework.beans.factory.support.ManagedMap;
8+
import org.springframework.beans.factory.xml.ParserContext;
9+
import org.springframework.util.xml.DomUtils;
10+
import org.w3c.dom.Element;
11+
12+
public class ExceptionElementParser {
13+
14+
@SuppressWarnings("unchecked")
15+
public ManagedMap parse(Element element, ParserContext parserContext, String exceptionListName) {
16+
List<Element> children = DomUtils.getChildElementsByTagName(element, exceptionListName);
17+
if (children.size() == 1) {
18+
ManagedMap map = new ManagedMap();
19+
Element exceptionClassesElement = children.get(0);
20+
addExceptionClasses("include", true, exceptionClassesElement, map, parserContext);
21+
addExceptionClasses("exclude", false, exceptionClassesElement, map, parserContext);
22+
map.put(ForceRollbackForWriteSkipException.class, true);
23+
return map;
24+
}
25+
else if (children.size() > 1) {
26+
parserContext.getReaderContext().error(
27+
"The <" + exceptionListName + "/> element may not appear more than once in a single <"
28+
+ element.getNodeName() + "/>.", element);
29+
}
30+
return null;
31+
}
32+
33+
@SuppressWarnings("unchecked")
34+
private void addExceptionClasses(String elementName, boolean include, Element exceptionClassesElement,
35+
ManagedMap map, ParserContext parserContext) {
36+
for (Element child : DomUtils.getChildElementsByTagName(exceptionClassesElement, elementName)) {
37+
String className = child.getAttribute("class");
38+
map.put(new TypedStringValue(className, Class.class), include);
39+
}
40+
}
41+
}

spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/JobParserJobFactoryBean.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
* @author Dave Syer
3636
* @since 2.0.1
3737
*/
38-
class JobParserJobFactoryBean implements SmartFactoryBean {
38+
public class JobParserJobFactoryBean implements SmartFactoryBean {
3939

4040
private String name;
4141

spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/SplitParser.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,13 @@ public Collection<BeanDefinition> parse(Element element, ParserContext parserCon
8484
stateBuilder.addPropertyValue("taskExecutor", taskExecutorRef);
8585
}
8686

87-
@SuppressWarnings("unchecked")
8887
List<Element> flowElements = DomUtils.getChildElementsByTagName(element, "flow");
8988

9089
if (flowElements.size() < 2) {
9190
parserContext.getReaderContext().error("A <split/> must contain at least two 'flow' elements.", element);
9291
}
9392

94-
@SuppressWarnings("unchecked")
93+
@SuppressWarnings({"rawtypes", "unchecked"})
9594
Collection<Object> flows = new ManagedList();
9695
int i = 0;
9796
String prefix = idAttribute;

0 commit comments

Comments
 (0)