diff --git a/archetypes/simple-cli/.project b/archetypes/simple-cli/.project
index c663d81a2..fbbe41a0f 100644
--- a/archetypes/simple-cli/.project
+++ b/archetypes/simple-cli/.project
@@ -39,7 +39,7 @@ $ mvn archetype:create -DgroupId=com.mycompany -DartifactId=batch \
archetypes-pom.xml
1
- SPRING_BATCH/archetypes/pom.xml
+ SPRING_BATCH/archetypes/pom.xml
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 d985b8451..57d13c825 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
@@ -243,6 +243,8 @@ public class ItemOrientedStep extends AbstractStep {
TransactionStatus transaction = transactionManager.getTransaction(transactionAttribute);
+ boolean locked = false;
+
try {
try {
@@ -265,7 +267,8 @@ public class ItemOrientedStep extends AbstractStep {
// to synchronize changes to the step execution (at a
// minimum).
try {
- synchronizer.lock(stepExecution);
+ synchronizer.lock(stepExecution);
+ locked = true;
}
catch (InterruptedException e) {
stepExecution.setStatus(BatchStatus.STOPPED);
@@ -345,7 +348,11 @@ public class ItemOrientedStep extends AbstractStep {
throw e;
}
finally {
- synchronizer.release(stepExecution);
+ // only release the lock if we acquired it
+ if (locked) {
+ synchronizer.release(stepExecution);
+ }
+ locked = false;
}
// Check for interruption after transaction as well, so that
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/StepExecutorInterruptionTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/StepExecutorInterruptionTests.java
index 495589de3..f306e7999 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/StepExecutorInterruptionTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/item/StepExecutorInterruptionTests.java
@@ -141,6 +141,35 @@ public class StepExecutorInterruptionTests extends TestCase {
}
+ public void testLockNotReleasedIfChunkFails() throws Exception {
+
+ step.setItemHandler(new SimpleItemHandler(new AbstractItemReader() {
+ public Object read() throws Exception {
+ throw new RuntimeException("Planned!");
+ }
+ }, itemWriter));
+
+ step.setSynchronizer(new StepExecutionSynchronizer() {
+ private boolean locked = false;
+ public void lock(StepExecution stepExecution) throws InterruptedException {
+ locked = true;
+ }
+ public void release(StepExecution stepExecution) {
+ assertTrue("Lock released before it is acquired", locked);
+ }
+ });
+
+ try {
+ step.execute(stepExecution);
+ fail("Expected planned RuntimeException");
+ } catch (RuntimeException e) {
+ assertEquals("Planned!", e.getMessage());
+ }
+
+ assertEquals(BatchStatus.FAILED, stepExecution.getStatus());
+
+ }
+
/**
* @return
*/