diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/SimpleStepHandler.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/SimpleStepHandler.java index 0ea08a8d7..eb69243ae 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/SimpleStepHandler.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/SimpleStepHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2013 the original author or authors. + * Copyright 2006-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. @@ -54,15 +54,15 @@ public class SimpleStepHandler implements StepHandler, InitializingBean { } /** - * @param jobRepository + * @param jobRepository a {@link org.springframework.batch.core.repository.JobRepository} */ public SimpleStepHandler(JobRepository jobRepository) { this(jobRepository, new ExecutionContext()); } /** - * @param jobRepository - * @param executionContext + * @param jobRepository a {@link org.springframework.batch.core.repository.JobRepository} + * @param executionContext the {@link org.springframework.batch.item.ExecutionContext} for the current Step */ public SimpleStepHandler(JobRepository jobRepository, ExecutionContext executionContext) { this.jobRepository = jobRepository; @@ -132,6 +132,10 @@ public class SimpleStepHandler implements StepHandler, InitializingBean { if (isRestart) { currentStepExecution.setExecutionContext(lastStepExecution.getExecutionContext()); + + if(lastStepExecution.getExecutionContext().containsKey("batch.executed")) { + currentStepExecution.getExecutionContext().remove("batch.executed"); + } } else { currentStepExecution.setExecutionContext(new ExecutionContext(executionContext)); @@ -142,6 +146,7 @@ public class SimpleStepHandler implements StepHandler, InitializingBean { logger.info("Executing step: [" + step.getName() + "]"); try { step.execute(currentStepExecution); + currentStepExecution.getExecutionContext().put("batch.executed", true); } catch (JobInterruptedException e) { // Ensure that the job gets the message that it is stopping @@ -161,9 +166,6 @@ public class SimpleStepHandler implements StepHandler, InitializingBean { } } - else { - // currentStepExecution.setExitStatus(ExitStatus.NOOP); - } return currentStepExecution; } @@ -172,7 +174,7 @@ public class SimpleStepHandler implements StepHandler, InitializingBean { * Detect whether a step execution belongs to this job execution. * @param jobExecution the current job execution * @param stepExecution an existing step execution - * @return + * @return true if the {@link org.springframework.batch.core.StepExecution} is part of the {@link org.springframework.batch.core.JobExecution} */ private boolean stepExecutionPartOfExistingJobExecution(JobExecution jobExecution, StepExecution stepExecution) { return stepExecution != null && stepExecution.getJobExecutionId() != null @@ -208,7 +210,7 @@ public class SimpleStepHandler implements StepHandler, InitializingBean { + "so it may be dangerous to proceed. Manual intervention is probably necessary."); } - if ((stepStatus == BatchStatus.COMPLETED && step.isAllowStartIfComplete() == false) + if ((stepStatus == BatchStatus.COMPLETED && !step.isAllowStartIfComplete()) || stepStatus == BatchStatus.ABANDONED) { // step is complete, false should be returned, indicating that the // step should not be started diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/SimpleFlow.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/SimpleFlow.java index bdfba5d16..dff195011 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/SimpleFlow.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/support/SimpleFlow.java @@ -15,17 +15,6 @@ */ package org.springframework.batch.core.job.flow.support; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.batch.core.Step; @@ -38,6 +27,17 @@ import org.springframework.batch.core.job.flow.FlowExecutor; import org.springframework.batch.core.job.flow.State; import org.springframework.beans.factory.InitializingBean; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + /** * A {@link Flow} that branches conditionally depending on the exit status of * the last {@link State}. The input parameters are the state transitions (in no @@ -169,7 +169,7 @@ public class SimpleFlow implements Flow, InitializingBean { catch (Exception e) { executor.close(new FlowExecution(stateName, status)); throw new FlowExecutionException(String.format("Ended flow=%s at state=%s with exception", name, - stateName), e); + stateName), e); } logger.debug("Completed state="+stateName+" with status="+status); @@ -183,9 +183,25 @@ public class SimpleFlow implements Flow, InitializingBean { } +<<<<<<< HEAD protected Map> getTransitionMap() { return transitionMap; } +======= + private boolean isFlowContinued(State state, FlowExecutionStatus status, StepExecution stepExecution) { + boolean continued = true; + + continued = state != null && status!=FlowExecutionStatus.STOPPED; + + if(stepExecution != null) { + Boolean reRun = (Boolean) stepExecution.getExecutionContext().get("batch.restart"); + Boolean executed = (Boolean) stepExecution.getExecutionContext().get("batch.executed"); + + if((executed == null || !executed) && reRun != null && reRun && status == FlowExecutionStatus.STOPPED && !state.getName().endsWith(stepExecution.getStepName())) { + continued = true; + } + } +>>>>>>> 4e5b4c1... BATCH-2016: Added new flag to indicate if the step is being executed on protected Map getStateMap() { return stateMap; @@ -193,14 +209,14 @@ public class SimpleFlow implements Flow, InitializingBean { /** * @return the next {@link Step} (or null if this is the end) - * @throws FlowExecutionException + * @throws org.springframework.batch.core.job.flow.FlowExecutionException */ protected State nextState(String stateName, FlowExecutionStatus status, StepExecution stepExecution) throws FlowExecutionException { Set set = transitionMap.get(stateName); if (set == null) { throw new FlowExecutionException(String.format("No transitions found in flow=%s for state=%s", getName(), - stateName)); + stateName)); } String next = null; @@ -218,17 +234,15 @@ public class SimpleFlow implements Flow, InitializingBean { } if (next == null) { - throw new FlowExecutionException(String.format( - "Next state not found in flow=%s for state=%s with exit status=%s", getName(), stateName, status.getName())); + throw new FlowExecutionException(String.format("Next state not found in flow=%s for state=%s with exit status=%s", getName(), stateName, status.getName())); } if (!stateMap.containsKey(next)) { throw new FlowExecutionException(String.format("Next state not specified in flow=%s for next=%s", - getName(), next)); + getName(), next)); } - State state = stateMap.get(next); - return state; + return stateMap.get(next); } @@ -308,7 +322,7 @@ public class SimpleFlow implements Flow, InitializingBean { if (!hasEndStep) { throw new IllegalArgumentException( - "No end state was found. You must specify at least one transition with no next state."); + "No end state was found. You must specify at least one transition with no next state."); } startState = stateTransitions.get(0).getState(); diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/builder/FaultTolerantStepBuilder.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/builder/FaultTolerantStepBuilder.java index 91fa15dcd..e9d608ecc 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/builder/FaultTolerantStepBuilder.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/builder/FaultTolerantStepBuilder.java @@ -89,11 +89,8 @@ import java.util.Set; * additional properties for retry and skip of failed items. * * @author Dave Syer -<<<<<<< HEAD * @author Chris Schaefer -======= * @author Michael Minella ->>>>>>> 2c62f20... BATCH-2185: Updated to support annotation based listener configuration via javaconfig * * @since 2.2 */ diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/RestartInPriorStepTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/RestartInPriorStepTests.java index ba038ba38..a5f5c4038 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/RestartInPriorStepTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/RestartInPriorStepTests.java @@ -15,10 +15,6 @@ */ package org.springframework.batch.core.step; -import static org.junit.Assert.assertEquals; - -import java.util.Map; - import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.batch.core.BatchStatus; @@ -39,6 +35,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + /** * @author Michael Minella * @@ -58,17 +58,11 @@ public class RestartInPriorStepTests { @Test public void test() throws Exception { - // - // Run 1 - // JobExecution run1 = jobLauncher.run(job, new JobParameters()); assertEquals(BatchStatus.STOPPED, run1.getStatus()); assertEquals(2, run1.getStepExecutions().size()); - // - // Run 2 - // JobExecution run2 = jobLauncher.run(job, new JobParameters()); assertEquals(BatchStatus.COMPLETED, run2.getStatus()); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/RestartLoopTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/RestartLoopTests.java new file mode 100644 index 000000000..773229579 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/RestartLoopTests.java @@ -0,0 +1,67 @@ +/* + * 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.step; + +import org.junit.Test; +import org.junit.runner.RunWith; +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.StepContribution; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import static org.junit.Assert.assertEquals; + +/** + * @author Michael Minella + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class RestartLoopTests { + + @Autowired + private Job job; + + @Autowired + private JobLauncher jobLauncher; + + @Test + public void test() throws Exception { + // Run 1 + JobExecution jobExecution1 = jobLauncher.run(job, new JobParameters()); + + assertEquals(BatchStatus.STOPPED, jobExecution1.getStatus()); + + // Run 2 + JobExecution jobExecution2 = jobLauncher.run(job, new JobParameters()); + + assertEquals(BatchStatus.STOPPED, jobExecution2.getStatus()); + } + + public static class DefaultTasklet implements Tasklet { + @Override + public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { + return RepeatStatus.FINISHED; + } + } +} diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/step/RestartInPriorStepTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/step/RestartInPriorStepTests-context.xml index ec1131aac..4cdb9be87 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/step/RestartInPriorStepTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/step/RestartInPriorStepTests-context.xml @@ -4,8 +4,6 @@ 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://www.springframework.org/schema/util - http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.2.xsd"> @@ -54,7 +52,9 @@ + + @@ -62,12 +62,12 @@ - + - + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/step/RestartLoopTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/step/RestartLoopTests-context.xml new file mode 100644 index 000000000..612efa618 --- /dev/null +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/step/RestartLoopTests-context.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file