RESOLVED - issue BATCH-1439: Make step names unique within a job

This commit is contained in:
dsyer
2009-11-16 08:46:56 +00:00
parent 86e67871a2
commit fa1ddbf2ea
30 changed files with 375 additions and 151 deletions

View File

@@ -5,6 +5,7 @@
<packaging>jar</packaging>
<name>Core</name>
<description>Core domain for batch processing, expressing a domain of Jobs, Steps, Chunks, etc.</description>
<url>http://static.springframework.org/spring-batch/${project.artifactId}</url>
<parent>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-parent</artifactId>

View File

@@ -25,7 +25,6 @@ import java.util.Map;
import java.util.Set;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.support.SimpleFlow;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -81,20 +80,8 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
// For generating unique state names for end transitions
private static int endCounter = 0;
private String flowName;
private String jobFactoryRef;
/**
* Convenience method for subclasses to set up the flow name for error
* reporting.
*
* @param flowName
*/
protected void setFlowName(String flowName) {
this.flowName = flowName;
}
/**
* Convenience method for subclasses to set the job factory reference if it
* is available (null is fine, but the quality of error reports is better if
@@ -112,8 +99,8 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
* @see AbstractSingleBeanDefinitionParser#getBeanClass(Element)
*/
@Override
protected Class<SimpleFlow> getBeanClass(Element element) {
return SimpleFlow.class;
protected Class<?> getBeanClass(Element element) {
return SimpleFlowFactoryBean.class;
}
/**
@@ -166,6 +153,7 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
}
}
String flowName = (String) builder.getRawBeanDefinition().getAttribute("flowName");
if (!stepExists && !StringUtils.hasText(element.getAttribute("parent"))) {
parserContext.getReaderContext().error("The flow [" + flowName + "] must contain at least one step",
element);
@@ -180,7 +168,6 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
}
}
builder.addConstructorArgValue(flowName);
ManagedList managedList = new ManagedList();
@SuppressWarnings( { "unchecked", "unused" })
boolean dummy = managedList.addAll(stateTransitions);

View File

@@ -17,9 +17,11 @@ package org.springframework.batch.core.configuration.xml;
import java.util.Collection;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
@@ -49,7 +51,12 @@ public class FlowElementParser {
BeanDefinitionBuilder stateBuilder =
BeanDefinitionBuilder.genericBeanDefinition("org.springframework.batch.core.job.flow.support.state.FlowState");
stateBuilder.addConstructorArgValue(new RuntimeBeanReference(refAttribute));
AbstractBeanDefinition flowDefinition = new GenericBeanDefinition();
flowDefinition.setParentName(refAttribute);
MutablePropertyValues propertyValues = flowDefinition.getPropertyValues();
propertyValues.addPropertyValue("name", idAttribute);
stateBuilder.addConstructorArgValue(flowDefinition);
stateBuilder.addConstructorArgValue(idAttribute);
return InlineFlowParser.getNextElements(parserContext, stateBuilder.getBeanDefinition(), element);

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.batch.core.configuration.xml;
import org.springframework.batch.core.job.flow.support.SimpleFlow;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
@@ -27,6 +26,8 @@ import org.w3c.dom.Element;
*/
public class InlineFlowParser extends AbstractFlowParser {
private final String flowName;
/**
* Construct a {@link InlineFlowParser} with the specified name and using the
* provided job repository ref.
@@ -36,21 +37,11 @@ public class InlineFlowParser extends AbstractFlowParser {
* from the enclosing tag
*/
public InlineFlowParser(String flowName, String jobFactoryRef) {
setFlowName(flowName);
this.flowName = flowName;
setJobFactoryRef(jobFactoryRef);
}
/*
* (non-Javadoc)
*
* @see AbstractSingleBeanDefinitionParser#getBeanClass(Element)
*/
@Override
protected Class<SimpleFlow> getBeanClass(Element element) {
return SimpleFlow.class;
}
/**
* @param element the top level element containing a flow definition
* @param parserContext the {@link ParserContext}
@@ -58,6 +49,8 @@ public class InlineFlowParser extends AbstractFlowParser {
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
builder.getRawBeanDefinition().setAttribute("flowName", flowName);
builder.addPropertyValue("name", flowName);
super.doParse(element, parserContext, builder);
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
parserContext.popAndRegisterContainingComponent();

View File

@@ -0,0 +1,179 @@
package org.springframework.batch.core.configuration.xml;
import java.util.ArrayList;
import java.util.List;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.FlowExecutor;
import org.springframework.batch.core.job.flow.State;
import org.springframework.batch.core.job.flow.support.SimpleFlow;
import org.springframework.batch.core.job.flow.support.StateTransition;
import org.springframework.batch.core.job.flow.support.state.AbstractState;
import org.springframework.batch.core.job.flow.support.state.StepState;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* Convenience factory for SimpleFlow instances for use in XML namespace. It
* replaces the states in the input with proxies that have a unique name formed
* from the flow name and the original state name (unless the name is already in
* that form, in which case it is not modified).
*
* @author Dave Syer
*
*/
public class SimpleFlowFactoryBean implements FactoryBean, InitializingBean {
private String name;
private List<StateTransition> stateTransitions;
private String prefix;
/**
* The name of the flow that is created by this factory.
*
* @param name the value of the name
*/
public void setName(String name) {
this.name = name;
this.prefix = name + ".";
}
/**
* The raw state transitions for the flow. They will be transformed into
* proxies that have the same behaviour but unique names prefixed with the
* flow name.
*
* @param name the value of the name
*/
public void setStateTransitions(List<StateTransition> stateTransitions) {
this.stateTransitions = stateTransitions;
}
/**
* Check mandatory properties (name).
*
* @throws Exception
*/
public void afterPropertiesSet() throws Exception {
Assert.hasText(name, "The flow must have a name");
}
public Object getObject() throws Exception {
SimpleFlow flow = new SimpleFlow(name);
List<StateTransition> updatedTransitions = new ArrayList<StateTransition>();
for (StateTransition stateTransition : stateTransitions) {
State state = getProxyState(stateTransition.getState());
updatedTransitions.add(StateTransition.switchOriginAndDestination(stateTransition, state, getNext(stateTransition.getNext())));
}
flow.setStateTransitions(updatedTransitions);
flow.afterPropertiesSet();
return flow;
}
private String getNext(String next) {
if (next == null) {
return null;
}
return (next.startsWith(this.prefix) ? "" : this.prefix) + next;
}
/**
* Convenience method to get a state that proxies the input but with a
* different name, appropriate to this flow. If the state is a StepState
* then the step name is also changed.
*
* @param state
* @return
*/
private State getProxyState(State state) {
String oldName = state.getName();
if (oldName.startsWith(prefix)) {
return state;
}
String stateName = prefix + oldName;
if (state instanceof StepState) {
Step step = ((StepState) state).getStep();
return new StepState(stateName, new DelegateStep(step, stateName));
}
return new DelegateState(stateName, state);
}
public Class<?> getObjectType() {
return SimpleFlow.class;
}
public boolean isSingleton() {
return true;
}
/**
* A State that proxies a delegate and changes its name but leaves its
* behaviour unchanged.
*
* @author Dave Syer
*
*/
private static class DelegateState extends AbstractState {
private final State state;
private DelegateState(String name, State state) {
super(name);
this.state = state;
}
public boolean isEndState() {
return state.isEndState();
}
@Override
public FlowExecutionStatus handle(FlowExecutor executor) throws Exception {
return state.handle(executor);
}
}
/**
* A Step that proxies a delegate and changes its name but leaves its
* behaviour unchanged.
*
* @author Dave Syer
*
*/
private static class DelegateStep implements Step {
private final Step step;
private final String name;
private DelegateStep(Step step, String name) {
this.step = step;
this.name = name;
}
public boolean isAllowStartIfComplete() {
return step.isAllowStartIfComplete();
}
public int getStartLimit() {
return step.getStartLimit();
}
public String getName() {
return name;
}
public void execute(StepExecution stepExecution) throws JobInterruptedException {
step.execute(stepExecution);
}
}
}

View File

@@ -18,9 +18,12 @@ package org.springframework.batch.core.configuration.xml;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
@@ -86,23 +89,28 @@ public class SplitParser {
@SuppressWarnings("unchecked")
Collection<Object> flows = new ManagedList();
int i = 0;
String prefix = idAttribute.startsWith(jobFactoryRef) ? idAttribute : jobFactoryRef+"."+idAttribute;
for (Element nextElement : flowElements) {
InlineFlowParser flowParser = new InlineFlowParser(idAttribute + "#" + i, jobFactoryRef);
String ref = nextElement.getAttribute("ref");
if (StringUtils.hasText(ref)) {
if (nextElement.getElementsByTagName("*").getLength() > 0) {
parserContext.getReaderContext().error("A <flow/> in a <split/> must have ref= or nested <flow/>, but not both.", nextElement);
}
flows.add(new RuntimeBeanReference(ref));
AbstractBeanDefinition flowDefinition = new GenericBeanDefinition();
flowDefinition.setParentName(ref);
MutablePropertyValues propertyValues = flowDefinition.getPropertyValues();
propertyValues.addPropertyValue("name", prefix + "." + i);
flows.add(flowDefinition);
}
else {
InlineFlowParser flowParser = new InlineFlowParser(prefix + "." + i, jobFactoryRef);
flows.add(flowParser.parse(nextElement, parserContext));
}
i++;
}
stateBuilder.addConstructorArgValue(flows);
stateBuilder.addConstructorArgValue(idAttribute);
stateBuilder.addConstructorArgValue(prefix);
return InlineFlowParser.getNextElements(parserContext, stateBuilder.getBeanDefinition(), element);

View File

@@ -33,7 +33,9 @@ public class TopLevelFlowParser extends AbstractFlowParser {
*/
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
setFlowName(element.getAttribute(ID_ATTR));
String flowName = element.getAttribute(ID_ATTR);
builder.getRawBeanDefinition().setAttribute("flowName", flowName);
builder.addPropertyValue("name", flowName);
super.doParse(element, parserContext, builder);
}

View File

@@ -64,6 +64,20 @@ public class StateTransition implements Comparable<StateTransition> {
return createStateTransition(state, pattern, null);
}
/**
* Convenience method to switch the origin and destination of a transition,
* creating a new instance.
*
* @param stateTransition an existing state transition
* @param state the new state for the origin
* @param next the new name for the destination
*
* @return a {@link StateTransition}
*/
public static StateTransition switchOriginAndDestination(StateTransition stateTransition, State state, String next) {
return createStateTransition(state, stateTransition.pattern, next);
}
/**
* Create a new state {@link StateTransition} specification with a wildcard
* pattern that matches all outcomes.
@@ -101,7 +115,7 @@ public class StateTransition implements Comparable<StateTransition> {
Assert.notNull(state, "A state is required for a StateTransition");
if (state.isEndState() && StringUtils.hasText(next)) {
throw new IllegalStateException("End state cannot have next: "+state);
throw new IllegalStateException("End state cannot have next: " + state);
}
this.next = next;
@@ -182,8 +196,8 @@ public class StateTransition implements Comparable<StateTransition> {
*/
@Override
public String toString() {
return String.format("StateTransition: [state=%s, pattern=%s, next=%s]", state == null ? null : state.getName(),
pattern, next);
return String.format("StateTransition: [state=%s, pattern=%s, next=%s]",
state == null ? null : state.getName(), pattern, next);
}
}

View File

@@ -67,7 +67,7 @@ public class BranchStepJobParserTests {
for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
names.add(stepExecution.getStepName());
}
assertTrue(names.contains("s3"));
assertFalse(names.contains("s2"));
assertTrue(names.contains("job.s3"));
assertFalse(names.contains("job.s2"));
}
}

