diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java index 71222968a..efc919f37 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/AbstractJob.java @@ -125,6 +125,14 @@ public abstract class AbstractJob implements Job, BeanNameAware, InitializingBea return name; } + /** + * Retrieve the step with the given name + * + * @param stepName + * @return the step + */ + public abstract Step getStep(String stepName); + /** * Boolean flag to prevent categorically a job from restarting, even if it * has failed previously. diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/SimpleJob.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/SimpleJob.java index 9b0c5ab76..6a4d7fe42 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/SimpleJob.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/SimpleJob.java @@ -60,11 +60,18 @@ public class SimpleJob extends AbstractJob { this.steps.add(step); } - /** - * @return the steps currently set for this job + /* + * (non-Javadoc) + * @see org.springframework.batch.core.job.AbstractJob#getStep(java.lang.String) */ - public List getSteps(){ - return steps; + public Step getStep(String stepName){ + for (Step step : this.steps) { + if(step.getName().equals(stepName)) + { + return step; + } + } + throw new IllegalStateException("No Step found with name: [" + stepName + "]"); } /** diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/Flow.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/Flow.java index c497ecea1..ffb8723a2 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/Flow.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/Flow.java @@ -15,6 +15,8 @@ */ package org.springframework.batch.core.job.flow; +import org.springframework.batch.core.job.flow.support.State; + /** * @author Dave Syer * @@ -26,6 +28,12 @@ public interface Flow { */ String getName(); + /** + * @param stateName + * @return the State in the flow with given name + */ + public State getState(String stateName); + /** * @throws FlowExecutionException */ diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/FlowJob.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/FlowJob.java index 3bb7f7c7e..613a6c02c 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/FlowJob.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/flow/FlowJob.java @@ -23,6 +23,8 @@ import org.springframework.batch.core.StartLimitExceededException; import org.springframework.batch.core.Step; import org.springframework.batch.core.StepExecution; import org.springframework.batch.core.job.AbstractJob; +import org.springframework.batch.core.job.flow.support.State; +import org.springframework.batch.core.job.flow.support.state.StepState; import org.springframework.batch.core.repository.JobRestartException; import org.springframework.util.Assert; @@ -57,11 +59,14 @@ public class FlowJob extends AbstractJob { this.flow = flow; } - /** - * @return the flow + /* + * (non-Javadoc) + * @see org.springframework.batch.core.job.AbstractJob#getStep(java.lang.String) */ - public Flow getFlow(){ - return this.flow; + public Step getStep(String stepName){ + State state = this.flow.getState(stepName); + Assert.isInstanceOf(StepState.class, state, "State is not a StepState: [" + stepName + "]"); + return ((StepState) state).getStep(); } /** 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 dbcb2b580..5e738dfe7 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 @@ -30,6 +30,7 @@ import org.springframework.batch.core.job.flow.FlowExecution; import org.springframework.batch.core.job.flow.FlowExecutionException; import org.springframework.batch.core.job.flow.FlowExecutor; import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; /** * A {@link Flow} that branches conditionally depending on the exit status of @@ -81,12 +82,14 @@ public class SimpleFlow implements Flow, InitializingBean { this.stateTransitions = stateTransitions; } - /** - * @param stateName - * @return state with given name, null if not found + /* + * (non-Javadoc) + * @see org.springframework.batch.core.job.flow.Flow#getState(java.lang.String) */ public State getState(String stateName) { - return stateMap.get(stateName); + State state = stateMap.get(stateName); + Assert.notNull(state, "No State found with name: [" + stateName + "]"); + return state; } /** diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/job/AbstractJobTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/job/AbstractJobTests.java index 336f40743..1aa86e9c1 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/job/AbstractJobTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/job/AbstractJobTests.java @@ -25,6 +25,7 @@ import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobExecutionException; import org.springframework.batch.core.JobInterruptedException; import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.Step; import org.springframework.batch.core.StepExecution; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean; @@ -170,6 +171,11 @@ public class AbstractJobTests { return null; } + @Override + public Step getStep(String stepName) { + return null; + } + } } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/job/flow/support/SimpleFlowTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/job/flow/support/SimpleFlowTests.java index 35cfd2595..44586c77f 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/job/flow/support/SimpleFlowTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/job/flow/support/SimpleFlowTests.java @@ -16,6 +16,7 @@ package org.springframework.batch.core.job.flow.support; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -203,6 +204,24 @@ public class SimpleFlowTests { assertEquals(FlowExecution.COMPLETED, execution.getStatus()); assertEquals("step3", execution.getName()); } + + @Test + public void testGetStateExists() throws Exception { + flow.setStateTransitions(Collections.singletonList(StateTransition.createEndStateTransition(new StubState( + "step1")))); + flow.afterPropertiesSet(); + State state = flow.getState("step1"); + assertNotNull(state); + assertEquals("step1", state.getName()); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetStateDoesNotExist() throws Exception { + flow.setStateTransitions(Collections.singletonList(StateTransition.createEndStateTransition(new StubState( + "step1")))); + flow.afterPropertiesSet(); + flow.getState("bar"); + } private List collect(StateTransition s1, StateTransition s2) { List list = new ArrayList(); diff --git a/spring-batch-test/src/main/java/org/springframework/batch/test/AbstractJobTests.java b/spring-batch-test/src/main/java/org/springframework/batch/test/AbstractJobTests.java index 5817205c4..c1a7350c0 100644 --- a/spring-batch-test/src/main/java/org/springframework/batch/test/AbstractJobTests.java +++ b/spring-batch-test/src/main/java/org/springframework/batch/test/AbstractJobTests.java @@ -27,27 +27,24 @@ import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobParameter; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.Step; +import org.springframework.batch.core.job.AbstractJob; import org.springframework.batch.core.job.SimpleJob; import org.springframework.batch.core.job.flow.FlowJob; -import org.springframework.batch.core.job.flow.support.SimpleFlow; -import org.springframework.batch.core.job.flow.support.State; -import org.springframework.batch.core.job.flow.support.state.StepState; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.repository.JobRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; -import org.springframework.util.Assert; /** *

* Base class for testing batch jobs. It provides methods for launching an - * entire {@link Job}, allowing for end to end testing of individual steps, - * without having to run every step in the job. Any test classes inheriting from - * this class should make sure they are part of an {@link ApplicationContext}, - * which is generally expected to be done as part of the Spring test framework. - * Furthermore, the {@link ApplicationContext} in which it is a part of is - * expected to have one {@link JobLauncher}, {@link JobRepository}, and a - * single {@link Job} implementation. + * entire {@link AbstractJob}, allowing for end to end testing of individual + * steps, without having to run every step in the job. Any test classes + * inheriting from this class should make sure they are part of an + * {@link ApplicationContext}, which is generally expected to be done as part + * of the Spring test framework. Furthermore, the {@link ApplicationContext} in + * which it is a part of is expected to have one {@link JobLauncher}, + * {@link JobRepository}, and a single {@link AbstractJob} implementation. * *

* This class also provides the ability to run {@link Step}s from a @@ -74,13 +71,12 @@ public abstract class AbstractJobTests { private JobLauncher launcher; @Autowired - private Job job; + private AbstractJob job; @Autowired private JobRepository jobRepository; private StepRunner stepRunner; - private Map stepMap; /** * @return the job repository @@ -92,7 +88,7 @@ public abstract class AbstractJobTests { /** * @return the job */ - public Job getJob() { + public AbstractJob getJob() { return job; } @@ -147,69 +143,14 @@ public abstract class AbstractJobTests { * @param stepName */ public JobExecution launchStep(String stepName) { - return getStepRunner().launchStep(getStep(stepName)); - } - - /** - * @param stepName - * @return - */ - public Step getStep(String stepName) { - Job job = getJob(); - if (job instanceof FlowJob) { - return getFlowJobStep(stepName); + Step step; + try { + step = this.job.getStep(stepName); } - else if (job instanceof SimpleJob) { - return getSimpleJobStep(stepName); + catch (IllegalArgumentException e) { + throw new IllegalStateException("No Step found with name: [" + stepName + "]", e); } - else { - throw new IllegalStateException("Job is neither a FlowJob or a SimpleJob"); - } - } - - /** - * Extract the step from a FlowJob. Throw an exception of the step does not - * exist. - * - * @param stepName - * @return the step - */ - private Step getFlowJobStep(String stepName) { - try{ - State state = ((SimpleFlow) ((FlowJob) getJob()).getFlow()).getState(stepName); - Assert.notNull(state, "no matching state found in flow for " + stepName); - Assert.isInstanceOf(StepState.class, state); - return ((StepState) state).getStep(); - } - catch(IllegalArgumentException e) - { - throw new IllegalStateException("No Step found with name: [" + stepName + "]"); - } - } - - /** - * Extract the step from a SimpleJob. Throw an exception of the step does - * not exist. - * - * @param stepName - * @return the step - */ - private Step getSimpleJobStep(String stepName) { - if (this.stepMap == null) { - // - // Populate the step map - // - SimpleJob simpleJob = (SimpleJob) getJob(); - this.stepMap = new HashMap(); - for (Step step : simpleJob.getSteps()) { - this.stepMap.put(step.getName(), step); - } - } - - if (!this.stepMap.containsKey(stepName)) { - throw new IllegalStateException("No Step found with name: [" + stepName + "]"); - } - return this.stepMap.get(stepName); + return getStepRunner().launchStep(step); } /** @@ -219,6 +160,6 @@ public abstract class AbstractJobTests { * @param jobParameters */ public JobExecution launchStep(String stepName, JobParameters jobParameters) { - return getStepRunner().launchStep(getStep(stepName), jobParameters); + return getStepRunner().launchStep(this.job.getStep(stepName), jobParameters); } }