Skip to content

Commit ebf156d

Browse files
fmbenhassinemminella
authored andcommitted
Make JobParametersBuilder#getNextJobParameters consistent with CommandLineJobRunner and JobOperator
Before this commit, JobParametersBuilder#getNextJobParameters was checking for restartability conditions. This is not only already done by the JobLauncher, but also makes it inconsistent with the behaviour of CommandLineJobRunner when used with "-next" option and JobOperator#startNextInstance, which is starting the next instance in sequence based on the incrementer without dealing with restartability. This commit fixes the JobParametersBuilder#getNextJobParameters to behave like the CommandLineJobRunner and JobOperator in regards to starting the next instance. Resolves BATCH-2711
1 parent f8f8a02 commit ebf156d

File tree

5 files changed

+43
-104
lines changed

5 files changed

+43
-104
lines changed

spring-batch-core/src/main/java/org/springframework/batch/core/JobParametersBuilder.java

Lines changed: 20 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
/**
3030
* Helper class for creating {@link JobParameters}. Useful because all
3131
* {@link JobParameter} objects are immutable, and must be instantiated separately
32-
* to ensure typesafety. Once created, it can be used in the
32+
* to ensure type safety. Once created, it can be used in the
3333
* same was a java.lang.StringBuilder (except, order is irrelevant), by adding
3434
* various parameter types and creating a valid {@link JobParameters} once
3535
* finished.<br>
@@ -239,66 +239,46 @@ public JobParametersBuilder addJobParameters(JobParameters jobParameters) {
239239
/**
240240
* Initializes the {@link JobParameters} based on the state of the {@link Job}. This
241241
* should be called after all parameters have been entered into the builder.
242+
* All parameters already set on this builder instance will be appended to
243+
* those retrieved from the job incrementer, overriding any with the same key (Same
244+
* behaviour as {@link org.springframework.batch.core.launch.support.CommandLineJobRunner}
245+
* with "-next" option and {@link org.springframework.batch.core.launch.JobOperator#startNextInstance(String)})
242246
*
243247
* @param job the job for which the {@link JobParameters} are being constructed.
244248
* @return a reference to this object.
245249
*
246250
* @since 4.0
247251
*/
248252
public JobParametersBuilder getNextJobParameters(Job job) {
249-
if(this.jobExplorer == null) {
250-
throw new IllegalStateException("A JobExplore is required to get next job parameters");
251-
}
253+
Assert.state(this.jobExplorer != null, "A JobExplorer is required to get next job parameters");
254+
Assert.notNull(job, "Job must not be null");
255+
Assert.notNull(job.getJobParametersIncrementer(), "No job parameters incrementer found for job=" + job.getName());
252256

253257
String name = job.getName();
254-
JobParameters nextParameters = new JobParameters();
258+
JobParameters nextParameters;
255259
List<JobInstance> lastInstances = this.jobExplorer.getJobInstances(name, 0, 1);
256260
JobParametersIncrementer incrementer = job.getJobParametersIncrementer();
257261
if (lastInstances.isEmpty()) {
258262
// Start from a completely clean sheet
259-
if (incrementer != null) {
260-
nextParameters = incrementer.getNext(new JobParameters());
261-
}
263+
nextParameters = incrementer.getNext(new JobParameters());
262264
}
263265
else {
264-
List<JobExecution> previousExecutions = this.jobExplorer
265-
.getJobExecutions(lastInstances.get(0));
266-
JobExecution previousExecution = previousExecutions.get(0);
267-
if (previousExecution == null) {
266+
List<JobExecution> previousExecutions = this.jobExplorer.getJobExecutions(lastInstances.get(0));
267+
if (previousExecutions.isEmpty()) {
268268
// Normally this will not happen - an instance exists with no executions
269-
if (incrementer != null) {
270-
nextParameters = incrementer.getNext(new JobParameters());
271-
}
272-
}
273-
else if (isStoppedOrFailed(previousExecution) && job.isRestartable()) {
274-
// Retry a failed or stopped execution
275-
nextParameters = previousExecution.getJobParameters();
276-
// Non-identifying additional parameters can be removed to a retry
277-
removeNonIdentifying(this.parameterMap);
269+
nextParameters = incrementer.getNext(new JobParameters());
278270
}
279-
else if (incrementer != null) {
280-
// New instance so increment the parameters if we can
271+
else {
272+
JobExecution previousExecution = previousExecutions.get(0);
281273
nextParameters = incrementer.getNext(previousExecution.getJobParameters());
282274
}
283275
}
284276

285-
this.parameterMap = addJobParameters(nextParameters)
286-
.toJobParameters()
287-
.getParameters();
277+
// start with parameters from the incrementer
278+
Map<String, JobParameter> nextParametersMap = new HashMap<>(nextParameters.getParameters());
279+
// append new parameters (overriding those with the same key)
280+
nextParametersMap.putAll(this.parameterMap);
281+
this.parameterMap = nextParametersMap;
288282
return this;
289283
}
290-
291-
private void removeNonIdentifying(Map<String, JobParameter> parameters) {
292-
HashMap<String, JobParameter> copy = new HashMap<>(parameters);
293-
for (Map.Entry<String, JobParameter> parameter : copy.entrySet()) {
294-
if (!parameter.getValue().isIdentifying()) {
295-
parameters.remove(parameter.getKey());
296-
}
297-
}
298-
}
299-
300-
private boolean isStoppedOrFailed(JobExecution execution) {
301-
BatchStatus status = execution.getStatus();
302-
return (status == BatchStatus.STOPPED || status == BatchStatus.FAILED);
303-
}
304284
}

spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/CommandLineJobRunner.java

Lines changed: 5 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@
2121
import java.util.ArrayList;
2222
import java.util.Arrays;
2323
import java.util.Collections;
24-
import java.util.HashMap;
2524
import java.util.LinkedHashSet;
2625
import java.util.List;
27-
import java.util.Map;
2826
import java.util.Properties;
2927
import java.util.Set;
3028

@@ -36,8 +34,8 @@
3634
import org.springframework.batch.core.Job;
3735
import org.springframework.batch.core.JobExecution;
3836
import org.springframework.batch.core.JobInstance;
39-
import org.springframework.batch.core.JobParameter;
4037
import org.springframework.batch.core.JobParameters;
38+
import org.springframework.batch.core.JobParametersBuilder;
4139
import org.springframework.batch.core.JobParametersIncrementer;
4240
import org.springframework.batch.core.configuration.JobLocator;
4341
import org.springframework.batch.core.converter.DefaultJobParametersConverter;
@@ -47,7 +45,6 @@
4745
import org.springframework.batch.core.launch.JobExecutionNotRunningException;
4846
import org.springframework.batch.core.launch.JobExecutionNotStoppedException;
4947
import org.springframework.batch.core.launch.JobLauncher;
50-
import org.springframework.batch.core.launch.JobParametersNotFoundException;
5148
import org.springframework.batch.core.launch.NoSuchJobException;
5249
import org.springframework.batch.core.repository.JobRepository;
5350
import org.springframework.beans.factory.BeanDefinitionStoreException;
@@ -356,10 +353,9 @@ int start(String jobPath, String jobIdentifier, String[] parameters, Set<String>
356353
}
357354

358355
if (opts.contains("-next")) {
359-
JobParameters nextParameters = getNextJobParameters(job);
360-
Map<String, JobParameter> map = new HashMap<String, JobParameter>(nextParameters.getParameters());
361-
map.putAll(jobParameters.getParameters());
362-
jobParameters = new JobParameters(map);
356+
jobParameters = new JobParametersBuilder(jobParameters, jobExplorer)
357+
.getNextJobParameters(job)
358+
.toJobParameters();
363359
}
364360

365361
JobExecution jobExecution = launcher.run(job, jobParameters);
@@ -469,35 +465,6 @@ private Long getLongIdentifier(String jobIdentifier) {
469465
}
470466
}
471467

