From 342cb1375fc3d267b3d86fbb1775965796aa36dd Mon Sep 17 00:00:00 2001 From: nebhale Date: Fri, 8 Feb 2008 17:06:06 +0000 Subject: [PATCH] [BATCH-334] Added a TaskletStep implementation --- .../execution/step/tasklet/TaskletStep.java | 81 ++++++++++++++ .../step/tasklet/TaskletStepTest.java | 105 ++++++++++++++++++ 2 files changed, 186 insertions(+) create mode 100644 spring-batch-execution/src/main/java/org/springframework/batch/execution/step/tasklet/TaskletStep.java create mode 100644 spring-batch-execution/src/test/java/org/springframework/batch/execution/step/tasklet/TaskletStepTest.java diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/tasklet/TaskletStep.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/tasklet/TaskletStep.java new file mode 100644 index 000000000..936530fbf --- /dev/null +++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/tasklet/TaskletStep.java @@ -0,0 +1,81 @@ +/* + * 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.step.tasklet; + +import java.util.Date; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.batch.core.domain.BatchStatus; +import org.springframework.batch.core.domain.Step; +import org.springframework.batch.core.domain.StepExecution; +import org.springframework.batch.core.domain.StepInterruptedException; +import org.springframework.batch.core.domain.StepSupport; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.tasklet.Tasklet; +import org.springframework.batch.io.exception.BatchCriticalException; +import org.springframework.batch.repeat.ExitStatus; + +/** + * A {@link Step} that executes a {@link Tasklet} directly. This step does not manage transactions or any looping + * functionality. The tasklet should do this on its own. + * + * @author Ben Hale + */ +public class TaskletStep extends StepSupport { + + private static final Log logger = LogFactory.getLog(TaskletStep.class); + + private final Tasklet tasklet; + + private final JobRepository jobRepository; + + /** + * Creates a new Step for executing a Tasklet + * + * @param tasklet The Tasklet to execute + * @param jobRepository The JobRepository to use for persistence of incremental state + */ + public TaskletStep(Tasklet tasklet, JobRepository jobRepository) { + this.tasklet = tasklet; + this.jobRepository = jobRepository; + } + + public void execute(StepExecution stepExecution) throws StepInterruptedException, BatchCriticalException { + stepExecution.setStartTime(new Date()); + updateStatus(stepExecution, BatchStatus.STARTED); + + ExitStatus exitStatus = ExitStatus.FAILED; + try { + exitStatus = tasklet.execute(); + updateStatus(stepExecution, BatchStatus.COMPLETED); + } catch (Exception e) { + logger.error("Encountered an error running the tasklet"); + updateStatus(stepExecution, BatchStatus.FAILED); + throw new BatchCriticalException(e); + } finally { + stepExecution.setExitStatus(exitStatus); + stepExecution.setEndTime(new Date()); + jobRepository.saveOrUpdate(stepExecution); + } + } + + private void updateStatus(StepExecution stepExecution, BatchStatus status) { + stepExecution.setStatus(status); + jobRepository.saveOrUpdate(stepExecution); + } + +} diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/tasklet/TaskletStepTest.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/tasklet/TaskletStepTest.java new file mode 100644 index 000000000..7c104c2aa --- /dev/null +++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/step/tasklet/TaskletStepTest.java @@ -0,0 +1,105 @@ +package org.springframework.batch.execution.step.tasklet; + +import junit.framework.TestCase; + +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.StepExecution; +import org.springframework.batch.core.domain.StepInstance; +import org.springframework.batch.core.domain.StepInterruptedException; +import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.tasklet.Tasklet; +import org.springframework.batch.io.exception.BatchCriticalException; +import org.springframework.batch.repeat.ExitStatus; + +public class TaskletStepTest extends TestCase { + + private StepExecution stepExecution; + + protected void setUp() throws Exception { + stepExecution = new StepExecution(new StepInstance(new Long(11)), new JobExecution(new JobInstance( + new Long(0L), new JobParameters()), new Long(12))); + } + + public void testSuccessfulExecution() throws StepInterruptedException, BatchCriticalException { + TaskletStep step = new TaskletStep(new StubTasklet(false, false), new StubJobRepository()); + step.execute(stepExecution); + assertNotNull(stepExecution.getStartTime()); + assertSame(ExitStatus.FINISHED, stepExecution.getExitStatus()); + assertNotNull(stepExecution.getEndTime()); + } + + public void testFailureExecution() throws StepInterruptedException, BatchCriticalException { + TaskletStep step = new TaskletStep(new StubTasklet(true, false), new StubJobRepository()); + step.execute(stepExecution); + assertNotNull(stepExecution.getStartTime()); + assertSame(ExitStatus.FAILED, stepExecution.getExitStatus()); + assertNotNull(stepExecution.getEndTime()); + } + + public void testExceptionExecution() throws StepInterruptedException, BatchCriticalException { + TaskletStep step = new TaskletStep(new StubTasklet(false, true), new StubJobRepository()); + try { + step.execute(stepExecution); + fail(); + } catch (BatchCriticalException e) { + assertNotNull(stepExecution.getStartTime()); + assertSame(ExitStatus.FAILED, stepExecution.getExitStatus()); + assertNotNull(stepExecution.getEndTime()); + } + } + + private class StubTasklet implements Tasklet { + + private final boolean exitFailure; + + private final boolean throwException; + + public StubTasklet(boolean exitFailure, boolean throwException) { + this.exitFailure = exitFailure; + this.throwException = throwException; + } + + public ExitStatus execute() throws Exception { + if (throwException) { + throw new Exception(); + } + + if (exitFailure) { + return ExitStatus.FAILED; + } + + return ExitStatus.FINISHED; + } + + } + + private class StubJobRepository implements JobRepository { + + public JobExecution createJobExecution(Job job, JobParameters jobParameters) + throws JobExecutionAlreadyRunningException { + // TODO Auto-generated method stub + return null; + } + + public void saveOrUpdate(JobExecution jobExecution) { + // TODO Auto-generated method stub + } + + public void saveOrUpdate(StepExecution stepExecution) { + // TODO Auto-generated method stub + } + + public void update(JobInstance jobInstance) { + // TODO Auto-generated method stub + } + + public void update(StepInstance stepInstance) { + // TODO Auto-generated method stub + } + + } +}