BATCH-2048: Simplified the use fo a MapJobRepository by making the DataSource optional
This commit is contained in:
@@ -15,10 +15,6 @@
|
||||
*/
|
||||
package org.springframework.batch.core.configuration.annotation;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.batch.core.configuration.JobRegistry;
|
||||
import org.springframework.batch.core.configuration.support.MapJobRegistry;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
@@ -35,6 +31,9 @@ import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Base {@code Configuration} class providing common structure for enabling and using Spring Batch. Customization is
|
||||
* available by implementing the {@link BatchConfigurer} interface. {@link BatchConfigurer}.
|
||||
@@ -92,16 +91,21 @@ public abstract class AbstractBatchConfiguration implements ImportAware {
|
||||
return this.configurer;
|
||||
}
|
||||
if (configurers == null || configurers.isEmpty()) {
|
||||
if (dataSources == null || dataSources.isEmpty() || dataSources.size() > 1) {
|
||||
throw new IllegalStateException(
|
||||
"To use the default BatchConfigurer the context must contain precisely one DataSource, found "
|
||||
+ (dataSources == null ? 0 : dataSources.size()));
|
||||
if (dataSources == null || dataSources.isEmpty()) {
|
||||
DefaultBatchConfigurer configurer = new DefaultBatchConfigurer();
|
||||
configurer.initialize();
|
||||
this.configurer = configurer;
|
||||
return configurer;
|
||||
} else if(dataSources != null && dataSources.size() == 1) {
|
||||
DataSource dataSource = dataSources.iterator().next();
|
||||
DefaultBatchConfigurer configurer = new DefaultBatchConfigurer(dataSource);
|
||||
configurer.initialize();
|
||||
this.configurer = configurer;
|
||||
return configurer;
|
||||
} else {
|
||||
throw new IllegalStateException("To use the default BatchConfigurer the context must contain no more than" +
|
||||
"one DataSource, found " + dataSources.size());
|
||||
}
|
||||
DataSource dataSource = dataSources.iterator().next();
|
||||
DefaultBatchConfigurer configurer = new DefaultBatchConfigurer(dataSource);
|
||||
configurer.initialize();
|
||||
this.configurer = configurer;
|
||||
return configurer;
|
||||
}
|
||||
if (configurers.size() > 1) {
|
||||
throw new IllegalStateException(
|
||||
|
||||
@@ -15,27 +15,32 @@
|
||||
*/
|
||||
package org.springframework.batch.core.configuration.annotation;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.batch.core.launch.support.SimpleJobLauncher;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
|
||||
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
|
||||
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@Component
|
||||
public class DefaultBatchConfigurer implements BatchConfigurer {
|
||||
private static final Log logger = LogFactory.getLog(DefaultBatchConfigurer.class);
|
||||
|
||||
private DataSource dataSource;
|
||||
private PlatformTransactionManager transactionManager;
|
||||
private JobRepository jobRepository;
|
||||
private JobLauncher jobLauncher;
|
||||
|
||||
@Autowired
|
||||
@Autowired(required = false)
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
this.transactionManager = new DataSourceTransactionManager(dataSource);
|
||||
@@ -64,7 +69,20 @@ public class DefaultBatchConfigurer implements BatchConfigurer {
|
||||
|
||||
@PostConstruct
|
||||
public void initialize() throws Exception {
|
||||
this.jobRepository = createJobRepository();
|
||||
if(dataSource == null) {
|
||||
logger.warn("No datasource was provided...using a Map based JobRepository");
|
||||
|
||||
if(this.transactionManager == null) {
|
||||
this.transactionManager = new ResourcelessTransactionManager();
|
||||
}
|
||||
|
||||
MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean(this.transactionManager);
|
||||
factory.afterPropertiesSet();
|
||||
this.jobRepository = factory.getObject();
|
||||
} else {
|
||||
this.jobRepository = createJobRepository();
|
||||
}
|
||||
|
||||
this.jobLauncher = createJobLauncher();
|
||||
}
|
||||
|
||||
@@ -82,5 +100,4 @@ public class DefaultBatchConfigurer implements BatchConfigurer {
|
||||
factory.afterPropertiesSet();
|
||||
return factory.getObject();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
* Copyright 2012-2014 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.
|
||||
@@ -15,14 +15,6 @@
|
||||
*/
|
||||
package org.springframework.batch.core.configuration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.batch.core.configuration.JobRegistry;
|
||||
import org.springframework.batch.core.configuration.support.ApplicationContextFactory;
|
||||
import org.springframework.batch.core.configuration.support.AutomaticJobRegistrar;
|
||||
@@ -31,6 +23,13 @@ import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Enable Spring Batch features and provide a base configuration for setting up batch jobs in an @Configuration
|
||||
@@ -62,7 +61,7 @@ import org.springframework.transaction.PlatformTransactionManager;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* The user has to provide a {@link DataSource} as a bean in the context, or else implement {@link BatchConfigurer} in
|
||||
* The user should to provide a {@link DataSource} as a bean in the context, or else implement {@link BatchConfigurer} in
|
||||
* the configuration class itself, e.g.
|
||||
*
|
||||
* <pre class="code">
|
||||
@@ -85,6 +84,9 @@ import org.springframework.transaction.PlatformTransactionManager;
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* If a user does not provide a {@link javax.sql.DataSource} within the context, a Map based
|
||||
* {@link org.springframework.batch.core.repository.JobRepository} will be used.
|
||||
*
|
||||
* Note that only one of your configuration classes needs to have the <code>@EnableBatchProcessing</code>
|
||||
* annotation. Once you have an <code>@EnableBatchProcessing</code> class in your configuration you will have an
|
||||
* instance of {@link StepScope} so your beans inside steps can have <code>@Scope("step")</code>. You will also be
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2014 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 org.springframework.batch.core.configuration.annotation;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.BatchStatus;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.PooledEmbeddedDataSource;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
public class MapJobRepositoryConfigurationTests {
|
||||
|
||||
JobLauncher jobLauncher;
|
||||
JobRepository jobRepository;
|
||||
Job job;
|
||||
|
||||
@Test
|
||||
public void testRoseyScenario() throws Exception {
|
||||
testConfigurationClass(MapRepositoryBatchConfiguration.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneDataSource() throws Exception {
|
||||
testConfigurationClass(HsqlBatchConfiguration.class);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testMultipleDataSources() throws Exception {
|
||||
testConfigurationClass(InvalidBatchConfiguration.class);
|
||||
}
|
||||
|
||||
private void testConfigurationClass(Class clazz) throws Exception {
|
||||
GenericApplicationContext context = new AnnotationConfigApplicationContext(clazz);
|
||||
this.jobLauncher = context.getBean(JobLauncher.class);
|
||||
this.jobRepository = context.getBean(JobRepository.class);
|
||||
this.job = context.getBean(Job.class);
|
||||
|
||||
JobExecution jobExecution = jobLauncher.run(job, new JobParameters());
|
||||
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
|
||||
JobExecution repositoryJobExecution = jobRepository.getLastJobExecution(job.getName(), new JobParameters());
|
||||
assertEquals(jobExecution.getId(), repositoryJobExecution.getId());
|
||||
context.close();
|
||||
}
|
||||
|
||||
public static class InvalidBatchConfiguration extends HsqlBatchConfiguration {
|
||||
|
||||
@Bean
|
||||
DataSource dataSource2() {
|
||||
return new PooledEmbeddedDataSource(new EmbeddedDatabaseBuilder().setName("badDatabase").build());
|
||||
}
|
||||
}
|
||||
|
||||
public static class HsqlBatchConfiguration extends MapRepositoryBatchConfiguration {
|
||||
|
||||
@Bean
|
||||
DataSource dataSource() {
|
||||
return new PooledEmbeddedDataSource(new EmbeddedDatabaseBuilder().
|
||||
addScript("classpath:org/springframework/batch/core/schema-drop-hsqldb.sql").
|
||||
addScript("classpath:org/springframework/batch/core/schema-hsqldb.sql").
|
||||
build());
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
@EnableBatchProcessing
|
||||
public static class MapRepositoryBatchConfiguration {
|
||||
@Autowired
|
||||
JobBuilderFactory jobFactory;
|
||||
|
||||
@Autowired
|
||||
StepBuilderFactory stepFactory;
|
||||
|
||||
@Bean
|
||||
Step step1 () {
|
||||
return stepFactory.get("step1").tasklet(new Tasklet() {
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
}).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
Job job() {
|
||||
return jobFactory.get("job").start(step1()).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user