diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandTasklet.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandTasklet.java index 7e614e36b..84ad3e1e6 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandTasklet.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/tasklet/SystemCommandTasklet.java @@ -45,7 +45,7 @@ import org.springframework.util.Assert; * {@link #setTaskExecutor(TaskExecutor)} - timeout value is required to be set, so that * the batch job does not hang forever if the external process hangs. * - * Tasklet periodically checks for termination status (i.e. {@link #setCommand(String)} + * Tasklet periodically checks for termination status (i.e. {@link #setCommand(String...)} * finished its execution or {@link #setTimeout(long)} expired or job was interrupted). * The check interval is given by {@link #setTerminationCheckInterval(long)}. * @@ -66,7 +66,7 @@ public class SystemCommandTasklet implements StepExecutionListener, StoppableTas private CommandRunner commandRunner = new JvmCommandRunner(); - private String command; + private String[] cmdArray; private String[] environmentParams = null; @@ -102,8 +102,14 @@ public class SystemCommandTasklet implements StepExecutionListener, StoppableTas @Override public Integer call() throws Exception { - Process process = commandRunner.exec(command, environmentParams, workingDirectory); - return process.waitFor(); + if (cmdArray.length == 1) { + String command = cmdArray[0]; + Process process = commandRunner.exec(command, environmentParams, workingDirectory); + return process.waitFor(); + } else { + Process process = Runtime.getRuntime().exec(cmdArray, environmentParams, workingDirectory); + return process.waitFor(); + } } }); @@ -134,6 +140,7 @@ public class SystemCommandTasklet implements StepExecutionListener, StoppableTas } else if (execution.isTerminateOnly()) { systemCommandTask.cancel(interruptOnCancel); + String command = String.join(" ", cmdArray); throw new JobInterruptedException("Job interrupted while executing system command '" + command + "'"); } else if (stopped) { @@ -155,10 +162,17 @@ public class SystemCommandTasklet implements StepExecutionListener, StoppableTas } /** - * @param command command to be executed in a separate system process + * @param command command to be executed in a separate system process. Either a single command can be supplied + * to be tokenized with a space delimiter, or the command and its arguments are supplied as multiple + * strings that are not tokenized. + *

+ *

Possible calls to setCommand: + * + *

 {@code setCommand("myCommand myArg1 myArg2");}
+ *
 {@code setCommand("myCommand", "myArg1", "myArg2 'args for myArg2'");}
*/ - public void setCommand(String command) { - this.command = command; + public void setCommand(String... command) { + this.cmdArray = command ; } /** @@ -187,7 +201,10 @@ public class SystemCommandTasklet implements StepExecutionListener, StoppableTas @Override public void afterPropertiesSet() throws Exception { Assert.notNull(commandRunner, "CommandRunner must be set"); - Assert.hasLength(command, "'command' property value is required"); + Assert.notNull(cmdArray, "'cmdArray' property value is required with at least 1 element"); + Assert.notEmpty(cmdArray, "'cmdArray' property value is required with at least 1 element"); + Assert.noNullElements(cmdArray, "'cmdArray' property value is required with at least 1 element"); + Assert.hasLength(cmdArray[0], "'cmdArray' property value is required with at least 1 element"); Assert.notNull(systemProcessExitCodeMapper, "SystemProcessExitCodeMapper must be set"); Assert.isTrue(timeout > 0, "timeout value must be greater than zero"); Assert.notNull(taskExecutor, "taskExecutor is required"); diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/step/tasklet/SystemCommandTaskletIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/step/tasklet/SystemCommandTaskletIntegrationTests.java index 4a44ce26d..d467a1f6b 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/step/tasklet/SystemCommandTaskletIntegrationTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/step/tasklet/SystemCommandTaskletIntegrationTests.java @@ -84,6 +84,20 @@ class SystemCommandTaskletIntegrationTests { tasklet.setTaskExecutor(new SimpleAsyncTaskExecutor()); } + /* + * Power usage scenario - successful execution of system command. + */ + @Test + public void testExecuteWithSeparateArgument() throws Exception { + tasklet.setCommand(getJavaCommand(), "--version"); + tasklet.afterPropertiesSet(); + + log.info("Executing command: " + getJavaCommand() + " --version"); + RepeatStatus exitStatus = tasklet.execute(stepExecution.createStepContribution(), null); + + assertEquals(RepeatStatus.FINISHED, exitStatus); + } + /* * Regular usage scenario - successful execution of system command. */