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 fc97db05f..36264ad13 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 @@ -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. @@ -147,12 +147,6 @@ public class FlowParser extends AbstractFlowParser { Collection list = new ArrayList(); - String shortNextAttribute = element.getAttribute(NEXT_ATTRIBUTE); - boolean hasNextAttribute = StringUtils.hasText(shortNextAttribute); - if (hasNextAttribute) { - list.add(getStateTransitionReference(parserContext, stateDef, null, shortNextAttribute)); - } - boolean transitionElementExists = false; List childElements = DomUtils.getChildElements(element); for(Element childElement : childElements) { @@ -162,6 +156,9 @@ public class FlowParser extends AbstractFlowParser { } } + String shortNextAttribute = element.getAttribute(NEXT_ATTRIBUTE); + boolean hasNextAttribute = StringUtils.hasText(shortNextAttribute); + if (!transitionElementExists) { list.addAll(createTransition(FlowExecutionStatus.FAILED, FlowExecutionStatus.FAILED.getName(), null, null, stateDef, parserContext, false)); @@ -173,6 +170,10 @@ public class FlowParser extends AbstractFlowParser { } } + if (hasNextAttribute) { + list.add(getStateTransitionReference(parserContext, stateDef, null, shortNextAttribute)); + } + return list; } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/launch/JsrJobOperator.java b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/launch/JsrJobOperator.java index b3590231a..597857981 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/launch/JsrJobOperator.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/jsr/launch/JsrJobOperator.java @@ -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. @@ -447,7 +447,7 @@ public class JsrJobOperator implements JobOperator, InitializingBean { } } - String jobName = previousJobExecution.getJobInstance().getJobName(); + final String jobName = previousJobExecution.getJobInstance().getJobName(); Properties jobRestartProperties = getJobRestartProperties(params, previousJobExecution); @@ -477,12 +477,6 @@ public class JsrJobOperator implements JobOperator, InitializingBean { throw new JobRestartException(e); } - final Job job = batchContext.getBean(Job.class); - - if(!job.isRestartable()) { - throw new JobRestartException("Job " + jobName + " is not restartable"); - } - final org.springframework.batch.core.JobExecution jobExecution; try { @@ -506,6 +500,11 @@ public class JsrJobOperator implements JobOperator, InitializingBean { factoryBean = (JobContextFactoryBean) batchContext.getBean("&" + JSR_JOB_CONTEXT_BEAN_NAME); factoryBean.setJobExecution(jobExecution); final Job job = batchContext.getBean(Job.class); + + if(!job.isRestartable()) { + throw new JobRestartException("Job " + jobName + " is not restartable"); + } + semaphore.release(); // Initialization of the JobExecution for job level dependencies jobRegistry.register(job, jobExecution); @@ -537,7 +536,10 @@ public class JsrJobOperator implements JobOperator, InitializingBean { if (jobExecution.getExitStatus().equals(ExitStatus.UNKNOWN)) { jobExecution.setExitStatus(ExitStatus.FAILED.addExitDescription(e)); } + jobRepository.update(jobExecution); + + throw new JobRestartException(e); } finally { batchContext.close(); } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/FlowParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/FlowParserTests.java index fb6415921..c14b81785 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/FlowParserTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/configuration/xml/FlowParserTests.java @@ -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. @@ -16,13 +16,18 @@ package org.springframework.batch.core.jsr.configuration.xml; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.springframework.batch.core.jsr.JsrTestUtils.restartJob; import static org.springframework.batch.core.jsr.JsrTestUtils.runJob; +import java.util.List; import java.util.Properties; import javax.batch.api.AbstractBatchlet; +import javax.batch.operations.JobOperator; +import javax.batch.runtime.BatchRuntime; import javax.batch.runtime.JobExecution; +import javax.batch.runtime.StepExecution; import javax.batch.runtime.context.StepContext; import javax.inject.Inject; @@ -38,7 +43,6 @@ import org.springframework.batch.core.ExitStatus; * @since 3.0 */ public class FlowParserTests { - @Test public void testDuplicateTransitionPatternsAllowed() throws Exception { JobExecution stoppedExecution = runJob("FlowParserTests-context", new Properties(), 10000l); @@ -48,6 +52,18 @@ public class FlowParserTests { assertEquals(ExitStatus.COMPLETED.getExitCode(), endedExecution.getExitStatus()); } + @Test + public void testWildcardAddedLastWhenUsedWithNextAttrAndNoTransitionElements() throws Exception { + JobExecution jobExecution = runJob("FlowParserTestsWildcardAndNextAttrJob", new Properties(), 1000l); + assertEquals(ExitStatus.FAILED.getExitCode(), jobExecution.getExitStatus()); + + JobOperator jobOperator = BatchRuntime.getJobOperator(); + List stepExecutions = jobOperator.getStepExecutions(jobExecution.getExecutionId()); + assertEquals(1, stepExecutions.size()); + StepExecution failedStep = stepExecutions.get(0); + assertTrue("step1".equals(failedStep.getStepName())); + } + public static class TestBatchlet extends AbstractBatchlet { private static int CNT; @@ -66,4 +82,11 @@ public class FlowParserTests { return exitCode; } } + + public static class FailingTestBatchlet extends AbstractBatchlet { + @Override + public String process() throws Exception { + throw new RuntimeException("blah"); + } + } } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/launch/JsrJobOperatorTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/launch/JsrJobOperatorTests.java index fcb7838c1..32f2ef788 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/launch/JsrJobOperatorTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/jsr/launch/JsrJobOperatorTests.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.Properties; import java.util.Set; +import javax.batch.api.AbstractBatchlet; import javax.batch.api.Batchlet; import javax.batch.operations.JobExecutionIsRunningException; import javax.batch.operations.JobOperator; @@ -424,6 +425,14 @@ public class JsrJobOperatorTests { assertEquals(BatchStatus.COMPLETED, execution.getBatchStatus()); } + @Test(expected = JobRestartException.class) + public void testNonRestartableJob() throws Exception { + javax.batch.runtime.JobExecution jobExecutionStart = runJob("jsrJobOperatorTestNonRestartableJob", new Properties(), TIMEOUT); + assertEquals(BatchStatus.FAILED, jobExecutionStart.getBatchStatus()); + + restartJob(jobExecutionStart.getExecutionId(), null, TIMEOUT); + } + @Test(expected = JobRestartException.class) public void testRestartAbandoned() throws Exception { jsrJobOperator = BatchRuntime.getJobOperator(); @@ -534,4 +543,11 @@ public class JsrJobOperatorTests { stopped = true; } } + + public static class FailingBatchlet extends AbstractBatchlet { + @Override + public String process() throws Exception { + throw new RuntimeException("blah"); + } + } } diff --git a/spring-batch-core/src/test/resources/META-INF/batch-jobs/FlowParserTests-context.xml b/spring-batch-core/src/test/resources/META-INF/batch-jobs/FlowParserTests-context.xml index 13125eab6..69afbd063 100644 --- a/spring-batch-core/src/test/resources/META-INF/batch-jobs/FlowParserTests-context.xml +++ b/spring-batch-core/src/test/resources/META-INF/batch-jobs/FlowParserTests-context.xml @@ -2,7 +2,6 @@ diff --git a/spring-batch-core/src/test/resources/META-INF/batch-jobs/FlowParserTestsWildcardAndNextAttrJob.xml b/spring-batch-core/src/test/resources/META-INF/batch-jobs/FlowParserTestsWildcardAndNextAttrJob.xml new file mode 100644 index 000000000..489795418 --- /dev/null +++ b/spring-batch-core/src/test/resources/META-INF/batch-jobs/FlowParserTestsWildcardAndNextAttrJob.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + diff --git a/spring-batch-core/src/test/resources/META-INF/batch-jobs/jsrJobOperatorTestNonRestartableJob.xml b/spring-batch-core/src/test/resources/META-INF/batch-jobs/jsrJobOperatorTestNonRestartableJob.xml new file mode 100644 index 000000000..63b2fa0cd --- /dev/null +++ b/spring-batch-core/src/test/resources/META-INF/batch-jobs/jsrJobOperatorTestNonRestartableJob.xml @@ -0,0 +1,7 @@ + + + + + + +