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
This commit is contained in:
committed by
Michael Minella
parent
42dccf6efb
commit
bb1ec38a18
@@ -0,0 +1,25 @@
|
||||
<assembly>
|
||||
<id>distribution</id>
|
||||
<formats>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>src/main/scripts</directory>
|
||||
<outputDirectory>bin</outputDirectory>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>src/main/resources</directory>
|
||||
<outputDirectory>resources</outputDirectory>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<filtered>true</filtered>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<outputDirectory>lib</outputDirectory>
|
||||
</dependencySet>
|
||||
</dependencySets>
|
||||
</assembly>
|
||||
@@ -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<Person> itemReader() {
|
||||
FlatFileItemReader<Person> reader = new FlatFileItemReader<Person>();
|
||||
reader.setResource(new ClassPathResource("support/sample-data.csv"));
|
||||
reader.setLineMapper(new DefaultLineMapper<Person>() {{
|
||||
setLineTokenizer(new DelimitedLineTokenizer() {{
|
||||
setNames(new String[] { "firstName", "lastName" });
|
||||
}});
|
||||
setFieldSetMapper(new BeanWrapperFieldSetMapper<Person>() {{
|
||||
setTargetType(Person.class);
|
||||
}});
|
||||
}});
|
||||
return reader;
|
||||
}
|
||||
|
||||
@Bean
|
||||
PersonItemProcessor itemProcess() {
|
||||
return new PersonItemProcessor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
ItemWriter<Person> itemWriter(DataSource dataSource) {
|
||||
JdbcBatchItemWriter<Person> writer = new JdbcBatchItemWriter<Person>();
|
||||
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Person>());
|
||||
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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<Person> reader,
|
||||
ItemWriter<Person> writer, ItemProcessor<Person, Person> processor) {
|
||||
return stepBuilderFactory.get("step1")
|
||||
.<Person, Person> chunk(10)
|
||||
.reader(reader)
|
||||
.processor(processor)
|
||||
.writer(writer)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Domain object representing information about a person.
|
||||
* </p>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* An example {@link org.springframework.batch.item.ItemProcessor} implementation that upper cases attributes on the
|
||||
* provided {@link Person} object.
|
||||
* </p>
|
||||
*/
|
||||
public class PersonItemProcessor implements ItemProcessor<Person, Person> {
|
||||
@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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
);
|
||||
@@ -0,0 +1,5 @@
|
||||
Jill,Doe
|
||||
Joe,Doe
|
||||
Justin,Doe
|
||||
Jane,Doe
|
||||
John,Doe
|
||||
|
@@ -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
|
||||
@@ -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
|
||||
20
archetypes/simple-cli-javaconfig/src/site/site.xml
Normal file
20
archetypes/simple-cli-javaconfig/src/site/site.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<project name="Spring Batch: ${project.name}">
|
||||
<bannerLeft>
|
||||
<name>Spring Batch: ${project.name}</name>
|
||||
<href>index.html</href>
|
||||
</bannerLeft>
|
||||
|
||||
<skin>
|
||||
<groupId>org.springframework.maven.skins</groupId>
|
||||
<artifactId>maven-spring-skin</artifactId>
|
||||
<version>1.0.5</version>
|
||||
</skin>
|
||||
|
||||
<body>
|
||||
<links>
|
||||
<item name="${project.name}" href="index.html"/>
|
||||
</links>
|
||||
<menu ref="reports"/>
|
||||
</body>
|
||||
</project>
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Example test case processing a {@link Person} using the {@link PersonItemProcessor}.
|
||||
* </p>
|
||||
*/
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Test cases asserting on the example job's configuration.
|
||||
* </p>
|
||||
*/
|
||||
@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;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Creates a new {@link JobExecution} using a {@link JobLauncher}.
|
||||
* </p>
|
||||
*
|
||||
* @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());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Create a unique job instance and check it's execution completes successfully.
|
||||
* Uses the convenience methods provided by the testing superclass.
|
||||
* </p>
|
||||
*
|
||||
* @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());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Execute a fresh {@link JobInstance} using {@link JobOperator} which is closer to
|
||||
* a remote invocation scenario.
|
||||
* </p>
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user