diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/JobExecution.java b/spring-batch-core/src/main/java/org/springframework/batch/core/JobExecution.java index db1a8edb6..99ed94b50 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/JobExecution.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/JobExecution.java @@ -319,4 +319,14 @@ public class JobExecution extends Entity { startTime, endTime, lastUpdated, status, exitStatus, jobInstance); } + /** + * Setter for the step executions. For internal use only. + * @param stepExecutions + */ + public void addStepExecutions(List stepExecutions) { + if (stepExecutions!=null) { + this.stepExecutions.addAll(stepExecutions); + } + } + } \ No newline at end of file diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/job/SimpleJob.java b/spring-batch-core/src/main/java/org/springframework/batch/core/job/SimpleJob.java index 29ffb7ed9..c902e5a95 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/job/SimpleJob.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/job/SimpleJob.java @@ -39,6 +39,20 @@ import org.springframework.batch.core.repository.JobRestartException; public class SimpleJob extends AbstractJob { private List steps = new ArrayList(); + + /** + * Default constructor for job with null name + */ + public SimpleJob() { + this(null); + } + + /** + * @param name + */ + public SimpleJob(String name) { + super(name); + } /** * Public setter for the steps in this job. Overrides any calls to diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapStepExecutionDao.java b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapStepExecutionDao.java index 8a666ca4d..354bf096c 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapStepExecutionDao.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/repository/dao/MapStepExecutionDao.java @@ -52,6 +52,7 @@ public class MapStepExecutionDao implements StepExecutionDao { } public void saveStepExecution(StepExecution stepExecution) { + Assert.isTrue(stepExecution.getId() == null); Assert.isTrue(stepExecution.getVersion() == null); Assert.notNull(stepExecution.getJobExecutionId(), "JobExecution must be saved already."); @@ -61,11 +62,13 @@ public class MapStepExecutionDao implements StepExecutionDao { executions = TransactionAwareProxyFactory.createTransactionalMap(); executionsByJobExecutionId.put(stepExecution.getJobExecutionId(), executions); } + stepExecution.setId(currentId++); stepExecution.incrementVersion(); StepExecution copy = copy(stepExecution); executions.put(stepExecution.getId(), copy); executionsByStepExecutionId.put(stepExecution.getId(), copy); + } public void updateStepExecution(StepExecution stepExecution) { @@ -113,6 +116,7 @@ public class MapStepExecutionDao implements StepExecutionDao { for (StepExecution exec : result) { copy.add(copy(exec)); } + jobExecution.addStepExecutions(copy); return copy; } } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/TaskletStep.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/TaskletStep.java index dcd0acdb8..b1a5cf51a 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/TaskletStep.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/TaskletStep.java @@ -43,6 +43,7 @@ import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.interceptor.DefaultTransactionAttribute; import org.springframework.transaction.interceptor.TransactionAttribute; +import org.springframework.util.Assert; /** * Simple implementation of executing the step as a call to a {@link Tasklet}, @@ -101,6 +102,15 @@ public class TaskletStep extends AbstractStep { public TaskletStep(String name) { super(name); } + + /* (non-Javadoc) + * @see org.springframework.batch.core.step.AbstractStep#afterPropertiesSet() + */ + @Override + public void afterPropertiesSet() throws Exception { + super.afterPropertiesSet(); + Assert.notNull(transactionManager, "TransactionManager is mandatory"); + } /** * Public setter for the {@link PlatformTransactionManager}. diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/JobExecutionTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/JobExecutionTests.java index 4be3a5b12..26b6b2342 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/JobExecutionTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/JobExecutionTests.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import java.util.Arrays; import java.util.Date; import java.util.List; @@ -171,6 +172,13 @@ public class JobExecutionTests { assertEquals(1, execution.getStepExecutions().size()); } + @Test + public void testSetStepExecutions() throws Exception { + assertEquals(0, execution.getStepExecutions().size()); + execution.addStepExecutions(Arrays.asList(new StepExecution("step", execution))); + assertEquals(1, execution.getStepExecutions().size()); + } + @Test public void testStop() throws Exception { StepExecution stepExecution = execution.createStepExecution("step"); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/exlore/support/MapJobExplorerIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/exlore/support/MapJobExplorerIntegrationTests.java new file mode 100644 index 000000000..0c0c4dd85 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/exlore/support/MapJobExplorerIntegrationTests.java @@ -0,0 +1,82 @@ +/* + * 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.core.exlore.support; + +import static org.junit.Assert.assertEquals; + +import java.util.Set; + +import org.junit.Test; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.explore.JobExplorer; +import org.springframework.batch.core.explore.support.MapJobExplorerFactoryBean; +import org.springframework.batch.core.job.SimpleJob; +import org.springframework.batch.core.launch.support.SimpleJobLauncher; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.batch.core.step.tasklet.TaskletStep; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.batch.support.transaction.ResourcelessTransactionManager; +import org.springframework.core.task.SimpleAsyncTaskExecutor; + +/** + * @author Dave Syer + * + */ +public class MapJobExplorerIntegrationTests { + + private boolean block = true; + + @Test + public void testRunningJobExecution() throws Exception { + SimpleJobLauncher jobLauncher = new SimpleJobLauncher(); + MapJobRepositoryFactoryBean repositoryFactory = new MapJobRepositoryFactoryBean(); + ResourcelessTransactionManager transactionManager = new ResourcelessTransactionManager(); + repositoryFactory.setTransactionManager(transactionManager); + repositoryFactory.afterPropertiesSet(); + JobRepository jobRepository = (JobRepository) repositoryFactory.getObject(); + jobLauncher.setJobRepository(jobRepository); + jobLauncher.setTaskExecutor(new SimpleAsyncTaskExecutor()); + jobLauncher.afterPropertiesSet(); + SimpleJob job = new SimpleJob("job"); + TaskletStep step = new TaskletStep("step"); + step.setTasklet(new Tasklet() { + public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { + while (block) { + Thread.sleep(100L); + } + return RepeatStatus.FINISHED; + } + }); + step.setTransactionManager(transactionManager); + step.setJobRepository(jobRepository); + step.afterPropertiesSet(); + job.addStep(step); + job.setJobRepository(jobRepository); + job.afterPropertiesSet(); + jobLauncher.run(job, new JobParametersBuilder().addString("test", getClass().getName()).toJobParameters()); + Thread.sleep(500L); + JobExplorer explorer = (JobExplorer) new MapJobExplorerFactoryBean().getObject(); + Set executions = explorer.findRunningJobExecutions("job"); + assertEquals(1, executions.size()); + assertEquals(1, executions.iterator().next().getStepExecutions().size()); + block = false; + } +}