diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java
index 41f534994..a9ad50d6c 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java
@@ -250,7 +250,7 @@ public class SimpleJobRepository implements JobRepository {
* @see org.springframework.batch.core.repository.JobRepository#saveOrUpdateExecutionContext(org.springframework.batch.core.domain.StepExecution)
*/
public void saveOrUpdateExecutionContext(StepExecution stepExecution) {
- saveOrUpdate(stepExecution);
+ // Until there is an interface change (
stepExecutionDao.saveOrUpdateExecutionContext(stepExecution);
jobExecutionDao.saveOrUpdateExecutionContext(stepExecution.getJobExecution());
}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java
index 23a54beda..fbf81ecff 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/AbstractStep.java
@@ -171,6 +171,7 @@ public abstract class AbstractStep implements Step, InitializingBean, BeanNameAw
exitStatus = exitStatus.and(getCompositeListener().afterStep(stepExecution));
try {
+ getJobRepository().saveOrUpdate(stepExecution);
getJobRepository().saveOrUpdateExecutionContext(stepExecution);
}
catch (Exception e) {
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ItemOrientedStep.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ItemOrientedStep.java
index 0f5e7591c..d516e1f5c 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ItemOrientedStep.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/ItemOrientedStep.java
@@ -211,6 +211,7 @@ public class ItemOrientedStep extends AbstractStep {
*/
protected ExitStatus doExecute(final StepExecution stepExecution) throws Exception {
stream.update(stepExecution.getExecutionContext());
+ getJobRepository().saveOrUpdate(stepExecution);
getJobRepository().saveOrUpdateExecutionContext(stepExecution);
itemHandler.mark();
@@ -362,6 +363,12 @@ public class ItemOrientedStep extends AbstractStep {
throw new FatalException("Failed while processing rollback", e);
}
}
+
+ if (fatalException.hasException()) {
+ // Try and give the system a chance to update the stepExecution with
+ // the failure status.
+ getJobRepository().saveOrUpdate(stepExecution);
+ }
}
private static class ExceptionHolder {
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java
index 028a96fb4..e8c5ca4f9 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/job/SimpleJobTests.java
@@ -19,7 +19,6 @@ package org.springframework.batch.core.job;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.Properties;
import junit.framework.TestCase;
@@ -45,6 +44,7 @@ import org.springframework.batch.core.repository.dao.MapStepExecutionDao;
import org.springframework.batch.core.repository.dao.StepExecutionDao;
import org.springframework.batch.core.repository.support.SimpleJobRepository;
import org.springframework.batch.core.step.StepSupport;
+import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.repeat.ExitStatus;
/**
@@ -269,7 +269,6 @@ public class SimpleJobTests extends TestCase {
catch (Error e) {
assertEquals(exception, e);
}
- System.err.println(list);
assertEquals(0, list.size());
checkRepository(BatchStatus.FAILED, ExitStatus.FAILED);
}
@@ -347,6 +346,7 @@ public class SimpleJobTests extends TestCase {
assertSame(exception, e);
}
assertTrue(step1.passedInStepContext.isEmpty());
+ System.err.println(step2.passedInStepContext);
assertFalse(step2.passedInStepContext.isEmpty());
}
@@ -463,9 +463,9 @@ public class SimpleJobTests extends TestCase {
private JobRepository jobRepository;
- private Properties passedInStepContext;
+ private ExecutionContext passedInStepContext;
- private Properties passedInJobContext;
+ private ExecutionContext passedInJobContext;
/**
* @param string
@@ -495,10 +495,11 @@ public class SimpleJobTests extends TestCase {
public void execute(StepExecution stepExecution) throws JobInterruptedException,
UnexpectedJobExecutionException {
- passedInJobContext = stepExecution.getJobExecution().getExecutionContext().getProperties();
- passedInStepContext = stepExecution.getExecutionContext().getProperties();
+ passedInJobContext = new ExecutionContext(stepExecution.getJobExecution().getExecutionContext());
+ passedInStepContext = new ExecutionContext(stepExecution.getExecutionContext());
stepExecution.getExecutionContext().putString("stepKey", "stepValue");
stepExecution.getJobExecution().getExecutionContext().putString("jobKey", "jobValue");
+ jobRepository.saveOrUpdate(stepExecution);
jobRepository.saveOrUpdateExecutionContext(stepExecution);
if (exception instanceof RuntimeException) {
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/ItemOrientedStepIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/ItemOrientedStepIntegrationTests.java
new file mode 100644
index 000000000..5f1b35cd7
--- /dev/null
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/ItemOrientedStepIntegrationTests.java
@@ -0,0 +1,166 @@
+/*
+ * 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.step.item;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.sql.DataSource;
+
+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.JobSupport;
+import org.springframework.batch.core.repository.JobRepository;
+import org.springframework.batch.core.repository.dao.MapJobExecutionDao;
+import org.springframework.batch.core.repository.dao.MapJobInstanceDao;
+import org.springframework.batch.core.repository.dao.MapStepExecutionDao;
+import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
+import org.springframework.batch.item.AbstractItemWriter;
+import org.springframework.batch.item.ExecutionContext;
+import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.support.ListItemReader;
+import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
+import org.springframework.batch.repeat.support.RepeatTemplate;
+import org.springframework.batch.support.PropertiesConverter;
+import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.support.TransactionSynchronizationAdapter;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+/**
+ * @author Dave Syer
+ *
+ */
+public class ItemOrientedStepIntegrationTests extends AbstractDependencyInjectionSpringContextTests {
+
+ private List processed = new ArrayList();
+
+ private ItemOrientedStep step;
+
+ private Job job;
+
+ private PlatformTransactionManager transactionManager;
+
+ private DataSource dataSource;
+
+ private JobRepository jobRepository;
+
+ /**
+ * Public setter for the PlatformTransactionManager.
+ * @param transactionManager the transactionManager to set
+ */
+ public void setTransactionManager(PlatformTransactionManager transactionManager) {
+ this.transactionManager = transactionManager;
+ }
+
+ /**
+ * Public setter for the DataSource.
+ * @param dataSource the dataSource to set
+ */
+ public void setDataSource(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ private ItemReader getReader(String[] args) {
+ return new ListItemReader(Arrays.asList(args));
+ }
+
+ protected void onSetUp() throws Exception {
+ MapJobInstanceDao.clear();
+ MapStepExecutionDao.clear();
+ MapJobExecutionDao.clear();
+
+ JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
+ jobRepositoryFactoryBean.setDatabaseType("hsql");
+ jobRepositoryFactoryBean.setDataSource(dataSource);
+ jobRepositoryFactoryBean.setTransactionManager(transactionManager);
+ jobRepositoryFactoryBean.afterPropertiesSet();
+ jobRepository = (JobRepository) jobRepositoryFactoryBean.getObject();
+ RepeatTemplate template;
+
+ step = new ItemOrientedStep("stepName");
+ step.setJobRepository(jobRepository);
+ step.setTransactionManager(transactionManager);
+ template = new RepeatTemplate();
+ template.setCompletionPolicy(new SimpleCompletionPolicy(1));
+ step.setStepOperations(template);
+
+ // Only process one item:
+ template = new RepeatTemplate();
+ template.setCompletionPolicy(new SimpleCompletionPolicy(1));
+ step.setChunkOperations(template);
+
+ job = new JobSupport("FOO");
+
+ step.setTransactionManager(transactionManager);
+
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.test.AbstractSingleSpringContextTests#getConfigLocations()
+ */
+ protected String[] getConfigLocations() {
+ return new String[] { "sql-dao-test.xml" };
+ }
+
+ public void testStatusForCommitFailedException() throws Exception {
+
+ step.setItemHandler(new SimpleItemHandler(getReader(new String[] { "a", "b", "c" }), new AbstractItemWriter() {
+ public void write(Object data) throws Exception {
+ processed.add((String) data);
+ TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
+ public void beforeCommit(boolean readOnly) {
+ throw new RuntimeException("Simulate commit failure");
+ }
+ });
+ }
+ }));
+
+ JobExecution jobExecution = jobRepository.createJobExecution(job, new JobParameters());
+ StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
+
+ stepExecution.setExecutionContext(new ExecutionContext(PropertiesConverter.stringToProperties("foo=bar")));
+ // step.setLastExecution(stepExecution);
+
+ try {
+ step.execute(stepExecution);
+ fail("Expected BatchCriticalException");
+ }
+ catch (RuntimeException e) {
+
+ assertEquals(BatchStatus.UNKNOWN, stepExecution.getStatus());
+ StepExecution lastStepExecution = jobRepository.getLastStepExecution(jobExecution.getJobInstance(), step);
+ assertEquals(lastStepExecution, stepExecution);
+ assertFalse(lastStepExecution == stepExecution);
+
+ // If the StepExecution is not saved after the failure it will be
+ // STARTED instead of UNKNOWN
+ assertEquals(BatchStatus.UNKNOWN, lastStepExecution.getStatus());
+
+ String msg = stepExecution.getExitStatus().getExitDescription();
+ assertTrue(msg.contains("Fatal error detected during commit"));
+ // The original rollback was caused by this one:
+ assertEquals("Simulate commit failure", e.getCause().getMessage());
+
+ }
+ }
+
+}
diff --git a/spring-batch-core/src/test/resources/log4j.properties b/spring-batch-core/src/test/resources/log4j.properties
index f242f56df..aa887525f 100644
--- a/spring-batch-core/src/test/resources/log4j.properties
+++ b/spring-batch-core/src/test/resources/log4j.properties
@@ -8,6 +8,7 @@ log4j.category.org.apache.activemq=ERROR
log4j.category.org.springframework.batch=DEBUG
log4j.category.org.springframework.batch.support=INFO
# log4j.category.org.springframework.transaction=INFO
+log4j.category.org.springframework.jdbc=DEBUG
# log4j.category.org.hibernate.SQL=DEBUG
# for debugging datasource initialization
diff --git a/spring-batch-infrastructure-tests/pom.xml b/spring-batch-infrastructure-tests/pom.xml
index bb61c923e..a58e5aaac 100644
--- a/spring-batch-infrastructure-tests/pom.xml
+++ b/spring-batch-infrastructure-tests/pom.xml
@@ -59,7 +59,7 @@
hsqldb
hsqldb
- test
+ runtime
commons-io
diff --git a/spring-batch-samples/.springBeans b/spring-batch-samples/.springBeans
index af76377a4..63237cf04 100644
--- a/spring-batch-samples/.springBeans
+++ b/spring-batch-samples/.springBeans
@@ -1,10 +1,11 @@
1
-
+
+
src/main/resources/jobs/fixedLengthImportJob.xml
src/main/resources/jobs/multilineJob.xml