diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/DecisionAdapter.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/DecisionAdapter.java deleted file mode 100644 index c125123df..000000000 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/DecisionAdapter.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2013 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; - -import javax.batch.api.Decider; -import javax.batch.operations.BatchRuntimeException; - -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.StepExecution; -import org.springframework.batch.core.job.flow.FlowExecutionStatus; -import org.springframework.batch.core.job.flow.JobExecutionDecider; -import org.springframework.util.Assert; - -/** - * Wrapper for {@link Decider} implementation to allow it to be used - * by the rest of the framework. - * - * @author Michael Minella - * @since 3.0 - */ -public class DecisionAdapter implements JobExecutionDecider { - - private Decider decider; - - /** - * @param decider a {@link Decider} - */ - public DecisionAdapter(Decider decider) { - Assert.notNull(decider, "A Decider implementation is required"); - - this.decider = decider; - } - - /* (non-Javadoc) - * @see org.springframework.batch.core.job.flow.JobExecutionDecider#decide(org.springframework.batch.core.JobExecution, org.springframework.batch.core.StepExecution) - */ - @Override - public FlowExecutionStatus decide(JobExecution jobExecution, - StepExecution stepExecution) { - - javax.batch.runtime.StepExecution [] executions = null; - - //TODO: Address splits - if(stepExecution != null) { - executions = new org.springframework.batch.core.jsr.StepExecution[1]; - executions[0] = new org.springframework.batch.core.jsr.StepExecution(stepExecution); - } - - try { - return new FlowExecutionStatus(decider.decide(executions)); - } catch (Exception e) { - throw new BatchRuntimeException(e); - } - } -} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/DecisionParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/DecisionParser.java index 81e584b63..5e3634c3b 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/DecisionParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/DecisionParser.java @@ -18,9 +18,14 @@ 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.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.StringUtils; import org.w3c.dom.Element; /** @@ -36,14 +41,25 @@ public class DecisionParser { private static final String ID_ATTRIBUTE = "id"; private static final String REF_ATTRIBUTE = "ref"; - public Collection parse(Element element, ParserContext parserContext) { - String refAttribute = element.getAttribute(REF_ATTRIBUTE); + public Collection parse(Element element, ParserContext parserContext, String jobFactoryRef) { + BeanDefinitionBuilder factoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(); + AbstractBeanDefinition factoryDefinition = factoryBuilder.getRawBeanDefinition(); + factoryDefinition.setBeanClass(DecisionStepFactoryBean.class); + + BeanDefinitionBuilder stateBuilder = BeanDefinitionBuilder.genericBeanDefinition(StepState.class); + String idAttribute = element.getAttribute(ID_ATTRIBUTE); - BeanDefinitionBuilder stateBuilder = - BeanDefinitionBuilder.genericBeanDefinition("org.springframework.batch.core.jsr.configuration.xml.DecisionStateFactoryBean"); - stateBuilder.addPropertyReference("decider", refAttribute); - stateBuilder.addPropertyValue("name", idAttribute); + parserContext.registerBeanComponent(new BeanComponentDefinition(factoryDefinition, idAttribute)); + stateBuilder.addConstructorArgReference(idAttribute); + + String refAttribute = element.getAttribute(REF_ATTRIBUTE); + factoryDefinition.getPropertyValues().add("decider", new RuntimeBeanReference(refAttribute)); + factoryDefinition.getPropertyValues().add("name", idAttribute); + + if(StringUtils.hasText(jobFactoryRef)) { + factoryDefinition.setAttribute("jobParserJobFactoryBeanRef", jobFactoryRef); + } new PropertyParser(refAttribute, parserContext).parseProperties(element); diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/DecisionStateFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/DecisionStepFactoryBean.java similarity index 55% rename from spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/DecisionStateFactoryBean.java rename to spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/DecisionStepFactoryBean.java index ec2036ee6..7dfd58d27 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/DecisionStateFactoryBean.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/DecisionStepFactoryBean.java @@ -17,39 +17,38 @@ package org.springframework.batch.core.jsr.configuration.xml; import javax.batch.api.Decider; -import org.springframework.batch.core.job.flow.JobExecutionDecider; -import org.springframework.batch.core.job.flow.State; -import org.springframework.batch.core.job.flow.support.state.DecisionState; -import org.springframework.batch.core.jsr.DecisionAdapter; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.jsr.step.DecisionStep; +import org.springframework.batch.core.repository.JobRepository; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; /** - * {@link FactoryBean} for creating a {@link DecisionState}. If the underlying - * decider is a {@link Decider}, it will be wrapped in a {@link DecisionAdapter}. + * {@link FactoryBean} for creating a {@link DecisionStep}. * * @author Michael Minella * @since 3.0 */ -public class DecisionStateFactoryBean implements FactoryBean, InitializingBean { +public class DecisionStepFactoryBean implements FactoryBean, InitializingBean { private Decider jsrDecider; - private JobExecutionDecider decider; private String name; + private JobRepository jobRepository; /** - * @param decider either a {@link Decider} or a {@link JobExecutionDecider} + * @param jobRepository All steps need to be able to reference a {@link JobRepository} + */ + public void setJobRepository(JobRepository jobRepository) { + this.jobRepository = jobRepository; + } + + /** + * @param decider a {@link Decider} * @throws IllegalArgumentException if the type passed in is not a valid type */ - public void setDecider(Object decider) { - if(decider instanceof JobExecutionDecider) { - this.decider = (JobExecutionDecider) decider; - } else if(decider instanceof Decider) { - this.jsrDecider = (Decider) decider; - } else { - throw new IllegalArgumentException("Invalid type for a decider"); - } + public void setDecider(Decider decider) { + this.jsrDecider = decider; } /** @@ -65,17 +64,13 @@ public class DecisionStateFactoryBean implements FactoryBean, Initializin * @see org.springframework.beans.factory.FactoryBean#getObject() */ @Override - public State getObject() throws Exception { - JobExecutionDecider wrappedDecider = null; + public Step getObject() throws Exception { - if(decider != null) { - wrappedDecider = decider; - } else if(jsrDecider != null) { - wrappedDecider = new DecisionAdapter(jsrDecider); - } - State state = new DecisionState(wrappedDecider, name); + DecisionStep decisionStep = new DecisionStep(jsrDecider); + decisionStep.setName(name); + decisionStep.setJobRepository(jobRepository); - return state; + return decisionStep; } /* (non-Javadoc) @@ -83,7 +78,7 @@ public class DecisionStateFactoryBean implements FactoryBean, Initializin */ @Override public Class getObjectType() { - return JobExecutionDecider.class; + return DecisionStep.class; } /* (non-Javadoc) @@ -96,7 +91,7 @@ public class DecisionStateFactoryBean implements FactoryBean, Initializin @Override public void afterPropertiesSet() throws Exception { - Assert.isTrue(!(decider == null && jsrDecider == null), "A decider implementation is required"); + Assert.isTrue(jsrDecider != null, "A decider implementation is required"); Assert.notNull(name, "A name is required for a decision state"); } } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/FlowParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/FlowParser.java index b94e64571..b59f0b1a1 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/FlowParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/FlowParser.java @@ -35,7 +35,7 @@ import org.w3c.dom.NodeList; /** * Parses flows as defined in JSR-352. The current state parses a flow * as it is within a regular Spring Batch job/flow. - * + * * @author Michael Minella * @since 3.0 */ @@ -47,7 +47,8 @@ public class FlowParser extends AbstractFlowParser { private StepParser stepParser = new StepParser(); private String flowName; - public FlowParser(String flowName) { + public FlowParser(String flowName, String jobFactoryRef) { + super.setJobFactoryRef(jobFactoryRef); this.flowName = flowName; } @@ -75,9 +76,9 @@ public class FlowParser extends AbstractFlowParser { if (nodeName.equals(STEP_ELEMENT)) { stateTransitions.addAll(stepParser.parse(child, parserContext, builder)); } else if(nodeName.equals(SPLIT_ELEMENT)) { - stateTransitions.addAll(new SplitParser().parse(child, parserContext)); + stateTransitions.addAll(new SplitParser(flowName).parse(child, parserContext)); } else if(nodeName.equals(DECISION_ELEMENT)) { - stateTransitions.addAll(new DecisionParser().parse(child, parserContext)); + stateTransitions.addAll(new DecisionParser().parse(child, parserContext, flowName)); } } } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/JobParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/JobParser.java index 33633bc88..1bcecdcd7 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/JobParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/JobParser.java @@ -55,7 +55,7 @@ public class JobParser extends AbstractSingleBeanDefinitionParser { builder.addPropertyValue("restartable", restartableAttribute); } - BeanDefinition flowDef = new FlowParser(jobName).parse(element, parserContext); + BeanDefinition flowDef = new FlowParser(jobName, jobName).parse(element, parserContext); builder.addPropertyValue("flow", flowDef); AbstractBeanDefinition stepContextBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(StepContextFactoryBean.class) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/SplitParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/SplitParser.java index fdeba899d..b8f1e0d35 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/SplitParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/configuration/xml/SplitParser.java @@ -27,12 +27,18 @@ import org.w3c.dom.Element; /** * Parses a <split /> element as defined in JSR-352. - * + * * @author Michael Minella * @since 3.0 */ public class SplitParser { + private String jobFactoryRef; + + public SplitParser(String jobFactoryRef) { + this.jobFactoryRef = jobFactoryRef; + } + public Collection parse(Element element, ParserContext parserContext) { String idAttribute = element.getAttribute("id"); @@ -48,15 +54,14 @@ public class SplitParser { Collection flows = new ManagedList(); int i = 0; - String prefix = idAttribute; for (Element nextElement : flowElements) { - FlowParser flowParser = new FlowParser(prefix + "." + i); + FlowParser flowParser = new FlowParser(idAttribute + "." + i, jobFactoryRef); flows.add(flowParser.parse(nextElement, parserContext)); i++; } stateBuilder.addConstructorArgValue(flows); - stateBuilder.addConstructorArgValue(prefix); + stateBuilder.addConstructorArgValue(idAttribute); return FlowParser.getNextElements(parserContext, null, stateBuilder.getBeanDefinition(), element); } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/step/DecisionStep.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/step/DecisionStep.java new file mode 100644 index 000000000..8b57919f8 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/step/DecisionStep.java @@ -0,0 +1,81 @@ +/* + * Copyright 2013 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.step; + +import java.util.Collection; + +import javax.batch.api.Decider; +import javax.batch.operations.BatchRuntimeException; + +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.StepExecution; +import org.springframework.batch.core.step.AbstractStep; + +/** + * Implements a {@link Step} to follow the rules for a decision state + * as defined by JSR-352. Currently does not support the JSR requirement + * to provide all of the last {@link javax.batch.runtime.StepExecution}s from + * a split. + * + * @author Michael Minella + * @since 3.0 + */ +public class DecisionStep extends AbstractStep { + + private final Decider decider; + + /** + * @param decider a {@link Decider} implementation + */ + public DecisionStep(Decider decider) { + this.decider = decider; + } + + @Override + protected void doExecute(StepExecution stepExecution) throws Exception { + Collection stepExecutions = stepExecution.getJobExecution().getStepExecutions(); + + // Used to determine if this step is the first step in the job (not allowed) + if(stepExecutions.size() == 1) { + stepExecution.setTerminateOnly(); + throw new BatchRuntimeException("Decision not a valid first step"); + } + + // Currently does not support splits + StepExecution lastExecution = null; + + if(stepExecutions != null) { + for (StepExecution curStepExecution : stepExecutions) { + if(lastExecution == null || (curStepExecution.getEndTime() != null && curStepExecution.getEndTime().after(lastExecution.getEndTime()))) { + lastExecution = curStepExecution; + } + } + } + + javax.batch.runtime.StepExecution [] executions = new org.springframework.batch.core.jsr.StepExecution[1]; + + executions[0] = new org.springframework.batch.core.jsr.StepExecution(lastExecution); + + try { + stepExecution.setExitStatus(new ExitStatus(decider.decide(executions))); + } catch (Exception e) { + stepExecution.setTerminateOnly(); + stepExecution.addFailureException(e); + throw e; + } + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests.java index e8d743f94..5ab178c90 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests.java @@ -17,16 +17,14 @@ package org.springframework.batch.core.jsr.configuration.xml; import static org.junit.Assert.assertEquals; -import org.junit.Ignore; +import javax.batch.api.Decider; + 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.StepExecution; -import org.springframework.batch.core.job.flow.FlowExecutionStatus; -import org.springframework.batch.core.job.flow.JobExecutionDecider; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; @@ -43,19 +41,18 @@ public class DecisionParsingTests { public JobLauncher jobLauncher; @Test - @Ignore public void test() throws Exception { JobExecution execution = jobLauncher.run(job, new JobParameters()); assertEquals(BatchStatus.COMPLETED, execution.getStatus()); - assertEquals(2, execution.getStepExecutions().size()); + assertEquals(3, execution.getStepExecutions().size()); } - public static class TestDecider implements JobExecutionDecider { + public static class JsrDecider implements Decider { @Override - public FlowExecutionStatus decide(JobExecution jobExecution, - StepExecution stepExecution) { - return new FlowExecutionStatus("step2"); + public String decide(javax.batch.runtime.StepExecution[] executions) + throws Exception { + return "next"; } } } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/DecisionStateFactoryBeanTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/DecisionStateFactoryBeanTests.java deleted file mode 100644 index 763ebbda8..000000000 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/DecisionStateFactoryBeanTests.java +++ /dev/null @@ -1,100 +0,0 @@ -package org.springframework.batch.core.jsr.configuration.xml; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import javax.batch.api.Decider; -import javax.batch.runtime.StepExecution; - -import org.junit.Before; -import org.junit.Test; -import org.springframework.batch.core.JobExecution; -import org.springframework.batch.core.job.flow.FlowExecutionStatus; -import org.springframework.batch.core.job.flow.JobExecutionDecider; -import org.springframework.batch.core.job.flow.State; -import org.springframework.batch.core.job.flow.support.state.DecisionState; - -public class DecisionStateFactoryBeanTests { - - private DecisionStateFactoryBean factoryBean; - - @Before - public void setUp() throws Exception { - factoryBean = new DecisionStateFactoryBean(); - } - - @Test - public void testGetObjectType() { - assertEquals(JobExecutionDecider.class, factoryBean.getObjectType()); - } - - @Test - public void testIsSingleton() { - assertTrue(factoryBean.isSingleton()); - } - - @Test(expected=IllegalArgumentException.class) - public void testNullDeciderAndName() throws Exception { - factoryBean.afterPropertiesSet(); - } - - @Test(expected=IllegalArgumentException.class) - public void testNullDecider() throws Exception{ - factoryBean.setName("state1"); - factoryBean.afterPropertiesSet(); - } - - @Test(expected=IllegalArgumentException.class) - public void testNullName() throws Exception { - factoryBean.setDecider(new DeciderSupport()); - factoryBean.afterPropertiesSet(); - } - - @Test(expected=IllegalArgumentException.class) - public void setWrongDeciderType() { - factoryBean.setDecider("Some decider"); - } - - @Test - public void testJobExecutionDeciderState() throws Exception { - factoryBean.setDecider(new JobExecutionDeciderSupport()); - factoryBean.setName("IL"); - - factoryBean.afterPropertiesSet(); - - State state = factoryBean.getObject(); - - assertEquals("IL", state.getName()); - assertEquals(DecisionState.class, state.getClass()); - } - - @Test - public void testDeciderDeciderState() throws Exception { - factoryBean.setDecider(new DeciderSupport()); - factoryBean.setName("IL"); - - factoryBean.afterPropertiesSet(); - - State state = factoryBean.getObject(); - - assertEquals("IL", state.getName()); - assertEquals(DecisionState.class, state.getClass()); - } - - public static class DeciderSupport implements Decider { - - @Override - public String decide(StepExecution[] executions) throws Exception { - return null; - } - } - - public static class JobExecutionDeciderSupport implements JobExecutionDecider { - - @Override - public FlowExecutionStatus decide(JobExecution jobExecution, - org.springframework.batch.core.StepExecution stepExecution) { - return null; - } - } -} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/DecisionStepFactoryBeanTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/DecisionStepFactoryBeanTests.java new file mode 100644 index 000000000..ba47e3d5b --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/DecisionStepFactoryBeanTests.java @@ -0,0 +1,70 @@ +package org.springframework.batch.core.jsr.configuration.xml; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import javax.batch.api.Decider; +import javax.batch.runtime.StepExecution; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.jsr.step.DecisionStep; + +public class DecisionStepFactoryBeanTests { + + private DecisionStepFactoryBean factoryBean; + + @Before + public void setUp() throws Exception { + factoryBean = new DecisionStepFactoryBean(); + } + + @Test + public void testGetObjectType() { + assertEquals(DecisionStep.class, factoryBean.getObjectType()); + } + + @Test + public void testIsSingleton() { + assertTrue(factoryBean.isSingleton()); + } + + @Test(expected=IllegalArgumentException.class) + public void testNullDeciderAndName() throws Exception { + factoryBean.afterPropertiesSet(); + } + + @Test(expected=IllegalArgumentException.class) + public void testNullDecider() throws Exception{ + factoryBean.setName("state1"); + factoryBean.afterPropertiesSet(); + } + + @Test(expected=IllegalArgumentException.class) + public void testNullName() throws Exception { + factoryBean.setDecider(new DeciderSupport()); + factoryBean.afterPropertiesSet(); + } + + @Test + public void testDeciderDeciderState() throws Exception { + factoryBean.setDecider(new DeciderSupport()); + factoryBean.setName("IL"); + + factoryBean.afterPropertiesSet(); + + Step step = factoryBean.getObject(); + + assertEquals("IL", step.getName()); + assertEquals(DecisionStep.class, step.getClass()); + } + + public static class DeciderSupport implements Decider { + + @Override + public String decide(StepExecution[] executions) throws Exception { + return null; + } + } +} diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/DecisionStepTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/DecisionStepTests.java new file mode 100644 index 000000000..58f4c6df9 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/step/DecisionStepTests.java @@ -0,0 +1,122 @@ +package org.springframework.batch.core.jsr.step; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.List; + +import javax.batch.api.Decider; +import javax.batch.runtime.StepExecution; + +import org.junit.Ignore; +import org.junit.Test; +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.launch.JobLauncher; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.GenericXmlApplicationContext; + +@SuppressWarnings("resource") +public class DecisionStepTests { + + @Test + public void testDecisionAsFirstStepOfJob() throws Exception { + ApplicationContext context = new GenericXmlApplicationContext("classpath:/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionAsFirstStep-context.xml"); + + JobLauncher launcher = context.getBean(JobLauncher.class); + Job job = context.getBean(Job.class); + + JobExecution execution = launcher.run(job, new JobParameters()); + assertEquals(BatchStatus.FAILED, execution.getStatus()); + assertEquals(1, execution.getStepExecutions().size()); + } + + @Test + public void testDecisionThrowsException() throws Exception { + ApplicationContext context = new GenericXmlApplicationContext("classpath:/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionThrowsException-context.xml"); + + JobLauncher launcher = context.getBean(JobLauncher.class); + Job job = context.getBean(Job.class); + + JobExecution execution = launcher.run(job, new JobParameters()); + assertEquals(BatchStatus.FAILED, execution.getStatus()); + assertEquals(2, execution.getStepExecutions().size()); + List allFailureExceptions = execution.getAllFailureExceptions(); + + boolean found = false; + for (Throwable throwable : allFailureExceptions) { + if(throwable.getMessage().equals("Expected")) { + found = true; + break; + } + } + + if(!found) { + fail(); + } + } + + @Test + public void testDecisionValidExitStatus() throws Exception { + ApplicationContext context = new GenericXmlApplicationContext("classpath:/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionValidExitStatus-context.xml"); + + JobLauncher launcher = context.getBean(JobLauncher.class); + Job job = context.getBean(Job.class); + + JobExecution execution = launcher.run(job, new JobParameters()); + assertEquals(BatchStatus.COMPLETED, execution.getStatus()); + assertEquals(3, execution.getStepExecutions().size()); + } + + @Test + public void testDecisionInvalidExitStatus() throws Exception { + ApplicationContext context = new GenericXmlApplicationContext("classpath:/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionInvalidExitStatus-context.xml"); + + JobLauncher launcher = context.getBean(JobLauncher.class); + Job job = context.getBean(Job.class); + + JobExecution execution = launcher.run(job, new JobParameters()); + assertEquals(BatchStatus.FAILED, execution.getStatus()); + assertEquals(2, execution.getStepExecutions().size()); + + for (org.springframework.batch.core.StepExecution curExecution : execution.getStepExecutions()) { + assertEquals(BatchStatus.COMPLETED, curExecution.getStatus()); + } + } + + @Test + @Ignore("Flows as first steps are not supported yet") + public void testDecisionAfterFlow() throws Exception { + ApplicationContext context = new GenericXmlApplicationContext("classpath:/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionAfterFlow-context.xml"); + + JobLauncher launcher = context.getBean(JobLauncher.class); + Job job = context.getBean(Job.class); + + JobExecution execution = launcher.run(job, new JobParameters()); + assertEquals(BatchStatus.COMPLETED, execution.getStatus()); + assertEquals(3, execution.getStepExecutions().size()); + } + + @Test + @Ignore("Splits are not implemented yet as part of our JSR implementation") + public void testDecisionAfterSplit() { + } + + public static class NextDecider implements Decider { + + @Override + public String decide(StepExecution[] executions) throws Exception { + return "next"; + } + } + + public static class FailureDecider implements Decider { + + @Override + public String decide(StepExecution[] executions) throws Exception { + throw new RuntimeException("Expected"); + } + } +} diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests-context.xml index e0fa6acd7..7f7eaa240 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/configuration/xml/DecisionParsingTests-context.xml @@ -8,24 +8,24 @@ - - + + - + - + - + - - - + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionAfterFlow-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionAfterFlow-context.xml new file mode 100644 index 000000000..61771d5d0 --- /dev/null +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionAfterFlow-context.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionAsFirstStep-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionAsFirstStep-context.xml new file mode 100644 index 000000000..ac38f6448 --- /dev/null +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionAsFirstStep-context.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionInvalidExitStatus-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionInvalidExitStatus-context.xml new file mode 100644 index 000000000..91f3469bb --- /dev/null +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionInvalidExitStatus-context.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionThrowsException-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionThrowsException-context.xml new file mode 100644 index 000000000..4ecc16dfa --- /dev/null +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionThrowsException-context.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionValidExitStatus-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionValidExitStatus-context.xml new file mode 100644 index 000000000..348f9e60a --- /dev/null +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionValidExitStatus-context.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +