BATCH-1067:

* FlowJob waits until the Job is finished before updating BatchStatus and ExitStatus.  This is required so that individual flows in a split don't modifify the JobExecution prematurely.
* Removed FlowExecution$Status and replaced it with FlowExecutionStatus, a class that holds both a BatchStatus and an ExitStatus.  This is required by the EndState because the handle() method needs to be able to return both BatchStatus and ExitStatus so that they can be applied correctly to the JobExecution when ending the job.
This commit is contained in:
dhgarrette
2009-02-08 18:32:03 +00:00
parent 1e1c78408f
commit 7c4953f2be
22 changed files with 270 additions and 157 deletions

View File

@@ -16,6 +16,7 @@
package org.springframework.batch.core;
/**
* Enumeration representing the status of a an Execution.
*
@@ -115,4 +116,21 @@ public enum BatchStatus {
return this.compareTo(other) <= 0;
}
/**
* Find a BatchStatus that matches the beginning of the given value. If
* no match is found, return COMPLETED as the default because has is low
* precedence.
*
* @param value a string representing a status
* @return a BatchStatus
*/
public static BatchStatus match(String value) {
for (BatchStatus status : values()) {
if (value.startsWith(status.toString())) {
return status;
}
}
// Default match should be the lowest priority
return COMPLETED;
}
}

View File

