45
45
* {@link #setTaskExecutor(TaskExecutor)} - timeout value is required to be set, so that
46
46
* the batch job does not hang forever if the external process hangs.
47
47
*
48
- * Tasklet periodically checks for termination status (i.e. {@link #setCommand(String)}
48
+ * Tasklet periodically checks for termination status (i.e. {@link #setCommand(String... )}
49
49
* finished its execution or {@link #setTimeout(long)} expired or job was interrupted).
50
50
* The check interval is given by {@link #setTerminationCheckInterval(long)}.
51
51
*
@@ -66,7 +66,7 @@ public class SystemCommandTasklet implements StepExecutionListener, StoppableTas
66
66
67
67
private CommandRunner commandRunner = new JvmCommandRunner ();
68
68
69
- private String command ;
69
+ private String [] cmdArray ;
70
70
71
71
private String [] environmentParams = null ;
72
72
@@ -102,8 +102,14 @@ public RepeatStatus execute(StepContribution contribution, ChunkContext chunkCon
102
102
103
103
@ Override
104
104
public Integer call () throws Exception {
105
- Process process = commandRunner .exec (command , environmentParams , workingDirectory );
106
- return process .waitFor ();
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
+ }
107
113
}
108
114
109
115
});
@@ -134,6 +140,7 @@ else if (System.currentTimeMillis() - t0 > timeout) {
134
140
}
135
141
else if (execution .isTerminateOnly ()) {
136
142
systemCommandTask .cancel (interruptOnCancel );
143
+ String command = String .join (" " , cmdArray );
137
144
throw new JobInterruptedException ("Job interrupted while executing system command '" + command + "'" );
138
145
}
139
146
else if (stopped ) {
@@ -155,10 +162,17 @@ public void setCommandRunner(CommandRunner commandRunner) {
155
162
}
156
163
157
164
/**
158
- * @param command command to be executed in a separate system process
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
173
*/
160
- public void setCommand (String command ) {
161
- this .command = command ;
174
+ public void setCommand (String ... command ) {
175
+ this .cmdArray = command ;
162
176
}
163
177
164
178
/**
@@ -187,7 +201,10 @@ public void setWorkingDirectory(String dir) {
187
201
@ Override
188
202
public void afterPropertiesSet () throws Exception {
189
203
Assert .notNull (commandRunner , "CommandRunner must be set" );
190
- Assert .hasLength (command , "'command' property value is required" );
204
+ Assert .notNull (cmdArray , "'cmdArray' property value is required with at least 1 element" );
205
+ 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" );
207
+ Assert .hasLength (cmdArray [0 ], "'cmdArray' property value is required with at least 1 element" );
191
208
Assert .notNull (systemProcessExitCodeMapper , "SystemProcessExitCodeMapper must be set" );
192
209
Assert .isTrue (timeout > 0 , "timeout value must be greater than zero" );
193
210
Assert .notNull (taskExecutor , "taskExecutor is required" );
0 commit comments