472-
/**
473-
* @param job the job that we need to find the next parameters for
474-
* @return the next job parameters if they can be located
475-
* @throws JobParametersNotFoundException if there is a problem
476-
*/
477-
private JobParameters getNextJobParameters(Job job) throws JobParametersNotFoundException {
478-
String jobIdentifier = job.getName();
479-
JobParameters jobParameters;
480-
List<JobInstance> lastInstances = jobExplorer.getJobInstances(jobIdentifier, 0, 1);
481-
482-
JobParametersIncrementer incrementer = job.getJobParametersIncrementer();
483-
if (incrementer == null) {
484-
throw new JobParametersNotFoundException("No job parameters incrementer found for job=" + jobIdentifier);
485-
}
486-
487-
if (lastInstances.isEmpty()) {
488-
jobParameters = incrementer.getNext(new JobParameters());
489-
if (jobParameters == null) {
490-
throw new JobParametersNotFoundException("No bootstrap parameters found from incrementer for job="
491-
+ jobIdentifier);
492-
}
493-
}
494-
else {
495-
List<JobExecution> lastExecutions = jobExplorer.getJobExecutions(lastInstances.get(0));
496-
jobParameters = incrementer.getNext(lastExecutions.get(0).getJobParameters());
497-
}
498-
return jobParameters;
499-
}
500-
501468
/**
502469
* Launch a batch job using a {@link CommandLineJobRunner}. Creates a new
503470
* Spring context for the job execution, and uses a common parent for all
@@ -515,7 +482,7 @@ private JobParameters getNextJobParameters(Job job) throws JobParametersNotFound
515482
* interpreted either as the name of the job or the id of the job execution
516483
* that failed.</li>
517484
* <li>-next: (optional) if the job has a {@link JobParametersIncrementer}
518-
* that can be used to launch the next in a sequence</li>
485+
* that can be used to launch the next instance in a sequence</li>
519486
* <li>jobPath: the xml application context containing a {@link Job}
520487
* <li>jobIdentifier: the bean id of the job or id of the failed execution
521488
* in the case of a restart.

spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/SimpleJobOperator.java

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2013 the original author or authors.
2+
* Copyright 2006-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@
3131
import org.springframework.batch.core.JobExecution;
3232
import org.springframework.batch.core.JobInstance;
3333
import org.springframework.batch.core.JobParameters;
34-
import org.springframework.batch.core.JobParametersIncrementer;
34+
import org.springframework.batch.core.JobParametersBuilder;
3535
import org.springframework.batch.core.JobParametersInvalidException;
3636
import org.springframework.batch.core.Step;
3737
import org.springframework.batch.core.StepExecution;
@@ -45,7 +45,6 @@
4545
import org.springframework.batch.core.launch.JobInstanceAlreadyExistsException;
4646
import org.springframework.batch.core.launch.JobLauncher;
4747
import org.springframework.batch.core.launch.JobOperator;
48-
import org.springframework.batch.core.launch.JobParametersNotFoundException;
4948
import org.springframework.batch.core.launch.NoSuchJobException;
5049
import org.springframework.batch.core.launch.NoSuchJobExecutionException;
5150
import org.springframework.batch.core.launch.NoSuchJobInstanceException;
@@ -79,6 +78,7 @@
7978
* @author Dave Syer
8079
* @author Lucas Ward
8180
* @author Will Schipp
81+
* @author Mahmoud Ben Hassine
8282
* @since 2.0
8383
*/
8484
public class SimpleJobOperator implements JobOperator, InitializingBean {
@@ -334,30 +334,15 @@ public Long start(String jobName, String parameters) throws NoSuchJobException,
334334
* @see JobOperator#startNextInstance(String )
335335
*/
336336
@Override
337-
public Long startNextInstance(String jobName) throws NoSuchJobException, JobParametersNotFoundException,
337+
public Long startNextInstance(String jobName) throws NoSuchJobException,
338338
UnexpectedJobExecutionException, JobParametersInvalidException {
339339

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

342342
Job job = jobRegistry.getJob(jobName);
343-
List<JobInstance> lastInstances = jobExplorer.getJobInstances(jobName, 0, 1);
344-
345-
JobParametersIncrementer incrementer = job.getJobParametersIncrementer();
346-
if (incrementer == null) {
347-
throw new JobParametersNotFoundException("No job parameters incrementer found for job=" + jobName);
348-
}
349-
350-
JobParameters parameters;
351-
if (lastInstances.isEmpty()) {
352-
parameters = incrementer.getNext(new JobParameters());
353-
if (parameters == null) {
354-
throw new JobParametersNotFoundException("No bootstrap parameters found for job=" + jobName);
355-
}
356-
}
357-
else {
358-
List<JobExecution> lastExecutions = jobExplorer.getJobExecutions(lastInstances.get(0));
359-
parameters = incrementer.getNext(lastExecutions.get(0).getJobParameters());
360-
}
343+
JobParameters parameters = new JobParametersBuilder(jobExplorer)
344+
.getNextJobParameters(job)
345+
.toJobParameters();
361346

362347
logger.info(String.format("Attempting to launch job with name=%s and parameters=%s", jobName, parameters));
363348
try {

spring-batch-core/src/test/java/org/springframework/batch/core/JobParametersBuilderTests.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
import java.util.Properties;
2424

2525
import org.junit.Before;
26+
import org.junit.Rule;
2627
import org.junit.Test;
28+
import org.junit.rules.ExpectedException;
2729

2830
import org.springframework.batch.core.explore.JobExplorer;
2931
import org.springframework.batch.core.job.SimpleJob;
@@ -56,6 +58,9 @@ public class JobParametersBuilderTests {
5658

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

61+
@Rule
62+
public ExpectedException expectedException = ExpectedException.none();
63+
5964
@Before
6065
public void initialize() {
6166
this.job = new SimpleJob("simpleJob");
@@ -198,9 +203,10 @@ public void testGetNextJobParametersFirstRun(){
198203

199204
@Test
200205
public void testGetNextJobParametersNoIncrementer(){
206+
expectedException.expect(IllegalArgumentException.class);
207+
expectedException.expectMessage("No job parameters incrementer found for job=simpleJob");
201208
initializeForNextJobParameters();
202209
this.parametersBuilder.getNextJobParameters(this.job);
203-
baseJobParametersVerify(this.parametersBuilder.toJobParameters(), 3);
204210
}
205211

206212
@Test
@@ -226,14 +232,13 @@ public void testGetNextJobParametersRestartable(){
226232
initializeForNextJobParameters();
227233
this.parametersBuilder.addLong("NON_IDENTIFYING_LONG", new Long(1), false);
228234
this.parametersBuilder.getNextJobParameters(this.job);
229-
baseJobParametersVerify(this.parametersBuilder.toJobParameters(), 3);
235+
baseJobParametersVerify(this.parametersBuilder.toJobParameters(), 5);
230236
}
231237

232238
@Test
233239
public void testGetNextJobParametersNoPreviousExecution(){
234240
this.job.setJobParametersIncrementer(new RunIdIncrementer());
235241
this.jobInstanceList.add(new JobInstance(1L, "simpleJobInstance"));
236-
this.jobExecutionList.add(null);
237242
when(this.jobExplorer.getJobInstances("simpleJob",0,1)).thenReturn(this.jobInstanceList);
238243
when(this.jobExplorer.getJobExecutions(any())).thenReturn(this.jobExecutionList);
239244
initializeForNextJobParameters();

spring-batch-core/src/test/java/org/springframework/batch/core/launch/support/SimpleJobOperatorTests.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2013 the original author or authors.
2+
* Copyright 2006-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -67,6 +67,7 @@
6767
/**
6868
* @author Dave Syer
6969
* @author Will Schipp
70+
* @author Mahmoud Ben Hassine
7071
*
7172
*/
7273
public class SimpleJobOperatorTests {
@@ -153,6 +154,7 @@ public void testMandatoryProperties() throws Exception {
153154
*/
154155
@Test
155156
public void testStartNextInstanceSunnyDay() throws Exception {
157+
jobParameters = new JobParameters();
156158
JobInstance jobInstance = new JobInstance(321L, "foo");
157159
when(jobExplorer.getJobInstances("foo", 0, 1)).thenReturn(Collections.singletonList(jobInstance));
158160
when(jobExplorer.getJobExecutions(jobInstance)).thenReturn(Collections.singletonList(new JobExecution(jobInstance, new JobParameters())));

0 commit comments

Comments
 (0)