diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/ExecutionContextDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/ExecutionContextDao.java index 2ec5e3764..590b75e74 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/ExecutionContextDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/ExecutionContextDao.java @@ -40,14 +40,30 @@ public interface ExecutionContextDao { ExecutionContext getExecutionContext(StepExecution stepExecution); /** - * Persist the execution context associated with the given jobExecution + * Persist the execution context associated with the given jobExecution, + * persistent entry for the context should not exist yet. * @param jobExecution */ - void persistExecutionContext(final JobExecution jobExecution); + void saveExecutionContext(final JobExecution jobExecution); /** - * Persist the execution context associated with the given stepExecution + * Persist the execution context associated with the given stepExecution, + * persistent entry for the context should not exist yet. * @param stepExecution */ - void persistExecutionContext(final StepExecution stepExecution); + void saveExecutionContext(final StepExecution stepExecution); + + /** + * Persist the updates of execution context associated with the given + * jobExecution. Persistent entry should already exist for this context. + * @param jobExecution + */ + void updateExecutionContext(final JobExecution jobExecution); + + /** + * Persist the updates of execution context associated with the given + * stepExecution. Persistent entry should already exist for this context. + * @param stepExecution + */ + void updateExecutionContext(final StepExecution stepExecution); } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcExecutionContextDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcExecutionContextDao.java index 2f88aa655..f9b1a9505 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcExecutionContextDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/JdbcExecutionContextDao.java @@ -49,31 +49,26 @@ public class JdbcExecutionContextDao extends AbstractJdbcBatchMetadataDao implem private static final String COUNT_JOB_EXECUTION_CONTEXT = "SELECT COUNT(*) FROM %PREFIX%JOB_EXECUTION_CONTEXT " + "WHERE JOB_EXECUTION_ID = ?"; - private static final String FIND_JOB_EXECUTION_CONTEXT = "SELECT SHORT_CONTEXT, SERIALIZED_CONTEXT " + - "FROM %PREFIX%JOB_EXECUTION_CONTEXT WHERE JOB_EXECUTION_ID = ?"; + private static final String FIND_JOB_EXECUTION_CONTEXT = "SELECT SHORT_CONTEXT, SERIALIZED_CONTEXT " + + "FROM %PREFIX%JOB_EXECUTION_CONTEXT WHERE JOB_EXECUTION_ID = ?"; - private static final String INSERT_JOB_EXECUTION_CONTEXT = "INSERT INTO %PREFIX%JOB_EXECUTION_CONTEXT " + - "(JOB_EXECUTION_ID, SHORT_CONTEXT, SERIALIZED_CONTEXT) " + - "VALUES(?, ?, ?)"; + private static final String INSERT_JOB_EXECUTION_CONTEXT = "INSERT INTO %PREFIX%JOB_EXECUTION_CONTEXT " + + "(JOB_EXECUTION_ID, SHORT_CONTEXT, SERIALIZED_CONTEXT) " + "VALUES(?, ?, ?)"; - private static final String UPDATE_JOB_EXECUTION_CONTEXT = "UPDATE %PREFIX%JOB_EXECUTION_CONTEXT " + - "SET SHORT_CONTEXT = ?, SERIALIZED_CONTEXT = ? " + - "WHERE JOB_EXECUTION_ID = ?"; + private static final String UPDATE_JOB_EXECUTION_CONTEXT = "UPDATE %PREFIX%JOB_EXECUTION_CONTEXT " + + "SET SHORT_CONTEXT = ?, SERIALIZED_CONTEXT = ? " + "WHERE JOB_EXECUTION_ID = ?"; private static final String COUNT_STEP_EXECUTION_CONTEXT = "SELECT COUNT(*) FROM %PREFIX%STEP_EXECUTION_CONTEXT " + "WHERE STEP_EXECUTION_ID = ?"; - private static final String FIND_STEP_EXECUTION_CONTEXT = "SELECT SHORT_CONTEXT, SERIALIZED_CONTEXT " + - "FROM %PREFIX%STEP_EXECUTION_CONTEXT WHERE STEP_EXECUTION_ID = ?"; + private static final String FIND_STEP_EXECUTION_CONTEXT = "SELECT SHORT_CONTEXT, SERIALIZED_CONTEXT " + + "FROM %PREFIX%STEP_EXECUTION_CONTEXT WHERE STEP_EXECUTION_ID = ?"; + private static final String INSERT_STEP_EXECUTION_CONTEXT = "INSERT INTO %PREFIX%STEP_EXECUTION_CONTEXT " + + "(STEP_EXECUTION_ID, SHORT_CONTEXT, SERIALIZED_CONTEXT) " + "VALUES(?, ?, ?)"; - private static final String INSERT_STEP_EXECUTION_CONTEXT = "INSERT INTO %PREFIX%STEP_EXECUTION_CONTEXT " + - "(STEP_EXECUTION_ID, SHORT_CONTEXT, SERIALIZED_CONTEXT) " + - "VALUES(?, ?, ?)"; - - private static final String UPDATE_STEP_EXECUTION_CONTEXT = "UPDATE %PREFIX%STEP_EXECUTION_CONTEXT " + - "SET SHORT_CONTEXT = ?, SERIALIZED_CONTEXT = ? " + - "WHERE STEP_EXECUTION_ID = ?"; + private static final String UPDATE_STEP_EXECUTION_CONTEXT = "UPDATE %PREFIX%STEP_EXECUTION_CONTEXT " + + "SET SHORT_CONTEXT = ?, SERIALIZED_CONTEXT = ? " + "WHERE STEP_EXECUTION_ID = ?"; private static final int MAX_VARCHAR_LENGTH = 2500; @@ -90,8 +85,7 @@ public class JdbcExecutionContextDao extends AbstractJdbcBatchMetadataDao implem Assert.notNull(executionId, "ExecutionId must not be null."); List results = getJdbcTemplate().query(getQuery(FIND_JOB_EXECUTION_CONTEXT), - new ExecutionContextRowMapper(), - executionId); + new ExecutionContextRowMapper(), executionId); if (results.size() > 0) { return results.get(0); } @@ -109,8 +103,7 @@ public class JdbcExecutionContextDao extends AbstractJdbcBatchMetadataDao implem Assert.notNull(executionId, "ExecutionId must not be null."); List results = getJdbcTemplate().query(getQuery(FIND_STEP_EXECUTION_CONTEXT), - new ExecutionContextRowMapper(), - executionId); + new ExecutionContextRowMapper(), executionId); if (results.size() > 0) { return results.get(0); } @@ -124,7 +117,7 @@ public class JdbcExecutionContextDao extends AbstractJdbcBatchMetadataDao implem * jobExecution * @param jobExecution */ - public void persistExecutionContext(final JobExecution jobExecution) { + public void updateExecutionContext(final JobExecution jobExecution) { Long executionId = jobExecution.getId(); ExecutionContext executionContext = jobExecution.getExecutionContext(); Assert.notNull(executionId, "ExecutionId must not be null."); @@ -140,7 +133,7 @@ public class JdbcExecutionContextDao extends AbstractJdbcBatchMetadataDao implem * stepExecution * @param stepExecution */ - public void persistExecutionContext(final StepExecution stepExecution) { + public void updateExecutionContext(final StepExecution stepExecution) { Long executionId = stepExecution.getId(); ExecutionContext executionContext = stepExecution.getExecutionContext(); @@ -152,6 +145,14 @@ public class JdbcExecutionContextDao extends AbstractJdbcBatchMetadataDao implem persistSerializedContext(executionId, serializedContext, false); } + public void saveExecutionContext(JobExecution jobExecution) { + updateExecutionContext(jobExecution); + } + + public void saveExecutionContext(StepExecution stepExecution) { + updateExecutionContext(stepExecution); + } + public void setLobHandler(LobHandler lobHandler) { this.lobHandler = lobHandler; } @@ -160,10 +161,11 @@ public class JdbcExecutionContextDao extends AbstractJdbcBatchMetadataDao implem public void afterPropertiesSet() throws Exception { super.afterPropertiesSet(); serializer = new XStreamExecutionContextStringSerializer(); - ((XStreamExecutionContextStringSerializer)serializer).afterPropertiesSet(); + ((XStreamExecutionContextStringSerializer) serializer).afterPropertiesSet(); } - private void persistSerializedContext(final Long executionId, String serializedContext, boolean isJobExecutionContext) { + private void persistSerializedContext(final Long executionId, String serializedContext, + boolean isJobExecutionContext) { String countSql = isJobExecutionContext ? COUNT_JOB_EXECUTION_CONTEXT : COUNT_STEP_EXECUTION_CONTEXT; String updateSql = isJobExecutionContext ? UPDATE_JOB_EXECUTION_CONTEXT : UPDATE_STEP_EXECUTION_CONTEXT; String insertSql = isJobExecutionContext ? INSERT_JOB_EXECUTION_CONTEXT : INSERT_STEP_EXECUTION_CONTEXT; @@ -181,36 +183,33 @@ public class JdbcExecutionContextDao extends AbstractJdbcBatchMetadataDao implem longContext = null; } - if (count > 0) { - getJdbcTemplate().getJdbcOperations().update(getQuery(updateSql), - new PreparedStatementSetter() { - public void setValues(PreparedStatement ps) throws SQLException { - ps.setString(1, shortContext); - if (longContext != null) { - lobHandler.getLobCreator().setClobAsString(ps, 2, longContext); - } - else { - ps.setNull(2, Types.CLOB); - } - ps.setLong(3, executionId); - } - }); + getJdbcTemplate().getJdbcOperations().update(getQuery(updateSql), new PreparedStatementSetter() { + public void setValues(PreparedStatement ps) throws SQLException { + ps.setString(1, shortContext); + if (longContext != null) { + lobHandler.getLobCreator().setClobAsString(ps, 2, longContext); + } + else { + ps.setNull(2, Types.CLOB); + } + ps.setLong(3, executionId); + } + }); } else { - getJdbcTemplate().getJdbcOperations().update(getQuery(insertSql), - new PreparedStatementSetter() { - public void setValues(PreparedStatement ps) throws SQLException { - ps.setLong(1, executionId); - ps.setString(2, shortContext); - if (longContext != null) { - lobHandler.getLobCreator().setClobAsString(ps, 3, longContext); - } - else { - ps.setNull(3, Types.CLOB); - } - } - }); + getJdbcTemplate().getJdbcOperations().update(getQuery(insertSql), new PreparedStatementSetter() { + public void setValues(PreparedStatement ps) throws SQLException { + ps.setLong(1, executionId); + ps.setString(2, shortContext); + if (longContext != null) { + lobHandler.getLobCreator().setClobAsString(ps, 3, longContext); + } + else { + ps.setNull(3, Types.CLOB); + } + } + }); } } @@ -236,4 +235,5 @@ public class JdbcExecutionContextDao extends AbstractJdbcBatchMetadataDao implem return executionContext; } } + } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapExecutionContextDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapExecutionContextDao.java index 1febce5a1..32cc1ec21 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapExecutionContextDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapExecutionContextDao.java @@ -44,7 +44,7 @@ public class MapExecutionContextDao implements ExecutionContextDao { return copy(contextsByStepExecutionId.get(stepExecution.getId())); } - public void persistExecutionContext(StepExecution stepExecution) { + public void updateExecutionContext(StepExecution stepExecution) { contextsByStepExecutionId.put(stepExecution.getId(), copy(stepExecution.getExecutionContext())); } @@ -52,9 +52,17 @@ public class MapExecutionContextDao implements ExecutionContextDao { return copy(contextsByJobExecutionId.get(jobExecution.getId())); } - public void persistExecutionContext(JobExecution jobExecution) { + public void updateExecutionContext(JobExecution jobExecution) { contextsByJobExecutionId.put(jobExecution.getId(), copy(jobExecution.getExecutionContext())); } + public void saveExecutionContext(JobExecution jobExecution) { + updateExecutionContext(jobExecution); + } + + public void saveExecutionContext(StepExecution stepExecution) { + updateExecutionContext(stepExecution); + } + } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java index 75994d887..b3ddc2fa7 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/support/SimpleJobRepository.java @@ -196,18 +196,17 @@ public class SimpleJobRepository implements JobRepository { // Save the JobExecution so that it picks up an ID (useful for clients // monitoring asynchronous executions): jobExecutionDao.saveJobExecution(jobExecution); + ecDao.saveExecutionContext(jobExecution); return jobExecution; } /** - * Save or Update a JobExecution. A JobExecution is considered one - * 'execution' of a particular job. Therefore, it must have it's jobId field - * set before it is passed into this method. It also has it's own unique - * identifier, because it must be updatable separately. If an id isn't - * found, a new JobExecution is created, if one is found, the current row is - * updated. + * Update a JobExecution. A JobExecution is considered one 'execution' of a + * particular job. Therefore, it must have it's jobId field set before it is + * passed into this method. It also has it's own unique identifier, because + * it must be updatable separately. * * @param jobExecution to be stored. * @throws IllegalArgumentException if jobExecution is null. @@ -233,6 +232,7 @@ public class SimpleJobRepository implements JobRepository { stepExecution.setLastUpdated(new Date(System.currentTimeMillis())); stepExecutionDao.saveStepExecution(stepExecution); + ecDao.saveExecutionContext(stepExecution); } /** @@ -256,17 +256,9 @@ public class SimpleJobRepository implements JobRepository { Assert.notNull(stepExecution.getJobExecutionId(), "StepExecution must belong to persisted JobExecution"); } - /* - * (non-Javadoc) - * - * @see org.springframework.batch.core.repository.JobRepository# - * persistExecutionContext - * (org.springframework.batch.core.domain.StepExecution) - */ public void updateExecutionContext(StepExecution stepExecution) { - // Until there is an interface change ( - ecDao.persistExecutionContext(stepExecution.getJobExecution()); - ecDao.persistExecutionContext(stepExecution); + ecDao.updateExecutionContext(stepExecution.getJobExecution()); + ecDao.updateExecutionContext(stepExecution); } /** diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractExecutionContextDaoTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractExecutionContextDaoTests.java index 9b9f14046..7714f38df 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractExecutionContextDaoTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/AbstractExecutionContextDaoTests.java @@ -76,7 +76,7 @@ public abstract class AbstractExecutionContextDaoTests extends AbstractTransacti ExecutionContext ctx = new ExecutionContext(Collections. singletonMap("key", "value")); jobExecution.setExecutionContext(ctx); - contextDao.persistExecutionContext(jobExecution); + contextDao.updateExecutionContext(jobExecution); ExecutionContext retrieved = contextDao.getExecutionContext(jobExecution); assertEquals(ctx, retrieved); @@ -88,7 +88,7 @@ public abstract class AbstractExecutionContextDaoTests extends AbstractTransacti ExecutionContext ctx = new ExecutionContext(); jobExecution.setExecutionContext(ctx); - contextDao.persistExecutionContext(jobExecution); + contextDao.updateExecutionContext(jobExecution); ExecutionContext retrieved = contextDao.getExecutionContext(jobExecution); assertEquals(ctx, retrieved); @@ -101,10 +101,10 @@ public abstract class AbstractExecutionContextDaoTests extends AbstractTransacti ExecutionContext ctx = new ExecutionContext(Collections . singletonMap("key", "value")); jobExecution.setExecutionContext(ctx); - contextDao.persistExecutionContext(jobExecution); + contextDao.updateExecutionContext(jobExecution); ctx.putLong("longKey", 7); - contextDao.persistExecutionContext(jobExecution); + contextDao.updateExecutionContext(jobExecution); ExecutionContext retrieved = contextDao.getExecutionContext(jobExecution); assertEquals(ctx, retrieved); @@ -117,7 +117,7 @@ public abstract class AbstractExecutionContextDaoTests extends AbstractTransacti ExecutionContext ctx = new ExecutionContext(Collections. singletonMap("key", "value")); stepExecution.setExecutionContext(ctx); - contextDao.persistExecutionContext(stepExecution); + contextDao.updateExecutionContext(stepExecution); ExecutionContext retrieved = contextDao.getExecutionContext(stepExecution); assertEquals(ctx, retrieved); @@ -129,7 +129,7 @@ public abstract class AbstractExecutionContextDaoTests extends AbstractTransacti ExecutionContext ctx = new ExecutionContext(); stepExecution.setExecutionContext(ctx); - contextDao.persistExecutionContext(stepExecution); + contextDao.updateExecutionContext(stepExecution); ExecutionContext retrieved = contextDao.getExecutionContext(stepExecution); assertEquals(ctx, retrieved); @@ -141,10 +141,10 @@ public abstract class AbstractExecutionContextDaoTests extends AbstractTransacti ExecutionContext ctx = new ExecutionContext(Collections. singletonMap("key", "value")); stepExecution.setExecutionContext(ctx); - contextDao.persistExecutionContext(stepExecution); + contextDao.updateExecutionContext(stepExecution); ctx.putLong("longKey", 7); - contextDao.persistExecutionContext(stepExecution); + contextDao.updateExecutionContext(stepExecution); ExecutionContext retrieved = contextDao.getExecutionContext(stepExecution); assertEquals(ctx, retrieved); @@ -158,7 +158,7 @@ public abstract class AbstractExecutionContextDaoTests extends AbstractTransacti ExecutionContext ec = new ExecutionContext(); ec.put("intValue", new Integer(343232)); stepExecution.setExecutionContext(ec); - contextDao.persistExecutionContext(stepExecution); + contextDao.updateExecutionContext(stepExecution); ExecutionContext restoredEc = contextDao.getExecutionContext(stepExecution); assertEquals(ec, restoredEc); } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/MapExecutionContextDaoTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/MapExecutionContextDaoTests.java index af04972ae..80f090890 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/MapExecutionContextDaoTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/repository/dao/MapExecutionContextDaoTests.java @@ -45,13 +45,13 @@ public class MapExecutionContextDaoTests extends AbstractExecutionContextDaoTest StepExecution stepExecution = new StepExecution("stepName", jobExecution); assertTrue(stepExecution.getExecutionContext().isEmpty()); - tested.persistExecutionContext(stepExecution); + tested.updateExecutionContext(stepExecution); stepExecution.getExecutionContext().put("key","value"); ExecutionContext retrieved = tested.getExecutionContext(stepExecution); assertTrue(retrieved.isEmpty()); - tested.persistExecutionContext(jobExecution); + tested.updateExecutionContext(jobExecution); jobExecution.getExecutionContext().put("key", "value"); retrieved = tested.getExecutionContext(jobExecution); assertTrue(retrieved.isEmpty()); diff --git a/spring-batch-samples/src/test/java/org/springframework/batch/sample/support/JdbcJobRepositoryTests.java b/spring-batch-samples/src/test/java/org/springframework/batch/sample/support/JdbcJobRepositoryTests.java index 747e1bff1..38b6913ce 100644 --- a/spring-batch-samples/src/test/java/org/springframework/batch/sample/support/JdbcJobRepositoryTests.java +++ b/spring-batch-samples/src/test/java/org/springframework/batch/sample/support/JdbcJobRepositoryTests.java @@ -50,7 +50,7 @@ import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = {"/simple-job-launcher-context.xml"}) +@ContextConfiguration(locations = { "/simple-job-launcher-context.xml" }) public class JdbcJobRepositoryTests { private JobRepository repository; @@ -67,9 +67,9 @@ public class JdbcJobRepositoryTests { private PlatformTransactionManager transactionManager; - /** Logger */ + /** Logger */ private final Log logger = LogFactory.getLog(getClass()); - + @Autowired public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); @@ -100,18 +100,21 @@ public class JdbcJobRepositoryTests { @AfterTransaction public void onTearDownAfterTransaction() throws Exception { for (Long id : jobExecutionIds) { + simpleJdbcTemplate.update("DELETE FROM BATCH_JOB_EXECUTION_CONTEXT where JOB_EXECUTION_ID=?", id); simpleJdbcTemplate.update("DELETE FROM BATCH_JOB_EXECUTION where JOB_EXECUTION_ID=?", id); } for (Long id : jobIds) { simpleJdbcTemplate.update("DELETE FROM BATCH_JOB_INSTANCE where JOB_INSTANCE_ID=?", id); } for (Long id : jobIds) { - int count = simpleJdbcTemplate.queryForInt("SELECT COUNT(*) FROM BATCH_JOB_INSTANCE where JOB_INSTANCE_ID=?", id); + int count = simpleJdbcTemplate.queryForInt( + "SELECT COUNT(*) FROM BATCH_JOB_INSTANCE where JOB_INSTANCE_ID=?", id); assertEquals(0, count); } } - @Transactional @Test + @Transactional + @Test public void testFindOrCreateJob() throws Exception { job.setName("foo"); int before = 0; @@ -121,7 +124,8 @@ public class JdbcJobRepositoryTests { assertNotNull(execution.getId()); } - @Transactional @Test + @Transactional + @Test public void testFindOrCreateJobConcurrently() throws Exception { job.setName("bar"); @@ -199,7 +203,8 @@ public class JdbcJobRepositoryTests { new TransactionTemplate(transactionManager).execute(new TransactionCallback() { public Object doInTransaction(org.springframework.transaction.TransactionStatus status) { try { - JobExecution execution = repository.createJobExecution(job.getName(), new JobParameters()); + JobExecution execution = repository.createJobExecution(job.getName(), + new JobParameters()); cacheJobIds(execution); list.add(execution); Thread.sleep(1000);