diff --git a/spring-batch-core/.classpath b/spring-batch-core/.classpath
index 6165ff76e..b6d9ce7c7 100644
--- a/spring-batch-core/.classpath
+++ b/spring-batch-core/.classpath
@@ -1,10 +1,10 @@
-
+
-
-
+
+
-
+
diff --git a/spring-batch-core/.project b/spring-batch-core/.project
index aee145583..0dfc18b4e 100644
--- a/spring-batch-core/.project
+++ b/spring-batch-core/.project
@@ -1,30 +1,30 @@
-
-
- spring-batch-core
- Core domain for batch processing, expressing a domain of Jobs, Steps, Chunks, etc.
-
- spring-batch-infrastructure
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- org.springframework.ide.eclipse.core.springbuilder
-
-
-
-
- org.devzuz.q.maven.jdt.core.mavenIncrementalBuilder
-
-
-
-
-
- org.springframework.ide.eclipse.core.springnature
- org.eclipse.jdt.core.javanature
- org.devzuz.q.maven.jdt.core.mavenNature
-
-
+
+
+ spring-batch-core
+ Core domain for batch processing, expressing a domain of Jobs, Steps, Chunks, etc.
+
+ spring-batch-infrastructure
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.springframework.ide.eclipse.core.springbuilder
+
+
+
+
+ org.devzuz.q.maven.jdt.core.mavenIncrementalBuilder
+
+
+
+
+
+ org.springframework.ide.eclipse.core.springnature
+ org.eclipse.jdt.core.javanature
+ org.devzuz.q.maven.jdt.core.mavenNature
+
+
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobListener.java b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobListener.java
index 2fc58c5e5..e770a568a 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobListener.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/domain/JobListener.java
@@ -15,8 +15,12 @@
*/
package org.springframework.batch.core.domain;
-
/**
+ * Provide callbacks at specific points in the lifecycle of a {@link Job}.
+ * Implementations can be stateful if they are careful to either ensure thread
+ * safety, or to use one instance of a listener per job, assuming that job
+ * instances themselves are not used by more than one thread.
+ *
* @author Dave Syer
*
*/
@@ -30,7 +34,7 @@ public interface JobListener {
void beforeJob(JobExecution jobExecution);
/**
- *
+ * Callback after successful completion of a job.
*/
void afterJob();
}
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/AbstractStepFactoryBean.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/AbstractStepFactoryBean.java
index b602f3fe4..794c72042 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/AbstractStepFactoryBean.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/AbstractStepFactoryBean.java
@@ -21,7 +21,7 @@ import org.springframework.batch.execution.step.ItemOrientedStep;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.BeanNameAware;
-import org.springframework.beans.factory.config.AbstractFactoryBean;
+import org.springframework.beans.factory.FactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.Assert;
@@ -33,7 +33,7 @@ import org.springframework.util.Assert;
* @author Dave Syer
*
*/
-public abstract class AbstractStepFactoryBean extends AbstractFactoryBean implements BeanNameAware {
+public abstract class AbstractStepFactoryBean implements FactoryBean, BeanNameAware {
private String name;
@@ -49,6 +49,8 @@ public abstract class AbstractStepFactoryBean extends AbstractFactoryBean implem
private JobRepository jobRepository;
+ private boolean singleton = true;
+
/**
*
*/
@@ -140,7 +142,12 @@ public abstract class AbstractStepFactoryBean extends AbstractFactoryBean implem
this.transactionManager = transactionManager;
}
- protected Object createInstance() throws Exception {
+ /**
+ * Create a {@link Step} from the configuration provided.
+ *
+ * @see org.springframework.beans.factory.FactoryBean#getObject()
+ */
+ public final Object getObject() throws Exception {
ItemOrientedStep step = new ItemOrientedStep(getName());
applyConfiguration(step);
return step;
@@ -156,7 +163,7 @@ public abstract class AbstractStepFactoryBean extends AbstractFactoryBean implem
Assert.notNull(getItemWriter(), "ItemWriter must be provided");
Assert.notNull(jobRepository, "JobRepository must be provided");
Assert.notNull(transactionManager, "TransactionManager must be provided");
-
+
step.setItemProcessor(new SimpleItemHandler(itemReader, itemWriter));
step.setTransactionManager(transactionManager);
step.setJobRepository(jobRepository);
@@ -169,4 +176,23 @@ public abstract class AbstractStepFactoryBean extends AbstractFactoryBean implem
return Step.class;
}
+ /**
+ * Returns true by default, but in most cases a {@link Step} should not be
+ * treated as thread safe. Clients are recommended to create a new step for
+ * each job execution.
+ *
+ * @see org.springframework.beans.factory.FactoryBean#isSingleton()
+ */
+ public boolean isSingleton() {
+ return this.singleton;
+ }
+
+ /**
+ * Public setter for the singleton flag.
+ * @param singleton the value to set. Defaults to true.
+ */
+ public void setSingleton(boolean singleton) {
+ this.singleton = singleton;
+ }
+
}
\ No newline at end of file
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/StatefulRetryStepFactoryBean.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/StatefulRetryStepFactoryBean.java
index 44144e973..149eff84b 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/StatefulRetryStepFactoryBean.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/StatefulRetryStepFactoryBean.java
@@ -39,9 +39,6 @@ import org.springframework.batch.retry.support.RetryTemplate;
* limit given by the {@link RetryPolicy}. When the retry is exhausted instead
* of the item being skipped it is handled by an {@link ItemRecoverer}.
*
- * TODO: checking for null retry callback is a sucky way of determining if a
- * stateful retry has been requested.
- *
* @author Dave Syer
*
*/
@@ -51,6 +48,8 @@ public class StatefulRetryStepFactoryBean extends DefaultStepFactoryBean {
private ItemKeyGenerator itemKeyGenerator;
+ private ItemRecoverer itemRecoverer;
+
/**
* Public setter for the {@link RetryPolicy}.
* @param retryPolicy the {@link RetryPolicy} to set
@@ -73,6 +72,18 @@ public class StatefulRetryStepFactoryBean extends DefaultStepFactoryBean {
this.itemKeyGenerator = itemKeyGenerator;
}
+ /**
+ * Public setter for the {@link ItemRecoverer}. If this is set the
+ * {@link ItemRecoverer#recover(Object, Throwable)} will be called when
+ * retry is exhausted, and within the business transaction (which will not
+ * roll back because of any other item-related errors).
+ *
+ * @param itemRecoverer the {@link ItemRecoverer} to set
+ */
+ public void setItemRecoverer(ItemRecoverer itemRecoverer) {
+ this.itemRecoverer = itemRecoverer;
+ }
+
/**
* @param step
*
@@ -87,36 +98,20 @@ public class StatefulRetryStepFactoryBean extends DefaultStepFactoryBean {
// exception handler limit, so this is a hack for now.
getStepOperations().setExceptionHandler(new SimpleLimitExceptionHandler(Integer.MAX_VALUE));
- ItemReaderRetryCallback retryCallback = new ItemReaderRetryCallback(getItemReader(), getKeyGenerator(),
+ ItemReaderRetryCallback retryCallback = new ItemReaderRetryCallback(getItemReader(), itemKeyGenerator,
getItemWriter());
+ retryCallback.setRecoverer(itemRecoverer);
ItemReaderRetryPolicy itemProviderRetryPolicy = new ItemReaderRetryPolicy(retryPolicy);
RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.setRetryPolicy(itemProviderRetryPolicy);
- StatefulRetryItemHandler itemProcessor = new StatefulRetryItemHandler(getItemReader(), getItemWriter(), retryTemplate, retryCallback);
-
+ StatefulRetryItemHandler itemProcessor = new StatefulRetryItemHandler(getItemReader(), getItemWriter(),
+ retryTemplate, retryCallback);
+
step.setItemProcessor(itemProcessor);
-
- }
- }
-
- /**
- * @return an {@link ItemKeyGenerator} or null if none is found.
- */
- private ItemKeyGenerator getKeyGenerator() {
-
- if (itemKeyGenerator != null) {
- return itemKeyGenerator;
}
- if (getItemReader() instanceof ItemKeyGenerator) {
- return (ItemKeyGenerator) getItemReader();
- }
- if (getItemWriter() instanceof ItemKeyGenerator) {
- return (ItemKeyGenerator) getItemWriter();
- }
- return null;
}
@@ -129,10 +124,11 @@ public class StatefulRetryStepFactoryBean extends DefaultStepFactoryBean {
/**
* @param itemReader
* @param itemWriter
- * @param retryCallback
- * @param retryTemplate
+ * @param retryCallback
+ * @param retryTemplate
*/
- public StatefulRetryItemHandler(ItemReader itemReader, ItemWriter itemWriter, RetryOperations retryTemplate, ItemReaderRetryCallback retryCallback) {
+ public StatefulRetryItemHandler(ItemReader itemReader, ItemWriter itemWriter, RetryOperations retryTemplate,
+ ItemReaderRetryCallback retryCallback) {
super(itemReader, itemWriter);
this.retryOperations = retryTemplate;
this.retryCallback = retryCallback;
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/repository/SimpleJobRepositoryTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/repository/SimpleJobRepositoryTests.java
index 18351e0db..47b649e9c 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/repository/SimpleJobRepositoryTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/repository/SimpleJobRepositoryTests.java
@@ -79,8 +79,6 @@ public class SimpleJobRepositoryTests extends TestCase {
ExecutionContext executionContext;
- private JobExecution jobExecution;
-
public void setUp() throws Exception {
jobExecutionDao = (JobExecutionDao) jobExecutionDaoControl.getMock();
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/ItemOrientedStepTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/ItemOrientedStepTests.java
index 13289df86..a0429a04d 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/ItemOrientedStepTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/ItemOrientedStepTests.java
@@ -393,7 +393,7 @@ public class ItemOrientedStepTests extends TestCase {
public void testAfterStep() throws Exception{
- final ExitStatus customStatus = new ExitStatus(true, "custom code");
+ final ExitStatus customStatus = new ExitStatus(false, "custom code");
itemOrientedStep.setStepListeners(new StepListener[] {new StepListenerSupport() {
public ExitStatus afterStep() {
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/DefaultStepFactoryBeanTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/DefaultStepFactoryBeanTests.java
index 903d7376a..6300d777a 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/DefaultStepFactoryBeanTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/DefaultStepFactoryBeanTests.java
@@ -26,7 +26,6 @@ import junit.framework.TestCase;
import org.springframework.batch.core.domain.BatchListener;
import org.springframework.batch.core.domain.BatchStatus;
import org.springframework.batch.core.domain.JobExecution;
-import org.springframework.batch.core.domain.JobInstance;
import org.springframework.batch.core.domain.JobParameters;
import org.springframework.batch.core.listener.ItemListenerSupport;
import org.springframework.batch.execution.job.SimpleJob;
@@ -36,7 +35,6 @@ import org.springframework.batch.execution.repository.dao.MapJobInstanceDao;
import org.springframework.batch.execution.repository.dao.MapStepExecutionDao;
import org.springframework.batch.execution.step.AbstractStep;
import org.springframework.batch.execution.step.ItemOrientedStep;
-import org.springframework.batch.execution.step.support.DefaultStepFactoryBean;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.reader.ListItemReader;
@@ -84,7 +82,6 @@ public class DefaultStepFactoryBeanTests extends TestCase {
private DefaultStepFactoryBean getStep(String[] args) throws Exception {
DefaultStepFactoryBean factory = new DefaultStepFactoryBean();
- factory.setSingleton(false);
List items = TransactionAwareProxyFactory.createTransactionalList();
items.addAll(Arrays.asList(args));
@@ -95,13 +92,6 @@ public class DefaultStepFactoryBeanTests extends TestCase {
factory.setJobRepository(repository);
factory.setTransactionManager(new ResourcelessTransactionManager());
factory.setBeanName("stepName");
- // step.setItemRecoverer(new ItemRecoverer() {
- // public boolean recover(Object item, Throwable cause) {
- // recovered.add(item);
- // assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
- // return true;
- // }
- // });
return factory;
}
@@ -115,12 +105,10 @@ public class DefaultStepFactoryBeanTests extends TestCase {
step.setName("step2");
job.addStep(step);
- JobInstance jobInstance = repository.createJobExecution(job, new JobParameters()).getJobInstance();
+ JobExecution jobExecution = repository.createJobExecution(job, new JobParameters());
- JobExecution jobExecutionContext = new JobExecution(jobInstance);
-
- job.execute(jobExecutionContext);
- assertEquals(BatchStatus.COMPLETED, jobExecutionContext.getStatus());
+ job.execute(jobExecution);
+ assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(3, processed.size());
assertTrue(processed.contains("foo"));
}
@@ -154,6 +142,7 @@ public class DefaultStepFactoryBeanTests extends TestCase {
public void onReadError(Exception ex) {
recovered.add(ex);
}
+
public void onWriteError(Exception ex, Object item) {
recovered.add(ex);
}
@@ -173,8 +162,6 @@ public class DefaultStepFactoryBeanTests extends TestCase {
assertEquals(null, provider.read());
assertEquals(3, recovered.size());
}
-
- // TODO: test recovery and stateful retry
public void testExceptionTerminates() throws Exception {
DefaultStepFactoryBean factory = getStep(new String[] { "foo", "bar", "spam" });
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/RepeatOperationsStepFactoryBeanTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/RepeatOperationsStepFactoryBeanTests.java
index 9b60306bf..b564740b4 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/RepeatOperationsStepFactoryBeanTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/RepeatOperationsStepFactoryBeanTests.java
@@ -44,7 +44,14 @@ public class RepeatOperationsStepFactoryBeanTests extends TestCase {
private List list;
private JobExecution jobExecution = new JobExecution(new JobInstance(new Long(0L), new JobParameters(),
- new JobSupport("job")));;
+ new JobSupport("job")));
+
+ protected void setUp() throws Exception {
+ factory.setItemReader(new ListItemReader(new ArrayList()));
+ factory.setItemWriter(new EmptyItemWriter());
+ factory.setJobRepository(new JobRepositorySupport());
+ factory.setTransactionManager(new ResourcelessTransactionManager());
+ }
public void testType() throws Exception {
assertEquals(Step.class, factory.getObjectType());
@@ -70,8 +77,6 @@ public class RepeatOperationsStepFactoryBeanTests extends TestCase {
}
});
- factory.setSingleton(false);
-
Step step = (Step) factory.getObject();
step.execute(new StepExecution(step, jobExecution));
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/StatefulRetryStepFactoryBeanTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/StatefulRetryStepFactoryBeanTests.java
index 917b457cd..7b20df886 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/StatefulRetryStepFactoryBeanTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/StatefulRetryStepFactoryBeanTests.java
@@ -15,24 +15,115 @@
*/
package org.springframework.batch.execution.step.support;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
import junit.framework.TestCase;
+import org.springframework.batch.core.domain.JobExecution;
+import org.springframework.batch.core.domain.JobParameters;
+import org.springframework.batch.core.domain.JobParametersBuilder;
import org.springframework.batch.core.domain.Step;
+import org.springframework.batch.core.domain.StepExecution;
+import org.springframework.batch.execution.job.JobSupport;
+import org.springframework.batch.execution.repository.SimpleJobRepository;
+import org.springframework.batch.execution.repository.dao.MapJobExecutionDao;
+import org.springframework.batch.execution.repository.dao.MapJobInstanceDao;
+import org.springframework.batch.execution.repository.dao.MapStepExecutionDao;
+import org.springframework.batch.execution.step.ItemOrientedStep;
+import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.ItemRecoverer;
+import org.springframework.batch.item.ItemWriter;
+import org.springframework.batch.item.reader.ListItemReader;
+import org.springframework.batch.item.writer.AbstractItemWriter;
+import org.springframework.batch.retry.policy.AlwaysRetryPolicy;
+import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
+import org.springframework.batch.support.transaction.TransactionAwareProxyFactory;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* @author Dave Syer
- *
+ *
*/
public class StatefulRetryStepFactoryBeanTests extends TestCase {
- private AbstractStepFactoryBean factory = new StatefulRetryStepFactoryBean();
-
+ private StatefulRetryStepFactoryBean factory = new StatefulRetryStepFactoryBean();
+
+ private List recovered = new ArrayList();
+
+ private List processed = new ArrayList();
+
+ private SimpleJobRepository repository = new SimpleJobRepository(new MapJobInstanceDao(), new MapJobExecutionDao(),
+ new MapStepExecutionDao());
+
+ JobExecution jobExecution;
+
+ private ItemWriter processor = new AbstractItemWriter() {
+ public void write(Object data) throws Exception {
+ processed.add((String) data);
+ }
+ };
+
+ /*
+ * (non-Javadoc)
+ * @see junit.framework.TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+
+ MapJobInstanceDao.clear();
+ MapJobExecutionDao.clear();
+ MapStepExecutionDao.clear();
+
+ factory.setBeanName("step");
+
+ factory.setItemReader(new ListItemReader(new ArrayList()));
+ factory.setItemWriter(processor);
+ factory.setJobRepository(repository);
+ factory.setTransactionManager(new ResourcelessTransactionManager());
+
+ JobSupport job = new JobSupport("jobName");
+ job.setRestartable(true);
+ JobParameters jobParameters = new JobParametersBuilder().addString("statefulTest", "make_this_unique").toJobParameters();
+ jobExecution = repository.createJobExecution(job, jobParameters);
+ jobExecution.setEndTime(new Date());
+
+ }
+
public void testType() throws Exception {
assertEquals(Step.class, factory.getObjectType());
}
-
+
public void testDefaultValue() throws Exception {
assertTrue(factory.getObject() instanceof Step);
}
+ public void testRecovery() throws Exception {
+ factory.setItemRecoverer(new ItemRecoverer() {
+ public boolean recover(Object item, Throwable cause) {
+ recovered.add(item);
+ assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
+ return true;
+ }
+ });
+ List items = TransactionAwareProxyFactory.createTransactionalList();
+ items.addAll(Arrays.asList(new String[] { "a", "b", "c" }));
+ ItemReader provider = new ListItemReader(items) {
+ int count = 0;
+ public Object read() {
+ count++;
+ if (count == 2) {
+ throw new RuntimeException("Temporary error - retry for success.");
+ }
+ return super.read();
+ }
+ };
+ factory.setItemReader(provider);
+ factory.setRetryPolicy(new AlwaysRetryPolicy());
+ ItemOrientedStep step = (ItemOrientedStep) factory.getObject();
+
+ step.execute(new StepExecution(step, jobExecution));
+ }
+
}
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/StepExecutorInterruptionTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/StepExecutorInterruptionTests.java
index 877771d93..9d5c58895 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/StepExecutorInterruptionTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/support/StepExecutorInterruptionTests.java
@@ -26,12 +26,9 @@ import org.springframework.batch.core.domain.StepExecution;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.execution.job.JobSupport;
import org.springframework.batch.execution.repository.SimpleJobRepository;
-import org.springframework.batch.execution.repository.dao.JobExecutionDao;
-import org.springframework.batch.execution.repository.dao.JobInstanceDao;
import org.springframework.batch.execution.repository.dao.MapJobExecutionDao;
import org.springframework.batch.execution.repository.dao.MapJobInstanceDao;
import org.springframework.batch.execution.repository.dao.MapStepExecutionDao;
-import org.springframework.batch.execution.repository.dao.StepExecutionDao;
import org.springframework.batch.execution.step.ItemOrientedStep;
import org.springframework.batch.item.reader.AbstractItemReader;
import org.springframework.batch.item.reader.ItemReaderAdapter;
@@ -42,14 +39,6 @@ import org.springframework.batch.support.transaction.ResourcelessTransactionMana
public class StepExecutorInterruptionTests extends TestCase {
- private JobRepository jobRepository;
-
- private JobInstanceDao jobInstanceDao = new MapJobInstanceDao();
-
- private JobExecutionDao jobExecutionDao = new MapJobExecutionDao();
-
- private StepExecutionDao stepExecutionDao = new MapStepExecutionDao();
-
private ItemOrientedStep step;
private JobExecution jobExecution;
@@ -61,7 +50,7 @@ public class StepExecutorInterruptionTests extends TestCase {
MapJobExecutionDao.clear();
MapStepExecutionDao.clear();
- jobRepository = new SimpleJobRepository(jobInstanceDao, jobExecutionDao, stepExecutionDao);
+ JobRepository jobRepository = new SimpleJobRepository(new MapJobInstanceDao(), new MapJobExecutionDao(), new MapStepExecutionDao());
JobSupport jobConfiguration = new JobSupport();
step = new ItemOrientedStep("interruptedStep");
diff --git a/spring-batch-infrastructure/.classpath b/spring-batch-infrastructure/.classpath
index bf5d1cf16..317ed9707 100644
--- a/spring-batch-infrastructure/.classpath
+++ b/spring-batch-infrastructure/.classpath
@@ -1,8 +1,8 @@
-
-
+
+
diff --git a/spring-batch-infrastructure/.settings/org.eclipse.jdt.core.prefs b/spring-batch-infrastructure/.settings/org.eclipse.jdt.core.prefs
index d60e8dcbb..2021b6bf0 100644
--- a/spring-batch-infrastructure/.settings/org.eclipse.jdt.core.prefs
+++ b/spring-batch-infrastructure/.settings/org.eclipse.jdt.core.prefs
@@ -1,8 +1,6 @@
-#Fri Feb 29 13:52:09 GMT 2008
+#Tue Mar 04 12:26:32 GMT 2008
eclipse.preferences.version=1
instance/org.eclipse.core.net/org.eclipse.core.net.hasMigrated=true
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.4
org.eclipse.jdt.core.compiler.compliance=1.4
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
-org.eclipse.jdt.core.compiler.source=1.4
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/ExitStatus.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/ExitStatus.java
index 2e85062bb..a88f8c4b0 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/ExitStatus.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/repeat/ExitStatus.java
@@ -49,7 +49,7 @@ public class ExitStatus implements Serializable {
* Convenient constant value representing finished processing.
*/
public static final ExitStatus FINISHED = new ExitStatus(false, "COMPLETED");
-
+
/**
* Convenient constant value representing interrupted processing.
*/
@@ -131,8 +131,11 @@ public class ExitStatus implements Serializable {
/**
* Create a new {@link ExitStatus} with a logical combination of the
- * continuable flag, and a concatenation of the codes. If the input is null
- * we just return this.
+ * continuable flag, and a concatenation of the descriptions. The exit code
+ * is only replaced if the result is continuable or the input is not
+ * continuable.
+ *
+ * If the input is null just return this.
*
* @param status an {@link ExitStatus} to combine with this one.
* @return a new {@link ExitStatus} with {@link #isContinuable()} the
@@ -142,7 +145,11 @@ public class ExitStatus implements Serializable {
if (status == null) {
return this;
}
- return and(status.continuable).replaceExitCode(status.exitCode).addExitDescription(status.exitDescription);
+ ExitStatus result = and(status.continuable).addExitDescription(status.exitDescription);
+ if (result.continuable || !status.continuable) {
+ result = result.replaceExitCode(status.exitCode);
+ }
+ return result;
}
/*
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/repeat/ExitStatusTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/repeat/ExitStatusTests.java
index e46a12a83..21ccc969f 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/repeat/ExitStatusTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/repeat/ExitStatusTests.java
@@ -21,12 +21,13 @@ import junit.framework.TestCase;
/**
* @author Dave Syer
- *
+ *
*/
public class ExitStatusTests extends TestCase {
/**
- * Test method for {@link org.springframework.batch.repeat.ExitStatus#ExitStatus(boolean, int)}.
+ * Test method for
+ * {@link org.springframework.batch.repeat.ExitStatus#ExitStatus(boolean, int)}.
*/
public void testExitStatusBooleanInt() {
ExitStatus status = new ExitStatus(true, "10");
@@ -35,7 +36,8 @@ public class ExitStatusTests extends TestCase {
}
/**
- * Test method for {@link org.springframework.batch.repeat.ExitStatus#ExitStatus(boolean, int)}.
+ * Test method for
+ * {@link org.springframework.batch.repeat.ExitStatus#ExitStatus(boolean, int)}.
*/
public void testExitStatusConstantsContinuable() {
ExitStatus status = ExitStatus.CONTINUABLE;
@@ -44,14 +46,15 @@ public class ExitStatusTests extends TestCase {
}
/**
- * Test method for {@link org.springframework.batch.repeat.ExitStatus#ExitStatus(boolean, int)}.
+ * Test method for
+ * {@link org.springframework.batch.repeat.ExitStatus#ExitStatus(boolean, int)}.
*/
public void testExitStatusConstantsFinished() {
ExitStatus status = ExitStatus.FINISHED;
assertFalse(status.isContinuable());
assertEquals("COMPLETED", status.getExitCode());
}
-
+
/**
* Test equality of exit statuses.
*
@@ -60,13 +63,13 @@ public class ExitStatusTests extends TestCase {
public void testEqualsWithSameProperties() throws Exception {
assertEquals(ExitStatus.CONTINUABLE, new ExitStatus(true, "CONTINUABLE"));
}
-
- public void testEqualsSelf(){
+
+ public void testEqualsSelf() {
ExitStatus status = new ExitStatus(true, "test");
assertEquals(status, status);
}
-
- public void testEquals(){
+
+ public void testEquals() {
assertEquals(new ExitStatus(true, "test"), new ExitStatus(true, "test"));
}
@@ -89,57 +92,93 @@ public class ExitStatusTests extends TestCase {
}
/**
- * Test method for {@link org.springframework.batch.repeat.ExitStatus#and(boolean)}.
+ * Test method for
+ * {@link org.springframework.batch.repeat.ExitStatus#and(boolean)}.
*/
public void testAndBoolean() {
assertTrue(ExitStatus.CONTINUABLE.and(true).isContinuable());
assertFalse(ExitStatus.CONTINUABLE.and(false).isContinuable());
- }
-
- /**
- * Test method for {@link org.springframework.batch.repeat.ExitStatus#and(org.springframework.batch.repeat.ExitStatus)}.
- */
- public void testAndExitStatus() {
- assertTrue(ExitStatus.CONTINUABLE.and(ExitStatus.CONTINUABLE.isContinuable()).isContinuable());
- assertFalse(ExitStatus.CONTINUABLE.and(ExitStatus.FINISHED.isContinuable()).isContinuable());
- assertTrue(ExitStatus.FINISHED.and(ExitStatus.CONTINUABLE.isContinuable()).getExitCode()
- == ExitStatus.FINISHED.getExitCode());
ExitStatus status = new ExitStatus(false, "CUSTOM_CODE", "CUSTOM_DESCRIPTION");
assertTrue(status.and(true).getExitCode() == "CUSTOM_CODE");
assertTrue(status.and(true).getExitDescription() == "CUSTOM_DESCRIPTION");
}
+ /**
+ * Test method for
+ * {@link org.springframework.batch.repeat.ExitStatus#and(org.springframework.batch.repeat.ExitStatus)}.
+ */
+ public void testAndExitStatusStillContinuable() {
+ assertTrue(ExitStatus.CONTINUABLE.and(ExitStatus.CONTINUABLE).isContinuable());
+ assertFalse(ExitStatus.CONTINUABLE.and(ExitStatus.FINISHED).isContinuable());
+ assertTrue(ExitStatus.CONTINUABLE.and(ExitStatus.CONTINUABLE).getExitCode() == ExitStatus.CONTINUABLE
+ .getExitCode());
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.repeat.ExitStatus#and(org.springframework.batch.repeat.ExitStatus)}.
+ */
+ public void testAndExitStatusWhenFinishedAddedToContinuable() {
+ assertEquals(ExitStatus.FINISHED.getExitCode(), ExitStatus.CONTINUABLE.and(ExitStatus.FINISHED).getExitCode());
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.repeat.ExitStatus#and(org.springframework.batch.repeat.ExitStatus)}.
+ */
+ public void testAndExitStatusWhenContinuableAddedToFinished() {
+ assertEquals(ExitStatus.FINISHED.getExitCode(), ExitStatus.FINISHED.and(ExitStatus.CONTINUABLE).getExitCode());
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.repeat.ExitStatus#and(org.springframework.batch.repeat.ExitStatus)}.
+ */
+ public void testAndExitStatusWhenCustomContinuableAddedToContinuable() {
+ assertEquals("CUSTOM", ExitStatus.CONTINUABLE.and(ExitStatus.CONTINUABLE.replaceExitCode("CUSTOM"))
+ .getExitCode());
+ }
+
+ /**
+ * Test method for
+ * {@link org.springframework.batch.repeat.ExitStatus#and(org.springframework.batch.repeat.ExitStatus)}.
+ */
+ public void testAndExitStatusWhenCustomContinuableAddedToFinished() {
+ assertEquals(ExitStatus.FINISHED.getExitCode(), ExitStatus.FINISHED.and(ExitStatus.CONTINUABLE.replaceExitCode("CUSTOM"))
+ .getExitCode());
+ }
+
public void testAddExitCode() throws Exception {
ExitStatus status = ExitStatus.CONTINUABLE.replaceExitCode("FOO");
- assertTrue(ExitStatus.CONTINUABLE!=status);
+ assertTrue(ExitStatus.CONTINUABLE != status);
assertTrue(status.isContinuable());
assertEquals("FOO", status.getExitCode());
}
public void testAddExitCodeToExistingStatus() throws Exception {
ExitStatus status = ExitStatus.CONTINUABLE.replaceExitCode("FOO").replaceExitCode("BAR");
- assertTrue(ExitStatus.CONTINUABLE!=status);
+ assertTrue(ExitStatus.CONTINUABLE != status);
assertTrue(status.isContinuable());
assertEquals("BAR", status.getExitCode());
}
public void testAddExitCodeToSameStatus() throws Exception {
ExitStatus status = ExitStatus.CONTINUABLE.replaceExitCode(ExitStatus.CONTINUABLE.getExitCode());
- assertTrue(ExitStatus.CONTINUABLE!=status);
+ assertTrue(ExitStatus.CONTINUABLE != status);
assertTrue(status.isContinuable());
assertEquals(ExitStatus.CONTINUABLE.getExitCode(), status.getExitCode());
}
public void testAddExitDescription() throws Exception {
ExitStatus status = ExitStatus.CONTINUABLE.addExitDescription("Foo");
- assertTrue(ExitStatus.CONTINUABLE!=status);
+ assertTrue(ExitStatus.CONTINUABLE != status);
assertTrue(status.isContinuable());
assertEquals("Foo", status.getExitDescription());
}
public void testAddExitDescriptionToSameStatus() throws Exception {
ExitStatus status = ExitStatus.CONTINUABLE.addExitDescription("Foo").addExitDescription("Foo");
- assertTrue(ExitStatus.CONTINUABLE!=status);
+ assertTrue(ExitStatus.CONTINUABLE != status);
assertTrue(status.isContinuable());
assertEquals("Foo", status.getExitDescription());
}
@@ -149,12 +188,12 @@ public class ExitStatusTests extends TestCase {
assertEquals("FOO", status.getExitCode());
assertEquals("Bar", status.getExitDescription());
}
-
+
public void testRunningIsRunning() throws Exception {
assertTrue(ExitStatus.RUNNING.isRunning());
assertTrue(new ExitStatus(true, "RUNNING").isRunning());
}
-
+
public void testUnkownIsRunning() throws Exception {
assertTrue(ExitStatus.UNKNOWN.isRunning());
}
diff --git a/spring-batch-integration/.classpath b/spring-batch-integration/.classpath
index 6ceeb8b67..b6d9ce7c7 100644
--- a/spring-batch-integration/.classpath
+++ b/spring-batch-integration/.classpath
@@ -1,10 +1,10 @@
-
+
-
+
-
+