Created a JSR-352 specific StepState to maintain in the Job's
ExecutionContext what the last step executed was. This is needed for restarts when the step to restart at is a DecisionStep.
This commit is contained in:
@@ -151,11 +151,25 @@ public class SimpleFlowFactoryBean implements FactoryBean, InitializingBean {
|
||||
}
|
||||
String stateName = prefix + oldName;
|
||||
if (state instanceof StepState) {
|
||||
return new StepState(stateName, ((StepState) state).getStep(oldName));
|
||||
return createNewStepState(state, oldName, stateName);
|
||||
}
|
||||
return new DelegateState(stateName, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an extension point to provide alternative {@link StepState}
|
||||
* implementations within a {@link SimpleFlow}
|
||||
*
|
||||
* @param state The state that will be used to create the StepState
|
||||
* @param oldName The name to be replaced
|
||||
* @param stateName The name for the new State
|
||||
* @return
|
||||
*/
|
||||
protected State createNewStepState(State state, String oldName,
|
||||
String stateName) {
|
||||
return new StepState(stateName, ((StepState) state).getStep(oldName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return SimpleFlow.class;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -18,8 +18,8 @@ package org.springframework.batch.core.jsr.configuration.xml;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.batch.core.job.flow.JobExecutionDecider;
|
||||
import org.springframework.batch.core.job.flow.support.state.StepState;
|
||||
import org.springframework.batch.core.jsr.configuration.support.BatchArtifact;
|
||||
import org.springframework.batch.core.jsr.job.flow.support.state.StepState;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
|
||||
@@ -24,7 +24,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.batch.core.configuration.xml.AbstractFlowParser;
|
||||
import org.springframework.batch.core.configuration.xml.SimpleFlowFactoryBean;
|
||||
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
|
||||
import org.springframework.batch.core.jsr.job.flow.support.DefaultFlow;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -73,7 +72,7 @@ public class FlowParser extends AbstractFlowParser {
|
||||
|
||||
@Override
|
||||
protected Class<?> getBeanClass(Element element) {
|
||||
return SimpleFlowFactoryBean.class;
|
||||
return JsrFlowFactoryBean.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2014 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.springframework.batch.core.configuration.xml.SimpleFlowFactoryBean;
|
||||
import org.springframework.batch.core.job.flow.State;
|
||||
import org.springframework.batch.core.jsr.job.flow.support.state.StepState;
|
||||
|
||||
/**
|
||||
* Extension to the {@link SimpleFlowFactoryBean} that provides {@link StepState}
|
||||
* implementations for JSR-352 based jobs.
|
||||
*
|
||||
* @author Michael Minella
|
||||
* @since 3.0
|
||||
*/
|
||||
public class JsrFlowFactoryBean extends SimpleFlowFactoryBean {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.configuration.xml.SimpleFlowFactoryBean#createNewStepState(org.springframework.batch.core.job.flow.State, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected State createNewStepState(State state, String oldName,
|
||||
String stateName) {
|
||||
return new StepState(stateName, ((StepState) state).getStep(oldName));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2014 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.
|
||||
@@ -17,8 +17,8 @@ package org.springframework.batch.core.jsr.configuration.xml;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.batch.core.job.flow.support.state.StepState;
|
||||
import org.springframework.batch.core.jsr.configuration.support.BatchArtifact;
|
||||
import org.springframework.batch.core.jsr.job.flow.support.state.StepState;
|
||||
import org.springframework.batch.core.listener.StepListenerFactoryBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
|
||||
@@ -29,9 +29,9 @@ import org.springframework.batch.core.job.flow.FlowJob;
|
||||
import org.springframework.batch.core.job.flow.JobFlowExecutor;
|
||||
import org.springframework.batch.core.job.flow.State;
|
||||
import org.springframework.batch.core.job.flow.support.state.FlowState;
|
||||
import org.springframework.batch.core.job.flow.support.state.StepState;
|
||||
import org.springframework.batch.core.jsr.job.DefaultStepHandler;
|
||||
import org.springframework.batch.core.jsr.job.flow.support.DefaultFlow;
|
||||
import org.springframework.batch.core.jsr.job.flow.support.state.StepState;
|
||||
import org.springframework.batch.core.jsr.step.DecisionStep;
|
||||
import org.springframework.batch.core.launch.NoSuchJobException;
|
||||
import org.springframework.batch.core.launch.support.ExitCodeMapper;
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.springframework.batch.core.job.flow.FlowExecutionStatus;
|
||||
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.StepState;
|
||||
import org.springframework.batch.core.jsr.job.flow.support.state.StepState;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ public class SplitState extends org.springframework.batch.core.job.flow.support.
|
||||
}
|
||||
|
||||
if(!stepNames.isEmpty()) {
|
||||
executor.getJobExecution().getExecutionContext().put("batch.splitLastSteps", stepNames);
|
||||
executor.getJobExecution().getExecutionContext().put("batch.lastSteps", stepNames);
|
||||
}
|
||||
|
||||
executor.getJobExecution().setExitStatus(null);
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2014 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.job.flow.support.state;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
|
||||
import org.springframework.batch.core.job.flow.FlowExecutor;
|
||||
|
||||
/**
|
||||
* Extends {@link org.springframework.batch.core.job.flow.support.state.StepState} to persist what the
|
||||
* last step that was executed was (used in Decisions and restarts).
|
||||
*
|
||||
* @author Michael Minella
|
||||
* @since 3.0
|
||||
*/
|
||||
public class StepState extends org.springframework.batch.core.job.flow.support.state.StepState {
|
||||
|
||||
/**
|
||||
* @param step the step that will be executed
|
||||
*/
|
||||
public StepState(Step step) {
|
||||
super(step);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name for the step that will be executed
|
||||
* @param step the step that will be executed
|
||||
*/
|
||||
public StepState(String name, Step step) {
|
||||
super(name, step);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.job.flow.support.state.StepState#handle(org.springframework.batch.core.job.flow.FlowExecutor)
|
||||
*/
|
||||
@Override
|
||||
public FlowExecutionStatus handle(FlowExecutor executor) throws Exception {
|
||||
FlowExecutionStatus result = super.handle(executor);
|
||||
|
||||
executor.getJobExecution().getExecutionContext().put("batch.lastSteps", Collections.singletonList(getStep().getName()));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -47,13 +47,14 @@ public class DecisionStep extends AbstractStep {
|
||||
this.decider = decider;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void doExecute(StepExecution stepExecution) throws Exception {
|
||||
ExecutionContext executionContext = stepExecution.getJobExecution().getExecutionContext();
|
||||
List<javax.batch.runtime.StepExecution> stepExecutions = new ArrayList<javax.batch.runtime.StepExecution>();
|
||||
|
||||
if(executionContext.containsKey("batch.splitLastSteps")) {
|
||||
List<String> stepNames = (List<String>) executionContext.get("batch.splitLastSteps");
|
||||
if(executionContext.containsKey("batch.lastSteps")) {
|
||||
List<String> stepNames = (List<String>) executionContext.get("batch.lastSteps");
|
||||
|
||||
for (String stepName : stepNames) {
|
||||
StepExecution curStepExecution = getJobRepository().getLastStepExecution(stepExecution.getJobExecution().getJobInstance(), stepName);
|
||||
@@ -81,8 +82,8 @@ public class DecisionStep extends AbstractStep {
|
||||
stepExecution.getJobExecution().setExitStatus(exitStatus);
|
||||
stepExecution.setExitStatus(exitStatus);
|
||||
|
||||
if(executionContext.containsKey("batch.splitLastSteps")) {
|
||||
executionContext.remove("batch.splitLastSteps");
|
||||
if(executionContext.containsKey("batch.lastSteps")) {
|
||||
executionContext.remove("batch.lastSteps");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
stepExecution.setTerminateOnly();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.springframework.batch.core.jsr.step;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.batch.core.jsr.JsrTestUtils.restartJob;
|
||||
import static org.springframework.batch.core.jsr.JsrTestUtils.runJob;
|
||||
|
||||
import java.util.List;
|
||||
@@ -20,6 +21,7 @@ import org.springframework.beans.factory.access.BeanFactoryReference;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
public class DecisionStepTests {
|
||||
|
||||
@@ -101,6 +103,45 @@ public class DecisionStepTests {
|
||||
assertEquals(2, StepExecutionCountingDecider.previousStepCount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecisionRestart() throws Exception {
|
||||
JobExecution execution = runJob("DecisionStepTests-restart-context", new Properties(), 10000l);
|
||||
assertEquals(BatchStatus.STOPPED, execution.getBatchStatus());
|
||||
|
||||
List<StepExecution> stepExecutions = BatchRuntime.getJobOperator().getStepExecutions(execution.getExecutionId());
|
||||
assertEquals(2, stepExecutions.size());
|
||||
|
||||
assertEquals("step1", stepExecutions.get(0).getStepName());
|
||||
assertEquals("decision1", stepExecutions.get(1).getStepName());
|
||||
|
||||
JobExecution execution2 = restartJob(execution.getExecutionId(), new Properties(), 10000l);
|
||||
assertEquals(BatchStatus.COMPLETED, execution2.getBatchStatus());
|
||||
|
||||
List<StepExecution> stepExecutions2 = BatchRuntime.getJobOperator().getStepExecutions(execution2.getExecutionId());
|
||||
assertEquals(2, stepExecutions2.size());
|
||||
|
||||
assertEquals("decision1", stepExecutions2.get(0).getStepName());
|
||||
assertEquals("step2", stepExecutions2.get(1).getStepName());
|
||||
}
|
||||
|
||||
public static class RestartDecider implements Decider {
|
||||
|
||||
private static int runs = 0;
|
||||
|
||||
@Override
|
||||
public String decide(StepExecution[] executions) throws Exception {
|
||||
Assert.isTrue(executions.length == 1);
|
||||
Assert.isTrue(executions[0].getStepName().equals("step1"));
|
||||
|
||||
if(runs == 0) {
|
||||
runs++;
|
||||
return "STOP_HERE";
|
||||
} else {
|
||||
return "CONTINUE";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class StepExecutionCountingDecider implements Decider {
|
||||
|
||||
static int previousStepCount = 0;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/jobXML_1_0.xsd">
|
||||
<job id="job1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
|
||||
<step id="step1" next="decision1">
|
||||
<batchlet ref="doSomethingBatchlet"/>
|
||||
</step>
|
||||
<decision ref="org.springframework.batch.core.jsr.step.DecisionStepTests.RestartDecider" id="decision1">
|
||||
<stop on="STOP_HERE"/>
|
||||
<next on="CONTINUE" to="step2"/>
|
||||
</decision>
|
||||
<step id="step2">
|
||||
<batchlet ref="doSomethingBatchlet"/>
|
||||
</step>
|
||||
</job>
|
||||
|
||||
<bean id="doSomethingBatchlet" class="org.springframework.batch.core.jsr.step.batchlet.BatchletSupport" scope="step"/>
|
||||
</beans>
|
||||
Reference in New Issue
Block a user