001/* 002 * Copyright 2012-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.autoconfigure.batch; 018 019import javax.annotation.PostConstruct; 020import javax.persistence.EntityManagerFactory; 021import javax.sql.DataSource; 022 023import org.apache.commons.logging.Log; 024import org.apache.commons.logging.LogFactory; 025 026import org.springframework.batch.core.configuration.annotation.BatchConfigurer; 027import org.springframework.batch.core.explore.JobExplorer; 028import org.springframework.batch.core.explore.support.JobExplorerFactoryBean; 029import org.springframework.batch.core.launch.JobLauncher; 030import org.springframework.batch.core.launch.support.SimpleJobLauncher; 031import org.springframework.batch.core.repository.JobRepository; 032import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean; 033import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; 034import org.springframework.jdbc.datasource.DataSourceTransactionManager; 035import org.springframework.orm.jpa.JpaTransactionManager; 036import org.springframework.transaction.PlatformTransactionManager; 037import org.springframework.util.StringUtils; 038 039/** 040 * Basic {@link BatchConfigurer} implementation. 041 * 042 * @author Dave Syer 043 * @author Andy Wilkinson 044 * @author Kazuki Shimizu 045 */ 046public class BasicBatchConfigurer implements BatchConfigurer { 047 048 private static final Log logger = LogFactory.getLog(BasicBatchConfigurer.class); 049 050 private final BatchProperties properties; 051 052 private final DataSource dataSource; 053 054 private final EntityManagerFactory entityManagerFactory; 055 056 private PlatformTransactionManager transactionManager; 057 058 private final TransactionManagerCustomizers transactionManagerCustomizers; 059 060 private JobRepository jobRepository; 061 062 private JobLauncher jobLauncher; 063 064 private JobExplorer jobExplorer; 065 066 /** 067 * Create a new {@link BasicBatchConfigurer} instance. 068 * @param properties the batch properties 069 * @param dataSource the underlying data source 070 * @param transactionManagerCustomizers transaction manager customizers (or 071 * {@code null}) 072 */ 073 protected BasicBatchConfigurer(BatchProperties properties, DataSource dataSource, 074 TransactionManagerCustomizers transactionManagerCustomizers) { 075 this(properties, dataSource, null, transactionManagerCustomizers); 076 } 077 078 /** 079 * Create a new {@link BasicBatchConfigurer} instance. 080 * @param properties the batch properties 081 * @param dataSource the underlying data source 082 * @param entityManagerFactory the entity manager factory (or {@code null}) 083 * @param transactionManagerCustomizers transaction manager customizers (or 084 * {@code null}) 085 */ 086 protected BasicBatchConfigurer(BatchProperties properties, DataSource dataSource, 087 EntityManagerFactory entityManagerFactory, 088 TransactionManagerCustomizers transactionManagerCustomizers) { 089 this.properties = properties; 090 this.entityManagerFactory = entityManagerFactory; 091 this.dataSource = dataSource; 092 this.transactionManagerCustomizers = transactionManagerCustomizers; 093 } 094 095 @Override 096 public JobRepository getJobRepository() { 097 return this.jobRepository; 098 } 099 100 @Override 101 public PlatformTransactionManager getTransactionManager() { 102 return this.transactionManager; 103 } 104 105 @Override 106 public JobLauncher getJobLauncher() { 107 return this.jobLauncher; 108 } 109 110 @Override 111 public JobExplorer getJobExplorer() throws Exception { 112 return this.jobExplorer; 113 } 114 115 @PostConstruct 116 public void initialize() { 117 try { 118 this.transactionManager = createTransactionManager(); 119 this.jobRepository = createJobRepository(); 120 this.jobLauncher = createJobLauncher(); 121 this.jobExplorer = createJobExplorer(); 122 } 123 catch (Exception ex) { 124 throw new IllegalStateException("Unable to initialize Spring Batch", ex); 125 } 126 } 127 128 protected JobExplorer createJobExplorer() throws Exception { 129 JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean(); 130 jobExplorerFactoryBean.setDataSource(this.dataSource); 131 String tablePrefix = this.properties.getTablePrefix(); 132 if (StringUtils.hasText(tablePrefix)) { 133 jobExplorerFactoryBean.setTablePrefix(tablePrefix); 134 } 135 jobExplorerFactoryBean.afterPropertiesSet(); 136 return jobExplorerFactoryBean.getObject(); 137 } 138 139 protected JobLauncher createJobLauncher() throws Exception { 140 SimpleJobLauncher jobLauncher = new SimpleJobLauncher(); 141 jobLauncher.setJobRepository(getJobRepository()); 142 jobLauncher.afterPropertiesSet(); 143 return jobLauncher; 144 } 145 146 protected JobRepository createJobRepository() throws Exception { 147 JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean(); 148 factory.setDataSource(this.dataSource); 149 if (this.entityManagerFactory != null) { 150 logger.warn( 151 "JPA does not support custom isolation levels, so locks may not be taken when launching Jobs"); 152 factory.setIsolationLevelForCreate("ISOLATION_DEFAULT"); 153 } 154 String tablePrefix = this.properties.getTablePrefix(); 155 if (StringUtils.hasText(tablePrefix)) { 156 factory.setTablePrefix(tablePrefix); 157 } 158 factory.setTransactionManager(getTransactionManager()); 159 factory.afterPropertiesSet(); 160 return factory.getObject(); 161 } 162 163 protected PlatformTransactionManager createTransactionManager() { 164 PlatformTransactionManager transactionManager = createAppropriateTransactionManager(); 165 if (this.transactionManagerCustomizers != null) { 166 this.transactionManagerCustomizers.customize(transactionManager); 167 } 168 return transactionManager; 169 } 170 171 private PlatformTransactionManager createAppropriateTransactionManager() { 172 if (this.entityManagerFactory != null) { 173 return new JpaTransactionManager(this.entityManagerFactory); 174 } 175 return new DataSourceTransactionManager(this.dataSource); 176 } 177 178}