View File

@@ -41,17 +41,17 @@ public class DefaultFailureJobParserTests extends AbstractJobParserTests {
JobExecution jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(2, stepNamesList.size());
assertTrue(stepNamesList.contains("s1"));
assertTrue(stepNamesList.contains("fail"));
assertTrue(stepNamesList.contains("job.s1"));
assertTrue(stepNamesList.contains("job.fail"));
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
assertEquals(ExitStatus.FAILED.getExitCode(), jobExecution.getExitStatus().getExitCode());
StepExecution stepExecution1 = getStepExecution(jobExecution, "s1");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.s1");
assertEquals(BatchStatus.COMPLETED, stepExecution1.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution1.getExitStatus());
StepExecution stepExecution2 = getStepExecution(jobExecution, "fail");
StepExecution stepExecution2 = getStepExecution(jobExecution, "job.fail");
assertEquals(BatchStatus.FAILED, stepExecution2.getStatus());
assertEquals(ExitStatus.FAILED.getExitCode(), stepExecution2.getExitStatus().getExitCode());

View File

@@ -41,17 +41,17 @@ public class DefaultSuccessJobParserTests extends AbstractJobParserTests {
JobExecution jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(2, stepNamesList.size());
assertTrue(stepNamesList.contains("s1"));
assertTrue(stepNamesList.contains("s2"));
assertTrue(stepNamesList.contains("job.s1"));
assertTrue(stepNamesList.contains("job.s2"));
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
StepExecution stepExecution1 = getStepExecution(jobExecution, "s1");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.s1");
assertEquals(BatchStatus.COMPLETED, stepExecution1.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution1.getExitStatus());
StepExecution stepExecution2 = getStepExecution(jobExecution, "s2");
StepExecution stepExecution2 = getStepExecution(jobExecution, "job.s2");
assertEquals(BatchStatus.COMPLETED, stepExecution2.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution2.getExitStatus());

View File

@@ -41,12 +41,12 @@ public class EndTransitionDefaultStatusJobParserTests extends AbstractJobParserT
JobExecution jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(1, stepNamesList.size());
assertTrue(stepNamesList.contains("fail"));
assertTrue(stepNamesList.contains("job.fail"));
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
StepExecution stepExecution1 = getStepExecution(jobExecution, "fail");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.fail");
assertEquals(BatchStatus.FAILED, stepExecution1.getStatus());
assertEquals(ExitStatus.FAILED.getExitCode(), stepExecution1.getExitStatus().getExitCode());

View File

@@ -46,17 +46,17 @@ public class EndTransitionJobParserTests extends AbstractJobParserTests {
JobExecution jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(2, stepNamesList.size());
assertTrue(stepNamesList.contains("s1"));
assertTrue(stepNamesList.contains("fail"));
assertTrue(stepNamesList.contains("job.s1"));
assertTrue(stepNamesList.contains("job.fail"));
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals("EARLY TERMINATION", jobExecution.getExitStatus().getExitCode());
StepExecution stepExecution1 = getStepExecution(jobExecution, "s1");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.s1");
assertEquals(BatchStatus.COMPLETED, stepExecution1.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution1.getExitStatus());
StepExecution stepExecution2 = getStepExecution(jobExecution, "fail");
StepExecution stepExecution2 = getStepExecution(jobExecution, "job.fail");
assertEquals(BatchStatus.FAILED, stepExecution2.getStatus());
assertEquals(ExitStatus.FAILED.getExitCode(), stepExecution2.getExitStatus().getExitCode());

View File

@@ -41,12 +41,12 @@ public class FailTransitionDefaultStatusJobParserTests extends AbstractJobParser
JobExecution jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(1, stepNamesList.size());
assertTrue(stepNamesList.contains("s1"));
assertTrue(stepNamesList.contains("job.s1"));
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
assertEquals(ExitStatus.FAILED, jobExecution.getExitStatus());
StepExecution stepExecution1 = getStepExecution(jobExecution, "s1");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.s1");
assertEquals(BatchStatus.COMPLETED, stepExecution1.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution1.getExitStatus());

View File

@@ -44,18 +44,18 @@ public class FailTransitionJobParserTests extends AbstractJobParserTests {
JobExecution jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(2, stepNamesList.size());
assertTrue(stepNamesList.contains("s1"));
assertTrue(stepNamesList.contains("fail"));
assertTrue(stepNamesList.contains("job.s1"));
assertTrue(stepNamesList.contains("job.fail"));
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
assertEquals("EARLY TERMINATION", jobExecution.getExitStatus()
.getExitCode());
StepExecution stepExecution1 = getStepExecution(jobExecution, "s1");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.s1");
assertEquals(BatchStatus.COMPLETED, stepExecution1.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution1.getExitStatus());
StepExecution stepExecution2 = getStepExecution(jobExecution, "fail");
StepExecution stepExecution2 = getStepExecution(jobExecution, "job.fail");
assertEquals(BatchStatus.FAILED, stepExecution2.getStatus());
assertEquals(ExitStatus.FAILED.getExitCode(), stepExecution2
.getExitStatus().getExitCode());
@@ -67,7 +67,7 @@ public class FailTransitionJobParserTests extends AbstractJobParserTests {
jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(1, stepNamesList.size());
assertTrue(stepNamesList.contains("fail"));
assertTrue(stepNamesList.contains("job.fail"));
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
}

View File

@@ -18,6 +18,9 @@ package org.springframework.batch.core.configuration.xml;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -25,6 +28,7 @@ import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
@@ -71,7 +75,9 @@ public class FlowJobParserTests {
JobExecution jobExecution = jobRepository.createJobExecution(job1.getName(), new JobParameters());
job1.execute(jobExecution);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(4, jobExecution.getStepExecutions().size());
List<String> stepNames = getStepNames(jobExecution);
assertEquals(4, stepNames.size());
assertEquals("[job1.s1, job1.flow.s2, job1.flow.s3, job1.s4]", stepNames.toString());
}
@Test
@@ -81,6 +87,9 @@ public class FlowJobParserTests {
job2.execute(jobExecution);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(3, jobExecution.getStepExecutions().size());
List<String> stepNames = getStepNames(jobExecution);
assertEquals(3, stepNames.size());
assertEquals("[job2.flow.s2, job2.flow.s3, job2.s1]", stepNames.toString());
}
@Test
@@ -89,7 +98,9 @@ public class FlowJobParserTests {
JobExecution jobExecution = jobRepository.createJobExecution(job3.getName(), new JobParameters());
job3.execute(jobExecution);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(2, jobExecution.getStepExecutions().size());
List<String> stepNames = getStepNames(jobExecution);
assertEquals(2, stepNames.size());
assertEquals("[job3.flow.s2, job3.flow.s3]", stepNames.toString());
}
@Test
@@ -98,7 +109,17 @@ public class FlowJobParserTests {
JobExecution jobExecution = jobRepository.createJobExecution(job4.getName(), new JobParameters());
job4.execute(jobExecution);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(4, jobExecution.getStepExecutions().size());
List<String> stepNames = getStepNames(jobExecution);
assertEquals(4, stepNames.size());
assertEquals("[job4.split.0.s2, job4.split.0.s3, job4.split.1.s2, job4.split.1.s3]", stepNames.toString());
}
private List<String> getStepNames(JobExecution jobExecution) {
List<String> list = new ArrayList<String>();
for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
list.add(stepExecution.getStepName());
}
return list;
}
}

View File

@@ -0,0 +1,51 @@
package org.springframework.batch.core.configuration.xml;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class JobParserExceptionTests {
@Test
public void testUnreachableStep() {
try {
new ClassPathXmlApplicationContext(
"org/springframework/batch/core/configuration/xml/JobParserUnreachableStepTests-context.xml");
fail("Error expected");
}
catch (BeanDefinitionParsingException e) {
assertTrue(e.getMessage().contains("The element [s2] is unreachable"));
}
}
@Test
public void testUnreachableStepInFlow() {
try {
new ClassPathXmlApplicationContext(
"org/springframework/batch/core/configuration/xml/JobParserUnreachableStepInFlowTests-context.xml");
fail("Error expected");
}
catch (BeanDefinitionParsingException e) {
assertTrue(e.getMessage().contains("The element [s4] is unreachable"));
}
}
@Test
public void testNextOutOfScope() {
try {
new ClassPathXmlApplicationContext(
"org/springframework/batch/core/configuration/xml/JobParserNextOutOfScopeTests-context.xml");
fail("Error expected");
}
catch (BeanCreationException e) {
String message = e.getMessage();
assertTrue("Wrong message: "+message, message.matches(".*Missing state for \\[StateTransition: \\[state=.*s2, pattern=\\*, next=.*s3\\]\\]"));
}
}
}

View File

@@ -17,7 +17,6 @@ package org.springframework.batch.core.configuration.xml;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.Collection;
@@ -33,8 +32,6 @@ import org.springframework.batch.core.job.DefaultJobParametersValidator;
import org.springframework.batch.core.listener.JobExecutionListenerSupport;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.SimpleJobRepository;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@@ -148,42 +145,6 @@ public class JobParserTests {
return (JobRepository) jobRepository;
}
@Test
public void testUnreachableStep() {
try {
new ClassPathXmlApplicationContext(
"org/springframework/batch/core/configuration/xml/JobParserUnreachableStepTests-context.xml");
fail("Error expected");
}
catch (BeanDefinitionParsingException e) {
assertTrue(e.getMessage().contains("The element [s2] is unreachable"));
}
}
@Test
public void testUnreachableStepInFlow() {
try {
new ClassPathXmlApplicationContext(
"org/springframework/batch/core/configuration/xml/JobParserUnreachableStepInFlowTests-context.xml");
fail("Error expected");
}
catch (BeanDefinitionParsingException e) {
assertTrue(e.getMessage().contains("The element [s4] is unreachable"));
}
}
@Test
public void testNextOutOfScope() {
try {
new ClassPathXmlApplicationContext(
"org/springframework/batch/core/configuration/xml/JobParserNextOutOfScopeTests-context.xml");
fail("Error expected");
}
catch (BeanCreationException e) {
assertTrue(e.getMessage().contains("Missing state for [StateTransition: [state=s2, pattern=*, next=s3]]"));
}
}
@Test
public void testParametersValidator() {
ApplicationContext ctx = jobParserParentAttributeTestsCtx;

View File

@@ -44,17 +44,17 @@ public class NextAttributeJobParserTests extends AbstractJobParserTests {
JobExecution jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(2, stepNamesList.size()); //s2 is not executed
assertTrue(stepNamesList.contains("s1"));
assertTrue(stepNamesList.contains("fail"));
assertTrue(stepNamesList.contains("job.s1"));
assertTrue(stepNamesList.contains("job.fail"));
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
assertEquals("FAILED", jobExecution.getExitStatus().getExitCode());
StepExecution stepExecution1 = getStepExecution(jobExecution, "s1");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.s1");
assertEquals(BatchStatus.COMPLETED, stepExecution1.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution1.getExitStatus());
StepExecution stepExecution2 = getStepExecution(jobExecution, "fail");
StepExecution stepExecution2 = getStepExecution(jobExecution, "job.fail");
assertEquals(BatchStatus.FAILED, stepExecution2.getStatus());
assertEquals(ExitStatus.FAILED.getExitCode(), stepExecution2.getExitStatus().getExitCode());
@@ -65,12 +65,12 @@ public class NextAttributeJobParserTests extends AbstractJobParserTests {
jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(1, stepNamesList.size()); //s1,s2 are not executed
assertTrue(stepNamesList.contains("fail"));
assertTrue(stepNamesList.contains("job.fail"));
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
assertEquals("FAILED", jobExecution.getExitStatus().getExitCode());
StepExecution stepExecution3 = getStepExecution(jobExecution, "fail");
StepExecution stepExecution3 = getStepExecution(jobExecution, "job.fail");
assertEquals(BatchStatus.FAILED, stepExecution3.getStatus());
assertEquals(ExitStatus.FAILED.getExitCode(), stepExecution3.getExitStatus().getExitCode());

View File

@@ -41,17 +41,17 @@ public class SplitDifferentResultsFailFirstJobParserTests extends AbstractJobPar
JobExecution jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(2, stepNamesList.size());
assertTrue(stepNamesList.contains("s1"));
assertTrue(stepNamesList.contains("fail"));
assertTrue("Wrong step names: "+stepNamesList, stepNamesList.contains("job.split1.1.s1"));
assertTrue(stepNamesList.contains("job.split1.0.fail"));
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
assertEquals(ExitStatus.FAILED, jobExecution.getExitStatus());
StepExecution stepExecution1 = getStepExecution(jobExecution, "s1");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.split1.1.s1");
assertEquals(BatchStatus.COMPLETED, stepExecution1.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution1.getExitStatus());
StepExecution stepExecution2 = getStepExecution(jobExecution, "fail");
StepExecution stepExecution2 = getStepExecution(jobExecution, "job.split1.0.fail");
assertEquals(BatchStatus.FAILED, stepExecution2.getStatus());
assertEquals(ExitStatus.FAILED.getExitCode(), stepExecution2.getExitStatus().getExitCode());

View File

@@ -41,23 +41,23 @@ public class SplitDifferentResultsFailSecondJobParserTests extends AbstractJobPa
JobExecution jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals("Wrong step names: "+stepNamesList, 3, stepNamesList.size());
assertTrue(stepNamesList.contains("s1"));
assertTrue(stepNamesList.contains("fail"));
assertTrue(stepNamesList.contains("s3"));
assertTrue("Wrong step names: "+stepNamesList, stepNamesList.contains("job.split1.0.s1"));
assertTrue("Wrong step names: "+stepNamesList, stepNamesList.contains("job.split1.1.fail"));
assertTrue(stepNamesList.contains("job.s3"));
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
// You can't suppress a FAILED exit status
assertEquals(ExitStatus.FAILED, jobExecution.getExitStatus());
StepExecution stepExecution1 = getStepExecution(jobExecution, "s1");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.split1.0.s1");
assertEquals(BatchStatus.COMPLETED, stepExecution1.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution1.getExitStatus());
StepExecution stepExecution2 = getStepExecution(jobExecution, "fail");
StepExecution stepExecution2 = getStepExecution(jobExecution, "job.split1.1.fail");
assertEquals(BatchStatus.FAILED, stepExecution2.getStatus());
assertEquals(ExitStatus.FAILED.getExitCode(), stepExecution2.getExitStatus().getExitCode());
StepExecution stepExecution3 = getStepExecution(jobExecution, "s3");
StepExecution stepExecution3 = getStepExecution(jobExecution, "job.s3");
assertEquals(BatchStatus.COMPLETED, stepExecution3.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution3.getExitStatus());

View File

@@ -52,9 +52,9 @@ public class SplitInterruptedJobParserTests extends AbstractJobParserTests {
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
assertEquals(ExitStatus.STOPPED.getExitCode(), jobExecution.getExitStatus().getExitCode());
assertTrue(stepNamesList.contains("stop"));
assertTrue("Wrong step names: "+stepNamesList, stepNamesList.contains("job.split1.0.stop"));
StepExecution stepExecution = getStepExecution(jobExecution, "stop");
StepExecution stepExecution = getStepExecution(jobExecution, "job.split1.0.stop");
assertEquals(BatchStatus.STOPPED, stepExecution.getStatus());
assertEquals(ExitStatus.STOPPED.getExitCode(), stepExecution.getExitStatus().getExitCode());

View File

@@ -65,10 +65,10 @@ public class StepWithSimpleTaskJobParserTests {
assertTrue(job instanceof FlowJob);
JobExecution jobExecution = jobRepository.createJobExecution(job.getName(), new JobParameters());
TestTasklet t1 = assertTasklet(job, "step1", "t1");
TestTasklet t2 = assertTasklet(job, "step2", "t2");
TestTasklet t3 = assertTasklet(job, "step3", "t3");
TestTasklet t4 = assertTasklet(job, "step4", "t4");
TestTasklet t1 = assertTasklet(job, "job.step1", "t1");
TestTasklet t2 = assertTasklet(job, "job.step2", "t2");
TestTasklet t3 = assertTasklet(job, "job.step3", "t3");
TestTasklet t4 = assertTasklet(job, "job.step4", "t4");
job.execute(jobExecution);
@@ -83,7 +83,7 @@ public class StepWithSimpleTaskJobParserTests {
}
private TestTasklet assertTasklet(Job job, String stepName, String taskletName) {
Step step = ((FlowJob) job).getStep(stepName);
Step step = (Step) ReflectionTestUtils.getField(((FlowJob) job).getStep(stepName), "step");
assertTrue(step instanceof TaskletStep);
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
assertTrue(tasklet instanceof TestTasklet);

View File

@@ -43,8 +43,8 @@ public class StopAndRestartFailedJobParserTests extends AbstractJobParserTests {
//
// First Launch
//
JobExecution jobExecution = launchAndAssert("[s0, s1]");
StepExecution stepExecution = getStepExecution(jobExecution, "s1");
JobExecution jobExecution = launchAndAssert("[job.s0, job.s1]");
StepExecution stepExecution = getStepExecution(jobExecution, "job.s1");
assertEquals(BatchStatus.ABANDONED, stepExecution.getStatus());
assertEquals(ExitStatus.FAILED.getExitCode(), stepExecution.getExitStatus().getExitCode());
@@ -52,8 +52,8 @@ public class StopAndRestartFailedJobParserTests extends AbstractJobParserTests {
// Second Launch
//
stepNamesList.clear();
jobExecution = launchAndAssert("[s0, s2]");
stepExecution = getStepExecution(jobExecution, "s2");
jobExecution = launchAndAssert("[job.s0, job.s2]");
stepExecution = getStepExecution(jobExecution, "job.s2");
assertEquals(BatchStatus.COMPLETED, stepExecution.getStatus());
assertEquals(ExitStatus.COMPLETED.getExitCode(), stepExecution.getExitStatus().getExitCode());

View File

@@ -44,12 +44,12 @@ public class StopAndRestartJobParserTests extends AbstractJobParserTests {
JobExecution jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(1, stepNamesList.size());
assertTrue(stepNamesList.contains("s1"));
assertTrue(stepNamesList.contains("job.s1"));
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
assertEquals(ExitStatus.STOPPED.getExitCode(), jobExecution.getExitStatus().getExitCode());
StepExecution stepExecution1 = getStepExecution(jobExecution, "s1");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.s1");
assertEquals(BatchStatus.COMPLETED, stepExecution1.getStatus());
assertEquals(ExitStatus.COMPLETED.getExitCode(), stepExecution1.getExitStatus().getExitCode());
@@ -60,12 +60,12 @@ public class StopAndRestartJobParserTests extends AbstractJobParserTests {
jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(1, stepNamesList.size()); // step1 is not executed
assertTrue(stepNamesList.contains("s2"));
assertTrue(stepNamesList.contains("job.s2"));
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
StepExecution stepExecution2 = getStepExecution(jobExecution, "s2");
StepExecution stepExecution2 = getStepExecution(jobExecution, "job.s2");
assertEquals(BatchStatus.COMPLETED, stepExecution2.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution2.getExitStatus());

View File

@@ -43,13 +43,13 @@ public class StopCustomStatusJobParserTests extends AbstractJobParserTests {
//
JobExecution jobExecution = createJobExecution();
job.execute(jobExecution);
assertTrue("Wrong steps executed: "+stepNamesList, stepNamesList.contains("stop"));
assertTrue("Wrong steps executed: "+stepNamesList, stepNamesList.contains("job.stop"));
assertEquals(1, stepNamesList.size());
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
assertEquals(ExitStatus.STOPPED.getExitCode(), jobExecution.getExitStatus().getExitCode());
StepExecution stepExecution1 = getStepExecution(jobExecution, "stop");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.stop");
assertEquals(BatchStatus.COMPLETED, stepExecution1.getStatus());
assertEquals("FOO", stepExecution1.getExitStatus().getExitCode());
@@ -59,13 +59,13 @@ public class StopCustomStatusJobParserTests extends AbstractJobParserTests {
stepNamesList.clear();
jobExecution = createJobExecution();
job.execute(jobExecution);
assertTrue("Wrong steps executed: "+stepNamesList, stepNamesList.contains("s2"));
assertTrue("Wrong steps executed: "+stepNamesList, stepNamesList.contains("job.s2"));
assertEquals(1, stepNamesList.size()); // step1 is not executed
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
StepExecution stepExecution2 = getStepExecution(jobExecution, "s2");
StepExecution stepExecution2 = getStepExecution(jobExecution, "job.s2");
assertEquals(BatchStatus.COMPLETED, stepExecution2.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution2.getExitStatus());

View File

@@ -43,13 +43,13 @@ public class StopIncompleteJobParserTests extends AbstractJobParserTests {
//
JobExecution jobExecution = createJobExecution();
job.execute(jobExecution);
assertTrue("Wrong steps executed: "+stepNamesList, stepNamesList.contains("fail"));
assertTrue("Wrong steps executed: "+stepNamesList, stepNamesList.contains("job.fail"));
assertEquals(1, stepNamesList.size());
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
assertEquals(ExitStatus.STOPPED.getExitCode(), jobExecution.getExitStatus().getExitCode());
StepExecution stepExecution1 = getStepExecution(jobExecution, "fail");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.fail");
assertEquals(BatchStatus.ABANDONED, stepExecution1.getStatus());
assertEquals(ExitStatus.FAILED.getExitCode(), stepExecution1.getExitStatus().getExitCode());
@@ -59,13 +59,13 @@ public class StopIncompleteJobParserTests extends AbstractJobParserTests {
stepNamesList.clear();
jobExecution = createJobExecution();
job.execute(jobExecution);
assertTrue("Wrong steps executed: "+stepNamesList, stepNamesList.contains("s2"));
assertTrue("Wrong steps executed: "+stepNamesList, stepNamesList.contains("job.s2"));
assertEquals(1, stepNamesList.size()); // step1 is not executed
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
StepExecution stepExecution2 = getStepExecution(jobExecution, "s2");
StepExecution stepExecution2 = getStepExecution(jobExecution, "job.s2");
assertEquals(BatchStatus.COMPLETED, stepExecution2.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution2.getExitStatus());

View File

@@ -46,12 +46,12 @@ public class StopJobParserTests extends AbstractJobParserTests {
JobExecution jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(1, stepNamesList.size());
assertTrue(stepNamesList.contains("s1"));
assertTrue(stepNamesList.contains("job.s1"));
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
assertEquals(ExitStatus.STOPPED.getExitCode(), jobExecution.getExitStatus().getExitCode());
StepExecution stepExecution1 = getStepExecution(jobExecution, "s1");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.s1");
assertEquals(BatchStatus.COMPLETED, stepExecution1.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution1.getExitStatus());
@@ -62,12 +62,12 @@ public class StopJobParserTests extends AbstractJobParserTests {
jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(1, stepNamesList.size()); // step1 is not executed
assertTrue(stepNamesList.contains("s2"));
assertTrue(stepNamesList.contains("job.s2"));
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
StepExecution stepExecution2 = getStepExecution(jobExecution, "s2");
StepExecution stepExecution2 = getStepExecution(jobExecution, "job.s2");
assertEquals(BatchStatus.COMPLETED, stepExecution2.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution2.getExitStatus());

View File

@@ -43,13 +43,13 @@ public class StopRestartOnCompletedStepJobParserTests extends AbstractJobParserT
//
// First Launch
//
launchAndAssert("[s1]");
launchAndAssert("[job.s1]");
//
// Second Launch
//
stepNamesList.clear();
launchAndAssert("[s1]");
launchAndAssert("[job.s1]");
}
@@ -62,7 +62,7 @@ public class StopRestartOnCompletedStepJobParserTests extends AbstractJobParserT
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
assertEquals(ExitStatus.STOPPED.getExitCode(), jobExecution.getExitStatus().getExitCode());
StepExecution stepExecution1 = getStepExecution(jobExecution, "s1");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.s1");
assertEquals(BatchStatus.COMPLETED, stepExecution1.getStatus());
assertEquals(ExitStatus.COMPLETED.getExitCode(), stepExecution1.getExitStatus().getExitCode());
}

View File

@@ -43,13 +43,13 @@ public class StopRestartOnFailedStepJobParserTests extends AbstractJobParserTest
//
// First Launch
//
launchAndAssert("[s0, fail]");
launchAndAssert("[job.s0, job.fail]");
//
// Second Launch
//
stepNamesList.clear();
launchAndAssert("[fail]");
launchAndAssert("[job.fail]");
}
@@ -62,7 +62,7 @@ public class StopRestartOnFailedStepJobParserTests extends AbstractJobParserTest
assertEquals(BatchStatus.STOPPED, jobExecution.getStatus());
assertEquals(ExitStatus.STOPPED.getExitCode(), jobExecution.getExitStatus().getExitCode());
StepExecution stepExecution1 = getStepExecution(jobExecution, "fail");
StepExecution stepExecution1 = getStepExecution(jobExecution, "job.fail");
assertEquals(BatchStatus.FAILED, stepExecution1.getStatus());
assertEquals(ExitStatus.FAILED.getExitCode(), stepExecution1.getExitStatus().getExitCode());
}