diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/domain/Job.java b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/Job.java
index 964866380..6e604ed1c 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/domain/Job.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/Job.java
@@ -18,7 +18,6 @@ package org.springframework.batch.core.domain;
import java.util.List;
import org.springframework.batch.io.exception.BatchCriticalException;
-import org.springframework.batch.repeat.ExitStatus;
/**
* Batch domain object representing a job. Job is an explicit abstraction
@@ -39,6 +38,6 @@ public interface Job {
boolean isRestartable();
- ExitStatus run(JobExecution execution) throws BatchCriticalException;
+ void run(JobExecution execution) throws BatchCriticalException;
}
\ No newline at end of file
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobSupport.java b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobSupport.java
index db479b1f7..e79e6dcb7 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobSupport.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobSupport.java
@@ -20,7 +20,6 @@ import java.util.ArrayList;
import java.util.List;
import org.springframework.batch.io.exception.BatchCriticalException;
-import org.springframework.batch.repeat.ExitStatus;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.util.ClassUtils;
@@ -134,7 +133,7 @@ public class JobSupport implements BeanNameAware, Job {
/* (non-Javadoc)
* @see org.springframework.batch.core.domain.Job#run(org.springframework.batch.core.domain.JobExecution)
*/
- public ExitStatus run(JobExecution execution) throws BatchCriticalException {
+ public void run(JobExecution execution) throws BatchCriticalException {
throw new UnsupportedOperationException("JobSupport does not provide an implementation of run(). Use a smarter subclass.");
}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/domain/Step.java b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/Step.java
index 266984873..a555b2489 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/domain/Step.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/Step.java
@@ -16,14 +16,12 @@
package org.springframework.batch.core.domain;
import org.springframework.batch.io.exception.BatchCriticalException;
-import org.springframework.batch.repeat.ExitStatus;
-
/**
* Batch domain interface representing the configuration of a step. As with the
- * (@link Job), step configuration is meant to explicitly represent
- * a the configuration of a step by a developer. This allows for the separation
- * of what a developer configures from the myriad of concerns required for
+ * (@link Job), step configuration is meant to explicitly represent a the
+ * configuration of a step by a developer. This allows for the separation of
+ * what a developer configures from the myriad of concerns required for
* executing a job.
*
* @author Dave Syer
@@ -41,7 +39,7 @@ public interface Step {
* again.
*/
boolean isAllowStartIfComplete();
-
+
/**
* Flag to indicate if restart data needs to be saved for this step.
* @return true if restart data should be saved
@@ -53,11 +51,15 @@ public interface Step {
* identifier.
*/
int getStartLimit();
-
+
/**
- * It is not safe to re-use an instance of {@link StepExecutor} to process
- * multiple concurrent executions. Use the factory method in {@link Step} to
- * create a new instance and execute that.
+ * Process the step and assign progress and status meta information to the
+ * {@link StepExecution} provided. The {@link Step} is responsible for
+ * setting the meta information and also saving it if required by the
+ * implementation.
+ *
+ * It is not safe to re-use an instance of {@link Step} to process multiple
+ * concurrent executions.
*
* @param stepExecution an entity representing the step to be executed
*
@@ -65,6 +67,6 @@ public interface Step {
* @throws BatchCriticalException if there is a problem that needs to be
* signalled to the caller
*/
- ExitStatus process(StepExecution stepExecution) throws StepInterruptedException, BatchCriticalException;
+ void process(StepExecution stepExecution) throws StepInterruptedException, BatchCriticalException;
}
\ No newline at end of file
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/domain/StepSupport.java b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/StepSupport.java
index bcbee4640..a7baba0a5 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/domain/StepSupport.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/StepSupport.java
@@ -136,7 +136,7 @@ public class StepSupport implements Step, BeanNameAware {
*
* @see org.springframework.batch.core.domain.Step#process(org.springframework.batch.core.domain.StepExecution)
*/
- public org.springframework.batch.repeat.ExitStatus process(StepExecution stepExecution)
+ public void process(StepExecution stepExecution)
throws StepInterruptedException, BatchCriticalException {
throw new UnsupportedOperationException(
"Cannot process a StepExecution. Use a smarter subclass of StepSupport.");
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/job/simple/SimpleJob.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/job/simple/SimpleJob.java
index b1124dbf1..241672c9b 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/job/simple/SimpleJob.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/job/simple/SimpleJob.java
@@ -55,7 +55,7 @@ public class SimpleJob extends JobSupport {
*
* @see org.springframework.batch.core.domain.Job#run(org.springframework.batch.core.domain.JobExecution)
*/
- public ExitStatus run(JobExecution execution) throws BatchCriticalException {
+ public void run(JobExecution execution) throws BatchCriticalException {
JobInstance jobInstance = execution.getJobInstance();
updateStatus(execution, BatchStatus.STARTING);
@@ -78,7 +78,8 @@ public class SimpleJob extends JobSupport {
startedCount++;
updateStatus(execution, BatchStatus.STARTED);
StepExecution stepExecution = execution.createStepExecution(stepInstance);
- status = step.process(stepExecution);
+ step.process(stepExecution);
+ status = stepExecution.getExitStatus();
}
}
@@ -111,7 +112,6 @@ public class SimpleJob extends JobSupport {
jobRepository.saveOrUpdate(execution);
}
- return status;
}
private void updateStatus(JobExecution jobExecution, BatchStatus status) {
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/launch/SimpleJobLauncher.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/launch/SimpleJobLauncher.java
index 87f4622b5..c68ad4327 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/launch/SimpleJobLauncher.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/launch/SimpleJobLauncher.java
@@ -24,7 +24,6 @@ import org.springframework.batch.core.domain.JobParameters;
import org.springframework.batch.core.domain.JobSupport;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobRepository;
-import org.springframework.batch.repeat.ExitStatus;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
@@ -83,10 +82,7 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean {
public void run() {
try {
logger.info("Job: [" + job + "] launched with the following parameters: [" + jobParameters + "]");
- ExitStatus exitStatus = job.run(jobExecution);
- // The exit status should be set by the Job. TODO: remove
- // this line...
- jobExecution.setExitStatus(exitStatus);
+ job.run(jobExecution);
logger.info("Job: [" + job + "] completed successfully with the following parameters: ["
+ jobParameters + "]");
}
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/AbstractStep.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/AbstractStep.java
index e4fd4dec2..cbaf5c6fa 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/AbstractStep.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/AbstractStep.java
@@ -22,7 +22,6 @@ import org.springframework.batch.core.domain.StepSupport;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.tasklet.Tasklet;
import org.springframework.batch.io.exception.BatchCriticalException;
-import org.springframework.batch.repeat.ExitStatus;
import org.springframework.batch.repeat.exception.handler.ExceptionHandler;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.Assert;
@@ -112,9 +111,9 @@ public abstract class AbstractStep extends StepSupport {
/* (non-Javadoc)
* @see org.springframework.batch.core.domain.StepSupport#process(org.springframework.batch.core.domain.StepExecution)
*/
- public ExitStatus process(StepExecution stepExecution) throws StepInterruptedException, BatchCriticalException {
+ public void process(StepExecution stepExecution) throws StepInterruptedException, BatchCriticalException {
SimpleStepExecutor executor = createStepExecutor();
- return executor.process(stepExecution);
+ executor.process(stepExecution);
}
/**
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/RepeatOperationsStep.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/RepeatOperationsStep.java
index daaed6c19..743cef001 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/RepeatOperationsStep.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/RepeatOperationsStep.java
@@ -20,7 +20,6 @@ import org.springframework.batch.core.domain.Step;
import org.springframework.batch.core.domain.StepExecution;
import org.springframework.batch.core.domain.StepInterruptedException;
import org.springframework.batch.io.exception.BatchCriticalException;
-import org.springframework.batch.repeat.ExitStatus;
import org.springframework.batch.repeat.RepeatOperations;
/**
@@ -78,7 +77,7 @@ public class RepeatOperationsStep extends AbstractStep implements RepeatOperatio
/* (non-Javadoc)
* @see org.springframework.batch.execution.step.simple.AbstractStep#process(org.springframework.batch.core.domain.StepExecution)
*/
- public ExitStatus process(StepExecution stepExecution) throws StepInterruptedException, BatchCriticalException {
+ public void process(StepExecution stepExecution) throws StepInterruptedException, BatchCriticalException {
assertMandatoryProperties();
SimpleStepExecutor executor = (SimpleStepExecutor) super.createStepExecutor();
if (stepOperations != null) {
@@ -87,6 +86,6 @@ public class RepeatOperationsStep extends AbstractStep implements RepeatOperatio
if (chunkOperations != null) {
executor.setChunkOperations(chunkOperations);
}
- return executor.process(stepExecution);
+ executor.process(stepExecution);
}
}
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java
index 38e1d8494..4215746cd 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java
@@ -173,7 +173,7 @@ public class SimpleStepExecutor {
* execution
* @see StepExecutor#process(StepExecution)
*/
- public ExitStatus process(final StepExecution stepExecution) throws BatchCriticalException,
+ public void process(final StepExecution stepExecution) throws BatchCriticalException,
StepInterruptedException {
final StepInstance stepInstance = stepExecution.getStep();
@@ -276,7 +276,6 @@ public class SimpleStepExecutor {
});
updateStatus(stepExecution, BatchStatus.COMPLETED);
- return status;
}
catch (RuntimeException e) {
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/tasklet/ItemOrientedTasklet.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/tasklet/ItemOrientedTasklet.java
index 883fea698..5e5f0f7a6 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/tasklet/ItemOrientedTasklet.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/tasklet/ItemOrientedTasklet.java
@@ -21,6 +21,7 @@ import org.springframework.batch.io.Skippable;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemRecoverer;
import org.springframework.batch.item.ItemWriter;
+import org.springframework.batch.item.KeyedItemReader;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.batch.retry.RetryPolicy;
import org.springframework.batch.retry.callback.ItemReaderRetryCallback;
@@ -111,7 +112,8 @@ public class ItemOrientedTasklet implements Tasklet, Skippable, InitializingBean
template.setRetryPolicy(itemProviderRetryPolicy);
if (retryPolicy != null) {
- retryCallback = new ItemReaderRetryCallback(itemProvider, itemWriter);
+ Assert.state(itemProvider instanceof KeyedItemReader, "ItemReader must be instance of KeyedItemReader to use the retry policy");
+ retryCallback = new ItemReaderRetryCallback((KeyedItemReader) itemProvider, itemWriter);
retryCallback.setRecoverer(itemRecoverer);
}
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/job/simple/SimpleJobTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/job/simple/SimpleJobTests.java
index 246fc77b8..f2abe69c4 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/job/simple/SimpleJobTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/job/simple/SimpleJobTests.java
@@ -272,7 +272,7 @@ public class SimpleJobTests extends TestCase {
this.runnable = runnable;
}
- public ExitStatus process(StepExecution stepExecution) throws StepInterruptedException, BatchCriticalException {
+ public void process(StepExecution stepExecution) throws StepInterruptedException, BatchCriticalException {
if (exception instanceof RuntimeException) {
throw (RuntimeException)exception;
}
@@ -282,7 +282,7 @@ public class SimpleJobTests extends TestCase {
if (runnable!=null) {
runnable.run();
}
- return ExitStatus.FINISHED;
+ stepExecution.setExitStatus(ExitStatus.FINISHED);
}
}
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/launch/SimpleJobLauncherTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/launch/SimpleJobLauncherTests.java
index 10c178e8e..e0b86c8b8 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/launch/SimpleJobLauncherTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/launch/SimpleJobLauncherTests.java
@@ -41,8 +41,9 @@ public class SimpleJobLauncherTests extends TestCase {
private MockControl repositoryControl = MockControl.createControl(JobRepository.class);
private Job job = new JobSupport("foo") {
- public ExitStatus run(JobExecution execution) {
- return ExitStatus.FINISHED;
+ public void run(JobExecution execution) {
+ execution.setExitStatus(ExitStatus.FINISHED);
+ return;
}
};
@@ -88,7 +89,7 @@ public class SimpleJobLauncherTests extends TestCase {
public void testRunWithException() throws Exception {
job = new JobSupport() {
- public ExitStatus run(JobExecution execution) {
+ public void run(JobExecution execution) {
execution.setExitStatus(ExitStatus.FAILED);
throw new RuntimeException("foo");
}
@@ -104,7 +105,7 @@ public class SimpleJobLauncherTests extends TestCase {
public void testRunWithError() throws Exception {
job = new JobSupport() {
- public ExitStatus run(JobExecution execution) {
+ public void run(JobExecution execution) {
execution.setExitStatus(ExitStatus.FAILED);
throw new Error("foo");
}
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/tasklet/ItemOrientedTaskletTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/tasklet/ItemOrientedTaskletTests.java
index 9d03297de..6304ccb34 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/tasklet/ItemOrientedTaskletTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/tasklet/ItemOrientedTaskletTests.java
@@ -27,6 +27,7 @@ import org.springframework.batch.io.Skippable;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemRecoverer;
import org.springframework.batch.item.ItemWriter;
+import org.springframework.batch.item.KeyedItemReader;
import org.springframework.batch.item.reader.AbstractItemReader;
import org.springframework.batch.item.writer.AbstractItemWriter;
import org.springframework.batch.repeat.context.RepeatContextSupport;
@@ -217,11 +218,7 @@ public class ItemOrientedTaskletTests extends TestCase {
return true;
}
});
- module.setItemReader(new AbstractItemReader() {
- public Object read() throws Exception {
- return "foo";
- }
- });
+ module.setItemReader(new MockItemReader());
module.setItemWriter(new AbstractItemWriter() {
public void write(Object data) throws Exception {
throw new RuntimeException("FOO");
@@ -267,7 +264,16 @@ public class ItemOrientedTaskletTests extends TestCase {
}
}
- private class SkippableItemReader implements ItemReader,
+ private class MockItemReader extends AbstractItemReader implements KeyedItemReader {
+ public Object read() throws Exception {
+ return "foo";
+ }
+ public Object getKey(Object item) {
+ return item;
+ }
+ }
+
+ private class SkippableItemReader implements KeyedItemReader,
Skippable, StatisticsProvider {
public Object read() throws Exception {
return itemProvider.read();
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/tasklet/RestartableItemOrientedTaskletTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/tasklet/RestartableItemOrientedTaskletTests.java
index 7752ee0cd..786c15c25 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/tasklet/RestartableItemOrientedTaskletTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/tasklet/RestartableItemOrientedTaskletTests.java
@@ -55,10 +55,6 @@ public class RestartableItemOrientedTaskletTests extends TestCase {
assertEquals(this.data.getProperties(), data.getProperties());
}
- public Object getKey(Object item) {
- return null;
- }
-
public boolean recover(Object data, Throwable cause) {
return false;
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/cursor/JdbcCursorItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/cursor/JdbcCursorItemReader.java
index f5fc39efb..2f18b1018 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/cursor/JdbcCursorItemReader.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/cursor/JdbcCursorItemReader.java
@@ -31,7 +31,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.io.Skippable;
import org.springframework.batch.io.support.AbstractTransactionalIoSource;
-import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.KeyedItemReader;
import org.springframework.batch.item.ResourceLifecycle;
import org.springframework.batch.restart.GenericRestartData;
import org.springframework.batch.restart.RestartData;
@@ -117,7 +117,7 @@ import org.springframework.util.StringUtils;
* @author Peter Zozom
*/
public class JdbcCursorItemReader extends AbstractTransactionalIoSource
- implements ItemReader, ResourceLifecycle, DisposableBean,
+ implements KeyedItemReader, ResourceLifecycle, DisposableBean,
InitializingBean, Restartable, StatisticsProvider, Skippable {
private static Log log = LogFactory.getLog(JdbcCursorItemReader.class);
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/driving/DrivingQueryItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/driving/DrivingQueryItemReader.java
index 1dc05952f..2f37d3bcc 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/driving/DrivingQueryItemReader.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/driving/DrivingQueryItemReader.java
@@ -19,7 +19,7 @@ import java.util.Iterator;
import java.util.List;
import org.springframework.batch.io.support.AbstractTransactionalIoSource;
-import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.KeyedItemReader;
import org.springframework.batch.item.ResourceLifecycle;
import org.springframework.batch.repeat.synch.BatchTransactionSynchronizationManager;
import org.springframework.batch.restart.RestartData;
@@ -51,7 +51,7 @@ import org.springframework.util.Assert;
* @since 1.0
*/
public class DrivingQueryItemReader extends AbstractTransactionalIoSource
- implements ItemReader, ResourceLifecycle, InitializingBean,
+ implements KeyedItemReader, ResourceLifecycle, InitializingBean,
DisposableBean, Restartable {
private boolean initialized = false;
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemReader.java
index f63d0f140..33619c813 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemReader.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/ItemReader.java
@@ -16,9 +16,10 @@
package org.springframework.batch.item;
+import org.springframework.batch.item.reader.AbstractItemReader;
+
/**
- * Strategy interface for providing the data for a given batch stage execution.
- *
+ * Strategy interface for providing the data.
*
* Implementations are expected to be stateful and will be called multiple times
* for each batch, with each call to {@link #next} returning a different value
@@ -26,8 +27,8 @@ package org.springframework.batch.item;
*
* Implementations need to be thread safe and clients of a {@link ItemReader}
* need to be aware that this is the case. Clients can code to this interface
- * without worrying about thread safety by using the AbstractItemProvider base
- * class.
+ * without worrying about thread safety by using the {@link AbstractItemReader}
+ * base class.
*
* A richer interface (e.g. with a look ahead or peek) is not feasible because
* we need to support transactions in an asynchronous batch.
@@ -50,15 +51,6 @@ public interface ItemReader {
*/
Object read() throws Exception;
- /**
- * Get a unique identifier for the item that can be used to cache it between
- * calls if necessary, and then identify it later.
- *
- * @param item the current item.
- * @return a unique identifier.
- */
- Object getKey(Object item);
-
/**
* Close the reader, freeing any resources that may have been allocated
* since the first call to read().
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/KeyedItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/KeyedItemReader.java
new file mode 100644
index 000000000..44441138c
--- /dev/null
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/KeyedItemReader.java
@@ -0,0 +1,36 @@
+/*
+ * 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.item;
+
+/**
+ * Extension of the {@link ItemReader} interface that allows items to be
+ * identified and tagged by a unique key.
+ *
+ * @author Dave Syer
+ *
+ */
+public interface KeyedItemReader extends ItemReader {
+
+ /**
+ * Get a unique identifier for the item that can be used to cache it between
+ * calls if necessary, and then identify it later.
+ *
+ * @param item the current item.
+ * @return a unique identifier.
+ */
+ Object getKey(Object item);
+
+}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/AbstractItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/AbstractItemReader.java
index 77f2d1a63..c9f33f7ca 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/AbstractItemReader.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/AbstractItemReader.java
@@ -24,18 +24,11 @@ import org.springframework.batch.item.ItemReader;
*
*/
public abstract class AbstractItemReader implements ItemReader {
-
- /**
- * Simply returns the item itself. Will be adequate for many purposes, but
- * not (for example) if the item is a message - in which case the identifier
- * should be used.
- *
- * @see org.springframework.batch.item.ItemReader#getKey(java.lang.Object)
- */
- public Object getKey(Object item) {
- return item;
- }
+ /**
+ * Do nothing.
+ * @see org.springframework.batch.item.ItemReader#close()
+ */
public void close() throws Exception {
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/ItemReaderAdapter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/ItemReaderAdapter.java
index abf0fad7a..f9ffcebcf 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/ItemReaderAdapter.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/ItemReaderAdapter.java
@@ -33,11 +33,11 @@ public class ItemReaderAdapter extends AbstractMethodInvokingDelegator implement
return invokeDelegateMethod();
}
- //harmless implementation of method required by ItemReader interface
- public Object getKey(Object item) {
- return item;
- }
-
+ /**
+ * Do nothing.
+ *
+ * @see org.springframework.batch.item.ItemReader#close()
+ */
public void close() throws Exception {
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/JmsItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/JmsItemReader.java
index f31f037dd..85a2c90e1 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/JmsItemReader.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/reader/JmsItemReader.java
@@ -24,6 +24,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.FailedItemIdentifier;
import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.KeyedItemReader;
import org.springframework.batch.item.exception.UnexpectedInputException;
import org.springframework.jms.JmsException;
import org.springframework.jms.core.JmsOperations;
@@ -39,7 +40,7 @@ import org.springframework.util.Assert;
* @author Dave Syer
*
*/
-public class JmsItemReader extends AbstractItemReader implements FailedItemIdentifier {
+public class JmsItemReader extends AbstractItemReader implements KeyedItemReader, FailedItemIdentifier {
protected Log logger = LogFactory.getLog(getClass());
@@ -151,7 +152,7 @@ public class JmsItemReader extends AbstractItemReader implements FailedItemIdent
throw new UnexpectedInputException("Could not extract message ID", e);
}
}
- return super.getKey(item);
+ return item;
}
/**
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/callback/ItemReaderRetryCallback.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/callback/ItemReaderRetryCallback.java
index 97ce24ac1..c784c3119 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/callback/ItemReaderRetryCallback.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/callback/ItemReaderRetryCallback.java
@@ -21,6 +21,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemRecoverer;
import org.springframework.batch.item.ItemWriter;
+import org.springframework.batch.item.KeyedItemReader;
import org.springframework.batch.retry.RetryCallback;
import org.springframework.batch.retry.RetryContext;
import org.springframework.batch.retry.RetryPolicy;
@@ -47,13 +48,13 @@ public class ItemReaderRetryCallback implements RetryCallback {
public static final String ITEM = ItemReaderRetryCallback.class.getName()
+ ".ITEM";
- private ItemReader provider;
+ private KeyedItemReader provider;
private ItemWriter writer;
private ItemRecoverer recoverer;
- public ItemReaderRetryCallback(ItemReader provider,
+ public ItemReaderRetryCallback(KeyedItemReader provider,
ItemWriter writer) {
super();
this.provider = provider;
@@ -127,7 +128,7 @@ public class ItemReaderRetryCallback implements RetryCallback {
*
* @return the {@link ItemReader} instance.
*/
- public ItemReader getReader() {
+ public KeyedItemReader getReader() {
return provider;
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/policy/ItemReaderRetryPolicy.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/policy/ItemReaderRetryPolicy.java
index 2c0a7cfb9..907791ea4 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/policy/ItemReaderRetryPolicy.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/policy/ItemReaderRetryPolicy.java
@@ -19,8 +19,8 @@ package org.springframework.batch.retry.policy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.FailedItemIdentifier;
-import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemRecoverer;
+import org.springframework.batch.item.KeyedItemReader;
import org.springframework.batch.repeat.synch.RepeatSynchronizationManager;
import org.springframework.batch.retry.RetryCallback;
import org.springframework.batch.retry.RetryContext;
@@ -109,7 +109,7 @@ public class ItemReaderRetryPolicy extends AbstractStatefulRetryPolicy {
public RetryContext open(RetryCallback callback) {
Assert.state(callback instanceof ItemReaderRetryCallback,
"Callback must be ItemProviderRetryCallback");
- ItemProviderRetryContext context = new ItemProviderRetryContext(
+ ItemReaderRetryContext context = new ItemReaderRetryContext(
(ItemReaderRetryCallback) callback);
context.open(callback);
return context;
@@ -137,7 +137,7 @@ public class ItemReaderRetryPolicy extends AbstractStatefulRetryPolicy {
return ((RetryPolicy) context).handleRetryExhausted(context);
}
- private class ItemProviderRetryContext extends RetryContextSupport
+ private class ItemReaderRetryContext extends RetryContextSupport
implements RetryPolicy {
private Object item;
@@ -145,11 +145,11 @@ public class ItemReaderRetryPolicy extends AbstractStatefulRetryPolicy {
// The delegate context...
private RetryContext delegateContext;
- private ItemReader reader;
+ private KeyedItemReader reader;
private ItemRecoverer recoverer;
- public ItemProviderRetryContext(ItemReaderRetryCallback callback) {
+ public ItemReaderRetryContext(ItemReaderRetryCallback callback) {
super(RetrySynchronizationManager.getContext());
item = callback.next(this);
this.reader = callback.getReader();
@@ -239,7 +239,7 @@ public class ItemReaderRetryPolicy extends AbstractStatefulRetryPolicy {
* @param item
* @return
*/
- protected boolean hasFailed(ItemReader provider, Object item) {
+ protected boolean hasFailed(KeyedItemReader provider, Object item) {
if (provider instanceof FailedItemIdentifier) {
return ((FailedItemIdentifier) provider).hasFailed(item);
}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/reader/DelegatingItemReaderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/reader/DelegatingItemReaderIntegrationTests.java
index b0a8563f4..d5ce02528 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/reader/DelegatingItemReaderIntegrationTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/reader/DelegatingItemReaderIntegrationTests.java
@@ -41,14 +41,6 @@ public class DelegatingItemReaderIntegrationTests extends AbstractDependencyInje
}
}
- /**
- * getKey(..) is implemented trivially.
- */
- public void testGetKey() {
- Object item = new Object();
- assertSame(item, provider.getKey(item));
- }
-
public void setProvider(ItemReaderAdapter provider) {
this.provider = provider;
}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/ListItemReaderRecoverer.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/ListItemReaderRecoverer.java
index 89ec8b16c..f41bc01bc 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/ListItemReaderRecoverer.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/ListItemReaderRecoverer.java
@@ -18,11 +18,11 @@ package org.springframework.batch.retry;
import java.util.List;
-import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemRecoverer;
+import org.springframework.batch.item.KeyedItemReader;
import org.springframework.batch.item.reader.ListItemReader;
-public class ListItemReaderRecoverer extends ListItemReader implements ItemReader, ItemRecoverer {
+public class ListItemReaderRecoverer extends ListItemReader implements KeyedItemReader, ItemRecoverer {
/**
* Delegate to super class constructor.
@@ -43,5 +43,14 @@ public class ListItemReaderRecoverer extends ListItemReader implements ItemReade
public boolean recover(Object item, Throwable cause) {
return false;
}
+
+ /**
+ * Return the item (assume it is its own key).
+ *
+ * @see org.springframework.batch.item.KeyedItemReader#getKey(java.lang.Object)
+ */
+ public Object getKey(Object item) {
+ return item;
+ }
}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/callback/ItemReaderRetryCallbackTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/callback/ItemReaderRetryCallbackTests.java
index f95a15ad9..f8a567228 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/callback/ItemReaderRetryCallbackTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/callback/ItemReaderRetryCallbackTests.java
@@ -22,7 +22,6 @@ import java.util.List;
import junit.framework.TestCase;
-import org.springframework.batch.item.reader.ListItemReader;
import org.springframework.batch.item.writer.AbstractItemWriter;
import org.springframework.batch.retry.ListItemReaderRecoverer;
import org.springframework.batch.retry.RetryContext;
@@ -40,7 +39,7 @@ public class ItemReaderRetryCallbackTests extends TestCase {
RetryTemplate template;
- ListItemReader provider;
+ ListItemReaderRecoverer provider;
ItemReaderRetryCallback callback;
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/ItemReaderRetryPolicyTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/ItemReaderRetryPolicyTests.java
index 7bec2480d..9a9354cb9 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/ItemReaderRetryPolicyTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/ItemReaderRetryPolicyTests.java
@@ -24,7 +24,7 @@ import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.item.FailedItemIdentifier;
-import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.KeyedItemReader;
import org.springframework.batch.item.reader.ListItemReader;
import org.springframework.batch.item.writer.AbstractItemWriter;
import org.springframework.batch.repeat.RepeatContext;
@@ -41,7 +41,7 @@ public class ItemReaderRetryPolicyTests extends TestCase {
private ItemReaderRetryPolicy policy = new ItemReaderRetryPolicy();
- private ItemReader provider;
+ private org.springframework.batch.item.KeyedItemReader provider;
private int count = 0;
@@ -299,7 +299,7 @@ public class ItemReaderRetryPolicyTests extends TestCase {
assertTrue(policy.hasFailed(provider, "foo"));
}
- private static class MockFailedItemProvider extends ListItemReader implements FailedItemIdentifier {
+ private static class MockFailedItemProvider extends ListItemReader implements KeyedItemReader, FailedItemIdentifier {
private int hasFailedCount = 0;
diff --git a/spring-batch-integration/src/test/java/org/springframework/batch/item/AbstractItemReaderRecoverer.java b/spring-batch-integration/src/test/java/org/springframework/batch/item/AbstractItemReaderRecoverer.java
index 55d7dcd51..c93c1daf1 100644
--- a/spring-batch-integration/src/test/java/org/springframework/batch/item/AbstractItemReaderRecoverer.java
+++ b/spring-batch-integration/src/test/java/org/springframework/batch/item/AbstractItemReaderRecoverer.java
@@ -21,5 +21,8 @@ import org.springframework.batch.item.reader.AbstractItemReader;
* @author Dave Syer
*
*/
-public abstract class AbstractItemReaderRecoverer extends AbstractItemReader implements ItemRecoverer {
+public abstract class AbstractItemReaderRecoverer extends AbstractItemReader implements KeyedItemReader, ItemRecoverer {
+ public Object getKey(Object item) {
+ return item;
+ }
}
diff --git a/spring-batch-integration/src/test/java/org/springframework/batch/jms/ExternalRetryInBatchTests.java b/spring-batch-integration/src/test/java/org/springframework/batch/jms/ExternalRetryInBatchTests.java
index e133d81f1..df009abda 100644
--- a/spring-batch-integration/src/test/java/org/springframework/batch/jms/ExternalRetryInBatchTests.java
+++ b/spring-batch-integration/src/test/java/org/springframework/batch/jms/ExternalRetryInBatchTests.java
@@ -22,7 +22,7 @@ import java.util.List;
import javax.sql.DataSource;
import org.springframework.batch.item.AbstractItemReaderRecoverer;
-import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.KeyedItemReader;
import org.springframework.batch.item.writer.AbstractItemWriter;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.batch.repeat.RepeatCallback;
@@ -48,7 +48,7 @@ public class ExternalRetryInBatchTests extends AbstractDependencyInjectionSpring
private RepeatTemplate repeatTemplate;
- private ItemReader provider;
+ private KeyedItemReader provider;
private JdbcTemplate jdbcTemplate;
diff --git a/spring-batch-integration/src/test/java/org/springframework/batch/retry/jms/ExternalRetryTests.java b/spring-batch-integration/src/test/java/org/springframework/batch/retry/jms/ExternalRetryTests.java
index 99ae1bd36..e73259468 100644
--- a/spring-batch-integration/src/test/java/org/springframework/batch/retry/jms/ExternalRetryTests.java
+++ b/spring-batch-integration/src/test/java/org/springframework/batch/retry/jms/ExternalRetryTests.java
@@ -22,7 +22,7 @@ import java.util.List;
import javax.sql.DataSource;
import org.springframework.batch.item.AbstractItemReaderRecoverer;
-import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.KeyedItemReader;
import org.springframework.batch.item.writer.AbstractItemWriter;
import org.springframework.batch.retry.callback.ItemReaderRetryCallback;
import org.springframework.batch.retry.policy.ItemReaderRetryPolicy;
@@ -41,7 +41,7 @@ public class ExternalRetryTests extends AbstractDependencyInjectionSpringContext
private RetryTemplate retryTemplate;
- private ItemReader provider;
+ private KeyedItemReader provider;
private JdbcTemplate jdbcTemplate;
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/reader/StagingItemReader.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/reader/StagingItemReader.java
index 9a35e53ba..f58cca01c 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/reader/StagingItemReader.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/reader/StagingItemReader.java
@@ -11,7 +11,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.execution.scope.StepContext;
import org.springframework.batch.execution.scope.StepContextAware;
-import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.KeyedItemReader;
import org.springframework.batch.item.ResourceLifecycle;
import org.springframework.batch.repeat.synch.BatchTransactionSynchronizationManager;
import org.springframework.batch.sample.item.writer.StagingItemWriter;
@@ -26,7 +26,7 @@ import org.springframework.transaction.support.TransactionSynchronizationAdapter
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
-public class StagingItemReader extends JdbcDaoSupport implements ItemReader, ResourceLifecycle, DisposableBean,
+public class StagingItemReader extends JdbcDaoSupport implements KeyedItemReader, ResourceLifecycle, DisposableBean,
StepContextAware {
// Key for buffer in transaction synchronization manager