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        while (setListener == null && childClass != null) {
225            setListener = entitySetListeners.get(childClass);
226            childClass = childClass.getSuperclass();
227        }
228
229        if (setListener != null) {
230            listeners.put(childClass, setListener);
231        }
232    }
233
234
235    public UpdateListener getUpdateListener(Class<?> entityClass) {
236        return entityUpdateListeners.get(entityClass);
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, boolean interfaceOnly) {
247
248        Map<Class<?>, UpdateListener> map = new HashMap<>();
249        if (!interfaceOnly) {
250            doGetSupportedUpdateListener(entityClass, map);
251        }
252
253        while (entityClass.getSuperclass() != null) {
254            Class<?>[] interfaces = entityClass.getInterfaces();
255            for (Class<?> interfaceClass : interfaces) {
256                doGetSupportedUpdateListener(interfaceClass, map);
257            }
258            entityClass = entityClass.getSuperclass();
259        }
260
261        return new ArrayList<>(map.values());
262    }
263
264
265    private void doGetSupportedUpdateListener(Class<?> childClass, Map<Class<?>, UpdateListener> listeners) {
266        UpdateListener updateListener = null;
267        while (updateListener == null && childClass != null) {
268            updateListener = entityUpdateListeners.get(childClass);
269            childClass = childClass.getSuperclass();
270        }
271
272        if (updateListener != null) {
273            listeners.put(childClass, updateListener);
274        }
275    }
276
277
278    public InsertListener getInsertListener(Class<?> entityClass) {
279        return entityInsertListeners.get(entityClass);
280    }
281
282    /**
283     * 获取支持该 {@code entityClass} 的insert监听器
284     * <p>当registerClass是entityClass的本身或其超类时,则视为支持</p>
285     *
286     * @param entityClass 实体class
287     * @return InsertListener
288     */
289    public List<InsertListener> getSupportedInsertListener(Class<?> entityClass, boolean interfaceOnly) {
290
291        Map<Class<?>, InsertListener> map = new HashMap<>();
292        if (!interfaceOnly) {
293            doGetSupportedInsertListener(entityClass, map);
294        }
295
296        while (entityClass.getSuperclass() != null) {
297            Class<?>[] interfaces = entityClass.getInterfaces();
298            for (Class<?> interfaceClass : interfaces) {
299                doGetSupportedInsertListener(interfaceClass, map);
300            }
301            entityClass = entityClass.getSuperclass();
302        }
303
304        return new ArrayList<>(map.values());
305    }
306
307
308    private void doGetSupportedInsertListener(Class<?> childClass, Map<Class<?>, InsertListener> listeners) {
309        InsertListener insertListener = null;
310        while (insertListener == null && childClass != null) {
311            insertListener = entityInsertListeners.get(childClass);
312            childClass = childClass.getSuperclass();
313        }
314
315        if (insertListener != null) {
316            listeners.put(childClass, insertListener);
317        }
318    }
319
320
321    public Object getNormalValueOfLogicDelete() {
322        return normalValueOfLogicDelete;
323    }
324
325    public void setNormalValueOfLogicDelete(Object normalValueOfLogicDelete) {
326        FlexAssert.notNull(normalValueOfLogicDelete, "normalValueOfLogicDelete");
327        this.normalValueOfLogicDelete = normalValueOfLogicDelete;
328    }
329
330    public Object getDeletedValueOfLogicDelete() {
331        return deletedValueOfLogicDelete;
332    }
333
334    public void setDeletedValueOfLogicDelete(Object deletedValueOfLogicDelete) {
335        FlexAssert.notNull(deletedValueOfLogicDelete, "deletedValueOfLogicDelete");
336        this.deletedValueOfLogicDelete = deletedValueOfLogicDelete;
337    }
338
339    public int getDefaultPageSize() {
340        return defaultPageSize;
341    }
342
343    public void setDefaultPageSize(int defaultPageSize) {
344        this.defaultPageSize = defaultPageSize;
345    }
346
347    public int getDefaultRelationQueryDepth() {
348        return defaultRelationQueryDepth;
349    }
350
351    public void setDefaultRelationQueryDepth(int defaultRelationQueryDepth) {
352        this.defaultRelationQueryDepth = defaultRelationQueryDepth;
353    }
354
355    public String getLogicDeleteColumn() {
356        return logicDeleteColumn;
357    }
358
359    public void setLogicDeleteColumn(String logicDeleteColumn) {
360        this.logicDeleteColumn = logicDeleteColumn;
361    }
362
363    public String getTenantColumn() {
364        return tenantColumn;
365    }
366
367    public void setTenantColumn(String tenantColumn) {
368        this.tenantColumn = tenantColumn;
369    }
370
371    public String getVersionColumn() {
372        return versionColumn;
373    }
374
375    public void setVersionColumn(String versionColumn) {
376        this.versionColumn = versionColumn;
377    }
378
379    public FlexDataSource getDataSource() {
380        return (FlexDataSource) getConfiguration().getEnvironment().getDataSource();
381    }
382
383    public static ConcurrentHashMap<String, FlexGlobalConfig> getGlobalConfigs() {
384        return globalConfigs;
385    }
386
387    public static void setGlobalConfigs(ConcurrentHashMap<String, FlexGlobalConfig> globalConfigs) {
388        FlexGlobalConfig.globalConfigs = globalConfigs;
389    }
390
391
392    /**
393     * 对应的是 注解 {@link com.mybatisflex.annotation.Id} 的配置
394     */
395    public static class KeyConfig {
396
397        private KeyType keyType;
398        private String value;
399        private boolean before = true;
400
401        public KeyType getKeyType() {
402            return keyType;
403        }
404
405        public void setKeyType(KeyType keyType) {
406            this.keyType = keyType;
407        }
408
409        public String getValue() {
410            return value;
411        }
412
413        public void setValue(String value) {
414            this.value = value;
415        }
416
417        public boolean isBefore() {
418            return before;
419        }
420
421        public void setBefore(boolean before) {
422            this.before = before;
423        }
424
425    }
426
427
428    /////static factory methods/////
429    private static ConcurrentHashMap<String, FlexGlobalConfig> globalConfigs = new ConcurrentHashMap<>();
430    private static FlexGlobalConfig defaultConfig = new FlexGlobalConfig();
431
432    public static FlexGlobalConfig getDefaultConfig() {
433        return defaultConfig;
434    }
435
436    public static void setDefaultConfig(FlexGlobalConfig config) {
437        if (config == null) {
438            throw new NullPointerException("config must not be null.");
439        }
440        defaultConfig = config;
441    }
442
443    public static FlexGlobalConfig getConfig(Configuration configuration) {
444        return getConfig(configuration.getEnvironment().getId());
445    }
446
447    public static FlexGlobalConfig getConfig(String environmentId) {
448        return globalConfigs.get(environmentId);
449    }
450
451
452    /**
453     * 设置全局配置
454     *
455     * @param id        环境id
456     * @param config    全局配置
457     * @param isDefault 自动指定默认全局配置(在多源时,方便由注解指定默认源)
458     */
459    public static synchronized void setConfig(String id, FlexGlobalConfig config, boolean isDefault) {
460        if (isDefault) {
461            defaultConfig.setSqlSessionFactory(config.sqlSessionFactory);
462            defaultConfig.setConfiguration(config.configuration);
463        }
464
465        globalConfigs.put(id, isDefault ? defaultConfig : config);
466    }
467
468}