4
4
import java .util .List ;
5
5
import java .util .Set ;
6
6
7
+ import javax .inject .Inject ;
8
+
7
9
import org .slf4j .Logger ;
8
10
import org .slf4j .LoggerFactory ;
9
11
import org .springframework .batch .core .BatchStatus ;
12
+ import org .springframework .batch .core .Job ;
10
13
import org .springframework .batch .core .JobExecution ;
11
14
import org .springframework .batch .core .JobParameters ;
12
15
import org .springframework .batch .core .configuration .JobLocator ;
15
18
import org .springframework .batch .core .launch .JobExecutionNotRunningException ;
16
19
import org .springframework .batch .core .launch .JobLauncher ;
17
20
import org .springframework .batch .core .launch .JobOperator ;
21
+ import org .springframework .batch .core .launch .NoSuchJobException ;
18
22
import org .springframework .batch .core .launch .support .CommandLineJobRunner ;
19
- import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
23
+ import org .springframework .beans .factory .annotation .Autowired ;
24
+ import org .springframework .beans .factory .config .AutowireCapableBeanFactory ;
20
25
import org .springframework .boot .ExitCodeGenerator ;
21
26
import org .springframework .boot .SpringApplication ;
22
27
import org .springframework .boot .WebApplicationType ;
23
28
import org .springframework .context .ConfigurableApplicationContext ;
24
29
import org .springframework .util .StringUtils ;
25
30
26
31
/**
27
- * Launcher for launching batch jobs from the command line when Spring Boot is used. Similar to the
28
- * {@link CommandLineJobRunner}, which does not work very well with Spring Boot.
29
- * <p>
30
- * Do not use this class if Spring Boot is not used!
31
- * <p>
32
- * It expects the full class name of the Spring Boot configuration class to be used as first argument, the class/XML
33
- * file for configuring the job as second argument and the job name as third.<br>
32
+ * Launcher for launching batch jobs from the command line when Spring Boot is used. It is somewhat similar to the
33
+ * {@link CommandLineJobRunner}. The main difference is, that this launcher disables the web-app for the spring context.
34
+ *
35
+ * It expects the full class name of the Spring Boot configuration class to be used as first argument and the jobs
36
+ * beanname as the second.<br>
34
37
* Moreover parameters can be specified as further arguments (convention: key1=value1 key2=value2 ...).
35
38
* <p>
36
39
* Example:<br>
37
- * java com.devonfw.module.batch.common.base.SpringBootBatchCommandLine
38
- * com.devonfw.gastronomy.restaurant.SpringBootBatchApp classpath:config/app/batch/beans-productimport.xml
39
- * productImportJob drinks.file=file:import/drinks.csv date(date)=2015/12/20
40
+ * {@code java -jar my-app-batch-bootified.jar com.devonfw.application.example.SpringBootApp myJob param=value...}
41
+ * </p>
40
42
* <p>
41
43
* For stopping all running executions of a job, use the -stop option.
42
- * <p>
44
+ *
43
45
* Example:<br>
44
- * java com.devonfw.module.batch.common.base.SpringBootBatchCommandLine
45
- * com.devonfw.gastronomy.restaurant.SpringBootBatchApp classpath:config/app/batch/beans-productimport.xml
46
- * productImportJob -stop
46
+ * {@code java -jar my-app-batch-bootified.jar com.devonfw.application.example.SpringBootApp myJob -stop}
47
+ * </p>
48
+ * <p>
49
+ * To make that work expect that the batchs is deployed in form of a "bootified" jar, whith this class here als the
50
+ * start-class. For that you have to add the following snipped to your pom.xml:
51
+ *
52
+ * <pre>
53
+ * {@code
54
+ <build>
55
+ <plugins>
56
+ <plugin>
57
+ <groupId>org.apache.maven.plugins</groupId>
58
+ <artifactId>maven-jar-plugin</artifactId>
59
+ <configuration>
60
+ <excludes>
61
+ <exclude>config/application.properties</exclude>
62
+ </excludes>
63
+ </configuration>
64
+ </plugin>
65
+ <plugin>
66
+ <groupId>org.springframework.boot</groupId>
67
+ <artifactId>spring-boot-maven-plugin</artifactId>
68
+ <configuration>
69
+ <mainClass>com.devonfw.module.batch.common.base.SpringBootBatchCommandLine</mainClass>
70
+ <classifier>bootified</classifier>
71
+ </configuration>
72
+ <executions>
73
+ <execution>
74
+ <goals>
75
+ <goal>repackage</goal>
76
+ </goals>
77
+ </execution>
78
+ </executions>
79
+ </plugin>
80
+ </plugins>
81
+ </build>
82
+ * }
83
+ * </pre>
84
+ * </p>
85
+ * <p>
86
+ *
87
+ * @deprecated Since spring batch and spring boot are nicely integrated it is possible to start batches without any
88
+ * custom launcher. This is documented in the current devonfw batch documentation. This launcher is no
89
+ * longer required and will be removed in one of the next releases.
47
90
*/
91
+ @ Deprecated
48
92
public class SpringBootBatchCommandLine {
49
93
50
94
private static final Logger LOG = LoggerFactory .getLogger (SpringBootBatchCommandLine .class );
@@ -59,12 +103,16 @@ public static enum Operation {
59
103
STOP
60
104
};
61
105
106
+ @ Inject
62
107
private JobLauncher launcher ;
63
108
109
+ @ Inject
64
110
private JobLocator locator ;
65
111
66
- private JobParametersConverter parametersConverter ;
112
+ @ Autowired (required = false ) // Use Autowired here, since @Inject does not support required = false.
113
+ private JobParametersConverter parametersConverter = new DefaultJobParametersConverter ();;
67
114
115
+ @ Inject
68
116
private JobOperator operator ;
69
117
70
118
/**
@@ -73,22 +121,18 @@ public static enum Operation {
73
121
*/
74
122
public static void main (String [] args ) throws Exception {
75
123
76
- if (args .length < 3 ) {
124
+ if (args .length < 2 ) {
77
125
78
126
handleIncorrectParameters ();
79
127
return ;
80
128
}
81
129
82
- List <String > configurations = new ArrayList <>(2 );
83
- configurations .add (args [0 ]);
84
- configurations .add (args [1 ]);
85
-
86
130
List <String > parameters = new ArrayList <>();
87
131
88
132
Operation op = Operation .START ;
89
- if (args .length > 3 && args [3 ].equalsIgnoreCase ("-stop" )) {
133
+ if (args .length > 2 && args [2 ].equalsIgnoreCase ("-stop" )) {
90
134
91
- if (args .length > 4 ) {
135
+ if (args .length > 3 ) {
92
136
93
137
handleIncorrectParameters ();
94
138
return ;
@@ -97,29 +141,25 @@ public static void main(String[] args) throws Exception {
97
141
op = Operation .STOP ;
98
142
} else {
99
143
100
- for (int i = 3 ; i < args .length ; i ++) {
144
+ for (int i = 2 ; i < args .length ; i ++) {
101
145
102
146
parameters .add (args [i ]);
103
147
}
104
148
}
105
149
106
- new SpringBootBatchCommandLine ().execute (op , configurations , args [2 ], parameters );
150
+ new SpringBootBatchCommandLine ().execute (op , args [ 0 ] , args [1 ], parameters );
107
151
}
108
152
109
153
private static void handleIncorrectParameters () {
110
154
111
155
LOG .error ("Incorrect parameters." );
112
156
LOG .info ("Usage:" );
113
- LOG .info ("java com.devonfw.module.batch.common.base.SpringBootBatchCommandLine"
114
- + " <SpringBootConfiguration> <BatchJobConfiguration>" + " <JobName> param1=value1 param2=value2 ..." );
157
+ LOG .info (
158
+ "java -jar my-app-batch-bootified.jar <SpringBootConfiguration> <JobName> param1=value1 param2=value2 ..." );
115
159
LOG .info ("For stopping all running executions of a batch job:" );
116
- LOG .info ("java com.devonfw.module.batch.common.base.BatchCommandLine"
117
- + " <SpringBootConfiguration> <BatchJobConfiguration>" + " <JobName> -stop" );
160
+ LOG .info ("java -jar my-app-batch-bootified.jar <SpringBootConfiguration> <JobName> -stop" );
118
161
LOG .info ("Example:" );
119
- LOG .info ("java com.devonfw.module.batch.common.base.SpringBootBatchCommandLine"
120
- + " com.devonfw.gastronomy.restaurant.SpringBootBatchApp"
121
- + " classpath:config/app/batch/beans-productimport.xml" + " productImportJob drinks.file=file:import/drinks.csv"
122
- + " date(date)=2015/12/20" );
162
+ LOG .info ("java com.devonfw.application.example.SpringBootApp exportJob pathToFile=myfile.csv" );
123
163
}
124
164
125
165
/**
@@ -134,50 +174,32 @@ protected int getReturnCode(JobExecution jobExecution) {
134
174
return 1 ;
135
175
}
136
176
137
- private void findBeans (ConfigurableApplicationContext ctx ) {
138
-
139
- this .launcher = ctx .getBean (JobLauncher .class );
140
- this .locator = ctx .getBean (JobLocator .class ); // supertype of JobRegistry
141
- this .operator = ctx .getBean (JobOperator .class );
142
- try {
143
-
144
- this .parametersConverter = ctx .getBean (JobParametersConverter .class );
145
- } catch (NoSuchBeanDefinitionException e ) {
146
-
147
- this .parametersConverter = new DefaultJobParametersConverter ();
148
- }
149
- }
150
-
151
177
/**
152
178
* Initialize the application context and execute the operation.
153
179
* <p>
154
180
* The application context is closed after the operation has finished.
155
181
*
156
182
* @param operation The operation to start.
157
- * @param configurations The sources of bean configurations (either JavaConfig classes or XML files) .
183
+ * @param configuration The sources of app context configuration .
158
184
* @param jobName The name of the job to launch/stop.
159
185
* @param parameters The parameters (key=value).
160
186
* @throws Exception in case of an error.
161
187
*/
162
- @ SuppressWarnings ("deprecation" )
163
- public void execute (Operation operation , List <String > configurations , String jobName , List <String > parameters )
188
+ public void execute (Operation operation , String configuration , String jobName , List <String > parameters )
164
189
throws Exception {
165
190
166
- // get sources of configuration
167
- Class <?>[] configurationClasses = new Class [configurations .size ()];
168
- for (int i = 0 ; i < configurations .size (); i ++) {
169
-
170
- configurationClasses [i ] = Class .forName (configurations .get (i ));
171
- }
172
-
173
- SpringApplication app = new SpringApplication (configurationClasses );
191
+ SpringApplication app = new SpringApplication (Class .forName (configuration ));
174
192
175
193
// no (web) server needed
176
194
app .setWebApplicationType (WebApplicationType .NONE );
177
195
178
196
// start the application
179
197
ConfigurableApplicationContext ctx = app .run (new String [0 ]);
180
198
199
+ // start injection for properties of this class (here), by manually invoking autowiring for the new context.
200
+ ctx .getAutowireCapableBeanFactory ().autowireBeanProperties (this , AutowireCapableBeanFactory .AUTOWIRE_BY_TYPE ,
201
+ false );
202
+
181
203
switch (operation ) {
182
204
case START :
183
205
startBatch (ctx , jobName , parameters );
@@ -197,15 +219,22 @@ private void startBatch(ConfigurableApplicationContext ctx, String jobName, List
197
219
JobExecution jobExecution = null ;
198
220
try {
199
221
200
- findBeans (ctx );
201
-
202
222
JobParameters params = this .parametersConverter
203
223
.getJobParameters (StringUtils .splitArrayElementsIntoProperties (parameters .toArray (new String [] {}), "=" ));
204
224
205
225
// execute the batch
206
- // the JobOperator would require special logic for a restart, so we
207
- // are using the JobLauncher directly here
208
- jobExecution = this .launcher .run (this .locator .getJob (jobName ), params );
226
+ Job job = null ;
227
+ if (this .locator != null ) {
228
+ try {
229
+ job = this .locator .getJob (jobName );
230
+ } catch (NoSuchJobException e ) {
231
+ }
232
+ }
233
+ if (job == null ) {
234
+ job = (Job ) ctx .getBean (jobName );
235
+ }
236
+
237
+ jobExecution = this .launcher .run (job , params );
209
238
210
239
} finally {
211
240
@@ -245,8 +274,6 @@ private void stopBatch(ConfigurableApplicationContext ctx, String jobName) throw
245
274
int returnCode = 0 ;
246
275
try {
247
276
248
- findBeans (ctx );
249
-
250
277
Set <Long > runningJobExecutionIDs = this .operator .getRunningExecutions (jobName );
251
278
if (runningJobExecutionIDs .isEmpty ()) {
252
279
0 commit comments