Skip to content

Make JobParametersBuilder#getNextJobParameters consistent with CommandLineJobRunner and JobOperator #660

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
/**
* Helper class for creating {@link JobParameters}. Useful because all
* {@link JobParameter} objects are immutable, and must be instantiated separately
* to ensure typesafety. Once created, it can be used in the
* to ensure type safety. Once created, it can be used in the
* same was a java.lang.StringBuilder (except, order is irrelevant), by adding
* various parameter types and creating a valid {@link JobParameters} once
* finished.<br>
Expand Down Expand Up @@ -239,66 +239,46 @@ public JobParametersBuilder addJobParameters(JobParameters jobParameters) {
/**
* Initializes the {@link JobParameters} based on the state of the {@link Job}. This
* should be called after all parameters have been entered into the builder.
* All parameters already set on this builder instance will be appended to
* those retrieved from the job incrementer, overriding any with the same key (Same
* behaviour as {@link org.springframework.batch.core.launch.support.CommandLineJobRunner}
* with "-next" option and {@link org.springframework.batch.core.launch.JobOperator#startNextInstance(String)})
*
* @param job the job for which the {@link JobParameters} are being constructed.
* @return a reference to this object.
*
* @since 4.0
*/
public JobParametersBuilder getNextJobParameters(Job job) {
if(this.jobExplorer == null) {
throw new IllegalStateException("A JobExplore is required to get next job parameters");
}
Assert.state(this.jobExplorer != null, "A JobExplorer is required to get next job parameters");
Assert.notNull(job, "Job must not be null");
Assert.notNull(job.getJobParametersIncrementer(), "No job parameters incrementer found for job=" + job.getName());

String name = job.getName();
JobParameters nextParameters = new JobParameters();
JobParameters nextParameters;
List<JobInstance> lastInstances = this.jobExplorer.getJobInstances(name, 0, 1);
JobParametersIncrementer incrementer = job.getJobParametersIncrementer();
if (lastInstances.isEmpty()) {
// Start from a completely clean sheet
if (incrementer != null) {
nextParameters = incrementer.getNext(new JobParameters());
}
nextParameters = incrementer.getNext(new JobParameters());
}
else {
List<JobExecution> previousExecutions = this.jobExplorer
.getJobExecutions(lastInstances.get(0));
JobExecution previousExecution = previousExecutions.get(0);
if (previousExecution == null) {
List<JobExecution> previousExecutions = this.jobExplorer.getJobExecutions(lastInstances.get(0));
if (previousExecutions.isEmpty()) {
// Normally this will not happen - an instance exists with no executions
if (incrementer != null) {
nextParameters = incrementer.getNext(new JobParameters());
}
}
else if (isStoppedOrFailed(previousExecution) && job.isRestartable()) {
// Retry a failed or stopped execution
nextParameters = previousExecution.getJobParameters();
// Non-identifying additional parameters can be removed to a retry
removeNonIdentifying(this.parameterMap);
nextParameters = incrementer.getNext(new JobParameters());
}
else if (incrementer != null) {
// New instance so increment the parameters if we can
else {
JobExecution previousExecution = previousExecutions.get(0);
nextParameters = incrementer.getNext(previousExecution.getJobParameters());
}
}

this.parameterMap = addJobParameters(nextParameters)
.toJobParameters()
.getParameters();
// start with parameters from the incrementer
Map<String, JobParameter> nextParametersMap = new HashMap<>(nextParameters.getParameters());
// append new parameters (overriding those with the same key)
nextParametersMap.putAll(this.parameterMap);
this.parameterMap = nextParametersMap;
return this;
}

private void removeNonIdentifying(Map<String, JobParameter> parameters) {
HashMap<String, JobParameter> copy = new HashMap<>(parameters);
for (Map.Entry<String, JobParameter> parameter : copy.entrySet()) {
if (!parameter.getValue().isIdentifying()) {
parameters.remove(parameter.getKey());
}
}
}

private boolean isStoppedOrFailed(JobExecution execution) {
BatchStatus status = execution.getStatus();
return (status == BatchStatus.STOPPED || status == BatchStatus.FAILED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

Expand All @@ -36,8 +34,8 @@
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameter;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.JobParametersIncrementer;
import org.springframework.batch.core.configuration.JobLocator;
import org.springframework.batch.core.converter.DefaultJobParametersConverter;
Expand All @@ -47,7 +45,6 @@
import org.springframework.batch.core.launch.JobExecutionNotRunningException;
import org.springframework.batch.core.launch.JobExecutionNotStoppedException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.JobParametersNotFoundException;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.beans.factory.BeanDefinitionStoreException;
Expand Down Expand Up @@ -356,10 +353,9 @@ int start(String jobPath, String jobIdentifier, String[] parameters, Set<String>
}

if (opts.contains("-next")) {
JobParameters nextParameters = getNextJobParameters(job);
Map<String, JobParameter> map = new HashMap<String, JobParameter>(nextParameters.getParameters());
map.putAll(jobParameters.getParameters());
jobParameters = new JobParameters(map);
jobParameters = new JobParametersBuilder(jobParameters, jobExplorer)
.getNextJobParameters(job)
.toJobParameters();
}

JobExecution jobExecution = launcher.run(job, jobParameters);
Expand Down Expand Up @@ -469,35 +465,6 @@ private Long getLongIdentifier(String jobIdentifier) {
}
}

/**
* @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 jobIdentifier = job.getName();
JobParameters jobParameters;
List<JobInstance> lastInstances = jobExplorer.getJobInstances(jobIdentifier, 0, 1);

JobParametersIncrementer incrementer = job.getJobParametersIncrementer();
if (incrementer == null) {
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="
+ jobIdentifier);
}
}
else {
List<JobExecution> lastExecutions = jobExplorer.getJobExecutions(lastInstances.get(0));
jobParameters = incrementer.getNext(lastExecutions.get(0).getJobParameters());
}
return jobParameters;
}

/**
* Launch a batch job using a {@link CommandLineJobRunner}. Creates a new
* Spring context for the job execution, and uses a common parent for all
Expand All @@ -515,7 +482,7 @@ private JobParameters getNextJobParameters(Job job) throws JobParametersNotFound
* interpreted either as the name of the job or the id of the job execution
* that failed.</li>
* <li>-next: (optional) if the job has a {@link JobParametersIncrementer}
* that can be used to launch the next in a sequence</li>
* that can be used to launch the next instance in a sequence</li>
* <li>jobPath: the xml application context containing a {@link Job}
* <li>jobIdentifier: the bean id of the job or id of the failed execution
* in the case of a restart.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2006-2013 the original author or authors.
* Copyright 2006-2018 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.
Expand Down Expand Up @@ -31,7 +31,7 @@
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersIncrementer;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
Expand All @@ -45,7 +45,6 @@
import org.springframework.batch.core.launch.JobInstanceAlreadyExistsException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.batch.core.launch.JobParametersNotFoundException;
import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.batch.core.launch.NoSuchJobExecutionException;
import org.springframework.batch.core.launch.NoSuchJobInstanceException;
Expand Down Expand Up @@ -79,6 +78,7 @@
* @author Dave Syer
* @author Lucas Ward
* @author Will Schipp
* @author Mahmoud Ben Hassine
* @since 2.0
*/
public class SimpleJobOperator implements JobOperator, InitializingBean {
Expand Down Expand Up @@ -334,30 +334,15 @@ public Long start(String jobName, String parameters) throws NoSuchJobException,
* @see JobOperator#startNextInstance(String )
*/
@Override
public Long startNextInstance(String jobName) throws NoSuchJobException, JobParametersNotFoundException,
public Long startNextInstance(String jobName) throws NoSuchJobException,
UnexpectedJobExecutionException, JobParametersInvalidException {

logger.info("Locating parameters for next instance of job with name=" + jobName);

Job job = jobRegistry.getJob(jobName);
List<JobInstance> lastInstances = jobExplorer.getJobInstances(jobName, 0, 1);

JobParametersIncrementer incrementer = job.getJobParametersIncrementer();
if (incrementer == null) {
throw new JobParametersNotFoundException("No job parameters incrementer found for job=" + jobName);
}

JobParameters parameters;
if (lastInstances.isEmpty()) {
parameters = incrementer.getNext(new JobParameters());
if (parameters == null) {
throw new JobParametersNotFoundException("No bootstrap parameters found for job=" + jobName);
}
}
else {
List<JobExecution> lastExecutions = jobExplorer.getJobExecutions(lastInstances.get(0));
parameters = incrementer.getNext(lastExecutions.get(0).getJobParameters());
}
JobParameters parameters = new JobParametersBuilder(jobExplorer)
.getNextJobParameters(job)
.toJobParameters();

logger.info(String.format("Attempting to launch job with name=%s and parameters=%s", jobName, parameters));
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
import java.util.Properties;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.job.SimpleJob;
Expand Down Expand Up @@ -56,6 +58,9 @@ public class JobParametersBuilderTests {

private Date date = new Date(System.currentTimeMillis());

@Rule
public ExpectedException expectedException = ExpectedException.none();

@Before
public void initialize() {
this.job = new SimpleJob("simpleJob");
Expand Down Expand Up @@ -198,9 +203,10 @@ public void testGetNextJobParametersFirstRun(){

@Test
public void testGetNextJobParametersNoIncrementer(){
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("No job parameters incrementer found for job=simpleJob");
initializeForNextJobParameters();
this.parametersBuilder.getNextJobParameters(this.job);
baseJobParametersVerify(this.parametersBuilder.toJobParameters(), 3);
}

@Test
Expand All @@ -226,14 +232,13 @@ public void testGetNextJobParametersRestartable(){
initializeForNextJobParameters();
this.parametersBuilder.addLong("NON_IDENTIFYING_LONG", new Long(1), false);
this.parametersBuilder.getNextJobParameters(this.job);
baseJobParametersVerify(this.parametersBuilder.toJobParameters(), 3);
baseJobParametersVerify(this.parametersBuilder.toJobParameters(), 5);
}

@Test
public void testGetNextJobParametersNoPreviousExecution(){
this.job.setJobParametersIncrementer(new RunIdIncrementer());
this.jobInstanceList.add(new JobInstance(1L, "simpleJobInstance"));
this.jobExecutionList.add(null);
when(this.jobExplorer.getJobInstances("simpleJob",0,1)).thenReturn(this.jobInstanceList);
when(this.jobExplorer.getJobExecutions(any())).thenReturn(this.jobExecutionList);
initializeForNextJobParameters();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2006-2013 the original author or authors.
* Copyright 2006-2018 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.
Expand Down Expand Up @@ -67,6 +67,7 @@
/**
* @author Dave Syer
* @author Will Schipp
* @author Mahmoud Ben Hassine
*
*/
public class SimpleJobOperatorTests {
Expand Down Expand Up @@ -153,6 +154,7 @@ public void testMandatoryProperties() throws Exception {
*/
@Test
public void testStartNextInstanceSunnyDay() throws Exception {
jobParameters = new JobParameters();
JobInstance jobInstance = new JobInstance(321L, "foo");
when(jobExplorer.getJobInstances("foo", 0, 1)).thenReturn(Collections.singletonList(jobInstance));
when(jobExplorer.getJobExecutions(jobInstance)).thenReturn(Collections.singletonList(new JobExecution(jobInstance, new JobParameters())));
Expand Down