Skip to content

Commit 26c39cb

Browse files
committed
Refine contribution #3967
Related to #752
1 parent 746c919 commit 26c39cb

File tree

4 files changed

+29
-37
lines changed

4 files changed

+29
-37
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public interface CommandRunner {
3232
/**
3333
* Executes the specified string command in a separate process with the specified
3434
* environment and working directory.
35-
* @param command a specified system command.
35+
* @param command a specified system command and its arguments.
3636
* @param envp array of strings, each element of which has environment variable
3737
* settings in the format <i>name</i>=<i>value</i>, or {@code null} if the subprocess
3838
* should inherit the environment of the current process.
@@ -49,6 +49,6 @@ public interface CommandRunner {
4949
*
5050
* @see Runtime#exec(String, String[], File)
5151
*/
52-
Process exec(String command, String[] envp, File dir) throws IOException;
52+
Process exec(String command[], String[] envp, File dir) throws IOException;
5353

5454
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,18 @@
2525
* mocking {@link Runtime}.
2626
*
2727
* @author Stefano Cordio
28+
* @author Mahmoud Ben Hassine
2829
* @since 5.0
2930
*/
3031
public class JvmCommandRunner implements CommandRunner {
3132

3233
/**
3334
* Delegate call to {@link Runtime#exec} with the arguments provided.
3435
*
35-
* @see CommandRunner#exec(String, String[], File)
36+
* @see CommandRunner#exec(String[], String[], File)
3637
*/
3738
@Override
38-
public Process exec(String command, String[] envp, File dir) throws IOException {
39+
public Process exec(String command[], String[] envp, File dir) throws IOException {
3940
return Runtime.getRuntime().exec(command, envp, dir);
4041
}
4142

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

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,8 @@ public RepeatStatus execute(StepContribution contribution, ChunkContext chunkCon
102102

103103
@Override
104104
public Integer call() throws Exception {
105-
if (cmdArray.length == 1) {
106-
String command = cmdArray[0];
107-
Process process = commandRunner.exec(command, environmentParams, workingDirectory);
108-
return process.waitFor();
109-
} else {
110-
Process process = Runtime.getRuntime().exec(cmdArray, environmentParams, workingDirectory);
111-
return process.waitFor();
112-
}
105+
Process process = commandRunner.exec(cmdArray, environmentParams, workingDirectory);
106+
return process.waitFor();
113107
}
114108

115109
});
@@ -162,17 +156,13 @@ public void setCommandRunner(CommandRunner commandRunner) {
162156
}
163157

164158
/**
165-
* @param command command to be executed in a separate system process. Either a single command can be supplied
166-
* to be tokenized with a space delimiter, or the command and its arguments are supplied as multiple
167-
* strings that are not tokenized.
168-
* <p>
169-
* <p>Possible calls to setCommand:
170-
*
171-
* <pre> {@code setCommand("myCommand myArg1 myArg2");}</pre>
172-
* <pre> {@code setCommand("myCommand", "myArg1", "myArg2 'args for myArg2'");}</pre>
159+
* Set the command to execute along with its arguments. For example:
160+
*
161+
* <pre>setCommand("myCommand", "myArg1", "myArg2");</pre>
162+
* @param command command to be executed in a separate system process.
173163
*/
174164
public void setCommand(String... command) {
175-
this.cmdArray = command ;
165+
this.cmdArray = command;
176166
}
177167

178168
/**
@@ -201,9 +191,9 @@ public void setWorkingDirectory(String dir) {
201191
@Override
202192
public void afterPropertiesSet() throws Exception {
203193
Assert.notNull(commandRunner, "CommandRunner must be set");
204-
Assert.notNull(cmdArray, "'cmdArray' property value is required with at least 1 element");
194+
Assert.notNull(cmdArray, "'cmdArray' property value must not be null");
205195
Assert.notEmpty(cmdArray, "'cmdArray' property value is required with at least 1 element");
206-
Assert.noNullElements(cmdArray, "'cmdArray' property value is required with at least 1 element");
196+
Assert.noNullElements(cmdArray, "'cmdArray' property value must not contain be null elements");
207197
Assert.hasLength(cmdArray[0], "'cmdArray' property value is required with at least 1 element");
208198
Assert.notNull(systemProcessExitCodeMapper, "SystemProcessExitCodeMapper must be set");
209199
Assert.isTrue(timeout > 0, "timeout value must be greater than zero");

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

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,11 @@ public void testExecuteWithSeparateArgument() throws Exception {
103103
*/
104104
@Test
105105
void testExecute() throws Exception {
106-
String command = getJavaCommand() + " --version";
106+
String[] command = new String[] { getJavaCommand(), "--version" };
107107
tasklet.setCommand(command);
108108
tasklet.afterPropertiesSet();
109109

110-
log.info("Executing command: " + command);
110+
log.info("Executing command: " + String.join(" ", command));
111111
RepeatStatus exitStatus = tasklet.execute(stepExecution.createStepContribution(), null);
112112

113113
assertEquals(RepeatStatus.FINISHED, exitStatus);
@@ -118,21 +118,21 @@ void testExecute() throws Exception {
118118
*/
119119
@Test
120120
void testExecuteFailure() throws Exception {
121-
String command = getJavaCommand() + " org.springframework.batch.sample.tasklet.UnknownClass";
121+
String[] command = new String[] { getJavaCommand() + " org.springframework.batch.sample.tasklet.UnknownClass" };
122122
tasklet.setCommand(command);
123123
tasklet.setTimeout(200L);
124124
tasklet.afterPropertiesSet();
125125

126-
log.info("Executing command: " + command);
126+
log.info("Executing command: " + String.join(" ", command));
127127
try {
128128
StepContribution contribution = stepExecution.createStepContribution();
129129
RepeatStatus exitStatus = tasklet.execute(contribution, null);
130130
assertEquals(RepeatStatus.FINISHED, exitStatus);
131131
assertEquals(ExitStatus.FAILED, contribution.getExitStatus());
132132
}
133-
catch (RuntimeException e) {
133+
catch (Exception e) {
134134
// on some platforms the system call does not return
135-
assertEquals("Execution of system command did not finish within the timeout", e.getMessage());
135+
assertTrue(e.getMessage().contains("Cannot run program"));
136136
}
137137
}
138138

@@ -141,7 +141,7 @@ void testExecuteFailure() throws Exception {
141141
*/
142142
@Test
143143
void testExecuteException() throws Exception {
144-
String command = "non-sense-that-should-cause-exception-when-attempted-to-execute";
144+
String[] command = new String[] { "non-sense-that-should-cause-exception-when-attempted-to-execute" };
145145
tasklet.setCommand(command);
146146
tasklet.afterPropertiesSet();
147147

@@ -153,12 +153,12 @@ void testExecuteException() throws Exception {
153153
*/
154154
@Test
155155
void testExecuteTimeout() throws Exception {
156-
String command = isRunningOnWindows() ? "ping 127.0.0.1" : "sleep 3";
156+
String[] command = isRunningOnWindows() ? new String[] { "ping", "127.0.0.1" } : new String[] { "sleep", "3" };
157157
tasklet.setCommand(command);
158158
tasklet.setTimeout(10);
159159
tasklet.afterPropertiesSet();
160160

161-
log.info("Executing command: " + command);
161+
log.info("Executing command: " + String.join(" ", command));
162162
Exception exception = assertThrows(SystemCommandException.class, () -> tasklet.execute(null, null));
163163
assertTrue(exception.getMessage().contains("did not finish within the timeout"));
164164
}
@@ -168,7 +168,7 @@ void testExecuteTimeout() throws Exception {
168168
*/
169169
@Test
170170
void testInterruption() throws Exception {
171-
String command = isRunningOnWindows() ? "ping 127.0.0.1" : "sleep 5";
171+
String[] command = isRunningOnWindows() ? new String[] { "ping", "127.0.0.1" } : new String[] { "sleep", "5" };
172172
tasklet.setCommand(command);
173173
tasklet.setTerminationCheckInterval(10);
174174
tasklet.afterPropertiesSet();
@@ -178,7 +178,7 @@ void testInterruption() throws Exception {
178178
String message = exception.getMessage();
179179
System.out.println(message);
180180
assertTrue(message.contains("Job interrupted while executing system command"));
181-
assertTrue(message.contains(command));
181+
assertTrue(message.contains(command[0]));
182182
}
183183

184184
/*
@@ -255,7 +255,8 @@ void testStopped() throws Exception {
255255
when(jobExplorer.getJobExecution(1L)).thenReturn(stepExecution.getJobExecution(),
256256
stepExecution.getJobExecution(), stoppedJobExecution);
257257

258-
String command = isRunningOnWindows() ? "ping 127.0.0.1 -n 5" : "sleep 15";
258+
String[] command = isRunningOnWindows() ? new String[] { "ping", "127.0.0.1", "-n", "5" }
259+
: new String[] { "sleep", "15" };
259260
tasklet.setCommand(command);
260261
tasklet.setTerminationCheckInterval(10);
261262
tasklet.afterPropertiesSet();
@@ -294,7 +295,7 @@ public void testExecuteWithSuccessfulCommandRunnerMockExecution() throws Excepti
294295
StepContribution stepContribution = stepExecution.createStepContribution();
295296
CommandRunner commandRunner = mock(CommandRunner.class);
296297
Process process = mock(Process.class);
297-
String command = "invalid command";
298+
String[] command = new String[] { "invalid command" };
298299

299300
when(commandRunner.exec(eq(command), any(), any())).thenReturn(process);
300301
when(process.waitFor()).thenReturn(0);
@@ -314,7 +315,7 @@ public void testExecuteWithFailedCommandRunnerMockExecution() throws Exception {
314315
StepContribution stepContribution = stepExecution.createStepContribution();
315316
CommandRunner commandRunner = mock(CommandRunner.class);
316317
Process process = mock(Process.class);
317-
String command = "invalid command";
318+
String[] command = new String[] { "invalid command" };
318319

319320
when(commandRunner.exec(eq(command), any(), any())).thenReturn(process);
320321
when(process.waitFor()).thenReturn(1);

0 commit comments

Comments
 (0)