001/*
002 *  Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
003 *  <p>
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 *  <p>
008 *  http://www.apache.org/licenses/LICENSE-2.0
009 *  <p>
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 */
016package com.mybatisflex.core;
017
018import com.mybatisflex.core.datasource.FlexDataSource;
019import com.mybatisflex.core.exception.FlexAssert;
020import com.mybatisflex.core.mybatis.FlexConfiguration;
021import com.mybatisflex.core.mybatis.FlexSqlSessionFactoryBuilder;
022import com.mybatisflex.core.mybatis.Mappers;
023import org.apache.ibatis.logging.Log;
024import org.apache.ibatis.logging.LogFactory;
025import org.apache.ibatis.mapping.Environment;
026import org.apache.ibatis.session.Configuration;
027import org.apache.ibatis.transaction.TransactionFactory;
028import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
029
030import javax.sql.DataSource;
031import java.util.ArrayList;
032import java.util.List;
033import java.util.concurrent.atomic.AtomicBoolean;
034
035/**
036 * MybatisFlex 的启动类
037 *
038 * <code>
039 * MybatisFlexBootstrap.getInstance()
040 * .setDatasource(...)
041 * .addMapper(...)
042 * .start();
043 * <p>
044 * <p>
045 * MybatisFlexBootstrap.getInstance()
046 * .execute(...)
047 * </code>
048 */
049public class MybatisFlexBootstrap {
050
051    protected final AtomicBoolean started = new AtomicBoolean(false);
052
053    protected String environmentId = FlexConsts.NAME;
054    protected TransactionFactory transactionFactory;
055
056    protected FlexDataSource dataSource;
057    protected Configuration configuration;
058    protected List<Class<?>> mappers;
059
060    protected Class<? extends Log> logImpl;
061
062
063    /**
064     * 虽然提供了 getInstance,但也允许用户进行实例化,
065     * 用于创建多个 MybatisFlexBootstrap 实例达到管理多数据源的目的
066     */
067    public MybatisFlexBootstrap() {
068
069    }
070
071    private static volatile MybatisFlexBootstrap instance;
072
073    public static MybatisFlexBootstrap getInstance() {
074        if (instance == null) {
075            synchronized (MybatisFlexBootstrap.class) {
076                if (instance == null) {
077                    instance = new MybatisFlexBootstrap();
078                }
079            }
080        }
081        return instance;
082    }
083
084
085    public <T> MybatisFlexBootstrap addMapper(Class<T> type) {
086        if (this.mappers == null) {
087            mappers = new ArrayList<>();
088        }
089        mappers.add(type);
090        return this;
091    }
092
093
094    public MybatisFlexBootstrap start() {
095        if (started.compareAndSet(false, true)) {
096
097            FlexAssert.notNull(dataSource,"dataSource");
098
099            //init configuration
100            if (configuration == null) {
101
102                if (transactionFactory == null) {
103                    transactionFactory = new JdbcTransactionFactory();
104                }
105
106                Environment environment = new Environment(environmentId, transactionFactory, dataSource);
107                configuration = new FlexConfiguration(environment);
108            }
109
110            if (logImpl != null) {
111                configuration.setLogImpl(logImpl);
112            }
113
114            //init sqlSessionFactory
115            new FlexSqlSessionFactoryBuilder().build(configuration);
116
117            //init mappers
118            if (mappers != null) {
119                mappers.forEach(configuration::addMapper);
120            }
121
122            LogFactory.getLog(MybatisFlexBootstrap.class).debug("Mybatis-Flex has started.");
123        }
124
125        return this;
126    }
127
128
129    /**
130     * 直接获取 mapper 对象执行
131     *
132     * @param mapperClass
133     * @return mapperObject
134     */
135    public <T> T getMapper(Class<T> mapperClass) {
136        return Mappers.ofMapperClass(mapperClass);
137    }
138
139
140    public String getEnvironmentId() {
141        return environmentId;
142    }
143
144    public MybatisFlexBootstrap setEnvironmentId(String environmentId) {
145        this.environmentId = environmentId;
146        return this;
147    }
148
149    public TransactionFactory getTransactionFactory() {
150        return transactionFactory;
151    }
152
153    public MybatisFlexBootstrap setTransactionFactory(TransactionFactory transactionFactory) {
154        this.transactionFactory = transactionFactory;
155        return this;
156    }
157
158    public DataSource getDataSource() {
159        return dataSource;
160    }
161
162    public MybatisFlexBootstrap setDataSource(DataSource dataSource) {
163        this.dataSource = new FlexDataSource(FlexConsts.NAME, dataSource);
164        return this;
165    }
166
167    public MybatisFlexBootstrap setDataSource(String dataSourceKey, DataSource dataSource) {
168        this.dataSource = new FlexDataSource(dataSourceKey, dataSource);
169        return this;
170    }
171
172    public MybatisFlexBootstrap addDataSource(String dataSourceKey, DataSource dataSource) {
173        if (this.dataSource == null) {
174            this.dataSource = new FlexDataSource(dataSourceKey, dataSource);
175        } else {
176            this.dataSource.addDataSource(dataSourceKey, dataSource);
177        }
178        return this;
179    }
180
181    public Configuration getConfiguration() {
182        return configuration;
183    }
184
185    public MybatisFlexBootstrap setConfiguration(FlexConfiguration configuration) {
186        this.configuration = configuration;
187        this.environmentId = configuration.getEnvironment().getId();
188        return this;
189    }
190
191    public List<Class<?>> getMappers() {
192        return mappers;
193    }
194
195
196    public Class<? extends Log> getLogImpl() {
197        return logImpl;
198    }
199
200    public MybatisFlexBootstrap setLogImpl(Class<? extends Log> logImpl) {
201        this.logImpl = logImpl;
202        return this;
203    }
204
205}