From 2826e277c5bd484e114bac52f629abd013f0faed Mon Sep 17 00:00:00 2001 From: dsyer Date: Thu, 31 Dec 2009 13:45:39 +0000 Subject: [PATCH] BATCH-1376: add -restart of job execution by id --- .../launch/support/CommandLineJobRunner.java | 110 ++++++++++-------- .../support/CommandLineJobRunnerTests.java | 26 +++-- 2 files changed, 79 insertions(+), 57 deletions(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/CommandLineJobRunner.java b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/CommandLineJobRunner.java index 1d84f7d29..ab9f178e6 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/CommandLineJobRunner.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/CommandLineJobRunner.java @@ -38,6 +38,7 @@ import org.springframework.batch.core.configuration.JobLocator; import org.springframework.batch.core.converter.DefaultJobParametersConverter; import org.springframework.batch.core.converter.JobParametersConverter; import org.springframework.batch.core.explore.JobExplorer; +import org.springframework.batch.core.launch.JobExecutionNotFailedException; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.launch.JobParametersNotFoundException; import org.springframework.beans.factory.BeanDefinitionStoreException; @@ -89,7 +90,7 @@ import org.springframework.util.StringUtils; *

* * - * jobPath jobName (jobParameters)* + * jobPath jobIdentifier (jobParameters)* * * *

@@ -99,7 +100,7 @@ import org.springframework.util.StringUtils; *

  • -restart: (optional) to restart the last failed execution
  • *
  • -next: (optional) to start the next in a sequence according to the * {@link JobParametersIncrementer} in the {@link Job}
  • - *
  • jobName: the bean id of the job. + *
  • jobIdentifier: the bean id of the job. *
  • jobParameters: 0 to many parameters that will be used to launch a job. * *

    @@ -130,10 +131,10 @@ import org.springframework.util.StringUtils; * loaded this way. If none is contained in the bean factory (it searches by * type) then a {@link BeanDefinitionStoreException} will be thrown. The same * exception will also be thrown if there is more than one present. Assuming the - * JobLauncher has been set correctly, the jobName argument will be used to - * obtain an actual {@link Job}. If a {@link JobLocator} has been set, then it - * will be used, if not the beanFactory will be asked, using the jobName as the - * bean id. + * JobLauncher has been set correctly, the jobIdentifier argument will be used + * to obtain an actual {@link Job}. If a {@link JobLocator} has been set, then + * it will be used, if not the beanFactory will be asked, using the + * jobIdentifier as the bean id. *

    * * @author Dave Syer @@ -248,7 +249,7 @@ public class CommandLineJobRunner { * job paths. If a JobLocator has been set, then use it to obtain an actual * job, if not ask the context for it. */ - int start(String jobPath, String jobName, String[] parameters, Set opts) { + int start(String jobPath, String jobIdentifier, String[] parameters, Set opts) { ConfigurableApplicationContext context = null; @@ -264,13 +265,7 @@ public class CommandLineJobRunner { "A JobExplorer must be provided for a restart or start next operation. Please add one to the configuration."); } - Job job; - if (jobLocator != null) { - job = jobLocator.getJob(jobName); - } - else { - job = (Job) context.getBean(jobName); - } + String jobName = jobIdentifier; JobParameters jobParameters = jobParametersConverter.getJobParameters(StringUtils .splitArrayElementsIntoProperties(parameters, "=")); @@ -279,9 +274,23 @@ public class CommandLineJobRunner { + ". If parameters are provided they should be in the form name=value (no whitespace)."); if (opts.contains("-restart")) { - jobParameters = getLastFailedJobParameters(jobName); + JobExecution jobExecution = getLastFailedJobExecution(jobIdentifier); + if (jobExecution == null) { + throw new JobExecutionNotFailedException("No failed or stopped execution found for job=" + jobIdentifier); + } + jobParameters = jobExecution.getJobInstance().getJobParameters(); + jobName = jobExecution.getJobInstance().getJobName(); } - else if (opts.contains("-next")) { + + Job job; + if (jobLocator != null) { + job = jobLocator.getJob(jobName); + } + else { + job = (Job) context.getBean(jobName); + } + + if (opts.contains("-next")) { JobParameters nextParameters = getNextJobParameters(job); Map map = new HashMap(nextParameters.getParameters()); map.putAll(jobParameters.getParameters()); @@ -306,21 +315,23 @@ public class CommandLineJobRunner { } /** - * @param jobName + * @param jobIdentifier * @return * @throws JobParametersNotFoundException */ - private JobParameters getLastFailedJobParameters(String jobName) throws JobParametersNotFoundException { + private JobExecution getLastFailedJobExecution(String jobIdentifier) { + + Long executionId = getLongIdentifier(jobIdentifier); + if (executionId != null) { + JobExecution jobExecution = jobExplorer.getJobExecution(executionId); + if (jobExecution.getStatus().isGreaterThan(BatchStatus.STOPPING)) { + return jobExecution; + } + } int start = 0; int count = 100; - List lastInstances = jobExplorer.getJobInstances(jobName, start, count); - - JobParameters jobParameters = null; - - if (lastInstances.isEmpty()) { - throw new JobParametersNotFoundException("No job instance found for job=" + jobName); - } + List lastInstances = jobExplorer.getJobInstances(jobIdentifier, start, count); while (!lastInstances.isEmpty()) { @@ -331,47 +342,49 @@ public class CommandLineJobRunner { } JobExecution jobExecution = jobExecutions.get(jobExecutions.size() - 1); if (jobExecution.getStatus().isGreaterThan(BatchStatus.STOPPING)) { - jobParameters = jobInstance.getJobParameters(); - break; + return jobExecution; } } - if (jobParameters != null) { - break; - } - start += count; - lastInstances = jobExplorer.getJobInstances(jobName, start, count); + lastInstances = jobExplorer.getJobInstances(jobIdentifier, start, count); } - if (jobParameters == null) { - throw new JobParametersNotFoundException("No failed or stopped execution found for job=" + jobName); - } - return jobParameters; + return null; } + private Long getLongIdentifier(String jobIdentifier) { + try { + return new Long(jobIdentifier); + } + catch (NumberFormatException e) { + // Not an ID - must be a name + return null; + } + } + /** * @param job the job that we need to find the next parameters for * @return the next job parameters if they can be located * @throws JobParametersNotFoundException if there is a problem */ private JobParameters getNextJobParameters(Job job) throws JobParametersNotFoundException { - String jobName = job.getName(); + String jobIdentifier = job.getName(); JobParameters jobParameters; - List lastInstances = jobExplorer.getJobInstances(jobName, 0, 1); + List lastInstances = jobExplorer.getJobInstances(jobIdentifier, 0, 1); JobParametersIncrementer incrementer = job.getJobParametersIncrementer(); if (incrementer == null) { - throw new JobParametersNotFoundException("No job parameters incrementer found for job=" + jobName); + throw new JobParametersNotFoundException("No job parameters incrementer found for job=" + jobIdentifier); } if (lastInstances.isEmpty()) { jobParameters = incrementer.getNext(new JobParameters()); if (jobParameters == null) { throw new JobParametersNotFoundException("No bootstrap parameters found from incrementer for job=" - + jobName); + + jobIdentifier); } } else { @@ -393,11 +406,14 @@ public class CommandLineJobRunner { * @param args

    *

      *
    • -restart: (optional) if the job has failed or stopped and the most - * recent execution should be restarted
    • + * should be restarted. If specified then the jobIdentifier parameter can be + * interpreted either as the name of the job or the id of teh job execution + * that failed. *
    • -next: (optional) if the job has a {@link JobParametersIncrementer} * that can be used to launch the next in a sequence
    • *
    • jobPath: the xml application context containing a {@link Job} - *
    • jobName: the bean id of the job. + *
    • jobIdentifier: the bean id of the job or id of the failed execution + * in the case of a restart. *
    • jobParameters: 0 to many parameters that will be used to launch a * job. *
    @@ -414,7 +430,7 @@ public class CommandLineJobRunner { int count = 0; String jobPath = null; - String jobName = null; + String jobIdentifier = null; for (String arg : args) { if (arg.startsWith("-")) { @@ -426,7 +442,7 @@ public class CommandLineJobRunner { jobPath = arg; break; case 1: - jobName = arg; + jobIdentifier = arg; break; default: params.add(arg); @@ -436,8 +452,8 @@ public class CommandLineJobRunner { } } - if (jobPath == null || jobName == null) { - String message = "At least 2 arguments are required: JobPath and JobName."; + if (jobPath == null || jobIdentifier == null) { + String message = "At least 2 arguments are required: JobPath and jobIdentifier."; logger.error(message); CommandLineJobRunner.message = message; command.exit(1); @@ -445,7 +461,7 @@ public class CommandLineJobRunner { String[] parameters = params.toArray(new String[params.size()]); - int result = command.start(jobPath, jobName, parameters, opts); + int result = command.start(jobPath, jobIdentifier, parameters, opts); command.exit(result); } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/launch/support/CommandLineJobRunnerTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/launch/support/CommandLineJobRunnerTests.java index 0a6b816de..684610cad 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/launch/support/CommandLineJobRunnerTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/launch/support/CommandLineJobRunnerTests.java @@ -140,6 +140,18 @@ public class CommandLineJobRunnerTests { assertEquals(jobParameters, StubJobLauncher.jobParameters); } + @Test + public void testRestartExecution() throws Throwable { + String[] args = new String[] { jobPath, "-restart", "11" }; + JobParameters jobParameters = new JobParametersBuilder().addString("foo", "bar").toJobParameters(); + JobExecution jobExecution = new JobExecution(new JobInstance(0L, jobParameters, jobName), 11L); + jobExecution.setStatus(BatchStatus.FAILED); + StubJobExplorer.jobExecution = jobExecution; + CommandLineJobRunner.main(args); + assertEquals(0, StubSystemExiter.status); + assertEquals(jobParameters, StubJobLauncher.jobParameters); + } + @Test public void testRestartNotFailed() throws Throwable { String[] args = new String[] { jobPath, "-restart", jobName }; @@ -152,16 +164,6 @@ public class CommandLineJobRunnerTests { .contains("No failed or stopped execution found")); } - @Test - public void testRestartNoParameters() throws Throwable { - String[] args = new String[] { jobPath, "-restart", jobName }; - StubJobExplorer.jobInstances = new ArrayList(); - CommandLineJobRunner.main(args); - assertEquals(1, StubSystemExiter.status); - String errorMessage = CommandLineJobRunner.getErrorMessage(); - assertTrue("Wrong error message: " + errorMessage, errorMessage.contains("No job instance found for job")); - } - @Test public void testNext() throws Throwable { String[] args = new String[] { jobPath, "-next", jobName, "bar=foo" }; @@ -255,12 +257,16 @@ public class CommandLineJobRunnerTests { public static class StubJobExplorer implements JobExplorer { static List jobInstances = new ArrayList(); + static JobExecution jobExecution; public Set findRunningJobExecutions(String jobName) { throw new UnsupportedOperationException(); } public JobExecution getJobExecution(Long executionId) { + if (jobExecution!=null) { + return jobExecution; + } throw new UnsupportedOperationException(); }