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     * 未匹配列处理器
115     */
116    private static UnMappedColumnHandler unMappedColumnHandler;
117
118    public boolean isPrintBanner() {
119        return printBanner;
120    }
121
122    public void setPrintBanner(boolean printBanner) {
123        this.printBanner = printBanner;
124    }
125
126    public DbType getDbType() {
127        return dbType;
128    }
129
130    public void setDbType(DbType dbType) {
131        this.dbType = dbType;
132    }
133
134    public Configuration getConfiguration() {
135        return configuration;
136    }
137
138    public void setConfiguration(Configuration configuration) {
139        this.configuration = configuration;
140        DataSource dataSource = configuration.getEnvironment().getDataSource();
141        if (dataSource instanceof FlexDataSource) {
142            this.dbType = ((FlexDataSource) dataSource).getDefaultDbType();
143        }
144    }
145
146    public SqlSessionFactory getSqlSessionFactory() {
147        return sqlSessionFactory;
148    }
149
150    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
151        this.sqlSessionFactory = sqlSessionFactory;
152    }
153
154    public KeyConfig getKeyConfig() {
155        return keyConfig;
156    }
157
158    public void setKeyConfig(KeyConfig keyConfig) {
159        this.keyConfig = keyConfig;
160    }
161
162    public Map<Class<?>, List<SetListener>> getEntitySetListeners() {
163        return entitySetListeners;
164    }
165
166    public void setEntitySetListeners(Map<Class<?>, List<SetListener>> entitySetListeners) {
167        this.entitySetListeners = entitySetListeners;
168    }
169
170    public Map<Class<?>, List<UpdateListener>> getEntityUpdateListeners() {
171        return entityUpdateListeners;
172    }
173
174    public void setEntityUpdateListeners(Map<Class<?>, List<UpdateListener>> entityUpdateListeners) {
175        this.entityUpdateListeners = entityUpdateListeners;
176    }
177
178    public Map<Class<?>, List<InsertListener>> getEntityInsertListeners() {
179        return entityInsertListeners;
180    }
181
182    public void setEntityInsertListeners(Map<Class<?>, List<InsertListener>> entityInsertListeners) {
183        this.entityInsertListeners = entityInsertListeners;
184    }
185
186    public void registerSetListener(SetListener listener, Class<?>... classes) {
187        for (Class<?> aClass : classes) {
188            entitySetListeners.computeIfAbsent(aClass, k -> new ArrayList<>()).add(listener);
189        }
190    }
191
192    public void registerUpdateListener(UpdateListener listener, Class<?>... classes) {
193        for (Class<?> aClass : classes) {
194            entityUpdateListeners.computeIfAbsent(aClass, k -> new ArrayList<>()).add(listener);
195        }
196    }
197
198    public void registerInsertListener(InsertListener listener, Class<?>... classes) {
199        for (Class<?> aClass : classes) {
200            entityInsertListeners.computeIfAbsent(aClass, k -> new ArrayList<>()).add(listener);
201        }
202    }
203
204    public List<SetListener> getSetListener(Class<?> entityClass) {
205        return entitySetListeners.get(entityClass);
206    }
207
208    /**
209     * 获取支持该 {@code entityClass} 的set监听器
210     * <p>当registerClass是entityClass的本身或其超类时,则视为支持</p>
211     *
212     * @param entityClass 实体class
213     * @return UpdateListener
214     */
215    public List<SetListener> getSupportedSetListener(Class<?> entityClass) {
216        return this.findSupportedListeners(entityClass, this.entitySetListeners);
217    }
218
219    public List<UpdateListener> getUpdateListener(Class<?> entityClass) {
220        return entityUpdateListeners.get(entityClass);
221    }
222
223    /**
224     * 查找支持该 {@code entityClass} 的监听器
225     *
226     * @param entityClass 实体class
227     * @param listenerMap 监听器map
228     * @param <T>         监听器类型
229     * @return 符合条件的监听器
230     */
231    public <T extends Listener> List<T> findSupportedListeners(Class<?> entityClass, Map<Class<?>, List<T>> listenerMap) {
232        return listenerMap.entrySet()
233            .stream()
234            .filter(entry -> entry.getKey().isAssignableFrom(entityClass))
235            .flatMap(e -> e.getValue().stream())
236            .collect(Collectors.toList());
237    }
238
239    /**
240     * 获取支持该 {@code entityClass} 的update监听器
241     * <p>当registerClass是entityClass的本身或其超类时,则视为支持</p>
242     *
243     * @param entityClass 实体class
244     * @return UpdateListener
245     */
246    public List<UpdateListener> getSupportedUpdateListener(Class<?> entityClass) {
247        return this.findSupportedListeners(entityClass, this.entityUpdateListeners);
248    }
249
250
251    public List<InsertListener> getInsertListener(Class<?> entityClass) {
252        return entityInsertListeners.get(entityClass);
253    }
254
255    /**
256     * 获取支持该 {@code entityClass} 的insert监听器
257     * <p>当registerClass是entityClass的本身或其超类时,则视为支持</p>
258     *
259     * @param entityClass 实体class
260     * @return InsertListener
261     */
262    public List<InsertListener> getSupportedInsertListener(Class<?> entityClass) {
263        return this.findSupportedListeners(entityClass, this.entityInsertListeners);
264    }
265
266    public Object getNormalValueOfLogicDelete() {
267        return normalValueOfLogicDelete;
268    }
269
270    public void setNormalValueOfLogicDelete(Object normalValueOfLogicDelete) {
271        FlexAssert.notNull(normalValueOfLogicDelete, "normalValueOfLogicDelete");
272        this.normalValueOfLogicDelete = normalValueOfLogicDelete;
273    }
274
275    public Object getDeletedValueOfLogicDelete() {
276        return deletedValueOfLogicDelete;
277    }
278
279    public void setDeletedValueOfLogicDelete(Object deletedValueOfLogicDelete) {
280        FlexAssert.notNull(deletedValueOfLogicDelete, "deletedValueOfLogicDelete");
281        this.deletedValueOfLogicDelete = deletedValueOfLogicDelete;
282    }
283
284    public int getDefaultPageSize() {
285        return defaultPageSize;
286    }
287
288    public void setDefaultPageSize(int defaultPageSize) {
289        this.defaultPageSize = defaultPageSize;
290    }
291
292    public int getDefaultMaxPageSize() {
293        return defaultMaxPageSize;
294    }
295
296    public void setDefaultMaxPageSize(int defaultMaxPageSize) {
297        this.defaultMaxPageSize = defaultMaxPageSize;
298    }
299
300    public int getDefaultRelationQueryDepth() {
301        return defaultRelationQueryDepth;
302    }
303
304    public void setDefaultRelationQueryDepth(int defaultRelationQueryDepth) {
305        this.defaultRelationQueryDepth = defaultRelationQueryDepth;
306    }
307
308    public String getLogicDeleteColumn() {
309        return logicDeleteColumn;
310    }
311
312    public void setLogicDeleteColumn(String logicDeleteColumn) {
313        this.logicDeleteColumn = logicDeleteColumn;
314    }
315
316    public String getTenantColumn() {
317        return tenantColumn;
318    }
319
320    public void setTenantColumn(String tenantColumn) {
321        this.tenantColumn = tenantColumn;
322    }
323
324    public String getVersionColumn() {
325        return versionColumn;
326    }
327
328    public void setVersionColumn(String versionColumn) {
329        this.versionColumn = versionColumn;
330    }
331
332    public static UnMappedColumnHandler getUnMappedColumnHandler() {
333        return unMappedColumnHandler;
334    }
335
336    public void setUnMappedColumnHandler(UnMappedColumnHandler unMappedColumnHandler) {
337        this.unMappedColumnHandler = unMappedColumnHandler;
338    }
339
340    public FlexDataSource getDataSource() {
341        return (FlexDataSource) getConfiguration().getEnvironment().getDataSource();
342    }
343
344    public static ConcurrentHashMap<String, FlexGlobalConfig> getGlobalConfigs() {
345        return globalConfigs;
346    }
347
348    public static void setGlobalConfigs(ConcurrentHashMap<String, FlexGlobalConfig> globalConfigs) {
349        FlexGlobalConfig.globalConfigs = globalConfigs;
350    }
351
352
353    /**
354     * 对应的是 注解 {@link com.mybatisflex.annotation.Id} 的配置
355     */
356    public static class KeyConfig {
357
358        private KeyType keyType;
359        private String value;
360        private boolean before = true;
361
362        public KeyType getKeyType() {
363            return keyType;
364        }
365
366        public void setKeyType(KeyType keyType) {
367            this.keyType = keyType;
368        }
369
370        public String getValue() {
371            return value;
372        }
373
374        public void setValue(String value) {
375            this.value = value;
376        }
377
378        public boolean isBefore() {
379            return before;
380        }
381
382        public void setBefore(boolean before) {
383            this.before = before;
384        }
385
386    }
387
388
389    /////static factory methods/////
390    private static ConcurrentHashMap<String, FlexGlobalConfig> globalConfigs = new ConcurrentHashMap<>();
391    private static FlexGlobalConfig defaultConfig = new FlexGlobalConfig();
392
393    public static FlexGlobalConfig getDefaultConfig() {
394        return defaultConfig;
395    }
396
397    public static void setDefaultConfig(FlexGlobalConfig config) {
398        if (config == null) {
399            throw new NullPointerException("config must not be null.");
400        }
401        defaultConfig = config;
402    }
403
404    public static FlexGlobalConfig getConfig(Configuration configuration) {
405        return getConfig(configuration.getEnvironment().getId());
406    }
407
408    public static FlexGlobalConfig getConfig(String environmentId) {
409        return globalConfigs.get(environmentId);
410    }
411
412
413    /**
414     * 设置全局配置
415     *
416     * @param id        环境id
417     * @param config    全局配置
418     * @param isDefault 自动指定默认全局配置(在多源时,方便由注解指定默认源)
419     */
420    public static synchronized void setConfig(String id, FlexGlobalConfig config, boolean isDefault) {
421        if (isDefault) {
422            defaultConfig.setSqlSessionFactory(config.sqlSessionFactory);
423            defaultConfig.setConfiguration(config.configuration);
424        }
425
426        globalConfigs.put(id, isDefault ? defaultConfig : config);
427    }
428
429}