Skip to content

Commit 4eefb1d

Browse files
committed
Refine contribution #3972
Related to #3955
1 parent eccea80 commit 4eefb1d

File tree

5 files changed

+61
-113
lines changed

5 files changed

+61
-113
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2021 the original author or authors.
2+
* Copyright 2006-2022 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.

spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/CommandRunner.java

Lines changed: 24 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2021 the original author or authors.
2+
* Copyright 2006-2022 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.
@@ -19,50 +19,35 @@
1919
import java.io.IOException;
2020

2121
/**
22-
* Interface for executing commands. This abstraction is only
23-
* useful in order to allow classes that make {@link Runtime#exec} calls
24-
* to be testable, since the invoked command might not be
25-
* available during tests execution.
22+
* Strategy interface for executing commands. This abstraction is useful to decouple the
23+
* command execution from the enclosing tasklet so that implementations can be unit tested
24+
* in isolation.
2625
*
2726
* @author Stefano Cordio
28-
* @since FIXME
27+
* @author Mahmoud Ben Hassine
28+
* @since 5.0
2929
*/
3030
public interface CommandRunner {
3131

3232
/**
33-
* Executes the specified string command in a separate process with the
34-
* specified environment and working directory.
35-
*
36-
* @param command a specified system command.
37-
*
38-
* @param envp array of strings, each element of which
39-
* has environment variable settings in the format
40-
* <i>name</i>=<i>value</i>, or
41-
* {@code null} if the subprocess should inherit
42-
* the environment of the current process.
43-
*
44-
* @param dir the working directory of the subprocess, or
45-
* {@code null} if the subprocess should inherit
46-
* the working directory of the current process.
47-
*
48-
* @return A new {@link Process} object for managing the subprocess
49-
*
50-
* @throws SecurityException
51-
* If a security manager exists and its
52-
* {@link SecurityManager#checkExec checkExec}
53-
* method doesn't allow creation of the subprocess
54-
*
55-
* @throws IOException
56-
* If an I/O error occurs
57-
*
58-
* @throws NullPointerException
59-
* If {@code command} is {@code null},
60-
* or one of the elements of {@code envp} is {@code null}
61-
*
62-
* @throws IllegalArgumentException
63-
* If {@code command} is empty
64-
*
65-
* @see Runtime#exec(String, String[], File)
33+
* Executes the specified string command in a separate process with the specified
34+
* environment and working directory.
35+
* @param command a specified system command.
36+
* @param envp array of strings, each element of which has environment variable
37+
* settings in the format <i>name</i>=<i>value</i>, or {@code null} if the subprocess
38+
* should inherit the environment of the current process.
39+
* @param dir the working directory of the subprocess, or {@code null} if the
40+
* subprocess should inherit the working directory of the current process.
41+
* @return A new {@link Process} object for managing the subprocess
42+
* @throws SecurityException If a security manager exists and its
43+
* {@link SecurityManager#checkExec checkExec} method doesn't allow creation of the
44+
* subprocess
45+
* @throws IOException If an I/O error occurs
46+
* @throws NullPointerException If {@code command} is {@code null}, or one of the
47+
* elements of {@code envp} is {@code null}
48+
* @throws IllegalArgumentException If {@code command} is empty
49+
*
50+
* @see Runtime#exec(String, String[], File)
6651
*/
6752
Process exec(String command, String[] envp, File dir) throws IOException;
6853

spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/JvmCommandRunner.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2021 the original author or authors.
2+
* Copyright 2006-2022 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.
@@ -20,12 +20,12 @@
2020

2121
/**
2222
* Implementation of the {@link CommandRunner} interface that calls the standard
23-
* {@link Runtime#exec} method. It should be noted that there is no unit tests for
24-
* this class, since there is only one line of actual code, that would only be
25-
* testable by mocking {@link Runtime}.
23+
* {@link Runtime#exec} method. It should be noted that there is no unit tests for this
24+
* class, since there is only one line of actual code, that would only be testable by
25+
* mocking {@link Runtime}.
2626
*
2727
* @author Stefano Cordio
28-
* @since FIXME
28+
* @since 5.0
2929
*/
3030
public class JvmCommandRunner implements CommandRunner {
3131

spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandTasklet.java

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2006-2021 the original author or authors.
2+
* Copyright 2006-2022 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.
@@ -64,7 +64,7 @@ public class SystemCommandTasklet implements StepExecutionListener, StoppableTas
6464

6565
protected static final Log logger = LogFactory.getLog(SystemCommandTasklet.class);
6666

67-
private static CommandRunner commandRunner = new JvmCommandRunner();
67+
private CommandRunner commandRunner = new JvmCommandRunner();
6868

6969
private String command;
7070

@@ -144,24 +144,14 @@ else if (stopped) {
144144
}
145145
}
146146

147-
/**
148-
* Static setter for the {@link CommandRunner} so it can be adjusted before
149-
* dependency injection. Typically overridden by
150-
* {@link #setCommandRunner(CommandRunner)}.
151-
*
152-
* @param commandRunner {@link CommandRunner} instance to be used by SystemCommandTasklet instance.
153-
*/
154-
public static void presetCommandRunner(CommandRunner commandRunner) {
155-
SystemCommandTasklet.commandRunner = commandRunner;
156-
}
157-
158147
/**
159148
* Injection setter for the {@link CommandRunner}.
160-
*
161-
* @param commandRunner {@link CommandRunner} instance to be used by SystemCommandTasklet instance.
149+
* @param commandRunner {@link CommandRunner} instance to be used by
150+
* SystemCommandTasklet instance. Defaults to {@link JvmCommandRunner}.
151+
* @since 5.0
162152
*/
163153
public void setCommandRunner(CommandRunner commandRunner) {
164-
SystemCommandTasklet.commandRunner = commandRunner;
154+
this.commandRunner = commandRunner;
165155
}
166156

167157
/**

spring-batch-core/src/test/java/org/springframework/batch/core/step/tasklet/SystemCommandTaskletIntegrationTests.java

Lines changed: 25 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -172,27 +172,8 @@ void testInterruption() throws Exception {
172172
*/
173173
@Test
174174
public void testCommandRunnerNotSet() throws Exception {
175-
SystemCommandTasklet.presetCommandRunner(null);
176-
try {
177-
tasklet.afterPropertiesSet();
178-
fail();
179-
}
180-
catch (IllegalArgumentException e) {
181-
// expected
182-
} finally {
183-
SystemCommandTasklet.presetCommandRunner(new JvmCommandRunner());
184-
}
185-
186175
tasklet.setCommandRunner(null);
187-
try {
188-
tasklet.afterPropertiesSet();
189-
fail();
190-
}
191-
catch (IllegalArgumentException e) {
192-
// expected
193-
} finally {
194-
SystemCommandTasklet.presetCommandRunner(new JvmCommandRunner());
195-
}
176+
assertThrows(IllegalArgumentException.class, tasklet::afterPropertiesSet);
196177
}
197178

198179
/*
@@ -296,50 +277,42 @@ private boolean isRunningOnWindows() {
296277

297278
@Test
298279
public void testExecuteWithSuccessfulCommandRunnerMockExecution() throws Exception {
299-
try {
300-
StepContribution stepContribution = stepExecution.createStepContribution();
301-
CommandRunner commandRunner = mock(CommandRunner.class);
302-
Process process = mock(Process.class);
303-
String command = "invalid command";
280+
StepContribution stepContribution = stepExecution.createStepContribution();
281+
CommandRunner commandRunner = mock(CommandRunner.class);
282+
Process process = mock(Process.class);
283+
String command = "invalid command";
304284

305-
when(commandRunner.exec(eq(command), any(), any())).thenReturn(process);
306-
when(process.waitFor()).thenReturn(0);
285+
when(commandRunner.exec(eq(command), any(), any())).thenReturn(process);
286+
when(process.waitFor()).thenReturn(0);
307287

308-
SystemCommandTasklet.presetCommandRunner(commandRunner);
309-
tasklet.setCommand(command);
310-
tasklet.afterPropertiesSet();
288+
tasklet.setCommandRunner(commandRunner);
289+
tasklet.setCommand(command);
290+
tasklet.afterPropertiesSet();
311291

312-
RepeatStatus exitStatus = tasklet.execute(stepContribution, null);
292+
RepeatStatus exitStatus = tasklet.execute(stepContribution, null);
313293

314-
assertEquals(RepeatStatus.FINISHED, exitStatus);
315-
assertEquals(ExitStatus.COMPLETED, stepContribution.getExitStatus());
316-
} finally {
317-
SystemCommandTasklet.presetCommandRunner(new JvmCommandRunner());
318-
}
294+
assertEquals(RepeatStatus.FINISHED, exitStatus);
295+
assertEquals(ExitStatus.COMPLETED, stepContribution.getExitStatus());
319296
}
320297

321298
@Test
322299
public void testExecuteWithFailedCommandRunnerMockExecution() throws Exception {
323-
try {
324-
StepContribution stepContribution = stepExecution.createStepContribution();
325-
CommandRunner commandRunner = mock(CommandRunner.class);
326-
Process process = mock(Process.class);
327-
String command = "invalid command";
300+
StepContribution stepContribution = stepExecution.createStepContribution();
301+
CommandRunner commandRunner = mock(CommandRunner.class);
302+
Process process = mock(Process.class);
303+
String command = "invalid command";
328304

329-
when(commandRunner.exec(eq(command), any(), any())).thenReturn(process);
330-
when(process.waitFor()).thenReturn(1);
305+
when(commandRunner.exec(eq(command), any(), any())).thenReturn(process);
306+
when(process.waitFor()).thenReturn(1);
331307

332-
SystemCommandTasklet.presetCommandRunner(commandRunner);
333-
tasklet.setCommand(command);
334-
tasklet.afterPropertiesSet();
308+
tasklet.setCommandRunner(commandRunner);
309+
tasklet.setCommand(command);
310+
tasklet.afterPropertiesSet();
335311

336-
RepeatStatus exitStatus = tasklet.execute(stepContribution, null);
312+
RepeatStatus exitStatus = tasklet.execute(stepContribution, null);
337313

338-
assertEquals(RepeatStatus.FINISHED, exitStatus);
339-
assertEquals(ExitStatus.FAILED, stepContribution.getExitStatus());
340-
} finally {
341-
SystemCommandTasklet.presetCommandRunner(new JvmCommandRunner());
342-
}
314+
assertEquals(RepeatStatus.FINISHED, exitStatus);
315+
assertEquals(ExitStatus.FAILED, stepContribution.getExitStatus());
343316
}
344317

345318
}

0 commit comments

Comments
 (0)