BATCH-146: Changed my mind on the implementation, SimpleJobRepository (and DAOs) now throw Spring IncorrectResultSetSizeDataAccessException, rather than BatchRestartException.

This commit is contained in:
lucasward
2007-10-02 04:37:21 +00:00
parent 4dc2467a12
commit 7b1be4fc32
6 changed files with 81 additions and 83 deletions

View File

@@ -33,6 +33,7 @@ import org.springframework.batch.core.runtime.JobIdentifier;
import org.springframework.batch.execution.repository.dao.JobDao;
import org.springframework.batch.execution.repository.dao.StepDao;
import org.springframework.batch.restart.GenericRestartData;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.util.Assert;
/**
@@ -116,8 +117,8 @@ public class SimpleJobRepository implements JobRepository {
}
else {
// More than one job found, throw exception
throw new BatchRestartException("Error restarting job, more than one JobInstance found for: "
+ jobConfiguration.toString());
throw new IncorrectResultSizeDataAccessException("Error restarting job, more than one JobInstance found for: "
+ jobConfiguration.toString(), 1, jobs.size());
}
}

View File

@@ -34,8 +34,8 @@ import org.springframework.util.Assert;
* Implementation of {@link JobDao} functionality based on the Hibernate ORM
* framework. Its advantage is the independence of implementation on the
* underlying database.
*
* @author tomas.slanina
*
* @author Tomas Slanina
* @author Dave Syer
*/
@@ -43,7 +43,7 @@ public class HibernateJobDao extends HibernateDaoSupport implements JobDao {
/**
* @see JobDao#createJob(JobIdentifier)
*
*
* In this Hibernate implementation a job is stored into the database. Id is
* obtained from Hibernate.
*/
@@ -62,7 +62,7 @@ public class HibernateJobDao extends HibernateDaoSupport implements JobDao {
/**
* @see JobDao#findJobs(JobIdentifier)
*
*
* Hibernate is asked to get all jobs that matches criteria. Afterwards,
* result is mapped into domain objects.
*/
@@ -109,7 +109,7 @@ public class HibernateJobDao extends HibernateDaoSupport implements JobDao {
/**
* @see JobDao#save(JobExecution)
*
*
* Hibernate implementation persists JobExecution instance. Id is obtained
* from Hibernate.
*/
@@ -168,7 +168,7 @@ public class HibernateJobDao extends HibernateDaoSupport implements JobDao {
public Object doInHibernate(Session session) {
Criteria criteria = session
.createCriteria(JobExecution.class);
criteria.add(Expression.eq("jobId", jobId));
criteria.add(Expression.eq("job.id", jobId));
return criteria.list();
}
});
@@ -179,7 +179,7 @@ public class HibernateJobDao extends HibernateDaoSupport implements JobDao {
/*
* Validate JobExecution. At a minimum, JobId, StartTime, EndTime, and
* Status cannot be null.
*
*
* @param jobExecution @throws IllegalArgumentException
*/
private void validateJobExecution(JobExecution jobExecution) {

View File

@@ -33,6 +33,7 @@ import org.springframework.batch.restart.GenericRestartData;
import org.springframework.batch.restart.RestartData;
import org.springframework.batch.support.PropertiesConverter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
@@ -41,18 +42,18 @@ import org.springframework.util.StringUtils;
/**
* Sql implementation of {@link StepDao}. Uses Sequences (via Spring's
*
*
* @link DataFieldMaxValueIncrementer abstraction) to create all Step and
* StepExecution primary keys before inserting a new row. All objects are
* checked to ensure all fields to be stored are not null. If any are
* found to be null, an IllegalArgumentException will be thrown. This
* could be left to JdbcTemplate, however, the exception will be fairly
* vague, and fails to highlight which field caused the exception.
*
*
* TODO: JavaDoc should be geared more towards usability, the comments above are
* useful information, and should be there, but needs usability stuff. Depends
* on the step dao java docs as well.
*
*
* @author Lucas Ward
* @see StepDao
*/
@@ -97,7 +98,7 @@ public class SqlStepDao implements StepDao, InitializingBean {
* Public setter for the table prefix property. This will be prefixed to all
* the table names before queries are executed. Defaults to
* {@value #DEFAULT_TABLE_PREFIX}.
*
*
* @param tablePrefix
* the tablePrefix to set
*/
@@ -121,11 +122,11 @@ public class SqlStepDao implements StepDao, InitializingBean {
* row returned to a step object. If none are found, the list will be empty
* and null will be returned. If one step is found, it will be returned. If
* anymore than one step is found, an exception is thrown.
*
*
* @see StepDao#findStep(Long, String)
* @throws IllegalArgumentException
* if job, stepName, or job.id is null.
* @throws NoSuchBatchDomainObjectException
* @throws IncorrectResultSizeDataAccessException
* if more than one step is found.
*/
public StepInstance findStep(JobInstance job, String stepName) {
@@ -162,19 +163,19 @@ public class SqlStepDao implements StepDao, InitializingBean {
// This error will likely never be thrown, because there should
// never be two steps with the same name and Job_ID due to database
// constraints.
throw new NoSuchBatchDomainObjectException(
throw new IncorrectResultSizeDataAccessException(
"Step Invalid, multiple steps found for StepName:"
+ stepName + " and JobId:" + job.getId());
+ stepName + " and JobId:" + job.getId(), 1, steps.size());
}
}
/**
* @see StepDao#findSteps(JobInstance)
*
*
* Sql implementation which uses a RowMapper to populate a list of all rows
* in the step table with the same JOB_ID.
*
*
* @throws IllegalArgumentException
* if jobId is null.
*/
@@ -205,7 +206,7 @@ public class SqlStepDao implements StepDao, InitializingBean {
* Create a step with the given job's id, and the provided step name. A
* unique id is created for the step using an incrementer. (@link
* DataFieldMaxValueIncrementer)
*
*
* @see StepDao#createStep(JobInstance, String)
* @throws IllegalArgumentException
* if job or stepName is null.
@@ -251,7 +252,7 @@ public class SqlStepDao implements StepDao, InitializingBean {
* Save a StepExecution. A unique id will be generated by the
* stepExecutionIncrementor, and then set in the StepExecution. All values
* will then be stored via an INSERT statement.
*
*
* @see StepDao#save(StepExecution)
*/
public void save(StepExecution stepExecution) {
@@ -333,12 +334,10 @@ public class SqlStepDao implements StepDao, InitializingBean {
/**
* Get StepExecution for the given step. Due to the nature of statistics,
* they will not be returned with reconstituted object.
*
*
* @see StepDao#getStepExecution(Long)
* @throws IllegalArgumentException
* if id is null.
* @throws NoSuchBatchDomainObjectException
* if more than one step execution is returned.
*/
public List findStepExecutions(final StepInstance step) {
@@ -400,7 +399,7 @@ public class SqlStepDao implements StepDao, InitializingBean {
/*
* Validate StepExecution. At a minimum, JobId, StartTime, and Status cannot
* be null. EndTime can be null for an unfinished job.
*
*
* @param jobExecution @throws IllegalArgumentException
*/
private void validateStepExecution(StepExecution stepExecution) {

View File

@@ -35,6 +35,7 @@ import org.springframework.batch.core.tasklet.Tasklet;
import org.springframework.batch.execution.repository.dao.JobDao;
import org.springframework.batch.execution.repository.dao.StepDao;
import org.springframework.batch.restart.GenericRestartData;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
/*
* Test SimpleJobRepository. The majority of test cases are tested using EasyMock,
@@ -176,7 +177,7 @@ public class SimpleJobRepositoryTests extends TestCase {
try{
jobRepository.findOrCreateJob(jobConfiguration, jobRuntimeInformation);
fail();
}catch(BatchRestartException ex){
}catch(IncorrectResultSizeDataAccessException ex){
//expected
}
@@ -273,7 +274,7 @@ public class SimpleJobRepositoryTests extends TestCase {
// expected
}
}
public void testSaveOrUpdateValidJobExecution() throws Exception {
JobExecution jobExecution = new JobExecution(new JobInstance(null, new Long(1)));

View File

@@ -36,7 +36,7 @@ import org.springframework.util.ClassUtils;
/**
* @author Dave Syer
*
*
*/
public abstract class AbstractJobDaoTests extends
AbstractTransactionalDataSourceSpringContextTests {
@@ -170,15 +170,15 @@ public abstract class AbstractJobDaoTests extends
jobExecution.setEndTime(new Timestamp(System.currentTimeMillis()));
jobDao.update(jobExecution);
List executions = retrieveJobExecution(jobExecution.getId());
List executions = jobDao.findJobExecutions(job);
assertEquals(executions.size(), 1);
validateJobExecution(jobExecution, (JobExecution) executions.get(0));
}
public void testSaveJobExecution() {
public void testSaveJobExecution(){
List executions = retrieveJobExecution(jobExecution.getId());
List executions = jobDao.findJobExecutions(job);
assertEquals(executions.size(), 1);
validateJobExecution(jobExecution, (JobExecution) executions.get(0));
}
@@ -243,9 +243,16 @@ public abstract class AbstractJobDaoTests extends
}
private void validateJobExecution(JobExecution lhs, JobExecution rhs) {
public void testFindJobExecutions(){
// equals operator only checks id
List results = jobDao.findJobExecutions(job);
assertEquals(results.size(), 1);
validateJobExecution(jobExecution, (JobExecution)results.get(0));
}
private void validateJobExecution(JobExecution lhs, JobExecution rhs){
//equals operator only checks id
assertEquals(lhs, rhs);
assertEquals(lhs.getStartTime(), rhs.getStartTime());
assertEquals(lhs.getEndTime(), rhs.getEndTime());
@@ -253,27 +260,4 @@ public abstract class AbstractJobDaoTests extends
assertEquals(lhs.getExitStatus(), rhs.getExitStatus());
}
private List retrieveJobExecution(final Long id) {
RowMapper rowMapper = new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
JobExecution execution = new JobExecution(new JobInstance(
jobRuntimeInformation, new Long(rs.getLong(1))));
execution.setStartTime(rs.getTimestamp(2));
execution.setEndTime(rs.getTimestamp(3));
execution.setStatus(BatchStatus.getStatus(rs.getString(4)));
// TODO: Add boolean for continuable to queries
execution.setExitStatus(new ExitStatus("Y".equals(rs
.getString(5)), rs.getString(6), rs.getString(7)));
execution.setId(id);
return execution;
}
};
return jdbcTemplate.query(GET_JOB_EXECUTION, new Object[] { id },
rowMapper);
}
}

View File

@@ -26,11 +26,13 @@ import org.springframework.batch.core.domain.JobInstance;
import org.springframework.batch.core.domain.StepExecution;
import org.springframework.batch.core.domain.StepInstance;
import org.springframework.batch.core.executor.ExitCodeExceptionClassifier;
import org.springframework.batch.core.repository.NoSuchBatchDomainObjectException;
import org.springframework.batch.core.runtime.JobIdentifier;
import org.springframework.batch.execution.runtime.ScheduledJobIdentifier;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.batch.restart.GenericRestartData;
import org.springframework.batch.restart.RestartData;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
import org.springframework.util.ClassUtils;
@@ -38,7 +40,7 @@ import org.springframework.util.ClassUtils;
* Test for StepDao. 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
*/
@@ -49,11 +51,11 @@ public abstract class AbstractStepDaoTests extends AbstractTransactionalDataSour
protected StepDao stepDao;
protected JobInstance job;
protected StepInstance step1;
protected StepInstance step2;
protected StepExecution stepExecution;
protected JobExecution jobExecution;
@@ -90,29 +92,40 @@ public abstract class AbstractStepDaoTests extends AbstractTransactionalDataSour
stepExecution.setStartTime(new Timestamp(System.currentTimeMillis()));
stepDao.save(stepExecution);
}
public void testVersionIsNotNullForStep() throws Exception {
int version = jdbcTemplate.queryForInt("select version from BATCH_STEP where ID="+step1.getId());
assertEquals(0, version);
}
public void testVersionIsNotNullForStepExecution() throws Exception {
int version = jdbcTemplate.queryForInt("select version from BATCH_STEP_EXECUTION where ID="+stepExecution.getId());
assertEquals(0, version);
}
public void testFindStepNull(){
StepInstance step = stepDao.findStep(job, "UnSavedStep");
assertNull(step);
}
public void testFindStep(){
StepInstance tempStep = stepDao.findStep(job, "TestStep1");
assertEquals(tempStep, step1);
}
public void testFindStepsWithSameId(){
StepInstance duplicateStep = new StepInstance(step1.getId());
stepDao.createStep(job, step1.getName());
try{
stepDao.findStep(job, step1.getName());
fail();
}catch(IncorrectResultSizeDataAccessException ex){
//expected
}
}
public void testFindSteps(){
List steps = stepDao.findSteps(job);
@@ -120,31 +133,31 @@ public abstract class AbstractStepDaoTests extends AbstractTransactionalDataSour
assertTrue(steps.contains(step1));
assertTrue(steps.contains(step2));
}
public void testFindStepsNotSaved(){
//no steps are saved for given id, empty list should be returned
List steps = stepDao.findSteps(new JobInstance(null, new Long(38922)));
assertEquals(steps.size(), 0);
}
public void testCreateStep(){
StepInstance step3 = stepDao.createStep(job, "TestStep3");
StepInstance tempStep = stepDao.findStep(job, "TestStep3");
assertEquals(step3, tempStep);
}
public void testUpdateStepWithoutRestartData(){
step1.setStatus(BatchStatus.COMPLETED);
stepDao.update(step1);
StepInstance tempStep = stepDao.findStep(job, step1.getName());
assertEquals(tempStep, step1);
}
public void testUpdateStepWithRestartData(){
step1.setStatus(BatchStatus.COMPLETED);
Properties data = new Properties();
data.setProperty("restart.key1", "restartData");
@@ -153,10 +166,10 @@ public abstract class AbstractStepDaoTests extends AbstractTransactionalDataSour
stepDao.update(step1);
StepInstance tempStep = stepDao.findStep(job, step1.getName());
assertEquals(tempStep, step1);
assertEquals(tempStep.getRestartData().getProperties().toString(),
assertEquals(tempStep.getRestartData().getProperties().toString(),
restartData.getProperties().toString());
}
public void testSaveStepExecution(){
StepExecution execution = new StepExecution(step2, jobExecution);
@@ -175,9 +188,9 @@ public abstract class AbstractStepDaoTests extends AbstractTransactionalDataSour
assertEquals(execution.getStatistics(), tempExecution.getStatistics());
assertEquals(execution.getExitStatus(), tempExecution.getExitStatus());
}
public void testUpdateStepExecution(){
stepExecution.setStatus(BatchStatus.COMPLETED);
stepExecution.setEndTime(new Timestamp(System.currentTimeMillis()));
stepExecution.setCommitCount(5);
@@ -191,7 +204,7 @@ public abstract class AbstractStepDaoTests extends AbstractTransactionalDataSour
assertEquals(stepExecution, tempExecution);
assertEquals(stepExecution.getExitStatus(), tempExecution.getExitStatus());
}
public void testUpdateStepExecutionWithNullId(){
StepExecution stepExecution = new StepExecution(null, null);
try{
@@ -201,15 +214,15 @@ public abstract class AbstractStepDaoTests extends AbstractTransactionalDataSour
//expected
}
}
public void testGetStepExecutionCountForNoExecutions(){
int executionCount = stepDao.getStepExecutionCount(step2.getId());
assertEquals(executionCount, 0);
}
public void testIncrementStepExecutionCount(){
assertEquals(1, stepDao.getStepExecutionCount(step1.getId()));
StepExecution execution = new StepExecution(step1, new JobExecution(step1.getJob(), new Long(123)));
stepDao.save(execution);