Incomplete - task 84: Fix samples

Fix skip policy so it responds to subclasses
This commit is contained in:
dsyer
2008-02-26 14:29:27 +00:00
parent 2b32b8d38e
commit 42ba209b11
6 changed files with 1533 additions and 1567 deletions

View File

@@ -42,8 +42,6 @@ import org.springframework.util.Assert;
*/
public abstract class AbstractStep extends StepSupport implements InitializingBean {
private int skipLimit = 0;
protected ExceptionHandler exceptionHandler;
protected RetryPolicy retryPolicy;
@@ -102,14 +100,6 @@ public abstract class AbstractStep extends StepSupport implements InitializingBe
this.exceptionHandler = exceptionHandler;
}
public void setSkipLimit(int skipLimit) {
this.skipLimit = skipLimit;
}
public int getSkipLimit() {
return skipLimit;
}
/**
* Public setter for {@link JobRepository}.
*

View File

@@ -17,9 +17,15 @@ package org.springframework.batch.execution.step.support;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.springframework.batch.common.ExceptionClassifier;
import org.springframework.batch.common.SubclassExceptionClassifier;
import org.springframework.batch.core.domain.ItemSkipPolicy;
import org.springframework.batch.core.domain.Step;
import org.springframework.batch.core.domain.StepContribution;
import org.springframework.batch.core.domain.StepExecution;
import org.springframework.batch.io.exception.FlatFileParsingException;
@@ -44,9 +50,14 @@ import org.springframework.batch.io.exception.FlatFileParsingException;
*/
public class LimitCheckingItemSkipPolicy implements ItemSkipPolicy {
private final int skipLimit;
/**
* Label for classifying skippable exceptions.
*/
private static final String SKIP = "skip";
private final List skippableExceptions;
private final int skipLimit;
private ExceptionClassifier exceptionClassifier;
public LimitCheckingItemSkipPolicy(int skipLimit) {
this(skipLimit, new ArrayList(0));
@@ -54,7 +65,14 @@ public class LimitCheckingItemSkipPolicy implements ItemSkipPolicy {
public LimitCheckingItemSkipPolicy(int skipLimit, List skippableExceptions) {
this.skipLimit = skipLimit;
this.skippableExceptions = skippableExceptions;
SubclassExceptionClassifier exceptionClassifier = new SubclassExceptionClassifier();
Map typeMap = new HashMap();
for (Iterator iterator = skippableExceptions.iterator(); iterator.hasNext();) {
Class throwable = (Class) iterator.next();
typeMap.put(throwable, SKIP);
}
exceptionClassifier.setTypeMap(typeMap);
this.exceptionClassifier = exceptionClassifier;
}
/**
@@ -66,7 +84,7 @@ public class LimitCheckingItemSkipPolicy implements ItemSkipPolicy {
* will be thrown.
*/
public boolean shouldSkip(Exception ex, StepContribution stepContribution){
if(skippableExceptions.contains(ex.getClass())){
if(exceptionClassifier.classify(ex).equals(SKIP)){
if(stepContribution.getSkipCount() < skipLimit){
stepContribution.incrementSkipCount();
return true;

View File

@@ -1,193 +1,192 @@
/*
* 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.execution.launch;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.core.domain.BatchStatus;
import org.springframework.batch.core.domain.ItemFailureHandler;
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.execution.job.simple.SimpleJob;
import org.springframework.batch.execution.repository.SimpleJobRepository;
import org.springframework.batch.execution.repository.dao.MapJobDao;
import org.springframework.batch.execution.repository.dao.MapStepDao;
import org.springframework.batch.execution.step.AbstractStep;
import org.springframework.batch.execution.step.ItemOrientedStep;
import org.springframework.batch.execution.step.support.NeverSkipItemSkipPolicy;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.reader.ListItemReader;
import org.springframework.batch.item.writer.AbstractItemWriter;
import org.springframework.batch.repeat.RepeatContext;
import org.springframework.batch.repeat.exception.handler.ExceptionHandler;
import org.springframework.batch.repeat.support.RepeatTemplate;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.batch.support.transaction.TransactionAwareProxyFactory;
public class SimpleJobTests extends TestCase {
private List recovered = new ArrayList();
private SimpleJobRepository repository = new SimpleJobRepository(new MapJobDao(), new MapJobDao(), new MapStepDao());
private List processed = new ArrayList();
private ItemWriter processor = new AbstractItemWriter() {
public void write(Object data) throws Exception {
processed.add((String) data);
}
};
private ItemReader provider;
private SimpleJob job = new SimpleJob();;
protected void setUp() throws Exception {
super.setUp();
job.setJobRepository(repository);
}
private AbstractStep getStep(String arg) throws Exception {
return getStep(new String[] { arg });
}
private AbstractStep getStep(String arg0, String arg1) throws Exception {
return getStep(new String[] { arg0, arg1 });
}
private ItemOrientedStep getStep(String[] args) throws Exception {
ItemOrientedStep step = new ItemOrientedStep();
List items = TransactionAwareProxyFactory.createTransactionalList();
items.addAll(Arrays.asList(args));
provider = new ListItemReader(items);
// step.setItemRecoverer(new ItemRecoverer() {
// public boolean recover(Object item, Throwable cause) {
// recovered.add(item);
// assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
// return true;
// }
// });
step.setItemReader(provider);
step.setItemWriter(processor);
step.setJobRepository(repository);
step.setTransactionManager(new ResourcelessTransactionManager());
step.setName("stepName");
step.afterPropertiesSet();
return step;
}
public void testSimpleJob() throws Exception {
job.setSteps(new ArrayList());
AbstractStep step = getStep("foo", "bar");
job.addStep(step);
step = getStep("spam");
job.addStep(step);
JobInstance jobInstance = repository.createJobExecution(job, new JobParameters()).getJobInstance();
JobExecution jobExecutionContext = new JobExecution(jobInstance);
job.execute(jobExecutionContext);
assertEquals(BatchStatus.COMPLETED, jobExecutionContext.getStatus());
assertEquals(3, processed.size());
assertTrue(processed.contains("foo"));
}
public void testSimpleJobWithRecovery() throws Exception {
final List throwables = new ArrayList();
RepeatTemplate chunkOperations = new RepeatTemplate();
// Always handle the exception a check it is the right one...
chunkOperations.setExceptionHandler(new ExceptionHandler() {
public void handleException(RepeatContext context, Throwable throwable) throws RuntimeException {
throwables.add(throwable);
assertEquals("Error!", throwable.getMessage());
}
});
/*
* Each message fails once and the chunk (size=1) "rolls back"; then it
* is recovered ("skipped") on the second attempt (see retry policy
* definition above)...
*/
ItemOrientedStep step = getStep(new String[] { "foo", "bar", "spam" });
// Tasklet module = getTasklet(new String[] { "foo", "bar", "spam" });
// RepeatOperationsStep step = new RepeatOperationsStep();
step.setChunkOperations(chunkOperations);
step.setItemWriter(new AbstractItemWriter() {
public void write(Object data) throws Exception {
throw new RuntimeException("Error!");
}
});
step.setItemFailureHandler(new ItemFailureHandler(){
public void handleReadFailure(Exception ex) {
recovered.add(ex);
}
public void handleWriteFailure(Object item, Exception ex) {
recovered.add(ex);
}
});
step.afterPropertiesSet();
job.setSteps(Collections.singletonList(step));
JobExecution jobExecution = repository.createJobExecution(job, new JobParameters());
job.execute(jobExecution);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(0, processed.size());
// provider should be exhausted
assertEquals(null, provider.read());
assertEquals(3, recovered.size());
}
public void testExceptionTerminates() throws Exception {
// Tasklet module = getTasklet(new String[] { "foo", "bar", "spam" });
AbstractStep step = getStep(new String[] { "foo", "bar", "spam" });
step.setItemWriter(new AbstractItemWriter() {
public void write(Object data) throws Exception {
throw new RuntimeException("Foo");
}
});
step.afterPropertiesSet();
job.setSteps(Collections.singletonList(step));
JobExecution jobExecution = repository.createJobExecution(job, new JobParameters());
try {
job.execute(jobExecution);
fail("Expected RuntimeException");
}
catch (RuntimeException e) {
assertEquals("Foo", e.getMessage());
// expected
}
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
}
}
/*
* 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.execution.launch;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import junit.framework.TestCase;
import org.springframework.batch.core.domain.BatchStatus;
import org.springframework.batch.core.domain.ItemFailureHandler;
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.execution.job.simple.SimpleJob;
import org.springframework.batch.execution.repository.SimpleJobRepository;
import org.springframework.batch.execution.repository.dao.MapJobDao;
import org.springframework.batch.execution.repository.dao.MapStepDao;
import org.springframework.batch.execution.step.AbstractStep;
import org.springframework.batch.execution.step.ItemOrientedStep;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.reader.ListItemReader;
import org.springframework.batch.item.writer.AbstractItemWriter;
import org.springframework.batch.repeat.RepeatContext;
import org.springframework.batch.repeat.exception.handler.ExceptionHandler;
import org.springframework.batch.repeat.support.RepeatTemplate;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.batch.support.transaction.TransactionAwareProxyFactory;
public class SimpleJobTests extends TestCase {
private List recovered = new ArrayList();
private SimpleJobRepository repository = new SimpleJobRepository(new MapJobDao(), new MapJobDao(), new MapStepDao());
private List processed = new ArrayList();
private ItemWriter processor = new AbstractItemWriter() {
public void write(Object data) throws Exception {
processed.add((String) data);
}
};
private ItemReader provider;
private SimpleJob job = new SimpleJob();;
protected void setUp() throws Exception {
super.setUp();
job.setJobRepository(repository);
}
private AbstractStep getStep(String arg) throws Exception {
return getStep(new String[] { arg });
}
private AbstractStep getStep(String arg0, String arg1) throws Exception {
return getStep(new String[] { arg0, arg1 });
}
private ItemOrientedStep getStep(String[] args) throws Exception {
ItemOrientedStep step = new ItemOrientedStep();
List items = TransactionAwareProxyFactory.createTransactionalList();
items.addAll(Arrays.asList(args));
provider = new ListItemReader(items);
// step.setItemRecoverer(new ItemRecoverer() {
// public boolean recover(Object item, Throwable cause) {
// recovered.add(item);
// assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
// return true;
// }
// });
step.setItemReader(provider);
step.setItemWriter(processor);
step.setJobRepository(repository);
step.setTransactionManager(new ResourcelessTransactionManager());
step.setName("stepName");
step.afterPropertiesSet();
return step;
}
public void testSimpleJob() throws Exception {
job.setSteps(new ArrayList());
AbstractStep step = getStep("foo", "bar");
job.addStep(step);
step = getStep("spam");
job.addStep(step);
JobInstance jobInstance = repository.createJobExecution(job, new JobParameters()).getJobInstance();
JobExecution jobExecutionContext = new JobExecution(jobInstance);
job.execute(jobExecutionContext);
assertEquals(BatchStatus.COMPLETED, jobExecutionContext.getStatus());
assertEquals(3, processed.size());
assertTrue(processed.contains("foo"));
}
public void testSimpleJobWithRecovery() throws Exception {
final List throwables = new ArrayList();
RepeatTemplate chunkOperations = new RepeatTemplate();
// Always handle the exception a check it is the right one...
chunkOperations.setExceptionHandler(new ExceptionHandler() {
public void handleException(RepeatContext context, Throwable throwable) throws RuntimeException {
throwables.add(throwable);
assertEquals("Error!", throwable.getMessage());
}
});
/*
* Each message fails once and the chunk (size=1) "rolls back"; then it
* is recovered ("skipped") on the second attempt (see retry policy
* definition above)...
*/
ItemOrientedStep step = getStep(new String[] { "foo", "bar", "spam" });
// Tasklet module = getTasklet(new String[] { "foo", "bar", "spam" });
// RepeatOperationsStep step = new RepeatOperationsStep();
step.setChunkOperations(chunkOperations);
step.setItemWriter(new AbstractItemWriter() {
public void write(Object data) throws Exception {
throw new RuntimeException("Error!");
}
});
step.setItemFailureHandler(new ItemFailureHandler(){
public void handleReadFailure(Exception ex) {
recovered.add(ex);
}
public void handleWriteFailure(Object item, Exception ex) {
recovered.add(ex);
}
});
step.afterPropertiesSet();
job.setSteps(Collections.singletonList(step));
JobExecution jobExecution = repository.createJobExecution(job, new JobParameters());
job.execute(jobExecution);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(0, processed.size());
// provider should be exhausted
assertEquals(null, provider.read());
assertEquals(3, recovered.size());
}
public void testExceptionTerminates() throws Exception {
// Tasklet module = getTasklet(new String[] { "foo", "bar", "spam" });
AbstractStep step = getStep(new String[] { "foo", "bar", "spam" });
step.setItemWriter(new AbstractItemWriter() {
public void write(Object data) throws Exception {
throw new RuntimeException("Foo");
}
});
step.afterPropertiesSet();
job.setSteps(Collections.singletonList(step));
JobExecution jobExecution = repository.createJobExecution(job, new JobParameters());
try {
job.execute(jobExecution);
fail("Expected RuntimeException");
}
catch (RuntimeException e) {
assertEquals("Foo", e.getMessage());
// expected
}
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
}
}

View File

@@ -1,228 +1,224 @@
/*
* 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.execution.repository.dao;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.batch.core.domain.BatchStatus;
import org.springframework.batch.core.domain.Job;
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.domain.JobSupport;
import org.springframework.batch.core.domain.Step;
import org.springframework.batch.core.domain.StepExecution;
import org.springframework.batch.core.domain.StepSupport;
import org.springframework.batch.core.runtime.ExitStatusExceptionClassifier;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
import org.springframework.util.ClassUtils;
/**
* Tests for step persistence (StepInstanceDao and StepExecutionDao). Because it is very reasonable to assume that there is a
* foreign key constraint on the JobId of a step, the JobDao is used to create
* jobs, to have an id for creating steps.
*
* @author Lucas Ward
* @author Dave Syer
*/
public abstract class AbstractStepDaoTests extends AbstractTransactionalDataSourceSpringContextTests {
protected JobInstanceDao jobInstanceDao;
protected StepExecutionDao stepExecutionDao;
protected JobExecutionDao jobExecutionDao;
protected JobInstance jobInstance;
protected Step step1;
protected Step step2;
protected StepExecution stepExecution;
protected JobExecution jobExecution;
protected JobParameters jobParameters = new JobParameters();
protected ExecutionContext executionContext;
public void setJobInstanceDao(JobInstanceDao jobInstanceDao) {
this.jobInstanceDao = jobInstanceDao;
}
public void setStepExecutionDao(StepExecutionDao stepExecutionDao) {
this.stepExecutionDao = stepExecutionDao;
}
public void setJobExecutionDao(JobExecutionDao jobExecutionDao) {
this.jobExecutionDao = jobExecutionDao;
}
/*
* (non-Javadoc)
* @see org.springframework.test.AbstractSingleSpringContextTests#getConfigLocations()
*/
protected String[] getConfigLocations() {
return new String[] { ClassUtils.addResourcePathToPackagePath(getClass(), "sql-dao-test.xml") };
}
/*
* (non-Javadoc)
* @see org.springframework.test.AbstractTransactionalSpringContextTests#onSetUpInTransaction()
*/
protected void onSetUpInTransaction() throws Exception {
Job job = new JobSupport("TestJob");
jobInstance = jobInstanceDao.createJobInstance(job, jobParameters);
step1 = new StepSupport("TestStep1");
step2 = new StepSupport("TestStep2");
jobExecution = new JobExecution(jobInstance);
jobExecutionDao.saveJobExecution(jobExecution);
stepExecution = new StepExecution(step1, jobExecution, new Long(1));
stepExecution.setStatus(BatchStatus.STARTED);
stepExecution.setStartTime(new Date(System.currentTimeMillis()));
stepExecutionDao.saveStepExecution(stepExecution);
executionContext = new ExecutionContext();
executionContext.putString("1", "testString1");
executionContext.putString("2", "testString2");
executionContext.putLong("3", 3);
executionContext.putDouble("4", 4.4);
}
public void testVersionIsNotNullForStepExecution() throws Exception {
int version = jdbcTemplate.queryForInt("select version from BATCH_STEP_EXECUTION where STEP_EXECUTION_ID="
+ stepExecution.getId());
assertEquals(0, version);
}
public void testUpdateStepWithExecutionContext() {
stepExecution.setExecutionContext(executionContext);
stepExecutionDao.saveExecutionContext(stepExecution);
ExecutionContext tempAttributes = stepExecutionDao.findExecutionContext(stepExecution);
assertEquals(executionContext, tempAttributes);
}
public void testSaveStepExecution() {
StepExecution execution = new StepExecution(step2, jobExecution, null);
execution.setStatus(BatchStatus.STARTED);
execution.setStartTime(new Date(System.currentTimeMillis()));
execution.setExitStatus(new ExitStatus(false, ExitStatusExceptionClassifier.FATAL_EXCEPTION,
"java.lang.Exception"));
stepExecutionDao.saveStepExecution(execution);
StepExecution retrievedExecution = stepExecutionDao.getStepExecution(jobExecution, step2);
assertNotNull(retrievedExecution);
assertEquals(execution, retrievedExecution);
assertEquals(execution.getExitStatus(), retrievedExecution.getExitStatus());
}
public void testSaveStepExecutionAndExecutionContext() {
StepExecution execution = new StepExecution(step2, jobExecution, null);
execution.setStatus(BatchStatus.STARTED);
execution.setStartTime(new Date(System.currentTimeMillis()));
execution.setExecutionContext(executionContext);
execution.setExitStatus(new ExitStatus(false, ExitStatusExceptionClassifier.FATAL_EXCEPTION,
"java.lang.Exception"));
stepExecutionDao.saveStepExecution(execution);
stepExecutionDao.saveExecutionContext(execution);
StepExecution retrievedExecution = stepExecutionDao.getStepExecution(jobExecution, step2);
assertNotNull(retrievedExecution);
assertEquals(execution, retrievedExecution);
assertEquals(execution.getExecutionContext().getString("1"), retrievedExecution.getExecutionContext().getString("1"));
assertEquals(execution.getExecutionContext().getLong("3"), retrievedExecution.getExecutionContext().getLong("3"));
assertEquals(execution.getExitStatus(), retrievedExecution.getExitStatus());
}
public void testUpdateStepExecution() {
stepExecution.setStatus(BatchStatus.COMPLETED);
stepExecution.setEndTime(new Date(System.currentTimeMillis()));
stepExecution.setCommitCount(5);
stepExecution.setTaskCount(5);
stepExecution.setExecutionContext(new ExecutionContext());
stepExecution.setExitStatus(new ExitStatus(false, ExitStatusExceptionClassifier.FATAL_EXCEPTION,
"java.lang.Exception"));
stepExecutionDao.updateStepExecution(stepExecution);
StepExecution retrievedExecution = stepExecutionDao.getStepExecution(jobExecution, step1);
assertNotNull(retrievedExecution);
assertEquals(stepExecution, retrievedExecution);
assertEquals(stepExecution.getExitStatus(), retrievedExecution.getExitStatus());
}
public void testUpdateStepExecutionWithNullId() {
StepExecution stepExecution = new StepExecution(new StepSupport("testStep"), null, null);
try {
stepExecutionDao.updateStepExecution(stepExecution);
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
// expected
}
}
public void testUpdateStepExecutionVersion() throws Exception {
int before = stepExecution.getVersion().intValue();
stepExecutionDao.updateStepExecution(stepExecution);
int after = stepExecution.getVersion().intValue();
assertEquals("StepExecution version not updated", before + 1, after);
}
public void testUpdateStepExecutionOptimisticLocking() throws Exception {
stepExecution.incrementVersion(); // not really allowed outside dao
// code
try {
stepExecutionDao.updateStepExecution(stepExecution);
fail("Expected OptimisticLockingFailureException");
}
catch (OptimisticLockingFailureException e) {
// expected
assertTrue("Exception message should contain step execution id: " + e.getMessage(), e.getMessage().indexOf(
"" + stepExecution.getId()) >= 0);
assertTrue("Exception message should contain step execution version: " + e.getMessage(), e.getMessage()
.indexOf("" + stepExecution.getVersion()) >= 0);
}
}
public void testSaveExecutionContext(){
stepExecution.setExecutionContext(executionContext);
stepExecutionDao.saveExecutionContext(stepExecution);
ExecutionContext attributes = stepExecutionDao.findExecutionContext(stepExecution);
assertEquals(executionContext, attributes);
executionContext.putString("newString", "newString");
executionContext.putLong("newLong", 1);
executionContext.putDouble("newDouble", 2.5);
executionContext.put("newSerializable", "serializableValue");
stepExecutionDao.updateExecutionContext(stepExecution);
attributes = stepExecutionDao.findExecutionContext(stepExecution);
assertEquals(executionContext, attributes);
}
public void testGetStepExecution() {
assertEquals(stepExecution, stepExecutionDao.getStepExecution(jobExecution, step1));
}
}
/*
* 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.execution.repository.dao;
import java.util.Date;
import org.springframework.batch.core.domain.BatchStatus;
import org.springframework.batch.core.domain.Job;
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.domain.JobSupport;
import org.springframework.batch.core.domain.Step;
import org.springframework.batch.core.domain.StepExecution;
import org.springframework.batch.core.domain.StepSupport;
import org.springframework.batch.core.runtime.ExitStatusExceptionClassifier;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
import org.springframework.util.ClassUtils;
/**
* Tests for step persistence (StepInstanceDao and StepExecutionDao). Because it is very reasonable to assume that there is a
* foreign key constraint on the JobId of a step, the JobDao is used to create
* jobs, to have an id for creating steps.
*
* @author Lucas Ward
* @author Dave Syer
*/
public abstract class AbstractStepDaoTests extends AbstractTransactionalDataSourceSpringContextTests {
protected JobInstanceDao jobInstanceDao;
protected StepExecutionDao stepExecutionDao;
protected JobExecutionDao jobExecutionDao;
protected JobInstance jobInstance;
protected Step step1;
protected Step step2;
protected StepExecution stepExecution;
protected JobExecution jobExecution;
protected JobParameters jobParameters = new JobParameters();
protected ExecutionContext executionContext;
public void setJobInstanceDao(JobInstanceDao jobInstanceDao) {
this.jobInstanceDao = jobInstanceDao;
}
public void setStepExecutionDao(StepExecutionDao stepExecutionDao) {
this.stepExecutionDao = stepExecutionDao;
}
public void setJobExecutionDao(JobExecutionDao jobExecutionDao) {
this.jobExecutionDao = jobExecutionDao;
}
/*
* (non-Javadoc)
* @see org.springframework.test.AbstractSingleSpringContextTests#getConfigLocations()
*/
protected String[] getConfigLocations() {
return new String[] { ClassUtils.addResourcePathToPackagePath(getClass(), "sql-dao-test.xml") };
}
/*
* (non-Javadoc)
* @see org.springframework.test.AbstractTransactionalSpringContextTests#onSetUpInTransaction()
*/
protected void onSetUpInTransaction() throws Exception {
Job job = new JobSupport("TestJob");
jobInstance = jobInstanceDao.createJobInstance(job, jobParameters);
step1 = new StepSupport("TestStep1");
step2 = new StepSupport("TestStep2");
jobExecution = new JobExecution(jobInstance);
jobExecutionDao.saveJobExecution(jobExecution);
stepExecution = new StepExecution(step1, jobExecution, new Long(1));
stepExecution.setStatus(BatchStatus.STARTED);
stepExecution.setStartTime(new Date(System.currentTimeMillis()));
stepExecutionDao.saveStepExecution(stepExecution);
executionContext = new ExecutionContext();
executionContext.putString("1", "testString1");
executionContext.putString("2", "testString2");
executionContext.putLong("3", 3);
executionContext.putDouble("4", 4.4);
}
public void testVersionIsNotNullForStepExecution() throws Exception {
int version = jdbcTemplate.queryForInt("select version from BATCH_STEP_EXECUTION where STEP_EXECUTION_ID="
+ stepExecution.getId());
assertEquals(0, version);
}
public void testUpdateStepWithExecutionContext() {
stepExecution.setExecutionContext(executionContext);
stepExecutionDao.saveExecutionContext(stepExecution);
ExecutionContext tempAttributes = stepExecutionDao.findExecutionContext(stepExecution);
assertEquals(executionContext, tempAttributes);
}
public void testSaveStepExecution() {
StepExecution execution = new StepExecution(step2, jobExecution, null);
execution.setStatus(BatchStatus.STARTED);
execution.setStartTime(new Date(System.currentTimeMillis()));
execution.setExitStatus(new ExitStatus(false, ExitStatusExceptionClassifier.FATAL_EXCEPTION,
"java.lang.Exception"));
stepExecutionDao.saveStepExecution(execution);
StepExecution retrievedExecution = stepExecutionDao.getStepExecution(jobExecution, step2);
assertNotNull(retrievedExecution);
assertEquals(execution, retrievedExecution);
assertEquals(execution.getExitStatus(), retrievedExecution.getExitStatus());
}
public void testSaveStepExecutionAndExecutionContext() {
StepExecution execution = new StepExecution(step2, jobExecution, null);
execution.setStatus(BatchStatus.STARTED);
execution.setStartTime(new Date(System.currentTimeMillis()));
execution.setExecutionContext(executionContext);
execution.setExitStatus(new ExitStatus(false, ExitStatusExceptionClassifier.FATAL_EXCEPTION,
"java.lang.Exception"));
stepExecutionDao.saveStepExecution(execution);
stepExecutionDao.saveExecutionContext(execution);
StepExecution retrievedExecution = stepExecutionDao.getStepExecution(jobExecution, step2);
assertNotNull(retrievedExecution);
assertEquals(execution, retrievedExecution);
assertEquals(execution.getExecutionContext().getString("1"), retrievedExecution.getExecutionContext().getString("1"));
assertEquals(execution.getExecutionContext().getLong("3"), retrievedExecution.getExecutionContext().getLong("3"));
assertEquals(execution.getExitStatus(), retrievedExecution.getExitStatus());
}
public void testUpdateStepExecution() {
stepExecution.setStatus(BatchStatus.COMPLETED);
stepExecution.setEndTime(new Date(System.currentTimeMillis()));
stepExecution.setCommitCount(5);
stepExecution.setTaskCount(5);
stepExecution.setExecutionContext(new ExecutionContext());
stepExecution.setExitStatus(new ExitStatus(false, ExitStatusExceptionClassifier.FATAL_EXCEPTION,
"java.lang.Exception"));
stepExecutionDao.updateStepExecution(stepExecution);
StepExecution retrievedExecution = stepExecutionDao.getStepExecution(jobExecution, step1);
assertNotNull(retrievedExecution);
assertEquals(stepExecution, retrievedExecution);
assertEquals(stepExecution.getExitStatus(), retrievedExecution.getExitStatus());
}
public void testUpdateStepExecutionWithNullId() {
StepExecution stepExecution = new StepExecution(new StepSupport("testStep"), null, null);
try {
stepExecutionDao.updateStepExecution(stepExecution);
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
// expected
}
}
public void testUpdateStepExecutionVersion() throws Exception {
int before = stepExecution.getVersion().intValue();
stepExecutionDao.updateStepExecution(stepExecution);
int after = stepExecution.getVersion().intValue();
assertEquals("StepExecution version not updated", before + 1, after);
}
public void testUpdateStepExecutionOptimisticLocking() throws Exception {
stepExecution.incrementVersion(); // not really allowed outside dao
// code
try {
stepExecutionDao.updateStepExecution(stepExecution);
fail("Expected OptimisticLockingFailureException");
}
catch (OptimisticLockingFailureException e) {
// expected
assertTrue("Exception message should contain step execution id: " + e.getMessage(), e.getMessage().indexOf(
"" + stepExecution.getId()) >= 0);
assertTrue("Exception message should contain step execution version: " + e.getMessage(), e.getMessage()
.indexOf("" + stepExecution.getVersion()) >= 0);
}
}
public void testSaveExecutionContext(){
stepExecution.setExecutionContext(executionContext);
stepExecutionDao.saveExecutionContext(stepExecution);
ExecutionContext attributes = stepExecutionDao.findExecutionContext(stepExecution);
assertEquals(executionContext, attributes);
executionContext.putString("newString", "newString");
executionContext.putLong("newLong", 1);
executionContext.putDouble("newDouble", 2.5);
executionContext.put("newSerializable", "serializableValue");
stepExecutionDao.updateExecutionContext(stepExecution);
attributes = stepExecutionDao.findExecutionContext(stepExecution);
assertEquals(executionContext, attributes);
}
public void testGetStepExecution() {
assertEquals(stepExecution, stepExecutionDao.getStepExecution(jobExecution, step1));
}
}