diff --git a/execution/src/main/java/org/springframework/batch/execution/repository/SimpleJobRepository.java b/execution/src/main/java/org/springframework/batch/execution/repository/SimpleJobRepository.java index db5bfdefc..04b6c7348 100644 --- a/execution/src/main/java/org/springframework/batch/execution/repository/SimpleJobRepository.java +++ b/execution/src/main/java/org/springframework/batch/execution/repository/SimpleJobRepository.java @@ -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()); } } diff --git a/execution/src/main/java/org/springframework/batch/execution/repository/dao/HibernateJobDao.java b/execution/src/main/java/org/springframework/batch/execution/repository/dao/HibernateJobDao.java index 38ed51d8d..2b245eb02 100644 --- a/execution/src/main/java/org/springframework/batch/execution/repository/dao/HibernateJobDao.java +++ b/execution/src/main/java/org/springframework/batch/execution/repository/dao/HibernateJobDao.java @@ -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) { diff --git a/execution/src/main/java/org/springframework/batch/execution/repository/dao/SqlStepDao.java b/execution/src/main/java/org/springframework/batch/execution/repository/dao/SqlStepDao.java index ff87f3ef0..eadbf00c1 100644 --- a/execution/src/main/java/org/springframework/batch/execution/repository/dao/SqlStepDao.java +++ b/execution/src/main/java/org/springframework/batch/execution/repository/dao/SqlStepDao.java @@ -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) { diff --git a/execution/src/test/java/org/springframework/batch/execution/repository/SimpleJobRepositoryTests.java b/execution/src/test/java/org/springframework/batch/execution/repository/SimpleJobRepositoryTests.java index 25d3e05ad..8b1552973 100644 --- a/execution/src/test/java/org/springframework/batch/execution/repository/SimpleJobRepositoryTests.java +++ b/execution/src/test/java/org/springframework/batch/execution/repository/SimpleJobRepositoryTests.java @@ -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))); diff --git a/execution/src/test/java/org/springframework/batch/execution/repository/dao/AbstractJobDaoTests.java b/execution/src/test/java/org/springframework/batch/execution/repository/dao/AbstractJobDaoTests.java index 22fc9b54e..d930db3ea 100644 --- a/execution/src/test/java/org/springframework/batch/execution/repository/dao/AbstractJobDaoTests.java +++ b/execution/src/test/java/org/springframework/batch/execution/repository/dao/AbstractJobDaoTests.java @@ -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); - } - } diff --git a/execution/src/test/java/org/springframework/batch/execution/repository/dao/AbstractStepDaoTests.java b/execution/src/test/java/org/springframework/batch/execution/repository/dao/AbstractStepDaoTests.java index 7d3b8d3ff..bf7fb16de 100644 --- a/execution/src/test/java/org/springframework/batch/execution/repository/dao/AbstractStepDaoTests.java +++ b/execution/src/test/java/org/springframework/batch/execution/repository/dao/AbstractStepDaoTests.java @@ -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);