From bb1ec38a1861599190be312c3ec5fcc38e3c8d12 Mon Sep 17 00:00:00 2001 From: Greg Turnquist Date: Sun, 26 May 2013 15:57:01 -0400 Subject: [PATCH] Merge pull request #175 from gregturn/BATCH-2035 - Added a new archetype for javaconfig based projects - Updated the CommandLineJobRunner to also accept class names for context initialization --- .gitignore | 2 +- archetypes/pom.xml | 1 + archetypes/simple-cli-javaconfig/pom.xml | 286 ++++++++++++++++++ .../src/main/assembly/descriptor.xml | 25 ++ .../src/main/java/example/LaunchContext.java | 94 ++++++ .../src/main/java/example/ModuleContext.java | 37 +++ .../src/main/java/example/Person.java | 56 ++++ .../java/example/PersonItemProcessor.java | 38 +++ .../src/main/resources/batch.properties | 15 + .../src/main/resources/log4j.properties | 8 + .../src/main/resources/support/person.sql | 7 + .../main/resources/support/sample-data.csv | 5 + .../src/main/scripts/runJob.bat | 8 + .../src/main/scripts/runJob.sh | 8 + .../simple-cli-javaconfig/src/site/site.xml | 20 ++ .../java/example/PersonItemProcessorTest.java | 38 +++ .../example/PersonJobConfigurationTest.java | 97 ++++++ .../src/test/java/example/TestContext.java | 59 ++++ .../launch/support/CommandLineJobRunner.java | 23 +- 19 files changed, 820 insertions(+), 7 deletions(-) create mode 100644 archetypes/simple-cli-javaconfig/pom.xml create mode 100644 archetypes/simple-cli-javaconfig/src/main/assembly/descriptor.xml create mode 100644 archetypes/simple-cli-javaconfig/src/main/java/example/LaunchContext.java create mode 100644 archetypes/simple-cli-javaconfig/src/main/java/example/ModuleContext.java create mode 100644 archetypes/simple-cli-javaconfig/src/main/java/example/Person.java create mode 100644 archetypes/simple-cli-javaconfig/src/main/java/example/PersonItemProcessor.java create mode 100644 archetypes/simple-cli-javaconfig/src/main/resources/batch.properties create mode 100644 archetypes/simple-cli-javaconfig/src/main/resources/log4j.properties create mode 100644 archetypes/simple-cli-javaconfig/src/main/resources/support/person.sql create mode 100644 archetypes/simple-cli-javaconfig/src/main/resources/support/sample-data.csv create mode 100644 archetypes/simple-cli-javaconfig/src/main/scripts/runJob.bat create mode 100644 archetypes/simple-cli-javaconfig/src/main/scripts/runJob.sh create mode 100644 archetypes/simple-cli-javaconfig/src/site/site.xml create mode 100644 archetypes/simple-cli-javaconfig/src/test/java/example/PersonItemProcessorTest.java create mode 100644 archetypes/simple-cli-javaconfig/src/test/java/example/PersonJobConfigurationTest.java create mode 100644 archetypes/simple-cli-javaconfig/src/test/java/example/TestContext.java diff --git a/.gitignore b/.gitignore index fbc1fdfff..b36bb3dbc 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,4 @@ s3.properties *.iws .*.swp .DS_Store - +.springBeans diff --git a/archetypes/pom.xml b/archetypes/pom.xml index 32c0b15e2..9744ef4bd 100644 --- a/archetypes/pom.xml +++ b/archetypes/pom.xml @@ -14,6 +14,7 @@ simple-cli + simple-cli-javaconfig diff --git a/archetypes/simple-cli-javaconfig/pom.xml b/archetypes/simple-cli-javaconfig/pom.xml new file mode 100644 index 000000000..3dc32e258 --- /dev/null +++ b/archetypes/simple-cli-javaconfig/pom.xml @@ -0,0 +1,286 @@ + + + 4.0.0 + org.springframework.batch + spring-batch-simple-cli-javaconfig + 3.0.0.BUILD-SNAPSHOT + jar + Commandline + http://www.springframework.org/spring-batch/archetypes/simple-cli-archetype + This project is a command line batch sample from Spring Batch demonstrating a typical batch job. + The job can be invoked via "mvn exec:java" to see the job run from the command line. + During an "mvn package", a distribution archive in the format defined in src/main/assembly/descriptor.xml will + be created in the target directory which can be deployed and extracted to your target location of choice. + The ./bin/runJob.(sh|bat) script from the extracted deployment archive can be invoked to run the job. + + + 3.2.0.RELEASE + 3.0.0.BUILD-SNAPSHOT + false + 4.10 + 1.6 + 1.6 + UTF-8 + + + + staging + + + staging + file:///${user.dir}/target/staging + + + staging + file:///${user.dir}/target/staging + + + + + bootstrap + + + Codehaus + http://repository.codehaus.org/ + + false + + + + com.springsource.repository.bundles.release + SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases + http://repository.springsource.com/maven/bundles/release + + false + + + + + + + + junit + junit + ${junit.version} + test + + + org.springframework + spring-test + ${spring.framework.version} + test + + + org.springframework + spring-aop + ${spring.framework.version} + + + org.springframework + spring-jdbc + ${spring.framework.version} + + + org.springframework.batch + spring-batch-core + ${spring.batch.version} + + + org.springframework.batch + spring-batch-infrastructure + ${spring.batch.version} + + + org.springframework.batch + spring-batch-test + ${spring.batch.version} + test + + + commons-dbcp + commons-dbcp + 1.2.2 + + + org.slf4j + slf4j-log4j12 + 1.5.8 + true + + + log4j + log4j + 1.2.14 + true + + + commons-io + commons-io + 1.4 + + + org.hsqldb + hsqldb + 2.2.9 + + + org.aspectj + aspectjrt + 1.6.8 + + + org.aspectj + aspectjweaver + 1.6.8 + + + + + + org.springframework.build.aws + org.springframework.build.aws.maven + 3.0.0.RELEASE + + + + + + maven-assembly-plugin + false + + + project + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.apache.maven.plugins + maven-dependency-plugin + [1.0,) + + copy-dependencies + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + ${compiler.source.version} + ${compiler.target.version} + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*Tests.java + + + **/Abstract*.java + + junit:junit + + + + org.codehaus.mojo + exec-maven-plugin + 1.1 + + org.springframework.batch.core.launch.support.CommandLineJobRunner + + classpath:/launch-context.xml + personJob + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-dependencies + package + + copy-dependencies + + + ${project.build.directory}/lib + + + + + + maven-assembly-plugin + 2.3 + + + src/main/assembly/descriptor.xml + + + + + make-distribution + package + + single + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + false + + org.springframework.batch.core.launch.support.CommandLineJobRunner + true + lib/ + + + + + + + + http://www.springframework.org/download + + staging + file:///${user.dir}/target/staging/org.springframework.batch.archetype/${project.artifactId} + + + spring-release + Spring Release Repository + file:///${user.dir}/target/staging/release + + + spring-snapshot + Spring Snapshot Repository + file:///${user.dir}/target/staging/snapshot + + + diff --git a/archetypes/simple-cli-javaconfig/src/main/assembly/descriptor.xml b/archetypes/simple-cli-javaconfig/src/main/assembly/descriptor.xml new file mode 100644 index 000000000..c28873cb2 --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/main/assembly/descriptor.xml @@ -0,0 +1,25 @@ + + distribution + + tar.gz + + false + + + src/main/scripts + bin + true + + + src/main/resources + resources + true + true + + + + + lib + + + diff --git a/archetypes/simple-cli-javaconfig/src/main/java/example/LaunchContext.java b/archetypes/simple-cli-javaconfig/src/main/java/example/LaunchContext.java new file mode 100644 index 000000000..8894a1ff5 --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/main/java/example/LaunchContext.java @@ -0,0 +1,94 @@ +package example; + +import javax.annotation.PostConstruct; +import javax.sql.DataSource; + +import org.apache.commons.dbcp.BasicDataSource; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider; +import org.springframework.batch.item.database.JdbcBatchItemWriter; +import org.springframework.batch.item.file.FlatFileItemReader; +import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper; +import org.springframework.batch.item.file.mapping.DefaultLineMapper; +import org.springframework.batch.item.file.transform.DelimitedLineTokenizer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; + +@Configuration +@PropertySource("classpath:batch.properties") +@EnableBatchProcessing +@Import(ModuleContext.class) +public class LaunchContext { + + @Autowired + Environment env; + + @Bean + static PropertyPlaceholderConfigurer configurer() { + return new PropertyPlaceholderConfigurer(); + } + + @Bean + ItemReader itemReader() { + FlatFileItemReader reader = new FlatFileItemReader(); + reader.setResource(new ClassPathResource("support/sample-data.csv")); + reader.setLineMapper(new DefaultLineMapper() {{ + setLineTokenizer(new DelimitedLineTokenizer() {{ + setNames(new String[] { "firstName", "lastName" }); + }}); + setFieldSetMapper(new BeanWrapperFieldSetMapper() {{ + setTargetType(Person.class); + }}); + }}); + return reader; + } + + @Bean + PersonItemProcessor itemProcess() { + return new PersonItemProcessor(); + } + + @Bean + ItemWriter itemWriter(DataSource dataSource) { + JdbcBatchItemWriter writer = new JdbcBatchItemWriter(); + writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider()); + writer.setSql(env.getProperty("person.insert.sql")); + writer.setDataSource(dataSource); + return writer; + } + + @Bean + BasicDataSource dataSource() { + BasicDataSource dataSource = new BasicDataSource(); + dataSource.setDriverClassName(env.getProperty("batch.jdbc.driver")); + dataSource.setUrl(env.getProperty("batch.jdbc.url")); + dataSource.setUsername(env.getProperty("batch.jdbc.user")); + dataSource.setPassword(env.getProperty("batch.jdbc.password")); + return dataSource; + } + + @Autowired + private ResourceLoader resourceLoader; + + @PostConstruct + protected void initialize() throws Exception { + ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); + populator.addScript(this.resourceLoader.getResource(env.getProperty("batch.drop.script"))); + populator.addScript(this.resourceLoader.getResource(env.getProperty("person.sql.location"))); + populator.addScript(this.resourceLoader.getResource(env.getProperty("batch.schema.script"))); + populator.setContinueOnError(true); + DatabasePopulatorUtils.execute(populator, dataSource()); + } + +} diff --git a/archetypes/simple-cli-javaconfig/src/main/java/example/ModuleContext.java b/archetypes/simple-cli-javaconfig/src/main/java/example/ModuleContext.java new file mode 100644 index 000000000..fc85f82aa --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/main/java/example/ModuleContext.java @@ -0,0 +1,37 @@ +package example; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; +import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.core.launch.support.RunIdIncrementer; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.ItemWriter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ModuleContext { + + @Bean + public Job personJob(JobBuilderFactory jobs, Step s1) { + return jobs.get("personJob") + .incrementer(new RunIdIncrementer()) + .flow(s1) + .end() + .build(); + } + + @Bean + public Step step1(StepBuilderFactory stepBuilderFactory, ItemReader reader, + ItemWriter writer, ItemProcessor processor) { + return stepBuilderFactory.get("step1") + . chunk(10) + .reader(reader) + .processor(processor) + .writer(writer) + .build(); + } + +} diff --git a/archetypes/simple-cli-javaconfig/src/main/java/example/Person.java b/archetypes/simple-cli-javaconfig/src/main/java/example/Person.java new file mode 100644 index 000000000..b829697a0 --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/main/java/example/Person.java @@ -0,0 +1,56 @@ +/* + * Copyright 2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example; + +/** + *

