001/*
002 * Copyright 2012-2018 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.sql.DataSource;
021
022import org.springframework.batch.core.configuration.annotation.BatchConfigurer;
023import org.springframework.batch.core.explore.JobExplorer;
024import org.springframework.batch.core.explore.support.JobExplorerFactoryBean;
025import org.springframework.batch.core.launch.JobLauncher;
026import org.springframework.batch.core.launch.support.SimpleJobLauncher;
027import org.springframework.batch.core.repository.JobRepository;
028import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
029import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
030import org.springframework.boot.context.properties.PropertyMapper;
031import org.springframework.jdbc.datasource.DataSourceTransactionManager;
032import org.springframework.transaction.PlatformTransactionManager;
033
034/**
035 * Basic {@link BatchConfigurer} implementation.
036 *
037 * @author Dave Syer
038 * @author Andy Wilkinson
039 * @author Kazuki Shimizu
040 * @author Stephane Nicoll
041 */
042public class BasicBatchConfigurer implements BatchConfigurer {
043
044        private final BatchProperties properties;
045
046        private final DataSource dataSource;
047
048        private PlatformTransactionManager transactionManager;
049
050        private final TransactionManagerCustomizers transactionManagerCustomizers;
051
052        private JobRepository jobRepository;
053
054        private JobLauncher jobLauncher;
055
056        private JobExplorer jobExplorer;
057
058        /**
059         * Create a new {@link BasicBatchConfigurer} instance.
060         * @param properties the batch properties
061         * @param dataSource the underlying data source
062         * @param transactionManagerCustomizers transaction manager customizers (or
063         * {@code null})
064         */
065        protected BasicBatchConfigurer(BatchProperties properties, DataSource dataSource,
066                        TransactionManagerCustomizers transactionManagerCustomizers) {
067                this.properties = properties;
068                this.dataSource = dataSource;
069                this.transactionManagerCustomizers = transactionManagerCustomizers;
070        }
071
072        @Override
073        public JobRepository getJobRepository() {
074                return this.jobRepository;
075        }
076
077        @Override
078        public PlatformTransactionManager getTransactionManager() {
079                return this.transactionManager;
080        }
081
082        @Override
083        public JobLauncher getJobLauncher() {
084                return this.jobLauncher;
085        }
086
087        @Override
088        public JobExplorer getJobExplorer() throws Exception {
089                return this.jobExplorer;
090        }
091
092        @PostConstruct
093        public void initialize() {
094                try {
095                        this.transactionManager = buildTransactionManager();
096                        this.jobRepository = createJobRepository();
097                        this.jobLauncher = createJobLauncher();
098                        this.jobExplorer = createJobExplorer();
099                }
100                catch (Exception ex) {
101                        throw new IllegalStateException("Unable to initialize Spring Batch", ex);
102                }
103        }
104
105        protected JobExplorer createJobExplorer() throws Exception {
106                PropertyMapper map = PropertyMapper.get();
107                JobExplorerFactoryBean factory = new JobExplorerFactoryBean();
108                factory.setDataSource(this.dataSource);
109                map.from(this.properties::getTablePrefix).whenHasText()
110                                .to(factory::setTablePrefix);
111                factory.afterPropertiesSet();
112                return factory.getObject();
113        }
114
115        protected JobLauncher createJobLauncher() throws Exception {
116                SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
117                jobLauncher.setJobRepository(getJobRepository());
118                jobLauncher.afterPropertiesSet();
119                return jobLauncher;
120        }
121
122        protected JobRepository createJobRepository() throws Exception {
123                JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
124                PropertyMapper map = PropertyMapper.get();
125                map.from(this.dataSource).to(factory::setDataSource);
126                map.from(this::determineIsolationLevel).whenNonNull()
127                                .to(factory::setIsolationLevelForCreate);
128                map.from(this.properties::getTablePrefix).whenHasText()
129                                .to(factory::setTablePrefix);
130                map.from(this::getTransactionManager).to(factory::setTransactionManager);
131                factory.afterPropertiesSet();
132                return factory.getObject();
133        }
134
135        /**
136         * Determine the isolation level for create* operation of the {@link JobRepository}.
137         * @return the isolation level or {@code null} to use the default
138         */
139        protected String determineIsolationLevel() {
140                return null;
141        }
142
143        protected PlatformTransactionManager createTransactionManager() {
144                return new DataSourceTransactionManager(this.dataSource);
145        }
146
147        private PlatformTransactionManager buildTransactionManager() {
148                PlatformTransactionManager transactionManager = createTransactionManager();
149                if (this.transactionManagerCustomizers != null) {
150                        this.transactionManagerCustomizers.customize(transactionManager);
151                }
152                return transactionManager;
153        }
154
155}