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