From 6b4ff3a566f01cf3356570861f771b0fc5342bff Mon Sep 17 00:00:00 2001 From: Chris Schaefer Date: Wed, 27 Nov 2013 11:02:47 -0500 Subject: [PATCH] Remove unique transition pattern check per JSR requirements. Transitions are ordered based on their ordering in the job defintion XML document, so for example having an end and stop transition both with a pattern of "foo" is valid. --- .../jsr/configuration/xml/FlowParser.java | 31 +++++-- .../configuration/xml/FlowParserTests.java | 82 +++++++++++++++++++ .../xml/FlowParserTests-context.xml | 47 +++++++++++ 3 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/FlowParserTests.java create mode 100644 spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/FlowParserTests-context.xml diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/FlowParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/FlowParser.java index e2a4e7321..24452f8cd 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/FlowParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/FlowParser.java @@ -60,10 +60,18 @@ public class FlowParser extends AbstractFlowParser { private static final String TO_ATTRIBUTE = "to"; private static final String RESTART_ATTRIBUTE = "restart"; private static final String EXIT_STATUS_ATTRIBUTE = "exit-status"; + private static final List TRANSITION_TYPES = new ArrayList(); + static { + TRANSITION_TYPES.add(NEXT_ATTRIBUTE); + TRANSITION_TYPES.add(STOP_ATTRIBUTE); + TRANSITION_TYPES.add(END_ATTRIBUTE); + TRANSITION_TYPES.add(FAIL_ATTRIBUTE); + } + + private String flowName; private String jobFactoryRef; private StepParser stepParser = new StepParser(); - private String flowName; /** * @param flowName The name of the flow @@ -157,12 +165,10 @@ public class FlowParser extends AbstractFlowParser { } boolean transitionElementExists = false; - List patterns = new ArrayList(); - for (String transitionName : new String[] { NEXT_ATTRIBUTE, STOP_ATTRIBUTE, END_ATTRIBUTE, FAIL_ATTRIBUTE }) { - List transitionElements = DomUtils.getChildElementsByTagName(element, transitionName); - for (Element transitionElement : transitionElements) { - verifyUniquePattern(transitionElement, patterns, element, parserContext); - list.addAll(parseTransitionElement(transitionElement, stepId, stateDef, parserContext)); + List childElements = DomUtils.getChildElements(element); + for(Element childElement : childElements) { + if(isChildElementTransitionElement(childElement)) { + list.addAll(parseTransitionElement(childElement, stepId, stateDef, parserContext)); transitionElementExists = true; } } @@ -186,6 +192,17 @@ public class FlowParser extends AbstractFlowParser { return list; } + private static boolean isChildElementTransitionElement(Element childElement) { + boolean isTransitionElement = false; + + if(TRANSITION_TYPES.contains(childElement.getLocalName())) { + int index = TRANSITION_TYPES.indexOf(childElement.getLocalName()); + isTransitionElement = TRANSITION_TYPES.get(index) != null; + } + + return isTransitionElement; + } + protected static Collection parseTransitionElement(Element transitionElement, String stateId, BeanDefinition stateDef, ParserContext parserContext) { FlowExecutionStatus status = getBatchStatusFromEndTransitionName(transitionElement.getNodeName()); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/FlowParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/FlowParserTests.java new file mode 100644 index 000000000..a6230f886 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/FlowParserTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.core.jsr.configuration.xml; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.batch.core.*; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import javax.batch.api.Batchlet; +import javax.batch.runtime.context.StepContext; +import javax.inject.Inject; + +import static org.junit.Assert.assertEquals; + +/** + *

+ * Unit tests around {@link FlowParser}. + *

+ * + * @author Chris Schaefer + * @since 3.0 + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class FlowParserTests { + @Autowired + private Job job; + + @Autowired + private JobLauncher jobLauncher; + + @Test + public void testDuplicateTransitionPatternsAllowed() throws Exception { + JobExecution stoppedExecution = jobLauncher.run(job, new JobParameters()); + assertEquals(ExitStatus.STOPPED.getExitCode(), stoppedExecution.getExitStatus().getExitCode()); + + JobExecution endedExecution = jobLauncher.run(job, new JobParameters()); + assertEquals(ExitStatus.COMPLETED.getExitCode(), endedExecution.getExitStatus().getExitCode()); + + JobExecution failedExecution = jobLauncher.run(job, new JobParameters()); + assertEquals(ExitStatus.FAILED.getExitCode(), failedExecution.getExitStatus().getExitCode()); + } + + public static class TestBatchlet implements Batchlet { + private static int CNT; + + @Inject + private StepContext stepContext; + + @Override + public String process() throws Exception { + String exitCode = "DISTINCT"; + + if("step3".equals(stepContext.getStepName())) { + exitCode = CNT % 2 == 0 ? "DISTINCT" : "RESTART"; + CNT++; + } + + return exitCode; + } + + @Override + public void stop() throws Exception { } + } +} diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/FlowParserTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/FlowParserTests-context.xml new file mode 100644 index 000000000..08a05af29 --- /dev/null +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/FlowParserTests-context.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +