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