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.annotation.InsertListener;
019import com.mybatisflex.annotation.KeyType;
020import com.mybatisflex.annotation.Listener;
021import com.mybatisflex.annotation.SetListener;
022import com.mybatisflex.annotation.UpdateListener;
023import com.mybatisflex.core.datasource.FlexDataSource;
024import com.mybatisflex.core.dialect.DbType;
025import com.mybatisflex.core.exception.FlexAssert;
026import org.apache.ibatis.session.Configuration;
027import org.apache.ibatis.session.SqlSessionFactory;
028
029import javax.sql.DataSource;
030import java.util.ArrayList;
031import java.util.List;
032import java.util.Map;
033import java.util.concurrent.ConcurrentHashMap;
034import java.util.stream.Collectors;
035
036/**
037 * 全局配置文件
038 */
039public class FlexGlobalConfig {
040
041    /**
042     * 启动是否打印 banner 和 版本号
043     */
044    private boolean printBanner = true;
045
046    /**
047     * 默认使用 Mysql 数据库类型
048     */
049    private DbType dbType = DbType.MYSQL;
050
051    /**
052     * Mybatis 配置
053     */
054    private Configuration configuration;
055
056    /**
057     * 创建好的 sqlSessionFactory
058     */
059    private SqlSessionFactory sqlSessionFactory;
060
061    /**
062     * 全局的 ID 生成策略配置,当 @Id 未配置 或者 配置 KeyType 为 None 时
063     * 使用当前全局配置
064     */
065    private KeyConfig keyConfig;
066
067    /**
068     * entity 的监听器
069     */
070    private Map<Class<?>, List<SetListener>> entitySetListeners = new ConcurrentHashMap<>();
071    private Map<Class<?>, List<UpdateListener>> entityUpdateListeners = new ConcurrentHashMap<>();
072    private Map<Class<?>, List<InsertListener>> entityInsertListeners = new ConcurrentHashMap<>();
073
074
075    /**
076     * 逻辑删除的相关配置
077     */
078    private Object normalValueOfLogicDelete = FlexConsts.LOGIC_DELETE_NORMAL;
079    private Object deletedValueOfLogicDelete = FlexConsts.LOGIC_DELETE_DELETED;
080
081    /**
082     * 分页查询时,默认每页显示的数据数量。
083     */
084    private int defaultPageSize = 10;
085
086    /**
087     * 分页查询时,默认每页显示的数据数量最大限制。
088     */
089    private int defaultMaxPageSize = Integer.MAX_VALUE;
090
091
092    /**
093     * 默认的 Relation 注解查询深度
094     */
095    private int defaultRelationQueryDepth = 2;
096
097    /**
098     * 默认的逻辑删除字段,允许设置 {@code null} 忽略匹配。
099     */
100    private String logicDeleteColumn;
101
102    /**
103     * 默认的多租户字段,允许设置 {@code null} 忽略匹配。
104     */
105    private String tenantColumn;
106
107    /**
108     * 默认的乐观锁字段,允许设置 {@code null} 忽略匹配。
109     */
110    private String versionColumn;
111
112    public boolean isPrintBanner() {
113        return printBanner;
114    }
115
116    public void setPrintBanner(boolean printBanner) {
117        this.printBanner = printBanner;
118    }
119
120    public DbType getDbType() {
121        return dbType;
122    }
123
124    public void setDbType(DbType dbType) {
125        this.dbType = dbType;
126    }
127
128    public Configuration getConfiguration() {
129        return configuration;
130    }
131
132    public void setConfiguration(Configuration configuration) {
133        this.configuration = configuration;
134        DataSource dataSource = configuration.getEnvironment().getDataSource();
135        if (dataSource instanceof FlexDataSource) {
136            this.dbType = ((FlexDataSource) dataSource).getDefaultDbType();
137        }
138    }
139
140    public SqlSessionFactory getSqlSessionFactory() {
141        return sqlSessionFactory;
142    }
143
144    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
145        this.sqlSessionFactory = sqlSessionFactory;
146    }
147
148    public KeyConfig getKeyConfig() {
149        return keyConfig;
150    }
151
152    public void setKeyConfig(KeyConfig keyConfig) {
153        this.keyConfig = keyConfig;
154    }
155
156    public Map<Class<?>, List<SetListener>> getEntitySetListeners() {
157        return entitySetListeners;
158    }
159
160    public void setEntitySetListeners(Map<Class<?>, List<SetListener>> entitySetListeners) {
161        this.entitySetListeners = entitySetListeners;
162    }
163
164    public Map<Class<?>, List<UpdateListener>> getEntityUpdateListeners() {
165        return entityUpdateListeners;
166    }
167
168    public void setEntityUpdateListeners(Map<Class<?>, List<UpdateListener>> entityUpdateListeners) {
169        this.entityUpdateListeners = entityUpdateListeners;
170    }
171
172    public Map<Class<?>, List<InsertListener>> getEntityInsertListeners() {
173        return entityInsertListeners;
174    }
175
176    public void setEntityInsertListeners(Map<Class<?>, List<InsertListener>> entityInsertListeners) {
177        this.entityInsertListeners = entityInsertListeners;
178    }
179
180    public void registerSetListener(SetListener listener, Class<?>... classes) {
181        for (Class<?> aClass : classes) {
182            entitySetListeners.computeIfAbsent(aClass, k -> new ArrayList<>()).add(listener);
183        }
184    }
185
186    public void registerUpdateListener(UpdateListener listener, Class<?>... classes) {
187        for (Class<?> aClass : classes) {
188            entityUpdateListeners.computeIfAbsent(aClass, k -> new ArrayList<>()).add(listener);
189        }
190    }
191
192    public void registerInsertListener(InsertListener listener, Class<?>... classes) {
193        for (Class<?> aClass : classes) {
194            entityInsertListeners.computeIfAbsent(aClass, k -> new ArrayList<>()).add(listener);
195        }
196    }
197
198    public List<SetListener> getSetListener(Class<?> entityClass) {
199        return entitySetListeners.get(entityClass);
200    }
201
202    /**
203     * 获取支持该 {@code entityClass} 的set监听器
204     * <p>当registerClass是entityClass的本身或其超类时,则视为支持</p>
205     *
206     * @param entityClass 实体class
207     * @return UpdateListener
208     */
209    public List<SetListener> getSupportedSetListener(Class<?> entityClass) {
210        return this.findSupportedListeners(entityClass, this.entitySetListeners);
211    }
212
213    public List<UpdateListener> getUpdateListener(Class<?> entityClass) {
214        return entityUpdateListeners.get(entityClass);
215    }
216
217    /**
218     * 查找支持该 {@code entityClass} 的监听器
219     *
220     * @param entityClass 实体class
221     * @param listenerMap 监听器map
222     * @param <T>         监听器类型
223     * @return 符合条件的监听器
224     */
225    public <T extends Listener> List<T> findSupportedListeners(Class<?> entityClass, Map<Class<?>, List<T>> listenerMap) {
226        return listenerMap.entrySet()
227            .stream()
228            .filter(entry -> entry.getKey().isAssignableFrom(entityClass))
229            .flatMap(e -> e.getValue().stream())
230            .collect(Collectors.toList());
231    }
232
233    /**
234     * 获取支持该 {@code entityClass} 的update监听器
235     * <p>当registerClass是entityClass的本身或其超类时,则视为支持</p>
236     *
237     * @param entityClass 实体class
238     * @return UpdateListener
239     */
240    public List<UpdateListener> getSupportedUpdateListener(Class<?> entityClass) {
241        return this.findSupportedListeners(entityClass, this.entityUpdateListeners);
242    }
243
244
245    public List<InsertListener> getInsertListener(Class<?> entityClass) {
246        return entityInsertListeners.get(entityClass);
247    }
248
249    /**
250     * 获取支持该 {@code entityClass} 的insert监听器
251     * <p>当registerClass是entityClass的本身或其超类时,则视为支持</p>
252     *
253     * @param entityClass 实体class
254     * @return InsertListener
255     */
256    public List<InsertListener> getSupportedInsertListener(Class<?> entityClass) {
257        return this.findSupportedListeners(entityClass, this.entityInsertListeners);
258    }
259
260    public Object getNormalValueOfLogicDelete() {
261        return normalValueOfLogicDelete;
262    }
263
264    public void setNormalValueOfLogicDelete(Object normalValueOfLogicDelete) {
265        FlexAssert.notNull(normalValueOfLogicDelete, "normalValueOfLogicDelete");
266        this.normalValueOfLogicDelete = normalValueOfLogicDelete;
267    }
268
269    public Object getDeletedValueOfLogicDelete() {
270        return deletedValueOfLogicDelete;
271    }
272
273    public void setDeletedValueOfLogicDelete(Object deletedValueOfLogicDelete) {
274        FlexAssert.notNull(deletedValueOfLogicDelete, "deletedValueOfLogicDelete");
275        this.deletedValueOfLogicDelete = deletedValueOfLogicDelete;
276    }
277
278    public int getDefaultPageSize() {
279        return defaultPageSize;
280    }
281
282    public void setDefaultPageSize(int defaultPageSize) {
283        this.defaultPageSize = defaultPageSize;
284    }
285
286    public int getDefaultMaxPageSize() {
287        return defaultMaxPageSize;
288    }
289
290    public void setDefaultMaxPageSize(int defaultMaxPageSize) {
291        this.defaultMaxPageSize = defaultMaxPageSize;
292    }
293
294    public int getDefaultRelationQueryDepth() {
295        return defaultRelationQueryDepth;
296    }
297
298    public void setDefaultRelationQueryDepth(int defaultRelationQueryDepth) {
299        this.defaultRelationQueryDepth = defaultRelationQueryDepth;
300    }
301
302    public String getLogicDeleteColumn() {
303        return logicDeleteColumn;
304    }
305
306    public void setLogicDeleteColumn(String logicDeleteColumn) {
307        this.logicDeleteColumn = logicDeleteColumn;
308    }
309
310    public String getTenantColumn() {
311        return tenantColumn;
312    }
313
314    public void setTenantColumn(String tenantColumn) {
315        this.tenantColumn = tenantColumn;
316    }
317
318    public String getVersionColumn() {
319        return versionColumn;
320    }
321
322    public void setVersionColumn(String versionColumn) {
323        this.versionColumn = versionColumn;
324    }
325
326    public FlexDataSource getDataSource() {
327        return (FlexDataSource) getConfiguration().getEnvironment().getDataSource();
328    }
329
330    public static ConcurrentHashMap<String, FlexGlobalConfig> getGlobalConfigs() {
331        return globalConfigs;
332    }
333
334    public static void setGlobalConfigs(ConcurrentHashMap<String, FlexGlobalConfig> globalConfigs) {
335        FlexGlobalConfig.globalConfigs = globalConfigs;
336    }
337
338
339    /**
340     * 对应的是 注解 {@link com.mybatisflex.annotation.Id} 的配置
341     */
342    public static class KeyConfig {
343
344        private KeyType keyType;
345        private String value;
346        private boolean before = true;
347
348        public KeyType getKeyType() {
349            return keyType;
350        }
351
352        public void setKeyType(KeyType keyType) {
353            this.keyType = keyType;
354        }
355
356        public String getValue() {
357            return value;
358        }
359
360        public void setValue(String value) {
361            this.value = value;
362        }
363
364        public boolean isBefore() {
365            return before;
366        }
367
368        public void setBefore(boolean before) {
369            this.before = before;
370        }
371
372    }
373
374
375    /////static factory methods/////
376    private static ConcurrentHashMap<String, FlexGlobalConfig> globalConfigs = new ConcurrentHashMap<>();
377    private static FlexGlobalConfig defaultConfig = new FlexGlobalConfig();
378
379    public static FlexGlobalConfig getDefaultConfig() {
380        return defaultConfig;
381    }
382
383    public static void setDefaultConfig(FlexGlobalConfig config) {
384        if (config == null) {
385            throw new NullPointerException("config must not be null.");
386        }
387        defaultConfig = config;
388    }
389
390    public static FlexGlobalConfig getConfig(Configuration configuration) {
391        return getConfig(configuration.getEnvironment().getId());
392    }
393
394    public static FlexGlobalConfig getConfig(String environmentId) {
395        return globalConfigs.get(environmentId);
396    }
397
398
399    /**
400     * 设置全局配置
401     *
402     * @param id        环境id
403     * @param config    全局配置
404     * @param isDefault 自动指定默认全局配置(在多源时,方便由注解指定默认源)
405     */
406    public static synchronized void setConfig(String id, FlexGlobalConfig config, boolean isDefault) {
407        if (isDefault) {
408            defaultConfig.setSqlSessionFactory(config.sqlSessionFactory);
409            defaultConfig.setConfiguration(config.configuration);
410        }
411
412        globalConfigs.put(id, isDefault ? defaultConfig : config);
413    }
414
415}