@@ -15,61 +15,35 @@
*/
package org.springframework.batch.core.job.flow;
/**
* @author Dave Syer
*
*/
public class FlowExecution implements Comparable<FlowExecution> {
/**
* Special well-known status value.
*/
public static final String COMPLETED = Status.COMPLETED.toString();
/**
* Special well-known status value.
*/
public static final String PAUSED = Status.PAUSED.toString();
/**
* Special well-known status value.
*/
public static final String FAILED = Status.FAILED.toString();
/**
* Special well-known status value.
*/
public static final String UNKNOWN = Status.UNKNOWN.toString();
private final String name;
private final String status;
private enum Status {
COMPLETED, PAUSED, FAILED, UNKNOWN;
static Status match(String value) {
for (int i = 0; i < values().length; i++) {
Status status = values()[i];
if (value.startsWith(status.toString())) {
return status;
}
}
// Default match should be the lowest priority
return COMPLETED;
}
};
private final FlowExecutionStatus status;
/**
*
* @param name
* @param status
*/
public FlowExecution(String name, String status) {
public FlowExecution(String name, FlowExecutionStatus status) {
this.name = name;
this.status = status;
}
/**
* Convenience constructor that converts a String status to a {@link FlowExecutionStatus}.
*
* @param name
* @param status
*/
public FlowExecution(String name, String status) {
this(name, new FlowExecutionStatus(status));
}
/**
* @return the name of the end state reached
*/
@@ -80,7 +54,7 @@ public class FlowExecution implements Comparable<FlowExecution> {
/**
* @return the exit status
*/
public String getStatus() {
public FlowExecutionStatus getStatus() {
return status;
}
@@ -94,13 +68,7 @@ public class FlowExecution implements Comparable<FlowExecution> {
* @return negative, zero or positive as per the contract
*/
public int compareTo(FlowExecution other) {
Status one = Status.match(this.getStatus());
Status two = Status.match(other.getStatus());
int comparison = one.compareTo(two);
if (comparison==0) {
return this.getStatus().compareTo(other.getStatus());
}
return comparison;
return this.status.compareTo(other.getStatus());
}
@Override

View File

@@ -0,0 +1,135 @@
/*
* Copyright 2006-2007 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.job.flow;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
/**
* This class is used as a holder for a BatchStatus/ExitStatus pair.
*
* @author Dan Garrette
* @since 2.0
*/
public class FlowExecutionStatus implements Comparable<FlowExecutionStatus> {
private final String status;
private final ExitStatus exitStatus;
/**
* Special well-known status value.
*/
public static final FlowExecutionStatus COMPLETED = new FlowExecutionStatus(BatchStatus.COMPLETED,
ExitStatus.COMPLETED);
/**
* Special well-known status value.
*/
public static final FlowExecutionStatus STOPPED = new FlowExecutionStatus(BatchStatus.STOPPED, ExitStatus.FAILED);
/**
* Special well-known status value.
*/
public static final FlowExecutionStatus FAILED = new FlowExecutionStatus(BatchStatus.FAILED, ExitStatus.FAILED);
/**
* Special well-known status value.
*/
public static final FlowExecutionStatus UNKNOWN = new FlowExecutionStatus(BatchStatus.UNKNOWN, ExitStatus.UNKNOWN);
/**
* @param status
*/
public FlowExecutionStatus(String status) {
this(status, null);
}
/**
* @param status
* @param exitStatus
*/
public FlowExecutionStatus(String status, ExitStatus exitStatus) {
this.status = status;
this.exitStatus = exitStatus;
}
/**
* Convenience constructor that accepts a {@link BatchStatus} and
* {@link ExitStatus}.
*
* @param batchStatus
* @param exitStatus
*/
public FlowExecutionStatus(BatchStatus batchStatus, ExitStatus exitStatus) {
this(batchStatus.toString(), exitStatus);
}
/**
* Convenience getter for the {@link BatchStatus}.
*
* @return a {@link BatchStatus} representing the status
*/
public BatchStatus getBatchStatus() {
return BatchStatus.match(status);
}
/**
* Create an ordering on {@link FlowExecutionStatus} instances by comparing
* their statuses.
*
* @see Comparable#compareTo(Object)
*
* @param other
* @return negative, zero or positive as per the contract
*/
public int compareTo(FlowExecutionStatus other) {
BatchStatus one = this.getBatchStatus();
BatchStatus two = other.getBatchStatus();
int comparison = one.compareTo(two);
if (comparison == 0) {
return status.compareTo(other.getStatus());
}
return comparison;
}
/**
* Check the equality of the statuses.
*
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (!(other instanceof FlowExecutionStatus)) {
return false;
}
FlowExecutionStatus flowExecutionStatus = (FlowExecutionStatus) other;
return status.equals(flowExecutionStatus.getStatus());
}
public String toString() {
return "FlowExecutionStatus: status=[" + status + "] exitstatus=[" + exitStatus + "]";
}
public String getStatus() {
return status;
}
public ExitStatus getExitStatus() {
return exitStatus;
}
}

View File

@@ -16,6 +16,7 @@
package org.springframework.batch.core.job.flow;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionException;
import org.springframework.batch.core.JobInterruptedException;
@@ -76,7 +77,13 @@ public class FlowJob extends AbstractJob {
@Override
protected void doExecute(final JobExecution execution) throws JobExecutionException {
try {
flow.start(new JobFlowExecutor(execution));
FlowExecution flowExecution = flow.start(new JobFlowExecutor(execution));
synchronized (execution) {
FlowExecutionStatus status = flowExecution.getStatus();
execution.upgradeStatus(status.getBatchStatus());
execution.setExitStatus(status.getExitStatus());
}
}
catch (FlowExecutionException e) {
if (e.getCause() instanceof JobExecutionException) {
@@ -111,7 +118,7 @@ public class FlowJob extends AbstractJob {
}
StepExecution stepExecution = handleStep(step, execution);
stepExecutionHolder.set(stepExecution);
return stepExecution==null ? FlowExecution.COMPLETED : stepExecution.getExitStatus().getExitCode();
return stepExecution==null ? ExitStatus.COMPLETED.getExitCode() : stepExecution.getExitStatus().getExitCode();
}
public JobExecution getJobExecution() {

View File

@@ -28,6 +28,7 @@ import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.flow.Flow;
import org.springframework.batch.core.job.flow.FlowExecution;
import org.springframework.batch.core.job.flow.FlowExecutionException;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.FlowExecutor;
import org.springframework.beans.factory.InitializingBean;
@@ -115,7 +116,7 @@ public class SimpleFlow implements Flow, InitializingBean {
*/
public FlowExecution resume(String stateName, FlowExecutor executor) throws FlowExecutionException {
String status = FlowExecution.UNKNOWN;
FlowExecutionStatus status = FlowExecutionStatus.UNKNOWN;
State state = stateMap.get(stateName);
// Terminate if there are no more states
@@ -146,13 +147,7 @@ public class SimpleFlow implements Flow, InitializingBean {
* @return the next {@link Step} (or null if this is the end)
* @throws JobExecutionException
*/
private State nextState(String stateName, String status) throws FlowExecutionException {
// Special status value indicating that a state wishes to pause
// execution
if (status.equals(FlowExecution.PAUSED)) {
return null;
}
private State nextState(String stateName, FlowExecutionStatus status) throws FlowExecutionException {
Set<StateTransition> set = transitionMap.get(stateName);
@@ -163,7 +158,7 @@ public class SimpleFlow implements Flow, InitializingBean {
String next = null;
for (StateTransition stateTransition : set) {
if (stateTransition.matches(status)) {
if (stateTransition.matches(status.getStatus())) {
if (stateTransition.isEnd()) {
// End of job
return null;

View File

@@ -16,6 +16,7 @@
package org.springframework.batch.core.job.flow.support;
import org.springframework.batch.core.job.flow.FlowExecution;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.FlowExecutor;
@@ -42,9 +43,9 @@ public interface State {
* context is thread safe, or used in a thread safe manner.
*
* @param executor the context passed in by the caller
* @return a status for the execution
* @return a {@link FlowExecutionStatus} for the execution
* @throws Exception if anything goes wrong
*/
String handle(FlowExecutor executor) throws Exception;
FlowExecutionStatus handle(FlowExecutor executor) throws Exception;
}

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.batch.core.job.flow.support.state;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.FlowExecutor;
import org.springframework.batch.core.job.flow.support.State;
@@ -46,6 +47,6 @@ public abstract class AbstractState implements State {
return getClass().getSimpleName()+": name=["+name+"]";
}
public abstract String handle(FlowExecutor executor) throws Exception;
public abstract FlowExecutionStatus handle(FlowExecutor executor) throws Exception;
}

View File

@@ -16,10 +16,10 @@
package org.springframework.batch.core.job.flow.support.state;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.FlowExecutor;
import org.springframework.batch.core.job.flow.JobExecutionDecider;
/**
* @author Dave Syer
*
@@ -37,8 +37,8 @@ public class DecisionState extends AbstractState {
}
@Override
public String handle(FlowExecutor executor) throws Exception {
return decider.decide(executor.getJobExecution(), executor.getStepExecution());
public FlowExecutionStatus handle(FlowExecutor executor) throws Exception {
return new FlowExecutionStatus(decider.decide(executor.getJobExecution(), executor.getStepExecution()));
}
}

View File

@@ -19,7 +19,7 @@ package org.springframework.batch.core.job.flow.support.state;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.job.flow.FlowExecution;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.FlowExecutor;
import org.springframework.batch.core.job.flow.support.State;
@@ -57,32 +57,25 @@ public class EndState extends AbstractState {
}
/**
* Set the status as long the {@link JobExecution} is in progress. If this
* is the first place we came after a restart we do nothing (otherwise the
* same outcome that ended the job on the last run will occur).
* Return the {@link BatchStatus} and {@link ExitStatus} stored. If the
* {@link BatchStatus} is {@link BatchStatus#STOPPED}, then mark it on the
* {@link JobExecution} so that the job will know to stop.
*
* @see State#handle(FlowExecutor)
*/
@Override
public String handle(FlowExecutor executor) throws Exception {
public FlowExecutionStatus handle(FlowExecutor executor) throws Exception {
JobExecution jobExecution = executor.getJobExecution();
// If there are no step executions, then we are at the beginning of a
// restart
synchronized (jobExecution) {
if (!jobExecution.getStepExecutions().isEmpty()) {
BatchStatus beforeStatus = jobExecution.getStatus();
jobExecution.upgradeStatus(status);
//
// If the status was changed or the target status is the same as the old
//
if(beforeStatus != jobExecution.getStatus() || beforeStatus == status)
{
if (status == BatchStatus.STOPPED) {
jobExecution.upgradeStatus(status);
jobExecution.setExitStatus(exitStatus);
}
}
return FlowExecution.COMPLETED;
return new FlowExecutionStatus(status, exitStatus);
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.batch.core.job.flow.support.state;
import java.util.Collection;
import org.springframework.batch.core.job.flow.FlowExecution;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
/**
* Strategy interface for aggregating {@link FlowExecution} instances into a
@@ -32,6 +33,6 @@ public interface FlowExecutionAggregator {
* @param executions the executions to aggregate
* @return a summary status for the whole lot
*/
String aggregate(Collection<FlowExecution> executions);
FlowExecutionStatus aggregate(Collection<FlowExecution> executions);
}

View File

@@ -19,19 +19,24 @@ import java.util.Collection;
import java.util.Collections;
import org.springframework.batch.core.job.flow.FlowExecution;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
/**
* @author Dave Syer
*
*
*/
public class MaxValueFlowExecutionAggregator implements FlowExecutionAggregator {
/**
* Aggregate all of the {@link FlowExecutionStatus}es of the
* {@link FlowExecution}s into one status. The aggregate status will be the
* status with the highest precedence.
*
* @see FlowExecutionAggregator#aggregate(Collection)
*/
public String aggregate(Collection<FlowExecution> executions) {
if (executions==null || executions.size()==0) {
return FlowExecution.UNKNOWN;
public FlowExecutionStatus aggregate(Collection<FlowExecution> executions) {
if (executions == null || executions.size() == 0) {
return FlowExecutionStatus.UNKNOWN;
}
return Collections.max(executions).getStatus();
}

View File

@@ -24,6 +24,7 @@ import java.util.concurrent.FutureTask;
import org.springframework.batch.core.job.flow.Flow;
import org.springframework.batch.core.job.flow.FlowExecution;
import org.springframework.batch.core.job.flow.FlowExecutionException;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.FlowExecutor;
import org.springframework.batch.core.job.flow.support.State;
import org.springframework.core.task.SyncTaskExecutor;
@@ -68,7 +69,7 @@ public class SplitState extends AbstractState {
* @see State#handle(FlowExecutor)
*/
@Override
public String handle(final FlowExecutor executor) throws Exception {
public FlowExecutionStatus handle(final FlowExecutor executor) throws Exception {
Collection<Future<FlowExecution>> tasks = new ArrayList<Future<FlowExecution>>();

View File

@@ -17,6 +17,7 @@
package org.springframework.batch.core.job.flow.support.state;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.FlowExecutor;
import org.springframework.batch.core.job.flow.support.State;
@@ -49,8 +50,8 @@ public class StepState extends AbstractState {
}
@Override
public String handle(FlowExecutor executor) throws Exception {
return executor.executeStep(step);
public FlowExecutionStatus handle(FlowExecutor executor) throws Exception {
return new FlowExecutionStatus(executor.executeStep(step));
}
/**

View File

@@ -40,12 +40,13 @@ public class SplitDifferentResultsFailSecondJobParserTests extends AbstractJobPa
JobExecution jobExecution = createJobExecution();
job.execute(jobExecution);
assertEquals(2, stepNamesList.size());
assertEquals(3, stepNamesList.size());
assertTrue(stepNamesList.contains("step1"));
assertTrue(stepNamesList.contains("failingStep"));
assertTrue(stepNamesList.contains("step3"));
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
assertEquals(ExitStatus.FAILED, jobExecution.getExitStatus());
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
StepExecution stepExecution1 = getStepExecution(jobExecution, "step1");
assertEquals(BatchStatus.COMPLETED, stepExecution1.getStatus());
@@ -55,6 +56,10 @@ public class SplitDifferentResultsFailSecondJobParserTests extends AbstractJobPa
assertEquals(BatchStatus.FAILED, stepExecution2.getStatus());
assertEquals(ExitStatus.FAILED.getExitCode(), stepExecution2.getExitStatus().getExitCode());
StepExecution stepExecution3 = getStepExecution(jobExecution, "step3");
assertEquals(BatchStatus.COMPLETED, stepExecution3.getStatus());
assertEquals(ExitStatus.COMPLETED, stepExecution3.getExitStatus());
}
}

View File

@@ -31,7 +31,7 @@ public class FlowExecutionTests {
public void testBasicProperties() throws Exception {
FlowExecution execution = new FlowExecution("foo", "BAR");
assertEquals("foo",execution.getName());
assertEquals("BAR",execution.getStatus());
assertEquals("BAR",execution.getStatus().getStatus());
}
@Test
@@ -44,8 +44,8 @@ public class FlowExecutionTests {
@Test
public void testEnumOrdering() throws Exception {
FlowExecution first = new FlowExecution("foo", FlowExecution.COMPLETED);
FlowExecution second = new FlowExecution("foo", FlowExecution.FAILED);
FlowExecution first = new FlowExecution("foo", FlowExecutionStatus.COMPLETED);
FlowExecution second = new FlowExecution("foo", FlowExecutionStatus.FAILED);
assertTrue("Should be negative",first.compareTo(second)<0);
assertTrue("Should be positive",second.compareTo(first)>0);
}

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.batch.core.job.flow.support;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.StartLimitExceededException;
@@ -26,13 +27,13 @@ import org.springframework.batch.core.repository.JobRestartException;
/**
* @author Dave Syer
*
*
*/
public class JobFlowExecutorSupport implements FlowExecutor {
public String executeStep(Step step) throws JobInterruptedException, JobRestartException,
StartLimitExceededException {
return FlowExecution.COMPLETED;
return ExitStatus.COMPLETED.getExitCode();
}
public JobExecution getJobExecution() {

View File

@@ -26,9 +26,13 @@ import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.job.flow.FlowExecution;
import org.springframework.batch.core.job.flow.FlowExecutionException;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.FlowExecutor;
import org.springframework.batch.core.job.flow.support.state.EndState;
/**
* @author Dave Syer
@@ -56,17 +60,17 @@ public class SimpleFlowTests {
@Test
public void testStepLoop() throws Exception {
flow.setStateTransitions(collect(StateTransition.createStateTransition(new StateSupport("step"),
FlowExecution.FAILED, "step"), StateTransition.createEndStateTransition(new StateSupport("step"))));
ExitStatus.FAILED.getExitCode(), "step"), StateTransition.createEndStateTransition(new StateSupport("step"))));
flow.afterPropertiesSet();
FlowExecution execution = flow.start(executor);
assertEquals(FlowExecution.COMPLETED, execution.getStatus());
assertEquals(FlowExecutionStatus.COMPLETED, execution.getStatus());
assertEquals("step", execution.getName());
}
@Test(expected = IllegalArgumentException.class)
public void testNoEndStep() throws Exception {
flow.setStateTransitions(Collections.singletonList(StateTransition.createStateTransition(new StateSupport(
"step"), FlowExecution.FAILED, "step")));
"step"), ExitStatus.FAILED.getExitCode(), "step")));
flow.afterPropertiesSet();
}
@@ -76,7 +80,7 @@ public class SimpleFlowTests {
StateTransition.createEndStateTransition(new StubState("step2"))));
flow.afterPropertiesSet();
FlowExecution execution = flow.start(executor);
assertEquals(FlowExecution.COMPLETED, execution.getStatus());
assertEquals(FlowExecutionStatus.COMPLETED, execution.getStatus());
assertEquals("step1", execution.getName());
}
@@ -102,7 +106,7 @@ public class SimpleFlowTests {
"step1"))));
flow.afterPropertiesSet();
FlowExecution execution = flow.start(executor);
assertEquals(FlowExecution.COMPLETED, execution.getStatus());
assertEquals(FlowExecutionStatus.COMPLETED, execution.getStatus());
assertEquals("step1", execution.getName());
}
@@ -120,17 +124,17 @@ public class SimpleFlowTests {
};
FlowExecution execution = flow.start(executor);
assertEquals(1, list.size());
assertEquals(FlowExecution.COMPLETED, execution.getStatus());
assertEquals(FlowExecutionStatus.COMPLETED, execution.getStatus());
assertEquals("step1", execution.getName());
}
@Test
public void testExplicitStartStep() throws Exception {
flow.setStateTransitions(collect(StateTransition.createStateTransition(new StubState("step"),
FlowExecution.FAILED, "step"), StateTransition.createEndStateTransition(new StubState("step"))));
ExitStatus.FAILED.getExitCode(), "step"), StateTransition.createEndStateTransition(new StubState("step"))));
flow.afterPropertiesSet();
FlowExecution execution = flow.start(executor);
assertEquals(FlowExecution.COMPLETED, execution.getStatus());
assertEquals(FlowExecutionStatus.COMPLETED, execution.getStatus());
assertEquals("step", execution.getName());
}
@@ -140,7 +144,7 @@ public class SimpleFlowTests {
StateTransition.createEndStateTransition(new StubState("step2"))));
flow.afterPropertiesSet();
FlowExecution execution = flow.start(executor);
assertEquals(FlowExecution.COMPLETED, execution.getStatus());
assertEquals(FlowExecutionStatus.COMPLETED, execution.getStatus());
assertEquals("step2", execution.getName());
}
@@ -150,7 +154,7 @@ public class SimpleFlowTests {
StateTransition.createEndStateTransition(new StubState("step2"))));
flow.afterPropertiesSet();
FlowExecution execution = flow.resume("step2", executor);
assertEquals(FlowExecution.COMPLETED, execution.getStatus());
assertEquals(FlowExecutionStatus.COMPLETED, execution.getStatus());
assertEquals("step2", execution.getName());
}
@@ -158,54 +162,28 @@ public class SimpleFlowTests {
public void testFailedStep() throws Exception {
flow.setStateTransitions(collect(StateTransition.createStateTransition(new StubState("step1") {
@Override
public String handle(FlowExecutor executor) {
return FlowExecution.FAILED;
public FlowExecutionStatus handle(FlowExecutor executor) {
return FlowExecutionStatus.FAILED;
}
}, "step2"), StateTransition.createEndStateTransition(new StubState("step2"))));
flow.afterPropertiesSet();
FlowExecution execution = flow.start(executor);
assertEquals(FlowExecution.COMPLETED, execution.getStatus());
assertEquals(FlowExecutionStatus.COMPLETED, execution.getStatus());
assertEquals("step2", execution.getName());
}
@Test
public void testBranching() throws Exception {
flow.setStateTransitions(collect(StateTransition.createStateTransition(new StubState("step1"), "step2"),
StateTransition.createStateTransition(new StubState("step1"), FlowExecution.COMPLETED, "step3"),
StateTransition.createStateTransition(new StubState("step1"), ExitStatus.COMPLETED.getExitCode(), "step3"),
StateTransition.createEndStateTransition(new StubState("step2")), StateTransition
.createEndStateTransition(new StubState("step3"))));
flow.afterPropertiesSet();
FlowExecution execution = flow.start(executor);
assertEquals(FlowExecution.COMPLETED, execution.getStatus());
assertEquals(FlowExecutionStatus.COMPLETED, execution.getStatus());
assertEquals("step3", execution.getName());
}
@Test
public void testPause() throws Exception {
flow.setStateTransitions(collect(StateTransition.createStateTransition(new StubState("step1"), "step2"),
StateTransition.createStateTransition(new StubState("step2") {
private boolean paused = false;
@Override
public String handle(FlowExecutor executor) throws Exception {
if (!paused) {
paused = true;
return FlowExecution.PAUSED;
}
paused = false;
return FlowExecution.COMPLETED;
}
}, "step3"), StateTransition.createEndStateTransition(new StubState("step3"))));
flow.afterPropertiesSet();
FlowExecution execution = flow.start(executor);
assertEquals(FlowExecution.PAUSED, execution.getStatus());
assertEquals("step2", execution.getName());
execution = flow.resume(execution.getName(), executor);
assertEquals(FlowExecution.COMPLETED, execution.getStatus());
assertEquals("step3", execution.getName());
}
@Test
public void testGetStateExists() throws Exception {
flow.setStateTransitions(Collections.singletonList(StateTransition.createEndStateTransition(new StubState(

View File

@@ -15,9 +15,8 @@
*/
package org.springframework.batch.core.job.flow.support;
import org.springframework.batch.core.job.flow.FlowExecution;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.FlowExecutor;
import org.springframework.batch.core.job.flow.support.State;
import org.springframework.batch.core.job.flow.support.state.AbstractState;
/**
@@ -36,8 +35,8 @@ public class StateSupport extends AbstractState {
}
@Override
public String handle(FlowExecutor executor) throws Exception {
return FlowExecution.COMPLETED;
public FlowExecutionStatus handle(FlowExecutor executor) throws Exception {
return FlowExecutionStatus.COMPLETED;
}
}

View File

@@ -76,7 +76,7 @@ public class EndStateTests {
}
});
assertEquals(BatchStatus.UNKNOWN, jobExecution.getStatus());
assertEquals(BatchStatus.STARTING, jobExecution.getStatus());
}

View File

@@ -23,7 +23,7 @@ import java.util.Collections;
import org.junit.Test;
import org.springframework.batch.core.job.flow.FlowExecution;
import org.springframework.batch.core.job.flow.support.state.MaxValueFlowExecutionAggregator;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
/**
* @author Dave Syer
@@ -35,16 +35,16 @@ public class SimpleFlowExecutionAggregatorTests {
@Test
public void testFailed() throws Exception {
FlowExecution first = new FlowExecution("foo", FlowExecution.COMPLETED);
FlowExecution second = new FlowExecution("foo", FlowExecution.FAILED);
FlowExecution first = new FlowExecution("foo", FlowExecutionStatus.COMPLETED);
FlowExecution second = new FlowExecution("foo", FlowExecutionStatus.FAILED);
assertTrue("Should be negative", first.compareTo(second)<0);
assertTrue("Should be positive", second.compareTo(first)>0);
assertEquals(FlowExecution.FAILED, aggregator.aggregate(Arrays.asList(first, second)));
assertEquals(FlowExecutionStatus.FAILED, aggregator.aggregate(Arrays.asList(first, second)));
}
@Test
public void testEmpty() throws Exception {
assertEquals(FlowExecution.UNKNOWN, aggregator.aggregate(Collections.<FlowExecution> emptySet()));
assertEquals(FlowExecutionStatus.UNKNOWN, aggregator.aggregate(Collections.<FlowExecution> emptySet()));
}
}

View File

@@ -24,7 +24,7 @@ import org.easymock.EasyMock;
import org.junit.Test;
import org.springframework.batch.core.job.flow.Flow;
import org.springframework.batch.core.job.flow.FlowExecution;
import org.springframework.batch.core.job.flow.support.state.SplitState;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
@@ -45,12 +45,12 @@ public class SplitStateTests {
SplitState state = new SplitState(flows, "foo");
EasyMock.expect(flow1.start(null)).andReturn(new FlowExecution("step1", FlowExecution.COMPLETED));
EasyMock.expect(flow2.start(null)).andReturn(new FlowExecution("step1", FlowExecution.COMPLETED));
EasyMock.expect(flow1.start(null)).andReturn(new FlowExecution("step1", FlowExecutionStatus.COMPLETED));
EasyMock.expect(flow2.start(null)).andReturn(new FlowExecution("step1", FlowExecutionStatus.COMPLETED));
EasyMock.replay(flow1, flow2);
String result = state.handle(null);
assertEquals(FlowExecution.COMPLETED, result);
FlowExecutionStatus result = state.handle(null);
assertEquals(FlowExecutionStatus.COMPLETED, result);
EasyMock.verify(flow1, flow2);
@@ -68,12 +68,12 @@ public class SplitStateTests {
SplitState state = new SplitState(flows, "foo");
state.setTaskExecutor(new SimpleAsyncTaskExecutor());
EasyMock.expect(flow1.start(null)).andReturn(new FlowExecution("step1", FlowExecution.COMPLETED));
EasyMock.expect(flow2.start(null)).andReturn(new FlowExecution("step1", FlowExecution.COMPLETED));
EasyMock.expect(flow1.start(null)).andReturn(new FlowExecution("step1", FlowExecutionStatus.COMPLETED));
EasyMock.expect(flow2.start(null)).andReturn(new FlowExecution("step1", FlowExecutionStatus.COMPLETED));
EasyMock.replay(flow1, flow2);
String result = state.handle(null);
assertEquals(FlowExecution.COMPLETED, result);
FlowExecutionStatus result = state.handle(null);
assertEquals(FlowExecutionStatus.COMPLETED, result);
EasyMock.verify(flow1, flow2);

View File

@@ -10,6 +10,9 @@
<job id="job">
<split id="split1">
<next on="FAILED" to="step3"/>
<fail on="COMPLETED" />
<flow>
<step name="step1"/>
</flow>
@@ -17,6 +20,7 @@
<step name="failingStep"/>
</flow>
</split>
<step name="step3"/>
</job>
</beans:beans>