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