package org.ohdsi.webapi; import javax.annotation.PostConstruct; import javax.sql.DataSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.ohdsi.webapi.job.JobTemplate; import org.springframework.batch.admin.service.JdbcSearchableJobExecutionDao; import org.springframework.batch.admin.service.JdbcSearchableJobInstanceDao; import org.springframework.batch.admin.service.SearchableJobExecutionDao; import org.springframework.batch.admin.service.SearchableJobInstanceDao; import org.springframework.batch.core.configuration.BatchConfigurationException; import org.springframework.batch.core.configuration.annotation.BatchConfigurer; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.explore.support.JobExplorerFactoryBean; import org.springframework.batch.core.explore.support.MapJobExplorerFactoryBean; 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.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.TaskExecutor; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.transaction.PlatformTransactionManager; /** * Had to copy DefaultBatchConfigurer and include within because jobLauncher config is private. * https://github.com/spring-projects/spring-boot/issues/1655 */ @Configuration @EnableBatchProcessing public class JobConfig { private static final Log log = LogFactory.getLog(CustomBatchConfigurer.class); @Value("${spring.batch.repository.tableprefix}") private String tablePrefix; @Value("${spring.batch.repository.isolationLevelForCreate}") private String isolationLevelForCreate; @Autowired private DataSource dataSource; @Bean public String batchTablePrefix() { return this.tablePrefix; } @Bean public TaskExecutor taskExecutor() { final ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(10); taskExecutor.setMaxPoolSize(20);//TODO taskExecutor.afterPropertiesSet(); return taskExecutor; } @Bean public BatchConfigurer batchConfigurer() { return new CustomBatchConfigurer(this.dataSource); } @Bean public JobTemplate jobTemplate(final JobLauncher jobLauncher, final JobBuilderFactory jobBuilders, final StepBuilderFactory stepBuilders) { return new JobTemplate(jobLauncher, jobBuilders, stepBuilders); } @Bean public SearchableJobExecutionDao searchableJobExecutionDao(DataSource dataSource) { JdbcSearchableJobExecutionDao dao = new JdbcSearchableJobExecutionDao(); dao.setDataSource(dataSource); return dao; } @Bean public SearchableJobInstanceDao searchableJobInstanceDao(JdbcTemplate jdbcTemplate) { JdbcSearchableJobInstanceDao dao = new JdbcSearchableJobInstanceDao(); dao.setJdbcTemplate(jdbcTemplate);//no setDataSource as in SearchableJobExecutionDao return dao; } class CustomBatchConfigurer implements BatchConfigurer { private DataSource dataSource; private PlatformTransactionManager transactionManager; private JobRepository jobRepository; private JobLauncher jobLauncher; private JobExplorer jobExplorer; @Autowired public void setDataSource(final DataSource dataSource) { this.dataSource = dataSource; // this.transactionManager = new DataSourceTransactionManager(dataSource); } @Autowired public void setTransactionManager(final PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } protected CustomBatchConfigurer() { } public CustomBatchConfigurer(final DataSource dataSource) { setDataSource(dataSource); } @Override public JobRepository getJobRepository() { return this.jobRepository; } @Override public PlatformTransactionManager getTransactionManager() { return this.transactionManager; } @Override public JobLauncher getJobLauncher() { return this.jobLauncher; } @Override public JobExplorer getJobExplorer() { return this.jobExplorer; } @PostConstruct public void initialize() { try { if (this.dataSource == null) { log.warn("No datasource was provided...using a Map based JobRepository"); if (this.transactionManager == null) { this.transactionManager = new ResourcelessTransactionManager(); } final MapJobRepositoryFactoryBean jobRepositoryFactory = new MapJobRepositoryFactoryBean( this.transactionManager); jobRepositoryFactory.afterPropertiesSet(); this.jobRepository = jobRepositoryFactory.getObject(); final MapJobExplorerFactoryBean jobExplorerFactory = new MapJobExplorerFactoryBean(jobRepositoryFactory); jobExplorerFactory.afterPropertiesSet(); this.jobExplorer = jobExplorerFactory.getObject(); } else { this.jobRepository = createJobRepository(); final JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean(); jobExplorerFactoryBean.setDataSource(this.dataSource); jobExplorerFactoryBean.afterPropertiesSet(); this.jobExplorer = jobExplorerFactoryBean.getObject(); } this.jobLauncher = createJobLauncher(); } catch (final Exception e) { throw new BatchConfigurationException(e); } } private JobLauncher createJobLauncher() throws Exception { final SimpleJobLauncher jobLauncher = new SimpleJobLauncher(); //async TODO jobLauncher.setTaskExecutor(taskExecutor()); jobLauncher.setJobRepository(this.jobRepository); jobLauncher.afterPropertiesSet(); return jobLauncher; } protected JobRepository createJobRepository() throws Exception { final JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean(); factory.setDataSource(this.dataSource); //prevent ISOLATION_DEFAULT setting for oracle (i.e. SERIALIZABLE) //ISOLATION_REPEATABLE_READ throws READ_COMMITTED and SERIALIZABLE are the only valid transaction levels factory.setIsolationLevelForCreate(JobConfig.this.isolationLevelForCreate); factory.setTablePrefix(JobConfig.this.tablePrefix); factory.setTransactionManager(getTransactionManager()); factory.afterPropertiesSet(); return factory.getObject(); } } } /*extends DefaultBatchConfigurer { private static final Log log = LogFactory.getLog(BatchConfig.class); @Autowired private JobBuilderFactory jobBuilders; @Autowired private StepBuilderFactory stepBuilders; @Autowired private DataSource dataSource; @Value("${spring.batch.repository.tableprefix}") private String tablePrefix; @Bean public String batchTablePrefix() { return this.tablePrefix; } @Override protected JobRepository createJobRepository() throws Exception { final JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean(); factory.setDataSource(this.dataSource); factory.setTablePrefix(this.tablePrefix); factory.setIsolationLevelForCreate(this.isolationLevel); factory.setTransactionManager(getTransactionManager()); factory.afterPropertiesSet(); return factory.getObject(); } @Bean public TaskExecutor taskExecutor() { final ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setMaxPoolSize(2);//TODO taskExecutor.afterPropertiesSet(); return taskExecutor; } } */