+ * Domain object representing information about a person. + *

+ */ +public class Person { + private String lastName; + private String firstName; + + public Person() { + + } + + public Person(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public void setFirstName(final String firstName) { + this.firstName = firstName; + } + + public String getFirstName() { + return firstName; + } + + public void setLastName(final String lastName) { + this.lastName = lastName; + } + + public String getLastName() { + return lastName; + } + + @Override + public String toString() { + return "firstName: " + firstName + ", lastName: " + lastName; + } +} diff --git a/archetypes/simple-cli-javaconfig/src/main/java/example/PersonItemProcessor.java b/archetypes/simple-cli-javaconfig/src/main/java/example/PersonItemProcessor.java new file mode 100644 index 000000000..b9a25bdea --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/main/java/example/PersonItemProcessor.java @@ -0,0 +1,38 @@ +/* + * Copyright 2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example; + +import org.springframework.batch.item.ItemProcessor; + +/** + *

+ * An example {@link org.springframework.batch.item.ItemProcessor} implementation that upper cases attributes on the + * provided {@link Person} object. + *

+ */ +public class PersonItemProcessor implements ItemProcessor { + @Override + public Person process(final Person person) throws Exception { + final String firstName = person.getFirstName().toUpperCase(); + final String lastName = person.getLastName().toUpperCase(); + + final Person transformedPerson = new Person(); + transformedPerson.setFirstName(firstName); + transformedPerson.setLastName(lastName); + + return transformedPerson; + } +} diff --git a/archetypes/simple-cli-javaconfig/src/main/resources/batch.properties b/archetypes/simple-cli-javaconfig/src/main/resources/batch.properties new file mode 100644 index 000000000..dea386513 --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/main/resources/batch.properties @@ -0,0 +1,15 @@ +# Placeholders batch.* +# for HSQLDB: +batch.jdbc.driver=org.hsqldb.jdbcDriver +batch.jdbc.url=jdbc:hsqldb:mem:testdb;sql.enforce_strict_size=true +# use this one for a separate server process so you can inspect the results +# (or add it to system properties with -D to override at run time). +# batch.jdbc.url=jdbc:hsqldb:hsql://localhost:9005/samples +batch.jdbc.user=sa +batch.jdbc.password= +batch.schema.script=classpath:org/springframework/batch/core/schema-hsqldb.sql +batch.drop.script=classpath:org/springframework/batch/core/schema-drop-hsqldb.sql +person.sql.location=classpath:support/person.sql +person.test.data.location=classpath:support/sample-data.csv +person.insert.sql=INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName) +step1.commit.interval=5 diff --git a/archetypes/simple-cli-javaconfig/src/main/resources/log4j.properties b/archetypes/simple-cli-javaconfig/src/main/resources/log4j.properties new file mode 100644 index 000000000..233de0696 --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/main/resources/log4j.properties @@ -0,0 +1,8 @@ +log4j.rootCategory=INFO, stdout + +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d %p %t [%c] - <%m>%n + +log4j.category.org.springframework.batch=DEBUG +log4j.category.org.springframework.transaction=INFO \ No newline at end of file diff --git a/archetypes/simple-cli-javaconfig/src/main/resources/support/person.sql b/archetypes/simple-cli-javaconfig/src/main/resources/support/person.sql new file mode 100644 index 000000000..4e405e6de --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/main/resources/support/person.sql @@ -0,0 +1,7 @@ +DROP TABLE people IF EXISTS; + +CREATE TABLE people ( + person_id BIGINT IDENTITY NOT NULL PRIMARY KEY, + first_name VARCHAR(20), + last_name VARCHAR(20) +); diff --git a/archetypes/simple-cli-javaconfig/src/main/resources/support/sample-data.csv b/archetypes/simple-cli-javaconfig/src/main/resources/support/sample-data.csv new file mode 100644 index 000000000..cead90f5a --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/main/resources/support/sample-data.csv @@ -0,0 +1,5 @@ +Jill,Doe +Joe,Doe +Justin,Doe +Jane,Doe +John,Doe diff --git a/archetypes/simple-cli-javaconfig/src/main/scripts/runJob.bat b/archetypes/simple-cli-javaconfig/src/main/scripts/runJob.bat new file mode 100644 index 000000000..72ed089a4 --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/main/scripts/runJob.bat @@ -0,0 +1,8 @@ +@echo off + +IF NOT DEFINED JAVA_HOME ( + echo Error: JAVA_HOME environment variable is not set. + EXIT /B +) + +%JAVA_HOME%\bin\java -cp resources\;lib\* org.springframework.batch.core.launch.support.CommandLineJobRunner classpath:/launch-context.xml personJob diff --git a/archetypes/simple-cli-javaconfig/src/main/scripts/runJob.sh b/archetypes/simple-cli-javaconfig/src/main/scripts/runJob.sh new file mode 100644 index 000000000..fe9e1c8bd --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/main/scripts/runJob.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +if [ "$JAVA_HOME" = "" ]; then + echo "Error: JAVA_HOME environment variable is not set." + exit 1 +fi + +$JAVA_HOME/bin/java -cp resources/:lib/* org.springframework.batch.core.launch.support.CommandLineJobRunner classpath:/launch-context.xml personJob diff --git a/archetypes/simple-cli-javaconfig/src/site/site.xml b/archetypes/simple-cli-javaconfig/src/site/site.xml new file mode 100644 index 000000000..42b3b297e --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/site/site.xml @@ -0,0 +1,20 @@ + + + + Spring Batch: ${project.name} + index.html + + + + org.springframework.maven.skins + maven-spring-skin + 1.0.5 + + + + + + + + + diff --git a/archetypes/simple-cli-javaconfig/src/test/java/example/PersonItemProcessorTest.java b/archetypes/simple-cli-javaconfig/src/test/java/example/PersonItemProcessorTest.java new file mode 100644 index 000000000..49f0d3da0 --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/test/java/example/PersonItemProcessorTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +/** + *

+ * Example test case processing a {@link Person} using the {@link PersonItemProcessor}. + *

+ */ +public class PersonItemProcessorTest { + @Test + public void testProcessedPersonRecord() throws Exception { + final Person person = new Person(); + person.setFirstName("Jane"); + person.setLastName("Doe"); + + final Person processedPerson = new PersonItemProcessor().process(person); + + assertEquals("First name does not match expected value.", "JANE", processedPerson.getFirstName()); + assertEquals("Last name does not match expected value.", "DOE", processedPerson.getLastName()); + } +} diff --git a/archetypes/simple-cli-javaconfig/src/test/java/example/PersonJobConfigurationTest.java b/archetypes/simple-cli-javaconfig/src/test/java/example/PersonJobConfigurationTest.java new file mode 100644 index 000000000..c119254eb --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/test/java/example/PersonJobConfigurationTest.java @@ -0,0 +1,97 @@ +/* + * Copyright 2006-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package example; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.batch.core.BatchStatus; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobInstance; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.launch.JobOperator; +import org.springframework.batch.test.JobLauncherTestUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +/** + *

+ * Test cases asserting on the example job's configuration. + *

+ */ +@ContextConfiguration(classes=TestContext.class) +@RunWith(SpringJUnit4ClassRunner.class) +public class PersonJobConfigurationTest { + @Autowired + private JobLauncher jobLauncher; + + @Autowired + private Job job; + + @Autowired + private JobOperator jobOperator; + + @Autowired + private JobLauncherTestUtils jobLauncherTestUtils; + + /** + *

+ * Creates a new {@link JobExecution} using a {@link JobLauncher}. + *

+ * + * @throws Exception if any {@link Exception}'s occur + */ + @Test + public void testLaunchJobWithJobLauncher() throws Exception { + final JobExecution jobExecution = jobLauncher.run(job, new JobParameters()); + assertEquals("Batch status not COMPLETED", BatchStatus.COMPLETED, jobExecution.getStatus()); + } + + /** + *

+ * Create a unique job instance and check it's execution completes successfully. + * Uses the convenience methods provided by the testing superclass. + *

+ * + * @throws Exception if any {@link Exception}'s occur + */ + @Test + public void testLaunchJob() throws Exception { + final JobExecution jobExecution = jobLauncherTestUtils.launchJob(jobLauncherTestUtils.getUniqueJobParameters()); + assertEquals("Batch status not COMPLETED", BatchStatus.COMPLETED, jobExecution.getStatus()); + } + + /** + *

+ * Execute a fresh {@link JobInstance} using {@link JobOperator} which is closer to + * a remote invocation scenario. + *

+ * + * @throws Exception if any {@link Exception}'s occur + */ + @Test + public void testLaunchByJobOperator() throws Exception { + final long jobExecutionId = jobOperator.startNextInstance(jobLauncherTestUtils.getJob().getName()); + + final String result = jobOperator.getSummary(jobExecutionId); + assertTrue("Result does not contain status=COMPLETED", result.contains("status=" + BatchStatus.COMPLETED)); + } +} diff --git a/archetypes/simple-cli-javaconfig/src/test/java/example/TestContext.java b/archetypes/simple-cli-javaconfig/src/test/java/example/TestContext.java new file mode 100644 index 000000000..19b5c27c8 --- /dev/null +++ b/archetypes/simple-cli-javaconfig/src/test/java/example/TestContext.java @@ -0,0 +1,59 @@ +package example; + +import javax.sql.DataSource; + +import org.springframework.batch.core.configuration.JobRegistry; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor; +import org.springframework.batch.core.configuration.support.MapJobRegistry; +import org.springframework.batch.core.explore.JobExplorer; +import org.springframework.batch.core.explore.support.JobExplorerFactoryBean; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.launch.JobOperator; +import org.springframework.batch.core.launch.support.SimpleJobOperator; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.test.JobLauncherTestUtils; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +@Configuration +@EnableBatchProcessing +@Import(LaunchContext.class) +public class TestContext { + + @Bean + JobLauncherTestUtils jobLauncherTestUtils() { + return new JobLauncherTestUtils(); + } + + @Bean + JobOperator jobOperator(final JobLauncher jobLauncher, final JobExplorer jobExplorer, + final JobRepository jobRepository, final JobRegistry jobRegistry) { + return new SimpleJobOperator() {{ + setJobLauncher(jobLauncher); + setJobExplorer(jobExplorer); + setJobRepository(jobRepository); + setJobRegistry(jobRegistry); + }}; + } + + @Bean + JobExplorerFactoryBean jobExplorer(final DataSource dataSource) { + return new JobExplorerFactoryBean() {{ + setDataSource(dataSource); + }}; + } + + @Bean + MapJobRegistry jobRegister() { + return new MapJobRegistry(); + } + + @Bean + JobRegistryBeanPostProcessor jobRegisterBeanPostProcess(final JobRegistry jobRegistry) { + return new JobRegistryBeanPostProcessor() {{ + setJobRegistry(jobRegistry); + }}; + } +} diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/CommandLineJobRunner.java b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/CommandLineJobRunner.java index b8c9e71cb..f4d05ace1 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/CommandLineJobRunner.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/CommandLineJobRunner.java @@ -47,10 +47,13 @@ import org.springframework.batch.core.launch.JobExecutionNotRunningException; import org.springframework.batch.core.launch.JobExecutionNotStoppedException; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.launch.JobParametersNotFoundException; +import org.springframework.batch.core.launch.NoSuchJobException; import org.springframework.batch.core.repository.JobRepository; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -281,7 +284,12 @@ public class CommandLineJobRunner { ConfigurableApplicationContext context = null; try { - context = new ClassPathXmlApplicationContext(jobPath); + try { + context = new ClassPathXmlApplicationContext(jobPath); + } catch (BeansException e) { + logger.info("No XML-based context named " + jobPath + ". Trying class-based configuration."); + context = new AnnotationConfigApplicationContext(Class.forName(jobPath)); + } context.getAutowireCapableBeanFactory().autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false); @@ -292,7 +300,7 @@ public class CommandLineJobRunner { } String jobName = jobIdentifier; - + JobParameters jobParameters = jobParametersConverter.getJobParameters(StringUtils .splitArrayElementsIntoProperties(parameters, "=")); Assert.isTrue(parameters == null || parameters.length == 0 || !jobParameters.isEmpty(), @@ -333,11 +341,14 @@ public class CommandLineJobRunner { jobName = jobExecution.getJobInstance().getJobName(); } - Job job; + Job job = null; if (jobLocator != null) { - job = jobLocator.getJob(jobName); + try { + job = jobLocator.getJob(jobName); + } catch (NoSuchJobException e) { + } } - else { + if (job == null) { job = (Job) context.getBean(jobName); } @@ -566,7 +577,7 @@ public class CommandLineJobRunner { } if (jobPath == null || jobIdentifier == null) { - String message = "At least 2 arguments are required: JobPath and jobIdentifier."; + String message = "At least 2 arguments are required: JobPath/JobClass and jobIdentifier."; logger.error(message); CommandLineJobRunner.message = message; command.exit(1);